[skottie] Add a custom property manager util class

To facilitate demo code consolidation, introduce a custom property
manager which filters for node names starting with '$' and treats all
properties sharing the same name unitarily.

Update the Colorize GM to use this new helper.

Also revisit the PropertyObserver interface:

 * aliases for client-facing value types
 * introduce a new (decomposed) TransformPropertyValue, to replace component-wise setters
 * consolidate the PropertyHandle interface to only expose get()/set()

Bug: skia:
Change-Id: I9aa9ee80c1fb57bbfbacab0fc3f017da909b24d9
Reviewed-on: https://skia-review.googlesource.com/c/173220
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/modules/skottie/gm/SkottieGM.cpp b/modules/skottie/gm/SkottieGM.cpp
index 040b8b3..8febf25 100644
--- a/modules/skottie/gm/SkottieGM.cpp
+++ b/modules/skottie/gm/SkottieGM.cpp
@@ -90,6 +90,8 @@
 
 DEF_GM(return new SkottieWebFontGM;)
 
+using namespace skottie_utils;
+
 class SkottieColorizeGM : public skiagm::GM {
 protected:
     SkString onShortName() override {
@@ -102,10 +104,12 @@
 
     void onOnceBeforeDraw() override {
         if (auto stream = GetResourceAsStream("skottie/skottie_sample_search.json")) {
-            fColorizer = sk_make_sp<Colorizer>();
-            fAnimation = Animation::Builder()
-                            .setPropertyObserver(fColorizer)
-                            .make(stream.get());
+            auto propBuilder = sk_make_sp<CustomPropertyManagerBuilder>();
+            fAnimation   = Animation::Builder()
+                              .setPropertyObserver(propBuilder)
+                              .make(stream.get());
+            fPropManager = propBuilder->build();
+            fColors      = fPropManager->getColorProps();
         }
     }
 
@@ -139,7 +143,9 @@
 
         if (uni == 'c') {
             fColorIndex = (fColorIndex + 1) % SK_ARRAY_COUNT(kColors);
-            fColorizer->colorize(kColors[fColorIndex]);
+            for (const auto& prop : fColors) {
+                fPropManager->setColor(prop, kColors[fColorIndex]);
+            }
             return true;
         }
 
@@ -147,28 +153,12 @@
     }
 
 private:
-    class Colorizer final : public PropertyObserver {
-    public:
-        void onColorProperty(const char node_name[],
-                             const PropertyObserver::LazyHandle<ColorPropertyHandle>& lh) override {
-            fColorHandles.push_back(lh());
-        }
-
-        void colorize(SkColor c) {
-            for (const auto& handle : fColorHandles) {
-                handle->setColor(c);
-            }
-        }
-
-    private:
-        std::vector<std::unique_ptr<skottie::ColorPropertyHandle>> fColorHandles;
-    };
-
     static constexpr SkScalar kSize = 800;
 
-    sk_sp<Animation> fAnimation;
-    sk_sp<Colorizer> fColorizer;
-    size_t           fColorIndex = 0;
+    sk_sp<Animation>                            fAnimation;
+    std::unique_ptr<CustomPropertyManager>      fPropManager;
+    std::vector<CustomPropertyManager::PropKey> fColors;
+    size_t                                      fColorIndex = 0;
 
     using INHERITED = skiagm::GM;
 };
