@pixodesk/svg-animator-web 1.0.15 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -7,7 +7,6 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
9
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
- var __pow = Math.pow;
11
10
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
11
  var __spreadValues = (a, b) => {
13
12
  for (var prop in b || (b = {}))
@@ -58,6 +57,8 @@ __export(index_exports, {
58
57
  PxAnimatedSvgDocumentSchema: () => PxAnimatedSvgDocumentSchema,
59
58
  PxAnimationDefinitionSchema: () => PxAnimationDefinitionSchema,
60
59
  PxAnimatorConfigSchema: () => PxAnimatorConfigSchema,
60
+ PxAnimatorEngine: () => PxAnimatorEngine,
61
+ PxAnimatorMode: () => PxAnimatorMode,
61
62
  PxAttrValueSchema: () => PxAttrValueSchema,
62
63
  PxBezierPathSchema: () => PxBezierPathSchema,
63
64
  PxBindingSchema: () => PxBindingSchema,
@@ -65,6 +66,11 @@ __export(index_exports, {
65
66
  PxEasingOrRefSchema: () => PxEasingOrRefSchema,
66
67
  PxEffectsSchema: () => PxEffectsSchema,
67
68
  PxElementAnimationSchema: () => PxElementAnimationSchema,
69
+ PxFillGradientEffectSchema: () => PxFillGradientEffectSchema,
70
+ PxGradientSpreadMethod: () => PxGradientSpreadMethod,
71
+ PxGradientStopSchema: () => PxGradientStopSchema,
72
+ PxGradientType: () => PxGradientType,
73
+ PxGradientUnits: () => PxGradientUnits,
68
74
  PxKeyframeSchema: () => PxKeyframeSchema,
69
75
  PxLoopSchema: () => PxLoopSchema,
70
76
  PxMaskedByEffectSchema: () => PxMaskedByEffectSchema,
@@ -74,7 +80,9 @@ __export(index_exports, {
74
80
  PxRefEffectSchema: () => PxRefEffectSchema,
75
81
  PxRepeaterEffectSchema: () => PxRepeaterEffectSchema,
76
82
  PxRetimeEffectSchema: () => PxRetimeEffectSchema,
83
+ PxStrokeGradientEffectSchema: () => PxStrokeGradientEffectSchema,
77
84
  PxSvgNodeExtra: () => PxSvgNodeExtra,
85
+ PxTextAlongPathEffectSchema: () => PxTextAlongPathEffectSchema,
78
86
  PxTransformPartsSchema: () => PxTransformPartsSchema,
79
87
  PxTransformValueSchema: () => PxTransformValueSchema,
80
88
  PxTransformationEffectSchema: () => PxTransformationEffectSchema,
@@ -93,6 +101,7 @@ __export(index_exports, {
93
101
  createWebApiAnimator: () => createWebApiAnimator,
94
102
  describeSchema: () => describeSchema,
95
103
  diffInEffect: () => diffInEffect,
104
+ evaluateMotionPathSegment: () => evaluateMotionPathSegment,
96
105
  generateNewIds: () => generateNewIds,
97
106
  getAnimatorConfig: () => getAnimatorConfig,
98
107
  getBindings: () => getBindings,
@@ -102,7 +111,14 @@ __export(index_exports, {
102
111
  isPxElementFileFormat: () => isPxElementFileFormat,
103
112
  isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
104
113
  loadTagAnimators: () => loadTagAnimators,
114
+ materialiseAllInTree: () => materialiseAllInTree,
115
+ materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
116
+ materialiseInternalLoopsInPropAnim: () => materialiseInternalLoopsInPropAnim,
117
+ materialiseInternalLoopsInTree: () => materialiseInternalLoopsInTree,
118
+ materialiseMotionPathInPropAnim: () => materialiseMotionPathInPropAnim,
119
+ materialiseMotionPathsInTree: () => materialiseMotionPathsInTree,
105
120
  normalizeDocument: () => getNormalisedBindings,
121
+ propAnimIsMotionPath: () => propAnimIsMotionPath,
106
122
  px: () => px,
107
123
  renderNode: () => renderNode,
108
124
  schemaKeys: () => schemaKeys,
@@ -116,29 +132,29 @@ module.exports = __toCommonJS(index_exports);
116
132
  // src/effects/transformParts.ts
117
133
  function partsRecord(part, value, origin) {
118
134
  const rec = {};
119
- if (part === "translate") rec.translate = value;
120
- else if (part === "rotate") rec.rotate = value;
135
+ if (part === "translate" /* Translate */) rec.translate = value;
136
+ else if (part === "rotate" /* Rotate */) rec.rotate = value;
121
137
  else rec.scale = value;
122
- if (origin && part !== "translate") rec.origin = origin;
138
+ if (origin && part !== "translate" /* Translate */) rec.origin = origin;
123
139
  return rec;
124
140
  }
125
141
  function readAnimatable(raw) {
126
- if (raw === void 0) return { kind: "absent" };
127
- if (Array.isArray(raw)) return { kind: "static", value: raw };
142
+ if (raw === void 0) return { kind: "absent" /* Absent */ };
143
+ if (Array.isArray(raw)) return { kind: "static" /* Static */, value: raw };
128
144
  if (typeof raw === "object") {
129
145
  const obj = raw;
130
146
  if (obj.keyframes) {
131
- return { kind: "animated", keyframes: obj.keyframes, autoOrient: obj.autoOrient };
147
+ return { kind: "animated" /* Animated */, keyframes: obj.keyframes, autoOrient: obj.autoOrient };
132
148
  }
133
- if (obj.value !== void 0) return { kind: "static", value: obj.value };
149
+ if (obj.value !== void 0) return { kind: "static" /* Static */, value: obj.value };
134
150
  }
135
- return { kind: "static", value: raw };
151
+ return { kind: "static" /* Static */, value: raw };
136
152
  }
137
153
  function readStaticOrigin(raw, ctx) {
138
154
  var _a;
139
155
  const o = readAnimatable(raw);
140
- if (o.kind === "absent") return void 0;
141
- if (o.kind === "static") return o.value;
156
+ if (o.kind === "absent" /* Absent */) return void 0;
157
+ if (o.kind === "static" /* Static */) return o.value;
142
158
  ctx.warnings.push("transformation.origin: animated origin approximated by its first keyframe");
143
159
  return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
144
160
  }
@@ -156,15 +172,15 @@ function applyTransformationEffect(node, fx, ctx) {
156
172
  if (!fx) return node;
157
173
  delete node.transform;
158
174
  let n = node;
159
- n = wrapTransformPart(n, "skew", fx.skew, ctx);
175
+ n = wrapTransformPart(n, "skew" /* Skew */, fx.skew, ctx);
160
176
  n = wrapOrigin(
161
177
  n,
162
178
  fx.origin,
163
179
  /*invert=*/
164
180
  true
165
181
  );
166
- n = wrapTransformPart(n, "scale", normalizeScale(fx.scale), ctx);
167
- n = wrapTransformPart(n, "rotate", fx.rotate, ctx);
182
+ n = wrapTransformPart(n, "scale" /* Scale */, normalizeScale(fx.scale), ctx);
183
+ n = wrapTransformPart(n, "rotate" /* Rotate */, fx.rotate, ctx);
168
184
  n = wrapOrigin(
169
185
  n,
170
186
  fx.origin,
@@ -178,7 +194,7 @@ function applyTransformationEffect(node, fx, ctx) {
178
194
  /*invert=*/
179
195
  true
180
196
  );
181
- n = wrapTransformPart(n, "translate", fx.translate, ctx);
197
+ n = wrapTransformPart(n, "translate" /* Translate */, fx.translate, ctx);
182
198
  n = wrapOrigin(
183
199
  n,
184
200
  fx.origin,
@@ -186,7 +202,7 @@ function applyTransformationEffect(node, fx, ctx) {
186
202
  false
187
203
  );
188
204
  } else {
189
- n = wrapTransformPart(n, "translate", fx.translate, ctx);
205
+ n = wrapTransformPart(n, "translate" /* Translate */, fx.translate, ctx);
190
206
  }
191
207
  return n;
192
208
  }
@@ -203,19 +219,19 @@ function normalizeScale(raw) {
203
219
  }
204
220
  function wrapTransformPart(inner, part, raw, ctx) {
205
221
  if (raw === void 0) return inner;
206
- if (part === "skew") {
222
+ if (part === "skew" /* Skew */) {
207
223
  const skew = readAnimatable(raw);
208
- if (skew.kind !== "static") {
224
+ if (skew.kind !== "static" /* Static */) {
209
225
  ctx.warnings.push("transformation.skew: only static skew is supported");
210
226
  return inner;
211
227
  }
212
228
  return { type: "g", transform: "skewX(" + skew.value[0] + ")skewY(" + skew.value[1] + ")", children: [inner] };
213
229
  }
214
230
  const v = readAnimatable(raw);
215
- if (v.kind === "static") {
231
+ if (v.kind === "static" /* Static */) {
216
232
  return { type: "g", transform: { value: partsRecord(part, v.value, void 0) }, children: [inner] };
217
233
  }
218
- if (v.kind === "animated") {
234
+ if (v.kind === "animated" /* Animated */) {
219
235
  const animTr = { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, kf.value, void 0))) };
220
236
  if (v.autoOrient) animTr.autoOrient = true;
221
237
  return {
@@ -230,12 +246,12 @@ function wrapOrigin(inner, raw, invert) {
230
246
  if (raw === void 0) return inner;
231
247
  const v = readAnimatable(raw);
232
248
  const sign = (value) => invert ? [-value[0], -value[1]] : value;
233
- if (v.kind === "absent") return inner;
234
- if (v.kind === "static") {
249
+ if (v.kind === "absent" /* Absent */) return inner;
250
+ if (v.kind === "static" /* Static */) {
235
251
  if (v.value[0] === 0 && v.value[1] === 0) return inner;
236
252
  return { type: "g", transform: { value: { translate: sign(v.value) } }, children: [inner] };
237
253
  }
238
- if (v.kind === "animated") {
254
+ if (v.kind === "animated" /* Animated */) {
239
255
  return {
240
256
  type: "g",
241
257
  animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, { translate: sign(kf.value) })) } },
@@ -274,7 +290,7 @@ function splitForContentRef(node, transformation, originalId, innerId, ctx) {
274
290
  return outerWrapper;
275
291
  }
276
292
  function liftBodyTranslate(node, transformation) {
277
- var _a;
293
+ var _a, _b, _c;
278
294
  const out = {};
279
295
  let didLiftAnimate = false;
280
296
  const animTr = (_a = node.animate) == null ? void 0 : _a.transform;
@@ -325,6 +341,7 @@ function liftBodyTranslate(node, transformation) {
325
341
  }
326
342
  const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
327
343
  const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
344
+ 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);
328
345
  if (typeof node.transform === "string") {
329
346
  const split = splitTransformString(node.transform);
330
347
  if (stripBodyTranslateOnly) {
@@ -333,6 +350,8 @@ function liftBodyTranslate(node, transformation) {
333
350
  else delete node.transform;
334
351
  } else if (isPureTranslateBody(node.transform)) {
335
352
  delete node.transform;
353
+ } else if (liftedAnimateIsAutoOriented && isSingleMatrixBody(node.transform)) {
354
+ delete node.transform;
336
355
  }
337
356
  } else if (split.translate) {
338
357
  out.transform = split.translate;
@@ -342,6 +361,17 @@ function liftBodyTranslate(node, transformation) {
342
361
  }
343
362
  return out;
344
363
  }
364
+ function isSingleMatrixBody(s) {
365
+ const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
366
+ let count = 0;
367
+ let isMatrix = false;
368
+ let m;
369
+ while (m = re.exec(s)) {
370
+ count++;
371
+ if (m[1] === "matrix") isMatrix = true;
372
+ }
373
+ return count === 1 && isMatrix;
374
+ }
345
375
  function isPureTranslateBody(s) {
346
376
  const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
347
377
  const ops = [];
@@ -424,294 +454,6 @@ function needsOriginOnOuter(translateAnim) {
424
454
  return false;
425
455
  }
426
456
 
427
- // src/effects/util.ts
428
- function genId(ctx, prefix) {
429
- return "_lw_" + prefix + "_" + ctx.nextId++;
430
- }
431
- function indexById(node, map) {
432
- var _a;
433
- if (typeof node.id === "string") map.set(node.id, node);
434
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
435
- }
436
- function spliceDefs(root, defs) {
437
- if (!defs.length) return;
438
- const existing = root.children || (root.children = []);
439
- existing.unshift({ type: "defs", children: defs });
440
- }
441
- function clone(value) {
442
- if (value === null || typeof value !== "object") return value;
443
- if (Array.isArray(value)) return value.map(clone);
444
- const out = {};
445
- for (const k of Object.keys(value)) out[k] = clone(value[k]);
446
- return out;
447
- }
448
- function regenerateIdsInClone(root, ctx) {
449
- const oldToNew = /* @__PURE__ */ new Map();
450
- const walkAssign = (n) => {
451
- var _a;
452
- if (typeof n.id === "string") {
453
- const newId = genId(ctx, "retimed");
454
- oldToNew.set(n.id, newId);
455
- n.id = newId;
456
- }
457
- (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
458
- };
459
- walkAssign(root);
460
- const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
461
- const newId = oldToNew.get(oldId);
462
- return newId ? "url(#" + newId + ")" : m;
463
- });
464
- const walkRewrite = (n) => {
465
- var _a;
466
- if (typeof n.href === "string" && n.href.startsWith("#")) {
467
- const newId = oldToNew.get(n.href.slice(1));
468
- if (newId) n.href = "#" + newId;
469
- }
470
- for (const k of Object.keys(n)) {
471
- if (k === "children" || k === "effects" || k === "meta" || k === "href" || k === "id") continue;
472
- const v = n[k];
473
- if (typeof v === "string" && v.indexOf("url(#") !== -1) n[k] = rewriteUrl(v);
474
- }
475
- (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
476
- };
477
- walkRewrite(root);
478
- return oldToNew;
479
- }
480
-
481
- // src/effects/maskedByEffect.ts
482
- function applyMaskedByEffect(node, fx, transformation, ctx) {
483
- if (!fx) return node;
484
- if (!fx.href) {
485
- ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
486
- return node;
487
- }
488
- const maskId = genId(ctx, "mask");
489
- let content = { type: "use", href: "#" + fx.href };
490
- content = wrapInverseTransform(content, transformation, ctx);
491
- const mask = { type: "mask", id: maskId, children: [content] };
492
- if (fx.maskType) mask.maskType = fx.maskType;
493
- if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
494
- if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
495
- ctx.defs.push(mask);
496
- node.mask = "url(#" + maskId + ")";
497
- return node;
498
- }
499
- function wrapInverseTransform(inner, fx, ctx) {
500
- if (!fx) return inner;
501
- const origin = readStaticOrigin(fx.origin, ctx);
502
- let n = inner;
503
- n = wrapInversePart(n, "translate", fx.translate, void 0, ctx);
504
- n = wrapInversePart(n, "rotate", fx.rotate, origin, ctx);
505
- n = wrapInversePart(n, "scale", fx.scale, origin, ctx);
506
- return n;
507
- }
508
- function wrapInversePart(inner, part, raw, origin, ctx) {
509
- if (raw === void 0) return inner;
510
- const v = readAnimatable(raw);
511
- if (v.kind === "static") {
512
- return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
513
- }
514
- if (v.kind === "animated") {
515
- return {
516
- type: "g",
517
- animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, invertPartValue(part, kf.value), origin))) } },
518
- children: [inner]
519
- };
520
- }
521
- return inner;
522
- }
523
- function invertPartValue(part, value) {
524
- if (part === "translate") return [-value[0], -value[1]];
525
- if (part === "rotate") return -value;
526
- return [1 / value[0], 1 / value[1]];
527
- }
528
-
529
- // src/effects/refEffect.ts
530
- var CONTENT_SUBREF = "content";
531
- function applyRefAndTransformationEffect(node, ref, transformation, ctx) {
532
- if (ref) {
533
- const baseId = ref.baseId;
534
- if (!baseId) {
535
- ctx.errors.push("ref: missing baseId");
536
- } else {
537
- const targetId = ref.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
538
- node.href = "#" + targetId;
539
- }
540
- }
541
- return applyTransformationEffect(node, transformation, ctx);
542
- }
543
-
544
- // src/effects/repeaterEffect.ts
545
- function applyRepeaterEffect(node, fx, ctx) {
546
- var _a, _b;
547
- if (!fx) return node;
548
- const copies = (_a = fx.copies) != null ? _a : 1;
549
- if (copies < 1) {
550
- ctx.errors.push("repeater.copies invalid: " + fx.copies);
551
- return node;
552
- }
553
- const sharedTransform = node.transform;
554
- const sharedAnimTransform = (_b = node.animate) == null ? void 0 : _b.transform;
555
- const base = clone(node);
556
- delete base.transform;
557
- if (base.animate) {
558
- delete base.animate.transform;
559
- if (Object.keys(base.animate).length === 0) delete base.animate;
560
- }
561
- const children = [base];
562
- for (let i = 1; i < copies; i++) {
563
- const copy = clone(base);
564
- copy.transform = { value: perCopyParts(fx, i) };
565
- children.push(copy);
566
- }
567
- const wrapper = { type: "g", children };
568
- if (sharedTransform !== void 0) wrapper.transform = sharedTransform;
569
- if (sharedAnimTransform !== void 0) wrapper.animate = { transform: sharedAnimTransform };
570
- return wrapper;
571
- }
572
- function perCopyParts(fx, i) {
573
- const parts = {};
574
- if (fx.translate) parts.translate = [fx.translate[0] * i, fx.translate[1] * i];
575
- if (fx.rotate !== void 0) parts.rotate = fx.rotate * i;
576
- if (fx.scale) parts.scale = [__pow(fx.scale[0] / 100, i), __pow(fx.scale[1] / 100, i)];
577
- if (fx.origin) parts.origin = [fx.origin[0] * i, fx.origin[1] * i];
578
- return parts;
579
- }
580
-
581
- // src/effects/retimeEffect.ts
582
- var RETIME_AS_SYMBOL = true;
583
- function applyRetimeEffect(node, retime, ctx) {
584
- var _a, _b, _c, _d;
585
- if (!retime) return node;
586
- const baseId = retime.baseId;
587
- if (!baseId) {
588
- ctx.errors.push("retime: missing baseId");
589
- return node;
590
- }
591
- const target = ctx.idMap.get(baseId);
592
- if (!target) {
593
- ctx.warnings.push('retime: target "' + baseId + '" not found');
594
- return node;
595
- }
596
- const start = (_a = retime.start) != null ? _a : 0;
597
- const stretch = (_b = retime.stretch) != null ? _b : 1;
598
- if (RETIME_AS_SYMBOL) {
599
- const symbolClone = clone(target);
600
- regenerateIdsInClone(symbolClone, ctx);
601
- const cloneId = genId(ctx, "retime");
602
- symbolClone.id = cloneId;
603
- remapKeyframeTimes(symbolClone, start, stretch);
604
- ctx.defs.push(symbolClone);
605
- node.href = "#" + cloneId;
606
- return node;
607
- }
608
- const sourceNodes = target.type === "symbol" ? target.children || [] : [target];
609
- const content = sourceNodes.map((child) => {
610
- const c = clone(child);
611
- regenerateIdsInClone(c, ctx);
612
- remapKeyframeTimes(c, start, stretch);
613
- return c;
614
- });
615
- const g = __spreadProps(__spreadValues({}, node), { type: "g", children: content });
616
- delete g.href;
617
- const x = Number((_c = node.x) != null ? _c : 0), y = Number((_d = node.y) != null ? _d : 0);
618
- if (x || y) {
619
- const offset = "translate(" + x + "," + y + ")";
620
- g.transform = typeof g.transform === "string" ? offset + g.transform : offset;
621
- delete g.x;
622
- delete g.y;
623
- }
624
- return g;
625
- }
626
- function remapKeyframeTimes(node, start, stretch) {
627
- var _a;
628
- const remap2 = (kfs) => {
629
- for (const kf of kfs) if (typeof kf.time === "number") kf.time = start + kf.time * stretch;
630
- };
631
- if (node.transform && typeof node.transform === "object" && Array.isArray(node.transform.keyframes)) {
632
- remap2(node.transform.keyframes);
633
- }
634
- if (node.animate && typeof node.animate === "object") {
635
- for (const prop of Object.keys(node.animate)) {
636
- const anim = node.animate[prop];
637
- if (anim && Array.isArray(anim.keyframes)) remap2(anim.keyframes);
638
- }
639
- }
640
- (_a = node.children) == null ? void 0 : _a.forEach((child) => remapKeyframeTimes(child, start, stretch));
641
- }
642
-
643
- // src/effects/trimPathEffect.ts
644
- function applyTrimPathEffect(node, trimPath, isCombinedShape) {
645
- var _a;
646
- if (!trimPath && !isCombinedShape) return node;
647
- const d = (_a = node.d) != null ? _a : rectToPathD(node);
648
- if (d === void 0) return node;
649
- const g = __spreadProps(__spreadValues({}, node), { type: "g" });
650
- delete g.d;
651
- const meta = g.meta = __spreadValues({}, g.meta || {});
652
- const effects = meta.effects = __spreadValues({}, meta.effects || {});
653
- if (trimPath) effects.trimPath = trimPath;
654
- effects.isCombinedShape = true;
655
- g.children = [{ type: "path", d }];
656
- return g;
657
- }
658
- function rectToPathD(node) {
659
- var _a, _b, _c, _d;
660
- if (node.type !== "rect") return void 0;
661
- const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
662
- const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
663
- return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
664
- }
665
-
666
- // src/effects/PlayerEffectsUtil.ts
667
- function applyPlayerEffects(root) {
668
- const ctx = {
669
- defs: [],
670
- warnings: [],
671
- errors: [],
672
- idMap: /* @__PURE__ */ new Map(),
673
- nextId: 0,
674
- contentRefInnerIds: /* @__PURE__ */ new Map()
675
- };
676
- const working = clone(root);
677
- indexById(working, ctx.idMap);
678
- identifyContentRefTargets(working, ctx, () => genId(ctx, "inner"));
679
- const afterPass1 = applyPlayerEffects_exceptRetime(working, ctx);
680
- const out = applyPlayerEffects_retime(afterPass1, ctx);
681
- spliceDefs(out, ctx.defs);
682
- return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
683
- }
684
- function applyPlayerEffects_exceptRetime(node, ctx) {
685
- if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
686
- const fx = node.effects;
687
- const originalId = typeof node.id === "string" ? node.id : void 0;
688
- const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
689
- if (!fx && !innerIdForContentRef) return node;
690
- const { transformation, repeater, maskedBy, trimPath, retime, ref } = fx != null ? fx : {};
691
- const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
692
- if (fx) delete node.effects;
693
- let n = node;
694
- n = applyTrimPathEffect(n, trimPath, isCombinedShape);
695
- n = applyRepeaterEffect(n, repeater, ctx);
696
- n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
697
- if (innerIdForContentRef) {
698
- n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
699
- } else {
700
- n = applyRefAndTransformationEffect(n, ref, transformation, ctx);
701
- }
702
- if (retime) node.effects = { retime };
703
- if (originalId) ctx.idMap.set(originalId, n);
704
- return n;
705
- }
706
- function applyPlayerEffects_retime(node, ctx) {
707
- var _a;
708
- if (node.children) node.children = node.children.map((child) => applyPlayerEffects_retime(child, ctx));
709
- const retime = (_a = node.effects) == null ? void 0 : _a.retime;
710
- if (!retime) return node;
711
- delete node.effects;
712
- return applyRetimeEffect(node, retime, ctx);
713
- }
714
-
715
457
  // src/PxSchema.ts
716
458
  function pathStr(path) {
717
459
  if (!path.length) return ".";
@@ -1171,6 +913,15 @@ var px = {
1171
913
  // src/PxAnimatorTypes.ts
1172
914
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1173
915
  var PX_ANIM_ATTR_NAME = "_px_animator";
916
+ var PxAnimatorMode = {
917
+ auto: "auto",
918
+ webapi: "webapi",
919
+ frames: "frames"
920
+ };
921
+ var PxAnimatorEngine = {
922
+ webapi: PxAnimatorMode.webapi,
923
+ frames: PxAnimatorMode.frames
924
+ };
1174
925
  var TEXT_ATTR = "text";
1175
926
  var TEXT_CONTENT_ATTR = "textContent";
1176
927
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
@@ -1253,7 +1004,7 @@ var PxDefsSchema = implementsInterface()(px.object({
1253
1004
  styles: px.record(px.any()).optional()
1254
1005
  }));
1255
1006
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
1256
- mode: px.enum(["auto", "webapi", "frames"]).optional(),
1007
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
1257
1008
  duration: px.number().optional(),
1258
1009
  delay: px.number().optional(),
1259
1010
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
@@ -1292,47 +1043,96 @@ var PxAnimatableVec2Schema = px.union([
1292
1043
  autoOrient: px.boolean().optional()
1293
1044
  })
1294
1045
  ]);
1295
- var PxTransformationEffectSchema = px.object({
1046
+ var PxTransformationEffectSchema = implementsInterface()(px.object({
1296
1047
  translate: PxAnimatableVec2Schema.optional(),
1297
1048
  rotate: PxAnimatableNumberSchema.optional(),
1298
1049
  scale: PxAnimatableVec2Schema.optional(),
1299
1050
  skew: PxAnimatableVec2Schema.optional(),
1300
1051
  origin: PxAnimatableVec2Schema.optional()
1301
- });
1302
- var PxRepeaterEffectSchema = px.object({
1052
+ }));
1053
+ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1303
1054
  copies: px.number().optional(),
1304
- translate: px.tuple([px.number(), px.number()]).optional(),
1305
- rotate: px.number().optional(),
1306
- scale: px.tuple([px.number(), px.number()]).optional(),
1307
- // per-copy scale, PERCENT (85 → 0.85)
1308
- origin: px.tuple([px.number(), px.number()]).optional()
1309
- });
1310
- var PxMaskedByEffectSchema = px.object({
1055
+ translate: PxAnimatableVec2Schema.optional(),
1056
+ rotate: PxAnimatableNumberSchema.optional(),
1057
+ scale: PxAnimatableVec2Schema.optional(),
1058
+ origin: PxAnimatableVec2Schema.optional()
1059
+ }));
1060
+ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1311
1061
  href: px.string().optional(),
1312
1062
  maskType: px.string().optional(),
1313
1063
  maskUnits: px.string().optional(),
1314
1064
  maskContentUnits: px.string().optional()
1315
- });
1316
- var PxTrimPathEffectSchema = px.any();
1317
- var PxRetimeEffectSchema = px.object({
1065
+ }));
1066
+ var PxTrimPathEffectSchema = implementsInterface()(px.object({
1067
+ offset: PxAnimatableNumberSchema.optional(),
1068
+ range: PxAnimatableVec2Schema.optional(),
1069
+ trimAllAsOne: px.boolean().optional()
1070
+ }));
1071
+ var PxRetimeEffectSchema = implementsInterface()(px.object({
1318
1072
  baseId: px.string().optional(),
1319
1073
  start: px.number().optional(),
1320
1074
  stretch: px.number().optional(),
1321
1075
  timeCrop: px.tuple([px.number(), px.number()]).optional()
1322
- });
1323
- var PxRefEffectSchema = px.object({
1076
+ }));
1077
+ var PxRefEffectSchema = implementsInterface()(px.object({
1324
1078
  baseId: px.string().optional(),
1325
1079
  type: px.string().optional()
1326
- });
1327
- var PxEffectsSchema = px.object({
1080
+ }));
1081
+ var PxGradientUnits = {
1082
+ userSpaceOnUse: "userSpaceOnUse",
1083
+ objectBoundingBox: "objectBoundingBox"
1084
+ };
1085
+ var PxGradientSpreadMethod = {
1086
+ pad: "pad",
1087
+ reflect: "reflect",
1088
+ repeat: "repeat"
1089
+ };
1090
+ var PxGradientType = {
1091
+ linear: "linear",
1092
+ radial: "radial"
1093
+ };
1094
+ var PxGradientStopSchema = implementsInterface()(px.object({
1095
+ offset: px.number(),
1096
+ color: px.string()
1097
+ }));
1098
+ var PxAnimatableGradientStopsSchema = px.union([
1099
+ px.array(PxGradientStopSchema),
1100
+ px.object({ value: px.array(PxGradientStopSchema) }),
1101
+ px.object({ keyframes: px.array(PxKeyframeSchema) })
1102
+ ]);
1103
+ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1104
+ type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1105
+ p1: px.tuple([px.number(), px.number()]).optional(),
1106
+ p2: px.tuple([px.number(), px.number()]).optional(),
1107
+ c: px.tuple([px.number(), px.number()]).optional(),
1108
+ r: px.number().optional(),
1109
+ fp: px.tuple([px.number(), px.number()]).optional(),
1110
+ stops: PxAnimatableGradientStopsSchema.optional(),
1111
+ gradientUnits: px.string().optional(),
1112
+ spreadMethod: px.string().optional(),
1113
+ gradientTransform: px.string().optional()
1114
+ }));
1115
+ var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1116
+ var PxTextAlongPathEffectSchema = implementsInterface()(px.object({
1117
+ href: px.string(),
1118
+ lengthAdjust: px.string().optional(),
1119
+ method: px.string().optional(),
1120
+ spacing: px.string().optional(),
1121
+ startOffset: PxAnimatableNumberSchema.optional(),
1122
+ textLength: PxAnimatableNumberSchema.optional()
1123
+ }));
1124
+ var PxEffectsSchema = implementsInterface()(px.object({
1328
1125
  transformation: PxTransformationEffectSchema.optional(),
1329
1126
  repeater: PxRepeaterEffectSchema.optional(),
1330
1127
  maskedBy: PxMaskedByEffectSchema.optional(),
1331
1128
  trimPath: PxTrimPathEffectSchema.optional(),
1332
1129
  retime: PxRetimeEffectSchema.optional(),
1333
1130
  isCombinedShape: px.boolean().optional(),
1334
- ref: PxRefEffectSchema.optional()
1335
- });
1131
+ ref: PxRefEffectSchema.optional(),
1132
+ fillGradient: PxFillGradientEffectSchema.optional(),
1133
+ strokeGradient: PxStrokeGradientEffectSchema.optional(),
1134
+ textAlongPath: PxTextAlongPathEffectSchema.optional()
1135
+ }));
1336
1136
  function validateNodeEffects(root, opts) {
1337
1137
  const warnings = [];
1338
1138
  const walk = (node, path) => {
@@ -1358,7 +1158,10 @@ var PxNodeBase = px.openObject({
1358
1158
  // Consumed and removed by `applyPlayerEffects` before any other normalisation
1359
1159
  // (see `createAnimatorImpl`), so downstream code never sees it.
1360
1160
  effects: PxEffectsSchema.optional(),
1361
- animate: PxAnimationDefinitionSchema.optional(),
1161
+ // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
1162
+ // string ref / array of refs / inline definition / mixed array; mirrors
1163
+ // `animator.animate` map values and what `processNode` resolves at runtime.
1164
+ animate: PxElementAnimationSchema.optional(),
1362
1165
  style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
1363
1166
  }, PxAttrValueSchema);
1364
1167
  var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
@@ -1411,784 +1214,1586 @@ function getChildren(doc) {
1411
1214
  return doc == null ? void 0 : doc.children;
1412
1215
  }
1413
1216
 
1414
- // src/PxAnimatorUtil.ts
1415
- function bezierToSvgPath(path) {
1416
- var _a, _b, _c, _d;
1417
- const v = path.v;
1418
- const i = path.i;
1419
- const o = path.o;
1420
- const c = path.c;
1421
- if (!v.length) return "";
1422
- const d = [];
1423
- const len = v.length;
1424
- d.push("M" + v[0][0] + "," + v[0][1]);
1425
- for (let idx = 1; idx < len; idx++) {
1426
- const prevV = v[idx - 1];
1427
- const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
1428
- const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
1429
- const currV = v[idx];
1430
- const isLine = prevO[0] === prevV[0] && prevO[1] === prevV[1] && (currI[0] === currV[0] && currI[1] === currV[1]);
1431
- if (isLine) {
1432
- d.push("L" + currV[0] + "," + currV[1]);
1433
- } else {
1434
- d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
1217
+ // src/PxNodeCloneUtil.ts
1218
+ function deepClonePxNode(value) {
1219
+ if (value === null || typeof value !== "object") return value;
1220
+ if (Array.isArray(value)) return value.map(deepClonePxNode);
1221
+ const out = {};
1222
+ for (const k of Object.keys(value)) out[k] = deepClonePxNode(value[k]);
1223
+ return out;
1224
+ }
1225
+ function regenerateIdsAndRewriteRefs(root, genId3) {
1226
+ const oldToNew = /* @__PURE__ */ new Map();
1227
+ const walkAssign = (n) => {
1228
+ var _a;
1229
+ if (typeof n.id === "string") {
1230
+ const newId = genId3();
1231
+ oldToNew.set(n.id, newId);
1232
+ n.id = newId;
1435
1233
  }
1436
- }
1437
- if (c && len > 0) {
1438
- const lastV = v[len - 1];
1439
- const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
1440
- const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
1441
- const firstV = v[0];
1442
- const isLine = lastO[0] === lastV[0] && lastO[1] === lastV[1] && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
1443
- if (!isLine) {
1444
- d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
1234
+ (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
1235
+ };
1236
+ walkAssign(root);
1237
+ const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
1238
+ const newId = oldToNew.get(oldId);
1239
+ return newId ? "url(#" + newId + ")" : m;
1240
+ });
1241
+ const walkRewrite = (n) => {
1242
+ var _a;
1243
+ if (typeof n.href === "string" && n.href.startsWith("#")) {
1244
+ const newId = oldToNew.get(n.href.slice(1));
1245
+ if (newId) n.href = "#" + newId;
1445
1246
  }
1446
- d.push("z");
1447
- }
1448
- return d.join("");
1247
+ for (const k of Object.keys(n)) {
1248
+ if (k === "children" || k === "effects" || k === "meta" || k === "animate" || k === "href" || k === "id") continue;
1249
+ const v = n[k];
1250
+ if (typeof v === "string" && v.indexOf("url(#") !== -1) {
1251
+ n[k] = rewriteUrl(v);
1252
+ }
1253
+ }
1254
+ (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
1255
+ };
1256
+ walkRewrite(root);
1257
+ return oldToNew;
1449
1258
  }
1450
- function interpolateNum(a, b, t) {
1451
- return a + (b - a) * t;
1259
+ function toFiniteNum(v) {
1260
+ const n = typeof v === "number" ? v : typeof v === "string" ? parseFloat(v) : NaN;
1261
+ return Number.isFinite(n) ? n : 0;
1452
1262
  }
1453
- function interpolateVec(a, b, t) {
1454
- const res = [];
1455
- const count = Math.max(a.length, b.length);
1456
- for (let i = 0; i < count; i++) {
1457
- res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
1263
+ function applyUseOffsetToG(gNode) {
1264
+ var _a;
1265
+ const x = toFiniteNum(gNode.x);
1266
+ const y = toFiniteNum(gNode.y);
1267
+ delete gNode.x;
1268
+ delete gNode.y;
1269
+ if (!x && !y) return gNode;
1270
+ const offset = "translate(" + x + "," + y + ")";
1271
+ const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
1272
+ if (carriesTransform) {
1273
+ const inner = { type: "g", transform: offset, children: (_a = gNode.children) != null ? _a : [] };
1274
+ gNode.children = [inner];
1275
+ } else {
1276
+ gNode.transform = offset;
1458
1277
  }
1459
- return res;
1278
+ return gNode;
1460
1279
  }
1461
- function interpolateColor(a, b, t) {
1462
- return [
1463
- interpolateNum(a[0] || 0, b[0] || 0, t),
1464
- interpolateNum(a[1] || 0, b[1] || 0, t),
1465
- interpolateNum(a[2] || 0, b[2] || 0, t),
1466
- interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
1467
- ];
1280
+
1281
+ // src/effects/util.ts
1282
+ function genId(ctx, prefix) {
1283
+ return "_lw_" + prefix + "_" + ctx.nextId++;
1468
1284
  }
1469
- function interpolateBeziers(paths1, paths2, progress) {
1470
- const count = Math.max(paths1.length, paths2.length);
1471
- const res = [];
1472
- for (let i = 0; i < count; i++) {
1473
- res.push(interpolateBezier(paths1[i], paths2[i], progress));
1474
- }
1475
- return res;
1285
+ function stripHash(href) {
1286
+ return typeof href === "string" ? href.replace(/^#/, "") : void 0;
1476
1287
  }
1477
- function interpolateBezier(path1, path2, progress) {
1478
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1479
- if (!path1 || !path2) return path1 || path2 || { v: [] };
1480
- const t = Math.min(Math.max(progress, 0), 1);
1481
- const len = Math.min(path1.v.length, path2.v.length);
1482
- const v = [];
1483
- const i = [];
1484
- const o = [];
1485
- for (let idx = 0; idx < len; idx++) {
1486
- const v1 = path1.v[idx];
1487
- const v2 = path2.v[idx];
1488
- v.push(interpolateVec(v1, v2, t));
1489
- const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
1490
- const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
1491
- i.push(interpolateVec(i1, i2, t));
1492
- const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
1493
- const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
1494
- o.push(interpolateVec(o1, o2, t));
1495
- }
1496
- return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
1288
+ function indexById(node, map) {
1289
+ var _a;
1290
+ if (typeof node.id === "string") map.set(node.id, node);
1291
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
1497
1292
  }
1498
- function remap(value, inMin, inMax, outMin, outMax) {
1499
- if (inMax === inMin) return outMin;
1500
- const t = (value - inMin) / (inMax - inMin);
1501
- return outMin + t * (outMax - outMin);
1293
+ function spliceDefs(root, defs) {
1294
+ if (!defs.length) return;
1295
+ const existing = root.children || (root.children = []);
1296
+ existing.unshift({ type: "defs", children: defs });
1502
1297
  }
1503
- function solveCubicBezierX(p1x, p2x, x) {
1504
- if (x <= 0) return 0;
1505
- if (x >= 1) return 1;
1506
- const cx = 3 * p1x;
1507
- const bx = 3 * (p2x - p1x) - cx;
1508
- const ax = 1 - cx - bx;
1509
- function sampleX(t) {
1510
- return ((ax * t + bx) * t + cx) * t;
1511
- }
1512
- function sampleDX(t) {
1513
- return (3 * ax * t + 2 * bx) * t + cx;
1298
+ var clone = deepClonePxNode;
1299
+ function regenerateIdsInClone(root, ctx) {
1300
+ return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
1301
+ }
1302
+
1303
+ // src/effects/gradientEffect.ts
1304
+ function applyFillGradientEffect(node, fx, ctx) {
1305
+ return applyGradient(node, fx, ctx, "fill");
1306
+ }
1307
+ function applyStrokeGradientEffect(node, fx, ctx) {
1308
+ return applyGradient(node, fx, ctx, "stroke");
1309
+ }
1310
+ function applyGradient(node, fx, ctx, attr) {
1311
+ if (!fx) return node;
1312
+ const id = genId(ctx, "grad");
1313
+ const def = synthesiseGradientDef(fx, id, ctx);
1314
+ ctx.defs.push(def);
1315
+ node[attr] = "url(#" + id + ")";
1316
+ return node;
1317
+ }
1318
+ function synthesiseGradientDef(fx, id, ctx) {
1319
+ const out = {
1320
+ type: fx.type === PxGradientType.radial ? "radialGradient" : "linearGradient",
1321
+ id
1322
+ };
1323
+ if (fx.type === PxGradientType.linear) {
1324
+ if (fx.p1) {
1325
+ out.x1 = String(fx.p1[0]);
1326
+ out.y1 = String(fx.p1[1]);
1327
+ }
1328
+ if (fx.p2) {
1329
+ out.x2 = String(fx.p2[0]);
1330
+ out.y2 = String(fx.p2[1]);
1331
+ }
1332
+ } else {
1333
+ if (fx.c) {
1334
+ out.cx = String(fx.c[0]);
1335
+ out.cy = String(fx.c[1]);
1336
+ }
1337
+ if (fx.r !== void 0) out.r = String(fx.r);
1338
+ if (fx.fp) {
1339
+ out.fx = String(fx.fp[0]);
1340
+ out.fy = String(fx.fp[1]);
1341
+ }
1514
1342
  }
1515
- let t2 = x;
1516
- let t0 = 0;
1517
- let t1 = 1;
1518
- for (let i = 0; i < 8; i++) {
1519
- const x2 = sampleX(t2) - x;
1520
- if (Math.abs(x2) < 1e-6) return t2;
1521
- const d2 = sampleDX(t2);
1522
- if (Math.abs(d2) < 1e-6) break;
1523
- t2 -= x2 / d2;
1343
+ if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
1344
+ if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
1345
+ if (fx.gradientTransform) out.gradientTransform = fx.gradientTransform;
1346
+ out.children = buildStopChildren(fx.stops, ctx);
1347
+ return out;
1348
+ }
1349
+ function buildStopChildren(stops, ctx) {
1350
+ var _a, _b, _c, _d;
1351
+ if (!stops) return [];
1352
+ if (Array.isArray(stops)) return stops.map(staticStopNode);
1353
+ if (typeof stops === "object" && Array.isArray(stops.value)) {
1354
+ return stops.value.map(staticStopNode);
1355
+ }
1356
+ const animBlock = stops;
1357
+ const kfs = animBlock.keyframes;
1358
+ if (!Array.isArray(kfs) || !kfs.length) return [];
1359
+ let stopCount = 0;
1360
+ for (const kf of kfs) {
1361
+ const v = (_a = kf.value) != null ? _a : kf.v;
1362
+ if (Array.isArray(v) && v.length > stopCount) stopCount = v.length;
1524
1363
  }
1525
- t2 = x;
1526
- while (t0 < t1) {
1527
- const x2 = sampleX(t2);
1528
- if (Math.abs(x2 - x) < 1e-6) return t2;
1529
- if (x > x2) t0 = t2;
1530
- else t1 = t2;
1531
- t2 = (t1 + t0) / 2;
1364
+ if (!stopCount) return [];
1365
+ const firstKfValue = (_b = kfs[0].value) != null ? _b : kfs[0].v;
1366
+ const baselineStops = [];
1367
+ for (let i = 0; i < stopCount; i++) {
1368
+ 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" };
1369
+ baselineStops.push({ offset: s.offset, color: s.color });
1532
1370
  }
1533
- return t2;
1371
+ return baselineStops.map((bs, i) => animatedStopNode(bs, kfs, i, ctx));
1534
1372
  }
1535
- function cubicBezier(easing) {
1536
- const [p1x, p1y, p2x, p2y] = easing;
1537
- const cy = 3 * p1y;
1538
- const by = 3 * (p2y - p1y) - cy;
1539
- const ay = 1 - cy - by;
1540
- function sampleCurveY(t) {
1541
- return ((ay * t + by) * t + cy) * t;
1542
- }
1543
- return function(x) {
1544
- return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
1373
+ function staticStopNode(s) {
1374
+ return {
1375
+ type: "stop",
1376
+ offset: formatOffset(s.offset),
1377
+ stopColor: s.color
1545
1378
  };
1546
1379
  }
1547
- function lerp2(a, b, t) {
1548
- return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
1549
- }
1550
- function subdivideCubicBezier(p0, p1, p2, p3, t) {
1551
- const q0 = lerp2(p0, p1, t);
1552
- const q1 = lerp2(p1, p2, t);
1553
- const q2 = lerp2(p2, p3, t);
1554
- const r0 = lerp2(q0, q1, t);
1555
- const r1 = lerp2(q1, q2, t);
1556
- const s = lerp2(r0, r1, t);
1557
- return {
1558
- left: [p0, q0, r0, s],
1559
- right: [s, r1, q2, p3]
1380
+ function animatedStopNode(baseline, kfs, stopIdx, _ctx) {
1381
+ var _a, _b, _c, _d, _e;
1382
+ const colorKfs = [];
1383
+ const offsetKfs = [];
1384
+ let offsetVaries = false;
1385
+ for (const kf of kfs) {
1386
+ const t = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
1387
+ const arr = (_c = kf.value) != null ? _c : kf.v;
1388
+ const sliced = (_d = arr == null ? void 0 : arr[stopIdx]) != null ? _d : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
1389
+ if (!sliced) continue;
1390
+ const easing = (_e = kf.easing) != null ? _e : kf.e;
1391
+ const colorOut = { time: t, value: sliced.color };
1392
+ if (easing !== void 0) colorOut.easing = easing;
1393
+ colorKfs.push(colorOut);
1394
+ const offsetOut = { time: t, value: sliced.offset };
1395
+ if (easing !== void 0) offsetOut.easing = easing;
1396
+ offsetKfs.push(offsetOut);
1397
+ if (sliced.offset !== baseline.offset) offsetVaries = true;
1398
+ }
1399
+ const stop = {
1400
+ type: "stop",
1401
+ offset: formatOffset(baseline.offset),
1402
+ stopColor: baseline.color
1560
1403
  };
1404
+ const animate = {};
1405
+ if (colorKfs.length) animate.stopColor = { keyframes: colorKfs };
1406
+ if (offsetVaries && offsetKfs.length) animate.offset = { keyframes: offsetKfs };
1407
+ if (Object.keys(animate).length) stop.animate = animate;
1408
+ return stop;
1561
1409
  }
1562
- function splitEasing(easing, xFraction) {
1563
- if (!easing) return { left: void 0, right: void 0 };
1564
- if (xFraction <= 0) return { left: void 0, right: easing };
1565
- if (xFraction >= 1) return { left: easing, right: void 0 };
1566
- const [x1, y1, x2, y2] = easing;
1567
- const t = solveCubicBezierX(x1, x2, xFraction);
1568
- const p0 = [0, 0];
1569
- const p1 = [x1, y1];
1570
- const p2 = [x2, y2];
1571
- const p3 = [1, 1];
1572
- const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
1573
- const sx = left[3][0];
1574
- const sy = left[3][1];
1575
- let leftEasing;
1576
- if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
1577
- leftEasing = [
1578
- left[1][0] / sx,
1579
- left[1][1] / sy,
1580
- left[2][0] / sx,
1581
- left[2][1] / sy
1582
- ];
1410
+ function prevDefinedStop(kfs, fromIdx, stopIdx) {
1411
+ var _a, _b;
1412
+ for (let i = fromIdx; i >= 0; i--) {
1413
+ const arr = (_a = kfs[i].value) != null ? _a : kfs[i].v;
1414
+ if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
1583
1415
  }
1584
- let rightEasing;
1585
- const rx = 1 - sx;
1586
- const ry = 1 - sy;
1587
- if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
1588
- rightEasing = [
1589
- (right[1][0] - sx) / rx,
1590
- (right[1][1] - sy) / ry,
1591
- (right[2][0] - sx) / rx,
1592
- (right[2][1] - sy) / ry
1593
- ];
1416
+ for (let i = fromIdx + 1; i < kfs.length; i++) {
1417
+ const arr = (_b = kfs[i].value) != null ? _b : kfs[i].v;
1418
+ if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
1594
1419
  }
1595
- return { left: leftEasing, right: rightEasing };
1420
+ return void 0;
1596
1421
  }
1597
- function reverseEasing(easing) {
1598
- if (!easing) return void 0;
1599
- return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
1422
+ function formatOffset(o) {
1423
+ const pct = Math.round(o * 1e3) / 10;
1424
+ return pct + "%";
1600
1425
  }
1601
- function toRGBA(color) {
1602
- const r = Math.round(color[0] * 255);
1603
- const g = Math.round(color[1] * 255);
1604
- const b = Math.round(color[2] * 255);
1605
- return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
1426
+
1427
+ // src/effects/maskedByEffect.ts
1428
+ function applyMaskedByEffect(node, fx, transformation, ctx) {
1429
+ if (!fx) return node;
1430
+ if (!fx.href) {
1431
+ ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
1432
+ return node;
1433
+ }
1434
+ const maskId = genId(ctx, "mask");
1435
+ let content = { type: "use", href: "#" + fx.href };
1436
+ if (transformation) {
1437
+ content = wrapInverseTransform(content, transformation, ctx);
1438
+ } else if (hasAnimateTransform(node)) {
1439
+ content = wrapInverseAnimatedBodyTransform(content, node, ctx);
1440
+ } else {
1441
+ const bodyStatic = readTransformationFromBody(node);
1442
+ if (bodyStatic) content = wrapInverseTransform(content, bodyStatic, ctx);
1443
+ }
1444
+ const includeTargetOwn = transformation === void 0 && !nodeHasBodyTransform(node);
1445
+ content = wrapAncestorChainCompensation(content, node, fx.href, ctx, includeTargetOwn);
1446
+ const mask = { type: "mask", id: maskId, children: [content] };
1447
+ if (fx.maskType) mask.maskType = fx.maskType;
1448
+ if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
1449
+ if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
1450
+ ctx.defs.push(mask);
1451
+ node.mask = "url(#" + maskId + ")";
1452
+ return node;
1606
1453
  }
1607
- function parseRgba(s) {
1608
- var _a;
1609
- const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
1610
- if (!inner) throw new Error("Invalid rgb/rgba format");
1611
- const parts = inner.split(",").map((v) => +v.trim());
1612
- return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
1454
+ function wrapInverseTransform(inner, fx, ctx) {
1455
+ if (!fx) return inner;
1456
+ const origin = readStaticOrigin(fx.origin, ctx);
1457
+ let n = inner;
1458
+ n = wrapInversePart(n, "translate" /* Translate */, fx.translate, void 0, ctx);
1459
+ n = wrapInversePart(n, "rotate" /* Rotate */, fx.rotate, origin, ctx);
1460
+ n = wrapInversePart(n, "scale" /* Scale */, fx.scale, origin, ctx);
1461
+ return n;
1613
1462
  }
1614
- function parseHex(s) {
1615
- const hex = s.slice(1);
1616
- const isShort = hex.length <= 4;
1617
- const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
1618
- const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
1619
- const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
1620
- const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
1621
- const result = [
1622
- parseInt(r, 16) / 255,
1623
- parseInt(g, 16) / 255,
1624
- parseInt(b, 16) / 255
1625
- ];
1626
- if (a !== null) {
1627
- result.push(parseInt(a, 16) / 255);
1463
+ function wrapInversePart(inner, part, raw, origin, ctx) {
1464
+ if (raw === void 0) return inner;
1465
+ const normalisedRaw = part === "scale" /* Scale */ && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
1466
+ const v = readAnimatable(normalisedRaw);
1467
+ if (v.kind === "static" /* Static */) {
1468
+ return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
1628
1469
  }
1629
- return result;
1630
- }
1631
- function parseColor(s) {
1632
- if (!s) return void 0;
1633
- if (Array.isArray(s)) return s;
1634
- if (typeof s !== "string") return void 0;
1635
- if (s.startsWith("#")) {
1636
- return parseHex(s);
1637
- } else if (s.startsWith("rgb")) {
1638
- return parseRgba(s);
1639
- } else {
1640
- console.warn("Unsupported color format: " + s);
1470
+ if (v.kind === "animated" /* Animated */) {
1471
+ return {
1472
+ type: "g",
1473
+ animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, invertPartValue(part, kf.value), origin))) } },
1474
+ children: [inner]
1475
+ };
1641
1476
  }
1642
- return void 0;
1643
- }
1644
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
1645
- var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
1646
- var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1647
- function composeTransformParts(parts, opts) {
1648
- var _a;
1649
- if (!parts) return "";
1650
- const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
1651
- const segs = [];
1652
- const t = parts.translate;
1653
- const o = parts.origin;
1654
- const r = parts.rotate;
1655
- const s = parts.scale;
1656
- const tu = withUnits ? "px" : "";
1657
- const ru = withUnits ? "deg" : "";
1658
- if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
1659
- if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
1660
- if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
1661
- if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
1662
- if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
1663
- return segs.join("");
1664
- }
1665
- var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1666
- var DEFAULT_DURATION_MS = 1e3;
1667
- function kebabToCamelCaseWord(kebab) {
1668
- return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
1669
- }
1670
- function isCamelCaseWord(word) {
1671
- return !word.includes("-") && /[a-z][A-Z]/.test(word);
1672
- }
1673
- var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
1674
- // Transform/positioning
1675
- "viewBox",
1676
- "preserveAspectRatio",
1677
- // Gradient
1678
- "gradientUnits",
1679
- "gradientTransform",
1680
- "spreadMethod",
1681
- // Pattern
1682
- "patternUnits",
1683
- "patternContentUnits",
1684
- "patternTransform",
1685
- // Clipping/masking
1686
- "clipPathUnits",
1687
- "maskUnits",
1688
- "maskContentUnits",
1689
- // Text
1690
- "textLength",
1691
- "lengthAdjust",
1692
- "startOffset",
1693
- // Filter
1694
- "filterUnits",
1695
- "primitiveUnits",
1696
- "stdDeviation",
1697
- "baseFrequency",
1698
- "numOctaves",
1699
- "surfaceScale",
1700
- "diffuseConstant",
1701
- "specularConstant",
1702
- "specularExponent",
1703
- "kernelMatrix",
1704
- "kernelUnitLength",
1705
- "edgeMode",
1706
- "preserveAlpha",
1707
- "targetX",
1708
- "targetY"
1709
- // // Animation
1710
- // 'attributeName',
1711
- // 'attributeType',
1712
- // 'calcMode',
1713
- // 'keyTimes',
1714
- // 'keySplines',
1715
- // 'repeatCount',
1716
- // 'repeatDur'
1717
- ]);
1718
- function camelCaseToKebabWordIfNeeded(camel) {
1719
- return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
1720
- }
1721
- function clamp(value, min, max) {
1722
- return Math.max(min, Math.min(value, max));
1477
+ return inner;
1723
1478
  }
1724
- function bezier2D_pointAt(P0, P1, P2, P3, t) {
1725
- if (t <= 0) return [P0[0], P0[1]];
1726
- if (t >= 1) return [P3[0], P3[1]];
1727
- const u = 1 - t;
1728
- const u2 = u * u;
1729
- const u3 = u2 * u;
1730
- const t2 = t * t;
1731
- const t3 = t2 * t;
1732
- const w0 = u3;
1733
- const w1 = 3 * t * u2;
1734
- const w2 = 3 * t2 * u;
1735
- const w3 = t3;
1736
- return [
1737
- w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
1738
- w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
1739
- ];
1479
+ function invertPartValue(part, value) {
1480
+ if (part === "translate" /* Translate */) return [-value[0], -value[1]];
1481
+ if (part === "rotate" /* Rotate */) return -value;
1482
+ return [1 / value[0], 1 / value[1]];
1740
1483
  }
1741
- var BEZIER_T_NUDGE = 1e-4;
1742
- function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
1743
- const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
1744
- if (result[0] === 0 && result[1] === 0) {
1745
- const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
1746
- return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
1484
+ function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
1485
+ var _a;
1486
+ const animate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
1487
+ const animTr = animate == null ? void 0 : animate.transform;
1488
+ const kfs = animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes) ? animTr.keyframes : void 0;
1489
+ if (!kfs || !kfs.length) return inner;
1490
+ const translateKfs = [];
1491
+ const rotateKfs = [];
1492
+ const scaleKfs = [];
1493
+ for (const kf of kfs) {
1494
+ const v = ((_a = kf.value) != null ? _a : kf.v) || {};
1495
+ const baseKf = keyframeWith(kf, void 0);
1496
+ if (Array.isArray(v.translate)) {
1497
+ translateKfs.push(__spreadProps(__spreadValues({}, baseKf), { value: { translate: [-v.translate[0], -v.translate[1]] } }));
1498
+ }
1499
+ if (typeof v.rotate === "number") {
1500
+ const rec = { rotate: -v.rotate };
1501
+ if (Array.isArray(v.origin)) rec.origin = [v.origin[0], v.origin[1]];
1502
+ rotateKfs.push(__spreadProps(__spreadValues({}, baseKf), { value: rec }));
1503
+ }
1504
+ if (Array.isArray(v.scale)) {
1505
+ const rec = { scale: [1 / v.scale[0], 1 / v.scale[1]] };
1506
+ if (Array.isArray(v.origin)) rec.origin = [v.origin[0], v.origin[1]];
1507
+ scaleKfs.push(__spreadProps(__spreadValues({}, baseKf), { value: rec }));
1508
+ }
1747
1509
  }
1748
- return result;
1510
+ let n = inner;
1511
+ if (translateKfs.length) n = { type: "g", animate: { transform: { keyframes: translateKfs } }, children: [n] };
1512
+ if (rotateKfs.length) n = { type: "g", animate: { transform: { keyframes: rotateKfs } }, children: [n] };
1513
+ if (scaleKfs.length) n = { type: "g", animate: { transform: { keyframes: scaleKfs } }, children: [n] };
1514
+ return n;
1749
1515
  }
1750
- function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
1751
- const u = 1 - t;
1752
- const a = 3 * u * u;
1753
- const b = 6 * t * u;
1754
- const c = 3 * t * t;
1755
- return [
1756
- a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
1757
- a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
1758
- ];
1516
+ function nodeHasBodyTransform(node) {
1517
+ if (typeof node.transform === "string") return true;
1518
+ if (node.transform && typeof node.transform === "object") return true;
1519
+ return hasAnimateTransform(node);
1759
1520
  }
1760
- function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
1761
- const n = steps + 1;
1762
- const ts = new Float64Array(n);
1763
- const ds = new Float64Array(n);
1764
- let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
1765
- ts[0] = 0;
1766
- ds[0] = 0;
1767
- let cum = 0;
1768
- for (let i = 1; i < n; i++) {
1769
- const t = i / steps;
1770
- const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
1771
- const dx = cur[0] - prev[0];
1772
- const dy = cur[1] - prev[1];
1773
- cum += Math.sqrt(dx * dx + dy * dy);
1774
- ts[i] = t;
1775
- ds[i] = cum;
1776
- prev = cur;
1777
- }
1778
- return { ts, ds };
1521
+ function hasAnimateTransform(node) {
1522
+ const animate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
1523
+ return !!(animate && animate.transform);
1779
1524
  }
1780
- function bezier2D_tForDistance(lut, distance) {
1781
- const { ts, ds } = lut;
1782
- const last = ds.length - 1;
1783
- if (distance <= 0) return ts[0];
1784
- if (distance >= ds[last]) return ts[last];
1785
- let lo = 1;
1786
- let hi = last;
1787
- while (lo < hi) {
1788
- const mid = lo + hi >>> 1;
1789
- if (ds[mid] < distance) lo = mid + 1;
1790
- else hi = mid;
1525
+ function readTransformationFromBody(node) {
1526
+ if (typeof node.transform === "string") {
1527
+ const parts = parseTransformStringToParts(node.transform);
1528
+ if (!parts) return void 0;
1529
+ const out = {};
1530
+ if (parts.translate) out.translate = parts.translate;
1531
+ if (parts.rotate !== void 0) out.rotate = parts.rotate;
1532
+ if (parts.scale) out.scale = { value: parts.scale };
1533
+ if (parts.origin) out.origin = parts.origin;
1534
+ return Object.keys(out).length ? out : void 0;
1791
1535
  }
1792
- const dPrev = ds[hi - 1];
1793
- const dCur = ds[hi];
1794
- const span = dCur - dPrev;
1795
- const frac = span > 0 ? (distance - dPrev) / span : 0;
1796
- return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
1536
+ return void 0;
1797
1537
  }
1798
-
1799
- // src/PxAnimatorDOM.ts
1800
- var SVG_NS = "http://www.w3.org/2000/svg";
1801
- var ALLOWED_SVG_TAGS_LOWER_CASE = new Set([
1802
- "svg",
1803
- "g",
1804
- "path",
1805
- "circle",
1806
- "ellipse",
1807
- "rect",
1808
- "line",
1809
- "polyline",
1810
- "polygon",
1811
- "text",
1812
- "tspan",
1813
- "textPath",
1814
- "defs",
1815
- "clipPath",
1816
- "mask",
1817
- "pattern",
1818
- "linearGradient",
1819
- "radialGradient",
1820
- "stop",
1821
- "use",
1822
- "symbol",
1823
- "marker",
1824
- "filter",
1825
- "feGaussianBlur",
1826
- "feOffset",
1827
- "feBlend",
1828
- "feColorMatrix",
1829
- "feMerge",
1830
- "feMergeNode"
1831
- ].map((tagName) => tagName.toLowerCase()));
1832
- var ALLOWED_RESOURCE_ATTRIBUTES = [
1833
- "href",
1834
- // <use>
1835
- "src",
1836
- // <image>
1837
- "filter",
1838
- // url(#filterId)
1839
- "clipPath",
1840
- // clip-path="url(#clipPathId)"
1841
- "mask",
1842
- // url(#maskId)
1843
- "markerStart",
1844
- // marker-start="url(#markerId)"
1845
- "markerMid",
1846
- // marker-mid="url(#markerId)"
1847
- "markerEnd"
1848
- // marker-end="url(#markerId)"
1849
- // 'fill', // url(#gradientId) or url(#patternId)
1850
- // 'stroke', // url(#gradientId) or url(#patternId)
1851
- // Don't allow 'cursor', can use external SVG, // url(cursor.svg)
1852
- ];
1853
- var ALLOWED_RESOURCE_ATTRIBUTES_SET = new Set(ALLOWED_RESOURCE_ATTRIBUTES);
1854
- var ALLOWED_ATTRIBUTES = [
1855
- "href",
1856
- "src",
1857
- // Presentation
1858
- "fill",
1859
- "fillOpacity",
1860
- "fillRule",
1861
- "stroke",
1862
- "strokeWidth",
1863
- "strokeOpacity",
1864
- "strokeLinecap",
1865
- "strokeLinejoin",
1866
- "strokeMiterlimit",
1867
- "strokeDasharray",
1868
- "strokeDashoffset",
1869
- "opacity",
1870
- "transform",
1871
- // Geometry
1872
- "x",
1873
- "y",
1874
- "cx",
1875
- "cy",
1876
- "r",
1877
- "rx",
1878
- "ry",
1879
- "width",
1880
- "height",
1881
- "d",
1882
- "x1",
1883
- "y1",
1884
- "x2",
1885
- "y2",
1886
- "points",
1887
- "dx",
1888
- "dy",
1889
- // Font
1890
- "fontSize",
1891
- "fontFamily",
1892
- "fontWeight",
1893
- "fontStyle",
1894
- // Text
1895
- "textAnchor",
1896
- "letterSpacing",
1897
- "wordSpacing",
1898
- "space",
1899
- "xml:space",
1900
- "textDecoration",
1901
- "textTransform",
1902
- "whiteSpace",
1903
- "white-space",
1904
- "dominantBaseline",
1905
- "alignmentBaseline",
1906
- "rotate",
1907
- // per-glyph rotation array, currently not supported
1908
- // Structure
1909
- "id",
1910
- "class",
1911
- "viewBox",
1912
- "preserveAspectRatio",
1913
- // Gradient/Pattern
1914
- "offset",
1915
- "stopColor",
1916
- "stopOpacity",
1917
- "gradientTransform",
1918
- // Clippath/Mask
1919
- "clipPath",
1920
- "mask",
1921
- // Motion path
1922
- "offsetPath",
1923
- "offsetDistance",
1924
- "offsetRotate",
1925
- "offsetAnchor",
1926
- "offsetPosition",
1927
- // Text path
1928
- "startOffset",
1929
- "textLength",
1930
- "lengthAdjust",
1931
- // Filter
1932
- "filter",
1933
- "stdDeviation",
1934
- "in",
1935
- "in2",
1936
- "result",
1937
- "mode",
1938
- ...ALLOWED_RESOURCE_ATTRIBUTES
1939
- ];
1940
- var ALLOWED_ATTRIBUTES_LOW_SET = new Set(ALLOWED_ATTRIBUTES.map((str) => str.toLowerCase()));
1941
- function sanitiseAttributeValue(name, value) {
1942
- const nameLower = name.toLowerCase();
1943
- if (!ALLOWED_ATTRIBUTES_LOW_SET.has(nameLower)) {
1944
- console.warn("Attribute not in whitelist: ", nameLower);
1945
- return void 0;
1946
- }
1947
- if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopColor") {
1948
- const str = String(value);
1949
- if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
1950
- console.warn('Attribute "' + nameLower + '" blocked: url() references must be internal url(#id), got:', value);
1951
- return void 0;
1538
+ function parseTransformStringToParts(s) {
1539
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1540
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
1541
+ let m;
1542
+ const ops = [];
1543
+ while ((m = re.exec(s)) !== null) {
1544
+ const args = m[2].split(/[\s,]+/).filter((a) => a.length > 0).map(Number);
1545
+ ops.push({ name: m[1], args });
1546
+ }
1547
+ if (!ops.length) return void 0;
1548
+ const last = ops[ops.length - 1];
1549
+ if (last.name === "translate") {
1550
+ for (let j = ops.length - 2; j >= 0; j--) {
1551
+ const cand = ops[j];
1552
+ if (cand.name !== "translate") continue;
1553
+ const ox = (_a = cand.args[0]) != null ? _a : 0;
1554
+ const oy = (_b = cand.args[1]) != null ? _b : 0;
1555
+ const lx = (_c = last.args[0]) != null ? _c : 0;
1556
+ const ly = (_d = last.args[1]) != null ? _d : 0;
1557
+ if (lx !== -ox || ly !== -oy) continue;
1558
+ const out2 = {};
1559
+ out2.origin = [ox, oy];
1560
+ for (let k = 0; k < j; k++) {
1561
+ if (ops[k].name === "translate") {
1562
+ const tx = (_e = ops[k].args[0]) != null ? _e : 0;
1563
+ const ty = (_f = ops[k].args[1]) != null ? _f : 0;
1564
+ out2.translate = out2.translate ? [out2.translate[0] + tx, out2.translate[1] + ty] : [tx, ty];
1565
+ }
1566
+ }
1567
+ for (let k = j + 1; k < ops.length - 1; k++) {
1568
+ const op = ops[k];
1569
+ if (op.name === "rotate") out2.rotate = ((_g = out2.rotate) != null ? _g : 0) + ((_h = op.args[0]) != null ? _h : 0);
1570
+ else if (op.name === "scale") {
1571
+ const sx = (_i = op.args[0]) != null ? _i : 1;
1572
+ const sy = op.args.length > 1 ? op.args[1] : sx;
1573
+ out2.scale = out2.scale ? [out2.scale[0] * sx, out2.scale[1] * sy] : [sx, sy];
1574
+ }
1575
+ }
1576
+ return out2;
1952
1577
  }
1953
- return value;
1954
1578
  }
1955
- if (ALLOWED_RESOURCE_ATTRIBUTES_SET.has(nameLower)) {
1956
- const str = String(value);
1957
- if (str.startsWith("#")) {
1958
- return value;
1959
- }
1960
- if (/^url\(#[^)]+\)$/.test(str)) {
1961
- return value;
1579
+ let translate;
1580
+ let rotate;
1581
+ let scale;
1582
+ for (const op of ops) {
1583
+ if (op.name === "translate") {
1584
+ const dx = (_j = op.args[0]) != null ? _j : 0;
1585
+ const dy = (_k = op.args[1]) != null ? _k : 0;
1586
+ translate = translate ? [translate[0] + dx, translate[1] + dy] : [dx, dy];
1587
+ } else if (op.name === "rotate") {
1588
+ rotate = (rotate != null ? rotate : 0) + ((_l = op.args[0]) != null ? _l : 0);
1589
+ } else if (op.name === "scale") {
1590
+ const sx = (_m = op.args[0]) != null ? _m : 1;
1591
+ const sy = op.args.length > 1 ? op.args[1] : sx;
1592
+ scale = scale ? [scale[0] * sx, scale[1] * sy] : [sx, sy];
1962
1593
  }
1963
- return void 0;
1964
- }
1965
- return value;
1966
- }
1967
- function createElement(tagName, normalisedProps, style, children, textContent) {
1968
- if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) {
1969
- console.warn("Attribute not in whitelist: ", tagName);
1970
- return null;
1971
1594
  }
1972
- const element = document.createElementNS(SVG_NS, tagName);
1973
- for (const propName in normalisedProps) {
1974
- element.setAttribute(
1975
- camelCaseToKebabWordIfNeeded(propName),
1976
- sanitiseAttributeValue(propName, normalisedProps[propName])
1977
- );
1595
+ const out = {};
1596
+ if (translate) out.translate = translate;
1597
+ if (rotate !== void 0) out.rotate = rotate;
1598
+ if (scale) out.scale = scale;
1599
+ return Object.keys(out).length ? out : void 0;
1600
+ }
1601
+ function wrapAncestorChainCompensation(inner, maskedNode, sourceId, ctx, includeTargetOwn) {
1602
+ const sourceNode = ctx.idMap.get(sourceId);
1603
+ const targetAncestors = ctx.maskAncestorChains.get(maskedNode) || [];
1604
+ const targetOwn = includeTargetOwn ? extractTranslateOnly(maskedNode, ctx) : void 0;
1605
+ const targetChain = targetOwn ? [...targetAncestors, targetOwn] : targetAncestors;
1606
+ const sourceChain = sourceNode && ctx.maskAncestorChains.get(sourceNode) || [];
1607
+ if (!targetChain.length && !sourceChain.length) return inner;
1608
+ const times = /* @__PURE__ */ new Set();
1609
+ for (const a of targetChain) if (a.translateKeyframes) for (const kf of a.translateKeyframes) times.add(kf.time);
1610
+ for (const a of sourceChain) if (a.translateKeyframes) for (const kf of a.translateKeyframes) times.add(kf.time);
1611
+ const animated = times.size > 0;
1612
+ if (!animated) {
1613
+ const tgt = sumStaticTranslate(targetChain);
1614
+ const src = sumStaticTranslate(sourceChain);
1615
+ const dx = src[0] - tgt[0];
1616
+ const dy = src[1] - tgt[1];
1617
+ if (dx === 0 && dy === 0) return inner;
1618
+ return { type: "g", transform: "translate(" + dx + "," + dy + ")", children: [inner] };
1619
+ }
1620
+ const sortedTimes = Array.from(times).sort((a, b) => a - b);
1621
+ const keyframes = sortedTimes.map((t) => {
1622
+ const tgt = sumTranslateAt(targetChain, t);
1623
+ const src = sumTranslateAt(sourceChain, t);
1624
+ return { time: t, value: { translate: [src[0] - tgt[0], src[1] - tgt[1]] } };
1625
+ });
1626
+ return { type: "g", animate: { transform: { keyframes } }, children: [inner] };
1627
+ }
1628
+ function sumStaticTranslate(chain) {
1629
+ let x = 0, y = 0;
1630
+ for (const a of chain) {
1631
+ if (a.translate) {
1632
+ x += a.translate[0];
1633
+ y += a.translate[1];
1634
+ }
1978
1635
  }
1979
- if (style) {
1980
- for (const styleProp in style) {
1981
- element.style[styleProp] = String(style[styleProp]);
1636
+ return [x, y];
1637
+ }
1638
+ function sumTranslateAt(chain, t) {
1639
+ let x = 0, y = 0;
1640
+ for (const a of chain) {
1641
+ if (a.translateKeyframes && a.translateKeyframes.length) {
1642
+ const v = interpKfs(a.translateKeyframes, t);
1643
+ x += v[0];
1644
+ y += v[1];
1645
+ } else if (a.translate) {
1646
+ x += a.translate[0];
1647
+ y += a.translate[1];
1982
1648
  }
1983
1649
  }
1984
- if (children) {
1985
- for (const child of children) {
1986
- element.appendChild(child);
1650
+ return [x, y];
1651
+ }
1652
+ function interpKfs(kfs, t) {
1653
+ if (t <= kfs[0].time) return kfs[0].value;
1654
+ if (t >= kfs[kfs.length - 1].time) return kfs[kfs.length - 1].value;
1655
+ for (let i = 1; i < kfs.length; i++) {
1656
+ if (t <= kfs[i].time) {
1657
+ const prev = kfs[i - 1];
1658
+ const cur = kfs[i];
1659
+ const a = (t - prev.time) / (cur.time - prev.time);
1660
+ return [prev.value[0] + (cur.value[0] - prev.value[0]) * a, prev.value[1] + (cur.value[1] - prev.value[1]) * a];
1987
1661
  }
1988
1662
  }
1989
- if (textContent) element.textContent = textContent;
1990
- return element;
1991
- }
1992
- function resolveStyle(style, defs) {
1993
- var _a;
1994
- if (!style) return void 0;
1995
- if (typeof style === "string") {
1996
- return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
1997
- }
1998
- return style;
1663
+ return kfs[kfs.length - 1].value;
1664
+ }
1665
+ function collectMaskAncestorChains(root, ctx) {
1666
+ const interestingNodes = /* @__PURE__ */ new Set();
1667
+ const collectInterestingNodes = (n) => {
1668
+ var _a, _b;
1669
+ const href = (_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.href;
1670
+ if (typeof href === "string") {
1671
+ interestingNodes.add(n);
1672
+ const sourceNode = ctx.idMap.get(href);
1673
+ if (sourceNode) interestingNodes.add(sourceNode);
1674
+ }
1675
+ if (Array.isArray(n.children)) for (const ch of n.children) collectInterestingNodes(ch);
1676
+ };
1677
+ collectInterestingNodes(root);
1678
+ if (interestingNodes.size === 0) return;
1679
+ const walk = (node, chain) => {
1680
+ if (interestingNodes.has(node)) ctx.maskAncestorChains.set(node, chain);
1681
+ if (Array.isArray(node.children)) {
1682
+ const own = extractTranslateOnly(node, ctx);
1683
+ const next = own ? [...chain, own] : chain;
1684
+ for (const ch of node.children) walk(ch, next);
1685
+ }
1686
+ };
1687
+ walk(root, []);
1999
1688
  }
2000
- function getNormalizedProps(props) {
2001
- const propsCopy = {};
2002
- for (const key of Object.keys(props)) {
2003
- if (INTERNAL_ATTRS.has(key)) continue;
2004
- if (key === "style") continue;
2005
- let value = props[key];
2006
- if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2007
- propsCopy[key] = toRGBA(value);
2008
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
2009
- propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
2010
- } else if (TRANSFORM_FN_NAMES.has(key)) {
2011
- if (Array.isArray(value)) {
2012
- if (key === "translate") value = value.map((v) => v + "px");
2013
- value = value.join(",");
1689
+ function extractTranslateOnly(node, ctx) {
1690
+ var _a, _b, _c;
1691
+ const tr = node.transform;
1692
+ const animateBlock = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate.transform : void 0;
1693
+ if (tr === void 0 && !animateBlock) return void 0;
1694
+ const out = {};
1695
+ if (typeof tr === "string") {
1696
+ const parts = parseTranslateOnlyFromString(tr, ctx);
1697
+ if (parts) out.translate = parts;
1698
+ } else if (tr && typeof tr === "object") {
1699
+ const value = tr.value;
1700
+ if (value && typeof value === "object" && Array.isArray(value.translate)) {
1701
+ out.translate = [value.translate[0] || 0, value.translate[1] || 0];
1702
+ }
1703
+ if (value && (value.rotate !== void 0 || value.scale !== void 0 || value.skew !== void 0)) {
1704
+ ctx.warnings.push("maskedBy ancestor: non-translate transform parts ignored (rotate/scale not yet supported)");
1705
+ }
1706
+ }
1707
+ if (animateBlock && Array.isArray(animateBlock.keyframes)) {
1708
+ const kfs = animateBlock.keyframes;
1709
+ const translateKfs = [];
1710
+ for (const kf of kfs) {
1711
+ const v = (_a = kf.value) != null ? _a : kf.v;
1712
+ const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
1713
+ if (v && typeof v === "object" && Array.isArray(v.translate)) {
1714
+ translateKfs.push({ time: t, value: [v.translate[0] || 0, v.translate[1] || 0] });
1715
+ if (v.rotate !== void 0 || v.scale !== void 0 || v.skew !== void 0) {
1716
+ ctx.warnings.push("maskedBy ancestor: animated non-translate parts ignored");
1717
+ }
2014
1718
  }
2015
- if (key === "rotate") value = value + "deg";
2016
- propsCopy["transform"] = key + "(" + value + ")";
2017
- } else if (value !== void 0 && value !== null) {
2018
- propsCopy[key] = String(value);
2019
1719
  }
1720
+ if (translateKfs.length) out.translateKeyframes = translateKfs;
2020
1721
  }
2021
- return propsCopy;
1722
+ return out.translate || out.translateKeyframes ? out : void 0;
2022
1723
  }
2023
- function renderNode(node, defs) {
2024
- if (!node) return null;
2025
- const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
2026
- const nodeDefs = getDefs(node) || defs;
2027
- const resolvedStyle = resolveStyle(style, nodeDefs);
2028
- let childElements;
2029
- if (children) {
2030
- for (const ch of children) {
2031
- const child = renderNode(ch, nodeDefs);
2032
- if (child) {
2033
- if (!childElements) childElements = [];
2034
- childElements.push(child);
2035
- }
1724
+ function parseTranslateOnlyFromString(s, ctx) {
1725
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
1726
+ let m;
1727
+ let x = 0, y = 0;
1728
+ let seen = false;
1729
+ let droppedNonTranslate = false;
1730
+ while ((m = re.exec(s)) !== null) {
1731
+ const name = m[1];
1732
+ const args = m[2].split(/[\s,]+/).filter((a) => a.length > 0).map(Number);
1733
+ if (name === "translate") {
1734
+ x += args[0] || 0;
1735
+ y += args[1] || 0;
1736
+ seen = true;
1737
+ } else {
1738
+ droppedNonTranslate = true;
2036
1739
  }
2037
1740
  }
2038
- return createElement(
2039
- type || "g",
2040
- getNormalizedProps(props),
2041
- resolvedStyle,
2042
- childElements,
2043
- props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
2044
- );
1741
+ if (droppedNonTranslate) ctx.warnings.push("maskedBy ancestor: non-translate transform in string ignored: " + s);
1742
+ return seen ? [x, y] : void 0;
2045
1743
  }
2046
1744
 
2047
- // src/PxAnimatorTriggers.ts
2048
- function setupAnimationTriggers(api, config) {
2049
- const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
2050
- const root = api.getRootElement();
2051
- if (!root) {
2052
- console.warn("setupAnimationTriggers: No root element found for animation.");
2053
- return api;
1745
+ // src/effects/refEffect.ts
1746
+ var CONTENT_SUBREF = "content";
1747
+ function applyRefAndTransformationEffect(node, ref, transformation, ctx) {
1748
+ if (ref) {
1749
+ const baseId = ref.baseId;
1750
+ if (!baseId) {
1751
+ ctx.errors.push("ref: missing baseId");
1752
+ } else {
1753
+ const targetId = ref.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
1754
+ node.href = "#" + targetId;
1755
+ }
2054
1756
  }
2055
- const start = () => {
2056
- api.play();
2057
- };
2058
- const handleEndAction = () => {
2059
- switch (outAction) {
2060
- case "pause":
2061
- api.pause();
2062
- break;
2063
- case "reset":
2064
- api.cancel();
2065
- break;
2066
- case "reverse":
2067
- api.play();
2068
- break;
2069
- case "continue":
2070
- default:
2071
- break;
1757
+ return applyTransformationEffect(node, transformation, ctx);
1758
+ }
1759
+
1760
+ // src/effects/repeaterEffect.ts
1761
+ function applyRepeaterEffect(node, fx, ctx) {
1762
+ var _a, _b;
1763
+ if (!fx) return node;
1764
+ const copies = (_a = fx.copies) != null ? _a : 1;
1765
+ if (copies < 1) {
1766
+ ctx.errors.push("repeater.copies invalid: " + fx.copies);
1767
+ return node;
1768
+ }
1769
+ const sharedTransform = node.transform;
1770
+ const sharedAnimTransform = (_b = node.animate) == null ? void 0 : _b.transform;
1771
+ const base = clone(node);
1772
+ delete base.transform;
1773
+ if (base.animate) {
1774
+ delete base.animate.transform;
1775
+ if (Object.keys(base.animate).length === 0) delete base.animate;
1776
+ }
1777
+ const children = [base];
1778
+ for (let i = 1; i < copies; i++) {
1779
+ const baseClone = clone(base);
1780
+ const synthFx = synthesisePerCopyFx(fx, i);
1781
+ const wrapped = synthFx ? applyTransformationEffect(baseClone, synthFx, ctx) : baseClone;
1782
+ children.push(wrapped);
1783
+ }
1784
+ const wrapper = { type: "g", children };
1785
+ if (sharedTransform !== void 0) wrapper.transform = sharedTransform;
1786
+ if (sharedAnimTransform !== void 0) wrapper.animate = { transform: sharedAnimTransform };
1787
+ return wrapper;
1788
+ }
1789
+ function synthesisePerCopyFx(fx, i) {
1790
+ const out = {};
1791
+ if (fx.translate !== void 0) {
1792
+ out.translate = mapAnimatableVec2(fx.translate, (v) => [v[0] * i, v[1] * i]);
1793
+ }
1794
+ if (fx.rotate !== void 0) {
1795
+ out.rotate = mapAnimatableNumber(fx.rotate, (v) => v * i);
1796
+ }
1797
+ if (fx.scale !== void 0) {
1798
+ out.scale = synthesiseScale(fx.scale, i);
1799
+ }
1800
+ if (fx.origin !== void 0) {
1801
+ out.origin = fx.origin;
1802
+ }
1803
+ return Object.keys(out).length ? out : void 0;
1804
+ }
1805
+ function mapAnimatableVec2(raw, fn) {
1806
+ if (Array.isArray(raw)) return fn(raw);
1807
+ if (raw && typeof raw === "object") {
1808
+ const obj = raw;
1809
+ if (Array.isArray(obj.keyframes)) {
1810
+ return __spreadProps(__spreadValues({}, obj), {
1811
+ keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: fn(kf.value) }) : kf)
1812
+ });
2072
1813
  }
2073
- };
2074
- switch (startOn) {
2075
- case "load": {
2076
- const startHandler = () => start();
2077
- if (document.readyState === "complete") {
2078
- startHandler();
2079
- } else {
2080
- window.addEventListener("load", startHandler, { once: true });
2081
- }
2082
- break;
1814
+ if (obj.value !== void 0) {
1815
+ return __spreadProps(__spreadValues({}, obj), { value: fn(obj.value) });
2083
1816
  }
2084
- case "mouseOver": {
2085
- const mouseOverHandler = () => start();
2086
- const mouseOutHandler = () => handleEndAction();
2087
- root.addEventListener("mouseenter", mouseOverHandler);
2088
- root.addEventListener("mouseleave", mouseOutHandler);
2089
- break;
1817
+ }
1818
+ return raw;
1819
+ }
1820
+ function mapAnimatableNumber(raw, fn) {
1821
+ if (typeof raw === "number") return fn(raw);
1822
+ if (raw && typeof raw === "object") {
1823
+ const obj = raw;
1824
+ if (Array.isArray(obj.keyframes)) {
1825
+ return __spreadProps(__spreadValues({}, obj), {
1826
+ keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: fn(kf.value) }) : kf)
1827
+ });
2090
1828
  }
2091
- case "click": {
2092
- const clickHandler = () => {
2093
- if (api.isPlaying()) {
2094
- handleEndAction();
2095
- } else {
2096
- start();
2097
- }
2098
- };
2099
- root.addEventListener("click", clickHandler);
2100
- break;
1829
+ if (obj.value !== void 0) {
1830
+ return __spreadProps(__spreadValues({}, obj), { value: fn(obj.value) });
2101
1831
  }
2102
- case "scrollIntoView": {
2103
- const observer = new IntersectionObserver(
2104
- (entries) => {
2105
- entries.forEach((entry) => {
2106
- if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
2107
- start();
2108
- } else {
2109
- handleEndAction();
2110
- }
2111
- });
2112
- },
2113
- { threshold: scrollIntoViewThreshold }
2114
- );
2115
- observer.observe(root);
2116
- break;
1832
+ }
1833
+ return raw;
1834
+ }
1835
+ function synthesiseScale(raw, i) {
1836
+ const scalePowerFromPercent = (v) => [Math.pow(v[0] / 100, i), Math.pow(v[1] / 100, i)];
1837
+ const scalePowerFromUnits = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
1838
+ if (Array.isArray(raw)) {
1839
+ return { value: scalePowerFromPercent(raw) };
1840
+ }
1841
+ if (raw && typeof raw === "object") {
1842
+ const obj = raw;
1843
+ if (Array.isArray(obj.keyframes)) {
1844
+ return __spreadProps(__spreadValues({}, obj), {
1845
+ keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: scalePowerFromUnits(kf.value) }) : kf)
1846
+ });
1847
+ }
1848
+ if (obj.value !== void 0) {
1849
+ return __spreadProps(__spreadValues({}, obj), { value: scalePowerFromPercent(obj.value) });
2117
1850
  }
2118
- case "programmatic":
2119
- break;
2120
1851
  }
2121
- return api;
1852
+ return raw;
2122
1853
  }
2123
1854
 
2124
- // src/PxMotionPath.ts
2125
- function propAnimIsMotionPath(anim) {
2126
- var _a;
2127
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
2128
- if (!Array.isArray(kfs)) return false;
2129
- if (anim.autoOrient) return true;
2130
- for (const kf of kfs) {
2131
- if (kf.tangentIn || kf.tangentOut) return true;
2132
- }
2133
- return false;
1855
+ // src/effects/retimeEffect.ts
1856
+ var RETIME_MATERIALISATION_MODE_INLINE_G = false;
1857
+ function asRetime(r) {
1858
+ var _a, _b;
1859
+ return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
2134
1860
  }
2135
- var _segmentCache = /* @__PURE__ */ new WeakMap();
2136
- function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
2137
- const existing = _segmentCache.get(prevKf);
2138
- if (existing) return existing;
2139
- const to = prevKf.tangentOut;
2140
- const ti = nextKf.tangentIn;
2141
- const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
2142
- const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
2143
- const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
2144
- const entry = {
2145
- P0: prevPos,
2146
- P1,
2147
- P2,
2148
- P3: nextPos,
2149
- lut,
2150
- totalArc: lut.ds[lut.ds.length - 1]
1861
+ function concatRetime(child, parent) {
1862
+ return {
1863
+ start: parent.start + parent.stretch * child.start,
1864
+ stretch: parent.stretch * child.stretch
2151
1865
  };
2152
- _segmentCache.set(prevKf, entry);
2153
- return entry;
2154
1866
  }
2155
- function evaluateMotionPathSegment(prevKf, nextKf, prevPos, nextPos, localProgress, autoOrient) {
2156
- const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2157
- const t = seg.totalArc === 0 ? localProgress : bezier2D_tForDistance(seg.lut, localProgress * seg.totalArc);
2158
- const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2159
- if (!autoOrient) return { translate: point };
2160
- const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2161
- const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2162
- return { translate: point, rotateDeg };
1867
+ function applyAllRetimeEffects(root, ctx) {
1868
+ var _a;
1869
+ ctx.idMap.clear();
1870
+ indexById(root, ctx.idMap);
1871
+ const sites = [];
1872
+ const collect = (n) => {
1873
+ var _a2, _b;
1874
+ if ((_a2 = n.effects) == null ? void 0 : _a2.retime) sites.push(n);
1875
+ (_b = n.children) == null ? void 0 : _b.forEach(collect);
1876
+ };
1877
+ collect(root);
1878
+ for (const useNode of sites) {
1879
+ const retime = (_a = useNode.effects) == null ? void 0 : _a.retime;
1880
+ if (!retime) continue;
1881
+ delete useNode.effects.retime;
1882
+ if (Object.keys(useNode.effects).length === 0) delete useNode.effects;
1883
+ materialiseRetime(useNode, asRetime(retime), ctx);
1884
+ }
1885
+ }
1886
+ function materialiseRetime(useNode, retime, ctx) {
1887
+ const targetId = stripHash(useNode.href);
1888
+ if (!targetId) {
1889
+ ctx.errors.push("retime: <use> has no href to follow");
1890
+ return;
1891
+ }
1892
+ const chainRootId = buildChainClone(targetId, retime, ctx, /* @__PURE__ */ new Set());
1893
+ if (!chainRootId) return;
1894
+ if (RETIME_MATERIALISATION_MODE_INLINE_G) {
1895
+ const cloneNode = ctx.idMap.get(chainRootId);
1896
+ useNode.type = "g";
1897
+ delete useNode.href;
1898
+ useNode.children = [cloneNode];
1899
+ applyUseOffsetToG(useNode);
1900
+ ctx.defs = ctx.defs.filter((d) => d !== cloneNode);
1901
+ } else {
1902
+ useNode.href = "#" + chainRootId;
1903
+ }
2163
1904
  }
2164
-
2165
- // src/PxDefinitions.ts
2166
- function parsePathCommands(d) {
2167
- const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
2168
- const commands = [];
2169
- let currentCommand = null;
2170
- for (const token of tokens) {
2171
- if (/[MLCZmlcz]/.test(token)) {
2172
- currentCommand = { type: token, values: [] };
2173
- commands.push(currentCommand);
2174
- } else if (currentCommand) {
2175
- const value = +token;
2176
- currentCommand.values.push(Number.isNaN(value) ? 0 : value);
1905
+ function buildChainClone(targetId, accum, ctx, chain) {
1906
+ var _a, _b;
1907
+ if (chain.has(targetId)) {
1908
+ ctx.errors.push('retime: loop via "' + targetId + '"');
1909
+ return void 0;
1910
+ }
1911
+ const target = ctx.idMap.get(targetId);
1912
+ if (!target) {
1913
+ ctx.warnings.push('retime: target "' + targetId + '" not found');
1914
+ return void 0;
1915
+ }
1916
+ const cloneNode = clone(target);
1917
+ regenerateIdsInClone(cloneNode, ctx);
1918
+ if (target.type === "use") {
1919
+ remapKeyframeTimesOnly(cloneNode, accum.start, accum.stretch);
1920
+ } else {
1921
+ remapKeyframeTimes(cloneNode, accum.start, accum.stretch);
1922
+ }
1923
+ if ((_a = cloneNode.effects) == null ? void 0 : _a.retime) {
1924
+ delete cloneNode.effects.retime;
1925
+ if (Object.keys(cloneNode.effects).length === 0) delete cloneNode.effects;
1926
+ }
1927
+ if (target.type === "use" && target.href) {
1928
+ const subId = stripHash(target.href);
1929
+ if (subId) {
1930
+ const innerRetime = (_b = target.effects) == null ? void 0 : _b.retime;
1931
+ const subAccum = innerRetime ? concatRetime(asRetime(innerRetime), accum) : accum;
1932
+ const subChain = new Set(chain);
1933
+ subChain.add(targetId);
1934
+ const subId2 = buildChainClone(subId, subAccum, ctx, subChain);
1935
+ if (subId2) cloneNode.href = "#" + subId2;
2177
1936
  }
2178
1937
  }
2179
- return commands;
1938
+ ctx.defs.push(cloneNode);
1939
+ if (typeof cloneNode.id === "string") ctx.idMap.set(cloneNode.id, cloneNode);
1940
+ return typeof cloneNode.id === "string" ? cloneNode.id : void 0;
2180
1941
  }
2181
- function parseSvgPathToBezier(d) {
2182
- const res = [];
2183
- let currentPath;
2184
- const commands = parsePathCommands(d);
2185
- for (const command of commands) {
2186
- const type = command.type;
2187
- const values = command.values;
2188
- if (type === "M" || type === "m") {
2189
- const x = values[0] || 0;
2190
- const y = values[1] || 0;
2191
- currentPath = {
1942
+ function remapKeyframeTimes(node, start, stretch) {
1943
+ var _a;
1944
+ remapKeyframeTimesOnly(node, start, stretch);
1945
+ (_a = node.children) == null ? void 0 : _a.forEach((c) => remapKeyframeTimes(c, start, stretch));
1946
+ }
1947
+ function remapKeyframeTimesOnly(node, start, stretch) {
1948
+ const remap2 = (kfs) => {
1949
+ for (const kf of kfs) if (typeof kf.time === "number") kf.time = start + kf.time * stretch;
1950
+ };
1951
+ if (node.transform && typeof node.transform === "object" && Array.isArray(node.transform.keyframes)) {
1952
+ remap2(node.transform.keyframes);
1953
+ }
1954
+ if (node.animate && typeof node.animate === "object") {
1955
+ for (const prop of Object.keys(node.animate)) {
1956
+ const anim = node.animate[prop];
1957
+ if (anim && Array.isArray(anim.keyframes)) remap2(anim.keyframes);
1958
+ }
1959
+ }
1960
+ }
1961
+
1962
+ // src/effects/textAlongPathEffect.ts
1963
+ function applyTextAlongPathEffect(node, fx, _ctx) {
1964
+ var _a;
1965
+ if (!fx) return node;
1966
+ const href = typeof fx.href === "string" && !fx.href.startsWith("#") ? "#" + fx.href : fx.href;
1967
+ const textPath = {
1968
+ type: "textPath",
1969
+ href,
1970
+ children: (_a = node.children) != null ? _a : []
1971
+ };
1972
+ if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
1973
+ if (fx.method !== void 0) textPath.method = fx.method;
1974
+ if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
1975
+ applyAnimatableNumber(textPath, "startOffset", fx.startOffset);
1976
+ applyAnimatableNumber(textPath, "textLength", fx.textLength);
1977
+ node.children = [textPath];
1978
+ return node;
1979
+ }
1980
+ function applyAnimatableNumber(node, attrName, raw) {
1981
+ if (raw === void 0 || raw === null) return;
1982
+ if (typeof raw === "number") {
1983
+ node[attrName] = String(raw);
1984
+ return;
1985
+ }
1986
+ if (typeof raw === "object") {
1987
+ const obj = raw;
1988
+ if (Array.isArray(obj.keyframes)) {
1989
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
1990
+ const animate = __spreadValues({}, prevAnimate || {});
1991
+ animate[attrName] = { keyframes: obj.keyframes };
1992
+ node.animate = animate;
1993
+ return;
1994
+ }
1995
+ if (typeof obj.value === "number") {
1996
+ node[attrName] = String(obj.value);
1997
+ return;
1998
+ }
1999
+ }
2000
+ }
2001
+
2002
+ // src/PxAnimatorUtil.ts
2003
+ function bezierToSvgPath(path) {
2004
+ var _a, _b, _c, _d;
2005
+ const v = path.v;
2006
+ const i = path.i;
2007
+ const o = path.o;
2008
+ const c = path.c;
2009
+ if (!v.length) return "";
2010
+ const d = [];
2011
+ const len = v.length;
2012
+ d.push("M" + v[0][0] + "," + v[0][1]);
2013
+ for (let idx = 1; idx < len; idx++) {
2014
+ const prevV = v[idx - 1];
2015
+ const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
2016
+ const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
2017
+ const currV = v[idx];
2018
+ const isLine = prevO[0] === prevV[0] && prevO[1] === prevV[1] && (currI[0] === currV[0] && currI[1] === currV[1]);
2019
+ if (isLine) {
2020
+ d.push("L" + currV[0] + "," + currV[1]);
2021
+ } else {
2022
+ d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
2023
+ }
2024
+ }
2025
+ if (c && len > 0) {
2026
+ const lastV = v[len - 1];
2027
+ const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
2028
+ const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
2029
+ const firstV = v[0];
2030
+ const isLine = lastO[0] === lastV[0] && lastO[1] === lastV[1] && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
2031
+ if (!isLine) {
2032
+ d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
2033
+ }
2034
+ d.push("z");
2035
+ }
2036
+ return d.join("");
2037
+ }
2038
+ function interpolateNum(a, b, t) {
2039
+ return a + (b - a) * t;
2040
+ }
2041
+ function interpolateVec(a, b, t) {
2042
+ const res = [];
2043
+ const count = Math.max(a.length, b.length);
2044
+ for (let i = 0; i < count; i++) {
2045
+ res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
2046
+ }
2047
+ return res;
2048
+ }
2049
+ function interpolateColor(a, b, t) {
2050
+ return [
2051
+ interpolateNum(a[0] || 0, b[0] || 0, t),
2052
+ interpolateNum(a[1] || 0, b[1] || 0, t),
2053
+ interpolateNum(a[2] || 0, b[2] || 0, t),
2054
+ interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
2055
+ ];
2056
+ }
2057
+ function interpolateBeziers(paths1, paths2, progress) {
2058
+ const count = Math.max(paths1.length, paths2.length);
2059
+ const res = [];
2060
+ for (let i = 0; i < count; i++) {
2061
+ res.push(interpolateBezier(paths1[i], paths2[i], progress));
2062
+ }
2063
+ return res;
2064
+ }
2065
+ function interpolateBezier(path1, path2, progress) {
2066
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2067
+ if (!path1 || !path2) return path1 || path2 || { v: [] };
2068
+ const t = Math.min(Math.max(progress, 0), 1);
2069
+ const len = Math.min(path1.v.length, path2.v.length);
2070
+ const v = [];
2071
+ const i = [];
2072
+ const o = [];
2073
+ for (let idx = 0; idx < len; idx++) {
2074
+ const v1 = path1.v[idx];
2075
+ const v2 = path2.v[idx];
2076
+ v.push(interpolateVec(v1, v2, t));
2077
+ const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
2078
+ const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
2079
+ i.push(interpolateVec(i1, i2, t));
2080
+ const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
2081
+ const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
2082
+ o.push(interpolateVec(o1, o2, t));
2083
+ }
2084
+ return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
2085
+ }
2086
+ function remap(value, inMin, inMax, outMin, outMax) {
2087
+ if (inMax === inMin) return outMin;
2088
+ const t = (value - inMin) / (inMax - inMin);
2089
+ return outMin + t * (outMax - outMin);
2090
+ }
2091
+ function solveCubicBezierX(p1x, p2x, x) {
2092
+ if (x <= 0) return 0;
2093
+ if (x >= 1) return 1;
2094
+ const cx = 3 * p1x;
2095
+ const bx = 3 * (p2x - p1x) - cx;
2096
+ const ax = 1 - cx - bx;
2097
+ function sampleX(t) {
2098
+ return ((ax * t + bx) * t + cx) * t;
2099
+ }
2100
+ function sampleDX(t) {
2101
+ return (3 * ax * t + 2 * bx) * t + cx;
2102
+ }
2103
+ let t2 = x;
2104
+ let t0 = 0;
2105
+ let t1 = 1;
2106
+ for (let i = 0; i < 8; i++) {
2107
+ const x2 = sampleX(t2) - x;
2108
+ if (Math.abs(x2) < 1e-6) return t2;
2109
+ const d2 = sampleDX(t2);
2110
+ if (Math.abs(d2) < 1e-6) break;
2111
+ t2 -= x2 / d2;
2112
+ }
2113
+ t2 = x;
2114
+ while (t0 < t1) {
2115
+ const x2 = sampleX(t2);
2116
+ if (Math.abs(x2 - x) < 1e-6) return t2;
2117
+ if (x > x2) t0 = t2;
2118
+ else t1 = t2;
2119
+ t2 = (t1 + t0) / 2;
2120
+ }
2121
+ return t2;
2122
+ }
2123
+ function cubicBezier(easing) {
2124
+ const [p1x, p1y, p2x, p2y] = easing;
2125
+ const cy = 3 * p1y;
2126
+ const by = 3 * (p2y - p1y) - cy;
2127
+ const ay = 1 - cy - by;
2128
+ function sampleCurveY(t) {
2129
+ return ((ay * t + by) * t + cy) * t;
2130
+ }
2131
+ return function(x) {
2132
+ return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
2133
+ };
2134
+ }
2135
+ function lerp2(a, b, t) {
2136
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
2137
+ }
2138
+ function subdivideCubicBezier(p0, p1, p2, p3, t) {
2139
+ const q0 = lerp2(p0, p1, t);
2140
+ const q1 = lerp2(p1, p2, t);
2141
+ const q2 = lerp2(p2, p3, t);
2142
+ const r0 = lerp2(q0, q1, t);
2143
+ const r1 = lerp2(q1, q2, t);
2144
+ const s = lerp2(r0, r1, t);
2145
+ return {
2146
+ left: [p0, q0, r0, s],
2147
+ right: [s, r1, q2, p3]
2148
+ };
2149
+ }
2150
+ function splitEasing(easing, xFraction) {
2151
+ if (!easing) return { left: void 0, right: void 0 };
2152
+ if (xFraction <= 0) return { left: void 0, right: easing };
2153
+ if (xFraction >= 1) return { left: easing, right: void 0 };
2154
+ const [x1, y1, x2, y2] = easing;
2155
+ const t = solveCubicBezierX(x1, x2, xFraction);
2156
+ const p0 = [0, 0];
2157
+ const p1 = [x1, y1];
2158
+ const p2 = [x2, y2];
2159
+ const p3 = [1, 1];
2160
+ const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
2161
+ const sx = left[3][0];
2162
+ const sy = left[3][1];
2163
+ let leftEasing;
2164
+ if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
2165
+ leftEasing = [
2166
+ left[1][0] / sx,
2167
+ left[1][1] / sy,
2168
+ left[2][0] / sx,
2169
+ left[2][1] / sy
2170
+ ];
2171
+ }
2172
+ let rightEasing;
2173
+ const rx = 1 - sx;
2174
+ const ry = 1 - sy;
2175
+ if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
2176
+ rightEasing = [
2177
+ (right[1][0] - sx) / rx,
2178
+ (right[1][1] - sy) / ry,
2179
+ (right[2][0] - sx) / rx,
2180
+ (right[2][1] - sy) / ry
2181
+ ];
2182
+ }
2183
+ return { left: leftEasing, right: rightEasing };
2184
+ }
2185
+ function reverseEasing(easing) {
2186
+ if (!easing) return void 0;
2187
+ return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
2188
+ }
2189
+ function toRGBA(color) {
2190
+ const r = Math.round(color[0] * 255);
2191
+ const g = Math.round(color[1] * 255);
2192
+ const b = Math.round(color[2] * 255);
2193
+ return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
2194
+ }
2195
+ function parseRgba(s) {
2196
+ var _a;
2197
+ const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
2198
+ if (!inner) throw new Error("Invalid rgb/rgba format");
2199
+ const parts = inner.split(",").map((v) => +v.trim());
2200
+ return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
2201
+ }
2202
+ function parseHex(s) {
2203
+ const hex = s.slice(1);
2204
+ const isShort = hex.length <= 4;
2205
+ const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
2206
+ const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
2207
+ const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
2208
+ const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
2209
+ const result = [
2210
+ parseInt(r, 16) / 255,
2211
+ parseInt(g, 16) / 255,
2212
+ parseInt(b, 16) / 255
2213
+ ];
2214
+ if (a !== null) {
2215
+ result.push(parseInt(a, 16) / 255);
2216
+ }
2217
+ return result;
2218
+ }
2219
+ function parseColor(s) {
2220
+ if (!s) return void 0;
2221
+ if (Array.isArray(s)) return s;
2222
+ if (typeof s !== "string") return void 0;
2223
+ if (s.startsWith("#")) {
2224
+ return parseHex(s);
2225
+ } else if (s.startsWith("rgb")) {
2226
+ return parseRgba(s);
2227
+ } else {
2228
+ console.warn("Unsupported color format: " + s);
2229
+ }
2230
+ return void 0;
2231
+ }
2232
+ var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
2233
+ var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
2234
+ var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
2235
+ function composeTransformParts(parts, opts) {
2236
+ var _a;
2237
+ if (!parts) return "";
2238
+ const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
2239
+ const segs = [];
2240
+ const t = parts.translate;
2241
+ const o = parts.origin;
2242
+ const r = parts.rotate;
2243
+ const s = parts.scale;
2244
+ const tu = withUnits ? "px" : "";
2245
+ const ru = withUnits ? "deg" : "";
2246
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
2247
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
2248
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
2249
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
2250
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
2251
+ return segs.join("");
2252
+ }
2253
+ var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
2254
+ var DEFAULT_DURATION_MS = 1e3;
2255
+ function kebabToCamelCaseWord(kebab) {
2256
+ return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
2257
+ }
2258
+ function isCamelCaseWord(word) {
2259
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
2260
+ }
2261
+ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
2262
+ // Transform/positioning
2263
+ "viewBox",
2264
+ "preserveAspectRatio",
2265
+ // Gradient
2266
+ "gradientUnits",
2267
+ "gradientTransform",
2268
+ "spreadMethod",
2269
+ // Pattern
2270
+ "patternUnits",
2271
+ "patternContentUnits",
2272
+ "patternTransform",
2273
+ // Clipping/masking
2274
+ "clipPathUnits",
2275
+ "maskUnits",
2276
+ "maskContentUnits",
2277
+ // Marker (SVG spec keeps these camelCase, like viewBox)
2278
+ "markerUnits",
2279
+ "markerWidth",
2280
+ "markerHeight",
2281
+ "refX",
2282
+ "refY",
2283
+ // Text
2284
+ "textLength",
2285
+ "lengthAdjust",
2286
+ "startOffset",
2287
+ // Filter
2288
+ "filterUnits",
2289
+ "primitiveUnits",
2290
+ "stdDeviation",
2291
+ "baseFrequency",
2292
+ "numOctaves",
2293
+ "surfaceScale",
2294
+ "diffuseConstant",
2295
+ "specularConstant",
2296
+ "specularExponent",
2297
+ "kernelMatrix",
2298
+ "kernelUnitLength",
2299
+ "edgeMode",
2300
+ "preserveAlpha",
2301
+ "targetX",
2302
+ "targetY"
2303
+ // // Animation
2304
+ // 'attributeName',
2305
+ // 'attributeType',
2306
+ // 'calcMode',
2307
+ // 'keyTimes',
2308
+ // 'keySplines',
2309
+ // 'repeatCount',
2310
+ // 'repeatDur'
2311
+ ]);
2312
+ function camelCaseToKebabWordIfNeeded(camel) {
2313
+ return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
2314
+ }
2315
+ function clamp(value, min, max) {
2316
+ return Math.max(min, Math.min(value, max));
2317
+ }
2318
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
2319
+ if (t <= 0) return [P0[0], P0[1]];
2320
+ if (t >= 1) return [P3[0], P3[1]];
2321
+ const u = 1 - t;
2322
+ const u2 = u * u;
2323
+ const u3 = u2 * u;
2324
+ const t2 = t * t;
2325
+ const t3 = t2 * t;
2326
+ const w0 = u3;
2327
+ const w1 = 3 * t * u2;
2328
+ const w2 = 3 * t2 * u;
2329
+ const w3 = t3;
2330
+ return [
2331
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
2332
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
2333
+ ];
2334
+ }
2335
+ var BEZIER_T_NUDGE = 1e-4;
2336
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
2337
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
2338
+ if (result[0] === 0 && result[1] === 0) {
2339
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
2340
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
2341
+ }
2342
+ return result;
2343
+ }
2344
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
2345
+ const u = 1 - t;
2346
+ const a = 3 * u * u;
2347
+ const b = 6 * t * u;
2348
+ const c = 3 * t * t;
2349
+ return [
2350
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
2351
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
2352
+ ];
2353
+ }
2354
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
2355
+ const n = steps + 1;
2356
+ const ts = new Float64Array(n);
2357
+ const ds = new Float64Array(n);
2358
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
2359
+ ts[0] = 0;
2360
+ ds[0] = 0;
2361
+ let cum = 0;
2362
+ for (let i = 1; i < n; i++) {
2363
+ const t = i / steps;
2364
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
2365
+ const dx = cur[0] - prev[0];
2366
+ const dy = cur[1] - prev[1];
2367
+ cum += Math.sqrt(dx * dx + dy * dy);
2368
+ ts[i] = t;
2369
+ ds[i] = cum;
2370
+ prev = cur;
2371
+ }
2372
+ return { ts, ds };
2373
+ }
2374
+ function bezier2D_arcAtT(lut, t) {
2375
+ const { ts, ds } = lut;
2376
+ const last = ts.length - 1;
2377
+ if (t <= ts[0]) return ds[0];
2378
+ if (t >= ts[last]) return ds[last];
2379
+ let lo = 1, hi = last;
2380
+ while (lo < hi) {
2381
+ const mid = lo + hi >>> 1;
2382
+ if (ts[mid] < t) lo = mid + 1;
2383
+ else hi = mid;
2384
+ }
2385
+ const tPrev = ts[hi - 1];
2386
+ const span = ts[hi] - tPrev;
2387
+ const frac = span > 0 ? (t - tPrev) / span : 0;
2388
+ return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
2389
+ }
2390
+ function invertEasing(easing) {
2391
+ if (!easing) return (y) => y;
2392
+ const flipped = [easing[1], easing[0], easing[3], easing[2]];
2393
+ return cubicBezier(flipped);
2394
+ }
2395
+
2396
+ // src/PxMotionPath.ts
2397
+ function getKfTranslate(kf) {
2398
+ var _a;
2399
+ const v = (_a = kf.value) != null ? _a : kf.v;
2400
+ if (!v) return void 0;
2401
+ if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
2402
+ return [v[0], v[1]];
2403
+ }
2404
+ const tr = v.translate;
2405
+ if (Array.isArray(tr) && tr.length >= 2) return [tr[0], tr[1]];
2406
+ return void 0;
2407
+ }
2408
+ function getKfTime(kf) {
2409
+ var _a, _b;
2410
+ return (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2411
+ }
2412
+ function getKfEasing(kf) {
2413
+ var _a;
2414
+ return (_a = kf.easing) != null ? _a : kf.e;
2415
+ }
2416
+ function propAnimIsMotionPath(anim) {
2417
+ var _a, _b, _c;
2418
+ const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
2419
+ if (!Array.isArray(kfs)) return false;
2420
+ if (anim.autoOrient) return true;
2421
+ for (const kf of kfs) {
2422
+ if (((_b = kf.tangentIn) != null ? _b : kf.ti) || ((_c = kf.tangentOut) != null ? _c : kf.to)) return true;
2423
+ }
2424
+ return false;
2425
+ }
2426
+ var _segmentCache = /* @__PURE__ */ new WeakMap();
2427
+ function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
2428
+ var _a, _b;
2429
+ const existing = _segmentCache.get(prevKf);
2430
+ if (existing) return existing;
2431
+ const to = (_a = prevKf.tangentOut) != null ? _a : prevKf.to;
2432
+ const ti = (_b = nextKf.tangentIn) != null ? _b : nextKf.ti;
2433
+ const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
2434
+ const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
2435
+ const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
2436
+ const entry = {
2437
+ P0: prevPos,
2438
+ P1,
2439
+ P2,
2440
+ P3: nextPos,
2441
+ lut,
2442
+ totalArc: lut.ds[lut.ds.length - 1]
2443
+ };
2444
+ _segmentCache.set(prevKf, entry);
2445
+ return entry;
2446
+ }
2447
+ function evaluateMotionPathSegment(prevKf, nextKf, prevPos, nextPos, localProgress, autoOrient) {
2448
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2449
+ const t = seg.totalArc === 0 ? localProgress : tFromArcFraction(seg.lut, localProgress);
2450
+ const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2451
+ if (!autoOrient) return { translate: point };
2452
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2453
+ const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2454
+ return { translate: point, rotateDeg };
2455
+ }
2456
+ function tFromArcFraction(lut, arcFrac) {
2457
+ const total = lut.ds[lut.ds.length - 1];
2458
+ const target = arcFrac * total;
2459
+ const { ts, ds } = lut;
2460
+ const last = ds.length - 1;
2461
+ if (target <= 0) return ts[0];
2462
+ if (target >= ds[last]) return ts[last];
2463
+ let lo = 1, hi = last;
2464
+ while (lo < hi) {
2465
+ const mid = lo + hi >>> 1;
2466
+ if (ds[mid] < target) lo = mid + 1;
2467
+ else hi = mid;
2468
+ }
2469
+ const dPrev = ds[hi - 1];
2470
+ const span = ds[hi] - dPrev;
2471
+ const frac = span > 0 ? (target - dPrev) / span : 0;
2472
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
2473
+ }
2474
+ var DEFAULT_FLATNESS_TOL = 0.5;
2475
+ var DEFAULT_ROTATION_TOL = 5;
2476
+ var DEFAULT_MAX_SAMPLES = 32;
2477
+ function materialiseMotionPathInPropAnim(anim, opts) {
2478
+ var _a, _b, _c, _d;
2479
+ if (!propAnimIsMotionPath(anim)) return anim;
2480
+ const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
2481
+ if (!Array.isArray(kfs) || kfs.length < 2) return anim;
2482
+ const autoOrient = !!anim.autoOrient;
2483
+ const flatnessTol = (_b = opts == null ? void 0 : opts.flatnessTolerance) != null ? _b : DEFAULT_FLATNESS_TOL;
2484
+ const rotationTol = (_c = opts == null ? void 0 : opts.rotationTolerance) != null ? _c : DEFAULT_ROTATION_TOL;
2485
+ const maxSamples = (_d = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _d : DEFAULT_MAX_SAMPLES;
2486
+ const out = [];
2487
+ const firstPos = getKfTranslate(kfs[0]);
2488
+ if (!firstPos) return anim;
2489
+ const firstRotate = autoOrient ? derivAngleForFirstKf(kfs[0], kfs[1]) : void 0;
2490
+ out.push(makeOutKf(
2491
+ getKfTime(kfs[0]),
2492
+ buildOutKfValue(getKfValueParts(kfs[0]), getKfValueParts(kfs[0]), 0, firstPos, firstRotate, autoOrient)
2493
+ ));
2494
+ for (let i = 0; i < kfs.length - 1; i++) {
2495
+ const prevKf = kfs[i];
2496
+ const nextKf = kfs[i + 1];
2497
+ const prevPos = getKfTranslate(prevKf);
2498
+ const nextPos = getKfTranslate(nextKf);
2499
+ if (!prevPos || !nextPos) {
2500
+ out.push(makeOutKf(
2501
+ getKfTime(nextKf),
2502
+ buildOutKfValue(getKfValueParts(nextKf), getKfValueParts(nextKf), 1, nextPos != null ? nextPos : [0, 0], void 0, autoOrient)
2503
+ ));
2504
+ continue;
2505
+ }
2506
+ if (autoOrient && i > 0) {
2507
+ insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
2508
+ }
2509
+ materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2510
+ }
2511
+ const lastInE = getKfEasing(kfs[kfs.length - 1]);
2512
+ if (lastInE) out[out.length - 1].e = lastInE;
2513
+ if (autoOrient) unwrapAutoOrientRotations(out);
2514
+ const result = { kfs: out };
2515
+ if (anim.loop !== void 0) result.loop = anim.loop;
2516
+ return result;
2517
+ }
2518
+ function unwrapAutoOrientRotations(kfs) {
2519
+ var _a;
2520
+ let prev;
2521
+ for (const kf of kfs) {
2522
+ const v = (_a = kf.v) != null ? _a : kf.value;
2523
+ if (!v || typeof v.rotate !== "number") continue;
2524
+ if (prev === void 0) {
2525
+ prev = v.rotate;
2526
+ continue;
2527
+ }
2528
+ let r = v.rotate;
2529
+ while (r - prev > 180) r -= 360;
2530
+ while (r - prev < -180) r += 360;
2531
+ v.rotate = r;
2532
+ prev = r;
2533
+ }
2534
+ }
2535
+ function makeOutKf(time, value) {
2536
+ return { t: time, v: value };
2537
+ }
2538
+ function getKfValueParts(kf) {
2539
+ var _a;
2540
+ const v = (_a = kf.value) != null ? _a : kf.v;
2541
+ if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
2542
+ return v;
2543
+ }
2544
+ function interpolatePart(prev, next, p) {
2545
+ if (prev === void 0) return next;
2546
+ if (next === void 0) return prev;
2547
+ if (typeof prev === "number" && typeof next === "number") {
2548
+ return prev + (next - prev) * p;
2549
+ }
2550
+ if (Array.isArray(prev) && Array.isArray(next) && prev.length === next.length) {
2551
+ const out = new Array(prev.length);
2552
+ for (let i = 0; i < prev.length; i++) {
2553
+ const a = typeof prev[i] === "number" ? prev[i] : 0;
2554
+ const b = typeof next[i] === "number" ? next[i] : 0;
2555
+ out[i] = a + (b - a) * p;
2556
+ }
2557
+ return out;
2558
+ }
2559
+ return p < 0.5 ? prev : next;
2560
+ }
2561
+ function buildOutKfValue(prevV, nextV, p, translate, rotateDegFromAutoOrient, autoOrient) {
2562
+ const value = { translate };
2563
+ const keys = /* @__PURE__ */ new Set();
2564
+ if (prevV) for (const k of Object.keys(prevV)) keys.add(k);
2565
+ if (nextV) for (const k of Object.keys(nextV)) keys.add(k);
2566
+ for (const k of keys) {
2567
+ if (k === "translate") continue;
2568
+ if (k === "rotate" && autoOrient) continue;
2569
+ const pv = prevV == null ? void 0 : prevV[k];
2570
+ const nv = nextV == null ? void 0 : nextV[k];
2571
+ if (pv === void 0 && nv === void 0) continue;
2572
+ value[k] = interpolatePart(pv, nv, p);
2573
+ }
2574
+ if (rotateDegFromAutoOrient !== void 0) value.rotate = rotateDegFromAutoOrient;
2575
+ return value;
2576
+ }
2577
+ function derivAngleForFirstKf(kf0, kf1) {
2578
+ const p0 = getKfTranslate(kf0);
2579
+ const p1 = getKfTranslate(kf1);
2580
+ if (!p0 || !p1) return 0;
2581
+ const seg = getSegmentCache(kf0, kf1, p0, p1);
2582
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
2583
+ return Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2584
+ }
2585
+ function wrappedAngleDelta(a, b) {
2586
+ let d = a - b;
2587
+ while (d > 180) d -= 360;
2588
+ while (d < -180) d += 360;
2589
+ return d;
2590
+ }
2591
+ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
2592
+ var _a;
2593
+ const lastKf = out[out.length - 1];
2594
+ const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
2595
+ const prevExit = lastV == null ? void 0 : lastV.rotate;
2596
+ if (typeof prevExit !== "number") return;
2597
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2598
+ const tanAtStart = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
2599
+ const nextEntry = Math.atan2(tanAtStart[1], tanAtStart[0]) * 180 / Math.PI;
2600
+ const delta = wrappedAngleDelta(nextEntry, prevExit);
2601
+ if (Math.abs(delta) <= rotationTol) return;
2602
+ const dupValue = buildOutKfValue(
2603
+ getKfValueParts(prevKf),
2604
+ getKfValueParts(prevKf),
2605
+ 0,
2606
+ prevPos,
2607
+ nextEntry,
2608
+ true
2609
+ );
2610
+ out.push(makeOutKf(getKfTime(prevKf), dupValue));
2611
+ }
2612
+ function materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2613
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2614
+ const prevTime = getKfTime(prevKf);
2615
+ const nextTime = getKfTime(nextKf);
2616
+ const prevEasing = getKfEasing(prevKf);
2617
+ const invertFn = invertEasing(prevEasing);
2618
+ const prevV = getKfValueParts(prevKf);
2619
+ const nextV = getKfValueParts(nextKf);
2620
+ const interiorTs = computeSampleTs(seg, autoOrient, flatnessTol, rotationTol, maxSamples);
2621
+ const samples = [];
2622
+ for (const t of interiorTs) {
2623
+ const arc = bezier2D_arcAtT(seg.lut, t);
2624
+ const p = clamp(seg.totalArc > 0 ? arc / seg.totalArc : t, 0, 1);
2625
+ const u = clamp(invertFn(p), 0, 1);
2626
+ const pos = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2627
+ const sample = { u, p, pos };
2628
+ if (autoOrient) {
2629
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2630
+ sample.rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2631
+ }
2632
+ samples.push(sample);
2633
+ }
2634
+ let remaining = prevEasing;
2635
+ let prevU = 0;
2636
+ const startIdx = out.length - 1;
2637
+ for (let i = 0; i < samples.length; i++) {
2638
+ const s = samples[i];
2639
+ const xFrac = prevU < 1 ? clamp((s.u - prevU) / (1 - prevU), 0, 1) : 1;
2640
+ const { left, right } = splitEasing(remaining, xFrac);
2641
+ const ownerIdx = i === 0 ? startIdx : out.length - 1;
2642
+ if (left) out[ownerIdx].e = left;
2643
+ else delete out[ownerIdx].e;
2644
+ const tGlobal = prevTime + s.u * (nextTime - prevTime);
2645
+ const value = buildOutKfValue(prevV, nextV, s.p, s.pos, s.rotateDeg, autoOrient);
2646
+ out.push(makeOutKf(tGlobal, value));
2647
+ remaining = right;
2648
+ prevU = s.u;
2649
+ }
2650
+ }
2651
+ function computeSampleTs(seg, autoOrient, flatnessTol, rotationTol, maxSamples) {
2652
+ const extremes = [];
2653
+ addAxisExtremes(seg.P0[0], seg.P1[0], seg.P2[0], seg.P3[0], extremes);
2654
+ addAxisExtremes(seg.P0[1], seg.P1[1], seg.P2[1], seg.P3[1], extremes);
2655
+ extremes.sort((a, b) => a - b);
2656
+ const critical = [0];
2657
+ for (const t of extremes) {
2658
+ if (t > critical[critical.length - 1] + 1e-6 && t < 1 - 1e-6) {
2659
+ critical.push(t);
2660
+ }
2661
+ }
2662
+ critical.push(1);
2663
+ const out = [];
2664
+ const budget = { remaining: maxSamples - critical.length };
2665
+ for (let i = 0; i < critical.length - 1; i++) {
2666
+ bisect(critical[i], critical[i + 1], out, seg, autoOrient, flatnessTol, rotationTol, budget);
2667
+ }
2668
+ return out;
2669
+ }
2670
+ function addAxisExtremes(p0, p1, p2, p3, out) {
2671
+ const a = p1 - p0;
2672
+ const b = p2 - p1;
2673
+ const c = p3 - p2;
2674
+ const A = a - 2 * b + c;
2675
+ const B = 2 * (b - a);
2676
+ const C = a;
2677
+ if (Math.abs(A) < 1e-10) {
2678
+ if (Math.abs(B) > 1e-10) {
2679
+ const t = -C / B;
2680
+ if (t > 1e-6 && t < 1 - 1e-6) out.push(t);
2681
+ }
2682
+ return;
2683
+ }
2684
+ const disc = B * B - 4 * A * C;
2685
+ if (disc < 0) return;
2686
+ const sq = Math.sqrt(disc);
2687
+ const t1 = (-B - sq) / (2 * A);
2688
+ const t2 = (-B + sq) / (2 * A);
2689
+ if (t1 > 1e-6 && t1 < 1 - 1e-6) out.push(t1);
2690
+ if (t2 > 1e-6 && t2 < 1 - 1e-6) out.push(t2);
2691
+ }
2692
+ function bisect(tA, tB, out, seg, autoOrient, flatnessTol, rotationTol, budget) {
2693
+ const tMid = (tA + tB) / 2;
2694
+ const pA = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);
2695
+ const pB = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);
2696
+ const span = tB - tA;
2697
+ const p25 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.25);
2698
+ const p50 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tMid);
2699
+ const p75 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.75);
2700
+ const dev = Math.max(
2701
+ perpDist(p25, pA, pB),
2702
+ perpDist(p50, pA, pB),
2703
+ perpDist(p75, pA, pB)
2704
+ );
2705
+ let rotOk = true;
2706
+ if (autoOrient) {
2707
+ const tanA = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);
2708
+ const tanB = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);
2709
+ const angA = Math.atan2(tanA[1], tanA[0]) * 180 / Math.PI;
2710
+ const angB = Math.atan2(tanB[1], tanB[0]) * 180 / Math.PI;
2711
+ let delta = Math.abs(angA - angB);
2712
+ if (delta > 180) delta = 360 - delta;
2713
+ if (delta > rotationTol) rotOk = false;
2714
+ }
2715
+ if (dev <= flatnessTol && rotOk || budget.remaining <= 0 || span < 1e-6) {
2716
+ out.push(tB);
2717
+ return;
2718
+ }
2719
+ budget.remaining -= 1;
2720
+ bisect(tA, tMid, out, seg, autoOrient, flatnessTol, rotationTol, budget);
2721
+ bisect(tMid, tB, out, seg, autoOrient, flatnessTol, rotationTol, budget);
2722
+ }
2723
+ function perpDist(q, pA, pB) {
2724
+ const dx = pB[0] - pA[0];
2725
+ const dy = pB[1] - pA[1];
2726
+ const len2 = dx * dx + dy * dy;
2727
+ if (len2 < 1e-20) {
2728
+ const qdx = q[0] - pA[0];
2729
+ const qdy = q[1] - pA[1];
2730
+ return Math.sqrt(qdx * qdx + qdy * qdy);
2731
+ }
2732
+ const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
2733
+ return Math.abs(cross) / Math.sqrt(len2);
2734
+ }
2735
+ function materialiseMotionPathsInTree(root, opts) {
2736
+ const out = walkAndMaterialise(root, opts);
2737
+ return out != null ? out : root;
2738
+ }
2739
+ function walkAndMaterialise(node, opts) {
2740
+ let newChildren;
2741
+ if (node.children) {
2742
+ for (let i = 0; i < node.children.length; i++) {
2743
+ const ch = node.children[i];
2744
+ const ret = walkAndMaterialise(ch, opts);
2745
+ if (ret !== null) {
2746
+ if (!newChildren) newChildren = node.children.slice();
2747
+ newChildren[i] = ret;
2748
+ }
2749
+ }
2750
+ }
2751
+ let newAnimate;
2752
+ const animBucket = node.animate;
2753
+ if (animBucket && typeof animBucket === "object" && !Array.isArray(animBucket)) {
2754
+ const animDef = animBucket;
2755
+ const transformAnim = animDef.transform;
2756
+ if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
2757
+ const materialised = materialiseMotionPathInPropAnim(transformAnim, opts);
2758
+ if (materialised !== transformAnim) {
2759
+ newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialised });
2760
+ }
2761
+ }
2762
+ }
2763
+ if (!newChildren && !newAnimate) return null;
2764
+ const cloned = __spreadValues({}, node);
2765
+ if (newChildren) cloned.children = newChildren;
2766
+ if (newAnimate) cloned.animate = newAnimate;
2767
+ return cloned;
2768
+ }
2769
+
2770
+ // src/PxDefinitions.ts
2771
+ function parsePathCommands(d) {
2772
+ const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
2773
+ const commands = [];
2774
+ let currentCommand = null;
2775
+ for (const token of tokens) {
2776
+ if (/[MLCZmlcz]/.test(token)) {
2777
+ currentCommand = { type: token, values: [] };
2778
+ commands.push(currentCommand);
2779
+ } else if (currentCommand) {
2780
+ const value = +token;
2781
+ currentCommand.values.push(Number.isNaN(value) ? 0 : value);
2782
+ }
2783
+ }
2784
+ return commands;
2785
+ }
2786
+ function parseSvgPathToBezier(d) {
2787
+ const res = [];
2788
+ let currentPath;
2789
+ const commands = parsePathCommands(d);
2790
+ for (const command of commands) {
2791
+ const type = command.type;
2792
+ const values = command.values;
2793
+ if (type === "M" || type === "m") {
2794
+ const x = values[0] || 0;
2795
+ const y = values[1] || 0;
2796
+ currentPath = {
2192
2797
  v: [[x, y]],
2193
2798
  i: [[x, y]],
2194
2799
  o: [[x, y]],
@@ -2197,471 +2802,1296 @@ function parseSvgPathToBezier(d) {
2197
2802
  res.push(currentPath);
2198
2803
  continue;
2199
2804
  }
2200
- if (!currentPath) {
2201
- currentPath = {
2202
- v: [[0, 0]],
2203
- i: [[0, 0]],
2204
- o: [[0, 0]],
2205
- c: false
2206
- };
2207
- res.push(currentPath);
2805
+ if (!currentPath) {
2806
+ currentPath = {
2807
+ v: [[0, 0]],
2808
+ i: [[0, 0]],
2809
+ o: [[0, 0]],
2810
+ c: false
2811
+ };
2812
+ res.push(currentPath);
2813
+ }
2814
+ if (type === "L") {
2815
+ const x = values[0] || 0;
2816
+ const y = values[1] || 0;
2817
+ currentPath.v.push([x, y]);
2818
+ currentPath.i.push([x, y]);
2819
+ currentPath.o.push([x, y]);
2820
+ } else if (type === "C") {
2821
+ const outX = values[0] || 0;
2822
+ const outY = values[1] || 0;
2823
+ const inX2 = values[2] || 0;
2824
+ const inY2 = values[3] || 0;
2825
+ const x2 = values[4] || 0;
2826
+ const y2 = values[5] || 0;
2827
+ currentPath.o[currentPath.o.length - 1] = [outX, outY];
2828
+ currentPath.v.push([x2, y2]);
2829
+ currentPath.i.push([inX2, inY2]);
2830
+ currentPath.o.push([x2, y2]);
2831
+ } else if (type === "Z" || type === "z") {
2832
+ currentPath.c = true;
2833
+ } else {
2834
+ console.warn('Unsupported path command "' + type + '"');
2835
+ }
2836
+ }
2837
+ return res;
2838
+ }
2839
+ function extractPathData(str) {
2840
+ if (str.startsWith("path(") && str.endsWith(")")) {
2841
+ return str.slice(5, -1);
2842
+ }
2843
+ if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str)) {
2844
+ return str;
2845
+ }
2846
+ return void 0;
2847
+ }
2848
+ function isPathString(value) {
2849
+ return typeof value === "string" && extractPathData(value) !== void 0;
2850
+ }
2851
+ function normalizePathValue(value) {
2852
+ if (value && typeof value === "object" && typeof value.path === "string") {
2853
+ const d = extractPathData(value.path);
2854
+ return d ? { paths: parseSvgPathToBezier(d) } : value;
2855
+ }
2856
+ if (value && typeof value === "object" && "paths" in value) {
2857
+ const pathsArray = value.paths;
2858
+ if (Array.isArray(pathsArray) && pathsArray.length > 0) {
2859
+ if (isPathString(pathsArray[0])) {
2860
+ const paths = [];
2861
+ for (const pathStr2 of pathsArray) {
2862
+ const d = extractPathData(pathStr2);
2863
+ if (d) {
2864
+ paths.push(...parseSvgPathToBezier(d));
2865
+ }
2866
+ }
2867
+ return { paths };
2868
+ }
2869
+ }
2870
+ return value;
2871
+ }
2872
+ if (Array.isArray(value)) {
2873
+ if (value.length > 0 && isPathString(value[0])) {
2874
+ const paths = [];
2875
+ for (const pathStr2 of value) {
2876
+ const d = extractPathData(pathStr2);
2877
+ if (d) {
2878
+ paths.push(...parseSvgPathToBezier(d));
2879
+ }
2880
+ }
2881
+ return { paths };
2882
+ }
2883
+ return { paths: value };
2884
+ }
2885
+ if (isPathString(value)) {
2886
+ const d = extractPathData(value);
2887
+ return { paths: parseSvgPathToBezier(d) };
2888
+ }
2889
+ return value;
2890
+ }
2891
+ function resolveEasing(easing, defs) {
2892
+ var _a;
2893
+ if (!easing) return void 0;
2894
+ if (Array.isArray(easing)) {
2895
+ return easing;
2896
+ }
2897
+ if ((_a = defs == null ? void 0 : defs.easings) == null ? void 0 : _a[easing]) {
2898
+ return defs.easings[easing];
2899
+ }
2900
+ console.warn("Unknown easing name: " + easing);
2901
+ return void 0;
2902
+ }
2903
+ function resolveAnimation(animRef, defs) {
2904
+ var _a;
2905
+ if (typeof animRef === "string") {
2906
+ const resolved = (_a = defs == null ? void 0 : defs.animations) == null ? void 0 : _a[animRef];
2907
+ if (!resolved) {
2908
+ console.warn("Unknown animation name: " + animRef);
2909
+ }
2910
+ return resolved;
2911
+ }
2912
+ return animRef;
2913
+ }
2914
+ function resolveElementAnimation(animate, defs) {
2915
+ if (!animate) return [];
2916
+ const results = [];
2917
+ if (typeof animate === "string") {
2918
+ const resolved = resolveAnimation(animate, defs);
2919
+ if (resolved) results.push(resolved);
2920
+ } else if (Array.isArray(animate)) {
2921
+ for (const item of animate) {
2922
+ const resolved = resolveAnimation(item, defs);
2923
+ if (resolved) results.push(resolved);
2208
2924
  }
2209
- if (type === "L") {
2210
- const x = values[0] || 0;
2211
- const y = values[1] || 0;
2212
- currentPath.v.push([x, y]);
2213
- currentPath.i.push([x, y]);
2214
- currentPath.o.push([x, y]);
2215
- } else if (type === "C") {
2216
- const outX = values[0] || 0;
2217
- const outY = values[1] || 0;
2218
- const inX2 = values[2] || 0;
2219
- const inY2 = values[3] || 0;
2220
- const x2 = values[4] || 0;
2221
- const y2 = values[5] || 0;
2222
- currentPath.o[currentPath.o.length - 1] = [outX, outY];
2223
- currentPath.v.push([x2, y2]);
2224
- currentPath.i.push([inX2, inY2]);
2225
- currentPath.o.push([x2, y2]);
2226
- } else if (type === "Z" || type === "z") {
2227
- currentPath.c = true;
2925
+ } else {
2926
+ results.push(animate);
2927
+ }
2928
+ return results;
2929
+ }
2930
+ function interpolateValue(propName, a, b, t) {
2931
+ var _a, _b;
2932
+ if (propName === "d") {
2933
+ const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
2934
+ const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2935
+ return { paths: interpolateBeziers(aPaths, bPaths, t) };
2936
+ }
2937
+ if (COLOUR_ATTR_NAMES.has(propName)) {
2938
+ return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
2939
+ }
2940
+ if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
2941
+ return interpolateTransformParts(a, b, t);
2942
+ }
2943
+ if (propName === "rotate" && typeof a === "number" && typeof b === "number") {
2944
+ return interpolateNum(a, b, t);
2945
+ }
2946
+ if (TRANSFORM_FN_NAMES.has(propName) || propName === "stroke-dasharray" || propName === "strokeDasharray") {
2947
+ return interpolateVec(a || [], b || [], t);
2948
+ }
2949
+ return interpolateNum(+(a || 0), +(b || 0), t);
2950
+ }
2951
+ function interpolateTransformParts(a, b, t) {
2952
+ const keys = /* @__PURE__ */ new Set([...Object.keys(a != null ? a : {}), ...Object.keys(b != null ? b : {})]);
2953
+ const out = {};
2954
+ for (const k of keys) {
2955
+ const av = a == null ? void 0 : a[k];
2956
+ const bv = b == null ? void 0 : b[k];
2957
+ if (k === "rotate") {
2958
+ out[k] = interpolateNum(+(av != null ? av : 0), +(bv != null ? bv : 0), t);
2959
+ } else if (k === "translate" || k === "scale" || k === "origin") {
2960
+ const fallback = k === "scale" ? [1, 1] : [0, 0];
2961
+ out[k] = interpolateVec(av || fallback, bv || fallback, t);
2228
2962
  } else {
2229
- console.warn('Unsupported path command "' + type + '"');
2963
+ out[k] = bv != null ? bv : av;
2964
+ }
2965
+ }
2966
+ return out;
2967
+ }
2968
+ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2969
+ var _a, _b, _c, _d, _e;
2970
+ const totalIntervals = keyframes.length - 1;
2971
+ const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2972
+ let segKfs;
2973
+ if (loop.before) {
2974
+ segKfs = keyframes.slice(0, segCount + 1);
2975
+ } else {
2976
+ segKfs = keyframes.slice(totalIntervals - segCount);
2977
+ }
2978
+ const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2979
+ const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2980
+ let fillStart, fillEnd;
2981
+ if (loop.before) {
2982
+ fillStart = 0;
2983
+ fillEnd = firstT;
2984
+ } else {
2985
+ fillStart = lastT;
2986
+ fillEnd = duration;
2987
+ }
2988
+ const fillDuration = fillEnd - fillStart;
2989
+ if (fillDuration <= 0) return keyframes;
2990
+ const segStartT = (_d = segKfs[0].t) != null ? _d : 0;
2991
+ const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
2992
+ const segDuration = segEndT - segStartT;
2993
+ if (segDuration <= 0) return keyframes;
2994
+ const template = segKfs.map((kf) => {
2995
+ var _a2, _b2;
2996
+ return {
2997
+ relT: (kf.t - segStartT) / segDuration,
2998
+ v: kf.v,
2999
+ e: kf.e,
3000
+ tangentIn: (_a2 = kf.tangentIn) != null ? _a2 : kf.ti,
3001
+ tangentOut: (_b2 = kf.tangentOut) != null ? _b2 : kf.to
3002
+ };
3003
+ });
3004
+ const fullReps = Math.floor(fillDuration / segDuration);
3005
+ const remainder = fillDuration - fullReps * segDuration;
3006
+ const partialFraction = remainder / segDuration;
3007
+ const looped = [];
3008
+ function appendRep(repStart, isReversed, partial) {
3009
+ let entries;
3010
+ if (isReversed) {
3011
+ entries = [];
3012
+ for (let i = template.length - 1; i >= 0; i--) {
3013
+ entries.push({
3014
+ relT: 1 - template[i].relT,
3015
+ v: template[i].v,
3016
+ // Easing for reversed transition: use reversed easing from the forward "from" keyframe
3017
+ e: i > 0 ? reverseEasing(template[i - 1].e) : void 0,
3018
+ // Reversed traversal swaps each vertex's in/out spatial tangents
3019
+ // (geometry is identical, walked backwards), so curvature and
3020
+ // auto-orientation survive the reversed rep.
3021
+ tangentIn: template[i].tangentOut,
3022
+ tangentOut: template[i].tangentIn
3023
+ });
3024
+ }
3025
+ } else {
3026
+ entries = template;
3027
+ }
3028
+ const cutRelT = partial !== void 0 ? partial : 1;
3029
+ for (let i = 0; i < entries.length; i++) {
3030
+ const entry = entries[i];
3031
+ if (entry.relT > cutRelT + 1e-9) {
3032
+ const prev = entries[i - 1];
3033
+ const intervalSpan = entry.relT - prev.relT;
3034
+ const localFrac = (cutRelT - prev.relT) / intervalSpan;
3035
+ const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
3036
+ const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
3037
+ const { left: leftEasing } = splitEasing(prev.e, localFrac);
3038
+ if (looped.length > 0 && prev.relT <= cutRelT) {
3039
+ looped[looped.length - 1].e = leftEasing;
3040
+ }
3041
+ looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
3042
+ return;
3043
+ }
3044
+ const pushed = {
3045
+ t: repStart + entry.relT * segDuration,
3046
+ v: entry.v,
3047
+ e: i < entries.length - 1 ? entry.e : void 0
3048
+ };
3049
+ if (entry.tangentIn) pushed.tangentIn = entry.tangentIn;
3050
+ if (entry.tangentOut) pushed.tangentOut = entry.tangentOut;
3051
+ looped.push(pushed);
3052
+ }
3053
+ }
3054
+ for (let rep = 0; rep < fullReps; rep++) {
3055
+ const distFromBoundary = loop.before ? fullReps - 1 - rep : rep;
3056
+ const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
3057
+ const repStart = fillStart + rep * segDuration;
3058
+ appendRep(repStart, isReversed);
3059
+ }
3060
+ if (partialFraction > 1e-9) {
3061
+ const isReversed = !!loop.alternate && fullReps % 2 === 0;
3062
+ const repStart = fillStart + fullReps * segDuration;
3063
+ appendRep(repStart, isReversed, partialFraction);
3064
+ }
3065
+ if (loop.before) {
3066
+ return [...looped, ...keyframes];
3067
+ } else {
3068
+ return [...keyframes, ...looped];
3069
+ }
3070
+ }
3071
+ function normalizeKeyframes(propName, propAnim, duration, defs) {
3072
+ var _a, _b, _c, _d, _e, _f, _g;
3073
+ const keyframes = propAnim.keyframes || propAnim.kfs || [];
3074
+ const normalized = [];
3075
+ for (const kf of keyframes) {
3076
+ const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
3077
+ let value = (_c = kf.value) != null ? _c : kf.v;
3078
+ const easing = (_d = kf.easing) != null ? _d : kf.e;
3079
+ if (propName === "d") {
3080
+ value = normalizePathValue(value);
3081
+ }
3082
+ const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3083
+ if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
3084
+ value = (_e = parseColor(value)) != null ? _e : value;
3085
+ }
3086
+ const normKf = {
3087
+ t: timePct,
3088
+ v: value,
3089
+ e: resolveEasing(easing, defs)
3090
+ };
3091
+ const tIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
3092
+ const tOut = (_g = kf.tangentOut) != null ? _g : kf.to;
3093
+ if (tIn) normKf.tangentIn = tIn;
3094
+ if (tOut) normKf.tangentOut = tOut;
3095
+ normalized.push(normKf);
3096
+ }
3097
+ normalized.sort((a, b) => {
3098
+ var _a2, _b2;
3099
+ return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
3100
+ });
3101
+ const loopRaw = propAnim.loop;
3102
+ const loop = loopRaw === true ? {} : loopRaw || void 0;
3103
+ if (loop && normalized.length >= 2) {
3104
+ return expandLoopKeyframes(propName, normalized, loop, duration);
3105
+ }
3106
+ return normalized;
3107
+ }
3108
+ function mergeAnimationDefinitions(animations) {
3109
+ const merged = {};
3110
+ for (const anim of animations) {
3111
+ for (const [prop, propAnim] of Object.entries(anim)) {
3112
+ merged[prop] = propAnim;
3113
+ }
3114
+ }
3115
+ return merged;
3116
+ }
3117
+ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
3118
+ var _a;
3119
+ const loopRaw = propAnim.loop;
3120
+ if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
3121
+ const loop = loopRaw === true ? {} : loopRaw;
3122
+ const rawKfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
3123
+ if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
3124
+ const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3125
+ const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
3126
+ const kfs = rawKfs.map((kf) => {
3127
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
3128
+ const t = (_a2 = kf.t) != null ? _a2 : kf.time;
3129
+ let v = (_b = kf.v) != null ? _b : kf.value;
3130
+ if (propName === "d") v = normalizePathValue(v);
3131
+ if (isColour) v = (_c = parseColor(v)) != null ? _c : v;
3132
+ const e = (_d = kf.e) != null ? _d : kf.easing;
3133
+ const out2 = { t, v, e };
3134
+ if ((_e = kf.tangentIn) != null ? _e : kf.ti) out2.tangentIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
3135
+ if ((_g = kf.tangentOut) != null ? _g : kf.to) out2.tangentOut = (_h = kf.tangentOut) != null ? _h : kf.to;
3136
+ return out2;
3137
+ });
3138
+ const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
3139
+ const out = { kfs: expanded };
3140
+ if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3141
+ return out;
3142
+ }
3143
+ function materialiseInternalLoopsInTree(root, duration) {
3144
+ const ret = walkAndMaterialiseLoops(root, duration);
3145
+ return ret != null ? ret : root;
3146
+ }
3147
+ function walkAndMaterialiseLoops(node, duration) {
3148
+ let newChildren;
3149
+ if (node.children) {
3150
+ for (let i = 0; i < node.children.length; i++) {
3151
+ const ret = walkAndMaterialiseLoops(node.children[i], duration);
3152
+ if (ret !== null) {
3153
+ if (!newChildren) newChildren = node.children.slice();
3154
+ newChildren[i] = ret;
3155
+ }
3156
+ }
3157
+ }
3158
+ let newAnimate;
3159
+ const animBucket = node.animate;
3160
+ if (animBucket && typeof animBucket === "object" && !Array.isArray(animBucket)) {
3161
+ const animDef = animBucket;
3162
+ for (const propName of Object.keys(animDef)) {
3163
+ const propAnim = animDef[propName];
3164
+ const materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);
3165
+ if (materialised !== propAnim) {
3166
+ if (!newAnimate) newAnimate = __spreadValues({}, animDef);
3167
+ newAnimate[propName] = materialised;
3168
+ }
3169
+ }
3170
+ }
3171
+ if (!newChildren && !newAnimate) return null;
3172
+ const cloned = __spreadValues({}, node);
3173
+ if (newChildren) cloned.children = newChildren;
3174
+ if (newAnimate) cloned.animate = newAnimate;
3175
+ return cloned;
3176
+ }
3177
+ var _elementIdCounter = 0;
3178
+ function generateElementId() {
3179
+ return "_px_el_" + ++_elementIdCounter;
3180
+ }
3181
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.webapi) {
3182
+ const normalized = {};
3183
+ for (const [propName, propAnim] of Object.entries(animDef)) {
3184
+ const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
3185
+ if (normalizedKfs.length > 0) {
3186
+ const out = { kfs: normalizedKfs };
3187
+ if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3188
+ if (propAnim.loop !== void 0) out.loop = propAnim.loop;
3189
+ normalized[propName] = engine === PxAnimatorEngine.webapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
3190
+ }
3191
+ }
3192
+ return normalized;
3193
+ }
3194
+ function getNormalisedBindings(doc, engine = PxAnimatorEngine.webapi) {
3195
+ const animatorConfig = getAnimatorConfig(doc) || {};
3196
+ const defs = getDefs(doc);
3197
+ const duration = animatorConfig.duration || 1e3;
3198
+ const bindings = [];
3199
+ const processAnimation = (id, animate) => {
3200
+ if (!animate) return null;
3201
+ const animDefs = resolveElementAnimation(animate, defs);
3202
+ if (animDefs.length === 0) return null;
3203
+ const merged = mergeAnimationDefinitions(animDefs);
3204
+ const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
3205
+ if (Object.keys(normalizedAnim).length === 0) return null;
3206
+ return {
3207
+ id,
3208
+ animate: normalizedAnim
3209
+ };
3210
+ };
3211
+ const docBindings = getBindings(doc);
3212
+ if (docBindings) {
3213
+ for (const binding of docBindings) {
3214
+ const normalized = processAnimation(binding.id, binding.animate);
3215
+ if (normalized) bindings.push(normalized);
3216
+ }
3217
+ }
3218
+ const processNode = (node) => {
3219
+ const inlineAnim = node.animate;
3220
+ if (inlineAnim && Object.keys(inlineAnim).length > 0) {
3221
+ const nodeId = node.id || generateElementId();
3222
+ node.id = nodeId;
3223
+ const normalized = processAnimation(nodeId, inlineAnim);
3224
+ if (normalized) bindings.push(normalized);
3225
+ }
3226
+ if (node.children) {
3227
+ for (let i = 0; i < node.children.length; i++) {
3228
+ processNode(node.children[i]);
3229
+ }
3230
+ }
3231
+ };
3232
+ if (doc.children) {
3233
+ for (let i = 0; i < doc.children.length; i++) {
3234
+ processNode(doc.children[i]);
2230
3235
  }
2231
3236
  }
2232
- return res;
3237
+ return bindings;
2233
3238
  }
2234
- function extractPathData(str) {
2235
- if (str.startsWith("path(") && str.endsWith(")")) {
2236
- return str.slice(5, -1);
2237
- }
2238
- if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str)) {
2239
- return str;
3239
+ function getKeyframesPair(keyframes, progress) {
3240
+ var _a, _b;
3241
+ let prevKf = keyframes[0];
3242
+ let nextKf = keyframes[keyframes.length - 1];
3243
+ for (let j = 0; j < keyframes.length - 1; j++) {
3244
+ const aOff = (_a = keyframes[j].t) != null ? _a : 0;
3245
+ const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
3246
+ if (aOff <= progress && progress <= bOff) {
3247
+ prevKf = keyframes[j];
3248
+ nextKf = keyframes[j + 1];
3249
+ break;
3250
+ }
2240
3251
  }
2241
- return void 0;
2242
- }
2243
- function isPathString(value) {
2244
- return typeof value === "string" && extractPathData(value) !== void 0;
3252
+ return { prevKf, nextKf };
2245
3253
  }
2246
- function normalizePathValue(value) {
2247
- if (value && typeof value === "object" && typeof value.path === "string") {
2248
- const d = extractPathData(value.path);
2249
- return d ? { paths: parseSvgPathToBezier(d) } : value;
3254
+ function calcPropertyValue(propName, propAnim, progress) {
3255
+ var _a, _b, _c, _d, _e, _f, _g;
3256
+ const keyframes = propAnim.kfs || propAnim.keyframes || [];
3257
+ if (keyframes.length === 0) return null;
3258
+ const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
3259
+ let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
3260
+ localProgress = clamp(localProgress, 0, 1);
3261
+ const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
3262
+ if (easing && Array.isArray(easing)) {
3263
+ try {
3264
+ localProgress = cubicBezier(easing)(localProgress);
3265
+ } catch (e) {
3266
+ }
2250
3267
  }
2251
- if (value && typeof value === "object" && "paths" in value) {
2252
- const pathsArray = value.paths;
2253
- if (Array.isArray(pathsArray) && pathsArray.length > 0) {
2254
- if (isPathString(pathsArray[0])) {
2255
- const paths = [];
2256
- for (const pathStr2 of pathsArray) {
2257
- const d = extractPathData(pathStr2);
2258
- if (d) {
2259
- paths.push(...parseSvgPathToBezier(d));
2260
- }
2261
- }
2262
- return { paths };
3268
+ let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3269
+ let cssValue = null;
3270
+ const prevV = (_d = prevKf == null ? void 0 : prevKf.v) != null ? _d : prevKf == null ? void 0 : prevKf.value;
3271
+ const nextV = (_e = nextKf == null ? void 0 : nextKf.v) != null ? _e : nextKf == null ? void 0 : nextKf.value;
3272
+ if (cssAttrName === "d") {
3273
+ const prevPaths = (_f = prevV == null ? void 0 : prevV.paths) != null ? _f : Array.isArray(prevV) ? prevV : [];
3274
+ const nextPaths = (_g = nextV == null ? void 0 : nextV.paths) != null ? _g : Array.isArray(nextV) ? nextV : [];
3275
+ cssValue = interpolateBeziers(
3276
+ prevPaths,
3277
+ nextPaths,
3278
+ localProgress
3279
+ ).map((bz) => bezierToSvgPath(bz)).join("");
3280
+ } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
3281
+ cssValue = toRGBA(interpolateColor(
3282
+ prevV || [0, 0, 0, 1],
3283
+ nextV || [0, 0, 0, 1],
3284
+ localProgress
3285
+ ));
3286
+ cssAttrName = propName;
3287
+ } else if (cssAttrName === "stroke-dasharray") {
3288
+ cssValue = interpolateVec(
3289
+ prevV || [],
3290
+ nextV || [],
3291
+ localProgress
3292
+ ).join(" ");
3293
+ cssAttrName = propName;
3294
+ } else if (cssAttrName === "transform" && prevV !== null && typeof prevV === "object" && !Array.isArray(prevV)) {
3295
+ const partKeys = /* @__PURE__ */ new Set([
3296
+ ...prevV ? Object.keys(prevV) : [],
3297
+ ...nextV ? Object.keys(nextV) : []
3298
+ ]);
3299
+ const partsResult = {};
3300
+ for (const partKey of partKeys) {
3301
+ const prevPart = prevV == null ? void 0 : prevV[partKey];
3302
+ const nextPart = nextV == null ? void 0 : nextV[partKey];
3303
+ if (partKey === "rotate") {
3304
+ partsResult.rotate = interpolateNum(+(prevPart != null ? prevPart : 0), +(nextPart != null ? nextPart : 0), localProgress);
3305
+ } else if (partKey === "translate" || partKey === "scale" || partKey === "origin") {
3306
+ const fallback = partKey === "scale" ? [1, 1] : [0, 0];
3307
+ const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);
3308
+ partsResult[partKey] = interp;
2263
3309
  }
2264
3310
  }
2265
- return value;
2266
- }
2267
- if (Array.isArray(value)) {
2268
- if (value.length > 0 && isPathString(value[0])) {
2269
- const paths = [];
2270
- for (const pathStr2 of value) {
2271
- const d = extractPathData(pathStr2);
2272
- if (d) {
2273
- paths.push(...parseSvgPathToBezier(d));
2274
- }
3311
+ if (propAnimIsMotionPath(propAnim)) {
3312
+ const prevTr = prevV.translate;
3313
+ const nextTr = nextV.translate;
3314
+ if (Array.isArray(prevTr) && Array.isArray(nextTr)) {
3315
+ const sample = evaluateMotionPathSegment(
3316
+ prevKf,
3317
+ nextKf,
3318
+ [+prevTr[0], +prevTr[1]],
3319
+ [+nextTr[0], +nextTr[1]],
3320
+ localProgress,
3321
+ !!propAnim.autoOrient
3322
+ );
3323
+ partsResult.translate = [sample.translate[0], sample.translate[1]];
3324
+ if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
2275
3325
  }
2276
- return { paths };
2277
3326
  }
2278
- return { paths: value };
3327
+ cssValue = composeTransformParts(partsResult, { withUnits: false });
3328
+ cssAttrName = "transform";
3329
+ } else if (cssAttrName === "translate") {
3330
+ const v = interpolateVec(
3331
+ prevV || [0, 0],
3332
+ nextV || [0, 0],
3333
+ localProgress
3334
+ );
3335
+ cssValue = "translate(" + v.join(",") + ")";
3336
+ cssAttrName = "transform";
3337
+ } else if (cssAttrName === "rotate") {
3338
+ const v = interpolateNum(
3339
+ +(prevV || 0),
3340
+ +(nextV || 0),
3341
+ localProgress
3342
+ );
3343
+ cssValue = "rotate(" + v + ")";
3344
+ cssAttrName = "transform";
3345
+ } else if (cssAttrName === "scale") {
3346
+ const v = interpolateVec(
3347
+ prevV || [1, 1],
3348
+ nextV || [1, 1],
3349
+ localProgress
3350
+ );
3351
+ cssValue = "scale(" + v.join(",") + ")";
3352
+ cssAttrName = "transform";
3353
+ } else {
3354
+ const num2 = interpolateNum(
3355
+ +(prevV || 0),
3356
+ +(nextV || 0),
3357
+ localProgress
3358
+ );
3359
+ cssValue = num2;
2279
3360
  }
2280
- if (isPathString(value)) {
2281
- const d = extractPathData(value);
2282
- return { paths: parseSvgPathToBezier(d) };
3361
+ if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
3362
+ cssValue = cssValue * 100 + "%";
2283
3363
  }
2284
- return value;
3364
+ return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
2285
3365
  }
2286
- function resolveEasing(easing, defs) {
2287
- var _a;
2288
- if (!easing) return void 0;
2289
- if (Array.isArray(easing)) {
2290
- return easing;
2291
- }
2292
- if ((_a = defs == null ? void 0 : defs.easings) == null ? void 0 : _a[easing]) {
2293
- return defs.easings[easing];
3366
+ function calcAnimationValues(animDef, progress) {
3367
+ const result = {};
3368
+ for (const [propName, propAnim] of Object.entries(animDef)) {
3369
+ const computed = calcPropertyValue(propName, propAnim, progress);
3370
+ if (computed) {
3371
+ result[computed.k] = computed.v;
3372
+ }
2294
3373
  }
2295
- console.warn("Unknown easing name: " + easing);
2296
- return void 0;
3374
+ return result;
2297
3375
  }
2298
- function resolveAnimation(animRef, defs) {
2299
- var _a;
2300
- if (typeof animRef === "string") {
2301
- const resolved = (_a = defs == null ? void 0 : defs.animations) == null ? void 0 : _a[animRef];
2302
- if (!resolved) {
2303
- console.warn("Unknown animation name: " + animRef);
3376
+
3377
+ // src/effects/trimPathEffect.ts
3378
+ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
3379
+ if (!trimPath) return node;
3380
+ const trimAllAsOne = !!trimPath.trimAllAsOne;
3381
+ const leafEntries = [];
3382
+ let acc = 0;
3383
+ const measure = (n) => {
3384
+ if (Array.isArray(n.children) && n.children.length > 0) {
3385
+ for (const ch of n.children) measure(ch);
3386
+ return;
2304
3387
  }
2305
- return resolved;
3388
+ const d = typeof n.d === "string" ? n.d : rectToPathD(n);
3389
+ if (d === void 0) return;
3390
+ const subpaths = parseSvgPathToBezier(d);
3391
+ if (!subpaths.length) return;
3392
+ const entry = { leaf: n, subpaths: [] };
3393
+ for (const sp of subpaths) {
3394
+ if (!trimAllAsOne) acc = 0;
3395
+ const lengthPx = pxBezierPathLength(sp);
3396
+ entry.subpaths.push({ subpath: sp, lengthPx, startOffsetPx: acc });
3397
+ acc += lengthPx;
3398
+ }
3399
+ leafEntries.push(entry);
3400
+ };
3401
+ measure(node);
3402
+ if (!leafEntries.length) return node;
3403
+ const chainLengthPx = acc;
3404
+ if (trimAllAsOne && chainLengthPx < 1e-3) return node;
3405
+ const offsetReadRaw = readAnimatable(trimPath.offset);
3406
+ const offsetRead = offsetReadRaw.kind === "absent" /* Absent */ ? { kind: "static" /* Static */, value: 0 } : offsetReadRaw;
3407
+ const rangeReadRaw = readRangeWithCrossings(trimPath.range);
3408
+ const rangeRead = rangeReadRaw.kind === "absent" /* Absent */ ? { kind: "static" /* Static */, value: [0, 1] } : rangeReadRaw;
3409
+ const offsetValues = readScalarValues(offsetRead);
3410
+ const minOffset = offsetValues.length ? Math.min(...offsetValues) : 0;
3411
+ const maxOffset = offsetValues.length ? Math.max(...offsetValues) : 0;
3412
+ const minMaxOffset = [minOffset, maxOffset];
3413
+ if (leafEntries.length === 1 && leafEntries[0].leaf === node && leafEntries[0].subpaths.length === 1) {
3414
+ const entry = leafEntries[0];
3415
+ const sp = entry.subpaths[0];
3416
+ const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
3417
+ if (pathLengthPx < 1e-3) return node;
3418
+ const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
3419
+ return collapseLeafWithTrim(entry.leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead);
3420
+ }
3421
+ const replacements = /* @__PURE__ */ new Map();
3422
+ for (const entry of leafEntries) {
3423
+ const newChildren = [];
3424
+ for (const sp of entry.subpaths) {
3425
+ const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
3426
+ if (pathLengthPx < 1e-3) continue;
3427
+ const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
3428
+ newChildren.push(...buildSubpathNodes(entry.leaf, sp.subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx));
3429
+ }
3430
+ replacements.set(entry.leaf, wrapLeafAsGroup(entry.leaf, newChildren));
2306
3431
  }
2307
- return animRef;
3432
+ const swap = (n) => {
3433
+ const r = replacements.get(n);
3434
+ if (r) return r;
3435
+ if (Array.isArray(n.children) && n.children.length > 0) {
3436
+ return __spreadProps(__spreadValues({}, n), { children: n.children.map(swap) });
3437
+ }
3438
+ return n;
3439
+ };
3440
+ return swap(node);
3441
+ }
3442
+ function wrapLeafAsGroup(leaf, children) {
3443
+ const wrapper = __spreadProps(__spreadValues({}, leaf), { type: "g", children });
3444
+ delete wrapper.d;
3445
+ delete wrapper.strokeDasharray;
3446
+ delete wrapper.strokeDashoffset;
3447
+ delete wrapper.effects;
3448
+ return wrapper;
2308
3449
  }
2309
- function resolveElementAnimation(animate, defs) {
2310
- if (!animate) return [];
2311
- const results = [];
2312
- if (typeof animate === "string") {
2313
- const resolved = resolveAnimation(animate, defs);
2314
- if (resolved) results.push(resolved);
2315
- } else if (Array.isArray(animate)) {
2316
- for (const item of animate) {
2317
- const resolved = resolveAnimation(item, defs);
2318
- if (resolved) results.push(resolved);
3450
+ function buildSubpathNodes(leaf, subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx) {
3451
+ const offsetToDashOffset = makeOffsetToDashOffset(startOffsetPct, pathLengthPx, minMaxOffset);
3452
+ const rangeToDasharray = makeRangeToDasharray(pathLengthPx, minMaxOffset);
3453
+ const dashOffsetAttr = computeAnimAttr(offsetRead, offsetToDashOffset);
3454
+ const dashArrayAttr = computeAnimAttr(rangeRead, rangeToDasharray);
3455
+ const strokeOpacityAttr = computeOpacityFromRange(rangeRead);
3456
+ const dStr = bezierToSvgPath(subpath);
3457
+ const base = makeBareSubpath(dStr);
3458
+ applyAttr(base, "strokeDasharray", dashArrayAttr);
3459
+ applyAttr(base, "strokeDashoffset", dashOffsetAttr);
3460
+ applyAttr(base, "strokeOpacity", strokeOpacityAttr);
3461
+ return [base];
3462
+ }
3463
+ function collapseLeafWithTrim(leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead) {
3464
+ const offsetToDashOffset = makeOffsetToDashOffset(startOffsetPct, pathLengthPx, minMaxOffset);
3465
+ const rangeToDasharray = makeRangeToDasharray(pathLengthPx, minMaxOffset);
3466
+ const node = __spreadValues({}, leaf);
3467
+ delete node.effects;
3468
+ applyAttr(node, "strokeDasharray", computeAnimAttr(rangeRead, rangeToDasharray));
3469
+ applyAttr(node, "strokeDashoffset", computeAnimAttr(offsetRead, offsetToDashOffset));
3470
+ applyAttr(node, "strokeOpacity", computeOpacityFromRange(rangeRead));
3471
+ return node;
3472
+ }
3473
+ function makeBareSubpath(dStr) {
3474
+ return { type: "path", d: dStr };
3475
+ }
3476
+ var SMALL_PADDING_PX = 1;
3477
+ function makeOffsetToDashOffset(startOffsetPct, pathLengthPx, minMaxOffset) {
3478
+ const [minIdx] = getOffsetIndexRange(minMaxOffset);
3479
+ return (offsetVal) => pathLengthPx * (-offsetVal - minIdx + startOffsetPct) + SMALL_PADDING_PX;
3480
+ }
3481
+ function makeRangeToDasharray(pathLengthPx, minMaxOffset) {
3482
+ const [minIdx, maxIdx] = getOffsetIndexRange(minMaxOffset);
3483
+ const repeats = maxIdx - minIdx + 1;
3484
+ return (rangeVal) => {
3485
+ const a = clamp(rangeVal[0], 0, 1);
3486
+ const b = clamp(rangeVal[1], 0, 1);
3487
+ const minR = Math.min(a, b);
3488
+ const maxR = Math.max(a, b);
3489
+ const out = [0];
3490
+ let gap = SMALL_PADDING_PX;
3491
+ for (let i = 0; i < repeats; i++) {
3492
+ out.push(gap + minR * pathLengthPx);
3493
+ out.push((maxR - minR) * pathLengthPx);
3494
+ gap = (1 - maxR) * pathLengthPx;
2319
3495
  }
2320
- } else {
2321
- results.push(animate);
2322
- }
2323
- return results;
3496
+ out.push(gap + SMALL_PADDING_PX);
3497
+ return out;
3498
+ };
2324
3499
  }
2325
- function interpolateValue(propName, a, b, t) {
2326
- var _a, _b;
2327
- if (propName === "d") {
2328
- const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
2329
- const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2330
- return { paths: interpolateBeziers(aPaths, bPaths, t) };
2331
- }
2332
- if (COLOUR_ATTR_NAMES.has(propName)) {
2333
- return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
2334
- }
2335
- if (TRANSFORM_FN_NAMES.has(propName) || propName === "stroke-dasharray" || propName === "strokeDasharray") {
2336
- return interpolateVec(a || [], b || [], t);
3500
+ function getOffsetIndexRange(minMaxOffset) {
3501
+ return [
3502
+ Math.floor(Math.min(-minMaxOffset[0], -minMaxOffset[1])),
3503
+ Math.ceil(Math.max(-minMaxOffset[0], -minMaxOffset[1]))
3504
+ ];
3505
+ }
3506
+ function readScalarValues(r) {
3507
+ var _a;
3508
+ if (r.kind === "absent" /* Absent */) return [];
3509
+ if (r.kind === "static" /* Static */) return [r.value];
3510
+ const out = [];
3511
+ for (const kf of r.keyframes) {
3512
+ const v = (_a = kf.value) != null ? _a : kf.v;
3513
+ if (typeof v === "number") out.push(v);
2337
3514
  }
2338
- return interpolateNum(+(a || 0), +(b || 0), t);
3515
+ return out;
2339
3516
  }
2340
- function expandLoopKeyframes(propName, keyframes, loop, duration) {
2341
- var _a, _b, _c, _d, _e;
2342
- const totalIntervals = keyframes.length - 1;
2343
- const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2344
- let segKfs;
2345
- if (loop.before) {
2346
- segKfs = keyframes.slice(0, segCount + 1);
2347
- } else {
2348
- segKfs = keyframes.slice(totalIntervals - segCount);
3517
+ function computeAnimAttr(read, map) {
3518
+ if (read.kind === "absent" /* Absent */) return void 0;
3519
+ if (read.kind === "static" /* Static */) return { kind: "static" /* Static */, value: map(read.value) };
3520
+ return {
3521
+ kind: "animated" /* Animated */,
3522
+ keyframes: read.keyframes.map((kf) => {
3523
+ var _a, _b, _c, _d;
3524
+ return {
3525
+ time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
3526
+ value: map((_c = kf.value) != null ? _c : kf.v),
3527
+ easing: (_d = kf.easing) != null ? _d : kf.e
3528
+ };
3529
+ })
3530
+ };
3531
+ }
3532
+ function applyAttr(node, attrName, attr) {
3533
+ if (!attr) return;
3534
+ if (attr.kind === "static" /* Static */) {
3535
+ node[attrName] = attr.value;
3536
+ return;
2349
3537
  }
2350
- const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2351
- const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2352
- let fillStart, fillEnd;
2353
- if (loop.before) {
2354
- fillStart = 0;
2355
- fillEnd = firstT;
2356
- } else {
2357
- fillStart = lastT;
2358
- fillEnd = duration;
3538
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3539
+ const animate = __spreadValues({}, prevAnimate || {});
3540
+ animate[attrName] = { keyframes: attr.keyframes };
3541
+ node.animate = animate;
3542
+ }
3543
+ function computeOpacityFromRange(rangeRead) {
3544
+ var _a, _b, _c, _d, _e, _f;
3545
+ const hide = (v) => v[0] === v[1];
3546
+ if (rangeRead.kind === "absent" /* Absent */) return void 0;
3547
+ if (rangeRead.kind === "static" /* Static */) return hide(rangeRead.value) ? { kind: "static" /* Static */, value: 0 } : void 0;
3548
+ const kfs = rangeRead.keyframes;
3549
+ let anyHide = false;
3550
+ let allHide = true;
3551
+ for (const kf of kfs) {
3552
+ if (hide((_a = kf.value) != null ? _a : kf.v)) anyHide = true;
3553
+ else allHide = false;
2359
3554
  }
2360
- const fillDuration = fillEnd - fillStart;
2361
- if (fillDuration <= 0) return keyframes;
2362
- const segStartT = (_d = segKfs[0].t) != null ? _d : 0;
2363
- const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
2364
- const segDuration = segEndT - segStartT;
2365
- if (segDuration <= 0) return keyframes;
2366
- const template = segKfs.map((kf) => ({
2367
- relT: (kf.t - segStartT) / segDuration,
2368
- v: kf.v,
2369
- e: kf.e
2370
- }));
2371
- const fullReps = Math.floor(fillDuration / segDuration);
2372
- const remainder = fillDuration - fullReps * segDuration;
2373
- const partialFraction = remainder / segDuration;
2374
- const looped = [];
2375
- function appendRep(repStart, isReversed, partial) {
2376
- let entries;
2377
- if (isReversed) {
2378
- entries = [];
2379
- for (let i = template.length - 1; i >= 0; i--) {
2380
- entries.push({
2381
- relT: 1 - template[i].relT,
2382
- v: template[i].v,
2383
- // Easing for reversed transition: use reversed easing from the forward "from" keyframe
2384
- e: i > 0 ? reverseEasing(template[i - 1].e) : void 0
2385
- });
3555
+ if (!anyHide) return void 0;
3556
+ if (allHide) return { kind: "static" /* Static */, value: 0 };
3557
+ const out = [];
3558
+ for (let i = 0; i < kfs.length; i++) {
3559
+ const kf = kfs[i];
3560
+ const prevKf = i > 0 ? kfs[i - 1] : void 0;
3561
+ const nextKf = i < kfs.length - 1 ? kfs[i + 1] : void 0;
3562
+ const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
3563
+ const thisHide = hide((_d = kf.value) != null ? _d : kf.v);
3564
+ const prevHide = prevKf ? thisHide && hide((_e = prevKf.value) != null ? _e : prevKf.v) : thisHide;
3565
+ const nextHide = nextKf ? thisHide && hide((_f = nextKf.value) != null ? _f : nextKf.v) : thisHide;
3566
+ if (prevHide && !nextHide) {
3567
+ out.push({ time: t, value: 0 });
3568
+ out.push({ time: t + 1, value: 1 });
3569
+ } else if (!prevHide && nextHide) {
3570
+ out.push({ time: t - 1, value: 1 });
3571
+ out.push({ time: t, value: 0 });
3572
+ }
3573
+ }
3574
+ if (out.length <= 1) return void 0;
3575
+ return { kind: "animated" /* Animated */, keyframes: out };
3576
+ }
3577
+ function readRangeWithCrossings(raw) {
3578
+ const r = readAnimatable(raw);
3579
+ if (r.kind !== "animated" /* Animated */) return r;
3580
+ const kfs = r.keyframes.map((kf) => {
3581
+ var _a, _b, _c, _d;
3582
+ return {
3583
+ time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
3584
+ value: (_c = kf.value) != null ? _c : kf.v,
3585
+ easing: (_d = kf.easing) != null ? _d : kf.e
3586
+ };
3587
+ });
3588
+ const hasReverse = kfs.some((kf) => kf.value[0] > kf.value[1]);
3589
+ if (!hasReverse) {
3590
+ return {
3591
+ kind: "animated" /* Animated */,
3592
+ keyframes: kfs.map((kf) => ({ time: kf.time, value: kf.value, easing: kf.easing }))
3593
+ };
3594
+ }
3595
+ const crossingTimes = [];
3596
+ for (let i = 1; i < kfs.length; i++) {
3597
+ const prev = kfs[i - 1];
3598
+ const cur = kfs[i];
3599
+ const dPrev = prev.value[1] - prev.value[0];
3600
+ const dCur = cur.value[1] - cur.value[0];
3601
+ if (dPrev * dCur < 0) {
3602
+ const t = bisectionForRangeCrossing(prev, cur);
3603
+ if (t !== null && t > prev.time && t < cur.time) {
3604
+ crossingTimes.push(Math.round(t));
2386
3605
  }
3606
+ }
3607
+ }
3608
+ const uniqueTs = Array.from(new Set(crossingTimes)).sort((a, b) => a - b);
3609
+ const out = [];
3610
+ let j = 0;
3611
+ for (const kf of kfs) {
3612
+ while (j < uniqueTs.length && uniqueTs[j] < kf.time) {
3613
+ const t = uniqueTs[j++];
3614
+ const v2 = interpolateRangeAt(kfs, t);
3615
+ const m = (v2[0] + v2[1]) / 2;
3616
+ out.push({ time: t, value: [m, m] });
3617
+ }
3618
+ const v = kf.value[0] > kf.value[1] ? [kf.value[1], kf.value[0]] : kf.value;
3619
+ out.push({ time: kf.time, value: v, easing: kf.easing });
3620
+ }
3621
+ while (j < uniqueTs.length) {
3622
+ const t = uniqueTs[j++];
3623
+ const v = interpolateRangeAt(kfs, t);
3624
+ const m = (v[0] + v[1]) / 2;
3625
+ out.push({ time: t, value: [m, m] });
3626
+ }
3627
+ return { kind: "animated" /* Animated */, keyframes: out };
3628
+ }
3629
+ function bisectionForRangeCrossing(prev, cur) {
3630
+ const f = (t) => {
3631
+ const a = (t - prev.time) / (cur.time - prev.time);
3632
+ const v0 = prev.value[0] + (cur.value[0] - prev.value[0]) * a;
3633
+ const v1 = prev.value[1] + (cur.value[1] - prev.value[1]) * a;
3634
+ return v1 - v0;
3635
+ };
3636
+ let lo = prev.time, hi = cur.time;
3637
+ let fLo = f(lo);
3638
+ if (fLo === 0) return lo;
3639
+ const fHi = f(hi);
3640
+ if (fHi === 0) return hi;
3641
+ if (fLo * fHi > 0) return null;
3642
+ for (let i = 0; i < 100; i++) {
3643
+ const mid = (lo + hi) / 2;
3644
+ const fMid = f(mid);
3645
+ if (fMid === 0 || Math.abs(hi - lo) < 1e-4) return mid;
3646
+ if (fLo * fMid < 0) {
3647
+ hi = mid;
2387
3648
  } else {
2388
- entries = template;
3649
+ lo = mid;
3650
+ fLo = fMid;
2389
3651
  }
2390
- const cutRelT = partial !== void 0 ? partial : 1;
2391
- for (let i = 0; i < entries.length; i++) {
2392
- const entry = entries[i];
2393
- if (entry.relT > cutRelT + 1e-9) {
2394
- const prev = entries[i - 1];
2395
- const intervalSpan = entry.relT - prev.relT;
2396
- const localFrac = (cutRelT - prev.relT) / intervalSpan;
2397
- const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
2398
- const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
2399
- const { left: leftEasing } = splitEasing(prev.e, localFrac);
2400
- if (looped.length > 0 && prev.relT <= cutRelT) {
2401
- looped[looped.length - 1].e = leftEasing;
2402
- }
2403
- looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
2404
- return;
2405
- }
2406
- looped.push({
2407
- t: repStart + entry.relT * segDuration,
2408
- v: entry.v,
2409
- e: i < entries.length - 1 ? entry.e : void 0
2410
- });
3652
+ }
3653
+ return (lo + hi) / 2;
3654
+ }
3655
+ function interpolateRangeAt(kfs, t) {
3656
+ if (t <= kfs[0].time) return kfs[0].value;
3657
+ if (t >= kfs[kfs.length - 1].time) return kfs[kfs.length - 1].value;
3658
+ for (let i = 1; i < kfs.length; i++) {
3659
+ if (t <= kfs[i].time) {
3660
+ const prev = kfs[i - 1];
3661
+ const cur = kfs[i];
3662
+ const a = (t - prev.time) / (cur.time - prev.time);
3663
+ return [
3664
+ prev.value[0] + (cur.value[0] - prev.value[0]) * a,
3665
+ prev.value[1] + (cur.value[1] - prev.value[1]) * a
3666
+ ];
2411
3667
  }
2412
3668
  }
2413
- for (let rep = 0; rep < fullReps; rep++) {
2414
- const distFromBoundary = loop.before ? fullReps - 1 - rep : rep;
2415
- const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
2416
- const repStart = fillStart + rep * segDuration;
2417
- appendRep(repStart, isReversed);
3669
+ return kfs[kfs.length - 1].value;
3670
+ }
3671
+ function pxBezierPathLength(path) {
3672
+ const v = path.v;
3673
+ if (!v || v.length < 2) return 0;
3674
+ let total = 0;
3675
+ for (let i = 0; i < v.length - 1; i++) {
3676
+ total += segmentLength(path, i, i + 1);
2418
3677
  }
2419
- if (partialFraction > 1e-9) {
2420
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
2421
- const repStart = fillStart + fullReps * segDuration;
2422
- appendRep(repStart, isReversed, partialFraction);
3678
+ if (path.c && v.length > 1) {
3679
+ total += segmentLength(path, v.length - 1, 0);
2423
3680
  }
2424
- if (loop.before) {
2425
- return [...looped, ...keyframes];
3681
+ return total;
3682
+ }
3683
+ function segmentLength(path, from, to) {
3684
+ var _a, _b, _c, _d;
3685
+ const v = path.v;
3686
+ const p0 = v[from];
3687
+ const p3 = v[to];
3688
+ const p1 = (_b = (_a = path.o) == null ? void 0 : _a[from]) != null ? _b : p0;
3689
+ const p2 = (_d = (_c = path.i) == null ? void 0 : _c[to]) != null ? _d : p3;
3690
+ const lut = bezier2D_arcLengthLUT(p0, p1, p2, p3);
3691
+ return lut.ds[lut.ds.length - 1];
3692
+ }
3693
+ function rectToPathD(node) {
3694
+ var _a, _b, _c, _d;
3695
+ if (node.type !== "rect") return void 0;
3696
+ const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
3697
+ const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
3698
+ return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
3699
+ }
3700
+
3701
+ // src/effects/PlayerEffectsUtil.ts
3702
+ function applyPlayerEffects(root) {
3703
+ const ctx = {
3704
+ defs: [],
3705
+ warnings: [],
3706
+ errors: [],
3707
+ idMap: /* @__PURE__ */ new Map(),
3708
+ nextId: 0,
3709
+ contentRefInnerIds: /* @__PURE__ */ new Map(),
3710
+ maskAncestorChains: /* @__PURE__ */ new Map()
3711
+ };
3712
+ const working = clone(root);
3713
+ indexById(working, ctx.idMap);
3714
+ identifyContentRefTargets(working, ctx, () => genId(ctx, "inner"));
3715
+ collectMaskAncestorChains(working, ctx);
3716
+ const afterPass1 = applyPlayerEffects_exceptRetime(working, ctx);
3717
+ const out = applyPlayerEffects_retime(afterPass1, ctx);
3718
+ spliceDefs(out, ctx.defs);
3719
+ return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
3720
+ }
3721
+ function applyPlayerEffects_exceptRetime(node, ctx) {
3722
+ if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
3723
+ const fx = node.effects;
3724
+ const originalId = typeof node.id === "string" ? node.id : void 0;
3725
+ const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
3726
+ if (!fx && !innerIdForContentRef) return node;
3727
+ const { transformation, repeater, maskedBy, trimPath, retime, ref, fillGradient, strokeGradient, textAlongPath } = fx != null ? fx : {};
3728
+ const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
3729
+ if (fx) delete node.effects;
3730
+ let n = node;
3731
+ n = applyTextAlongPathEffect(n, textAlongPath, ctx);
3732
+ n = applyFillGradientEffect(n, fillGradient, ctx);
3733
+ n = applyStrokeGradientEffect(n, strokeGradient, ctx);
3734
+ n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
3735
+ n = applyRepeaterEffect(n, repeater, ctx);
3736
+ n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
3737
+ if (innerIdForContentRef) {
3738
+ n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
2426
3739
  } else {
2427
- return [...keyframes, ...looped];
3740
+ n = applyRefAndTransformationEffect(n, ref, transformation, ctx);
2428
3741
  }
3742
+ if (retime) node.effects = { retime };
3743
+ if (originalId) ctx.idMap.set(originalId, n);
3744
+ return n;
2429
3745
  }
2430
- function normalizeKeyframes(propName, propAnim, duration, defs) {
2431
- var _a, _b, _c, _d, _e;
2432
- const keyframes = propAnim.keyframes || propAnim.kfs || [];
2433
- const normalized = [];
2434
- for (const kf of keyframes) {
2435
- const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2436
- let value = (_c = kf.value) != null ? _c : kf.v;
2437
- const easing = (_d = kf.easing) != null ? _d : kf.e;
2438
- if (propName === "d") {
2439
- value = normalizePathValue(value);
3746
+ function applyPlayerEffects_retime(node, ctx) {
3747
+ applyAllRetimeEffects(node, ctx);
3748
+ return node;
3749
+ }
3750
+
3751
+ // src/PxAnimatorUseMaterialiser.ts
3752
+ function materialiseAnimatedUseInstances(root) {
3753
+ var _a;
3754
+ const idMap = buildIdMap(root);
3755
+ const animatedIds = computeAnimatedSubtreeIds(root, idMap);
3756
+ if (animatedIds.size === 0) return root;
3757
+ let idCounter = 0;
3758
+ const genId3 = () => "_lw_use_mat_" + ++idCounter;
3759
+ const defsCollector = [];
3760
+ const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector);
3761
+ if (defsCollector.length === 0) return walked;
3762
+ const defsNode = { type: "defs", children: defsCollector };
3763
+ const newChildren = [...(_a = walked.children) != null ? _a : [], defsNode];
3764
+ return __spreadProps(__spreadValues({}, walked), { children: newChildren });
3765
+ }
3766
+ function buildIdMap(root) {
3767
+ const map = /* @__PURE__ */ new Map();
3768
+ const visit = (n) => {
3769
+ var _a;
3770
+ if (typeof n.id === "string") map.set(n.id, n);
3771
+ (_a = n.children) == null ? void 0 : _a.forEach(visit);
3772
+ };
3773
+ visit(root);
3774
+ return map;
3775
+ }
3776
+ function computeAnimatedSubtreeIds(root, idMap) {
3777
+ const cache = /* @__PURE__ */ new WeakMap();
3778
+ const result = /* @__PURE__ */ new Set();
3779
+ const hasAnim = (n, visiting) => {
3780
+ const cached = cache.get(n);
3781
+ if (cached !== void 0) return cached;
3782
+ if (visiting.has(n)) return false;
3783
+ visiting.add(n);
3784
+ let r = false;
3785
+ if (n.animate && typeof n.animate === "object" && !Array.isArray(n.animate)) {
3786
+ for (const _ in n.animate) {
3787
+ r = true;
3788
+ break;
3789
+ }
2440
3790
  }
2441
- if (COLOUR_ATTR_NAMES.has(propName)) {
2442
- value = (_e = parseColor(value)) != null ? _e : value;
3791
+ if (!r && n.children) {
3792
+ for (const ch of n.children) {
3793
+ if (hasAnim(ch, visiting)) {
3794
+ r = true;
3795
+ break;
3796
+ }
3797
+ }
2443
3798
  }
2444
- normalized.push({
2445
- t: timePct,
2446
- v: value,
2447
- e: resolveEasing(easing, defs)
2448
- });
3799
+ if (!r && n.type === "use" && typeof n.href === "string") {
3800
+ const targetId = stripHash2(n.href);
3801
+ const target = targetId ? idMap.get(targetId) : void 0;
3802
+ if (target) r = hasAnim(target, visiting);
3803
+ }
3804
+ visiting.delete(n);
3805
+ cache.set(n, r);
3806
+ return r;
3807
+ };
3808
+ for (const [id, node] of idMap) {
3809
+ if (hasAnim(node, /* @__PURE__ */ new Set())) result.add(id);
2449
3810
  }
2450
- normalized.sort((a, b) => {
2451
- var _a2, _b2;
2452
- return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
3811
+ return result;
3812
+ }
3813
+ function stripHash2(href) {
3814
+ if (typeof href !== "string") return void 0;
3815
+ return href.startsWith("#") ? href.slice(1) : href;
3816
+ }
3817
+ function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector) {
3818
+ const clone2 = deepClonePxNode(target);
3819
+ regenerateIdsAndRewriteRefs(clone2, genId3);
3820
+ const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector) : clone2;
3821
+ const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector);
3822
+ const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materialisedClone] });
3823
+ delete newNode.href;
3824
+ return applyUseOffsetToG(newNode);
3825
+ }
3826
+ function rewriteSymbolRootToGroup(symbolNode, genId3, defsCollector) {
3827
+ const viewBox = parseViewBox(symbolNode.viewBox);
3828
+ const g = __spreadProps(__spreadValues({}, symbolNode), { type: "g" });
3829
+ delete g.viewBox;
3830
+ delete g.preserveAspectRatio;
3831
+ delete g.width;
3832
+ delete g.height;
3833
+ if (!viewBox) return g;
3834
+ const [vbX, vbY, vbW, vbH] = viewBox;
3835
+ if (vbX !== 0 || vbY !== 0) {
3836
+ g.transform = "translate(" + -vbX + "," + -vbY + ")";
3837
+ }
3838
+ const clipId = genId3();
3839
+ defsCollector.push({
3840
+ type: "clipPath",
3841
+ id: clipId,
3842
+ children: [{ type: "rect", x: vbX, y: vbY, width: vbW, height: vbH }]
2453
3843
  });
2454
- const loopRaw = propAnim.loop;
2455
- const loop = loopRaw === true ? {} : loopRaw || void 0;
2456
- if (loop && normalized.length >= 2) {
2457
- return expandLoopKeyframes(propName, normalized, loop, duration);
2458
- }
2459
- return normalized;
3844
+ g.clipPath = "url(#" + clipId + ")";
3845
+ return g;
2460
3846
  }
2461
- function mergeAnimationDefinitions(animations) {
2462
- const merged = {};
2463
- for (const anim of animations) {
2464
- for (const [prop, propAnim] of Object.entries(anim)) {
2465
- merged[prop] = propAnim;
3847
+ function parseViewBox(v) {
3848
+ if (typeof v !== "string") return void 0;
3849
+ const parts = v.trim().split(/[\s,]+/).map(Number);
3850
+ if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
3851
+ return [parts[0], parts[1], parts[2], parts[3]];
3852
+ }
3853
+ function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector) {
3854
+ if (node.type === "use" && typeof node.href === "string") {
3855
+ const targetId = stripHash2(node.href);
3856
+ if (targetId && animatedIds.has(targetId)) {
3857
+ const target = idMap.get(targetId);
3858
+ if (target) return materialiseOneUse(node, target, idMap, animatedIds, genId3, defsCollector);
2466
3859
  }
2467
3860
  }
2468
- return merged;
3861
+ if (!node.children) return node;
3862
+ let changed = false;
3863
+ const newChildren = node.children.map((ch) => {
3864
+ const m = walkAndMaterialise2(ch, idMap, animatedIds, genId3, defsCollector);
3865
+ if (m !== ch) changed = true;
3866
+ return m;
3867
+ });
3868
+ return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
2469
3869
  }
2470
- var _elementIdCounter = 0;
2471
- function generateElementId() {
2472
- return "_px_el_" + ++_elementIdCounter;
3870
+
3871
+ // src/PxAnimatorMaterialiseAll.ts
3872
+ function materialiseAllInTree(doc, engine, opts) {
3873
+ var _a, _b;
3874
+ let root = applyPlayerEffects(doc).root;
3875
+ const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
3876
+ root = materialiseInternalLoopsInTree(root, duration);
3877
+ if (engine === PxAnimatorEngine.webapi) {
3878
+ root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
3879
+ root = materialiseAnimatedUseInstances(root);
3880
+ }
3881
+ return root;
2473
3882
  }
2474
- function normalizeAnimationDefinition(animDef, duration, defs) {
2475
- const normalized = {};
2476
- for (const [propName, propAnim] of Object.entries(animDef)) {
2477
- const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2478
- if (normalizedKfs.length > 0) {
2479
- normalized[propName] = { kfs: normalizedKfs };
3883
+
3884
+ // src/PxAnimatorDOM.ts
3885
+ var SVG_NS = "http://www.w3.org/2000/svg";
3886
+ var DISALLOWED_SVG_TAGS_LOWER = /* @__PURE__ */ new Set([
3887
+ "script",
3888
+ "foreignobject"
3889
+ ]);
3890
+ var URL_VALUE_ATTRS_LOWER = /* @__PURE__ */ new Set([
3891
+ "href",
3892
+ // <use>, <image>
3893
+ "xlink:href",
3894
+ // legacy <use>
3895
+ "src",
3896
+ // <image>
3897
+ "filter",
3898
+ // url(#filterId)
3899
+ "clippath",
3900
+ // clip-path="url(#…)"
3901
+ "mask",
3902
+ // url(#maskId)
3903
+ "markerstart",
3904
+ // marker-start="url(#…)"
3905
+ "markermid",
3906
+ // marker-mid="url(#…)"
3907
+ "markerend"
3908
+ // marker-end="url(#…)"
3909
+ ]);
3910
+ var IMAGE_REF_ATTRS_LOWER = /* @__PURE__ */ new Set(["href", "xlink:href", "src"]);
3911
+ var DATA_RASTER_IMAGE_RE = /^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/i;
3912
+ function isDangerousAttrName(nameLower) {
3913
+ if (nameLower.startsWith("on")) return true;
3914
+ return false;
3915
+ }
3916
+ function sanitiseAttributeValue(name, value) {
3917
+ const nameLower = name.toLowerCase();
3918
+ if (isDangerousAttrName(nameLower)) {
3919
+ console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
3920
+ return void 0;
3921
+ }
3922
+ if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopcolor") {
3923
+ const str = String(value);
3924
+ if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
3925
+ console.warn('Attribute "' + nameLower + '" blocked: url() must be internal url(#id), got:', value);
3926
+ return void 0;
2480
3927
  }
3928
+ return value;
2481
3929
  }
2482
- return normalized;
3930
+ if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {
3931
+ const str = String(value);
3932
+ if (str.startsWith("#")) return value;
3933
+ if (/^url\(#[^)]+\)$/.test(str)) return value;
3934
+ if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && DATA_RASTER_IMAGE_RE.test(str)) return value;
3935
+ console.warn('Attribute "' + nameLower + '" blocked: must be #id, url(#id), or base64 raster data: URI, got:', value);
3936
+ return void 0;
3937
+ }
3938
+ return value;
2483
3939
  }
2484
- function getNormalisedBindings(doc) {
2485
- const animatorConfig = getAnimatorConfig(doc) || {};
2486
- const defs = getDefs(doc);
2487
- const duration = animatorConfig.duration || 1e3;
2488
- const bindings = [];
2489
- const processAnimation = (id, animate) => {
2490
- if (!animate) return null;
2491
- const animDefs = resolveElementAnimation(animate, defs);
2492
- if (animDefs.length === 0) return null;
2493
- const merged = mergeAnimationDefinitions(animDefs);
2494
- const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs);
2495
- if (Object.keys(normalizedAnim).length === 0) return null;
2496
- return {
2497
- id,
2498
- animate: normalizedAnim
2499
- };
2500
- };
2501
- const docBindings = getBindings(doc);
2502
- if (docBindings) {
2503
- for (const binding of docBindings) {
2504
- const normalized = processAnimation(binding.id, binding.animate);
2505
- if (normalized) bindings.push(normalized);
2506
- }
3940
+ function createElement(tagName, normalisedProps, style, children, textContent) {
3941
+ if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
3942
+ console.warn("SVG tag blocked (dangerous): ", tagName);
3943
+ return null;
2507
3944
  }
2508
- const processNode = (node) => {
2509
- const inlineAnim = node.animate;
2510
- if (inlineAnim && Object.keys(inlineAnim).length > 0) {
2511
- const nodeId = node.id || generateElementId();
2512
- node.id = nodeId;
2513
- const normalized = processAnimation(nodeId, inlineAnim);
2514
- if (normalized) bindings.push(normalized);
2515
- }
2516
- if (node.children) {
2517
- for (let i = 0; i < node.children.length; i++) {
2518
- processNode(node.children[i]);
2519
- }
2520
- }
2521
- };
2522
- if (doc.children) {
2523
- for (let i = 0; i < doc.children.length; i++) {
2524
- processNode(doc.children[i]);
3945
+ const element = document.createElementNS(SVG_NS, tagName);
3946
+ for (const propName in normalisedProps) {
3947
+ const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
3948
+ if (sanitised === void 0) continue;
3949
+ element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
3950
+ }
3951
+ if (style) {
3952
+ for (const styleProp in style) {
3953
+ element.style[styleProp] = String(style[styleProp]);
2525
3954
  }
2526
3955
  }
2527
- return bindings;
2528
- }
2529
- function getKeyframesPair(keyframes, progress) {
2530
- var _a, _b;
2531
- let prevKf = keyframes[0];
2532
- let nextKf = keyframes[keyframes.length - 1];
2533
- for (let j = 0; j < keyframes.length - 1; j++) {
2534
- const aOff = (_a = keyframes[j].t) != null ? _a : 0;
2535
- const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
2536
- if (aOff <= progress && progress <= bOff) {
2537
- prevKf = keyframes[j];
2538
- nextKf = keyframes[j + 1];
2539
- break;
3956
+ if (children) {
3957
+ for (const child of children) {
3958
+ element.appendChild(child);
2540
3959
  }
2541
3960
  }
2542
- return { prevKf, nextKf };
3961
+ if (textContent) element.textContent = textContent;
3962
+ return element;
2543
3963
  }
2544
- function calcPropertyValue(propName, propAnim, progress) {
2545
- var _a, _b, _c, _d, _e, _f, _g;
2546
- const keyframes = propAnim.kfs || propAnim.keyframes || [];
2547
- if (keyframes.length === 0) return null;
2548
- const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
2549
- let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
2550
- localProgress = clamp(localProgress, 0, 1);
2551
- const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
2552
- if (easing && Array.isArray(easing)) {
2553
- try {
2554
- localProgress = cubicBezier(easing)(localProgress);
2555
- } catch (e) {
2556
- }
3964
+ function resolveStyle(style, defs) {
3965
+ var _a;
3966
+ if (!style) return void 0;
3967
+ if (typeof style === "string") {
3968
+ return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
2557
3969
  }
2558
- let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2559
- let cssValue = null;
2560
- const prevV = (_d = prevKf == null ? void 0 : prevKf.v) != null ? _d : prevKf == null ? void 0 : prevKf.value;
2561
- const nextV = (_e = nextKf == null ? void 0 : nextKf.v) != null ? _e : nextKf == null ? void 0 : nextKf.value;
2562
- if (cssAttrName === "d") {
2563
- const prevPaths = (_f = prevV == null ? void 0 : prevV.paths) != null ? _f : Array.isArray(prevV) ? prevV : [];
2564
- const nextPaths = (_g = nextV == null ? void 0 : nextV.paths) != null ? _g : Array.isArray(nextV) ? nextV : [];
2565
- cssValue = interpolateBeziers(
2566
- prevPaths,
2567
- nextPaths,
2568
- localProgress
2569
- ).map((bz) => bezierToSvgPath(bz)).join("");
2570
- } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
2571
- cssValue = toRGBA(interpolateColor(
2572
- prevV || [0, 0, 0, 1],
2573
- nextV || [0, 0, 0, 1],
2574
- localProgress
2575
- ));
2576
- cssAttrName = propName;
2577
- } else if (cssAttrName === "stroke-dasharray") {
2578
- cssValue = interpolateVec(
2579
- prevV || [],
2580
- nextV || [],
2581
- localProgress
2582
- ).join(" ");
2583
- cssAttrName = propName;
2584
- } else if (cssAttrName === "transform" && prevV !== null && typeof prevV === "object" && !Array.isArray(prevV)) {
2585
- const partKeys = /* @__PURE__ */ new Set([
2586
- ...prevV ? Object.keys(prevV) : [],
2587
- ...nextV ? Object.keys(nextV) : []
2588
- ]);
2589
- const partsResult = {};
2590
- for (const partKey of partKeys) {
2591
- const prevPart = prevV == null ? void 0 : prevV[partKey];
2592
- const nextPart = nextV == null ? void 0 : nextV[partKey];
2593
- if (partKey === "rotate") {
2594
- partsResult.rotate = interpolateNum(+(prevPart != null ? prevPart : 0), +(nextPart != null ? nextPart : 0), localProgress);
2595
- } else if (partKey === "translate" || partKey === "scale" || partKey === "origin") {
2596
- const fallback = partKey === "scale" ? [1, 1] : [0, 0];
2597
- const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);
2598
- partsResult[partKey] = interp;
3970
+ return style;
3971
+ }
3972
+ function getNormalizedProps(props) {
3973
+ const propsCopy = {};
3974
+ for (const rawKey of Object.keys(props)) {
3975
+ const key = kebabToCamelCaseWord(rawKey);
3976
+ if (INTERNAL_ATTRS.has(key)) continue;
3977
+ if (key === "style") continue;
3978
+ let value = props[rawKey];
3979
+ if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
3980
+ propsCopy[key] = toRGBA(value);
3981
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
3982
+ propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
3983
+ } else if (TRANSFORM_FN_NAMES.has(key)) {
3984
+ if (Array.isArray(value)) {
3985
+ if (key === "translate") value = value.map((v) => v + "px");
3986
+ value = value.join(",");
2599
3987
  }
3988
+ if (key === "rotate") value = value + "deg";
3989
+ propsCopy["transform"] = key + "(" + value + ")";
3990
+ } else if (value !== void 0 && value !== null) {
3991
+ propsCopy[key] = String(value);
2600
3992
  }
2601
- if (propAnimIsMotionPath(propAnim)) {
2602
- const prevTr = prevV.translate;
2603
- const nextTr = nextV.translate;
2604
- if (Array.isArray(prevTr) && Array.isArray(nextTr)) {
2605
- const sample = evaluateMotionPathSegment(
2606
- prevKf,
2607
- nextKf,
2608
- [+prevTr[0], +prevTr[1]],
2609
- [+nextTr[0], +nextTr[1]],
2610
- localProgress,
2611
- !!propAnim.autoOrient
2612
- );
2613
- partsResult.translate = [sample.translate[0], sample.translate[1]];
2614
- if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
3993
+ }
3994
+ return propsCopy;
3995
+ }
3996
+ function renderNode(node, defs) {
3997
+ if (!node) return null;
3998
+ const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
3999
+ const nodeDefs = getDefs(node) || defs;
4000
+ const resolvedStyle = resolveStyle(style, nodeDefs);
4001
+ let childElements;
4002
+ if (children) {
4003
+ for (const ch of children) {
4004
+ const child = renderNode(ch, nodeDefs);
4005
+ if (child) {
4006
+ if (!childElements) childElements = [];
4007
+ childElements.push(child);
2615
4008
  }
2616
4009
  }
2617
- cssValue = composeTransformParts(partsResult, { withUnits: false });
2618
- cssAttrName = "transform";
2619
- } else if (cssAttrName === "translate") {
2620
- const v = interpolateVec(
2621
- prevV || [0, 0],
2622
- nextV || [0, 0],
2623
- localProgress
2624
- );
2625
- cssValue = "translate(" + v.join(",") + ")";
2626
- cssAttrName = "transform";
2627
- } else if (cssAttrName === "rotate") {
2628
- const v = interpolateNum(
2629
- +(prevV || 0),
2630
- +(nextV || 0),
2631
- localProgress
2632
- );
2633
- cssValue = "rotate(" + v + ")";
2634
- cssAttrName = "transform";
2635
- } else if (cssAttrName === "scale") {
2636
- const v = interpolateVec(
2637
- prevV || [1, 1],
2638
- nextV || [1, 1],
2639
- localProgress
2640
- );
2641
- cssValue = "scale(" + v.join(",") + ")";
2642
- cssAttrName = "transform";
2643
- } else {
2644
- const num2 = interpolateNum(
2645
- +(prevV || 0),
2646
- +(nextV || 0),
2647
- localProgress
2648
- );
2649
- cssValue = num2;
2650
- }
2651
- if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
2652
- cssValue = cssValue * 100 + "%";
2653
4010
  }
2654
- return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
4011
+ return createElement(
4012
+ type || "g",
4013
+ getNormalizedProps(props),
4014
+ resolvedStyle,
4015
+ childElements,
4016
+ props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
4017
+ );
2655
4018
  }
2656
- function calcAnimationValues(animDef, progress) {
2657
- const result = {};
2658
- for (const [propName, propAnim] of Object.entries(animDef)) {
2659
- const computed = calcPropertyValue(propName, propAnim, progress);
2660
- if (computed) {
2661
- result[computed.k] = computed.v;
4019
+
4020
+ // src/PxAnimatorTriggers.ts
4021
+ function setupAnimationTriggers(api, config) {
4022
+ const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
4023
+ const root = api.getRootElement();
4024
+ if (!root) {
4025
+ console.warn("setupAnimationTriggers: No root element found for animation.");
4026
+ return api;
4027
+ }
4028
+ const start = () => {
4029
+ api.play();
4030
+ };
4031
+ const handleEndAction = () => {
4032
+ switch (outAction) {
4033
+ case "pause":
4034
+ api.pause();
4035
+ break;
4036
+ case "reset":
4037
+ api.cancel();
4038
+ break;
4039
+ case "reverse":
4040
+ api.play();
4041
+ break;
4042
+ case "continue":
4043
+ default:
4044
+ break;
4045
+ }
4046
+ };
4047
+ switch (startOn) {
4048
+ case "load": {
4049
+ const startHandler = () => start();
4050
+ if (document.readyState === "complete") {
4051
+ startHandler();
4052
+ } else {
4053
+ window.addEventListener("load", startHandler, { once: true });
4054
+ }
4055
+ break;
4056
+ }
4057
+ case "mouseOver": {
4058
+ const mouseOverHandler = () => start();
4059
+ const mouseOutHandler = () => handleEndAction();
4060
+ root.addEventListener("mouseenter", mouseOverHandler);
4061
+ root.addEventListener("mouseleave", mouseOutHandler);
4062
+ break;
2662
4063
  }
4064
+ case "click": {
4065
+ const clickHandler = () => {
4066
+ if (api.isPlaying()) {
4067
+ handleEndAction();
4068
+ } else {
4069
+ start();
4070
+ }
4071
+ };
4072
+ root.addEventListener("click", clickHandler);
4073
+ break;
4074
+ }
4075
+ case "scrollIntoView": {
4076
+ const observer = new IntersectionObserver(
4077
+ (entries) => {
4078
+ entries.forEach((entry) => {
4079
+ if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
4080
+ start();
4081
+ } else {
4082
+ handleEndAction();
4083
+ }
4084
+ });
4085
+ },
4086
+ { threshold: scrollIntoViewThreshold }
4087
+ );
4088
+ observer.observe(root);
4089
+ break;
4090
+ }
4091
+ case "programmatic":
4092
+ break;
2663
4093
  }
2664
- return result;
4094
+ return api;
2665
4095
  }
2666
4096
 
2667
4097
  // src/PxAnimatorFrameLoop.ts
@@ -2670,7 +4100,7 @@ function getSelector(id) {
2670
4100
  }
2671
4101
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
2672
4102
  const config = getAnimatorConfig(doc) || {};
2673
- const bindings = getNormalisedBindings(doc);
4103
+ const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
2674
4104
  const _iterations = config.iterations;
2675
4105
  let iterations = 1;
2676
4106
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -2788,6 +4218,10 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
2788
4218
  };
2789
4219
  const startAnim = () => {
2790
4220
  if (playing) return;
4221
+ if (Number.isFinite(totalDuration) && timeBeforeLastStartMs >= totalDuration) {
4222
+ timeBeforeLastStartMs = 0;
4223
+ finishCalled = false;
4224
+ }
2791
4225
  playing = true;
2792
4226
  lastStartedTs = Date.now();
2793
4227
  loopAnim(true);
@@ -3020,7 +4454,6 @@ function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
3020
4454
  function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs) {
3021
4455
  var _a;
3022
4456
  const config = getAnimatorConfig(doc) || {};
3023
- const bindings = getNormalisedBindings(doc);
3024
4457
  if (!rootElement) {
3025
4458
  if (doc.id) {
3026
4459
  const rootSelector = getSelector(doc.id);
@@ -3030,6 +4463,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
3030
4463
  console.warn("createFrameLoopAnimator: No root element provided");
3031
4464
  }
3032
4465
  }
4466
+ const bindings = getNormalisedBindings(doc, PxAnimatorEngine.webapi);
3033
4467
  const animations = [];
3034
4468
  const _iterations = config.iterations;
3035
4469
  let iterations;
@@ -3161,15 +4595,15 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
3161
4595
  function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
3162
4596
  const animatorConfig = getAnimatorConfig(doc) || {};
3163
4597
  let res;
3164
- if (animatorConfig.mode === "frames") {
4598
+ if (animatorConfig.mode === PxAnimatorMode.frames) {
3165
4599
  res = createFrameLoopAnimator(doc, adapter, callbacks, rootElement);
3166
4600
  } else {
3167
4601
  res = createWebApiAnimator(
3168
4602
  doc,
3169
4603
  callbacks,
3170
4604
  rootElement,
3171
- animatorConfig.mode === "webapi"
3172
- // Forcing "webapi"
4605
+ animatorConfig.mode === PxAnimatorMode.webapi
4606
+ // forcing webapi
3173
4607
  ) || createFrameLoopAnimator(doc, adapter, callbacks, rootElement);
3174
4608
  }
3175
4609
  if (animatorConfig.debugInstName) {
@@ -3291,9 +4725,10 @@ function replaceUrlRefs(value, idMap) {
3291
4725
  function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
3292
4726
  const effectsWarnings = validateNodeEffects(doc);
3293
4727
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
3294
- doc = applyPlayerEffects(doc).root;
3295
4728
  const animatorConfig = getAnimatorConfig(doc) || {};
3296
4729
  animatorConfig.debug = true;
4730
+ const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
4731
+ doc = materialiseAllInTree(doc, engine);
3297
4732
  let rootElement = null;
3298
4733
  if (containerElement && doc.children) {
3299
4734
  doc = generateNewIds(doc);
@@ -3470,10 +4905,10 @@ function evalScalar(animated, staticVal, fallback, t) {
3470
4905
  }
3471
4906
  var CONTAINER_TYPES = /* @__PURE__ */ new Set(["svg", "g", "symbol"]);
3472
4907
  var SKIP_TYPES = /* @__PURE__ */ new Set(["defs", "mask", "clipPath", "title"]);
3473
- function buildIdMap(node, map) {
4908
+ function buildIdMap2(node, map) {
3474
4909
  var _a;
3475
4910
  if (typeof node.id === "string") map.set(node.id, node);
3476
- (_a = node.children) == null ? void 0 : _a.forEach((c) => buildIdMap(c, map));
4911
+ (_a = node.children) == null ? void 0 : _a.forEach((c) => buildIdMap2(c, map));
3477
4912
  }
3478
4913
  function num(v) {
3479
4914
  return v === void 0 || v === null ? 0 : Number(v);
@@ -3550,7 +4985,7 @@ function collectSampleTimes(node, into) {
3550
4985
  }
3551
4986
  function visualModelAt(root, t) {
3552
4987
  const idMap = /* @__PURE__ */ new Map();
3553
- buildIdMap(root, idMap);
4988
+ buildIdMap2(root, idMap);
3554
4989
  const out = [];
3555
4990
  flatten(root, IDENTITY, t, idMap, out);
3556
4991
  return out.sort();
@@ -3590,6 +5025,8 @@ function subtractMultiset(a, b) {
3590
5025
  PxAnimatedSvgDocumentSchema,
3591
5026
  PxAnimationDefinitionSchema,
3592
5027
  PxAnimatorConfigSchema,
5028
+ PxAnimatorEngine,
5029
+ PxAnimatorMode,
3593
5030
  PxAttrValueSchema,
3594
5031
  PxBezierPathSchema,
3595
5032
  PxBindingSchema,
@@ -3597,6 +5034,11 @@ function subtractMultiset(a, b) {
3597
5034
  PxEasingOrRefSchema,
3598
5035
  PxEffectsSchema,
3599
5036
  PxElementAnimationSchema,
5037
+ PxFillGradientEffectSchema,
5038
+ PxGradientSpreadMethod,
5039
+ PxGradientStopSchema,
5040
+ PxGradientType,
5041
+ PxGradientUnits,
3600
5042
  PxKeyframeSchema,
3601
5043
  PxLoopSchema,
3602
5044
  PxMaskedByEffectSchema,
@@ -3606,7 +5048,9 @@ function subtractMultiset(a, b) {
3606
5048
  PxRefEffectSchema,
3607
5049
  PxRepeaterEffectSchema,
3608
5050
  PxRetimeEffectSchema,
5051
+ PxStrokeGradientEffectSchema,
3609
5052
  PxSvgNodeExtra,
5053
+ PxTextAlongPathEffectSchema,
3610
5054
  PxTransformPartsSchema,
3611
5055
  PxTransformValueSchema,
3612
5056
  PxTransformationEffectSchema,
@@ -3625,6 +5069,7 @@ function subtractMultiset(a, b) {
3625
5069
  createWebApiAnimator,
3626
5070
  describeSchema,
3627
5071
  diffInEffect,
5072
+ evaluateMotionPathSegment,
3628
5073
  generateNewIds,
3629
5074
  getAnimatorConfig,
3630
5075
  getBindings,
@@ -3634,7 +5079,14 @@ function subtractMultiset(a, b) {
3634
5079
  isPxElementFileFormat,
3635
5080
  isPxElementFileFormatDeep,
3636
5081
  loadTagAnimators,
5082
+ materialiseAllInTree,
5083
+ materialiseAnimatedUseInstances,
5084
+ materialiseInternalLoopsInPropAnim,
5085
+ materialiseInternalLoopsInTree,
5086
+ materialiseMotionPathInPropAnim,
5087
+ materialiseMotionPathsInTree,
3637
5088
  normalizeDocument,
5089
+ propAnimIsMotionPath,
3638
5090
  px,
3639
5091
  renderNode,
3640
5092
  schemaKeys,