@pixodesk/svg-animator-react 1.0.15 → 1.0.17

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