diff --git a/modules/skottie/include/SkottieProperty.h b/modules/skottie/include/SkottieProperty.h
index 291b086..a738697 100644
--- a/modules/skottie/include/SkottieProperty.h
+++ b/modules/skottie/include/SkottieProperty.h
@@ -25,9 +25,48 @@
 
 namespace skottie {
 
-class ColorPropertyHandle;
-class OpacityPropertyHandle;
-class TransformPropertyHandle;
+using ColorPropertyValue   = SkColor;
+using OpacityPropertyValue = float;
+
+struct TransformPropertyValue {
+    SkPoint  fAnchorPoint,
+             fPosition;
+    SkVector fScale;
+    SkScalar fRotation,
+             fSkew,
+             fSkewAxis;
+
+    bool operator==(const TransformPropertyValue& other) const;
+    bool operator!=(const TransformPropertyValue& other) const;
+};
+
+namespace internal { class AnimationBuilder; }
+
+/**
+ * Property handles are adapters between user-facing AE model/values
+ * and the internal scene-graph representation.
+ */
+template <typename ValueT, typename NodeT>
+class SK_API PropertyHandle final {
+public:
+    ~PropertyHandle();
+
+    ValueT get() const;
+    void set(const ValueT&);
+
+private:
+    explicit PropertyHandle(sk_sp<NodeT> node) : fNode(std::move(node)) {}
+
+    friend class skottie::internal::AnimationBuilder;
+
+    const sk_sp<NodeT> fNode;
+};
+
+class TransformAdapter;
+
+using ColorPropertyHandle     = PropertyHandle<ColorPropertyValue    , sksg::Color         >;
+using OpacityPropertyHandle   = PropertyHandle<OpacityPropertyValue  , sksg::OpacityEffect >;
+using TransformPropertyHandle = PropertyHandle<TransformPropertyValue, TransformAdapter    >;
 
 /**
  * A PropertyObserver can be used to track and manipulate certain properties of "interesting"
@@ -37,7 +76,7 @@
  * various properties of layer and shape nodes.  The |node_name| argument corresponds to the
  * name ("nm") node property.
  */
-class PropertyObserver : public SkRefCnt {
+class SK_API PropertyObserver : public SkRefCnt {
 public:
     template <typename T>
     using LazyHandle = std::function<std::unique_ptr<T>()>;
@@ -50,72 +89,6 @@
                                      const LazyHandle<TransformPropertyHandle>&);
 };
 
-namespace internal { class AnimationBuilder; }
-
-class ColorPropertyHandle final {
-public:
-    ~ColorPropertyHandle();
-
-    SkColor getColor() const;
-    void setColor(SkColor);
-
-private:
-    explicit ColorPropertyHandle(sk_sp<sksg::Color>);
-
-    friend class skottie::internal::AnimationBuilder;
-
-    const sk_sp<sksg::Color> fColor;
-};
-
-class OpacityPropertyHandle final {
-public:
-    ~OpacityPropertyHandle();
-
-    float getOpacity() const;
-    void setOpacity(float);
-
-private:
-    explicit OpacityPropertyHandle(sk_sp<sksg::OpacityEffect>);
-
-    friend class skottie::internal::AnimationBuilder;
-
-    const sk_sp<sksg::OpacityEffect> fOpacity;
-};
-
-class TransformAdapter;
-
-class TransformPropertyHandle final {
-public:
-    ~TransformPropertyHandle();
-
-    SkPoint getAnchorPoint() const;
-    void setAnchorPoint(const SkPoint&);
-
-    SkPoint getPosition() const;
-    void setPosition(const SkPoint&);
-
-    SkVector getScale() const;
-    void setScale(const SkVector&);
-
-    SkScalar getRotation() const;
-    void setRotation(SkScalar);
-
-    SkScalar getSkew() const;
-    void setSkew(SkScalar);
-
-    SkScalar getSkewAxis() const;
-    void setSkewAxis(SkScalar);
-
-    SkMatrix getTotalMatrix() const;
-
-private:
-    explicit TransformPropertyHandle(sk_sp<TransformAdapter>);
-
-    friend class skottie::internal::AnimationBuilder;
-
-    const sk_sp<TransformAdapter> fTransform;
-};
-
 } // namespace skottie
 
 #endif // SkottieProperty_DEFINED
