[skottie] Venetian Blinds effect
Change-Id: I50e133dea448e044fef45379490cb85b39eea3bc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/223856
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/modules/skottie/skottie.gni b/modules/skottie/skottie.gni
index f806dfc..9cb00fe 100644
--- a/modules/skottie/skottie.gni
+++ b/modules/skottie/skottie.gni
@@ -40,6 +40,7 @@
"$_src/effects/TintEffect.cpp",
"$_src/effects/TransformEffect.cpp",
"$_src/effects/TritoneEffect.cpp",
+ "$_src/effects/VenetianBlindsEffect.cpp",
"$_src/text/RangeSelector.cpp",
"$_src/text/RangeSelector.h",
diff --git a/modules/skottie/src/effects/Effects.cpp b/modules/skottie/src/effects/Effects.cpp
index 205533e..a141812 100644
--- a/modules/skottie/src/effects/Effects.cpp
+++ b/modules/skottie/src/effects/Effects.cpp
@@ -8,7 +8,7 @@
#include "modules/skottie/src/effects/Effects.h"
#include "modules/skottie/src/SkottieJson.h"
-#include "modules/sksg/include/SkSGRenderNode.h"
+#include "modules/sksg/include/SkSGRenderEffect.h"
#include "src/utils/SkJSON.h"
namespace skottie {
@@ -57,7 +57,8 @@
kLevelsEffectMN[] = "ADBE Easy Levels2",
kLinearWipeEffectMN[] = "ADBE Linear Wipe",
kMotionTileEffectMN[] = "ADBE Tile",
- kTransformEffectMN[] = "ADBE Geometry2";
+ kTransformEffectMN[] = "ADBE Geometry2",
+ kVenetianBlindsEffectMN[] = "ADBE Venetian Blinds";
if (const skjson::StringValue* mn = jeffect["mn"]) {
if (!strcmp(mn->begin(), kGradientEffectMN)) {
@@ -75,6 +76,9 @@
if (!strcmp(mn->begin(), kTransformEffectMN)) {
return &EffectBuilder::attachTransformEffect;
}
+ if (!strcmp(mn->begin(), kVenetianBlindsEffectMN)) {
+ return &EffectBuilder::attachVenetianBlindsEffect;
+ }
}
fBuilder->log(Logger::Level::kWarning, nullptr, "Unsupported layer effect type: %d.", ty);
@@ -123,5 +127,19 @@
return jprop ? (*jprop)["v"] : kNull;
}
+MaskFilterEffectBase::MaskFilterEffectBase(sk_sp<sksg::RenderNode> child, const SkSize& ls)
+ : fMaskNode(sksg::MaskFilter::Make(nullptr))
+ , fMaskEffectNode(sksg::MaskFilterEffect::Make(std::move(child), fMaskNode))
+ , fLayerSize(ls) {}
+
+MaskFilterEffectBase::~MaskFilterEffectBase() = default;
+
+void MaskFilterEffectBase::apply() const {
+ const auto minfo = this->onMakeMask();
+
+ fMaskEffectNode->setVisible(minfo.fVisible);
+ fMaskNode->setMaskFilter(std::move(minfo.fMask));
+}
+
} // namespace internal
} // namespace skottie
diff --git a/modules/skottie/src/effects/Effects.h b/modules/skottie/src/effects/Effects.h
index 2685b1f..4e0331c 100644
--- a/modules/skottie/src/effects/Effects.h
+++ b/modules/skottie/src/effects/Effects.h
@@ -10,6 +10,13 @@
#include "modules/skottie/src/SkottiePriv.h"
+class SkMaskFilter;
+
+namespace sksg {
+class MaskFilter;
+class MaskFilterEffect;
+} // namespace sksg
+
namespace skottie {
namespace internal {
@@ -24,28 +31,30 @@
using EffectBuilderT = sk_sp<sksg::RenderNode>(EffectBuilder::*)(const skjson::ArrayValue&,
sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachDropShadowEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachFillEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachGaussianBlurEffect(const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachGradientEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachLevelsEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachLinearWipeEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachMotionTileEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachRadialWipeEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachTintEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachTransformEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
- sk_sp<sksg::RenderNode> attachTritoneEffect (const skjson::ArrayValue&,
- sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachDropShadowEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachFillEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachGaussianBlurEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachGradientEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachLevelsEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachLinearWipeEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachMotionTileEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachRadialWipeEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachTintEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachTransformEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachTritoneEffect (const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
+ sk_sp<sksg::RenderNode> attachVenetianBlindsEffect(const skjson::ArrayValue&,
+ sk_sp<sksg::RenderNode>) const;
EffectBuilderT findBuilder(const skjson::ObjectValue&) const;
@@ -56,6 +65,35 @@
AnimatorScope* fScope;
};
+
+/**
+ * Base class for mask-filter-related effects.
+ */
+class MaskFilterEffectBase : public SkRefCnt {
+public:
+ ~MaskFilterEffectBase() override;
+
+ const sk_sp<sksg::MaskFilterEffect>& root() const { return fMaskEffectNode; }
+
+protected:
+ MaskFilterEffectBase(sk_sp<sksg::RenderNode>, const SkSize&);
+
+ const SkSize& layerSize() const { return fLayerSize; }
+
+ void apply() const;
+
+ struct MaskInfo {
+ sk_sp<SkMaskFilter> fMask;
+ bool fVisible;
+ };
+ virtual MaskInfo onMakeMask() const = 0;
+
+private:
+ const sk_sp<sksg::MaskFilter> fMaskNode;
+ const sk_sp<sksg::MaskFilterEffect> fMaskEffectNode;
+ const SkSize fLayerSize;
+};
+
} // namespace internal
} // namespace skottie
diff --git a/modules/skottie/src/effects/LinearWipeEffect.cpp b/modules/skottie/src/effects/LinearWipeEffect.cpp
index d906f46..42245e8 100644
--- a/modules/skottie/src/effects/LinearWipeEffect.cpp
+++ b/modules/skottie/src/effects/LinearWipeEffect.cpp
@@ -22,32 +22,25 @@
namespace {
-class LinearWipeAdapter final : public SkNVRefCnt<LinearWipeAdapter> {
+class LinearWipeAdapter final : public MaskFilterEffectBase {
public:
LinearWipeAdapter(sk_sp<sksg::RenderNode> layer, const SkSize& ls)
- : fMaskNode(sksg::MaskFilter::Make(nullptr))
- , fMaskEffectNode(sksg::MaskFilterEffect::Make(std::move(layer), fMaskNode))
- , fLayerSize(ls) {}
+ : INHERITED(std::move(layer), ls) {}
ADAPTER_PROPERTY(Completion, float, 0)
ADAPTER_PROPERTY(Angle , float, 0)
ADAPTER_PROPERTY(Feather , float, 0)
- const sk_sp<sksg::MaskFilterEffect>& root() const { return fMaskEffectNode; }
-
private:
- void apply() const {
+ MaskInfo onMakeMask() const override {
if (fCompletion >= 100) {
// The layer is fully disabled.
- fMaskEffectNode->setVisible(false);
- return;
+ return { nullptr, false };
}
- fMaskEffectNode->setVisible(true);
if (fCompletion <= 0) {
// The layer is fully visible (no mask).
- fMaskNode->setMaskFilter(nullptr);
- return;
+ return { nullptr, true };
}
const auto t = SkTPin(fCompletion * 0.01f, 0.0f, 1.0f),
@@ -58,8 +51,8 @@
// Select the correct diagonal vector depending on quadrant.
const SkVector angle_v = {cos_, sin_},
- diag_v = {std::copysign(fLayerSize.width() , cos_),
- std::copysign(fLayerSize.height(), sin_)};
+ diag_v = {std::copysign(this->layerSize().width() , cos_),
+ std::copysign(this->layerSize().height(), sin_)};
// The transition length is the projection of the diagonal onto the angle vector.
const auto len = SkVector::DotProduct(diag_v, angle_v);
@@ -68,7 +61,8 @@
const auto grad_len = len + feather * 2;
const SkVector grad_v = angle_v * grad_len,
adjusted_grad_v = { grad_v.fX, -grad_v.fY }, // Y flipped for drawing space.
- center_v = {fLayerSize.width() * 0.5f, fLayerSize.height() * 0.5f};
+ center_v = {0.5f * this->layerSize().width(),
+ 0.5f * this->layerSize().height()};
// Gradient start/end points:
const SkPoint pts[] = {
@@ -90,13 +84,12 @@
const SkScalar pos[] = { adjusted_t,
adjusted_t + feather / grad_len };
- fMaskNode->setMaskFilter(SkShaderMaskFilter::Make(
- SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp)));
+ return { SkShaderMaskFilter::Make(SkGradientShader::MakeLinear(pts, colors, pos, 2,
+ SkTileMode::kClamp)),
+ true };
}
- const sk_sp<sksg::MaskFilter> fMaskNode;
- const sk_sp<sksg::MaskFilterEffect> fMaskEffectNode;
- const SkSize fLayerSize;
+ using INHERITED = MaskFilterEffectBase;
};
} // namespace
diff --git a/modules/skottie/src/effects/VenetianBlindsEffect.cpp b/modules/skottie/src/effects/VenetianBlindsEffect.cpp
new file mode 100644
index 0000000..3b770c5
--- /dev/null
+++ b/modules/skottie/src/effects/VenetianBlindsEffect.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "modules/skottie/src/effects/Effects.h"
+
+#include "include/effects/SkGradientShader.h"
+#include "include/effects/SkShaderMaskFilter.h"
+#include "modules/skottie/src/SkottieAdapter.h"
+#include "modules/skottie/src/SkottieValue.h"
+#include "modules/sksg/include/SkSGRenderEffect.h"
+#include "src/utils/SkJSON.h"
+
+#include <cmath>
+
+namespace skottie {
+namespace internal {
+
+namespace {
+
+class VenetialBlindsAdapter final : public MaskFilterEffectBase {
+public:
+ VenetialBlindsAdapter(sk_sp<sksg::RenderNode> layer, const SkSize& ls)
+ : INHERITED(std::move(layer), ls) {}
+
+ ADAPTER_PROPERTY(Completion, float, 0)
+ ADAPTER_PROPERTY(Direction , float, 0)
+ ADAPTER_PROPERTY(Width , float, 0)
+ ADAPTER_PROPERTY(Feather , float, 0)
+
+private:
+ MaskInfo onMakeMask() const override {
+ if (fCompletion >= 100) {
+ // The layer is fully disabled.
+ return { nullptr, false };
+ }
+
+ if (fCompletion <= 0) {
+ // The layer is fully visible (no mask).
+ return { nullptr, true };
+ }
+
+ static constexpr float kFeatherSigmaFactor = 3.0f,
+ kMinFeather = 0.5f; // for soft gradient edges
+
+ const auto t = fCompletion * 0.01f,
+ size = std::max(1.0f, fWidth),
+ angle = SkDegreesToRadians(-fDirection),
+ feather = std::max(fFeather * kFeatherSigmaFactor, kMinFeather),
+ df = feather / size, // feather distance in normalized stop space
+ df0 = 0.5f * std::min(df, t),
+ df1 = 0.5f * std::min(df, 1 - t);
+
+ // In its simplest form, the Venetian Blinds effect is a single-step gradient
+ // repeating along the direction vector.
+ //
+ // To avoid an expensive blur pass, we emulate the feather property by softening
+ // the gradient edges:
+ //
+ // 1.0 [ | ------- ]
+ // [ | / \ ]
+ // [ | / \ ]
+ // [ | / \ ]
+ // [ | / \ ]
+ // [ | / \ ]
+ // [ | / \ ]
+ // [ |/ \]
+ // 0.5 [ | ]
+ // [\ /| ]
+ // [ \ / | ]
+ // [ \ / | ]
+ // [ \ / | ]
+ // [ \ / | ]
+ // [ \ / | ]
+ // [ \ / | ]
+ // 0.0 [ ------------------- | ]
+ //
+ // ^ ^ ^ ^ ^ ^ ^
+ // 0 fp0 fp1 T fp2 fp3 1
+ //
+ // | | | | | | |
+ // |< df0 >| |< df0 >|< df1 >| |< df1 >|
+ //
+ // ... df >| |< df >| |< df ...
+ //
+ // Note 1: fp0-fp1 and/or fp2-fp3 can collapse when df is large enough.
+ //
+ // Note 2: G(fp0) == G(fp1) and G(fp2) == G(fp3), whether collapsed or not.
+ //
+ // Note 3: to minimize the number of gradient stops, we can shift the gradient by -df0
+ // (such that fp0 aligns with 0/pts[0]).
+
+ // Gradient value at fp0/fp1, fp2/fp3.
+ // Note: g01 > 0 iff fp0-fp1 is collapsed and g23 < 1 iff fp2-fp3 is collapsed
+ const auto g01 = std::max(0.0f, 0.5f * (1 + (0 - t) / df)),
+ g23 = std::min(1.0f, 0.5f * (1 + (1 - t) / df));
+
+ const SkColor c01 = SkColorSetA(SK_ColorWHITE, SkScalarRoundToInt(g01 * 0xff)),
+ c23 = SkColorSetA(SK_ColorWHITE, SkScalarRoundToInt(g23 * 0xff)),
+ colors[] = { c01, c23, c23, c01 };
+
+ const SkScalar pos[] = {
+ // 0, // fp0
+ t - df0 - df0, // fp1
+ t + df1 - df0, // fp2
+ 1 - df1 - df0, // fp3
+ 1,
+ };
+ static_assert(SK_ARRAY_COUNT(colors) == SK_ARRAY_COUNT(pos), "");
+
+ const auto center = SkPoint::Make(0.5f * this->layerSize().width(),
+ 0.5f * this->layerSize().height()),
+ grad_vec = SkVector::Make( size * std::cos(angle),
+ -size * std::sin(angle));
+
+ const SkPoint pts[] = {
+ center + grad_vec * (df0 + 0),
+ center + grad_vec * (df0 + 1),
+ };
+
+ return {
+ SkShaderMaskFilter::Make(SkGradientShader::MakeLinear(pts, colors, pos,
+ SK_ARRAY_COUNT(colors),
+ SkTileMode::kRepeat,
+ 0, nullptr)),
+ true
+ };
+ }
+
+ using INHERITED = MaskFilterEffectBase;
+};
+
+} // namespace
+
+sk_sp<sksg::RenderNode> EffectBuilder::attachVenetianBlindsEffect(
+ const skjson::ArrayValue& jprops, sk_sp<sksg::RenderNode> layer) const {
+ enum : size_t {
+ kCompletion_Index = 0,
+ kDirection_Index = 1,
+ kWidth_Index = 2,
+ kFeather_Index = 3,
+ };
+
+ auto adapter = sk_make_sp<VenetialBlindsAdapter>(std::move(layer), fLayerSize);
+
+ fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kCompletion_Index), fScope,
+ [adapter](const ScalarValue& c) {
+ adapter->setCompletion(c);
+ });
+ fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kDirection_Index), fScope,
+ [adapter](const ScalarValue& d) {
+ adapter->setDirection(d);
+ });
+ fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kWidth_Index), fScope,
+ [adapter](const ScalarValue& w) {
+ adapter->setWidth(w);
+ });
+ fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kFeather_Index), fScope,
+ [adapter](const ScalarValue& f) {
+ adapter->setFeather(f);
+ });
+
+ return adapter->root();
+}
+
+} // namespace internal
+} // namespace skottie
diff --git a/resources/skottie/skottie-venetianblinds-effect.json b/resources/skottie/skottie-venetianblinds-effect.json
new file mode 100644
index 0000000..a161a5c
--- /dev/null
+++ b/resources/skottie/skottie-venetianblinds-effect.json
@@ -0,0 +1 @@
+{"v":"5.5.2","fr":60,"ip":0,"op":300,"w":500,"h":500,"nm":"blinds","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":1,"nm":"Green Solid 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,130,0],"ix":2},"a":{"a":0,"k":[125,125,0],"ix":1},"s":{"a":0,"k":[80,80,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Venetian Blinds","np":6,"mn":"ADBE Venetian Blinds","ix":1,"en":1,"ef":[{"ty":0,"nm":"Transition Completion","mn":"ADBE Venetian Blinds-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":150,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[100]},{"t":299,"s":[0]}],"ix":1}},{"ty":0,"nm":"Direction","mn":"ADBE Venetian Blinds-0002","ix":2,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":299,"s":[360]}],"ix":2}},{"ty":0,"nm":"Width","mn":"ADBE Venetian Blinds-0003","ix":3,"v":{"a":0,"k":50,"ix":3}},{"ty":0,"nm":"Feather","mn":"ADBE Venetian Blinds-0004","ix":4,"v":{"a":0,"k":0,"ix":4}}]}],"sw":250,"sh":250,"sc":"#00ff00","ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":1,"nm":"Green Solid 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130,370,0],"ix":2},"a":{"a":0,"k":[125,125,0],"ix":1},"s":{"a":0,"k":[80,80,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Venetian Blinds","np":6,"mn":"ADBE Venetian Blinds","ix":1,"en":1,"ef":[{"ty":0,"nm":"Transition Completion","mn":"ADBE Venetian Blinds-0001","ix":1,"v":{"a":0,"k":75,"ix":1}},{"ty":0,"nm":"Direction","mn":"ADBE Venetian Blinds-0002","ix":2,"v":{"a":0,"k":45,"ix":2}},{"ty":0,"nm":"Width","mn":"ADBE Venetian Blinds-0003","ix":3,"v":{"a":0,"k":100,"ix":3}},{"ty":0,"nm":"Feather","mn":"ADBE Venetian Blinds-0004","ix":4,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":150,"s":[150]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[150]},{"t":299,"s":[0]}],"ix":4}}]}],"sw":250,"sh":250,"sc":"#00ff00","ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[370,130,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[80,80,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Venetian Blinds","np":6,"mn":"ADBE Venetian Blinds","ix":1,"en":1,"ef":[{"ty":0,"nm":"Transition Completion","mn":"ADBE Venetian Blinds-0001","ix":1,"v":{"a":0,"k":50,"ix":1}},{"ty":0,"nm":"Direction","mn":"ADBE Venetian Blinds-0002","ix":2,"v":{"a":0,"k":0,"ix":2}},{"ty":0,"nm":"Width","mn":"ADBE Venetian Blinds-0003","ix":3,"v":{"a":0,"k":100,"ix":3}},{"ty":0,"nm":"Feather","mn":"ADBE Venetian Blinds-0004","ix":4,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":150,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[100]},{"t":299,"s":[0]}],"ix":4}}]}],"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":33,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":100,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.314644604921,0.276639103889,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[250,250],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,1,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[370,370,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[80,80,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Venetian Blinds","np":6,"mn":"ADBE Venetian Blinds","ix":1,"en":1,"ef":[{"ty":0,"nm":"Transition Completion","mn":"ADBE Venetian Blinds-0001","ix":1,"v":{"a":0,"k":29,"ix":1}},{"ty":0,"nm":"Direction","mn":"ADBE Venetian Blinds-0002","ix":2,"v":{"a":0,"k":0,"ix":2}},{"ty":0,"nm":"Width","mn":"ADBE Venetian Blinds-0003","ix":3,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":150,"s":[250]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[250]},{"t":299,"s":[1]}],"ix":3}},{"ty":0,"nm":"Feather","mn":"ADBE Venetian Blinds-0004","ix":4,"v":{"a":0,"k":5,"ix":4}}]}],"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":33,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":100,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.314644604921,0.276639103889,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[250,250],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,1,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":1,"nm":"Black Solid 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[250,250,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"sw":500,"sh":500,"sc":"#000000","ip":0,"op":300,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file