@pixodesk/svg-animator-react 1.0.15 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -1770,7 +1770,6 @@ var PixodeskAnimatorReact = (() => {
1770
1770
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
1771
1771
  var __hasOwnProp2 = Object.prototype.hasOwnProperty;
1772
1772
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
1773
- var __pow = Math.pow;
1774
1773
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1775
1774
  var __spreadValues = (a, b) => {
1776
1775
  for (var prop in b || (b = {}))
@@ -1805,7 +1804,10 @@ var PixodeskAnimatorReact = (() => {
1805
1804
  return rec;
1806
1805
  }
1807
1806
  function readAnimatable(raw) {
1808
- if (raw === void 0) return { kind: "absent" };
1807
+ if (raw === void 0) return {
1808
+ kind: "absent"
1809
+ /* Absent */
1810
+ };
1809
1811
  if (Array.isArray(raw)) return { kind: "static", value: raw };
1810
1812
  if (typeof raw === "object") {
1811
1813
  const obj = raw;
@@ -1952,7 +1954,7 @@ var PixodeskAnimatorReact = (() => {
1952
1954
  return outerWrapper;
1953
1955
  }
1954
1956
  function liftBodyTranslate(node, transformation) {
1955
- var _a;
1957
+ var _a, _b, _c;
1956
1958
  const out = {};
1957
1959
  let didLiftAnimate = false;
1958
1960
  const animTr = (_a = node.animate) == null ? void 0 : _a.transform;
@@ -2003,6 +2005,7 @@ var PixodeskAnimatorReact = (() => {
2003
2005
  }
2004
2006
  const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
2005
2007
  const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
2008
+ const liftedAnimateIsAutoOriented = didLiftAnimate && needsOriginOnOuter(((_b = node.animate) == null ? void 0 : _b.transform) || void 0) || didLiftAnimate && needsOriginOnOuter(((_c = out.animate) == null ? void 0 : _c.transform) || void 0);
2006
2009
  if (typeof node.transform === "string") {
2007
2010
  const split = splitTransformString(node.transform);
2008
2011
  if (stripBodyTranslateOnly) {
@@ -2011,6 +2014,8 @@ var PixodeskAnimatorReact = (() => {
2011
2014
  else delete node.transform;
2012
2015
  } else if (isPureTranslateBody(node.transform)) {
2013
2016
  delete node.transform;
2017
+ } else if (liftedAnimateIsAutoOriented && isSingleMatrixBody(node.transform)) {
2018
+ delete node.transform;
2014
2019
  }
2015
2020
  } else if (split.translate) {
2016
2021
  out.transform = split.translate;
@@ -2020,6 +2025,17 @@ var PixodeskAnimatorReact = (() => {
2020
2025
  }
2021
2026
  return out;
2022
2027
  }
2028
+ function isSingleMatrixBody(s) {
2029
+ const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
2030
+ let count = 0;
2031
+ let isMatrix = false;
2032
+ let m;
2033
+ while (m = re.exec(s)) {
2034
+ count++;
2035
+ if (m[1] === "matrix") isMatrix = true;
2036
+ }
2037
+ return count === 1 && isMatrix;
2038
+ }
2023
2039
  function isPureTranslateBody(s) {
2024
2040
  const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
2025
2041
  const ops = [];
@@ -2101,280 +2117,6 @@ var PixodeskAnimatorReact = (() => {
2101
2117
  }
2102
2118
  return false;
2103
2119
  }
2104
- function genId(ctx, prefix) {
2105
- return "_lw_" + prefix + "_" + ctx.nextId++;
2106
- }
2107
- function indexById(node, map) {
2108
- var _a;
2109
- if (typeof node.id === "string") map.set(node.id, node);
2110
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
2111
- }
2112
- function spliceDefs(root, defs) {
2113
- if (!defs.length) return;
2114
- const existing = root.children || (root.children = []);
2115
- existing.unshift({ type: "defs", children: defs });
2116
- }
2117
- function clone(value) {
2118
- if (value === null || typeof value !== "object") return value;
2119
- if (Array.isArray(value)) return value.map(clone);
2120
- const out = {};
2121
- for (const k of Object.keys(value)) out[k] = clone(value[k]);
2122
- return out;
2123
- }
2124
- function regenerateIdsInClone(root, ctx) {
2125
- const oldToNew = /* @__PURE__ */ new Map();
2126
- const walkAssign = (n) => {
2127
- var _a;
2128
- if (typeof n.id === "string") {
2129
- const newId = genId(ctx, "retimed");
2130
- oldToNew.set(n.id, newId);
2131
- n.id = newId;
2132
- }
2133
- (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
2134
- };
2135
- walkAssign(root);
2136
- const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
2137
- const newId = oldToNew.get(oldId);
2138
- return newId ? "url(#" + newId + ")" : m;
2139
- });
2140
- const walkRewrite = (n) => {
2141
- var _a;
2142
- if (typeof n.href === "string" && n.href.startsWith("#")) {
2143
- const newId = oldToNew.get(n.href.slice(1));
2144
- if (newId) n.href = "#" + newId;
2145
- }
2146
- for (const k of Object.keys(n)) {
2147
- if (k === "children" || k === "effects" || k === "meta" || k === "href" || k === "id") continue;
2148
- const v = n[k];
2149
- if (typeof v === "string" && v.indexOf("url(#") !== -1) n[k] = rewriteUrl(v);
2150
- }
2151
- (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
2152
- };
2153
- walkRewrite(root);
2154
- return oldToNew;
2155
- }
2156
- function applyMaskedByEffect(node, fx, transformation, ctx) {
2157
- if (!fx) return node;
2158
- if (!fx.href) {
2159
- ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
2160
- return node;
2161
- }
2162
- const maskId = genId(ctx, "mask");
2163
- let content = { type: "use", href: "#" + fx.href };
2164
- content = wrapInverseTransform(content, transformation, ctx);
2165
- const mask = { type: "mask", id: maskId, children: [content] };
2166
- if (fx.maskType) mask.maskType = fx.maskType;
2167
- if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
2168
- if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
2169
- ctx.defs.push(mask);
2170
- node.mask = "url(#" + maskId + ")";
2171
- return node;
2172
- }
2173
- function wrapInverseTransform(inner, fx, ctx) {
2174
- if (!fx) return inner;
2175
- const origin = readStaticOrigin(fx.origin, ctx);
2176
- let n = inner;
2177
- n = wrapInversePart(n, "translate", fx.translate, void 0, ctx);
2178
- n = wrapInversePart(n, "rotate", fx.rotate, origin, ctx);
2179
- n = wrapInversePart(n, "scale", fx.scale, origin, ctx);
2180
- return n;
2181
- }
2182
- function wrapInversePart(inner, part, raw, origin, ctx) {
2183
- if (raw === void 0) return inner;
2184
- const v = readAnimatable(raw);
2185
- if (v.kind === "static") {
2186
- return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
2187
- }
2188
- if (v.kind === "animated") {
2189
- return {
2190
- type: "g",
2191
- animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, invertPartValue(part, kf.value), origin))) } },
2192
- children: [inner]
2193
- };
2194
- }
2195
- return inner;
2196
- }
2197
- function invertPartValue(part, value) {
2198
- if (part === "translate") return [-value[0], -value[1]];
2199
- if (part === "rotate") return -value;
2200
- return [1 / value[0], 1 / value[1]];
2201
- }
2202
- var CONTENT_SUBREF = "content";
2203
- function applyRefAndTransformationEffect(node, ref, transformation, ctx) {
2204
- if (ref) {
2205
- const baseId = ref.baseId;
2206
- if (!baseId) {
2207
- ctx.errors.push("ref: missing baseId");
2208
- } else {
2209
- const targetId = ref.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
2210
- node.href = "#" + targetId;
2211
- }
2212
- }
2213
- return applyTransformationEffect(node, transformation, ctx);
2214
- }
2215
- function applyRepeaterEffect(node, fx, ctx) {
2216
- var _a, _b;
2217
- if (!fx) return node;
2218
- const copies = (_a = fx.copies) != null ? _a : 1;
2219
- if (copies < 1) {
2220
- ctx.errors.push("repeater.copies invalid: " + fx.copies);
2221
- return node;
2222
- }
2223
- const sharedTransform = node.transform;
2224
- const sharedAnimTransform = (_b = node.animate) == null ? void 0 : _b.transform;
2225
- const base = clone(node);
2226
- delete base.transform;
2227
- if (base.animate) {
2228
- delete base.animate.transform;
2229
- if (Object.keys(base.animate).length === 0) delete base.animate;
2230
- }
2231
- const children = [base];
2232
- for (let i = 1; i < copies; i++) {
2233
- const copy = clone(base);
2234
- copy.transform = { value: perCopyParts(fx, i) };
2235
- children.push(copy);
2236
- }
2237
- const wrapper = { type: "g", children };
2238
- if (sharedTransform !== void 0) wrapper.transform = sharedTransform;
2239
- if (sharedAnimTransform !== void 0) wrapper.animate = { transform: sharedAnimTransform };
2240
- return wrapper;
2241
- }
2242
- function perCopyParts(fx, i) {
2243
- const parts = {};
2244
- if (fx.translate) parts.translate = [fx.translate[0] * i, fx.translate[1] * i];
2245
- if (fx.rotate !== void 0) parts.rotate = fx.rotate * i;
2246
- if (fx.scale) parts.scale = [__pow(fx.scale[0] / 100, i), __pow(fx.scale[1] / 100, i)];
2247
- if (fx.origin) parts.origin = [fx.origin[0] * i, fx.origin[1] * i];
2248
- return parts;
2249
- }
2250
- var RETIME_AS_SYMBOL = true;
2251
- function applyRetimeEffect(node, retime, ctx) {
2252
- var _a, _b, _c, _d;
2253
- if (!retime) return node;
2254
- const baseId = retime.baseId;
2255
- if (!baseId) {
2256
- ctx.errors.push("retime: missing baseId");
2257
- return node;
2258
- }
2259
- const target = ctx.idMap.get(baseId);
2260
- if (!target) {
2261
- ctx.warnings.push('retime: target "' + baseId + '" not found');
2262
- return node;
2263
- }
2264
- const start = (_a = retime.start) != null ? _a : 0;
2265
- const stretch = (_b = retime.stretch) != null ? _b : 1;
2266
- if (RETIME_AS_SYMBOL) {
2267
- const symbolClone = clone(target);
2268
- regenerateIdsInClone(symbolClone, ctx);
2269
- const cloneId = genId(ctx, "retime");
2270
- symbolClone.id = cloneId;
2271
- remapKeyframeTimes(symbolClone, start, stretch);
2272
- ctx.defs.push(symbolClone);
2273
- node.href = "#" + cloneId;
2274
- return node;
2275
- }
2276
- const sourceNodes = target.type === "symbol" ? target.children || [] : [target];
2277
- const content = sourceNodes.map((child) => {
2278
- const c = clone(child);
2279
- regenerateIdsInClone(c, ctx);
2280
- remapKeyframeTimes(c, start, stretch);
2281
- return c;
2282
- });
2283
- const g = __spreadProps(__spreadValues({}, node), { type: "g", children: content });
2284
- delete g.href;
2285
- const x = Number((_c = node.x) != null ? _c : 0), y = Number((_d = node.y) != null ? _d : 0);
2286
- if (x || y) {
2287
- const offset = "translate(" + x + "," + y + ")";
2288
- g.transform = typeof g.transform === "string" ? offset + g.transform : offset;
2289
- delete g.x;
2290
- delete g.y;
2291
- }
2292
- return g;
2293
- }
2294
- function remapKeyframeTimes(node, start, stretch) {
2295
- var _a;
2296
- const remap2 = (kfs) => {
2297
- for (const kf of kfs) if (typeof kf.time === "number") kf.time = start + kf.time * stretch;
2298
- };
2299
- if (node.transform && typeof node.transform === "object" && Array.isArray(node.transform.keyframes)) {
2300
- remap2(node.transform.keyframes);
2301
- }
2302
- if (node.animate && typeof node.animate === "object") {
2303
- for (const prop of Object.keys(node.animate)) {
2304
- const anim = node.animate[prop];
2305
- if (anim && Array.isArray(anim.keyframes)) remap2(anim.keyframes);
2306
- }
2307
- }
2308
- (_a = node.children) == null ? void 0 : _a.forEach((child) => remapKeyframeTimes(child, start, stretch));
2309
- }
2310
- function applyTrimPathEffect(node, trimPath, isCombinedShape) {
2311
- var _a;
2312
- if (!trimPath && !isCombinedShape) return node;
2313
- const d = (_a = node.d) != null ? _a : rectToPathD(node);
2314
- if (d === void 0) return node;
2315
- const g = __spreadProps(__spreadValues({}, node), { type: "g" });
2316
- delete g.d;
2317
- const meta = g.meta = __spreadValues({}, g.meta || {});
2318
- const effects = meta.effects = __spreadValues({}, meta.effects || {});
2319
- if (trimPath) effects.trimPath = trimPath;
2320
- effects.isCombinedShape = true;
2321
- g.children = [{ type: "path", d }];
2322
- return g;
2323
- }
2324
- function rectToPathD(node) {
2325
- var _a, _b, _c, _d;
2326
- if (node.type !== "rect") return void 0;
2327
- const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
2328
- const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
2329
- return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
2330
- }
2331
- function applyPlayerEffects(root) {
2332
- const ctx = {
2333
- defs: [],
2334
- warnings: [],
2335
- errors: [],
2336
- idMap: /* @__PURE__ */ new Map(),
2337
- nextId: 0,
2338
- contentRefInnerIds: /* @__PURE__ */ new Map()
2339
- };
2340
- const working = clone(root);
2341
- indexById(working, ctx.idMap);
2342
- identifyContentRefTargets(working, ctx, () => genId(ctx, "inner"));
2343
- const afterPass1 = applyPlayerEffects_exceptRetime(working, ctx);
2344
- const out = applyPlayerEffects_retime(afterPass1, ctx);
2345
- spliceDefs(out, ctx.defs);
2346
- return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
2347
- }
2348
- function applyPlayerEffects_exceptRetime(node, ctx) {
2349
- if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
2350
- const fx = node.effects;
2351
- const originalId = typeof node.id === "string" ? node.id : void 0;
2352
- const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
2353
- if (!fx && !innerIdForContentRef) return node;
2354
- const { transformation, repeater, maskedBy, trimPath, retime, ref } = fx != null ? fx : {};
2355
- const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
2356
- if (fx) delete node.effects;
2357
- let n = node;
2358
- n = applyTrimPathEffect(n, trimPath, isCombinedShape);
2359
- n = applyRepeaterEffect(n, repeater, ctx);
2360
- n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
2361
- if (innerIdForContentRef) {
2362
- n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
2363
- } else {
2364
- n = applyRefAndTransformationEffect(n, ref, transformation, ctx);
2365
- }
2366
- if (retime) node.effects = { retime };
2367
- if (originalId) ctx.idMap.set(originalId, n);
2368
- return n;
2369
- }
2370
- function applyPlayerEffects_retime(node, ctx) {
2371
- var _a;
2372
- if (node.children) node.children = node.children.map((child) => applyPlayerEffects_retime(child, ctx));
2373
- const retime = (_a = node.effects) == null ? void 0 : _a.retime;
2374
- if (!retime) return node;
2375
- delete node.effects;
2376
- return applyRetimeEffect(node, retime, ctx);
2377
- }
2378
2120
  function pathStr(path) {
2379
2121
  if (!path.length) return ".";
2380
2122
  let result = "";
@@ -2817,6 +2559,15 @@ var PixodeskAnimatorReact = (() => {
2817
2559
  };
2818
2560
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
2819
2561
  var PX_ANIM_ATTR_NAME = "_px_animator";
2562
+ var PxAnimatorMode = {
2563
+ auto: "auto",
2564
+ webapi: "webapi",
2565
+ frames: "frames"
2566
+ };
2567
+ var PxAnimatorEngine = {
2568
+ webapi: PxAnimatorMode.webapi,
2569
+ frames: PxAnimatorMode.frames
2570
+ };
2820
2571
  var TEXT_ATTR = "text";
2821
2572
  var TEXT_CONTENT_ATTR = "textContent";
2822
2573
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
@@ -2898,7 +2649,7 @@ var PixodeskAnimatorReact = (() => {
2898
2649
  styles: px.record(px.any()).optional()
2899
2650
  }));
2900
2651
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
2901
- mode: px.enum(["auto", "webapi", "frames"]).optional(),
2652
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
2902
2653
  duration: px.number().optional(),
2903
2654
  delay: px.number().optional(),
2904
2655
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
@@ -2937,47 +2688,87 @@ var PixodeskAnimatorReact = (() => {
2937
2688
  autoOrient: px.boolean().optional()
2938
2689
  })
2939
2690
  ]);
2940
- var PxTransformationEffectSchema = px.object({
2691
+ var PxTransformationEffectSchema = implementsInterface()(px.object({
2941
2692
  translate: PxAnimatableVec2Schema.optional(),
2942
2693
  rotate: PxAnimatableNumberSchema.optional(),
2943
2694
  scale: PxAnimatableVec2Schema.optional(),
2944
2695
  skew: PxAnimatableVec2Schema.optional(),
2945
2696
  origin: PxAnimatableVec2Schema.optional()
2946
- });
2947
- var PxRepeaterEffectSchema = px.object({
2697
+ }));
2698
+ var PxRepeaterEffectSchema = implementsInterface()(px.object({
2948
2699
  copies: px.number().optional(),
2949
- translate: px.tuple([px.number(), px.number()]).optional(),
2950
- rotate: px.number().optional(),
2951
- scale: px.tuple([px.number(), px.number()]).optional(),
2952
- // per-copy scale, PERCENT (85 → 0.85)
2953
- origin: px.tuple([px.number(), px.number()]).optional()
2954
- });
2955
- var PxMaskedByEffectSchema = px.object({
2700
+ translate: PxAnimatableVec2Schema.optional(),
2701
+ rotate: PxAnimatableNumberSchema.optional(),
2702
+ scale: PxAnimatableVec2Schema.optional(),
2703
+ origin: PxAnimatableVec2Schema.optional()
2704
+ }));
2705
+ var PxMaskedByEffectSchema = implementsInterface()(px.object({
2956
2706
  href: px.string().optional(),
2957
2707
  maskType: px.string().optional(),
2958
2708
  maskUnits: px.string().optional(),
2959
2709
  maskContentUnits: px.string().optional()
2960
- });
2961
- var PxTrimPathEffectSchema = px.any();
2962
- var PxRetimeEffectSchema = px.object({
2710
+ }));
2711
+ var PxTrimPathEffectSchema = implementsInterface()(px.object({
2712
+ offset: PxAnimatableNumberSchema.optional(),
2713
+ range: PxAnimatableVec2Schema.optional(),
2714
+ trimAllAsOne: px.boolean().optional()
2715
+ }));
2716
+ var PxRetimeEffectSchema = implementsInterface()(px.object({
2963
2717
  baseId: px.string().optional(),
2964
2718
  start: px.number().optional(),
2965
2719
  stretch: px.number().optional(),
2966
2720
  timeCrop: px.tuple([px.number(), px.number()]).optional()
2967
- });
2968
- var PxRefEffectSchema = px.object({
2721
+ }));
2722
+ var PxRefEffectSchema = implementsInterface()(px.object({
2969
2723
  baseId: px.string().optional(),
2970
2724
  type: px.string().optional()
2971
- });
2972
- var PxEffectsSchema = px.object({
2725
+ }));
2726
+ var PxGradientType = {
2727
+ linear: "linear",
2728
+ radial: "radial"
2729
+ };
2730
+ var PxGradientStopSchema = implementsInterface()(px.object({
2731
+ offset: px.number(),
2732
+ color: px.string()
2733
+ }));
2734
+ var PxAnimatableGradientStopsSchema = px.union([
2735
+ px.array(PxGradientStopSchema),
2736
+ px.object({ value: px.array(PxGradientStopSchema) }),
2737
+ px.object({ keyframes: px.array(PxKeyframeSchema) })
2738
+ ]);
2739
+ var PxFillGradientEffectSchema = implementsInterface()(px.object({
2740
+ type: px.enum([PxGradientType.linear, PxGradientType.radial]),
2741
+ p1: px.tuple([px.number(), px.number()]).optional(),
2742
+ p2: px.tuple([px.number(), px.number()]).optional(),
2743
+ c: px.tuple([px.number(), px.number()]).optional(),
2744
+ r: px.number().optional(),
2745
+ fp: px.tuple([px.number(), px.number()]).optional(),
2746
+ stops: PxAnimatableGradientStopsSchema.optional(),
2747
+ gradientUnits: px.string().optional(),
2748
+ spreadMethod: px.string().optional(),
2749
+ gradientTransform: px.string().optional()
2750
+ }));
2751
+ var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
2752
+ var PxTextAlongPathEffectSchema = implementsInterface()(px.object({
2753
+ href: px.string(),
2754
+ lengthAdjust: px.string().optional(),
2755
+ method: px.string().optional(),
2756
+ spacing: px.string().optional(),
2757
+ startOffset: PxAnimatableNumberSchema.optional(),
2758
+ textLength: PxAnimatableNumberSchema.optional()
2759
+ }));
2760
+ var PxEffectsSchema = implementsInterface()(px.object({
2973
2761
  transformation: PxTransformationEffectSchema.optional(),
2974
2762
  repeater: PxRepeaterEffectSchema.optional(),
2975
2763
  maskedBy: PxMaskedByEffectSchema.optional(),
2976
2764
  trimPath: PxTrimPathEffectSchema.optional(),
2977
2765
  retime: PxRetimeEffectSchema.optional(),
2978
2766
  isCombinedShape: px.boolean().optional(),
2979
- ref: PxRefEffectSchema.optional()
2980
- });
2767
+ ref: PxRefEffectSchema.optional(),
2768
+ fillGradient: PxFillGradientEffectSchema.optional(),
2769
+ strokeGradient: PxStrokeGradientEffectSchema.optional(),
2770
+ textAlongPath: PxTextAlongPathEffectSchema.optional()
2771
+ }));
2981
2772
  function validateNodeEffects(root, opts) {
2982
2773
  const warnings = [];
2983
2774
  const walk = (node, path) => {
@@ -3003,7 +2794,10 @@ var PixodeskAnimatorReact = (() => {
3003
2794
  // Consumed and removed by `applyPlayerEffects` before any other normalisation
3004
2795
  // (see `createAnimatorImpl`), so downstream code never sees it.
3005
2796
  effects: PxEffectsSchema.optional(),
3006
- animate: PxAnimationDefinitionSchema.optional(),
2797
+ // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
2798
+ // string ref / array of refs / inline definition / mixed array; mirrors
2799
+ // `animator.animate` map values and what `processNode` resolves at runtime.
2800
+ animate: PxElementAnimationSchema.optional(),
3007
2801
  style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
3008
2802
  }, PxAttrValueSchema);
3009
2803
  var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
@@ -3048,772 +2842,1562 @@ var PixodeskAnimatorReact = (() => {
3048
2842
  if (!animate) return void 0;
3049
2843
  return Object.entries(animate).map(([id, anim]) => ({ id, animate: anim }));
3050
2844
  }
3051
- function bezierToSvgPath(path) {
3052
- var _a, _b, _c, _d;
3053
- const v = path.v;
3054
- const i = path.i;
3055
- const o = path.o;
3056
- const c = path.c;
3057
- if (!v.length) return "";
3058
- const d = [];
3059
- const len = v.length;
3060
- d.push("M" + v[0][0] + "," + v[0][1]);
3061
- for (let idx = 1; idx < len; idx++) {
3062
- const prevV = v[idx - 1];
3063
- const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
3064
- const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
3065
- const currV = v[idx];
3066
- const isLine = prevO[0] === prevV[0] && prevO[1] === prevV[1] && (currI[0] === currV[0] && currI[1] === currV[1]);
3067
- if (isLine) {
3068
- d.push("L" + currV[0] + "," + currV[1]);
3069
- } else {
3070
- d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
2845
+ function deepClonePxNode(value) {
2846
+ if (value === null || typeof value !== "object") return value;
2847
+ if (Array.isArray(value)) return value.map(deepClonePxNode);
2848
+ const out = {};
2849
+ for (const k of Object.keys(value)) out[k] = deepClonePxNode(value[k]);
2850
+ return out;
2851
+ }
2852
+ function regenerateIdsAndRewriteRefs(root, genId3) {
2853
+ const oldToNew = /* @__PURE__ */ new Map();
2854
+ const walkAssign = (n) => {
2855
+ var _a;
2856
+ if (typeof n.id === "string") {
2857
+ const newId = genId3();
2858
+ oldToNew.set(n.id, newId);
2859
+ n.id = newId;
3071
2860
  }
3072
- }
3073
- if (c && len > 0) {
3074
- const lastV = v[len - 1];
3075
- const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
3076
- const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
3077
- const firstV = v[0];
3078
- const isLine = lastO[0] === lastV[0] && lastO[1] === lastV[1] && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
3079
- if (!isLine) {
3080
- d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
2861
+ (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
2862
+ };
2863
+ walkAssign(root);
2864
+ const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
2865
+ const newId = oldToNew.get(oldId);
2866
+ return newId ? "url(#" + newId + ")" : m;
2867
+ });
2868
+ const walkRewrite = (n) => {
2869
+ var _a;
2870
+ if (typeof n.href === "string" && n.href.startsWith("#")) {
2871
+ const newId = oldToNew.get(n.href.slice(1));
2872
+ if (newId) n.href = "#" + newId;
3081
2873
  }
3082
- d.push("z");
3083
- }
3084
- return d.join("");
2874
+ for (const k of Object.keys(n)) {
2875
+ if (k === "children" || k === "effects" || k === "meta" || k === "animate" || k === "href" || k === "id") continue;
2876
+ const v = n[k];
2877
+ if (typeof v === "string" && v.indexOf("url(#") !== -1) {
2878
+ n[k] = rewriteUrl(v);
2879
+ }
2880
+ }
2881
+ (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
2882
+ };
2883
+ walkRewrite(root);
2884
+ return oldToNew;
3085
2885
  }
3086
- function interpolateNum(a, b, t) {
3087
- return a + (b - a) * t;
2886
+ function toFiniteNum(v) {
2887
+ const n = typeof v === "number" ? v : typeof v === "string" ? parseFloat(v) : NaN;
2888
+ return Number.isFinite(n) ? n : 0;
3088
2889
  }
3089
- function interpolateVec(a, b, t) {
3090
- const res = [];
3091
- const count = Math.max(a.length, b.length);
3092
- for (let i = 0; i < count; i++) {
3093
- res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
2890
+ function applyUseOffsetToG(gNode) {
2891
+ var _a;
2892
+ const x = toFiniteNum(gNode.x);
2893
+ const y = toFiniteNum(gNode.y);
2894
+ delete gNode.x;
2895
+ delete gNode.y;
2896
+ if (!x && !y) return gNode;
2897
+ const offset = "translate(" + x + "," + y + ")";
2898
+ const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
2899
+ if (carriesTransform) {
2900
+ const inner = { type: "g", transform: offset, children: (_a = gNode.children) != null ? _a : [] };
2901
+ gNode.children = [inner];
2902
+ } else {
2903
+ gNode.transform = offset;
3094
2904
  }
3095
- return res;
2905
+ return gNode;
3096
2906
  }
3097
- function interpolateColor(a, b, t) {
3098
- return [
3099
- interpolateNum(a[0] || 0, b[0] || 0, t),
3100
- interpolateNum(a[1] || 0, b[1] || 0, t),
3101
- interpolateNum(a[2] || 0, b[2] || 0, t),
3102
- interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
3103
- ];
2907
+ function genId(ctx, prefix) {
2908
+ return "_lw_" + prefix + "_" + ctx.nextId++;
3104
2909
  }
3105
- function interpolateBeziers(paths1, paths2, progress) {
3106
- const count = Math.max(paths1.length, paths2.length);
3107
- const res = [];
3108
- for (let i = 0; i < count; i++) {
3109
- res.push(interpolateBezier(paths1[i], paths2[i], progress));
3110
- }
3111
- return res;
2910
+ function stripHash(href) {
2911
+ return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3112
2912
  }
3113
- function interpolateBezier(path1, path2, progress) {
3114
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3115
- if (!path1 || !path2) return path1 || path2 || { v: [] };
3116
- const t = Math.min(Math.max(progress, 0), 1);
3117
- const len = Math.min(path1.v.length, path2.v.length);
3118
- const v = [];
3119
- const i = [];
3120
- const o = [];
3121
- for (let idx = 0; idx < len; idx++) {
3122
- const v1 = path1.v[idx];
3123
- const v2 = path2.v[idx];
3124
- v.push(interpolateVec(v1, v2, t));
3125
- const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
3126
- const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
3127
- i.push(interpolateVec(i1, i2, t));
3128
- const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
3129
- const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
3130
- o.push(interpolateVec(o1, o2, t));
3131
- }
3132
- return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
2913
+ function indexById(node, map) {
2914
+ var _a;
2915
+ if (typeof node.id === "string") map.set(node.id, node);
2916
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3133
2917
  }
3134
- function remap(value, inMin, inMax, outMin, outMax) {
3135
- if (inMax === inMin) return outMin;
3136
- const t = (value - inMin) / (inMax - inMin);
3137
- return outMin + t * (outMax - outMin);
2918
+ function spliceDefs(root, defs) {
2919
+ if (!defs.length) return;
2920
+ const existing = root.children || (root.children = []);
2921
+ existing.unshift({ type: "defs", children: defs });
3138
2922
  }
3139
- function solveCubicBezierX(p1x, p2x, x) {
3140
- if (x <= 0) return 0;
3141
- if (x >= 1) return 1;
3142
- const cx = 3 * p1x;
3143
- const bx = 3 * (p2x - p1x) - cx;
3144
- const ax = 1 - cx - bx;
3145
- function sampleX(t) {
3146
- return ((ax * t + bx) * t + cx) * t;
3147
- }
3148
- function sampleDX(t) {
3149
- return (3 * ax * t + 2 * bx) * t + cx;
3150
- }
3151
- let t2 = x;
3152
- let t0 = 0;
3153
- let t1 = 1;
3154
- for (let i = 0; i < 8; i++) {
3155
- const x2 = sampleX(t2) - x;
3156
- if (Math.abs(x2) < 1e-6) return t2;
3157
- const d2 = sampleDX(t2);
3158
- if (Math.abs(d2) < 1e-6) break;
3159
- t2 -= x2 / d2;
3160
- }
3161
- t2 = x;
3162
- while (t0 < t1) {
3163
- const x2 = sampleX(t2);
3164
- if (Math.abs(x2 - x) < 1e-6) return t2;
3165
- if (x > x2) t0 = t2;
3166
- else t1 = t2;
3167
- t2 = (t1 + t0) / 2;
3168
- }
3169
- return t2;
2923
+ var clone = deepClonePxNode;
2924
+ function regenerateIdsInClone(root, ctx) {
2925
+ return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3170
2926
  }
3171
- function cubicBezier(easing) {
3172
- const [p1x, p1y, p2x, p2y] = easing;
3173
- const cy = 3 * p1y;
3174
- const by = 3 * (p2y - p1y) - cy;
3175
- const ay = 1 - cy - by;
3176
- function sampleCurveY(t) {
3177
- return ((ay * t + by) * t + cy) * t;
3178
- }
3179
- return function(x) {
3180
- return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
3181
- };
2927
+ function applyFillGradientEffect(node, fx, ctx) {
2928
+ return applyGradient(node, fx, ctx, "fill");
3182
2929
  }
3183
- function lerp2(a, b, t) {
3184
- return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
2930
+ function applyStrokeGradientEffect(node, fx, ctx) {
2931
+ return applyGradient(node, fx, ctx, "stroke");
3185
2932
  }
3186
- function subdivideCubicBezier(p0, p1, p2, p3, t) {
3187
- const q0 = lerp2(p0, p1, t);
3188
- const q1 = lerp2(p1, p2, t);
3189
- const q2 = lerp2(p2, p3, t);
3190
- const r0 = lerp2(q0, q1, t);
3191
- const r1 = lerp2(q1, q2, t);
3192
- const s = lerp2(r0, r1, t);
3193
- return {
3194
- left: [p0, q0, r0, s],
3195
- right: [s, r1, q2, p3]
2933
+ function applyGradient(node, fx, ctx, attr) {
2934
+ if (!fx) return node;
2935
+ const id = genId(ctx, "grad");
2936
+ const def = synthesiseGradientDef(fx, id, ctx);
2937
+ ctx.defs.push(def);
2938
+ node[attr] = "url(#" + id + ")";
2939
+ return node;
2940
+ }
2941
+ function synthesiseGradientDef(fx, id, ctx) {
2942
+ const out = {
2943
+ type: fx.type === PxGradientType.radial ? "radialGradient" : "linearGradient",
2944
+ id
3196
2945
  };
2946
+ if (fx.type === PxGradientType.linear) {
2947
+ if (fx.p1) {
2948
+ out.x1 = String(fx.p1[0]);
2949
+ out.y1 = String(fx.p1[1]);
2950
+ }
2951
+ if (fx.p2) {
2952
+ out.x2 = String(fx.p2[0]);
2953
+ out.y2 = String(fx.p2[1]);
2954
+ }
2955
+ } else {
2956
+ if (fx.c) {
2957
+ out.cx = String(fx.c[0]);
2958
+ out.cy = String(fx.c[1]);
2959
+ }
2960
+ if (fx.r !== void 0) out.r = String(fx.r);
2961
+ if (fx.fp) {
2962
+ out.fx = String(fx.fp[0]);
2963
+ out.fy = String(fx.fp[1]);
2964
+ }
2965
+ }
2966
+ if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
2967
+ if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
2968
+ if (fx.gradientTransform) out.gradientTransform = fx.gradientTransform;
2969
+ out.children = buildStopChildren(fx.stops, ctx);
2970
+ return out;
3197
2971
  }
3198
- function splitEasing(easing, xFraction) {
3199
- if (!easing) return { left: void 0, right: void 0 };
3200
- if (xFraction <= 0) return { left: void 0, right: easing };
3201
- if (xFraction >= 1) return { left: easing, right: void 0 };
3202
- const [x1, y1, x2, y2] = easing;
3203
- const t = solveCubicBezierX(x1, x2, xFraction);
3204
- const p0 = [0, 0];
3205
- const p1 = [x1, y1];
3206
- const p2 = [x2, y2];
3207
- const p3 = [1, 1];
3208
- const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
3209
- const sx = left[3][0];
3210
- const sy = left[3][1];
3211
- let leftEasing;
3212
- if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
3213
- leftEasing = [
3214
- left[1][0] / sx,
3215
- left[1][1] / sy,
3216
- left[2][0] / sx,
3217
- left[2][1] / sy
3218
- ];
2972
+ function buildStopChildren(stops, ctx) {
2973
+ var _a, _b, _c, _d;
2974
+ if (!stops) return [];
2975
+ if (Array.isArray(stops)) return stops.map(staticStopNode);
2976
+ if (typeof stops === "object" && Array.isArray(stops.value)) {
2977
+ return stops.value.map(staticStopNode);
2978
+ }
2979
+ const animBlock = stops;
2980
+ const kfs = animBlock.keyframes;
2981
+ if (!Array.isArray(kfs) || !kfs.length) return [];
2982
+ let stopCount = 0;
2983
+ for (const kf of kfs) {
2984
+ const v = (_a = kf.value) != null ? _a : kf.v;
2985
+ if (Array.isArray(v) && v.length > stopCount) stopCount = v.length;
3219
2986
  }
3220
- let rightEasing;
3221
- const rx = 1 - sx;
3222
- const ry = 1 - sy;
3223
- if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
3224
- rightEasing = [
3225
- (right[1][0] - sx) / rx,
3226
- (right[1][1] - sy) / ry,
3227
- (right[2][0] - sx) / rx,
3228
- (right[2][1] - sy) / ry
3229
- ];
2987
+ if (!stopCount) return [];
2988
+ const firstKfValue = (_b = kfs[0].value) != null ? _b : kfs[0].v;
2989
+ const baselineStops = [];
2990
+ for (let i = 0; i < stopCount; i++) {
2991
+ const s = (_d = (_c = firstKfValue == null ? void 0 : firstKfValue[i]) != null ? _c : prevDefinedStop(kfs, 0, i)) != null ? _d : { offset: i / Math.max(1, stopCount - 1), color: "#000000" };
2992
+ baselineStops.push({ offset: s.offset, color: s.color });
3230
2993
  }
3231
- return { left: leftEasing, right: rightEasing };
3232
- }
3233
- function reverseEasing(easing) {
3234
- if (!easing) return void 0;
3235
- return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
2994
+ return baselineStops.map((bs, i) => animatedStopNode(bs, kfs, i, ctx));
3236
2995
  }
3237
- function toRGBA(color) {
3238
- const r = Math.round(color[0] * 255);
3239
- const g = Math.round(color[1] * 255);
3240
- const b = Math.round(color[2] * 255);
3241
- return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
2996
+ function staticStopNode(s) {
2997
+ return {
2998
+ type: "stop",
2999
+ offset: formatOffset(s.offset),
3000
+ stopColor: s.color
3001
+ };
3242
3002
  }
3243
- function parseRgba(s) {
3244
- var _a;
3245
- const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
3246
- if (!inner) throw new Error("Invalid rgb/rgba format");
3247
- const parts = inner.split(",").map((v) => +v.trim());
3248
- return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
3003
+ function animatedStopNode(baseline, kfs, stopIdx, _ctx) {
3004
+ var _a, _b, _c, _d, _e;
3005
+ const colorKfs = [];
3006
+ const offsetKfs = [];
3007
+ let offsetVaries = false;
3008
+ for (const kf of kfs) {
3009
+ const t = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
3010
+ const arr = (_c = kf.value) != null ? _c : kf.v;
3011
+ const sliced = (_d = arr == null ? void 0 : arr[stopIdx]) != null ? _d : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
3012
+ if (!sliced) continue;
3013
+ const easing = (_e = kf.easing) != null ? _e : kf.e;
3014
+ const colorOut = { time: t, value: sliced.color };
3015
+ if (easing !== void 0) colorOut.easing = easing;
3016
+ colorKfs.push(colorOut);
3017
+ const offsetOut = { time: t, value: sliced.offset };
3018
+ if (easing !== void 0) offsetOut.easing = easing;
3019
+ offsetKfs.push(offsetOut);
3020
+ if (sliced.offset !== baseline.offset) offsetVaries = true;
3021
+ }
3022
+ const stop = {
3023
+ type: "stop",
3024
+ offset: formatOffset(baseline.offset),
3025
+ stopColor: baseline.color
3026
+ };
3027
+ const animate = {};
3028
+ if (colorKfs.length) animate.stopColor = { keyframes: colorKfs };
3029
+ if (offsetVaries && offsetKfs.length) animate.offset = { keyframes: offsetKfs };
3030
+ if (Object.keys(animate).length) stop.animate = animate;
3031
+ return stop;
3249
3032
  }
3250
- function parseHex(s) {
3251
- const hex = s.slice(1);
3252
- const isShort = hex.length <= 4;
3253
- const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
3254
- const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
3255
- const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
3256
- const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
3257
- const result = [
3258
- parseInt(r, 16) / 255,
3259
- parseInt(g, 16) / 255,
3260
- parseInt(b, 16) / 255
3261
- ];
3262
- if (a !== null) {
3263
- result.push(parseInt(a, 16) / 255);
3033
+ function prevDefinedStop(kfs, fromIdx, stopIdx) {
3034
+ var _a, _b;
3035
+ for (let i = fromIdx; i >= 0; i--) {
3036
+ const arr = (_a = kfs[i].value) != null ? _a : kfs[i].v;
3037
+ if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3264
3038
  }
3265
- return result;
3266
- }
3267
- function parseColor(s) {
3268
- if (!s) return void 0;
3269
- if (Array.isArray(s)) return s;
3270
- if (typeof s !== "string") return void 0;
3271
- if (s.startsWith("#")) {
3272
- return parseHex(s);
3273
- } else if (s.startsWith("rgb")) {
3274
- return parseRgba(s);
3275
- } else {
3276
- console.warn("Unsupported color format: " + s);
3039
+ for (let i = fromIdx + 1; i < kfs.length; i++) {
3040
+ const arr = (_b = kfs[i].value) != null ? _b : kfs[i].v;
3041
+ if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3277
3042
  }
3278
3043
  return void 0;
3279
3044
  }
3280
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
3281
- var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
3282
- var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
3283
- function composeTransformParts(parts, opts) {
3284
- var _a;
3285
- if (!parts) return "";
3286
- const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
3287
- const segs = [];
3288
- const t = parts.translate;
3289
- const o = parts.origin;
3290
- const r = parts.rotate;
3291
- const s = parts.scale;
3292
- const tu = withUnits ? "px" : "";
3293
- const ru = withUnits ? "deg" : "";
3294
- if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
3295
- if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
3296
- if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
3297
- if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
3298
- if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
3299
- return segs.join("");
3045
+ function formatOffset(o) {
3046
+ const pct = Math.round(o * 1e3) / 10;
3047
+ return pct + "%";
3300
3048
  }
3301
- var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
3302
- var DEFAULT_DURATION_MS = 1e3;
3303
- function kebabToCamelCaseWord(kebab) {
3304
- return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
3305
- }
3306
- function isCamelCaseWord(word) {
3307
- return !word.includes("-") && /[a-z][A-Z]/.test(word);
3049
+ function applyMaskedByEffect(node, fx, transformation, ctx) {
3050
+ if (!fx) return node;
3051
+ if (!fx.href) {
3052
+ ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
3053
+ return node;
3054
+ }
3055
+ const maskId = genId(ctx, "mask");
3056
+ let content = { type: "use", href: "#" + fx.href };
3057
+ if (transformation) {
3058
+ content = wrapInverseTransform(content, transformation, ctx);
3059
+ } else if (hasAnimateTransform(node)) {
3060
+ content = wrapInverseAnimatedBodyTransform(content, node, ctx);
3061
+ } else {
3062
+ const bodyStatic = readTransformationFromBody(node);
3063
+ if (bodyStatic) content = wrapInverseTransform(content, bodyStatic, ctx);
3064
+ }
3065
+ const includeTargetOwn = transformation === void 0 && !nodeHasBodyTransform(node);
3066
+ content = wrapAncestorChainCompensation(content, node, fx.href, ctx, includeTargetOwn);
3067
+ const mask = { type: "mask", id: maskId, children: [content] };
3068
+ if (fx.maskType) mask.maskType = fx.maskType;
3069
+ if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
3070
+ if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
3071
+ ctx.defs.push(mask);
3072
+ node.mask = "url(#" + maskId + ")";
3073
+ return node;
3308
3074
  }
3309
- var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
3310
- // Transform/positioning
3311
- "viewBox",
3312
- "preserveAspectRatio",
3313
- // Gradient
3314
- "gradientUnits",
3315
- "gradientTransform",
3316
- "spreadMethod",
3317
- // Pattern
3318
- "patternUnits",
3319
- "patternContentUnits",
3320
- "patternTransform",
3321
- // Clipping/masking
3322
- "clipPathUnits",
3323
- "maskUnits",
3324
- "maskContentUnits",
3325
- // Text
3326
- "textLength",
3327
- "lengthAdjust",
3328
- "startOffset",
3329
- // Filter
3330
- "filterUnits",
3331
- "primitiveUnits",
3332
- "stdDeviation",
3333
- "baseFrequency",
3334
- "numOctaves",
3335
- "surfaceScale",
3336
- "diffuseConstant",
3337
- "specularConstant",
3338
- "specularExponent",
3339
- "kernelMatrix",
3340
- "kernelUnitLength",
3341
- "edgeMode",
3342
- "preserveAlpha",
3343
- "targetX",
3344
- "targetY"
3345
- // // Animation
3346
- // 'attributeName',
3347
- // 'attributeType',
3348
- // 'calcMode',
3349
- // 'keyTimes',
3350
- // 'keySplines',
3351
- // 'repeatCount',
3352
- // 'repeatDur'
3353
- ]);
3354
- function camelCaseToKebabWordIfNeeded(camel) {
3355
- return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
3075
+ function wrapInverseTransform(inner, fx, ctx) {
3076
+ if (!fx) return inner;
3077
+ const origin = readStaticOrigin(fx.origin, ctx);
3078
+ let n = inner;
3079
+ n = wrapInversePart(n, "translate", fx.translate, void 0, ctx);
3080
+ n = wrapInversePart(n, "rotate", fx.rotate, origin, ctx);
3081
+ n = wrapInversePart(n, "scale", fx.scale, origin, ctx);
3082
+ return n;
3356
3083
  }
3357
- function clamp(value, min, max) {
3358
- return Math.max(min, Math.min(value, max));
3084
+ function wrapInversePart(inner, part, raw, origin, ctx) {
3085
+ if (raw === void 0) return inner;
3086
+ const normalisedRaw = part === "scale" && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
3087
+ const v = readAnimatable(normalisedRaw);
3088
+ if (v.kind === "static") {
3089
+ return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
3090
+ }
3091
+ if (v.kind === "animated") {
3092
+ return {
3093
+ type: "g",
3094
+ animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, invertPartValue(part, kf.value), origin))) } },
3095
+ children: [inner]
3096
+ };
3097
+ }
3098
+ return inner;
3359
3099
  }
3360
- function bezier2D_pointAt(P0, P1, P2, P3, t) {
3361
- if (t <= 0) return [P0[0], P0[1]];
3362
- if (t >= 1) return [P3[0], P3[1]];
3363
- const u = 1 - t;
3364
- const u2 = u * u;
3365
- const u3 = u2 * u;
3366
- const t2 = t * t;
3367
- const t3 = t2 * t;
3368
- const w0 = u3;
3369
- const w1 = 3 * t * u2;
3370
- const w2 = 3 * t2 * u;
3371
- const w3 = t3;
3372
- return [
3373
- w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
3374
- w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
3375
- ];
3100
+ function invertPartValue(part, value) {
3101
+ if (part === "translate") return [-value[0], -value[1]];
3102
+ if (part === "rotate") return -value;
3103
+ return [1 / value[0], 1 / value[1]];
3376
3104
  }
3377
- var BEZIER_T_NUDGE = 1e-4;
3378
- function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
3379
- const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
3380
- if (result[0] === 0 && result[1] === 0) {
3381
- const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
3382
- return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
3105
+ function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
3106
+ var _a;
3107
+ const animate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3108
+ const animTr = animate == null ? void 0 : animate.transform;
3109
+ const kfs = animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes) ? animTr.keyframes : void 0;
3110
+ if (!kfs || !kfs.length) return inner;
3111
+ const translateKfs = [];
3112
+ const rotateKfs = [];
3113
+ const scaleKfs = [];
3114
+ for (const kf of kfs) {
3115
+ const v = ((_a = kf.value) != null ? _a : kf.v) || {};
3116
+ const baseKf = keyframeWith(kf, void 0);
3117
+ if (Array.isArray(v.translate)) {
3118
+ translateKfs.push(__spreadProps(__spreadValues({}, baseKf), { value: { translate: [-v.translate[0], -v.translate[1]] } }));
3119
+ }
3120
+ if (typeof v.rotate === "number") {
3121
+ const rec = { rotate: -v.rotate };
3122
+ if (Array.isArray(v.origin)) rec.origin = [v.origin[0], v.origin[1]];
3123
+ rotateKfs.push(__spreadProps(__spreadValues({}, baseKf), { value: rec }));
3124
+ }
3125
+ if (Array.isArray(v.scale)) {
3126
+ const rec = { scale: [1 / v.scale[0], 1 / v.scale[1]] };
3127
+ if (Array.isArray(v.origin)) rec.origin = [v.origin[0], v.origin[1]];
3128
+ scaleKfs.push(__spreadProps(__spreadValues({}, baseKf), { value: rec }));
3129
+ }
3383
3130
  }
3384
- return result;
3131
+ let n = inner;
3132
+ if (translateKfs.length) n = { type: "g", animate: { transform: { keyframes: translateKfs } }, children: [n] };
3133
+ if (rotateKfs.length) n = { type: "g", animate: { transform: { keyframes: rotateKfs } }, children: [n] };
3134
+ if (scaleKfs.length) n = { type: "g", animate: { transform: { keyframes: scaleKfs } }, children: [n] };
3135
+ return n;
3385
3136
  }
3386
- function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
3387
- const u = 1 - t;
3388
- const a = 3 * u * u;
3389
- const b = 6 * t * u;
3390
- const c = 3 * t * t;
3391
- return [
3392
- a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
3393
- a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
3394
- ];
3137
+ function nodeHasBodyTransform(node) {
3138
+ if (typeof node.transform === "string") return true;
3139
+ if (node.transform && typeof node.transform === "object") return true;
3140
+ return hasAnimateTransform(node);
3395
3141
  }
3396
- function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
3397
- const n = steps + 1;
3398
- const ts = new Float64Array(n);
3399
- const ds = new Float64Array(n);
3400
- let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
3401
- ts[0] = 0;
3402
- ds[0] = 0;
3403
- let cum = 0;
3404
- for (let i = 1; i < n; i++) {
3405
- const t = i / steps;
3406
- const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
3407
- const dx = cur[0] - prev[0];
3408
- const dy = cur[1] - prev[1];
3409
- cum += Math.sqrt(dx * dx + dy * dy);
3410
- ts[i] = t;
3411
- ds[i] = cum;
3412
- prev = cur;
3413
- }
3414
- return { ts, ds };
3142
+ function hasAnimateTransform(node) {
3143
+ const animate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3144
+ return !!(animate && animate.transform);
3415
3145
  }
3416
- function bezier2D_tForDistance(lut, distance) {
3417
- const { ts, ds } = lut;
3418
- const last = ds.length - 1;
3419
- if (distance <= 0) return ts[0];
3420
- if (distance >= ds[last]) return ts[last];
3421
- let lo = 1;
3422
- let hi = last;
3423
- while (lo < hi) {
3424
- const mid = lo + hi >>> 1;
3425
- if (ds[mid] < distance) lo = mid + 1;
3426
- else hi = mid;
3146
+ function readTransformationFromBody(node) {
3147
+ if (typeof node.transform === "string") {
3148
+ const parts = parseTransformStringToParts(node.transform);
3149
+ if (!parts) return void 0;
3150
+ const out = {};
3151
+ if (parts.translate) out.translate = parts.translate;
3152
+ if (parts.rotate !== void 0) out.rotate = parts.rotate;
3153
+ if (parts.scale) out.scale = { value: parts.scale };
3154
+ if (parts.origin) out.origin = parts.origin;
3155
+ return Object.keys(out).length ? out : void 0;
3427
3156
  }
3428
- const dPrev = ds[hi - 1];
3429
- const dCur = ds[hi];
3430
- const span = dCur - dPrev;
3431
- const frac = span > 0 ? (distance - dPrev) / span : 0;
3432
- return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
3157
+ return void 0;
3433
3158
  }
3434
- var SVG_NS = "http://www.w3.org/2000/svg";
3435
- var ALLOWED_SVG_TAGS_LOWER_CASE = new Set([
3436
- "svg",
3437
- "g",
3438
- "path",
3439
- "circle",
3440
- "ellipse",
3441
- "rect",
3442
- "line",
3443
- "polyline",
3444
- "polygon",
3445
- "text",
3446
- "tspan",
3447
- "textPath",
3448
- "defs",
3449
- "clipPath",
3450
- "mask",
3451
- "pattern",
3452
- "linearGradient",
3453
- "radialGradient",
3454
- "stop",
3455
- "use",
3456
- "symbol",
3457
- "marker",
3458
- "filter",
3459
- "feGaussianBlur",
3460
- "feOffset",
3461
- "feBlend",
3462
- "feColorMatrix",
3463
- "feMerge",
3464
- "feMergeNode"
3465
- ].map((tagName) => tagName.toLowerCase()));
3466
- var ALLOWED_RESOURCE_ATTRIBUTES = [
3467
- "href",
3468
- // <use>
3469
- "src",
3470
- // <image>
3471
- "filter",
3472
- // url(#filterId)
3473
- "clipPath",
3474
- // clip-path="url(#clipPathId)"
3475
- "mask",
3476
- // url(#maskId)
3477
- "markerStart",
3478
- // marker-start="url(#markerId)"
3479
- "markerMid",
3480
- // marker-mid="url(#markerId)"
3481
- "markerEnd"
3482
- // marker-end="url(#markerId)"
3483
- // 'fill', // url(#gradientId) or url(#patternId)
3484
- // 'stroke', // url(#gradientId) or url(#patternId)
3485
- // Don't allow 'cursor', can use external SVG, // url(cursor.svg)
3486
- ];
3487
- var ALLOWED_RESOURCE_ATTRIBUTES_SET = new Set(ALLOWED_RESOURCE_ATTRIBUTES);
3488
- var ALLOWED_ATTRIBUTES = [
3489
- "href",
3490
- "src",
3491
- // Presentation
3492
- "fill",
3493
- "fillOpacity",
3494
- "fillRule",
3495
- "stroke",
3496
- "strokeWidth",
3497
- "strokeOpacity",
3498
- "strokeLinecap",
3499
- "strokeLinejoin",
3500
- "strokeMiterlimit",
3501
- "strokeDasharray",
3502
- "strokeDashoffset",
3503
- "opacity",
3504
- "transform",
3505
- // Geometry
3506
- "x",
3507
- "y",
3508
- "cx",
3509
- "cy",
3510
- "r",
3511
- "rx",
3512
- "ry",
3513
- "width",
3514
- "height",
3515
- "d",
3516
- "x1",
3517
- "y1",
3518
- "x2",
3519
- "y2",
3520
- "points",
3521
- "dx",
3522
- "dy",
3523
- // Font
3524
- "fontSize",
3525
- "fontFamily",
3526
- "fontWeight",
3527
- "fontStyle",
3528
- // Text
3529
- "textAnchor",
3530
- "letterSpacing",
3531
- "wordSpacing",
3532
- "space",
3533
- "xml:space",
3534
- "textDecoration",
3535
- "textTransform",
3536
- "whiteSpace",
3537
- "white-space",
3538
- "dominantBaseline",
3539
- "alignmentBaseline",
3540
- "rotate",
3541
- // per-glyph rotation array, currently not supported
3542
- // Structure
3543
- "id",
3544
- "class",
3545
- "viewBox",
3546
- "preserveAspectRatio",
3547
- // Gradient/Pattern
3548
- "offset",
3549
- "stopColor",
3550
- "stopOpacity",
3551
- "gradientTransform",
3552
- // Clippath/Mask
3553
- "clipPath",
3554
- "mask",
3555
- // Motion path
3556
- "offsetPath",
3557
- "offsetDistance",
3558
- "offsetRotate",
3559
- "offsetAnchor",
3560
- "offsetPosition",
3561
- // Text path
3562
- "startOffset",
3563
- "textLength",
3564
- "lengthAdjust",
3565
- // Filter
3566
- "filter",
3567
- "stdDeviation",
3568
- "in",
3569
- "in2",
3570
- "result",
3571
- "mode",
3572
- ...ALLOWED_RESOURCE_ATTRIBUTES
3573
- ];
3574
- var ALLOWED_ATTRIBUTES_LOW_SET = new Set(ALLOWED_ATTRIBUTES.map((str) => str.toLowerCase()));
3575
- function sanitiseAttributeValue(name, value) {
3576
- const nameLower = name.toLowerCase();
3577
- if (!ALLOWED_ATTRIBUTES_LOW_SET.has(nameLower)) {
3578
- console.warn("Attribute not in whitelist: ", nameLower);
3579
- return void 0;
3580
- }
3581
- if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopColor") {
3582
- const str = String(value);
3583
- if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
3584
- console.warn('Attribute "' + nameLower + '" blocked: url() references must be internal url(#id), got:', value);
3585
- return void 0;
3159
+ function parseTransformStringToParts(s) {
3160
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
3161
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
3162
+ let m;
3163
+ const ops = [];
3164
+ while ((m = re.exec(s)) !== null) {
3165
+ const args = m[2].split(/[\s,]+/).filter((a) => a.length > 0).map(Number);
3166
+ ops.push({ name: m[1], args });
3167
+ }
3168
+ if (!ops.length) return void 0;
3169
+ const last = ops[ops.length - 1];
3170
+ if (last.name === "translate") {
3171
+ for (let j = ops.length - 2; j >= 0; j--) {
3172
+ const cand = ops[j];
3173
+ if (cand.name !== "translate") continue;
3174
+ const ox = (_a = cand.args[0]) != null ? _a : 0;
3175
+ const oy = (_b = cand.args[1]) != null ? _b : 0;
3176
+ const lx = (_c = last.args[0]) != null ? _c : 0;
3177
+ const ly = (_d = last.args[1]) != null ? _d : 0;
3178
+ if (lx !== -ox || ly !== -oy) continue;
3179
+ const out2 = {};
3180
+ out2.origin = [ox, oy];
3181
+ for (let k = 0; k < j; k++) {
3182
+ if (ops[k].name === "translate") {
3183
+ const tx = (_e = ops[k].args[0]) != null ? _e : 0;
3184
+ const ty = (_f = ops[k].args[1]) != null ? _f : 0;
3185
+ out2.translate = out2.translate ? [out2.translate[0] + tx, out2.translate[1] + ty] : [tx, ty];
3186
+ }
3187
+ }
3188
+ for (let k = j + 1; k < ops.length - 1; k++) {
3189
+ const op = ops[k];
3190
+ if (op.name === "rotate") out2.rotate = ((_g = out2.rotate) != null ? _g : 0) + ((_h = op.args[0]) != null ? _h : 0);
3191
+ else if (op.name === "scale") {
3192
+ const sx = (_i = op.args[0]) != null ? _i : 1;
3193
+ const sy = op.args.length > 1 ? op.args[1] : sx;
3194
+ out2.scale = out2.scale ? [out2.scale[0] * sx, out2.scale[1] * sy] : [sx, sy];
3195
+ }
3196
+ }
3197
+ return out2;
3586
3198
  }
3587
- return value;
3588
3199
  }
3589
- if (ALLOWED_RESOURCE_ATTRIBUTES_SET.has(nameLower)) {
3590
- const str = String(value);
3591
- if (str.startsWith("#")) {
3592
- return value;
3200
+ let translate;
3201
+ let rotate;
3202
+ let scale;
3203
+ for (const op of ops) {
3204
+ if (op.name === "translate") {
3205
+ const dx = (_j = op.args[0]) != null ? _j : 0;
3206
+ const dy = (_k = op.args[1]) != null ? _k : 0;
3207
+ translate = translate ? [translate[0] + dx, translate[1] + dy] : [dx, dy];
3208
+ } else if (op.name === "rotate") {
3209
+ rotate = (rotate != null ? rotate : 0) + ((_l = op.args[0]) != null ? _l : 0);
3210
+ } else if (op.name === "scale") {
3211
+ const sx = (_m = op.args[0]) != null ? _m : 1;
3212
+ const sy = op.args.length > 1 ? op.args[1] : sx;
3213
+ scale = scale ? [scale[0] * sx, scale[1] * sy] : [sx, sy];
3593
3214
  }
3594
- if (/^url\(#[^)]+\)$/.test(str)) {
3595
- return value;
3596
- }
3597
- return void 0;
3598
3215
  }
3599
- return value;
3216
+ const out = {};
3217
+ if (translate) out.translate = translate;
3218
+ if (rotate !== void 0) out.rotate = rotate;
3219
+ if (scale) out.scale = scale;
3220
+ return Object.keys(out).length ? out : void 0;
3600
3221
  }
3601
- function createElement(tagName, normalisedProps, style, children, textContent) {
3602
- if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) {
3603
- console.warn("Attribute not in whitelist: ", tagName);
3604
- return null;
3605
- }
3606
- const element = document.createElementNS(SVG_NS, tagName);
3607
- for (const propName in normalisedProps) {
3608
- element.setAttribute(
3609
- camelCaseToKebabWordIfNeeded(propName),
3610
- sanitiseAttributeValue(propName, normalisedProps[propName])
3611
- );
3222
+ function wrapAncestorChainCompensation(inner, maskedNode, sourceId, ctx, includeTargetOwn) {
3223
+ const sourceNode = ctx.idMap.get(sourceId);
3224
+ const targetAncestors = ctx.maskAncestorChains.get(maskedNode) || [];
3225
+ const targetOwn = includeTargetOwn ? extractTranslateOnly(maskedNode, ctx) : void 0;
3226
+ const targetChain = targetOwn ? [...targetAncestors, targetOwn] : targetAncestors;
3227
+ const sourceChain = sourceNode && ctx.maskAncestorChains.get(sourceNode) || [];
3228
+ if (!targetChain.length && !sourceChain.length) return inner;
3229
+ const times = /* @__PURE__ */ new Set();
3230
+ for (const a of targetChain) if (a.translateKeyframes) for (const kf of a.translateKeyframes) times.add(kf.time);
3231
+ for (const a of sourceChain) if (a.translateKeyframes) for (const kf of a.translateKeyframes) times.add(kf.time);
3232
+ const animated = times.size > 0;
3233
+ if (!animated) {
3234
+ const tgt = sumStaticTranslate(targetChain);
3235
+ const src = sumStaticTranslate(sourceChain);
3236
+ const dx = src[0] - tgt[0];
3237
+ const dy = src[1] - tgt[1];
3238
+ if (dx === 0 && dy === 0) return inner;
3239
+ return { type: "g", transform: "translate(" + dx + "," + dy + ")", children: [inner] };
3240
+ }
3241
+ const sortedTimes = Array.from(times).sort((a, b) => a - b);
3242
+ const keyframes = sortedTimes.map((t) => {
3243
+ const tgt = sumTranslateAt(targetChain, t);
3244
+ const src = sumTranslateAt(sourceChain, t);
3245
+ return { time: t, value: { translate: [src[0] - tgt[0], src[1] - tgt[1]] } };
3246
+ });
3247
+ return { type: "g", animate: { transform: { keyframes } }, children: [inner] };
3248
+ }
3249
+ function sumStaticTranslate(chain) {
3250
+ let x = 0, y = 0;
3251
+ for (const a of chain) {
3252
+ if (a.translate) {
3253
+ x += a.translate[0];
3254
+ y += a.translate[1];
3255
+ }
3612
3256
  }
3613
- if (style) {
3614
- for (const styleProp in style) {
3615
- element.style[styleProp] = String(style[styleProp]);
3257
+ return [x, y];
3258
+ }
3259
+ function sumTranslateAt(chain, t) {
3260
+ let x = 0, y = 0;
3261
+ for (const a of chain) {
3262
+ if (a.translateKeyframes && a.translateKeyframes.length) {
3263
+ const v = interpKfs(a.translateKeyframes, t);
3264
+ x += v[0];
3265
+ y += v[1];
3266
+ } else if (a.translate) {
3267
+ x += a.translate[0];
3268
+ y += a.translate[1];
3269
+ }
3270
+ }
3271
+ return [x, y];
3272
+ }
3273
+ function interpKfs(kfs, t) {
3274
+ if (t <= kfs[0].time) return kfs[0].value;
3275
+ if (t >= kfs[kfs.length - 1].time) return kfs[kfs.length - 1].value;
3276
+ for (let i = 1; i < kfs.length; i++) {
3277
+ if (t <= kfs[i].time) {
3278
+ const prev = kfs[i - 1];
3279
+ const cur = kfs[i];
3280
+ const a = (t - prev.time) / (cur.time - prev.time);
3281
+ return [prev.value[0] + (cur.value[0] - prev.value[0]) * a, prev.value[1] + (cur.value[1] - prev.value[1]) * a];
3282
+ }
3283
+ }
3284
+ return kfs[kfs.length - 1].value;
3285
+ }
3286
+ function collectMaskAncestorChains(root, ctx) {
3287
+ const interestingNodes = /* @__PURE__ */ new Set();
3288
+ const collectInterestingNodes = (n) => {
3289
+ var _a, _b;
3290
+ const href = (_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.href;
3291
+ if (typeof href === "string") {
3292
+ interestingNodes.add(n);
3293
+ const sourceNode = ctx.idMap.get(href);
3294
+ if (sourceNode) interestingNodes.add(sourceNode);
3295
+ }
3296
+ if (Array.isArray(n.children)) for (const ch of n.children) collectInterestingNodes(ch);
3297
+ };
3298
+ collectInterestingNodes(root);
3299
+ if (interestingNodes.size === 0) return;
3300
+ const walk = (node, chain) => {
3301
+ if (interestingNodes.has(node)) ctx.maskAncestorChains.set(node, chain);
3302
+ if (Array.isArray(node.children)) {
3303
+ const own = extractTranslateOnly(node, ctx);
3304
+ const next = own ? [...chain, own] : chain;
3305
+ for (const ch of node.children) walk(ch, next);
3306
+ }
3307
+ };
3308
+ walk(root, []);
3309
+ }
3310
+ function extractTranslateOnly(node, ctx) {
3311
+ var _a, _b, _c;
3312
+ const tr = node.transform;
3313
+ const animateBlock = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate.transform : void 0;
3314
+ if (tr === void 0 && !animateBlock) return void 0;
3315
+ const out = {};
3316
+ if (typeof tr === "string") {
3317
+ const parts = parseTranslateOnlyFromString(tr, ctx);
3318
+ if (parts) out.translate = parts;
3319
+ } else if (tr && typeof tr === "object") {
3320
+ const value = tr.value;
3321
+ if (value && typeof value === "object" && Array.isArray(value.translate)) {
3322
+ out.translate = [value.translate[0] || 0, value.translate[1] || 0];
3323
+ }
3324
+ if (value && (value.rotate !== void 0 || value.scale !== void 0 || value.skew !== void 0)) {
3325
+ ctx.warnings.push("maskedBy ancestor: non-translate transform parts ignored (rotate/scale not yet supported)");
3326
+ }
3327
+ }
3328
+ if (animateBlock && Array.isArray(animateBlock.keyframes)) {
3329
+ const kfs = animateBlock.keyframes;
3330
+ const translateKfs = [];
3331
+ for (const kf of kfs) {
3332
+ const v = (_a = kf.value) != null ? _a : kf.v;
3333
+ const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
3334
+ if (v && typeof v === "object" && Array.isArray(v.translate)) {
3335
+ translateKfs.push({ time: t, value: [v.translate[0] || 0, v.translate[1] || 0] });
3336
+ if (v.rotate !== void 0 || v.scale !== void 0 || v.skew !== void 0) {
3337
+ ctx.warnings.push("maskedBy ancestor: animated non-translate parts ignored");
3338
+ }
3339
+ }
3616
3340
  }
3341
+ if (translateKfs.length) out.translateKeyframes = translateKfs;
3617
3342
  }
3618
- if (children) {
3619
- for (const child of children) {
3620
- element.appendChild(child);
3343
+ return out.translate || out.translateKeyframes ? out : void 0;
3344
+ }
3345
+ function parseTranslateOnlyFromString(s, ctx) {
3346
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
3347
+ let m;
3348
+ let x = 0, y = 0;
3349
+ let seen = false;
3350
+ let droppedNonTranslate = false;
3351
+ while ((m = re.exec(s)) !== null) {
3352
+ const name = m[1];
3353
+ const args = m[2].split(/[\s,]+/).filter((a) => a.length > 0).map(Number);
3354
+ if (name === "translate") {
3355
+ x += args[0] || 0;
3356
+ y += args[1] || 0;
3357
+ seen = true;
3358
+ } else {
3359
+ droppedNonTranslate = true;
3621
3360
  }
3622
3361
  }
3623
- if (textContent) element.textContent = textContent;
3624
- return element;
3362
+ if (droppedNonTranslate) ctx.warnings.push("maskedBy ancestor: non-translate transform in string ignored: " + s);
3363
+ return seen ? [x, y] : void 0;
3625
3364
  }
3626
- function resolveStyle(style, defs) {
3627
- var _a;
3628
- if (!style) return void 0;
3629
- if (typeof style === "string") {
3630
- return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
3631
- }
3632
- return style;
3633
- }
3634
- function getNormalizedProps(props) {
3635
- const propsCopy = {};
3636
- for (const key of Object.keys(props)) {
3637
- if (INTERNAL_ATTRS.has(key)) continue;
3638
- if (key === "style") continue;
3639
- let value = props[key];
3640
- if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
3641
- propsCopy[key] = toRGBA(value);
3642
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
3643
- propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
3644
- } else if (TRANSFORM_FN_NAMES.has(key)) {
3645
- if (Array.isArray(value)) {
3646
- if (key === "translate") value = value.map((v) => v + "px");
3647
- value = value.join(",");
3648
- }
3649
- if (key === "rotate") value = value + "deg";
3650
- propsCopy["transform"] = key + "(" + value + ")";
3651
- } else if (value !== void 0 && value !== null) {
3652
- propsCopy[key] = String(value);
3365
+ var CONTENT_SUBREF = "content";
3366
+ function applyRefAndTransformationEffect(node, ref, transformation, ctx) {
3367
+ if (ref) {
3368
+ const baseId = ref.baseId;
3369
+ if (!baseId) {
3370
+ ctx.errors.push("ref: missing baseId");
3371
+ } else {
3372
+ const targetId = ref.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
3373
+ node.href = "#" + targetId;
3653
3374
  }
3654
3375
  }
3655
- return propsCopy;
3376
+ return applyTransformationEffect(node, transformation, ctx);
3656
3377
  }
3657
- function renderNode(node, defs) {
3658
- if (!node) return null;
3659
- const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
3660
- const nodeDefs = getDefs(node) || defs;
3661
- const resolvedStyle = resolveStyle(style, nodeDefs);
3662
- let childElements;
3663
- if (children) {
3664
- for (const ch of children) {
3665
- const child = renderNode(ch, nodeDefs);
3666
- if (child) {
3667
- if (!childElements) childElements = [];
3668
- childElements.push(child);
3669
- }
3670
- }
3378
+ function applyRepeaterEffect(node, fx, ctx) {
3379
+ var _a, _b;
3380
+ if (!fx) return node;
3381
+ const copies = (_a = fx.copies) != null ? _a : 1;
3382
+ if (copies < 1) {
3383
+ ctx.errors.push("repeater.copies invalid: " + fx.copies);
3384
+ return node;
3671
3385
  }
3672
- return createElement(
3673
- type || "g",
3674
- getNormalizedProps(props),
3675
- resolvedStyle,
3676
- childElements,
3677
- props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
3678
- );
3386
+ const sharedTransform = node.transform;
3387
+ const sharedAnimTransform = (_b = node.animate) == null ? void 0 : _b.transform;
3388
+ const base = clone(node);
3389
+ delete base.transform;
3390
+ if (base.animate) {
3391
+ delete base.animate.transform;
3392
+ if (Object.keys(base.animate).length === 0) delete base.animate;
3393
+ }
3394
+ const children = [base];
3395
+ for (let i = 1; i < copies; i++) {
3396
+ const baseClone = clone(base);
3397
+ const synthFx = synthesisePerCopyFx(fx, i);
3398
+ const wrapped = synthFx ? applyTransformationEffect(baseClone, synthFx, ctx) : baseClone;
3399
+ children.push(wrapped);
3400
+ }
3401
+ const wrapper = { type: "g", children };
3402
+ if (sharedTransform !== void 0) wrapper.transform = sharedTransform;
3403
+ if (sharedAnimTransform !== void 0) wrapper.animate = { transform: sharedAnimTransform };
3404
+ return wrapper;
3679
3405
  }
3680
- function setupAnimationTriggers(api, config) {
3681
- const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
3682
- const root = api.getRootElement();
3683
- if (!root) {
3684
- console.warn("setupAnimationTriggers: No root element found for animation.");
3685
- return api;
3406
+ function synthesisePerCopyFx(fx, i) {
3407
+ const out = {};
3408
+ if (fx.translate !== void 0) {
3409
+ out.translate = mapAnimatableVec2(fx.translate, (v) => [v[0] * i, v[1] * i]);
3686
3410
  }
3687
- const start = () => {
3688
- api.play();
3689
- };
3690
- const handleEndAction = () => {
3691
- switch (outAction) {
3692
- case "pause":
3693
- api.pause();
3694
- break;
3695
- case "reset":
3696
- api.cancel();
3697
- break;
3698
- case "reverse":
3699
- api.play();
3700
- break;
3701
- case "continue":
3702
- default:
3703
- break;
3411
+ if (fx.rotate !== void 0) {
3412
+ out.rotate = mapAnimatableNumber(fx.rotate, (v) => v * i);
3413
+ }
3414
+ if (fx.scale !== void 0) {
3415
+ out.scale = synthesiseScale(fx.scale, i);
3416
+ }
3417
+ if (fx.origin !== void 0) {
3418
+ out.origin = fx.origin;
3419
+ }
3420
+ return Object.keys(out).length ? out : void 0;
3421
+ }
3422
+ function mapAnimatableVec2(raw, fn) {
3423
+ if (Array.isArray(raw)) return fn(raw);
3424
+ if (raw && typeof raw === "object") {
3425
+ const obj = raw;
3426
+ if (Array.isArray(obj.keyframes)) {
3427
+ return __spreadProps(__spreadValues({}, obj), {
3428
+ keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: fn(kf.value) }) : kf)
3429
+ });
3704
3430
  }
3705
- };
3706
- switch (startOn) {
3707
- case "load": {
3708
- const startHandler = () => start();
3709
- if (document.readyState === "complete") {
3710
- startHandler();
3711
- } else {
3712
- window.addEventListener("load", startHandler, { once: true });
3713
- }
3714
- break;
3431
+ if (obj.value !== void 0) {
3432
+ return __spreadProps(__spreadValues({}, obj), { value: fn(obj.value) });
3715
3433
  }
3716
- case "mouseOver": {
3717
- const mouseOverHandler = () => start();
3718
- const mouseOutHandler = () => handleEndAction();
3719
- root.addEventListener("mouseenter", mouseOverHandler);
3720
- root.addEventListener("mouseleave", mouseOutHandler);
3721
- break;
3434
+ }
3435
+ return raw;
3436
+ }
3437
+ function mapAnimatableNumber(raw, fn) {
3438
+ if (typeof raw === "number") return fn(raw);
3439
+ if (raw && typeof raw === "object") {
3440
+ const obj = raw;
3441
+ if (Array.isArray(obj.keyframes)) {
3442
+ return __spreadProps(__spreadValues({}, obj), {
3443
+ keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: fn(kf.value) }) : kf)
3444
+ });
3722
3445
  }
3723
- case "click": {
3724
- const clickHandler = () => {
3725
- if (api.isPlaying()) {
3726
- handleEndAction();
3727
- } else {
3728
- start();
3729
- }
3730
- };
3731
- root.addEventListener("click", clickHandler);
3732
- break;
3446
+ if (obj.value !== void 0) {
3447
+ return __spreadProps(__spreadValues({}, obj), { value: fn(obj.value) });
3733
3448
  }
3734
- case "scrollIntoView": {
3735
- const observer = new IntersectionObserver(
3736
- (entries) => {
3737
- entries.forEach((entry) => {
3738
- if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
3739
- start();
3740
- } else {
3741
- handleEndAction();
3742
- }
3743
- });
3744
- },
3745
- { threshold: scrollIntoViewThreshold }
3746
- );
3747
- observer.observe(root);
3748
- break;
3449
+ }
3450
+ return raw;
3451
+ }
3452
+ function synthesiseScale(raw, i) {
3453
+ const scalePowerFromPercent = (v) => [Math.pow(v[0] / 100, i), Math.pow(v[1] / 100, i)];
3454
+ const scalePowerFromUnits = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
3455
+ if (Array.isArray(raw)) {
3456
+ return { value: scalePowerFromPercent(raw) };
3457
+ }
3458
+ if (raw && typeof raw === "object") {
3459
+ const obj = raw;
3460
+ if (Array.isArray(obj.keyframes)) {
3461
+ return __spreadProps(__spreadValues({}, obj), {
3462
+ keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: scalePowerFromUnits(kf.value) }) : kf)
3463
+ });
3464
+ }
3465
+ if (obj.value !== void 0) {
3466
+ return __spreadProps(__spreadValues({}, obj), { value: scalePowerFromPercent(obj.value) });
3749
3467
  }
3750
- case "programmatic":
3751
- break;
3752
3468
  }
3753
- return api;
3469
+ return raw;
3754
3470
  }
3755
- function propAnimIsMotionPath(anim) {
3471
+ var RETIME_MATERIALISATION_MODE_INLINE_G = false;
3472
+ function asRetime(r) {
3473
+ var _a, _b;
3474
+ return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
3475
+ }
3476
+ function concatRetime(child, parent) {
3477
+ return {
3478
+ start: parent.start + parent.stretch * child.start,
3479
+ stretch: parent.stretch * child.stretch
3480
+ };
3481
+ }
3482
+ function applyAllRetimeEffects(root, ctx) {
3756
3483
  var _a;
3757
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
3758
- if (!Array.isArray(kfs)) return false;
3759
- if (anim.autoOrient) return true;
3760
- for (const kf of kfs) {
3761
- if (kf.tangentIn || kf.tangentOut) return true;
3484
+ ctx.idMap.clear();
3485
+ indexById(root, ctx.idMap);
3486
+ const sites = [];
3487
+ const collect = (n) => {
3488
+ var _a2, _b;
3489
+ if ((_a2 = n.effects) == null ? void 0 : _a2.retime) sites.push(n);
3490
+ (_b = n.children) == null ? void 0 : _b.forEach(collect);
3491
+ };
3492
+ collect(root);
3493
+ for (const useNode of sites) {
3494
+ const retime = (_a = useNode.effects) == null ? void 0 : _a.retime;
3495
+ if (!retime) continue;
3496
+ delete useNode.effects.retime;
3497
+ if (Object.keys(useNode.effects).length === 0) delete useNode.effects;
3498
+ materialiseRetime(useNode, asRetime(retime), ctx);
3762
3499
  }
3763
- return false;
3764
3500
  }
3765
- var _segmentCache = /* @__PURE__ */ new WeakMap();
3766
- function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
3767
- const existing = _segmentCache.get(prevKf);
3768
- if (existing) return existing;
3769
- const to = prevKf.tangentOut;
3770
- const ti = nextKf.tangentIn;
3771
- const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
3772
- const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
3773
- const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
3774
- const entry = {
3775
- P0: prevPos,
3776
- P1,
3777
- P2,
3778
- P3: nextPos,
3779
- lut,
3780
- totalArc: lut.ds[lut.ds.length - 1]
3501
+ function materialiseRetime(useNode, retime, ctx) {
3502
+ const targetId = stripHash(useNode.href);
3503
+ if (!targetId) {
3504
+ ctx.errors.push("retime: <use> has no href to follow");
3505
+ return;
3506
+ }
3507
+ const chainRootId = buildChainClone(targetId, retime, ctx, /* @__PURE__ */ new Set());
3508
+ if (!chainRootId) return;
3509
+ if (RETIME_MATERIALISATION_MODE_INLINE_G) {
3510
+ const cloneNode = ctx.idMap.get(chainRootId);
3511
+ useNode.type = "g";
3512
+ delete useNode.href;
3513
+ useNode.children = [cloneNode];
3514
+ applyUseOffsetToG(useNode);
3515
+ ctx.defs = ctx.defs.filter((d) => d !== cloneNode);
3516
+ } else {
3517
+ useNode.href = "#" + chainRootId;
3518
+ }
3519
+ }
3520
+ function buildChainClone(targetId, accum, ctx, chain) {
3521
+ var _a, _b;
3522
+ if (chain.has(targetId)) {
3523
+ ctx.errors.push('retime: loop via "' + targetId + '"');
3524
+ return void 0;
3525
+ }
3526
+ const target = ctx.idMap.get(targetId);
3527
+ if (!target) {
3528
+ ctx.warnings.push('retime: target "' + targetId + '" not found');
3529
+ return void 0;
3530
+ }
3531
+ const cloneNode = clone(target);
3532
+ regenerateIdsInClone(cloneNode, ctx);
3533
+ if (target.type === "use") {
3534
+ remapKeyframeTimesOnly(cloneNode, accum.start, accum.stretch);
3535
+ } else {
3536
+ remapKeyframeTimes(cloneNode, accum.start, accum.stretch);
3537
+ }
3538
+ if ((_a = cloneNode.effects) == null ? void 0 : _a.retime) {
3539
+ delete cloneNode.effects.retime;
3540
+ if (Object.keys(cloneNode.effects).length === 0) delete cloneNode.effects;
3541
+ }
3542
+ if (target.type === "use" && target.href) {
3543
+ const subId = stripHash(target.href);
3544
+ if (subId) {
3545
+ const innerRetime = (_b = target.effects) == null ? void 0 : _b.retime;
3546
+ const subAccum = innerRetime ? concatRetime(asRetime(innerRetime), accum) : accum;
3547
+ const subChain = new Set(chain);
3548
+ subChain.add(targetId);
3549
+ const subId2 = buildChainClone(subId, subAccum, ctx, subChain);
3550
+ if (subId2) cloneNode.href = "#" + subId2;
3551
+ }
3552
+ }
3553
+ ctx.defs.push(cloneNode);
3554
+ if (typeof cloneNode.id === "string") ctx.idMap.set(cloneNode.id, cloneNode);
3555
+ return typeof cloneNode.id === "string" ? cloneNode.id : void 0;
3556
+ }
3557
+ function remapKeyframeTimes(node, start, stretch) {
3558
+ var _a;
3559
+ remapKeyframeTimesOnly(node, start, stretch);
3560
+ (_a = node.children) == null ? void 0 : _a.forEach((c) => remapKeyframeTimes(c, start, stretch));
3561
+ }
3562
+ function remapKeyframeTimesOnly(node, start, stretch) {
3563
+ const remap2 = (kfs) => {
3564
+ for (const kf of kfs) if (typeof kf.time === "number") kf.time = start + kf.time * stretch;
3781
3565
  };
3782
- _segmentCache.set(prevKf, entry);
3783
- return entry;
3566
+ if (node.transform && typeof node.transform === "object" && Array.isArray(node.transform.keyframes)) {
3567
+ remap2(node.transform.keyframes);
3568
+ }
3569
+ if (node.animate && typeof node.animate === "object") {
3570
+ for (const prop of Object.keys(node.animate)) {
3571
+ const anim = node.animate[prop];
3572
+ if (anim && Array.isArray(anim.keyframes)) remap2(anim.keyframes);
3573
+ }
3574
+ }
3784
3575
  }
3785
- function evaluateMotionPathSegment(prevKf, nextKf, prevPos, nextPos, localProgress, autoOrient) {
3786
- const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
3787
- const t = seg.totalArc === 0 ? localProgress : bezier2D_tForDistance(seg.lut, localProgress * seg.totalArc);
3788
- const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
3789
- if (!autoOrient) return { translate: point };
3790
- const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
3791
- const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
3792
- return { translate: point, rotateDeg };
3576
+ function applyTextAlongPathEffect(node, fx, _ctx) {
3577
+ var _a;
3578
+ if (!fx) return node;
3579
+ const href = typeof fx.href === "string" && !fx.href.startsWith("#") ? "#" + fx.href : fx.href;
3580
+ const textPath = {
3581
+ type: "textPath",
3582
+ href,
3583
+ children: (_a = node.children) != null ? _a : []
3584
+ };
3585
+ if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
3586
+ if (fx.method !== void 0) textPath.method = fx.method;
3587
+ if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
3588
+ applyAnimatableNumber(textPath, "startOffset", fx.startOffset);
3589
+ applyAnimatableNumber(textPath, "textLength", fx.textLength);
3590
+ node.children = [textPath];
3591
+ return node;
3793
3592
  }
3794
- function parsePathCommands(d) {
3795
- const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
3796
- const commands = [];
3797
- let currentCommand = null;
3798
- for (const token of tokens) {
3799
- if (/[MLCZmlcz]/.test(token)) {
3800
- currentCommand = { type: token, values: [] };
3801
- commands.push(currentCommand);
3802
- } else if (currentCommand) {
3803
- const value = +token;
3804
- currentCommand.values.push(Number.isNaN(value) ? 0 : value);
3593
+ function applyAnimatableNumber(node, attrName, raw) {
3594
+ if (raw === void 0 || raw === null) return;
3595
+ if (typeof raw === "number") {
3596
+ node[attrName] = String(raw);
3597
+ return;
3598
+ }
3599
+ if (typeof raw === "object") {
3600
+ const obj = raw;
3601
+ if (Array.isArray(obj.keyframes)) {
3602
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3603
+ const animate = __spreadValues({}, prevAnimate || {});
3604
+ animate[attrName] = { keyframes: obj.keyframes };
3605
+ node.animate = animate;
3606
+ return;
3607
+ }
3608
+ if (typeof obj.value === "number") {
3609
+ node[attrName] = String(obj.value);
3610
+ return;
3805
3611
  }
3806
3612
  }
3807
- return commands;
3808
3613
  }
3809
- function parseSvgPathToBezier(d) {
3810
- const res = [];
3811
- let currentPath;
3812
- const commands = parsePathCommands(d);
3813
- for (const command of commands) {
3814
- const type = command.type;
3815
- const values = command.values;
3816
- if (type === "M" || type === "m") {
3614
+ function bezierToSvgPath(path) {
3615
+ var _a, _b, _c, _d;
3616
+ const v = path.v;
3617
+ const i = path.i;
3618
+ const o = path.o;
3619
+ const c = path.c;
3620
+ if (!v.length) return "";
3621
+ const d = [];
3622
+ const len = v.length;
3623
+ d.push("M" + v[0][0] + "," + v[0][1]);
3624
+ for (let idx = 1; idx < len; idx++) {
3625
+ const prevV = v[idx - 1];
3626
+ const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
3627
+ const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
3628
+ const currV = v[idx];
3629
+ const isLine = prevO[0] === prevV[0] && prevO[1] === prevV[1] && (currI[0] === currV[0] && currI[1] === currV[1]);
3630
+ if (isLine) {
3631
+ d.push("L" + currV[0] + "," + currV[1]);
3632
+ } else {
3633
+ d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
3634
+ }
3635
+ }
3636
+ if (c && len > 0) {
3637
+ const lastV = v[len - 1];
3638
+ const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
3639
+ const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
3640
+ const firstV = v[0];
3641
+ const isLine = lastO[0] === lastV[0] && lastO[1] === lastV[1] && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
3642
+ if (!isLine) {
3643
+ d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
3644
+ }
3645
+ d.push("z");
3646
+ }
3647
+ return d.join("");
3648
+ }
3649
+ function interpolateNum(a, b, t) {
3650
+ return a + (b - a) * t;
3651
+ }
3652
+ function interpolateVec(a, b, t) {
3653
+ const res = [];
3654
+ const count = Math.max(a.length, b.length);
3655
+ for (let i = 0; i < count; i++) {
3656
+ res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
3657
+ }
3658
+ return res;
3659
+ }
3660
+ function interpolateColor(a, b, t) {
3661
+ return [
3662
+ interpolateNum(a[0] || 0, b[0] || 0, t),
3663
+ interpolateNum(a[1] || 0, b[1] || 0, t),
3664
+ interpolateNum(a[2] || 0, b[2] || 0, t),
3665
+ interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
3666
+ ];
3667
+ }
3668
+ function interpolateBeziers(paths1, paths2, progress) {
3669
+ const count = Math.max(paths1.length, paths2.length);
3670
+ const res = [];
3671
+ for (let i = 0; i < count; i++) {
3672
+ res.push(interpolateBezier(paths1[i], paths2[i], progress));
3673
+ }
3674
+ return res;
3675
+ }
3676
+ function interpolateBezier(path1, path2, progress) {
3677
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3678
+ if (!path1 || !path2) return path1 || path2 || { v: [] };
3679
+ const t = Math.min(Math.max(progress, 0), 1);
3680
+ const len = Math.min(path1.v.length, path2.v.length);
3681
+ const v = [];
3682
+ const i = [];
3683
+ const o = [];
3684
+ for (let idx = 0; idx < len; idx++) {
3685
+ const v1 = path1.v[idx];
3686
+ const v2 = path2.v[idx];
3687
+ v.push(interpolateVec(v1, v2, t));
3688
+ const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
3689
+ const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
3690
+ i.push(interpolateVec(i1, i2, t));
3691
+ const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
3692
+ const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
3693
+ o.push(interpolateVec(o1, o2, t));
3694
+ }
3695
+ return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
3696
+ }
3697
+ function remap(value, inMin, inMax, outMin, outMax) {
3698
+ if (inMax === inMin) return outMin;
3699
+ const t = (value - inMin) / (inMax - inMin);
3700
+ return outMin + t * (outMax - outMin);
3701
+ }
3702
+ function solveCubicBezierX(p1x, p2x, x) {
3703
+ if (x <= 0) return 0;
3704
+ if (x >= 1) return 1;
3705
+ const cx = 3 * p1x;
3706
+ const bx = 3 * (p2x - p1x) - cx;
3707
+ const ax = 1 - cx - bx;
3708
+ function sampleX(t) {
3709
+ return ((ax * t + bx) * t + cx) * t;
3710
+ }
3711
+ function sampleDX(t) {
3712
+ return (3 * ax * t + 2 * bx) * t + cx;
3713
+ }
3714
+ let t2 = x;
3715
+ let t0 = 0;
3716
+ let t1 = 1;
3717
+ for (let i = 0; i < 8; i++) {
3718
+ const x2 = sampleX(t2) - x;
3719
+ if (Math.abs(x2) < 1e-6) return t2;
3720
+ const d2 = sampleDX(t2);
3721
+ if (Math.abs(d2) < 1e-6) break;
3722
+ t2 -= x2 / d2;
3723
+ }
3724
+ t2 = x;
3725
+ while (t0 < t1) {
3726
+ const x2 = sampleX(t2);
3727
+ if (Math.abs(x2 - x) < 1e-6) return t2;
3728
+ if (x > x2) t0 = t2;
3729
+ else t1 = t2;
3730
+ t2 = (t1 + t0) / 2;
3731
+ }
3732
+ return t2;
3733
+ }
3734
+ function cubicBezier(easing) {
3735
+ const [p1x, p1y, p2x, p2y] = easing;
3736
+ const cy = 3 * p1y;
3737
+ const by = 3 * (p2y - p1y) - cy;
3738
+ const ay = 1 - cy - by;
3739
+ function sampleCurveY(t) {
3740
+ return ((ay * t + by) * t + cy) * t;
3741
+ }
3742
+ return function(x) {
3743
+ return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
3744
+ };
3745
+ }
3746
+ function lerp2(a, b, t) {
3747
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
3748
+ }
3749
+ function subdivideCubicBezier(p0, p1, p2, p3, t) {
3750
+ const q0 = lerp2(p0, p1, t);
3751
+ const q1 = lerp2(p1, p2, t);
3752
+ const q2 = lerp2(p2, p3, t);
3753
+ const r0 = lerp2(q0, q1, t);
3754
+ const r1 = lerp2(q1, q2, t);
3755
+ const s = lerp2(r0, r1, t);
3756
+ return {
3757
+ left: [p0, q0, r0, s],
3758
+ right: [s, r1, q2, p3]
3759
+ };
3760
+ }
3761
+ function splitEasing(easing, xFraction) {
3762
+ if (!easing) return { left: void 0, right: void 0 };
3763
+ if (xFraction <= 0) return { left: void 0, right: easing };
3764
+ if (xFraction >= 1) return { left: easing, right: void 0 };
3765
+ const [x1, y1, x2, y2] = easing;
3766
+ const t = solveCubicBezierX(x1, x2, xFraction);
3767
+ const p0 = [0, 0];
3768
+ const p1 = [x1, y1];
3769
+ const p2 = [x2, y2];
3770
+ const p3 = [1, 1];
3771
+ const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
3772
+ const sx = left[3][0];
3773
+ const sy = left[3][1];
3774
+ let leftEasing;
3775
+ if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
3776
+ leftEasing = [
3777
+ left[1][0] / sx,
3778
+ left[1][1] / sy,
3779
+ left[2][0] / sx,
3780
+ left[2][1] / sy
3781
+ ];
3782
+ }
3783
+ let rightEasing;
3784
+ const rx = 1 - sx;
3785
+ const ry = 1 - sy;
3786
+ if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
3787
+ rightEasing = [
3788
+ (right[1][0] - sx) / rx,
3789
+ (right[1][1] - sy) / ry,
3790
+ (right[2][0] - sx) / rx,
3791
+ (right[2][1] - sy) / ry
3792
+ ];
3793
+ }
3794
+ return { left: leftEasing, right: rightEasing };
3795
+ }
3796
+ function reverseEasing(easing) {
3797
+ if (!easing) return void 0;
3798
+ return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
3799
+ }
3800
+ function toRGBA(color) {
3801
+ const r = Math.round(color[0] * 255);
3802
+ const g = Math.round(color[1] * 255);
3803
+ const b = Math.round(color[2] * 255);
3804
+ return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
3805
+ }
3806
+ function parseRgba(s) {
3807
+ var _a;
3808
+ const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
3809
+ if (!inner) throw new Error("Invalid rgb/rgba format");
3810
+ const parts = inner.split(",").map((v) => +v.trim());
3811
+ return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
3812
+ }
3813
+ function parseHex(s) {
3814
+ const hex = s.slice(1);
3815
+ const isShort = hex.length <= 4;
3816
+ const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
3817
+ const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
3818
+ const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
3819
+ const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
3820
+ const result = [
3821
+ parseInt(r, 16) / 255,
3822
+ parseInt(g, 16) / 255,
3823
+ parseInt(b, 16) / 255
3824
+ ];
3825
+ if (a !== null) {
3826
+ result.push(parseInt(a, 16) / 255);
3827
+ }
3828
+ return result;
3829
+ }
3830
+ function parseColor(s) {
3831
+ if (!s) return void 0;
3832
+ if (Array.isArray(s)) return s;
3833
+ if (typeof s !== "string") return void 0;
3834
+ if (s.startsWith("#")) {
3835
+ return parseHex(s);
3836
+ } else if (s.startsWith("rgb")) {
3837
+ return parseRgba(s);
3838
+ } else {
3839
+ console.warn("Unsupported color format: " + s);
3840
+ }
3841
+ return void 0;
3842
+ }
3843
+ var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
3844
+ var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
3845
+ var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
3846
+ function composeTransformParts(parts, opts) {
3847
+ var _a;
3848
+ if (!parts) return "";
3849
+ const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
3850
+ const segs = [];
3851
+ const t = parts.translate;
3852
+ const o = parts.origin;
3853
+ const r = parts.rotate;
3854
+ const s = parts.scale;
3855
+ const tu = withUnits ? "px" : "";
3856
+ const ru = withUnits ? "deg" : "";
3857
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
3858
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
3859
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
3860
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
3861
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
3862
+ return segs.join("");
3863
+ }
3864
+ var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
3865
+ var DEFAULT_DURATION_MS = 1e3;
3866
+ function kebabToCamelCaseWord(kebab) {
3867
+ return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
3868
+ }
3869
+ function isCamelCaseWord(word) {
3870
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
3871
+ }
3872
+ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
3873
+ // Transform/positioning
3874
+ "viewBox",
3875
+ "preserveAspectRatio",
3876
+ // Gradient
3877
+ "gradientUnits",
3878
+ "gradientTransform",
3879
+ "spreadMethod",
3880
+ // Pattern
3881
+ "patternUnits",
3882
+ "patternContentUnits",
3883
+ "patternTransform",
3884
+ // Clipping/masking
3885
+ "clipPathUnits",
3886
+ "maskUnits",
3887
+ "maskContentUnits",
3888
+ // Marker (SVG spec keeps these camelCase, like viewBox)
3889
+ "markerUnits",
3890
+ "markerWidth",
3891
+ "markerHeight",
3892
+ "refX",
3893
+ "refY",
3894
+ // Text
3895
+ "textLength",
3896
+ "lengthAdjust",
3897
+ "startOffset",
3898
+ // Filter
3899
+ "filterUnits",
3900
+ "primitiveUnits",
3901
+ "stdDeviation",
3902
+ "baseFrequency",
3903
+ "numOctaves",
3904
+ "surfaceScale",
3905
+ "diffuseConstant",
3906
+ "specularConstant",
3907
+ "specularExponent",
3908
+ "kernelMatrix",
3909
+ "kernelUnitLength",
3910
+ "edgeMode",
3911
+ "preserveAlpha",
3912
+ "targetX",
3913
+ "targetY"
3914
+ // // Animation
3915
+ // 'attributeName',
3916
+ // 'attributeType',
3917
+ // 'calcMode',
3918
+ // 'keyTimes',
3919
+ // 'keySplines',
3920
+ // 'repeatCount',
3921
+ // 'repeatDur'
3922
+ ]);
3923
+ function camelCaseToKebabWordIfNeeded(camel) {
3924
+ return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
3925
+ }
3926
+ function clamp(value, min, max) {
3927
+ return Math.max(min, Math.min(value, max));
3928
+ }
3929
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
3930
+ if (t <= 0) return [P0[0], P0[1]];
3931
+ if (t >= 1) return [P3[0], P3[1]];
3932
+ const u = 1 - t;
3933
+ const u2 = u * u;
3934
+ const u3 = u2 * u;
3935
+ const t2 = t * t;
3936
+ const t3 = t2 * t;
3937
+ const w0 = u3;
3938
+ const w1 = 3 * t * u2;
3939
+ const w2 = 3 * t2 * u;
3940
+ const w3 = t3;
3941
+ return [
3942
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
3943
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
3944
+ ];
3945
+ }
3946
+ var BEZIER_T_NUDGE = 1e-4;
3947
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
3948
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
3949
+ if (result[0] === 0 && result[1] === 0) {
3950
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
3951
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
3952
+ }
3953
+ return result;
3954
+ }
3955
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
3956
+ const u = 1 - t;
3957
+ const a = 3 * u * u;
3958
+ const b = 6 * t * u;
3959
+ const c = 3 * t * t;
3960
+ return [
3961
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
3962
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
3963
+ ];
3964
+ }
3965
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
3966
+ const n = steps + 1;
3967
+ const ts = new Float64Array(n);
3968
+ const ds = new Float64Array(n);
3969
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
3970
+ ts[0] = 0;
3971
+ ds[0] = 0;
3972
+ let cum = 0;
3973
+ for (let i = 1; i < n; i++) {
3974
+ const t = i / steps;
3975
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
3976
+ const dx = cur[0] - prev[0];
3977
+ const dy = cur[1] - prev[1];
3978
+ cum += Math.sqrt(dx * dx + dy * dy);
3979
+ ts[i] = t;
3980
+ ds[i] = cum;
3981
+ prev = cur;
3982
+ }
3983
+ return { ts, ds };
3984
+ }
3985
+ function bezier2D_arcAtT(lut, t) {
3986
+ const { ts, ds } = lut;
3987
+ const last = ts.length - 1;
3988
+ if (t <= ts[0]) return ds[0];
3989
+ if (t >= ts[last]) return ds[last];
3990
+ let lo = 1, hi = last;
3991
+ while (lo < hi) {
3992
+ const mid = lo + hi >>> 1;
3993
+ if (ts[mid] < t) lo = mid + 1;
3994
+ else hi = mid;
3995
+ }
3996
+ const tPrev = ts[hi - 1];
3997
+ const span = ts[hi] - tPrev;
3998
+ const frac = span > 0 ? (t - tPrev) / span : 0;
3999
+ return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
4000
+ }
4001
+ function invertEasing(easing) {
4002
+ if (!easing) return (y) => y;
4003
+ const flipped = [easing[1], easing[0], easing[3], easing[2]];
4004
+ return cubicBezier(flipped);
4005
+ }
4006
+ function getKfTranslate(kf) {
4007
+ var _a;
4008
+ const v = (_a = kf.value) != null ? _a : kf.v;
4009
+ if (!v) return void 0;
4010
+ if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
4011
+ return [v[0], v[1]];
4012
+ }
4013
+ const tr = v.translate;
4014
+ if (Array.isArray(tr) && tr.length >= 2) return [tr[0], tr[1]];
4015
+ return void 0;
4016
+ }
4017
+ function getKfTime(kf) {
4018
+ var _a, _b;
4019
+ return (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
4020
+ }
4021
+ function getKfEasing(kf) {
4022
+ var _a;
4023
+ return (_a = kf.easing) != null ? _a : kf.e;
4024
+ }
4025
+ function propAnimIsMotionPath(anim) {
4026
+ var _a, _b, _c;
4027
+ const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
4028
+ if (!Array.isArray(kfs)) return false;
4029
+ if (anim.autoOrient) return true;
4030
+ for (const kf of kfs) {
4031
+ if (((_b = kf.tangentIn) != null ? _b : kf.ti) || ((_c = kf.tangentOut) != null ? _c : kf.to)) return true;
4032
+ }
4033
+ return false;
4034
+ }
4035
+ var _segmentCache = /* @__PURE__ */ new WeakMap();
4036
+ function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
4037
+ var _a, _b;
4038
+ const existing = _segmentCache.get(prevKf);
4039
+ if (existing) return existing;
4040
+ const to = (_a = prevKf.tangentOut) != null ? _a : prevKf.to;
4041
+ const ti = (_b = nextKf.tangentIn) != null ? _b : nextKf.ti;
4042
+ const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
4043
+ const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
4044
+ const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
4045
+ const entry = {
4046
+ P0: prevPos,
4047
+ P1,
4048
+ P2,
4049
+ P3: nextPos,
4050
+ lut,
4051
+ totalArc: lut.ds[lut.ds.length - 1]
4052
+ };
4053
+ _segmentCache.set(prevKf, entry);
4054
+ return entry;
4055
+ }
4056
+ function evaluateMotionPathSegment(prevKf, nextKf, prevPos, nextPos, localProgress, autoOrient) {
4057
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
4058
+ const t = seg.totalArc === 0 ? localProgress : tFromArcFraction(seg.lut, localProgress);
4059
+ const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
4060
+ if (!autoOrient) return { translate: point };
4061
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
4062
+ const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
4063
+ return { translate: point, rotateDeg };
4064
+ }
4065
+ function tFromArcFraction(lut, arcFrac) {
4066
+ const total = lut.ds[lut.ds.length - 1];
4067
+ const target = arcFrac * total;
4068
+ const { ts, ds } = lut;
4069
+ const last = ds.length - 1;
4070
+ if (target <= 0) return ts[0];
4071
+ if (target >= ds[last]) return ts[last];
4072
+ let lo = 1, hi = last;
4073
+ while (lo < hi) {
4074
+ const mid = lo + hi >>> 1;
4075
+ if (ds[mid] < target) lo = mid + 1;
4076
+ else hi = mid;
4077
+ }
4078
+ const dPrev = ds[hi - 1];
4079
+ const span = ds[hi] - dPrev;
4080
+ const frac = span > 0 ? (target - dPrev) / span : 0;
4081
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
4082
+ }
4083
+ var DEFAULT_FLATNESS_TOL = 0.5;
4084
+ var DEFAULT_ROTATION_TOL = 5;
4085
+ var DEFAULT_MAX_SAMPLES = 32;
4086
+ function materialiseMotionPathInPropAnim(anim, opts) {
4087
+ var _a, _b, _c, _d;
4088
+ if (!propAnimIsMotionPath(anim)) return anim;
4089
+ const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
4090
+ if (!Array.isArray(kfs) || kfs.length < 2) return anim;
4091
+ const autoOrient = !!anim.autoOrient;
4092
+ const flatnessTol = (_b = opts == null ? void 0 : opts.flatnessTolerance) != null ? _b : DEFAULT_FLATNESS_TOL;
4093
+ const rotationTol = (_c = opts == null ? void 0 : opts.rotationTolerance) != null ? _c : DEFAULT_ROTATION_TOL;
4094
+ const maxSamples = (_d = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _d : DEFAULT_MAX_SAMPLES;
4095
+ const out = [];
4096
+ const firstPos = getKfTranslate(kfs[0]);
4097
+ if (!firstPos) return anim;
4098
+ const firstRotate = autoOrient ? derivAngleForFirstKf(kfs[0], kfs[1]) : void 0;
4099
+ out.push(makeOutKf(
4100
+ getKfTime(kfs[0]),
4101
+ buildOutKfValue(getKfValueParts(kfs[0]), getKfValueParts(kfs[0]), 0, firstPos, firstRotate, autoOrient)
4102
+ ));
4103
+ for (let i = 0; i < kfs.length - 1; i++) {
4104
+ const prevKf = kfs[i];
4105
+ const nextKf = kfs[i + 1];
4106
+ const prevPos = getKfTranslate(prevKf);
4107
+ const nextPos = getKfTranslate(nextKf);
4108
+ if (!prevPos || !nextPos) {
4109
+ out.push(makeOutKf(
4110
+ getKfTime(nextKf),
4111
+ buildOutKfValue(getKfValueParts(nextKf), getKfValueParts(nextKf), 1, nextPos != null ? nextPos : [0, 0], void 0, autoOrient)
4112
+ ));
4113
+ continue;
4114
+ }
4115
+ if (autoOrient && i > 0) {
4116
+ insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
4117
+ }
4118
+ materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
4119
+ }
4120
+ const lastInE = getKfEasing(kfs[kfs.length - 1]);
4121
+ if (lastInE) out[out.length - 1].e = lastInE;
4122
+ if (autoOrient) unwrapAutoOrientRotations(out);
4123
+ const result = { kfs: out };
4124
+ if (anim.loop !== void 0) result.loop = anim.loop;
4125
+ return result;
4126
+ }
4127
+ function unwrapAutoOrientRotations(kfs) {
4128
+ var _a;
4129
+ let prev;
4130
+ for (const kf of kfs) {
4131
+ const v = (_a = kf.v) != null ? _a : kf.value;
4132
+ if (!v || typeof v.rotate !== "number") continue;
4133
+ if (prev === void 0) {
4134
+ prev = v.rotate;
4135
+ continue;
4136
+ }
4137
+ let r = v.rotate;
4138
+ while (r - prev > 180) r -= 360;
4139
+ while (r - prev < -180) r += 360;
4140
+ v.rotate = r;
4141
+ prev = r;
4142
+ }
4143
+ }
4144
+ function makeOutKf(time, value) {
4145
+ return { t: time, v: value };
4146
+ }
4147
+ function getKfValueParts(kf) {
4148
+ var _a;
4149
+ const v = (_a = kf.value) != null ? _a : kf.v;
4150
+ if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
4151
+ return v;
4152
+ }
4153
+ function interpolatePart(prev, next, p) {
4154
+ if (prev === void 0) return next;
4155
+ if (next === void 0) return prev;
4156
+ if (typeof prev === "number" && typeof next === "number") {
4157
+ return prev + (next - prev) * p;
4158
+ }
4159
+ if (Array.isArray(prev) && Array.isArray(next) && prev.length === next.length) {
4160
+ const out = new Array(prev.length);
4161
+ for (let i = 0; i < prev.length; i++) {
4162
+ const a = typeof prev[i] === "number" ? prev[i] : 0;
4163
+ const b = typeof next[i] === "number" ? next[i] : 0;
4164
+ out[i] = a + (b - a) * p;
4165
+ }
4166
+ return out;
4167
+ }
4168
+ return p < 0.5 ? prev : next;
4169
+ }
4170
+ function buildOutKfValue(prevV, nextV, p, translate, rotateDegFromAutoOrient, autoOrient) {
4171
+ const value = { translate };
4172
+ const keys = /* @__PURE__ */ new Set();
4173
+ if (prevV) for (const k of Object.keys(prevV)) keys.add(k);
4174
+ if (nextV) for (const k of Object.keys(nextV)) keys.add(k);
4175
+ for (const k of keys) {
4176
+ if (k === "translate") continue;
4177
+ if (k === "rotate" && autoOrient) continue;
4178
+ const pv = prevV == null ? void 0 : prevV[k];
4179
+ const nv = nextV == null ? void 0 : nextV[k];
4180
+ if (pv === void 0 && nv === void 0) continue;
4181
+ value[k] = interpolatePart(pv, nv, p);
4182
+ }
4183
+ if (rotateDegFromAutoOrient !== void 0) value.rotate = rotateDegFromAutoOrient;
4184
+ return value;
4185
+ }
4186
+ function derivAngleForFirstKf(kf0, kf1) {
4187
+ const p0 = getKfTranslate(kf0);
4188
+ const p1 = getKfTranslate(kf1);
4189
+ if (!p0 || !p1) return 0;
4190
+ const seg = getSegmentCache(kf0, kf1, p0, p1);
4191
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
4192
+ return Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
4193
+ }
4194
+ function wrappedAngleDelta(a, b) {
4195
+ let d = a - b;
4196
+ while (d > 180) d -= 360;
4197
+ while (d < -180) d += 360;
4198
+ return d;
4199
+ }
4200
+ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
4201
+ var _a;
4202
+ const lastKf = out[out.length - 1];
4203
+ const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
4204
+ const prevExit = lastV == null ? void 0 : lastV.rotate;
4205
+ if (typeof prevExit !== "number") return;
4206
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
4207
+ const tanAtStart = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
4208
+ const nextEntry = Math.atan2(tanAtStart[1], tanAtStart[0]) * 180 / Math.PI;
4209
+ const delta = wrappedAngleDelta(nextEntry, prevExit);
4210
+ if (Math.abs(delta) <= rotationTol) return;
4211
+ const dupValue = buildOutKfValue(
4212
+ getKfValueParts(prevKf),
4213
+ getKfValueParts(prevKf),
4214
+ 0,
4215
+ prevPos,
4216
+ nextEntry,
4217
+ true
4218
+ );
4219
+ out.push(makeOutKf(getKfTime(prevKf), dupValue));
4220
+ }
4221
+ function materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
4222
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
4223
+ const prevTime = getKfTime(prevKf);
4224
+ const nextTime = getKfTime(nextKf);
4225
+ const prevEasing = getKfEasing(prevKf);
4226
+ const invertFn = invertEasing(prevEasing);
4227
+ const prevV = getKfValueParts(prevKf);
4228
+ const nextV = getKfValueParts(nextKf);
4229
+ const interiorTs = computeSampleTs(seg, autoOrient, flatnessTol, rotationTol, maxSamples);
4230
+ const samples = [];
4231
+ for (const t of interiorTs) {
4232
+ const arc = bezier2D_arcAtT(seg.lut, t);
4233
+ const p = clamp(seg.totalArc > 0 ? arc / seg.totalArc : t, 0, 1);
4234
+ const u = clamp(invertFn(p), 0, 1);
4235
+ const pos = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
4236
+ const sample = { u, p, pos };
4237
+ if (autoOrient) {
4238
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
4239
+ sample.rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
4240
+ }
4241
+ samples.push(sample);
4242
+ }
4243
+ let remaining = prevEasing;
4244
+ let prevU = 0;
4245
+ const startIdx = out.length - 1;
4246
+ for (let i = 0; i < samples.length; i++) {
4247
+ const s = samples[i];
4248
+ const xFrac = prevU < 1 ? clamp((s.u - prevU) / (1 - prevU), 0, 1) : 1;
4249
+ const { left, right } = splitEasing(remaining, xFrac);
4250
+ const ownerIdx = i === 0 ? startIdx : out.length - 1;
4251
+ if (left) out[ownerIdx].e = left;
4252
+ else delete out[ownerIdx].e;
4253
+ const tGlobal = prevTime + s.u * (nextTime - prevTime);
4254
+ const value = buildOutKfValue(prevV, nextV, s.p, s.pos, s.rotateDeg, autoOrient);
4255
+ out.push(makeOutKf(tGlobal, value));
4256
+ remaining = right;
4257
+ prevU = s.u;
4258
+ }
4259
+ }
4260
+ function computeSampleTs(seg, autoOrient, flatnessTol, rotationTol, maxSamples) {
4261
+ const extremes = [];
4262
+ addAxisExtremes(seg.P0[0], seg.P1[0], seg.P2[0], seg.P3[0], extremes);
4263
+ addAxisExtremes(seg.P0[1], seg.P1[1], seg.P2[1], seg.P3[1], extremes);
4264
+ extremes.sort((a, b) => a - b);
4265
+ const critical = [0];
4266
+ for (const t of extremes) {
4267
+ if (t > critical[critical.length - 1] + 1e-6 && t < 1 - 1e-6) {
4268
+ critical.push(t);
4269
+ }
4270
+ }
4271
+ critical.push(1);
4272
+ const out = [];
4273
+ const budget = { remaining: maxSamples - critical.length };
4274
+ for (let i = 0; i < critical.length - 1; i++) {
4275
+ bisect(critical[i], critical[i + 1], out, seg, autoOrient, flatnessTol, rotationTol, budget);
4276
+ }
4277
+ return out;
4278
+ }
4279
+ function addAxisExtremes(p0, p1, p2, p3, out) {
4280
+ const a = p1 - p0;
4281
+ const b = p2 - p1;
4282
+ const c = p3 - p2;
4283
+ const A = a - 2 * b + c;
4284
+ const B = 2 * (b - a);
4285
+ const C = a;
4286
+ if (Math.abs(A) < 1e-10) {
4287
+ if (Math.abs(B) > 1e-10) {
4288
+ const t = -C / B;
4289
+ if (t > 1e-6 && t < 1 - 1e-6) out.push(t);
4290
+ }
4291
+ return;
4292
+ }
4293
+ const disc = B * B - 4 * A * C;
4294
+ if (disc < 0) return;
4295
+ const sq = Math.sqrt(disc);
4296
+ const t1 = (-B - sq) / (2 * A);
4297
+ const t2 = (-B + sq) / (2 * A);
4298
+ if (t1 > 1e-6 && t1 < 1 - 1e-6) out.push(t1);
4299
+ if (t2 > 1e-6 && t2 < 1 - 1e-6) out.push(t2);
4300
+ }
4301
+ function bisect(tA, tB, out, seg, autoOrient, flatnessTol, rotationTol, budget) {
4302
+ const tMid = (tA + tB) / 2;
4303
+ const pA = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);
4304
+ const pB = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);
4305
+ const span = tB - tA;
4306
+ const p25 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.25);
4307
+ const p50 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tMid);
4308
+ const p75 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.75);
4309
+ const dev = Math.max(
4310
+ perpDist(p25, pA, pB),
4311
+ perpDist(p50, pA, pB),
4312
+ perpDist(p75, pA, pB)
4313
+ );
4314
+ let rotOk = true;
4315
+ if (autoOrient) {
4316
+ const tanA = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);
4317
+ const tanB = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);
4318
+ const angA = Math.atan2(tanA[1], tanA[0]) * 180 / Math.PI;
4319
+ const angB = Math.atan2(tanB[1], tanB[0]) * 180 / Math.PI;
4320
+ let delta = Math.abs(angA - angB);
4321
+ if (delta > 180) delta = 360 - delta;
4322
+ if (delta > rotationTol) rotOk = false;
4323
+ }
4324
+ if (dev <= flatnessTol && rotOk || budget.remaining <= 0 || span < 1e-6) {
4325
+ out.push(tB);
4326
+ return;
4327
+ }
4328
+ budget.remaining -= 1;
4329
+ bisect(tA, tMid, out, seg, autoOrient, flatnessTol, rotationTol, budget);
4330
+ bisect(tMid, tB, out, seg, autoOrient, flatnessTol, rotationTol, budget);
4331
+ }
4332
+ function perpDist(q, pA, pB) {
4333
+ const dx = pB[0] - pA[0];
4334
+ const dy = pB[1] - pA[1];
4335
+ const len2 = dx * dx + dy * dy;
4336
+ if (len2 < 1e-20) {
4337
+ const qdx = q[0] - pA[0];
4338
+ const qdy = q[1] - pA[1];
4339
+ return Math.sqrt(qdx * qdx + qdy * qdy);
4340
+ }
4341
+ const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
4342
+ return Math.abs(cross) / Math.sqrt(len2);
4343
+ }
4344
+ function materialiseMotionPathsInTree(root, opts) {
4345
+ const out = walkAndMaterialise(root, opts);
4346
+ return out != null ? out : root;
4347
+ }
4348
+ function walkAndMaterialise(node, opts) {
4349
+ let newChildren;
4350
+ if (node.children) {
4351
+ for (let i = 0; i < node.children.length; i++) {
4352
+ const ch = node.children[i];
4353
+ const ret = walkAndMaterialise(ch, opts);
4354
+ if (ret !== null) {
4355
+ if (!newChildren) newChildren = node.children.slice();
4356
+ newChildren[i] = ret;
4357
+ }
4358
+ }
4359
+ }
4360
+ let newAnimate;
4361
+ const animBucket = node.animate;
4362
+ if (animBucket && typeof animBucket === "object" && !Array.isArray(animBucket)) {
4363
+ const animDef = animBucket;
4364
+ const transformAnim = animDef.transform;
4365
+ if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
4366
+ const materialised = materialiseMotionPathInPropAnim(transformAnim, opts);
4367
+ if (materialised !== transformAnim) {
4368
+ newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialised });
4369
+ }
4370
+ }
4371
+ }
4372
+ if (!newChildren && !newAnimate) return null;
4373
+ const cloned = __spreadValues({}, node);
4374
+ if (newChildren) cloned.children = newChildren;
4375
+ if (newAnimate) cloned.animate = newAnimate;
4376
+ return cloned;
4377
+ }
4378
+ function parsePathCommands(d) {
4379
+ const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
4380
+ const commands = [];
4381
+ let currentCommand = null;
4382
+ for (const token of tokens) {
4383
+ if (/[MLCZmlcz]/.test(token)) {
4384
+ currentCommand = { type: token, values: [] };
4385
+ commands.push(currentCommand);
4386
+ } else if (currentCommand) {
4387
+ const value = +token;
4388
+ currentCommand.values.push(Number.isNaN(value) ? 0 : value);
4389
+ }
4390
+ }
4391
+ return commands;
4392
+ }
4393
+ function parseSvgPathToBezier(d) {
4394
+ const res = [];
4395
+ let currentPath;
4396
+ const commands = parsePathCommands(d);
4397
+ for (const command of commands) {
4398
+ const type = command.type;
4399
+ const values = command.values;
4400
+ if (type === "M" || type === "m") {
3817
4401
  const x = values[0] || 0;
3818
4402
  const y = values[1] || 0;
3819
4403
  currentPath = {
@@ -3825,478 +4409,1291 @@ var PixodeskAnimatorReact = (() => {
3825
4409
  res.push(currentPath);
3826
4410
  continue;
3827
4411
  }
3828
- if (!currentPath) {
3829
- currentPath = {
3830
- v: [[0, 0]],
3831
- i: [[0, 0]],
3832
- o: [[0, 0]],
3833
- c: false
3834
- };
3835
- res.push(currentPath);
4412
+ if (!currentPath) {
4413
+ currentPath = {
4414
+ v: [[0, 0]],
4415
+ i: [[0, 0]],
4416
+ o: [[0, 0]],
4417
+ c: false
4418
+ };
4419
+ res.push(currentPath);
4420
+ }
4421
+ if (type === "L") {
4422
+ const x = values[0] || 0;
4423
+ const y = values[1] || 0;
4424
+ currentPath.v.push([x, y]);
4425
+ currentPath.i.push([x, y]);
4426
+ currentPath.o.push([x, y]);
4427
+ } else if (type === "C") {
4428
+ const outX = values[0] || 0;
4429
+ const outY = values[1] || 0;
4430
+ const inX2 = values[2] || 0;
4431
+ const inY2 = values[3] || 0;
4432
+ const x2 = values[4] || 0;
4433
+ const y2 = values[5] || 0;
4434
+ currentPath.o[currentPath.o.length - 1] = [outX, outY];
4435
+ currentPath.v.push([x2, y2]);
4436
+ currentPath.i.push([inX2, inY2]);
4437
+ currentPath.o.push([x2, y2]);
4438
+ } else if (type === "Z" || type === "z") {
4439
+ currentPath.c = true;
4440
+ } else {
4441
+ console.warn('Unsupported path command "' + type + '"');
4442
+ }
4443
+ }
4444
+ return res;
4445
+ }
4446
+ function extractPathData(str) {
4447
+ if (str.startsWith("path(") && str.endsWith(")")) {
4448
+ return str.slice(5, -1);
4449
+ }
4450
+ if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str)) {
4451
+ return str;
4452
+ }
4453
+ return void 0;
4454
+ }
4455
+ function isPathString(value) {
4456
+ return typeof value === "string" && extractPathData(value) !== void 0;
4457
+ }
4458
+ function normalizePathValue(value) {
4459
+ if (value && typeof value === "object" && typeof value.path === "string") {
4460
+ const d = extractPathData(value.path);
4461
+ return d ? { paths: parseSvgPathToBezier(d) } : value;
4462
+ }
4463
+ if (value && typeof value === "object" && "paths" in value) {
4464
+ const pathsArray = value.paths;
4465
+ if (Array.isArray(pathsArray) && pathsArray.length > 0) {
4466
+ if (isPathString(pathsArray[0])) {
4467
+ const paths = [];
4468
+ for (const pathStr2 of pathsArray) {
4469
+ const d = extractPathData(pathStr2);
4470
+ if (d) {
4471
+ paths.push(...parseSvgPathToBezier(d));
4472
+ }
4473
+ }
4474
+ return { paths };
4475
+ }
4476
+ }
4477
+ return value;
4478
+ }
4479
+ if (Array.isArray(value)) {
4480
+ if (value.length > 0 && isPathString(value[0])) {
4481
+ const paths = [];
4482
+ for (const pathStr2 of value) {
4483
+ const d = extractPathData(pathStr2);
4484
+ if (d) {
4485
+ paths.push(...parseSvgPathToBezier(d));
4486
+ }
4487
+ }
4488
+ return { paths };
4489
+ }
4490
+ return { paths: value };
4491
+ }
4492
+ if (isPathString(value)) {
4493
+ const d = extractPathData(value);
4494
+ return { paths: parseSvgPathToBezier(d) };
4495
+ }
4496
+ return value;
4497
+ }
4498
+ function resolveEasing(easing, defs) {
4499
+ var _a;
4500
+ if (!easing) return void 0;
4501
+ if (Array.isArray(easing)) {
4502
+ return easing;
4503
+ }
4504
+ if ((_a = defs == null ? void 0 : defs.easings) == null ? void 0 : _a[easing]) {
4505
+ return defs.easings[easing];
4506
+ }
4507
+ console.warn("Unknown easing name: " + easing);
4508
+ return void 0;
4509
+ }
4510
+ function resolveAnimation(animRef, defs) {
4511
+ var _a;
4512
+ if (typeof animRef === "string") {
4513
+ const resolved = (_a = defs == null ? void 0 : defs.animations) == null ? void 0 : _a[animRef];
4514
+ if (!resolved) {
4515
+ console.warn("Unknown animation name: " + animRef);
4516
+ }
4517
+ return resolved;
4518
+ }
4519
+ return animRef;
4520
+ }
4521
+ function resolveElementAnimation(animate, defs) {
4522
+ if (!animate) return [];
4523
+ const results = [];
4524
+ if (typeof animate === "string") {
4525
+ const resolved = resolveAnimation(animate, defs);
4526
+ if (resolved) results.push(resolved);
4527
+ } else if (Array.isArray(animate)) {
4528
+ for (const item of animate) {
4529
+ const resolved = resolveAnimation(item, defs);
4530
+ if (resolved) results.push(resolved);
3836
4531
  }
3837
- if (type === "L") {
3838
- const x = values[0] || 0;
3839
- const y = values[1] || 0;
3840
- currentPath.v.push([x, y]);
3841
- currentPath.i.push([x, y]);
3842
- currentPath.o.push([x, y]);
3843
- } else if (type === "C") {
3844
- const outX = values[0] || 0;
3845
- const outY = values[1] || 0;
3846
- const inX2 = values[2] || 0;
3847
- const inY2 = values[3] || 0;
3848
- const x2 = values[4] || 0;
3849
- const y2 = values[5] || 0;
3850
- currentPath.o[currentPath.o.length - 1] = [outX, outY];
3851
- currentPath.v.push([x2, y2]);
3852
- currentPath.i.push([inX2, inY2]);
3853
- currentPath.o.push([x2, y2]);
3854
- } else if (type === "Z" || type === "z") {
3855
- currentPath.c = true;
4532
+ } else {
4533
+ results.push(animate);
4534
+ }
4535
+ return results;
4536
+ }
4537
+ function interpolateValue(propName, a, b, t) {
4538
+ var _a, _b;
4539
+ if (propName === "d") {
4540
+ const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
4541
+ const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
4542
+ return { paths: interpolateBeziers(aPaths, bPaths, t) };
4543
+ }
4544
+ if (COLOUR_ATTR_NAMES.has(propName)) {
4545
+ return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
4546
+ }
4547
+ if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
4548
+ return interpolateTransformParts(a, b, t);
4549
+ }
4550
+ if (propName === "rotate" && typeof a === "number" && typeof b === "number") {
4551
+ return interpolateNum(a, b, t);
4552
+ }
4553
+ if (TRANSFORM_FN_NAMES.has(propName) || propName === "stroke-dasharray" || propName === "strokeDasharray") {
4554
+ return interpolateVec(a || [], b || [], t);
4555
+ }
4556
+ return interpolateNum(+(a || 0), +(b || 0), t);
4557
+ }
4558
+ function interpolateTransformParts(a, b, t) {
4559
+ const keys = /* @__PURE__ */ new Set([...Object.keys(a != null ? a : {}), ...Object.keys(b != null ? b : {})]);
4560
+ const out = {};
4561
+ for (const k of keys) {
4562
+ const av = a == null ? void 0 : a[k];
4563
+ const bv = b == null ? void 0 : b[k];
4564
+ if (k === "rotate") {
4565
+ out[k] = interpolateNum(+(av != null ? av : 0), +(bv != null ? bv : 0), t);
4566
+ } else if (k === "translate" || k === "scale" || k === "origin") {
4567
+ const fallback = k === "scale" ? [1, 1] : [0, 0];
4568
+ out[k] = interpolateVec(av || fallback, bv || fallback, t);
3856
4569
  } else {
3857
- console.warn('Unsupported path command "' + type + '"');
4570
+ out[k] = bv != null ? bv : av;
4571
+ }
4572
+ }
4573
+ return out;
4574
+ }
4575
+ function expandLoopKeyframes(propName, keyframes, loop, duration) {
4576
+ var _a, _b, _c, _d, _e;
4577
+ const totalIntervals = keyframes.length - 1;
4578
+ const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
4579
+ let segKfs;
4580
+ if (loop.before) {
4581
+ segKfs = keyframes.slice(0, segCount + 1);
4582
+ } else {
4583
+ segKfs = keyframes.slice(totalIntervals - segCount);
4584
+ }
4585
+ const firstT = (_b = keyframes[0].t) != null ? _b : 0;
4586
+ const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
4587
+ let fillStart, fillEnd;
4588
+ if (loop.before) {
4589
+ fillStart = 0;
4590
+ fillEnd = firstT;
4591
+ } else {
4592
+ fillStart = lastT;
4593
+ fillEnd = duration;
4594
+ }
4595
+ const fillDuration = fillEnd - fillStart;
4596
+ if (fillDuration <= 0) return keyframes;
4597
+ const segStartT = (_d = segKfs[0].t) != null ? _d : 0;
4598
+ const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
4599
+ const segDuration = segEndT - segStartT;
4600
+ if (segDuration <= 0) return keyframes;
4601
+ const template = segKfs.map((kf) => {
4602
+ var _a2, _b2;
4603
+ return {
4604
+ relT: (kf.t - segStartT) / segDuration,
4605
+ v: kf.v,
4606
+ e: kf.e,
4607
+ tangentIn: (_a2 = kf.tangentIn) != null ? _a2 : kf.ti,
4608
+ tangentOut: (_b2 = kf.tangentOut) != null ? _b2 : kf.to
4609
+ };
4610
+ });
4611
+ const fullReps = Math.floor(fillDuration / segDuration);
4612
+ const remainder = fillDuration - fullReps * segDuration;
4613
+ const partialFraction = remainder / segDuration;
4614
+ const looped = [];
4615
+ function appendRep(repStart, isReversed, partial) {
4616
+ let entries;
4617
+ if (isReversed) {
4618
+ entries = [];
4619
+ for (let i = template.length - 1; i >= 0; i--) {
4620
+ entries.push({
4621
+ relT: 1 - template[i].relT,
4622
+ v: template[i].v,
4623
+ // Easing for reversed transition: use reversed easing from the forward "from" keyframe
4624
+ e: i > 0 ? reverseEasing(template[i - 1].e) : void 0,
4625
+ // Reversed traversal swaps each vertex's in/out spatial tangents
4626
+ // (geometry is identical, walked backwards), so curvature and
4627
+ // auto-orientation survive the reversed rep.
4628
+ tangentIn: template[i].tangentOut,
4629
+ tangentOut: template[i].tangentIn
4630
+ });
4631
+ }
4632
+ } else {
4633
+ entries = template;
4634
+ }
4635
+ const cutRelT = partial !== void 0 ? partial : 1;
4636
+ for (let i = 0; i < entries.length; i++) {
4637
+ const entry = entries[i];
4638
+ if (entry.relT > cutRelT + 1e-9) {
4639
+ const prev = entries[i - 1];
4640
+ const intervalSpan = entry.relT - prev.relT;
4641
+ const localFrac = (cutRelT - prev.relT) / intervalSpan;
4642
+ const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
4643
+ const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
4644
+ const { left: leftEasing } = splitEasing(prev.e, localFrac);
4645
+ if (looped.length > 0 && prev.relT <= cutRelT) {
4646
+ looped[looped.length - 1].e = leftEasing;
4647
+ }
4648
+ looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
4649
+ return;
4650
+ }
4651
+ const pushed = {
4652
+ t: repStart + entry.relT * segDuration,
4653
+ v: entry.v,
4654
+ e: i < entries.length - 1 ? entry.e : void 0
4655
+ };
4656
+ if (entry.tangentIn) pushed.tangentIn = entry.tangentIn;
4657
+ if (entry.tangentOut) pushed.tangentOut = entry.tangentOut;
4658
+ looped.push(pushed);
4659
+ }
4660
+ }
4661
+ for (let rep = 0; rep < fullReps; rep++) {
4662
+ const distFromBoundary = loop.before ? fullReps - 1 - rep : rep;
4663
+ const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
4664
+ const repStart = fillStart + rep * segDuration;
4665
+ appendRep(repStart, isReversed);
4666
+ }
4667
+ if (partialFraction > 1e-9) {
4668
+ const isReversed = !!loop.alternate && fullReps % 2 === 0;
4669
+ const repStart = fillStart + fullReps * segDuration;
4670
+ appendRep(repStart, isReversed, partialFraction);
4671
+ }
4672
+ if (loop.before) {
4673
+ return [...looped, ...keyframes];
4674
+ } else {
4675
+ return [...keyframes, ...looped];
4676
+ }
4677
+ }
4678
+ function normalizeKeyframes(propName, propAnim, duration, defs) {
4679
+ var _a, _b, _c, _d, _e, _f, _g;
4680
+ const keyframes = propAnim.keyframes || propAnim.kfs || [];
4681
+ const normalized = [];
4682
+ for (const kf of keyframes) {
4683
+ const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
4684
+ let value = (_c = kf.value) != null ? _c : kf.v;
4685
+ const easing = (_d = kf.easing) != null ? _d : kf.e;
4686
+ if (propName === "d") {
4687
+ value = normalizePathValue(value);
4688
+ }
4689
+ const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
4690
+ if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
4691
+ value = (_e = parseColor(value)) != null ? _e : value;
4692
+ }
4693
+ const normKf = {
4694
+ t: timePct,
4695
+ v: value,
4696
+ e: resolveEasing(easing, defs)
4697
+ };
4698
+ const tIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
4699
+ const tOut = (_g = kf.tangentOut) != null ? _g : kf.to;
4700
+ if (tIn) normKf.tangentIn = tIn;
4701
+ if (tOut) normKf.tangentOut = tOut;
4702
+ normalized.push(normKf);
4703
+ }
4704
+ normalized.sort((a, b) => {
4705
+ var _a2, _b2;
4706
+ return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
4707
+ });
4708
+ const loopRaw = propAnim.loop;
4709
+ const loop = loopRaw === true ? {} : loopRaw || void 0;
4710
+ if (loop && normalized.length >= 2) {
4711
+ return expandLoopKeyframes(propName, normalized, loop, duration);
4712
+ }
4713
+ return normalized;
4714
+ }
4715
+ function mergeAnimationDefinitions(animations) {
4716
+ const merged = {};
4717
+ for (const anim of animations) {
4718
+ for (const [prop, propAnim] of Object.entries(anim)) {
4719
+ merged[prop] = propAnim;
4720
+ }
4721
+ }
4722
+ return merged;
4723
+ }
4724
+ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
4725
+ var _a;
4726
+ const loopRaw = propAnim.loop;
4727
+ if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
4728
+ const loop = loopRaw === true ? {} : loopRaw;
4729
+ const rawKfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
4730
+ if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
4731
+ const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
4732
+ const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
4733
+ const kfs = rawKfs.map((kf) => {
4734
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
4735
+ const t = (_a2 = kf.t) != null ? _a2 : kf.time;
4736
+ let v = (_b = kf.v) != null ? _b : kf.value;
4737
+ if (propName === "d") v = normalizePathValue(v);
4738
+ if (isColour) v = (_c = parseColor(v)) != null ? _c : v;
4739
+ const e = (_d = kf.e) != null ? _d : kf.easing;
4740
+ const out2 = { t, v, e };
4741
+ if ((_e = kf.tangentIn) != null ? _e : kf.ti) out2.tangentIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
4742
+ if ((_g = kf.tangentOut) != null ? _g : kf.to) out2.tangentOut = (_h = kf.tangentOut) != null ? _h : kf.to;
4743
+ return out2;
4744
+ });
4745
+ const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
4746
+ const out = { kfs: expanded };
4747
+ if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
4748
+ return out;
4749
+ }
4750
+ function materialiseInternalLoopsInTree(root, duration) {
4751
+ const ret = walkAndMaterialiseLoops(root, duration);
4752
+ return ret != null ? ret : root;
4753
+ }
4754
+ function walkAndMaterialiseLoops(node, duration) {
4755
+ let newChildren;
4756
+ if (node.children) {
4757
+ for (let i = 0; i < node.children.length; i++) {
4758
+ const ret = walkAndMaterialiseLoops(node.children[i], duration);
4759
+ if (ret !== null) {
4760
+ if (!newChildren) newChildren = node.children.slice();
4761
+ newChildren[i] = ret;
4762
+ }
4763
+ }
4764
+ }
4765
+ let newAnimate;
4766
+ const animBucket = node.animate;
4767
+ if (animBucket && typeof animBucket === "object" && !Array.isArray(animBucket)) {
4768
+ const animDef = animBucket;
4769
+ for (const propName of Object.keys(animDef)) {
4770
+ const propAnim = animDef[propName];
4771
+ const materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);
4772
+ if (materialised !== propAnim) {
4773
+ if (!newAnimate) newAnimate = __spreadValues({}, animDef);
4774
+ newAnimate[propName] = materialised;
4775
+ }
4776
+ }
4777
+ }
4778
+ if (!newChildren && !newAnimate) return null;
4779
+ const cloned = __spreadValues({}, node);
4780
+ if (newChildren) cloned.children = newChildren;
4781
+ if (newAnimate) cloned.animate = newAnimate;
4782
+ return cloned;
4783
+ }
4784
+ var _elementIdCounter = 0;
4785
+ function generateElementId() {
4786
+ return "_px_el_" + ++_elementIdCounter;
4787
+ }
4788
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.webapi) {
4789
+ const normalized = {};
4790
+ for (const [propName, propAnim] of Object.entries(animDef)) {
4791
+ const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
4792
+ if (normalizedKfs.length > 0) {
4793
+ const out = { kfs: normalizedKfs };
4794
+ if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
4795
+ if (propAnim.loop !== void 0) out.loop = propAnim.loop;
4796
+ normalized[propName] = engine === PxAnimatorEngine.webapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
4797
+ }
4798
+ }
4799
+ return normalized;
4800
+ }
4801
+ function getNormalisedBindings(doc, engine = PxAnimatorEngine.webapi) {
4802
+ const animatorConfig = getAnimatorConfig(doc) || {};
4803
+ const defs = getDefs(doc);
4804
+ const duration = animatorConfig.duration || 1e3;
4805
+ const bindings = [];
4806
+ const processAnimation = (id, animate) => {
4807
+ if (!animate) return null;
4808
+ const animDefs = resolveElementAnimation(animate, defs);
4809
+ if (animDefs.length === 0) return null;
4810
+ const merged = mergeAnimationDefinitions(animDefs);
4811
+ const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
4812
+ if (Object.keys(normalizedAnim).length === 0) return null;
4813
+ return {
4814
+ id,
4815
+ animate: normalizedAnim
4816
+ };
4817
+ };
4818
+ const docBindings = getBindings(doc);
4819
+ if (docBindings) {
4820
+ for (const binding of docBindings) {
4821
+ const normalized = processAnimation(binding.id, binding.animate);
4822
+ if (normalized) bindings.push(normalized);
4823
+ }
4824
+ }
4825
+ const processNode = (node) => {
4826
+ const inlineAnim = node.animate;
4827
+ if (inlineAnim && Object.keys(inlineAnim).length > 0) {
4828
+ const nodeId = node.id || generateElementId();
4829
+ node.id = nodeId;
4830
+ const normalized = processAnimation(nodeId, inlineAnim);
4831
+ if (normalized) bindings.push(normalized);
4832
+ }
4833
+ if (node.children) {
4834
+ for (let i = 0; i < node.children.length; i++) {
4835
+ processNode(node.children[i]);
4836
+ }
4837
+ }
4838
+ };
4839
+ if (doc.children) {
4840
+ for (let i = 0; i < doc.children.length; i++) {
4841
+ processNode(doc.children[i]);
3858
4842
  }
3859
4843
  }
3860
- return res;
4844
+ return bindings;
3861
4845
  }
3862
- function extractPathData(str) {
3863
- if (str.startsWith("path(") && str.endsWith(")")) {
3864
- return str.slice(5, -1);
3865
- }
3866
- if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str)) {
3867
- return str;
4846
+ function getKeyframesPair(keyframes, progress) {
4847
+ var _a, _b;
4848
+ let prevKf = keyframes[0];
4849
+ let nextKf = keyframes[keyframes.length - 1];
4850
+ for (let j = 0; j < keyframes.length - 1; j++) {
4851
+ const aOff = (_a = keyframes[j].t) != null ? _a : 0;
4852
+ const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
4853
+ if (aOff <= progress && progress <= bOff) {
4854
+ prevKf = keyframes[j];
4855
+ nextKf = keyframes[j + 1];
4856
+ break;
4857
+ }
3868
4858
  }
3869
- return void 0;
3870
- }
3871
- function isPathString(value) {
3872
- return typeof value === "string" && extractPathData(value) !== void 0;
4859
+ return { prevKf, nextKf };
3873
4860
  }
3874
- function normalizePathValue(value) {
3875
- if (value && typeof value === "object" && typeof value.path === "string") {
3876
- const d = extractPathData(value.path);
3877
- return d ? { paths: parseSvgPathToBezier(d) } : value;
4861
+ function calcPropertyValue(propName, propAnim, progress) {
4862
+ var _a, _b, _c, _d, _e, _f, _g;
4863
+ const keyframes = propAnim.kfs || propAnim.keyframes || [];
4864
+ if (keyframes.length === 0) return null;
4865
+ const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
4866
+ let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
4867
+ localProgress = clamp(localProgress, 0, 1);
4868
+ const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
4869
+ if (easing && Array.isArray(easing)) {
4870
+ try {
4871
+ localProgress = cubicBezier(easing)(localProgress);
4872
+ } catch (e) {
4873
+ }
3878
4874
  }
3879
- if (value && typeof value === "object" && "paths" in value) {
3880
- const pathsArray = value.paths;
3881
- if (Array.isArray(pathsArray) && pathsArray.length > 0) {
3882
- if (isPathString(pathsArray[0])) {
3883
- const paths = [];
3884
- for (const pathStr2 of pathsArray) {
3885
- const d = extractPathData(pathStr2);
3886
- if (d) {
3887
- paths.push(...parseSvgPathToBezier(d));
3888
- }
3889
- }
3890
- return { paths };
4875
+ let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
4876
+ let cssValue = null;
4877
+ const prevV = (_d = prevKf == null ? void 0 : prevKf.v) != null ? _d : prevKf == null ? void 0 : prevKf.value;
4878
+ const nextV = (_e = nextKf == null ? void 0 : nextKf.v) != null ? _e : nextKf == null ? void 0 : nextKf.value;
4879
+ if (cssAttrName === "d") {
4880
+ const prevPaths = (_f = prevV == null ? void 0 : prevV.paths) != null ? _f : Array.isArray(prevV) ? prevV : [];
4881
+ const nextPaths = (_g = nextV == null ? void 0 : nextV.paths) != null ? _g : Array.isArray(nextV) ? nextV : [];
4882
+ cssValue = interpolateBeziers(
4883
+ prevPaths,
4884
+ nextPaths,
4885
+ localProgress
4886
+ ).map((bz) => bezierToSvgPath(bz)).join("");
4887
+ } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
4888
+ cssValue = toRGBA(interpolateColor(
4889
+ prevV || [0, 0, 0, 1],
4890
+ nextV || [0, 0, 0, 1],
4891
+ localProgress
4892
+ ));
4893
+ cssAttrName = propName;
4894
+ } else if (cssAttrName === "stroke-dasharray") {
4895
+ cssValue = interpolateVec(
4896
+ prevV || [],
4897
+ nextV || [],
4898
+ localProgress
4899
+ ).join(" ");
4900
+ cssAttrName = propName;
4901
+ } else if (cssAttrName === "transform" && prevV !== null && typeof prevV === "object" && !Array.isArray(prevV)) {
4902
+ const partKeys = /* @__PURE__ */ new Set([
4903
+ ...prevV ? Object.keys(prevV) : [],
4904
+ ...nextV ? Object.keys(nextV) : []
4905
+ ]);
4906
+ const partsResult = {};
4907
+ for (const partKey of partKeys) {
4908
+ const prevPart = prevV == null ? void 0 : prevV[partKey];
4909
+ const nextPart = nextV == null ? void 0 : nextV[partKey];
4910
+ if (partKey === "rotate") {
4911
+ partsResult.rotate = interpolateNum(+(prevPart != null ? prevPart : 0), +(nextPart != null ? nextPart : 0), localProgress);
4912
+ } else if (partKey === "translate" || partKey === "scale" || partKey === "origin") {
4913
+ const fallback = partKey === "scale" ? [1, 1] : [0, 0];
4914
+ const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);
4915
+ partsResult[partKey] = interp;
3891
4916
  }
3892
4917
  }
3893
- return value;
3894
- }
3895
- if (Array.isArray(value)) {
3896
- if (value.length > 0 && isPathString(value[0])) {
3897
- const paths = [];
3898
- for (const pathStr2 of value) {
3899
- const d = extractPathData(pathStr2);
3900
- if (d) {
3901
- paths.push(...parseSvgPathToBezier(d));
3902
- }
4918
+ if (propAnimIsMotionPath(propAnim)) {
4919
+ const prevTr = prevV.translate;
4920
+ const nextTr = nextV.translate;
4921
+ if (Array.isArray(prevTr) && Array.isArray(nextTr)) {
4922
+ const sample = evaluateMotionPathSegment(
4923
+ prevKf,
4924
+ nextKf,
4925
+ [+prevTr[0], +prevTr[1]],
4926
+ [+nextTr[0], +nextTr[1]],
4927
+ localProgress,
4928
+ !!propAnim.autoOrient
4929
+ );
4930
+ partsResult.translate = [sample.translate[0], sample.translate[1]];
4931
+ if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
3903
4932
  }
3904
- return { paths };
3905
4933
  }
3906
- return { paths: value };
3907
- }
3908
- if (isPathString(value)) {
3909
- const d = extractPathData(value);
3910
- return { paths: parseSvgPathToBezier(d) };
3911
- }
3912
- return value;
3913
- }
3914
- function resolveEasing(easing, defs) {
3915
- var _a;
3916
- if (!easing) return void 0;
3917
- if (Array.isArray(easing)) {
3918
- return easing;
4934
+ cssValue = composeTransformParts(partsResult, { withUnits: false });
4935
+ cssAttrName = "transform";
4936
+ } else if (cssAttrName === "translate") {
4937
+ const v = interpolateVec(
4938
+ prevV || [0, 0],
4939
+ nextV || [0, 0],
4940
+ localProgress
4941
+ );
4942
+ cssValue = "translate(" + v.join(",") + ")";
4943
+ cssAttrName = "transform";
4944
+ } else if (cssAttrName === "rotate") {
4945
+ const v = interpolateNum(
4946
+ +(prevV || 0),
4947
+ +(nextV || 0),
4948
+ localProgress
4949
+ );
4950
+ cssValue = "rotate(" + v + ")";
4951
+ cssAttrName = "transform";
4952
+ } else if (cssAttrName === "scale") {
4953
+ const v = interpolateVec(
4954
+ prevV || [1, 1],
4955
+ nextV || [1, 1],
4956
+ localProgress
4957
+ );
4958
+ cssValue = "scale(" + v.join(",") + ")";
4959
+ cssAttrName = "transform";
4960
+ } else {
4961
+ const num2 = interpolateNum(
4962
+ +(prevV || 0),
4963
+ +(nextV || 0),
4964
+ localProgress
4965
+ );
4966
+ cssValue = num2;
3919
4967
  }
3920
- if ((_a = defs == null ? void 0 : defs.easings) == null ? void 0 : _a[easing]) {
3921
- return defs.easings[easing];
4968
+ if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
4969
+ cssValue = cssValue * 100 + "%";
3922
4970
  }
3923
- console.warn("Unknown easing name: " + easing);
3924
- return void 0;
4971
+ return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
3925
4972
  }
3926
- function resolveAnimation(animRef, defs) {
3927
- var _a;
3928
- if (typeof animRef === "string") {
3929
- const resolved = (_a = defs == null ? void 0 : defs.animations) == null ? void 0 : _a[animRef];
3930
- if (!resolved) {
3931
- console.warn("Unknown animation name: " + animRef);
4973
+ function calcAnimationValues(animDef, progress) {
4974
+ const result = {};
4975
+ for (const [propName, propAnim] of Object.entries(animDef)) {
4976
+ const computed = calcPropertyValue(propName, propAnim, progress);
4977
+ if (computed) {
4978
+ result[computed.k] = computed.v;
3932
4979
  }
3933
- return resolved;
3934
4980
  }
3935
- return animRef;
4981
+ return result;
3936
4982
  }
3937
- function resolveElementAnimation(animate, defs) {
3938
- if (!animate) return [];
3939
- const results = [];
3940
- if (typeof animate === "string") {
3941
- const resolved = resolveAnimation(animate, defs);
3942
- if (resolved) results.push(resolved);
3943
- } else if (Array.isArray(animate)) {
3944
- for (const item of animate) {
3945
- const resolved = resolveAnimation(item, defs);
3946
- if (resolved) results.push(resolved);
4983
+ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4984
+ if (!trimPath) return node;
4985
+ const trimAllAsOne = !!trimPath.trimAllAsOne;
4986
+ const leafEntries = [];
4987
+ let acc = 0;
4988
+ const measure = (n) => {
4989
+ if (Array.isArray(n.children) && n.children.length > 0) {
4990
+ for (const ch of n.children) measure(ch);
4991
+ return;
3947
4992
  }
3948
- } else {
3949
- results.push(animate);
3950
- }
3951
- return results;
4993
+ const d = typeof n.d === "string" ? n.d : rectToPathD(n);
4994
+ if (d === void 0) return;
4995
+ const subpaths = parseSvgPathToBezier(d);
4996
+ if (!subpaths.length) return;
4997
+ const entry = { leaf: n, subpaths: [] };
4998
+ for (const sp of subpaths) {
4999
+ if (!trimAllAsOne) acc = 0;
5000
+ const lengthPx = pxBezierPathLength(sp);
5001
+ entry.subpaths.push({ subpath: sp, lengthPx, startOffsetPx: acc });
5002
+ acc += lengthPx;
5003
+ }
5004
+ leafEntries.push(entry);
5005
+ };
5006
+ measure(node);
5007
+ if (!leafEntries.length) return node;
5008
+ const chainLengthPx = acc;
5009
+ if (trimAllAsOne && chainLengthPx < 1e-3) return node;
5010
+ const offsetReadRaw = readAnimatable(trimPath.offset);
5011
+ const offsetRead = offsetReadRaw.kind === "absent" ? { kind: "static", value: 0 } : offsetReadRaw;
5012
+ const rangeReadRaw = readRangeWithCrossings(trimPath.range);
5013
+ const rangeRead = rangeReadRaw.kind === "absent" ? { kind: "static", value: [0, 1] } : rangeReadRaw;
5014
+ const offsetValues = readScalarValues(offsetRead);
5015
+ const minOffset = offsetValues.length ? Math.min(...offsetValues) : 0;
5016
+ const maxOffset = offsetValues.length ? Math.max(...offsetValues) : 0;
5017
+ const minMaxOffset = [minOffset, maxOffset];
5018
+ if (leafEntries.length === 1 && leafEntries[0].leaf === node && leafEntries[0].subpaths.length === 1) {
5019
+ const entry = leafEntries[0];
5020
+ const sp = entry.subpaths[0];
5021
+ const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
5022
+ if (pathLengthPx < 1e-3) return node;
5023
+ const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
5024
+ return collapseLeafWithTrim(entry.leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead);
5025
+ }
5026
+ const replacements = /* @__PURE__ */ new Map();
5027
+ for (const entry of leafEntries) {
5028
+ const newChildren = [];
5029
+ for (const sp of entry.subpaths) {
5030
+ const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
5031
+ if (pathLengthPx < 1e-3) continue;
5032
+ const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
5033
+ newChildren.push(...buildSubpathNodes(entry.leaf, sp.subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx));
5034
+ }
5035
+ replacements.set(entry.leaf, wrapLeafAsGroup(entry.leaf, newChildren));
5036
+ }
5037
+ const swap = (n) => {
5038
+ const r = replacements.get(n);
5039
+ if (r) return r;
5040
+ if (Array.isArray(n.children) && n.children.length > 0) {
5041
+ return __spreadProps(__spreadValues({}, n), { children: n.children.map(swap) });
5042
+ }
5043
+ return n;
5044
+ };
5045
+ return swap(node);
3952
5046
  }
3953
- function interpolateValue(propName, a, b, t) {
3954
- var _a, _b;
3955
- if (propName === "d") {
3956
- const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
3957
- const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
3958
- return { paths: interpolateBeziers(aPaths, bPaths, t) };
5047
+ function wrapLeafAsGroup(leaf, children) {
5048
+ const wrapper = __spreadProps(__spreadValues({}, leaf), { type: "g", children });
5049
+ delete wrapper.d;
5050
+ delete wrapper.strokeDasharray;
5051
+ delete wrapper.strokeDashoffset;
5052
+ delete wrapper.effects;
5053
+ return wrapper;
5054
+ }
5055
+ function buildSubpathNodes(leaf, subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx) {
5056
+ const offsetToDashOffset = makeOffsetToDashOffset(startOffsetPct, pathLengthPx, minMaxOffset);
5057
+ const rangeToDasharray = makeRangeToDasharray(pathLengthPx, minMaxOffset);
5058
+ const dashOffsetAttr = computeAnimAttr(offsetRead, offsetToDashOffset);
5059
+ const dashArrayAttr = computeAnimAttr(rangeRead, rangeToDasharray);
5060
+ const strokeOpacityAttr = computeOpacityFromRange(rangeRead);
5061
+ const dStr = bezierToSvgPath(subpath);
5062
+ const base = makeBareSubpath(dStr);
5063
+ applyAttr(base, "strokeDasharray", dashArrayAttr);
5064
+ applyAttr(base, "strokeDashoffset", dashOffsetAttr);
5065
+ applyAttr(base, "strokeOpacity", strokeOpacityAttr);
5066
+ return [base];
5067
+ }
5068
+ function collapseLeafWithTrim(leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead) {
5069
+ const offsetToDashOffset = makeOffsetToDashOffset(startOffsetPct, pathLengthPx, minMaxOffset);
5070
+ const rangeToDasharray = makeRangeToDasharray(pathLengthPx, minMaxOffset);
5071
+ const node = __spreadValues({}, leaf);
5072
+ delete node.effects;
5073
+ applyAttr(node, "strokeDasharray", computeAnimAttr(rangeRead, rangeToDasharray));
5074
+ applyAttr(node, "strokeDashoffset", computeAnimAttr(offsetRead, offsetToDashOffset));
5075
+ applyAttr(node, "strokeOpacity", computeOpacityFromRange(rangeRead));
5076
+ return node;
5077
+ }
5078
+ function makeBareSubpath(dStr) {
5079
+ return { type: "path", d: dStr };
5080
+ }
5081
+ var SMALL_PADDING_PX = 1;
5082
+ function makeOffsetToDashOffset(startOffsetPct, pathLengthPx, minMaxOffset) {
5083
+ const [minIdx] = getOffsetIndexRange(minMaxOffset);
5084
+ return (offsetVal) => pathLengthPx * (-offsetVal - minIdx + startOffsetPct) + SMALL_PADDING_PX;
5085
+ }
5086
+ function makeRangeToDasharray(pathLengthPx, minMaxOffset) {
5087
+ const [minIdx, maxIdx] = getOffsetIndexRange(minMaxOffset);
5088
+ const repeats = maxIdx - minIdx + 1;
5089
+ return (rangeVal) => {
5090
+ const a = clamp(rangeVal[0], 0, 1);
5091
+ const b = clamp(rangeVal[1], 0, 1);
5092
+ const minR = Math.min(a, b);
5093
+ const maxR = Math.max(a, b);
5094
+ const out = [0];
5095
+ let gap = SMALL_PADDING_PX;
5096
+ for (let i = 0; i < repeats; i++) {
5097
+ out.push(gap + minR * pathLengthPx);
5098
+ out.push((maxR - minR) * pathLengthPx);
5099
+ gap = (1 - maxR) * pathLengthPx;
5100
+ }
5101
+ out.push(gap + SMALL_PADDING_PX);
5102
+ return out;
5103
+ };
5104
+ }
5105
+ function getOffsetIndexRange(minMaxOffset) {
5106
+ return [
5107
+ Math.floor(Math.min(-minMaxOffset[0], -minMaxOffset[1])),
5108
+ Math.ceil(Math.max(-minMaxOffset[0], -minMaxOffset[1]))
5109
+ ];
5110
+ }
5111
+ function readScalarValues(r) {
5112
+ var _a;
5113
+ if (r.kind === "absent") return [];
5114
+ if (r.kind === "static") return [r.value];
5115
+ const out = [];
5116
+ for (const kf of r.keyframes) {
5117
+ const v = (_a = kf.value) != null ? _a : kf.v;
5118
+ if (typeof v === "number") out.push(v);
3959
5119
  }
3960
- if (COLOUR_ATTR_NAMES.has(propName)) {
3961
- return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
5120
+ return out;
5121
+ }
5122
+ function computeAnimAttr(read, map) {
5123
+ if (read.kind === "absent") return void 0;
5124
+ if (read.kind === "static") return { kind: "static", value: map(read.value) };
5125
+ return {
5126
+ kind: "animated",
5127
+ keyframes: read.keyframes.map((kf) => {
5128
+ var _a, _b, _c, _d;
5129
+ return {
5130
+ time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5131
+ value: map((_c = kf.value) != null ? _c : kf.v),
5132
+ easing: (_d = kf.easing) != null ? _d : kf.e
5133
+ };
5134
+ })
5135
+ };
5136
+ }
5137
+ function applyAttr(node, attrName, attr) {
5138
+ if (!attr) return;
5139
+ if (attr.kind === "static") {
5140
+ node[attrName] = attr.value;
5141
+ return;
5142
+ }
5143
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
5144
+ const animate = __spreadValues({}, prevAnimate || {});
5145
+ animate[attrName] = { keyframes: attr.keyframes };
5146
+ node.animate = animate;
5147
+ }
5148
+ function computeOpacityFromRange(rangeRead) {
5149
+ var _a, _b, _c, _d, _e, _f;
5150
+ const hide = (v) => v[0] === v[1];
5151
+ if (rangeRead.kind === "absent") return void 0;
5152
+ if (rangeRead.kind === "static") return hide(rangeRead.value) ? { kind: "static", value: 0 } : void 0;
5153
+ const kfs = rangeRead.keyframes;
5154
+ let anyHide = false;
5155
+ let allHide = true;
5156
+ for (const kf of kfs) {
5157
+ if (hide((_a = kf.value) != null ? _a : kf.v)) anyHide = true;
5158
+ else allHide = false;
5159
+ }
5160
+ if (!anyHide) return void 0;
5161
+ if (allHide) return { kind: "static", value: 0 };
5162
+ const out = [];
5163
+ for (let i = 0; i < kfs.length; i++) {
5164
+ const kf = kfs[i];
5165
+ const prevKf = i > 0 ? kfs[i - 1] : void 0;
5166
+ const nextKf = i < kfs.length - 1 ? kfs[i + 1] : void 0;
5167
+ const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
5168
+ const thisHide = hide((_d = kf.value) != null ? _d : kf.v);
5169
+ const prevHide = prevKf ? thisHide && hide((_e = prevKf.value) != null ? _e : prevKf.v) : thisHide;
5170
+ const nextHide = nextKf ? thisHide && hide((_f = nextKf.value) != null ? _f : nextKf.v) : thisHide;
5171
+ if (prevHide && !nextHide) {
5172
+ out.push({ time: t, value: 0 });
5173
+ out.push({ time: t + 1, value: 1 });
5174
+ } else if (!prevHide && nextHide) {
5175
+ out.push({ time: t - 1, value: 1 });
5176
+ out.push({ time: t, value: 0 });
5177
+ }
5178
+ }
5179
+ if (out.length <= 1) return void 0;
5180
+ return { kind: "animated", keyframes: out };
5181
+ }
5182
+ function readRangeWithCrossings(raw) {
5183
+ const r = readAnimatable(raw);
5184
+ if (r.kind !== "animated") return r;
5185
+ const kfs = r.keyframes.map((kf) => {
5186
+ var _a, _b, _c, _d;
5187
+ return {
5188
+ time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5189
+ value: (_c = kf.value) != null ? _c : kf.v,
5190
+ easing: (_d = kf.easing) != null ? _d : kf.e
5191
+ };
5192
+ });
5193
+ const hasReverse = kfs.some((kf) => kf.value[0] > kf.value[1]);
5194
+ if (!hasReverse) {
5195
+ return {
5196
+ kind: "animated",
5197
+ keyframes: kfs.map((kf) => ({ time: kf.time, value: kf.value, easing: kf.easing }))
5198
+ };
3962
5199
  }
3963
- if (TRANSFORM_FN_NAMES.has(propName) || propName === "stroke-dasharray" || propName === "strokeDasharray") {
3964
- return interpolateVec(a || [], b || [], t);
5200
+ const crossingTimes = [];
5201
+ for (let i = 1; i < kfs.length; i++) {
5202
+ const prev = kfs[i - 1];
5203
+ const cur = kfs[i];
5204
+ const dPrev = prev.value[1] - prev.value[0];
5205
+ const dCur = cur.value[1] - cur.value[0];
5206
+ if (dPrev * dCur < 0) {
5207
+ const t = bisectionForRangeCrossing(prev, cur);
5208
+ if (t !== null && t > prev.time && t < cur.time) {
5209
+ crossingTimes.push(Math.round(t));
5210
+ }
5211
+ }
3965
5212
  }
3966
- return interpolateNum(+(a || 0), +(b || 0), t);
5213
+ const uniqueTs = Array.from(new Set(crossingTimes)).sort((a, b) => a - b);
5214
+ const out = [];
5215
+ let j = 0;
5216
+ for (const kf of kfs) {
5217
+ while (j < uniqueTs.length && uniqueTs[j] < kf.time) {
5218
+ const t = uniqueTs[j++];
5219
+ const v2 = interpolateRangeAt(kfs, t);
5220
+ const m = (v2[0] + v2[1]) / 2;
5221
+ out.push({ time: t, value: [m, m] });
5222
+ }
5223
+ const v = kf.value[0] > kf.value[1] ? [kf.value[1], kf.value[0]] : kf.value;
5224
+ out.push({ time: kf.time, value: v, easing: kf.easing });
5225
+ }
5226
+ while (j < uniqueTs.length) {
5227
+ const t = uniqueTs[j++];
5228
+ const v = interpolateRangeAt(kfs, t);
5229
+ const m = (v[0] + v[1]) / 2;
5230
+ out.push({ time: t, value: [m, m] });
5231
+ }
5232
+ return { kind: "animated", keyframes: out };
3967
5233
  }
3968
- function expandLoopKeyframes(propName, keyframes, loop, duration) {
3969
- var _a, _b, _c, _d, _e;
3970
- const totalIntervals = keyframes.length - 1;
3971
- const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
3972
- let segKfs;
3973
- if (loop.before) {
3974
- segKfs = keyframes.slice(0, segCount + 1);
3975
- } else {
3976
- segKfs = keyframes.slice(totalIntervals - segCount);
3977
- }
3978
- const firstT = (_b = keyframes[0].t) != null ? _b : 0;
3979
- const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
3980
- let fillStart, fillEnd;
3981
- if (loop.before) {
3982
- fillStart = 0;
3983
- fillEnd = firstT;
3984
- } else {
3985
- fillStart = lastT;
3986
- fillEnd = duration;
3987
- }
3988
- const fillDuration = fillEnd - fillStart;
3989
- if (fillDuration <= 0) return keyframes;
3990
- const segStartT = (_d = segKfs[0].t) != null ? _d : 0;
3991
- const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
3992
- const segDuration = segEndT - segStartT;
3993
- if (segDuration <= 0) return keyframes;
3994
- const template = segKfs.map((kf) => ({
3995
- relT: (kf.t - segStartT) / segDuration,
3996
- v: kf.v,
3997
- e: kf.e
3998
- }));
3999
- const fullReps = Math.floor(fillDuration / segDuration);
4000
- const remainder = fillDuration - fullReps * segDuration;
4001
- const partialFraction = remainder / segDuration;
4002
- const looped = [];
4003
- function appendRep(repStart, isReversed, partial) {
4004
- let entries;
4005
- if (isReversed) {
4006
- entries = [];
4007
- for (let i = template.length - 1; i >= 0; i--) {
4008
- entries.push({
4009
- relT: 1 - template[i].relT,
4010
- v: template[i].v,
4011
- // Easing for reversed transition: use reversed easing from the forward "from" keyframe
4012
- e: i > 0 ? reverseEasing(template[i - 1].e) : void 0
4013
- });
4014
- }
5234
+ function bisectionForRangeCrossing(prev, cur) {
5235
+ const f = (t) => {
5236
+ const a = (t - prev.time) / (cur.time - prev.time);
5237
+ const v0 = prev.value[0] + (cur.value[0] - prev.value[0]) * a;
5238
+ const v1 = prev.value[1] + (cur.value[1] - prev.value[1]) * a;
5239
+ return v1 - v0;
5240
+ };
5241
+ let lo = prev.time, hi = cur.time;
5242
+ let fLo = f(lo);
5243
+ if (fLo === 0) return lo;
5244
+ const fHi = f(hi);
5245
+ if (fHi === 0) return hi;
5246
+ if (fLo * fHi > 0) return null;
5247
+ for (let i = 0; i < 100; i++) {
5248
+ const mid = (lo + hi) / 2;
5249
+ const fMid = f(mid);
5250
+ if (fMid === 0 || Math.abs(hi - lo) < 1e-4) return mid;
5251
+ if (fLo * fMid < 0) {
5252
+ hi = mid;
4015
5253
  } else {
4016
- entries = template;
4017
- }
4018
- const cutRelT = partial !== void 0 ? partial : 1;
4019
- for (let i = 0; i < entries.length; i++) {
4020
- const entry = entries[i];
4021
- if (entry.relT > cutRelT + 1e-9) {
4022
- const prev = entries[i - 1];
4023
- const intervalSpan = entry.relT - prev.relT;
4024
- const localFrac = (cutRelT - prev.relT) / intervalSpan;
4025
- const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
4026
- const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
4027
- const { left: leftEasing } = splitEasing(prev.e, localFrac);
4028
- if (looped.length > 0 && prev.relT <= cutRelT) {
4029
- looped[looped.length - 1].e = leftEasing;
4030
- }
4031
- looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
4032
- return;
4033
- }
4034
- looped.push({
4035
- t: repStart + entry.relT * segDuration,
4036
- v: entry.v,
4037
- e: i < entries.length - 1 ? entry.e : void 0
4038
- });
5254
+ lo = mid;
5255
+ fLo = fMid;
4039
5256
  }
4040
5257
  }
4041
- for (let rep = 0; rep < fullReps; rep++) {
4042
- const distFromBoundary = loop.before ? fullReps - 1 - rep : rep;
4043
- const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
4044
- const repStart = fillStart + rep * segDuration;
4045
- appendRep(repStart, isReversed);
5258
+ return (lo + hi) / 2;
5259
+ }
5260
+ function interpolateRangeAt(kfs, t) {
5261
+ if (t <= kfs[0].time) return kfs[0].value;
5262
+ if (t >= kfs[kfs.length - 1].time) return kfs[kfs.length - 1].value;
5263
+ for (let i = 1; i < kfs.length; i++) {
5264
+ if (t <= kfs[i].time) {
5265
+ const prev = kfs[i - 1];
5266
+ const cur = kfs[i];
5267
+ const a = (t - prev.time) / (cur.time - prev.time);
5268
+ return [
5269
+ prev.value[0] + (cur.value[0] - prev.value[0]) * a,
5270
+ prev.value[1] + (cur.value[1] - prev.value[1]) * a
5271
+ ];
5272
+ }
5273
+ }
5274
+ return kfs[kfs.length - 1].value;
5275
+ }
5276
+ function pxBezierPathLength(path) {
5277
+ const v = path.v;
5278
+ if (!v || v.length < 2) return 0;
5279
+ let total = 0;
5280
+ for (let i = 0; i < v.length - 1; i++) {
5281
+ total += segmentLength(path, i, i + 1);
4046
5282
  }
4047
- if (partialFraction > 1e-9) {
4048
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
4049
- const repStart = fillStart + fullReps * segDuration;
4050
- appendRep(repStart, isReversed, partialFraction);
5283
+ if (path.c && v.length > 1) {
5284
+ total += segmentLength(path, v.length - 1, 0);
4051
5285
  }
4052
- if (loop.before) {
4053
- return [...looped, ...keyframes];
5286
+ return total;
5287
+ }
5288
+ function segmentLength(path, from, to) {
5289
+ var _a, _b, _c, _d;
5290
+ const v = path.v;
5291
+ const p0 = v[from];
5292
+ const p3 = v[to];
5293
+ const p1 = (_b = (_a = path.o) == null ? void 0 : _a[from]) != null ? _b : p0;
5294
+ const p2 = (_d = (_c = path.i) == null ? void 0 : _c[to]) != null ? _d : p3;
5295
+ const lut = bezier2D_arcLengthLUT(p0, p1, p2, p3);
5296
+ return lut.ds[lut.ds.length - 1];
5297
+ }
5298
+ function rectToPathD(node) {
5299
+ var _a, _b, _c, _d;
5300
+ if (node.type !== "rect") return void 0;
5301
+ const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
5302
+ const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
5303
+ return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
5304
+ }
5305
+ function applyPlayerEffects(root) {
5306
+ const ctx = {
5307
+ defs: [],
5308
+ warnings: [],
5309
+ errors: [],
5310
+ idMap: /* @__PURE__ */ new Map(),
5311
+ nextId: 0,
5312
+ contentRefInnerIds: /* @__PURE__ */ new Map(),
5313
+ maskAncestorChains: /* @__PURE__ */ new Map()
5314
+ };
5315
+ const working = clone(root);
5316
+ indexById(working, ctx.idMap);
5317
+ identifyContentRefTargets(working, ctx, () => genId(ctx, "inner"));
5318
+ collectMaskAncestorChains(working, ctx);
5319
+ const afterPass1 = applyPlayerEffects_exceptRetime(working, ctx);
5320
+ const out = applyPlayerEffects_retime(afterPass1, ctx);
5321
+ spliceDefs(out, ctx.defs);
5322
+ return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
5323
+ }
5324
+ function applyPlayerEffects_exceptRetime(node, ctx) {
5325
+ if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
5326
+ const fx = node.effects;
5327
+ const originalId = typeof node.id === "string" ? node.id : void 0;
5328
+ const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
5329
+ if (!fx && !innerIdForContentRef) return node;
5330
+ const { transformation, repeater, maskedBy, trimPath, retime, ref, fillGradient, strokeGradient, textAlongPath } = fx != null ? fx : {};
5331
+ const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
5332
+ if (fx) delete node.effects;
5333
+ let n = node;
5334
+ n = applyTextAlongPathEffect(n, textAlongPath, ctx);
5335
+ n = applyFillGradientEffect(n, fillGradient, ctx);
5336
+ n = applyStrokeGradientEffect(n, strokeGradient, ctx);
5337
+ n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
5338
+ n = applyRepeaterEffect(n, repeater, ctx);
5339
+ n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
5340
+ if (innerIdForContentRef) {
5341
+ n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
4054
5342
  } else {
4055
- return [...keyframes, ...looped];
5343
+ n = applyRefAndTransformationEffect(n, ref, transformation, ctx);
4056
5344
  }
5345
+ if (retime) node.effects = { retime };
5346
+ if (originalId) ctx.idMap.set(originalId, n);
5347
+ return n;
4057
5348
  }
4058
- function normalizeKeyframes(propName, propAnim, duration, defs) {
4059
- var _a, _b, _c, _d, _e;
4060
- const keyframes = propAnim.keyframes || propAnim.kfs || [];
4061
- const normalized = [];
4062
- for (const kf of keyframes) {
4063
- const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
4064
- let value = (_c = kf.value) != null ? _c : kf.v;
4065
- const easing = (_d = kf.easing) != null ? _d : kf.e;
4066
- if (propName === "d") {
4067
- value = normalizePathValue(value);
5349
+ function applyPlayerEffects_retime(node, ctx) {
5350
+ applyAllRetimeEffects(node, ctx);
5351
+ return node;
5352
+ }
5353
+ function materialiseAnimatedUseInstances(root) {
5354
+ var _a;
5355
+ const idMap = buildIdMap(root);
5356
+ const animatedIds = computeAnimatedSubtreeIds(root, idMap);
5357
+ if (animatedIds.size === 0) return root;
5358
+ let idCounter = 0;
5359
+ const genId3 = () => "_lw_use_mat_" + ++idCounter;
5360
+ const defsCollector = [];
5361
+ const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector);
5362
+ if (defsCollector.length === 0) return walked;
5363
+ const defsNode = { type: "defs", children: defsCollector };
5364
+ const newChildren = [...(_a = walked.children) != null ? _a : [], defsNode];
5365
+ return __spreadProps(__spreadValues({}, walked), { children: newChildren });
5366
+ }
5367
+ function buildIdMap(root) {
5368
+ const map = /* @__PURE__ */ new Map();
5369
+ const visit = (n) => {
5370
+ var _a;
5371
+ if (typeof n.id === "string") map.set(n.id, n);
5372
+ (_a = n.children) == null ? void 0 : _a.forEach(visit);
5373
+ };
5374
+ visit(root);
5375
+ return map;
5376
+ }
5377
+ function computeAnimatedSubtreeIds(root, idMap) {
5378
+ const cache = /* @__PURE__ */ new WeakMap();
5379
+ const result = /* @__PURE__ */ new Set();
5380
+ const hasAnim = (n, visiting) => {
5381
+ const cached = cache.get(n);
5382
+ if (cached !== void 0) return cached;
5383
+ if (visiting.has(n)) return false;
5384
+ visiting.add(n);
5385
+ let r = false;
5386
+ if (n.animate && typeof n.animate === "object" && !Array.isArray(n.animate)) {
5387
+ for (const _ in n.animate) {
5388
+ r = true;
5389
+ break;
5390
+ }
4068
5391
  }
4069
- if (COLOUR_ATTR_NAMES.has(propName)) {
4070
- value = (_e = parseColor(value)) != null ? _e : value;
5392
+ if (!r && n.children) {
5393
+ for (const ch of n.children) {
5394
+ if (hasAnim(ch, visiting)) {
5395
+ r = true;
5396
+ break;
5397
+ }
5398
+ }
4071
5399
  }
4072
- normalized.push({
4073
- t: timePct,
4074
- v: value,
4075
- e: resolveEasing(easing, defs)
4076
- });
5400
+ if (!r && n.type === "use" && typeof n.href === "string") {
5401
+ const targetId = stripHash2(n.href);
5402
+ const target = targetId ? idMap.get(targetId) : void 0;
5403
+ if (target) r = hasAnim(target, visiting);
5404
+ }
5405
+ visiting.delete(n);
5406
+ cache.set(n, r);
5407
+ return r;
5408
+ };
5409
+ for (const [id, node] of idMap) {
5410
+ if (hasAnim(node, /* @__PURE__ */ new Set())) result.add(id);
4077
5411
  }
4078
- normalized.sort((a, b) => {
4079
- var _a2, _b2;
4080
- return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
5412
+ return result;
5413
+ }
5414
+ function stripHash2(href) {
5415
+ if (typeof href !== "string") return void 0;
5416
+ return href.startsWith("#") ? href.slice(1) : href;
5417
+ }
5418
+ function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector) {
5419
+ const clone2 = deepClonePxNode(target);
5420
+ regenerateIdsAndRewriteRefs(clone2, genId3);
5421
+ const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector) : clone2;
5422
+ const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector);
5423
+ const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materialisedClone] });
5424
+ delete newNode.href;
5425
+ return applyUseOffsetToG(newNode);
5426
+ }
5427
+ function rewriteSymbolRootToGroup(symbolNode, genId3, defsCollector) {
5428
+ const viewBox = parseViewBox(symbolNode.viewBox);
5429
+ const g = __spreadProps(__spreadValues({}, symbolNode), { type: "g" });
5430
+ delete g.viewBox;
5431
+ delete g.preserveAspectRatio;
5432
+ delete g.width;
5433
+ delete g.height;
5434
+ if (!viewBox) return g;
5435
+ const [vbX, vbY, vbW, vbH] = viewBox;
5436
+ if (vbX !== 0 || vbY !== 0) {
5437
+ g.transform = "translate(" + -vbX + "," + -vbY + ")";
5438
+ }
5439
+ const clipId = genId3();
5440
+ defsCollector.push({
5441
+ type: "clipPath",
5442
+ id: clipId,
5443
+ children: [{ type: "rect", x: vbX, y: vbY, width: vbW, height: vbH }]
4081
5444
  });
4082
- const loopRaw = propAnim.loop;
4083
- const loop = loopRaw === true ? {} : loopRaw || void 0;
4084
- if (loop && normalized.length >= 2) {
4085
- return expandLoopKeyframes(propName, normalized, loop, duration);
4086
- }
4087
- return normalized;
5445
+ g.clipPath = "url(#" + clipId + ")";
5446
+ return g;
4088
5447
  }
4089
- function mergeAnimationDefinitions(animations) {
4090
- const merged = {};
4091
- for (const anim of animations) {
4092
- for (const [prop, propAnim] of Object.entries(anim)) {
4093
- merged[prop] = propAnim;
4094
- }
4095
- }
4096
- return merged;
5448
+ function parseViewBox(v) {
5449
+ if (typeof v !== "string") return void 0;
5450
+ const parts = v.trim().split(/[\s,]+/).map(Number);
5451
+ if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
5452
+ return [parts[0], parts[1], parts[2], parts[3]];
4097
5453
  }
4098
- var _elementIdCounter = 0;
4099
- function generateElementId() {
4100
- return "_px_el_" + ++_elementIdCounter;
5454
+ function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector) {
5455
+ if (node.type === "use" && typeof node.href === "string") {
5456
+ const targetId = stripHash2(node.href);
5457
+ if (targetId && animatedIds.has(targetId)) {
5458
+ const target = idMap.get(targetId);
5459
+ if (target) return materialiseOneUse(node, target, idMap, animatedIds, genId3, defsCollector);
5460
+ }
5461
+ }
5462
+ if (!node.children) return node;
5463
+ let changed = false;
5464
+ const newChildren = node.children.map((ch) => {
5465
+ const m = walkAndMaterialise2(ch, idMap, animatedIds, genId3, defsCollector);
5466
+ if (m !== ch) changed = true;
5467
+ return m;
5468
+ });
5469
+ return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
4101
5470
  }
4102
- function normalizeAnimationDefinition(animDef, duration, defs) {
4103
- const normalized = {};
4104
- for (const [propName, propAnim] of Object.entries(animDef)) {
4105
- const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
4106
- if (normalizedKfs.length > 0) {
4107
- normalized[propName] = { kfs: normalizedKfs };
4108
- }
5471
+ function materialiseAllInTree(doc, engine, opts) {
5472
+ var _a, _b;
5473
+ let root = applyPlayerEffects(doc).root;
5474
+ const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5475
+ root = materialiseInternalLoopsInTree(root, duration);
5476
+ if (engine === PxAnimatorEngine.webapi) {
5477
+ root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5478
+ root = materialiseAnimatedUseInstances(root);
4109
5479
  }
4110
- return normalized;
5480
+ return root;
4111
5481
  }
4112
- function getNormalisedBindings(doc) {
4113
- const animatorConfig = getAnimatorConfig(doc) || {};
4114
- const defs = getDefs(doc);
4115
- const duration = animatorConfig.duration || 1e3;
4116
- const bindings = [];
4117
- const processAnimation = (id, animate) => {
4118
- if (!animate) return null;
4119
- const animDefs = resolveElementAnimation(animate, defs);
4120
- if (animDefs.length === 0) return null;
4121
- const merged = mergeAnimationDefinitions(animDefs);
4122
- const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs);
4123
- if (Object.keys(normalizedAnim).length === 0) return null;
4124
- return {
4125
- id,
4126
- animate: normalizedAnim
4127
- };
4128
- };
4129
- const docBindings = getBindings(doc);
4130
- if (docBindings) {
4131
- for (const binding of docBindings) {
4132
- const normalized = processAnimation(binding.id, binding.animate);
4133
- if (normalized) bindings.push(normalized);
4134
- }
5482
+ var SVG_NS = "http://www.w3.org/2000/svg";
5483
+ var DISALLOWED_SVG_TAGS_LOWER = /* @__PURE__ */ new Set([
5484
+ "script",
5485
+ "foreignobject"
5486
+ ]);
5487
+ var URL_VALUE_ATTRS_LOWER = /* @__PURE__ */ new Set([
5488
+ "href",
5489
+ // <use>, <image>
5490
+ "xlink:href",
5491
+ // legacy <use>
5492
+ "src",
5493
+ // <image>
5494
+ "filter",
5495
+ // url(#filterId)
5496
+ "clippath",
5497
+ // clip-path="url(#…)"
5498
+ "mask",
5499
+ // url(#maskId)
5500
+ "markerstart",
5501
+ // marker-start="url(#…)"
5502
+ "markermid",
5503
+ // marker-mid="url(#…)"
5504
+ "markerend"
5505
+ // marker-end="url(#…)"
5506
+ ]);
5507
+ var IMAGE_REF_ATTRS_LOWER = /* @__PURE__ */ new Set(["href", "xlink:href", "src"]);
5508
+ var DATA_RASTER_IMAGE_RE = /^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/i;
5509
+ function isDangerousAttrName(nameLower) {
5510
+ if (nameLower.startsWith("on")) return true;
5511
+ return false;
5512
+ }
5513
+ function sanitiseAttributeValue(name, value) {
5514
+ const nameLower = name.toLowerCase();
5515
+ if (isDangerousAttrName(nameLower)) {
5516
+ console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
5517
+ return void 0;
4135
5518
  }
4136
- const processNode = (node) => {
4137
- const inlineAnim = node.animate;
4138
- if (inlineAnim && Object.keys(inlineAnim).length > 0) {
4139
- const nodeId = node.id || generateElementId();
4140
- node.id = nodeId;
4141
- const normalized = processAnimation(nodeId, inlineAnim);
4142
- if (normalized) bindings.push(normalized);
4143
- }
4144
- if (node.children) {
4145
- for (let i = 0; i < node.children.length; i++) {
4146
- processNode(node.children[i]);
4147
- }
5519
+ if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopcolor") {
5520
+ const str = String(value);
5521
+ if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
5522
+ console.warn('Attribute "' + nameLower + '" blocked: url() must be internal url(#id), got:', value);
5523
+ return void 0;
4148
5524
  }
4149
- };
4150
- if (doc.children) {
4151
- for (let i = 0; i < doc.children.length; i++) {
4152
- processNode(doc.children[i]);
5525
+ return value;
5526
+ }
5527
+ if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {
5528
+ const str = String(value);
5529
+ if (str.startsWith("#")) return value;
5530
+ if (/^url\(#[^)]+\)$/.test(str)) return value;
5531
+ if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && DATA_RASTER_IMAGE_RE.test(str)) return value;
5532
+ console.warn('Attribute "' + nameLower + '" blocked: must be #id, url(#id), or base64 raster data: URI, got:', value);
5533
+ return void 0;
5534
+ }
5535
+ return value;
5536
+ }
5537
+ function createElement(tagName, normalisedProps, style, children, textContent) {
5538
+ if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
5539
+ console.warn("SVG tag blocked (dangerous): ", tagName);
5540
+ return null;
5541
+ }
5542
+ const element = document.createElementNS(SVG_NS, tagName);
5543
+ for (const propName in normalisedProps) {
5544
+ const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
5545
+ if (sanitised === void 0) continue;
5546
+ element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
5547
+ }
5548
+ if (style) {
5549
+ for (const styleProp in style) {
5550
+ element.style[styleProp] = String(style[styleProp]);
4153
5551
  }
4154
5552
  }
4155
- return bindings;
4156
- }
4157
- function getKeyframesPair(keyframes, progress) {
4158
- var _a, _b;
4159
- let prevKf = keyframes[0];
4160
- let nextKf = keyframes[keyframes.length - 1];
4161
- for (let j = 0; j < keyframes.length - 1; j++) {
4162
- const aOff = (_a = keyframes[j].t) != null ? _a : 0;
4163
- const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
4164
- if (aOff <= progress && progress <= bOff) {
4165
- prevKf = keyframes[j];
4166
- nextKf = keyframes[j + 1];
4167
- break;
5553
+ if (children) {
5554
+ for (const child of children) {
5555
+ element.appendChild(child);
4168
5556
  }
4169
5557
  }
4170
- return { prevKf, nextKf };
5558
+ if (textContent) element.textContent = textContent;
5559
+ return element;
4171
5560
  }
4172
- function calcPropertyValue(propName, propAnim, progress) {
4173
- var _a, _b, _c, _d, _e, _f, _g;
4174
- const keyframes = propAnim.kfs || propAnim.keyframes || [];
4175
- if (keyframes.length === 0) return null;
4176
- const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
4177
- let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
4178
- localProgress = clamp(localProgress, 0, 1);
4179
- const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
4180
- if (easing && Array.isArray(easing)) {
4181
- try {
4182
- localProgress = cubicBezier(easing)(localProgress);
4183
- } catch (e) {
4184
- }
5561
+ function resolveStyle(style, defs) {
5562
+ var _a;
5563
+ if (!style) return void 0;
5564
+ if (typeof style === "string") {
5565
+ return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
4185
5566
  }
4186
- let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
4187
- let cssValue = null;
4188
- const prevV = (_d = prevKf == null ? void 0 : prevKf.v) != null ? _d : prevKf == null ? void 0 : prevKf.value;
4189
- const nextV = (_e = nextKf == null ? void 0 : nextKf.v) != null ? _e : nextKf == null ? void 0 : nextKf.value;
4190
- if (cssAttrName === "d") {
4191
- const prevPaths = (_f = prevV == null ? void 0 : prevV.paths) != null ? _f : Array.isArray(prevV) ? prevV : [];
4192
- const nextPaths = (_g = nextV == null ? void 0 : nextV.paths) != null ? _g : Array.isArray(nextV) ? nextV : [];
4193
- cssValue = interpolateBeziers(
4194
- prevPaths,
4195
- nextPaths,
4196
- localProgress
4197
- ).map((bz) => bezierToSvgPath(bz)).join("");
4198
- } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
4199
- cssValue = toRGBA(interpolateColor(
4200
- prevV || [0, 0, 0, 1],
4201
- nextV || [0, 0, 0, 1],
4202
- localProgress
4203
- ));
4204
- cssAttrName = propName;
4205
- } else if (cssAttrName === "stroke-dasharray") {
4206
- cssValue = interpolateVec(
4207
- prevV || [],
4208
- nextV || [],
4209
- localProgress
4210
- ).join(" ");
4211
- cssAttrName = propName;
4212
- } else if (cssAttrName === "transform" && prevV !== null && typeof prevV === "object" && !Array.isArray(prevV)) {
4213
- const partKeys = /* @__PURE__ */ new Set([
4214
- ...prevV ? Object.keys(prevV) : [],
4215
- ...nextV ? Object.keys(nextV) : []
4216
- ]);
4217
- const partsResult = {};
4218
- for (const partKey of partKeys) {
4219
- const prevPart = prevV == null ? void 0 : prevV[partKey];
4220
- const nextPart = nextV == null ? void 0 : nextV[partKey];
4221
- if (partKey === "rotate") {
4222
- partsResult.rotate = interpolateNum(+(prevPart != null ? prevPart : 0), +(nextPart != null ? nextPart : 0), localProgress);
4223
- } else if (partKey === "translate" || partKey === "scale" || partKey === "origin") {
4224
- const fallback = partKey === "scale" ? [1, 1] : [0, 0];
4225
- const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);
4226
- partsResult[partKey] = interp;
5567
+ return style;
5568
+ }
5569
+ function getNormalizedProps(props) {
5570
+ const propsCopy = {};
5571
+ for (const rawKey of Object.keys(props)) {
5572
+ const key = kebabToCamelCaseWord(rawKey);
5573
+ if (INTERNAL_ATTRS.has(key)) continue;
5574
+ if (key === "style") continue;
5575
+ let value = props[rawKey];
5576
+ if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
5577
+ propsCopy[key] = toRGBA(value);
5578
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
5579
+ propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
5580
+ } else if (TRANSFORM_FN_NAMES.has(key)) {
5581
+ if (Array.isArray(value)) {
5582
+ if (key === "translate") value = value.map((v) => v + "px");
5583
+ value = value.join(",");
4227
5584
  }
5585
+ if (key === "rotate") value = value + "deg";
5586
+ propsCopy["transform"] = key + "(" + value + ")";
5587
+ } else if (value !== void 0 && value !== null) {
5588
+ propsCopy[key] = String(value);
4228
5589
  }
4229
- if (propAnimIsMotionPath(propAnim)) {
4230
- const prevTr = prevV.translate;
4231
- const nextTr = nextV.translate;
4232
- if (Array.isArray(prevTr) && Array.isArray(nextTr)) {
4233
- const sample = evaluateMotionPathSegment(
4234
- prevKf,
4235
- nextKf,
4236
- [+prevTr[0], +prevTr[1]],
4237
- [+nextTr[0], +nextTr[1]],
4238
- localProgress,
4239
- !!propAnim.autoOrient
4240
- );
4241
- partsResult.translate = [sample.translate[0], sample.translate[1]];
4242
- if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
5590
+ }
5591
+ return propsCopy;
5592
+ }
5593
+ function renderNode(node, defs) {
5594
+ if (!node) return null;
5595
+ const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
5596
+ const nodeDefs = getDefs(node) || defs;
5597
+ const resolvedStyle = resolveStyle(style, nodeDefs);
5598
+ let childElements;
5599
+ if (children) {
5600
+ for (const ch of children) {
5601
+ const child = renderNode(ch, nodeDefs);
5602
+ if (child) {
5603
+ if (!childElements) childElements = [];
5604
+ childElements.push(child);
4243
5605
  }
4244
5606
  }
4245
- cssValue = composeTransformParts(partsResult, { withUnits: false });
4246
- cssAttrName = "transform";
4247
- } else if (cssAttrName === "translate") {
4248
- const v = interpolateVec(
4249
- prevV || [0, 0],
4250
- nextV || [0, 0],
4251
- localProgress
4252
- );
4253
- cssValue = "translate(" + v.join(",") + ")";
4254
- cssAttrName = "transform";
4255
- } else if (cssAttrName === "rotate") {
4256
- const v = interpolateNum(
4257
- +(prevV || 0),
4258
- +(nextV || 0),
4259
- localProgress
4260
- );
4261
- cssValue = "rotate(" + v + ")";
4262
- cssAttrName = "transform";
4263
- } else if (cssAttrName === "scale") {
4264
- const v = interpolateVec(
4265
- prevV || [1, 1],
4266
- nextV || [1, 1],
4267
- localProgress
4268
- );
4269
- cssValue = "scale(" + v.join(",") + ")";
4270
- cssAttrName = "transform";
4271
- } else {
4272
- const num2 = interpolateNum(
4273
- +(prevV || 0),
4274
- +(nextV || 0),
4275
- localProgress
4276
- );
4277
- cssValue = num2;
4278
- }
4279
- if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
4280
- cssValue = cssValue * 100 + "%";
4281
5607
  }
4282
- return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
5608
+ return createElement(
5609
+ type || "g",
5610
+ getNormalizedProps(props),
5611
+ resolvedStyle,
5612
+ childElements,
5613
+ props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
5614
+ );
4283
5615
  }
4284
- function calcAnimationValues(animDef, progress) {
4285
- const result = {};
4286
- for (const [propName, propAnim] of Object.entries(animDef)) {
4287
- const computed = calcPropertyValue(propName, propAnim, progress);
4288
- if (computed) {
4289
- result[computed.k] = computed.v;
5616
+ function setupAnimationTriggers(api, config) {
5617
+ const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
5618
+ const root = api.getRootElement();
5619
+ if (!root) {
5620
+ console.warn("setupAnimationTriggers: No root element found for animation.");
5621
+ return api;
5622
+ }
5623
+ const start = () => {
5624
+ api.play();
5625
+ };
5626
+ const handleEndAction = () => {
5627
+ switch (outAction) {
5628
+ case "pause":
5629
+ api.pause();
5630
+ break;
5631
+ case "reset":
5632
+ api.cancel();
5633
+ break;
5634
+ case "reverse":
5635
+ api.play();
5636
+ break;
5637
+ case "continue":
5638
+ default:
5639
+ break;
5640
+ }
5641
+ };
5642
+ switch (startOn) {
5643
+ case "load": {
5644
+ const startHandler = () => start();
5645
+ if (document.readyState === "complete") {
5646
+ startHandler();
5647
+ } else {
5648
+ window.addEventListener("load", startHandler, { once: true });
5649
+ }
5650
+ break;
5651
+ }
5652
+ case "mouseOver": {
5653
+ const mouseOverHandler = () => start();
5654
+ const mouseOutHandler = () => handleEndAction();
5655
+ root.addEventListener("mouseenter", mouseOverHandler);
5656
+ root.addEventListener("mouseleave", mouseOutHandler);
5657
+ break;
4290
5658
  }
5659
+ case "click": {
5660
+ const clickHandler = () => {
5661
+ if (api.isPlaying()) {
5662
+ handleEndAction();
5663
+ } else {
5664
+ start();
5665
+ }
5666
+ };
5667
+ root.addEventListener("click", clickHandler);
5668
+ break;
5669
+ }
5670
+ case "scrollIntoView": {
5671
+ const observer = new IntersectionObserver(
5672
+ (entries) => {
5673
+ entries.forEach((entry) => {
5674
+ if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
5675
+ start();
5676
+ } else {
5677
+ handleEndAction();
5678
+ }
5679
+ });
5680
+ },
5681
+ { threshold: scrollIntoViewThreshold }
5682
+ );
5683
+ observer.observe(root);
5684
+ break;
5685
+ }
5686
+ case "programmatic":
5687
+ break;
4291
5688
  }
4292
- return result;
5689
+ return api;
4293
5690
  }
4294
5691
  function getSelector(id) {
4295
5692
  return "#" + id;
4296
5693
  }
4297
5694
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4298
5695
  const config = getAnimatorConfig(doc) || {};
4299
- const bindings = getNormalisedBindings(doc);
5696
+ const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
4300
5697
  const _iterations = config.iterations;
4301
5698
  let iterations = 1;
4302
5699
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -4414,6 +5811,10 @@ var PixodeskAnimatorReact = (() => {
4414
5811
  };
4415
5812
  const startAnim = () => {
4416
5813
  if (playing) return;
5814
+ if (Number.isFinite(totalDuration) && timeBeforeLastStartMs >= totalDuration) {
5815
+ timeBeforeLastStartMs = 0;
5816
+ finishCalled = false;
5817
+ }
4417
5818
  playing = true;
4418
5819
  lastStartedTs = Date.now();
4419
5820
  loopAnim(true);
@@ -4644,7 +6045,6 @@ var PixodeskAnimatorReact = (() => {
4644
6045
  function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs) {
4645
6046
  var _a;
4646
6047
  const config = getAnimatorConfig(doc) || {};
4647
- const bindings = getNormalisedBindings(doc);
4648
6048
  if (!rootElement) {
4649
6049
  if (doc.id) {
4650
6050
  const rootSelector = getSelector(doc.id);
@@ -4654,6 +6054,7 @@ var PixodeskAnimatorReact = (() => {
4654
6054
  console.warn("createFrameLoopAnimator: No root element provided");
4655
6055
  }
4656
6056
  }
6057
+ const bindings = getNormalisedBindings(doc, PxAnimatorEngine.webapi);
4657
6058
  const animations = [];
4658
6059
  const _iterations = config.iterations;
4659
6060
  let iterations;
@@ -4783,15 +6184,15 @@ var PixodeskAnimatorReact = (() => {
4783
6184
  function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
4784
6185
  const animatorConfig = getAnimatorConfig(doc) || {};
4785
6186
  let res;
4786
- if (animatorConfig.mode === "frames") {
6187
+ if (animatorConfig.mode === PxAnimatorMode.frames) {
4787
6188
  res = createFrameLoopAnimator(doc, adapter, callbacks, rootElement);
4788
6189
  } else {
4789
6190
  res = createWebApiAnimator(
4790
6191
  doc,
4791
6192
  callbacks,
4792
6193
  rootElement,
4793
- animatorConfig.mode === "webapi"
4794
- // Forcing "webapi"
6194
+ animatorConfig.mode === PxAnimatorMode.webapi
6195
+ // forcing webapi
4795
6196
  ) || createFrameLoopAnimator(doc, adapter, callbacks, rootElement);
4796
6197
  }
4797
6198
  if (animatorConfig.debugInstName) {
@@ -4913,9 +6314,10 @@ var PixodeskAnimatorReact = (() => {
4913
6314
  function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
4914
6315
  const effectsWarnings = validateNodeEffects(doc);
4915
6316
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
4916
- doc = applyPlayerEffects(doc).root;
4917
6317
  const animatorConfig = getAnimatorConfig(doc) || {};
4918
6318
  animatorConfig.debug = true;
6319
+ const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
6320
+ doc = materialiseAllInTree(doc, engine);
4919
6321
  let rootElement = null;
4920
6322
  if (containerElement && doc.children) {
4921
6323
  doc = generateNewIds(doc);