diff --git a/modules/skottie/src/SkottieProperty.cpp b/modules/skottie/src/SkottieProperty.cpp
index 7ca35b9..0d27017 100644
--- a/modules/skottie/src/SkottieProperty.cpp
+++ b/modules/skottie/src/SkottieProperty.cpp
@@ -13,93 +13,68 @@
 
 namespace skottie {
 
-ColorPropertyHandle::ColorPropertyHandle(sk_sp<sksg::Color> color)
-    : fColor(std::move(color)) {
-    SkASSERT(fColor);
+bool TransformPropertyValue::operator==(const TransformPropertyValue& other) const {
+    return this->fAnchorPoint == other.fAnchorPoint
+        && this->fPosition    == other.fPosition
+        && this->fScale       == other.fScale
+        && this->fSkew        == other.fSkew
+        && this->fSkewAxis    == other.fSkewAxis;
 }
 
-ColorPropertyHandle::~ColorPropertyHandle() = default;
-
-SkColor ColorPropertyHandle::getColor() const {
-    return fColor->getColor();
+bool TransformPropertyValue::operator!=(const TransformPropertyValue& other) const {
+    return !(*this == other);
 }
 
-void ColorPropertyHandle::setColor(SkColor color) {
-    fColor->setColor(color);
+template <>
+PropertyHandle<ColorPropertyValue, sksg::Color>::~PropertyHandle() {}
+
+template <>
+ColorPropertyValue PropertyHandle<ColorPropertyValue, sksg::Color>::get() const {
+    return fNode->getColor();
 }
 
-OpacityPropertyHandle::OpacityPropertyHandle(sk_sp<sksg::OpacityEffect> opacity)
-    : fOpacity(std::move(opacity)) {
-    SkASSERT(fOpacity);
+template <>
+void PropertyHandle<ColorPropertyValue, sksg::Color>::set(const ColorPropertyValue& c) {
+    fNode->setColor(c);
 }
 
-OpacityPropertyHandle::~OpacityPropertyHandle() = default;
+template <>
+PropertyHandle<OpacityPropertyValue, sksg::OpacityEffect>::~PropertyHandle() {}
 
-float OpacityPropertyHandle::getOpacity() const {
-    return fOpacity->getOpacity() * 100;
+template <>
+OpacityPropertyValue PropertyHandle<OpacityPropertyValue, sksg::OpacityEffect>::get() const {
+    return fNode->getOpacity() * 100;
 }
 
-void OpacityPropertyHandle::setOpacity(float opacity) {
-    fOpacity->setOpacity(opacity / 100);
+template <>
+void PropertyHandle<OpacityPropertyValue, sksg::OpacityEffect>::set(const OpacityPropertyValue& o) {
+    fNode->setOpacity(o / 100);
 }
 
-TransformPropertyHandle::TransformPropertyHandle(sk_sp<TransformAdapter> transform)
-    : fTransform(std::move(transform)) {
-    SkASSERT(fTransform);
+template <>
+PropertyHandle<TransformPropertyValue, TransformAdapter>::~PropertyHandle() {}
+
+template <>
+TransformPropertyValue PropertyHandle<TransformPropertyValue, TransformAdapter>::get() const {
+    return {
+        fNode->getAnchorPoint(),
+        fNode->getPosition(),
+        fNode->getScale(),
+        fNode->getRotation(),
+        fNode->getSkew(),
+        fNode->getSkewAxis()
+    };
 }
 
-TransformPropertyHandle::~TransformPropertyHandle() = default;
-
-SkPoint TransformPropertyHandle::getAnchorPoint() const {
-    return fTransform->getAnchorPoint();
-}
-
-void TransformPropertyHandle::setAnchorPoint(const SkPoint& ap) {
-    fTransform->setAnchorPoint(ap);
-}
-
-SkPoint TransformPropertyHandle::getPosition() const {
-    return fTransform->getPosition();
-}
-
-void TransformPropertyHandle::setPosition(const SkPoint& position) {
-    fTransform->setPosition(position);
-}
-
-SkVector TransformPropertyHandle::getScale() const {
-    return fTransform->getScale();
-}
-
-void TransformPropertyHandle::setScale(const SkVector& scale) {
-    fTransform->setScale(scale);
-}
-
-SkScalar TransformPropertyHandle::getRotation() const {
-    return fTransform->getRotation();
-}
-
-void TransformPropertyHandle::setRotation(SkScalar rotation) {
-    fTransform->setRotation(rotation);
-}
-
-SkScalar TransformPropertyHandle::getSkew() const {
-    return fTransform->getSkew();
-}
-
-void TransformPropertyHandle::setSkew(SkScalar skew) {
-    fTransform->setSkew(skew);
-}
-
-SkScalar TransformPropertyHandle::getSkewAxis() const {
-    return fTransform->getSkewAxis();
-}
-
-void TransformPropertyHandle::setSkewAxis(SkScalar sa) {
-    fTransform->setSkewAxis(sa);
-}
-
-SkMatrix TransformPropertyHandle::getTotalMatrix() const {
-    return fTransform->totalMatrix();
+template <>
+void PropertyHandle<TransformPropertyValue, TransformAdapter>::set(
+        const TransformPropertyValue& t) {
+    fNode->setAnchorPoint(t.fAnchorPoint);
+    fNode->setPosition(t.fPosition);
+    fNode->setScale(t.fScale);
+    fNode->setRotation(t.fRotation);
+    fNode->setSkew(t.fSkew);
+    fNode->setSkewAxis(t.fSkewAxis);
 }
 
 void PropertyObserver::onColorProperty(const char[],
diff --git a/modules/skottie/src/SkottieTest.cpp b/modules/skottie/src/SkottieTest.cpp
index a44bc15..268b5dd 100644
--- a/modules/skottie/src/SkottieTest.cpp
+++ b/modules/skottie/src/SkottieTest.cpp
@@ -83,23 +83,23 @@
         };
 
         struct TransformInfo {
-            SkString node_name;
-            SkMatrix matrix;
+            SkString                        node_name;
+            skottie::TransformPropertyValue transform;
         };
 
         void onColorProperty(const char node_name[],
                 const PropertyObserver::LazyHandle<ColorPropertyHandle>& lh) override {
-            fColors.push_back({SkString(node_name), lh()->getColor()});
+            fColors.push_back({SkString(node_name), lh()->get()});
         }
 
         void onOpacityProperty(const char node_name[],
                 const PropertyObserver::LazyHandle<OpacityPropertyHandle>& lh) override {
-            fOpacities.push_back({SkString(node_name), lh()->getOpacity()});
+            fOpacities.push_back({SkString(node_name), lh()->get()});
         }
 
         void onTransformProperty(const char node_name[],
                 const PropertyObserver::LazyHandle<TransformPropertyHandle>& lh) override {
-            fTransforms.push_back({SkString(node_name), lh()->getTotalMatrix()});
+            fTransforms.push_back({SkString(node_name), lh()->get()});
         }
 
         const std::vector<ColorInfo>& colors() const { return fColors; }
@@ -136,9 +136,23 @@
     const auto& transforms = observer->transforms();
     REPORTER_ASSERT(reporter, transforms.size() == 2);
     REPORTER_ASSERT(reporter, transforms[0].node_name.equals("shape_transform_0"));
-    REPORTER_ASSERT(reporter, transforms[0].matrix == SkMatrix::MakeScale(0.5, 0.5));
+    REPORTER_ASSERT(reporter, transforms[0].transform == skottie::TransformPropertyValue({
+        SkPoint::Make(0, 0),
+        SkPoint::Make(0, 0),
+        SkVector::Make(50, 50),
+        0,
+        0,
+        0
+    }));
     REPORTER_ASSERT(reporter, transforms[1].node_name.equals("layer_0"));
-    REPORTER_ASSERT(reporter, transforms[1].matrix == SkMatrix::I());
+    REPORTER_ASSERT(reporter, transforms[1].transform == skottie::TransformPropertyValue({
+        SkPoint::Make(0, 0),
+        SkPoint::Make(0, 0),
+        SkVector::Make(100, 100),
+        0,
+        0,
+        0
+    }));
 }
 
 DEF_TEST(Skottie_Annotations, reporter) {
diff --git a/modules/skottie/utils/SkottieUtils.cpp b/modules/skottie/utils/SkottieUtils.cpp
index d8f39d3..92efc2f 100644
--- a/modules/skottie/utils/SkottieUtils.cpp
+++ b/modules/skottie/utils/SkottieUtils.cpp
@@ -60,4 +60,123 @@
     return MultiFrameImageAsset::Make(this->load(resource_path, resource_name));
 }
 
+CustomPropertyManagerBuilder::CustomPropertyManagerBuilder() = default;
+CustomPropertyManagerBuilder::~CustomPropertyManagerBuilder() = default;
+
+std::unique_ptr<CustomPropertyManager> CustomPropertyManagerBuilder::build() {
+    return std::unique_ptr<CustomPropertyManager>(
+                new CustomPropertyManager(std::move(fColorMap),
+                                          std::move(fOpacityMap),
+                                          std::move(fTransformMap)));
+}
+
+void CustomPropertyManagerBuilder::onColorProperty(
+        const char node_name[],
+        const LazyHandle<skottie::ColorPropertyHandle>& c) {
+    const auto key = this->acceptProperty(node_name);
+    if (!key.empty()) {
+        fColorMap[key].push_back(c());
+    }
+}
+
+void CustomPropertyManagerBuilder::onOpacityProperty(
+        const char node_name[],
+        const LazyHandle<skottie::OpacityPropertyHandle>& o) {
+    const auto key = this->acceptProperty(node_name);
+    if (!key.empty()) {
+        fOpacityMap[key].push_back(o());
+    }
+}
+
+void CustomPropertyManagerBuilder::onTransformProperty(
+        const char node_name[],
+        const LazyHandle<skottie::TransformPropertyHandle>& t) {
+    const auto key = this->acceptProperty(node_name);
+    if (!key.empty()) {
+        fTransformMap[key].push_back(t());
+    }
+}
+
+CustomPropertyManager::CustomPropertyManager(PropMap<skottie::ColorPropertyHandle> cmap,
+                                             PropMap<skottie::OpacityPropertyHandle> omap,
+                                             PropMap<skottie::TransformPropertyHandle> tmap)
+    : fColorMap(std::move(cmap))
+    , fOpacityMap(std::move(omap))
+    , fTransformMap(std::move(tmap)) {}
+
+CustomPropertyManager::~CustomPropertyManager() = default;
+
+template <typename T>
+std::vector<CustomPropertyManager::PropKey>
+CustomPropertyManager::getProps(const PropMap<T>& container) const {
+    std::vector<PropKey> props;
+
+    for (const auto& prop_list : container) {
+        SkASSERT(!prop_list.second.empty());
+        props.push_back(prop_list.first);
+    }
+
+    return props;
+}
+
+template <typename V, typename T>
+V CustomPropertyManager::get(const PropKey& key, const PropMap<T>& container) const {
+    auto prop_group = container.find(key);
+
+    return prop_group == container.end()
+            ? V()
+            : prop_group->second.front()->get();
+}
+
+template <typename V, typename T>
+bool CustomPropertyManager::set(const PropKey& key, const V& val, const PropMap<T>& container) {
+    auto prop_group = container.find(key);
+
+    if (prop_group == container.end()) {
+        return false;
+    }
+
+    for (auto& handle : prop_group->second) {
+        handle->set(val);
+    }
+
+    return true;
+}
+
+std::vector<CustomPropertyManager::PropKey>
+CustomPropertyManager::getColorProps() const {
+    return this->getProps(fColorMap);
+}
+
+skottie::ColorPropertyValue CustomPropertyManager::getColor(const PropKey& key) const {
+    return this->get<skottie::ColorPropertyValue>(key, fColorMap);
+}
+
+bool CustomPropertyManager::setColor(const PropKey& key, const skottie::ColorPropertyValue& c) {
+    return this->set(key, c, fColorMap);
+}
+
+std::vector<CustomPropertyManager::PropKey>
+CustomPropertyManager::getOpacityProps() const {
+    return this->getProps(fOpacityMap);
+}
+
+skottie::OpacityPropertyValue CustomPropertyManager::getOpacity(const PropKey& key) const {
+    return this->get<skottie::OpacityPropertyValue>(key, fOpacityMap);
+}
+
+bool CustomPropertyManager::setOpacity(const PropKey& key, const skottie::OpacityPropertyValue& o) {
+    return this->set(key, o, fOpacityMap);
+}
+
+std::vector<CustomPropertyManager::PropKey>
+CustomPropertyManager::getTransformProps() const {
+    return this->getProps(fTransformMap);
+}
+
+bool CustomPropertyManager::setTransform(const PropKey& key,
+                                         const skottie::TransformPropertyValue& t) {
+    return this->set(key, t, fTransformMap);
+}
+
 } // namespace skottie_utils
diff --git a/modules/skottie/utils/SkottieUtils.h b/modules/skottie/utils/SkottieUtils.h
index 06f134a..23dec6c 100644
--- a/modules/skottie/utils/SkottieUtils.h
+++ b/modules/skottie/utils/SkottieUtils.h
@@ -8,10 +8,16 @@
 #ifndef SkottieUtils_DEFINED
 #define SkottieUtils_DEFINED
 
+#include "SkColor.h"
 #include "Skottie.h"
+#include "SkottieProperty.h"
 #include "SkString.h"
+#include "SkTHash.h"
 
 #include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
 
 class SkAnimCodecPlayer;
 class SkData;
@@ -51,6 +57,96 @@
     using INHERITED = skottie::ResourceProvider;
 };
 
+/**
+ * CustomPropertyManager implements a property management scheme where color/opacity/transform
+ * attributes are grouped and manipulated by name (one-to-many mapping).
+ *
+ *   - setters apply the value to all properties in a named group
+ *
+ *   - getters return all the managed property groups, and the first value within each of them
+ *     (unchecked assumption: all properties within the same group have the same value)
+ *
+ * Use CustomPropertyManagerBuilder to filter nodes at animation build time, and instantiate a
+ * CustomPropertyManager.
+ */
+class CustomPropertyManager final {
+public:
+    ~CustomPropertyManager();
+
+    using PropKey = std::string;
+
+    std::vector<PropKey> getColorProps() const;
+    skottie::ColorPropertyValue getColor(const PropKey&) const;
+    bool setColor(const PropKey&, const skottie::ColorPropertyValue&);
+
+    std::vector<PropKey> getOpacityProps() const;
+    skottie::OpacityPropertyValue getOpacity(const PropKey&) const;
+    bool setOpacity(const PropKey&, const skottie::OpacityPropertyValue&);
+
+    std::vector<PropKey> getTransformProps() const;
+    skottie::TransformPropertyValue getTransform(const PropKey&) const;
+    bool setTransform(const PropKey&, const skottie::TransformPropertyValue&);
+
+private:
+    friend class CustomPropertyManagerBuilder;
+
+    template <typename T>
+    using PropGroup = std::vector<std::unique_ptr<T>>;
+
+    template <typename T>
+    using PropMap = std::unordered_map<PropKey, PropGroup<T>>;
+
+    template <typename T>
+    std::vector<PropKey> getProps(const PropMap<T>& container) const;
+
+    template <typename V, typename T>
+    V get(const PropKey&, const PropMap<T>& container) const;
+
+    template <typename V, typename T>
+    bool set(const PropKey&, const V&, const PropMap<T>& container);
+
+    CustomPropertyManager(PropMap<skottie::ColorPropertyHandle>,
+                          PropMap<skottie::OpacityPropertyHandle>,
+                          PropMap<skottie::TransformPropertyHandle>);
+
+    PropMap<skottie::ColorPropertyHandle>     fColorMap;
+    PropMap<skottie::OpacityPropertyHandle>   fOpacityMap;
+    PropMap<skottie::TransformPropertyHandle> fTransformMap;
+};
+
+/**
+ * A builder for CustomPropertyManager.  Only accepts node names starting with '$'.
+ */
+class CustomPropertyManagerBuilder final : public skottie::PropertyObserver {
+public:
+    CustomPropertyManagerBuilder();
+    ~CustomPropertyManagerBuilder() override;
+
+    std::unique_ptr<CustomPropertyManager> build();
+
+    void onColorProperty    (const char node_name[],
+                             const LazyHandle<skottie::ColorPropertyHandle>&) override;
+    void onOpacityProperty  (const char node_name[],
+                             const LazyHandle<skottie::OpacityPropertyHandle>&) override;
+    void onTransformProperty(const char node_name[],
+                             const LazyHandle<skottie::TransformPropertyHandle>&) override;
+
+private:
+    std::string acceptProperty(const char* name) const {
+        static constexpr char kPrefix = '$';
+
+        return (name[0] == kPrefix && name[1] != '\0')
+            ? std::string(name + 1)
+            : std::string();
+    }
+
+    CustomPropertyManager::PropMap<skottie::ColorPropertyHandle>     fColorMap;
+    CustomPropertyManager::PropMap<skottie::OpacityPropertyHandle>   fOpacityMap;
+    CustomPropertyManager::PropMap<skottie::TransformPropertyHandle> fTransformMap;
+
+    using INHERITED = skottie::PropertyObserver;
+};
+
 } // namespace skottie_utils
 
 #endif // SkottieUtils_DEFINED
diff --git a/resources/skottie/skottie_sample_search.json b/resources/skottie/skottie_sample_search.json
index dddb766..f880f0a 100644
--- a/resources/skottie/skottie_sample_search.json
+++ b/resources/skottie/skottie_sample_search.json
@@ -117,7 +117,7 @@
                             "lc": 2,
                             "lj": 2,
                             "mn": "ADBE Vector Graphic - Stroke",
-                            "nm": "Stroke 1",
+                            "nm": "$Stroke 1",
                             "o": {
                                 "a": 0,
                                 "ix": 4,
@@ -143,7 +143,7 @@
                             },
                             "hd": false,
                             "mn": "ADBE Vector Graphic - Fill",
-                            "nm": "Fill 1",
+                            "nm": "$Fill 1",
                             "o": {
                                 "a": 0,
                                 "ix": 5,
@@ -249,7 +249,7 @@
                             "lc": 1,
                             "lj": 2,
                             "mn": "ADBE Vector Graphic - Stroke",
-                            "nm": "Stroke 1",
+                            "nm": "$Stroke 1",
                             "o": {
                                 "a": 0,
                                 "ix": 4,