@pixodesk/svg-animator-web 1.0.21 → 1.0.24

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.js CHANGED
@@ -184,8 +184,9 @@ var Union = class extends Base {
184
184
  }
185
185
  isValid(raw, ctx, path) {
186
186
  var _a;
187
- if (this.schemas.some((s) => s.isValid(raw))) return true;
188
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a = JSON.stringify(raw)) != null ? _a : "").slice(0, 60));
187
+ const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
188
+ if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
189
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a = JSON.stringify(raw)) != null ? _a : "").slice(0, 240));
189
190
  return false;
190
191
  }
191
192
  _canSanitize(raw) {
@@ -261,6 +262,7 @@ var Obj = class extends Base {
261
262
  if (ctx == null ? void 0 : ctx.strict) {
262
263
  for (const key of Object.keys(obj)) {
263
264
  if (key in this._shape) continue;
265
+ if (obj[key] === void 0) continue;
264
266
  p.push(key);
265
267
  ctx.errors.push(pathStr(p) + ": unexpected extra key");
266
268
  p.pop();
@@ -401,6 +403,23 @@ var Any = class extends Base {
401
403
  return true;
402
404
  }
403
405
  };
406
+ var Defined = class extends Base {
407
+ constructor() {
408
+ super(...arguments);
409
+ this._default = void 0;
410
+ }
411
+ sanitize(raw) {
412
+ return raw;
413
+ }
414
+ isValid(raw, ctx, path) {
415
+ if (raw !== void 0) return true;
416
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": required value is missing");
417
+ return false;
418
+ }
419
+ _canSanitize(raw) {
420
+ return raw !== void 0;
421
+ }
422
+ };
404
423
  var Lazy = class extends Base {
405
424
  constructor(fn, _default) {
406
425
  super();
@@ -512,6 +531,8 @@ var px = {
512
531
  record: (value) => new Rec(value),
513
532
  /** Passes anything through unchanged — always valid. */
514
533
  any: () => new Any(),
534
+ /** Anything EXCEPT `undefined` — an open type whose presence is required (V6). */
535
+ defined: () => new Defined(),
515
536
  /** Fixed-length tuple — validates element count and each position individually. */
516
537
  tuple: (schemas) => new Tuple(schemas),
517
538
  /** Defers schema creation — required for recursive types. Must supply a default value. */
@@ -521,13 +542,52 @@ var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
521
542
  var PX_ANIM_ATTR_NAME = "_px_animator";
522
543
  var PxAnimatorMode = {
523
544
  auto: "auto",
524
- webapi: "webapi",
545
+ waapi: "waapi",
525
546
  frames: "frames"
526
547
  };
527
548
  var PxAnimatorEngine = {
528
- webapi: PxAnimatorMode.webapi,
549
+ waapi: PxAnimatorMode.waapi,
529
550
  frames: PxAnimatorMode.frames
530
551
  };
552
+ var PxLoopExtend = {
553
+ /** Segment from the START; the animation is extended BEFORE the first keyframe
554
+ * (intro loops that run before the main timeline begins). */
555
+ before: "before",
556
+ /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
557
+ * loops that continue once the main timeline has finished). */
558
+ after: "after"
559
+ };
560
+ var PxMaskType = {
561
+ luminance: "luminance",
562
+ alpha: "alpha"
563
+ };
564
+ var PxUnits = {
565
+ userSpaceOnUse: "userSpaceOnUse",
566
+ objectBoundingBox: "objectBoundingBox"
567
+ };
568
+ var PxCloneType = {
569
+ content: "content"
570
+ };
571
+ var PxPathOverflow = {
572
+ clip: "clip",
573
+ extend: "extend"
574
+ };
575
+ var PxLengthAdjust = {
576
+ spacing: "spacing",
577
+ spacingAndGlyphs: "spacingAndGlyphs"
578
+ };
579
+ var PxTextPathMethod = {
580
+ align: "align",
581
+ stretch: "stretch"
582
+ };
583
+ var PxTextPathSpacing = {
584
+ auto: "auto",
585
+ exact: "exact"
586
+ };
587
+ var PxTrimSubPaths = {
588
+ separate: "separate",
589
+ combined: "combined"
590
+ };
531
591
  var TEXT_ATTR = "text";
532
592
  var TEXT_CONTENT_ATTR = "textContent";
533
593
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
@@ -536,9 +596,49 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
536
596
  "animator",
537
597
  "meta",
538
598
  "animate",
599
+ "effects",
539
600
  TEXT_ATTR,
540
601
  TEXT_CONTENT_ATTR
541
602
  ]);
603
+ var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
604
+ var PxGradientUnits = {
605
+ userSpaceOnUse: "userSpaceOnUse",
606
+ objectBoundingBox: "objectBoundingBox"
607
+ };
608
+ var PxGradientSpreadMethod = {
609
+ pad: "pad",
610
+ reflect: "reflect",
611
+ repeat: "repeat"
612
+ };
613
+ var PxGradientType = {
614
+ linear: "linear",
615
+ radial: "radial"
616
+ };
617
+ function isPxElementFileFormat(fileJson) {
618
+ if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
619
+ return false;
620
+ }
621
+ return fileJson["type"] === "svg";
622
+ }
623
+ function getAnimatorConfig(doc) {
624
+ var _a;
625
+ return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
626
+ }
627
+ function getDefs(doc) {
628
+ var _a;
629
+ if (!doc) return void 0;
630
+ return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
631
+ }
632
+ function getBindings(doc) {
633
+ var _a;
634
+ if (!doc) return void 0;
635
+ const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
636
+ if (!animateById) return void 0;
637
+ return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));
638
+ }
639
+ function getChildren(doc) {
640
+ return doc == null ? void 0 : doc.children;
641
+ }
542
642
  var PxEasingOrRefSchema = px.union([
543
643
  px.string(),
544
644
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -550,13 +650,15 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
550
650
  px.array(px.number()),
551
651
  px.lazy(() => PxTransformPartsSchema, {}),
552
652
  px.object({ path: px.string() }),
553
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] })
653
+ px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
654
+ // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
655
+ px.lazy(() => px.array(PxGradientStopSchema), [])
554
656
  ]));
555
657
  var PxKeyframeSchema = implementsInterface()(px.object({
556
658
  time: px.number().optional(),
557
659
  t: px.number().optional(),
558
- value: px.any().optional(),
559
- v: px.any().optional(),
660
+ value: PxKeyframeValueSchema.optional(),
661
+ v: PxKeyframeValueSchema.optional(),
560
662
  easing: PxEasingOrRefSchema.optional(),
561
663
  e: PxEasingOrRefSchema.optional(),
562
664
  tangentOut: px.tuple([px.number(), px.number()]).optional(),
@@ -570,16 +672,16 @@ var PxKeyframeSchema = implementsInterface()(px.object({
570
672
  }));
571
673
  var PxLoopSchema = implementsInterface()(px.object({
572
674
  segmentCount: px.number().optional(),
573
- before: px.boolean().optional(),
675
+ extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
574
676
  alternate: px.boolean().optional()
575
677
  }));
576
678
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
679
+ value: PxKeyframeValueSchema.optional(),
577
680
  keyframes: px.array(PxKeyframeSchema).optional(),
578
681
  kfs: px.array(PxKeyframeSchema).optional(),
579
682
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
580
683
  autoOrient: px.boolean().optional()
581
684
  }));
582
- var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
583
685
  var PxTransformPartsSchema = implementsInterface()(px.object({
584
686
  translate: px.tuple([px.number(), px.number()]).optional(),
585
687
  rotate: px.number().optional(),
@@ -589,6 +691,7 @@ var PxTransformPartsSchema = implementsInterface()(px.object({
589
691
  }));
590
692
  var PxTransformValueSchema = px.union([
591
693
  px.string(),
694
+ PxTransformPartsSchema,
592
695
  px.object({ value: PxTransformPartsSchema }),
593
696
  PxPropertyAnimationSchema
594
697
  ]);
@@ -623,9 +726,11 @@ var PxDefsSchema = implementsInterface()(px.object({
623
726
  glyphs: px.record(PxGlyphFontSchema).optional()
624
727
  }));
625
728
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
626
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
729
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
627
730
  duration: px.number().optional(),
628
731
  delay: px.number().optional(),
732
+ // LAW (SCHEMA-DESIGN R3, S10): the ONE sanctioned string-in-number union
733
+ // (CSS animation-iteration-count familiarity) — do not add more mixed unions.
629
734
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
630
735
  fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
631
736
  direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
@@ -633,8 +738,8 @@ var PxAnimatorConfigSchema = implementsInterface()(px.object({
633
738
  trigger: PxTriggerSchema.optional(),
634
739
  resetOnFinish: px.boolean().optional(),
635
740
  definitions: PxDefsSchema.optional(),
636
- animate: px.record(PxElementAnimationSchema).optional(),
637
- debug: px.boolean().optional(),
741
+ animateById: px.record(PxElementAnimationSchema).optional(),
742
+ timelineSource: px.string().optional(),
638
743
  debugInstName: px.string().optional()
639
744
  }));
640
745
  var PxBindingSchema = implementsInterface()(px.object({
@@ -644,26 +749,29 @@ var PxBindingSchema = implementsInterface()(px.object({
644
749
  var PxAttrValueSchema = px.union([
645
750
  px.string(),
646
751
  px.number(),
647
- px.object({ value: px.any() }),
648
- PxPropertyAnimationSchema
752
+ px.array(px.number()),
753
+ // Structured static — `{value: …}` (read-accepted transitional spelling, S1).
754
+ // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).
755
+ px.object({ value: px.defined() }),
756
+ // Bare transform parts record — the canonical static `transform` on the wire (T2).
757
+ PxTransformPartsSchema
649
758
  ]);
650
759
  var PxAnimatableNumberSchema = px.union([
651
760
  px.number(),
652
761
  px.object({ value: px.number() }),
653
- px.object({
654
- keyframes: px.array(PxKeyframeSchema),
655
- autoOrient: px.boolean().optional()
656
- })
762
+ PxPropertyAnimationSchema
657
763
  ]);
658
764
  var PxAnimatableVec2Schema = px.union([
659
765
  px.tuple([px.number(), px.number()]),
660
766
  px.object({ value: px.tuple([px.number(), px.number()]) }),
661
- px.object({
662
- keyframes: px.array(PxKeyframeSchema),
663
- autoOrient: px.boolean().optional()
664
- })
767
+ PxPropertyAnimationSchema
665
768
  ]);
666
- var PxTransformationEffectSchema = implementsInterface()(px.object({
769
+ var PxAnimatableStringSchema = px.union([
770
+ px.string(),
771
+ px.object({ value: px.string() }),
772
+ PxPropertyAnimationSchema
773
+ ]);
774
+ var PxTransformByEffectSchema = implementsInterface()(px.object({
667
775
  translate: PxAnimatableVec2Schema.optional(),
668
776
  rotate: PxAnimatableNumberSchema.optional(),
669
777
  scale: PxAnimatableVec2Schema.optional(),
@@ -671,51 +779,46 @@ var PxTransformationEffectSchema = implementsInterface()(px.object({
671
779
  origin: PxAnimatableVec2Schema.optional()
672
780
  }));
673
781
  var PxRepeaterEffectSchema = implementsInterface()(px.object({
782
+ // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
783
+ // once at expansion time and never sampled — plain number, no `keyframes`.
674
784
  copies: px.number().optional(),
675
785
  translate: PxAnimatableVec2Schema.optional(),
676
786
  rotate: PxAnimatableNumberSchema.optional(),
787
+ skew: PxAnimatableNumberSchema.optional(),
677
788
  scale: PxAnimatableVec2Schema.optional(),
678
789
  origin: PxAnimatableVec2Schema.optional()
679
790
  }));
680
791
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
681
- href: px.string().optional(),
682
- maskType: px.string().optional(),
683
- maskUnits: px.string().optional(),
684
- maskContentUnits: px.string().optional()
792
+ sourceId: px.string().optional(),
793
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
794
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
795
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
796
+ x: px.number().optional(),
797
+ y: px.number().optional(),
798
+ width: px.number().optional(),
799
+ height: px.number().optional()
685
800
  }));
686
801
  var PxClipPathEffectSchema = implementsInterface()(px.object({
687
- d: px.string().optional(),
802
+ d: PxAnimatableStringSchema.optional(),
688
803
  animate: PxPropertyAnimationSchema.optional()
689
804
  }));
690
805
  var PxTrimPathEffectSchema = implementsInterface()(px.object({
691
806
  offset: PxAnimatableNumberSchema.optional(),
692
807
  range: PxAnimatableVec2Schema.optional(),
693
- trimAllAsOne: px.boolean().optional()
808
+ subPaths: px.enum([PxTrimSubPaths.separate, PxTrimSubPaths.combined]).optional()
694
809
  }));
695
810
  var PxRetimeEffectSchema = implementsInterface()(px.object({
696
- baseId: px.string().optional(),
811
+ sourceId: px.string().optional(),
697
812
  start: px.number().optional(),
698
813
  stretch: px.number().optional(),
699
814
  timeCrop: px.tuple([px.number(), px.number()]).optional()
700
815
  }));
701
816
  var PxCloneEffectSchema = implementsInterface()(px.object({
702
- type: px.string().optional(),
703
- baseId: px.string().optional(),
817
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
818
+ type: px.enum([PxCloneType.content]).optional(),
819
+ sourceId: px.string().optional(),
704
820
  retime: PxRetimeEffectSchema.optional()
705
821
  }));
706
- var PxGradientUnits = {
707
- userSpaceOnUse: "userSpaceOnUse",
708
- objectBoundingBox: "objectBoundingBox"
709
- };
710
- var PxGradientSpreadMethod = {
711
- pad: "pad",
712
- reflect: "reflect",
713
- repeat: "repeat"
714
- };
715
- var PxGradientType = {
716
- linear: "linear",
717
- radial: "radial"
718
- };
719
822
  var PxGradientStopSchema = implementsInterface()(px.object({
720
823
  offset: px.number(),
721
824
  color: px.string()
@@ -723,27 +826,28 @@ var PxGradientStopSchema = implementsInterface()(px.object({
723
826
  var PxAnimatableGradientStopsSchema = px.union([
724
827
  px.array(PxGradientStopSchema),
725
828
  px.object({ value: px.array(PxGradientStopSchema) }),
726
- px.object({ keyframes: px.array(PxKeyframeSchema) })
829
+ PxPropertyAnimationSchema
727
830
  ]);
728
831
  var PxFillGradientEffectSchema = implementsInterface()(px.object({
832
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
729
833
  type: px.enum([PxGradientType.linear, PxGradientType.radial]),
730
- p1: px.tuple([px.number(), px.number()]).optional(),
731
- p2: px.tuple([px.number(), px.number()]).optional(),
732
- c: px.tuple([px.number(), px.number()]).optional(),
733
- r: px.number().optional(),
734
- fp: px.tuple([px.number(), px.number()]).optional(),
834
+ p1: PxAnimatableVec2Schema.optional(),
835
+ p2: PxAnimatableVec2Schema.optional(),
836
+ c: PxAnimatableVec2Schema.optional(),
837
+ r: PxAnimatableNumberSchema.optional(),
838
+ fp: PxAnimatableVec2Schema.optional(),
735
839
  stops: PxAnimatableGradientStopsSchema.optional(),
736
- gradientUnits: px.string().optional(),
737
- spreadMethod: px.string().optional(),
840
+ gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
841
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
738
842
  gradientTransform: px.string().optional()
739
843
  }));
740
844
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
741
845
  var PxTextPathEffectSchema = implementsInterface()(px.object({
742
846
  path: px.string(),
743
- pathOverflow: px.string().optional(),
744
- lengthAdjust: px.string().optional(),
745
- method: px.string().optional(),
746
- spacing: px.string().optional(),
847
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
848
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
849
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
850
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
747
851
  startOffset: PxAnimatableNumberSchema.optional(),
748
852
  textLength: PxAnimatableNumberSchema.optional()
749
853
  }));
@@ -751,13 +855,12 @@ var PxTextEffectSchema = implementsInterface()(px.object({
751
855
  useGlyphs: px.boolean().optional()
752
856
  }));
753
857
  var PxEffectsSchema = implementsInterface()(px.object({
754
- transformation: PxTransformationEffectSchema.optional(),
858
+ transformBy: PxTransformByEffectSchema.optional(),
755
859
  repeater: PxRepeaterEffectSchema.optional(),
756
860
  maskedBy: PxMaskedByEffectSchema.optional(),
757
861
  clipPath: PxClipPathEffectSchema.optional(),
758
862
  trimPath: PxTrimPathEffectSchema.optional(),
759
863
  clone: PxCloneEffectSchema.optional(),
760
- isCombinedShape: px.boolean().optional(),
761
864
  fillGradient: PxFillGradientEffectSchema.optional(),
762
865
  strokeGradient: PxStrokeGradientEffectSchema.optional(),
763
866
  textPath: PxTextPathEffectSchema.optional(),
@@ -781,6 +884,14 @@ function validateNodeEffects(root, opts) {
781
884
  return warnings;
782
885
  }
783
886
  var PxNodeBase = px.openObject({
887
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
888
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
889
+ // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
890
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
891
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
892
+ // would add words that all mean "type" and still need the carrier to read.
893
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
894
+ // (issues V3), never of distinct key names.
784
895
  type: px.string(),
785
896
  id: px.string().optional(),
786
897
  meta: px.any().optional(),
@@ -790,7 +901,7 @@ var PxNodeBase = px.openObject({
790
901
  effects: PxEffectsSchema.optional(),
791
902
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
792
903
  // string ref / array of refs / inline definition / mixed array; mirrors
793
- // `animator.animate` map values and what `processNode` resolves at runtime.
904
+ // `animator.animateById` map values and what `processNode` resolves at runtime.
794
905
  animate: PxElementAnimationSchema.optional(),
795
906
  style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
796
907
  }, PxAttrValueSchema);
@@ -814,35 +925,10 @@ var PxBezierPathSchema = implementsInterface()(px.object({
814
925
  o: px.array(px.array(px.number())).optional(),
815
926
  c: px.boolean().optional()
816
927
  }));
817
- function isPxElementFileFormat(fileJson) {
818
- if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
819
- return false;
820
- }
821
- return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
822
- }
823
928
  function isPxElementFileFormatDeep(fileJson) {
824
929
  const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
825
930
  return { valid, errors: valid ? [] : ["Document failed schema validation"] };
826
931
  }
827
- function getAnimatorConfig(doc) {
828
- var _a, _b;
829
- return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator) || (doc == null ? void 0 : doc.animation) || ((_b = doc == null ? void 0 : doc.meta) == null ? void 0 : _b.animation);
830
- }
831
- function getDefs(doc) {
832
- var _a;
833
- if (!doc) return void 0;
834
- return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
835
- }
836
- function getBindings(doc) {
837
- var _a;
838
- if (!doc) return void 0;
839
- const animate = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animate;
840
- if (!animate) return void 0;
841
- return Object.entries(animate).map(([id, anim]) => ({ id, animate: anim }));
842
- }
843
- function getChildren(doc) {
844
- return doc == null ? void 0 : doc.children;
845
- }
846
932
  function bezierToSvgPath(path, forceCurves = false) {
847
933
  var _a, _b, _c, _d;
848
934
  const v = path.v;
@@ -1293,7 +1379,7 @@ function generateNewIds(doc) {
1293
1379
  "flood-color",
1294
1380
  "lighting-color"
1295
1381
  ]);
1296
- const directIdRefAttrs = /* @__PURE__ */ new Set(["baseId", "targetId", "boundElementId"]);
1382
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
1297
1383
  function collectIds(node) {
1298
1384
  if (!node || typeof node !== "object") return;
1299
1385
  if (node.id && typeof node.id === "string") {
@@ -1331,9 +1417,10 @@ function generateNewIds(doc) {
1331
1417
  } else if (urlRefAttrs.has(key)) {
1332
1418
  node[key] = replaceUrlRefs(value, idMap);
1333
1419
  } else if (directIdRefAttrs.has(key)) {
1334
- const newId = idMap.get(value);
1420
+ const hasHash = value.startsWith("#");
1421
+ const newId = idMap.get(hasHash ? value.slice(1) : value);
1335
1422
  if (newId) {
1336
- node[key] = newId;
1423
+ node[key] = hasHash ? "#" + newId : newId;
1337
1424
  }
1338
1425
  } else if (value.includes("url(#")) {
1339
1426
  node[key] = replaceUrlRefs(value, idMap);
@@ -1351,14 +1438,14 @@ function generateNewIds(doc) {
1351
1438
  }
1352
1439
  collectIds(cloned);
1353
1440
  updateRefs(cloned);
1354
- const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animate;
1441
+ const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
1355
1442
  if (docAnimate && typeof docAnimate === "object") {
1356
1443
  const updatedAnimate = {};
1357
1444
  for (const [id, anim] of Object.entries(docAnimate)) {
1358
1445
  const newId = (_b = idMap.get(id)) != null ? _b : id;
1359
1446
  updatedAnimate[newId] = anim;
1360
1447
  }
1361
- cloned.animator = __spreadProps2(__spreadValues2({}, cloned.animator), { animate: updatedAnimate });
1448
+ cloned.animator = __spreadProps2(__spreadValues2({}, cloned.animator), { animateById: updatedAnimate });
1362
1449
  }
1363
1450
  return cloned;
1364
1451
  }
@@ -1447,8 +1534,9 @@ function getNormalizedProps(props) {
1447
1534
  let value = props[rawKey];
1448
1535
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1449
1536
  propsCopy[key] = toRGBA(value);
1450
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
1451
- propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
1537
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes && !value.kfs) {
1538
+ const parts = value.value && typeof value.value === "object" ? value.value : value;
1539
+ propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
1452
1540
  } else if (TRANSFORM_FN_NAMES.has(key)) {
1453
1541
  if (Array.isArray(value)) {
1454
1542
  if (key === "translate") value = value.map((v) => v + "px");
@@ -1456,6 +1544,8 @@ function getNormalizedProps(props) {
1456
1544
  }
1457
1545
  if (key === "rotate") value = value + "deg";
1458
1546
  propsCopy["transform"] = key + "(" + value + ")";
1547
+ } else if (Array.isArray(value)) {
1548
+ propsCopy[key] = value.join(",");
1459
1549
  } else if (value !== void 0 && value !== null) {
1460
1550
  propsCopy[key] = String(value);
1461
1551
  }
@@ -1853,6 +1943,16 @@ function walkAndMaterialise(node, opts) {
1853
1943
  if (newAnimate) cloned.animate = newAnimate;
1854
1944
  return cloned;
1855
1945
  }
1946
+ var LOOP_JUMP_SHIFT_MS = 10;
1947
+ function deepEqualValue(a, b) {
1948
+ if (a === b) return true;
1949
+ if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
1950
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
1951
+ const ka = Object.keys(a);
1952
+ const kb = Object.keys(b);
1953
+ if (ka.length !== kb.length) return false;
1954
+ return ka.every((k) => deepEqualValue(a[k], b[k]));
1955
+ }
1856
1956
  function parsePathCommands(d) {
1857
1957
  const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
1858
1958
  const commands = [];
@@ -2055,7 +2155,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2055
2155
  const totalIntervals = keyframes.length - 1;
2056
2156
  const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2057
2157
  let segKfs;
2058
- if (loop.before) {
2158
+ if (loop.extend === PxLoopExtend.before) {
2059
2159
  segKfs = keyframes.slice(0, segCount + 1);
2060
2160
  } else {
2061
2161
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -2063,7 +2163,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2063
2163
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2064
2164
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2065
2165
  let fillStart, fillEnd;
2066
- if (loop.before) {
2166
+ if (loop.extend === PxLoopExtend.before) {
2067
2167
  fillStart = 0;
2068
2168
  fillEnd = firstT;
2069
2169
  } else {
@@ -2090,7 +2190,10 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2090
2190
  const remainder = fillDuration - fullReps * segDuration;
2091
2191
  const partialFraction = remainder / segDuration;
2092
2192
  const looped = [];
2193
+ const separateBoundary = loop.extend !== PxLoopExtend.before;
2194
+ const originalTerminalKf = keyframes[keyframes.length - 1];
2093
2195
  function appendRep(repStart, isReversed, partial) {
2196
+ var _a2;
2094
2197
  let entries;
2095
2198
  if (isReversed) {
2096
2199
  entries = [];
@@ -2126,8 +2229,17 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2126
2229
  looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
2127
2230
  return;
2128
2231
  }
2232
+ const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2233
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2234
+ if (isBoundary) {
2235
+ if (deepEqualValue(prevKf.v, entry.v)) continue;
2236
+ if (looped.length > 0) {
2237
+ delete prevKf.tangentIn;
2238
+ delete prevKf.tangentOut;
2239
+ }
2240
+ }
2129
2241
  const pushed = {
2130
- t: repStart + entry.relT * segDuration,
2242
+ t: repStart + entry.relT * segDuration + (isBoundary ? LOOP_JUMP_SHIFT_MS : 0),
2131
2243
  v: entry.v,
2132
2244
  e: i < entries.length - 1 ? entry.e : void 0
2133
2245
  };
@@ -2175,7 +2287,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2175
2287
  looped.push(pushed);
2176
2288
  }
2177
2289
  }
2178
- if (loop.before) {
2290
+ if (loop.extend === PxLoopExtend.before) {
2179
2291
  if (partialFraction > 1e-9) {
2180
2292
  const isReversed = !!loop.alternate && fullReps % 2 === 0;
2181
2293
  appendRepTail(fillStart, isReversed, partialFraction);
@@ -2198,7 +2310,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2198
2310
  appendRep(repStart, isReversed, partialFraction);
2199
2311
  }
2200
2312
  }
2201
- if (loop.before) {
2313
+ if (loop.extend === PxLoopExtend.before) {
2202
2314
  return [...looped, ...keyframes];
2203
2315
  } else {
2204
2316
  return [...keyframes, ...looped];
@@ -2314,7 +2426,7 @@ var _elementIdCounter = 0;
2314
2426
  function generateElementId() {
2315
2427
  return "_px_el_" + ++_elementIdCounter;
2316
2428
  }
2317
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.webapi) {
2429
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2318
2430
  const normalized = {};
2319
2431
  for (const [propName, propAnim] of Object.entries(animDef)) {
2320
2432
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
@@ -2322,12 +2434,12 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimat
2322
2434
  const out = { kfs: normalizedKfs };
2323
2435
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2324
2436
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2325
- normalized[propName] = engine === PxAnimatorEngine.webapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2437
+ normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2326
2438
  }
2327
2439
  }
2328
2440
  return normalized;
2329
2441
  }
2330
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.webapi) {
2442
+ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2331
2443
  const animatorConfig = getAnimatorConfig(doc) || {};
2332
2444
  const defs = getDefs(doc);
2333
2445
  const duration = animatorConfig.duration || 1e3;
@@ -2732,6 +2844,7 @@ function partsRecord(part, value, origin) {
2732
2844
  return rec;
2733
2845
  }
2734
2846
  function readAnimatable(raw) {
2847
+ var _a, _b, _c;
2735
2848
  if (raw === void 0) return {
2736
2849
  kind: "absent"
2737
2850
  /* Absent */
@@ -2739,19 +2852,56 @@ function readAnimatable(raw) {
2739
2852
  if (Array.isArray(raw)) return { kind: "static", value: raw };
2740
2853
  if (typeof raw === "object") {
2741
2854
  const obj = raw;
2742
- if (obj.keyframes) {
2743
- return { kind: "animated", keyframes: obj.keyframes, autoOrient: obj.autoOrient, loop: obj.loop };
2855
+ const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
2856
+ if (kfs) {
2857
+ const out = { kind: "animated", keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
2858
+ const base = (_b = obj.value) != null ? _b : obj.v;
2859
+ if (base !== void 0 && out.kind === "animated") out.base = base;
2860
+ return out;
2744
2861
  }
2745
- if (obj.value !== void 0) return { kind: "static", value: obj.value };
2862
+ const staticValue = (_c = obj.value) != null ? _c : obj.v;
2863
+ if (staticValue !== void 0) return { kind: "static", value: staticValue };
2746
2864
  }
2747
2865
  return { kind: "static", value: raw };
2748
2866
  }
2867
+ function writeAnimatableChannel(node, attrName, read, opts) {
2868
+ var _a, _b, _c, _d;
2869
+ const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
2870
+ if (read.kind === "absent") return;
2871
+ if (read.kind === "static") {
2872
+ node[attrName] = toOut(read.value);
2873
+ return;
2874
+ }
2875
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
2876
+ const animate = __spreadValues2({}, prevAnimate || {});
2877
+ const block = { keyframes: read.keyframes };
2878
+ if (read.loop !== void 0) block.loop = read.loop;
2879
+ if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
2880
+ animate[attrName] = block;
2881
+ node.animate = animate;
2882
+ const baseline = (_d = (_b = read.base) != null ? _b : (_a = read.keyframes[0]) == null ? void 0 : _a.value) != null ? _d : (_c = read.keyframes[0]) == null ? void 0 : _c.v;
2883
+ if (baseline !== void 0) node[attrName] = toOut(baseline);
2884
+ }
2885
+ function normaliseKeyframe(kf) {
2886
+ if (!kf || typeof kf !== "object") return kf;
2887
+ const k = kf;
2888
+ if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
2889
+ return kf;
2890
+ }
2891
+ const out = __spreadValues2({}, k);
2892
+ if (out.time === void 0 && k.t !== void 0) out.time = k.t;
2893
+ if (out.value === void 0 && k.v !== void 0) out.value = k.v;
2894
+ if (out.easing === void 0 && k.e !== void 0) out.easing = k.e;
2895
+ if (out.tangentOut === void 0 && k.to !== void 0) out.tangentOut = k.to;
2896
+ if (out.tangentIn === void 0 && k.ti !== void 0) out.tangentIn = k.ti;
2897
+ return out;
2898
+ }
2749
2899
  function readStaticOrigin(raw, ctx) {
2750
2900
  var _a;
2751
2901
  const o = readAnimatable(raw);
2752
2902
  if (o.kind === "absent") return void 0;
2753
2903
  if (o.kind === "static") return o.value;
2754
- ctx.warnings.push("transformation.origin: animated origin approximated by its first keyframe");
2904
+ ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
2755
2905
  return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
2756
2906
  }
2757
2907
  function keyframeWith(kf, value) {
@@ -2762,7 +2912,7 @@ function keyframeWith(kf, value) {
2762
2912
  if (kf.tangentIn !== void 0) out.tangentIn = kf.tangentIn;
2763
2913
  return out;
2764
2914
  }
2765
- function applyTransformationEffect(node, fx, ctx) {
2915
+ function applyTransformByEffect(node, fx, ctx) {
2766
2916
  if (!fx) return node;
2767
2917
  delete node.transform;
2768
2918
  let n = node;
@@ -2798,6 +2948,10 @@ function applyTransformationEffect(node, fx, ctx) {
2798
2948
  } else {
2799
2949
  n = wrapTransformPart(n, "translate", fx.translate, ctx);
2800
2950
  }
2951
+ if (n !== node && node.id) {
2952
+ n.id = node.id;
2953
+ delete node.id;
2954
+ }
2801
2955
  return n;
2802
2956
  }
2803
2957
  function translateHasAutoOrient(translate) {
@@ -2807,8 +2961,6 @@ function translateHasAutoOrient(translate) {
2807
2961
  return Array.isArray(obj.keyframes) && obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
2808
2962
  }
2809
2963
  function normalizeScale(raw) {
2810
- if (raw === void 0) return void 0;
2811
- if (Array.isArray(raw)) return [raw[0] / 100, raw[1] / 100];
2812
2964
  return raw;
2813
2965
  }
2814
2966
  function wrapTransformPart(inner, part, raw, ctx) {
@@ -2849,34 +3001,54 @@ function wrapOrigin(inner, raw, invert) {
2849
3001
  }
2850
3002
  return inner;
2851
3003
  }
3004
+ function genId(ctx, prefix) {
3005
+ return "_lw_" + prefix + "_" + ctx.nextId++;
3006
+ }
3007
+ function stripHash2(href) {
3008
+ return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3009
+ }
3010
+ function indexById(node, map) {
3011
+ var _a;
3012
+ if (typeof node.id === "string") map.set(node.id, node);
3013
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3014
+ }
3015
+ function spliceDefs(root, defs) {
3016
+ if (!defs.length) return;
3017
+ const existing = root.children || (root.children = []);
3018
+ existing.unshift({ type: "defs", children: defs });
3019
+ }
3020
+ var clone = deepClonePxNode;
3021
+ function regenerateIdsInClone(root, ctx) {
3022
+ return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3023
+ }
2852
3024
  function identifyContentRefTargets(node, ctx, allocator) {
2853
3025
  var _a, _b, _c;
2854
3026
  if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.type) === "content") {
2855
- const baseId = node.effects.clone.baseId;
2856
- if (typeof baseId === "string" && baseId && !ctx.contentRefInnerIds.has(baseId)) {
2857
- ctx.contentRefInnerIds.set(baseId, allocator(baseId));
3027
+ const sourceId = stripHash2(node.effects.clone.sourceId);
3028
+ if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3029
+ ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
2858
3030
  }
2859
3031
  }
2860
3032
  (_c = node.children) == null ? void 0 : _c.forEach((c) => identifyContentRefTargets(c, ctx, allocator));
2861
3033
  }
2862
- function splitForContentRef(node, transformation, originalId, innerId, ctx) {
2863
- const outerBody = liftBodyTranslate(node, transformation);
3034
+ function splitForContentRef(node, transformBy, originalId, innerId, ctx) {
3035
+ const outerBody = liftBodyTranslate(node, transformBy);
2864
3036
  if (typeof node.id === "string") delete node.id;
2865
- const { outer: outerTr, inner: innerTr } = splitTransformationEffect(transformation);
3037
+ const { outer: outerTr, inner: innerTr } = splitTransformByEffect(transformBy);
2866
3038
  let innerNode = node;
2867
- innerNode = applyTransformationEffect(innerNode, innerTr, ctx);
3039
+ innerNode = applyTransformByEffect(innerNode, innerTr, ctx);
2868
3040
  const innerWrapper = { type: "g", id: innerId, children: [innerNode] };
2869
3041
  let outerWrapper = { type: "g", id: originalId, children: [innerWrapper] };
2870
3042
  if (outerBody.transform !== void 0) outerWrapper.transform = outerBody.transform;
2871
3043
  if (outerBody.animate !== void 0) outerWrapper.animate = outerBody.animate;
2872
3044
  if (outerTr) {
2873
3045
  delete outerWrapper.id;
2874
- outerWrapper = applyTransformationEffect(outerWrapper, outerTr, ctx);
3046
+ outerWrapper = applyTransformByEffect(outerWrapper, outerTr, ctx);
2875
3047
  outerWrapper.id = originalId;
2876
3048
  }
2877
3049
  return outerWrapper;
2878
3050
  }
2879
- function liftBodyTranslate(node, transformation) {
3051
+ function liftBodyTranslate(node, transformBy) {
2880
3052
  var _a, _b, _c;
2881
3053
  const out = {};
2882
3054
  let didLiftAnimate = false;
@@ -2930,7 +3102,7 @@ function liftBodyTranslate(node, transformation) {
2930
3102
  didLiftAnimate = true;
2931
3103
  }
2932
3104
  }
2933
- const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
3105
+ const transformationHasTranslate = (transformBy == null ? void 0 : transformBy.translate) !== void 0;
2934
3106
  const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
2935
3107
  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);
2936
3108
  if (typeof node.transform === "string") {
@@ -2949,6 +3121,24 @@ function liftBodyTranslate(node, transformation) {
2949
3121
  if (split.rest) node.transform = split.rest;
2950
3122
  else delete node.transform;
2951
3123
  }
3124
+ } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes && !node.transform.kfs) {
3125
+ const wrapped = node.transform.value;
3126
+ const isWrapped = !!(wrapped && typeof wrapped === "object");
3127
+ const value = isWrapped ? wrapped : node.transform;
3128
+ const rewrap = (rec) => isWrapped ? { value: rec } : rec;
3129
+ if (Array.isArray(value.translate)) {
3130
+ const rest = __spreadValues2({}, value);
3131
+ delete rest.translate;
3132
+ const hasRest = Object.keys(rest).length > 0;
3133
+ if (stripBodyTranslateOnly) {
3134
+ if (hasRest) node.transform = rewrap(rest);
3135
+ else delete node.transform;
3136
+ } else {
3137
+ out.transform = rewrap({ translate: value.translate });
3138
+ if (hasRest) node.transform = rewrap(rest);
3139
+ else delete node.transform;
3140
+ }
3141
+ }
2952
3142
  }
2953
3143
  return out;
2954
3144
  }
@@ -3018,7 +3208,7 @@ function parseTranslateArgs(translateOp) {
3018
3208
  const nums = m[1].split(/[\s,]+/).filter(Boolean).map(Number);
3019
3209
  return [nums[0] || 0, nums[1] || 0];
3020
3210
  }
3021
- function splitTransformationEffect(fx) {
3211
+ function splitTransformByEffect(fx) {
3022
3212
  if (!fx) return {};
3023
3213
  const originOnOuter = needsOriginOnOuter(fx.translate);
3024
3214
  const innerHasPivotedPart = fx.rotate !== void 0 || fx.scale !== void 0;
@@ -3044,26 +3234,6 @@ function needsOriginOnOuter(translateAnim) {
3044
3234
  }
3045
3235
  return false;
3046
3236
  }
3047
- function genId(ctx, prefix) {
3048
- return "_lw_" + prefix + "_" + ctx.nextId++;
3049
- }
3050
- function stripHash2(href) {
3051
- return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3052
- }
3053
- function indexById(node, map) {
3054
- var _a;
3055
- if (typeof node.id === "string") map.set(node.id, node);
3056
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3057
- }
3058
- function spliceDefs(root, defs) {
3059
- if (!defs.length) return;
3060
- const existing = root.children || (root.children = []);
3061
- existing.unshift({ type: "defs", children: defs });
3062
- }
3063
- var clone = deepClonePxNode;
3064
- function regenerateIdsInClone(root, ctx) {
3065
- return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3066
- }
3067
3237
  function applyFillGradientEffect(node, fx, ctx) {
3068
3238
  return applyGradient(node, fx, ctx, "fill");
3069
3239
  }
@@ -3084,62 +3254,63 @@ function synthesiseGradientDef(fx, id, ctx) {
3084
3254
  id
3085
3255
  };
3086
3256
  if (fx.type === PxGradientType.linear) {
3087
- if (fx.p1) {
3088
- out.x1 = String(fx.p1[0]);
3089
- out.y1 = String(fx.p1[1]);
3090
- }
3091
- if (fx.p2) {
3092
- out.x2 = String(fx.p2[0]);
3093
- out.y2 = String(fx.p2[1]);
3094
- }
3257
+ applyGeomVec(out, "x1", "y1", fx.p1);
3258
+ applyGeomVec(out, "x2", "y2", fx.p2);
3095
3259
  } else {
3096
- if (fx.c) {
3097
- out.cx = String(fx.c[0]);
3098
- out.cy = String(fx.c[1]);
3099
- }
3100
- if (fx.r !== void 0) out.r = String(fx.r);
3101
- if (fx.fp) {
3102
- out.fx = String(fx.fp[0]);
3103
- out.fy = String(fx.fp[1]);
3104
- }
3260
+ applyGeomVec(out, "cx", "cy", fx.c);
3261
+ applyGeomNumber(out, "r", fx.r);
3262
+ applyGeomVec(out, "fx", "fy", fx.fp);
3105
3263
  }
3106
3264
  if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
3107
3265
  if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
3108
3266
  if (fx.gradientTransform) out.gradientTransform = fx.gradientTransform;
3109
- const animate = fx.animate;
3110
- if (animate) {
3111
- const mapped = {};
3112
- for (const wireKey of Object.keys(animate)) {
3113
- const attr = GRADIENT_ANIM_CHANNEL_TO_ATTR[wireKey];
3114
- if (attr) mapped[attr] = animate[wireKey];
3115
- }
3116
- if (Object.keys(mapped).length) out.animate = mapped;
3117
- }
3118
3267
  out.children = buildStopChildren(fx.stops, ctx);
3119
3268
  return out;
3120
3269
  }
3121
- var GRADIENT_ANIM_CHANNEL_TO_ATTR = {
3122
- gradientX1: "x1",
3123
- gradientY1: "y1",
3124
- gradientX2: "x2",
3125
- gradientY2: "y2",
3126
- gradientCx: "cx",
3127
- gradientCy: "cy",
3128
- gradientFx: "fx",
3129
- gradientFy: "fy",
3130
- gradientR: "r"
3131
- };
3270
+ function applyGeomVec(out, xAttr, yAttr, raw) {
3271
+ var _a, _b, _c;
3272
+ const read = readAnimatable(raw);
3273
+ if (read.kind === "absent") return;
3274
+ if (read.kind === "static") {
3275
+ out[xAttr] = String(read.value[0]);
3276
+ out[yAttr] = String(read.value[1]);
3277
+ return;
3278
+ }
3279
+ const axisChannel = (idx) => {
3280
+ const block = {
3281
+ keyframes: read.keyframes.map((kf) => {
3282
+ const axisKf = { time: kf.time, value: Array.isArray(kf.value) ? kf.value[idx] : void 0 };
3283
+ if (kf.easing !== void 0) axisKf.easing = kf.easing;
3284
+ return axisKf;
3285
+ })
3286
+ };
3287
+ if (read.loop !== void 0) block.loop = read.loop;
3288
+ return block;
3289
+ };
3290
+ const animate = (_a = out.animate) != null ? _a : {};
3291
+ animate[xAttr] = axisChannel(0);
3292
+ animate[yAttr] = axisChannel(1);
3293
+ out.animate = animate;
3294
+ const baseline = (_c = read.base) != null ? _c : (_b = read.keyframes[0]) == null ? void 0 : _b.value;
3295
+ if (Array.isArray(baseline)) {
3296
+ out[xAttr] = String(baseline[0]);
3297
+ out[yAttr] = String(baseline[1]);
3298
+ }
3299
+ }
3300
+ function applyGeomNumber(out, attrName, raw) {
3301
+ const read = readAnimatable(raw);
3302
+ if (read.kind === "absent") return;
3303
+ writeAnimatableChannel(out, attrName, read, { asString: true });
3304
+ }
3132
3305
  function buildStopChildren(stops, ctx) {
3133
3306
  var _a, _b, _c, _d;
3134
3307
  if (!stops) return [];
3135
- if (Array.isArray(stops)) return stops.map(staticStopNode);
3136
- if (typeof stops === "object" && Array.isArray(stops.value)) {
3137
- return stops.value.map(staticStopNode);
3138
- }
3139
- const animBlock = stops;
3140
- const kfs = animBlock.keyframes;
3141
- if (!Array.isArray(kfs) || !kfs.length) return [];
3142
- const loopFromSource = animBlock.loop;
3308
+ const read = readAnimatable(stops);
3309
+ if (read.kind === "absent") return [];
3310
+ if (read.kind === "static") return Array.isArray(read.value) ? read.value.map(staticStopNode) : [];
3311
+ const kfs = read.keyframes;
3312
+ if (!kfs.length) return [];
3313
+ const loopFromSource = read.loop;
3143
3314
  let stopCount = 0;
3144
3315
  for (const kf of kfs) {
3145
3316
  const v = (_a = kf.value) != null ? _a : kf.v;
@@ -3214,36 +3385,60 @@ function formatOffset(o) {
3214
3385
  return pct + "%";
3215
3386
  }
3216
3387
  function applyClipPathEffect(node, fx, ctx) {
3388
+ var _a, _b;
3217
3389
  if (!fx || !fx.d && !fx.animate) return node;
3218
3390
  const clipId = genId(ctx, "clip");
3219
- const pathChild = { type: "path", d: fx.d };
3220
- if (fx.animate) pathChild.animate = { d: fx.animate };
3391
+ const pathChild = { type: "path" };
3392
+ const read = readAnimatable(fx.d);
3393
+ if (read.kind !== "absent") {
3394
+ if (read.kind === "static") {
3395
+ pathChild.d = pathString(read.value);
3396
+ } else {
3397
+ writeAnimatableChannel(pathChild, "d", read);
3398
+ if (pathChild.d !== void 0) pathChild.d = pathString(pathChild.d);
3399
+ }
3400
+ }
3401
+ if (fx.animate && !((_a = pathChild.animate) == null ? void 0 : _a.d)) {
3402
+ const animate = (_b = pathChild.animate) != null ? _b : {};
3403
+ animate.d = fx.animate;
3404
+ pathChild.animate = animate;
3405
+ }
3221
3406
  ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
3222
3407
  node.clipPath = "url(#" + clipId + ")";
3223
3408
  return node;
3224
3409
  }
3225
- function applyMaskedByEffect(node, fx, transformation, ctx) {
3410
+ function pathString(v) {
3411
+ if (typeof v === "string") return v;
3412
+ if (v && typeof v === "object" && typeof v.path === "string") return v.path;
3413
+ return void 0;
3414
+ }
3415
+ function applyMaskedByEffect(node, fx, transformBy, ctx) {
3226
3416
  if (!fx) return node;
3227
- if (!fx.href) {
3228
- ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
3417
+ const sourceId = stripHash2(fx.sourceId);
3418
+ if (!sourceId) {
3419
+ ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
3229
3420
  return node;
3230
3421
  }
3231
3422
  const maskId = genId(ctx, "mask");
3232
- let content = { type: "use", href: "#" + fx.href };
3233
- if (transformation) {
3234
- content = wrapInverseTransform(content, transformation, ctx);
3423
+ let content = { type: "use", href: "#" + sourceId };
3424
+ if (transformBy) {
3425
+ content = wrapInverseTransform(content, transformBy, ctx);
3235
3426
  } else if (hasAnimateTransform(node)) {
3236
3427
  content = wrapInverseAnimatedBodyTransform(content, node, ctx);
3237
3428
  } else {
3238
3429
  const bodyStatic = readTransformationFromBody(node);
3239
3430
  if (bodyStatic) content = wrapInverseTransform(content, bodyStatic, ctx);
3240
3431
  }
3241
- const includeTargetOwn = transformation === void 0 && !nodeHasBodyTransform(node);
3242
- content = wrapAncestorChainCompensation(content, node, fx.href, ctx, includeTargetOwn);
3432
+ const includeTargetOwn = transformBy === void 0 && !nodeHasBodyTransform(node);
3433
+ content = wrapAncestorChainCompensation(content, node, sourceId, ctx, includeTargetOwn);
3243
3434
  const mask = { type: "mask", id: maskId, children: [content] };
3244
3435
  if (fx.maskType) mask.maskType = fx.maskType;
3245
3436
  if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
3246
3437
  if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
3438
+ if (fx.x !== void 0) mask.x = String(fx.x);
3439
+ if (fx.y !== void 0) mask.y = String(fx.y);
3440
+ if (fx.width !== void 0) mask.width = String(fx.width);
3441
+ if (fx.height !== void 0) mask.height = String(fx.height);
3247
3442
  ctx.defs.push(mask);
3248
3443
  node.mask = "url(#" + maskId + ")";
3249
3444
  return node;
@@ -3350,6 +3545,19 @@ function readTransformationFromBody(node) {
3350
3545
  if (parts.origin) out.origin = parts.origin;
3351
3546
  return Object.keys(out).length ? out : void 0;
3352
3547
  }
3548
+ if (node.transform && typeof node.transform === "object" && !node.transform.keyframes && !node.transform.kfs) {
3549
+ const wrapped = node.transform.value;
3550
+ const value = wrapped && typeof wrapped === "object" ? wrapped : node.transform;
3551
+ if (value && typeof value === "object") {
3552
+ const out = {};
3553
+ if (Array.isArray(value.translate)) out.translate = value.translate;
3554
+ if (typeof value.rotate === "number") out.rotate = value.rotate;
3555
+ if (typeof value.skew === "number") out.skew = value.skew;
3556
+ if (Array.isArray(value.scale)) out.scale = { value: value.scale };
3557
+ if (Array.isArray(value.origin)) out.origin = value.origin;
3558
+ return Object.keys(out).length ? out : void 0;
3559
+ }
3560
+ }
3353
3561
  return void 0;
3354
3562
  }
3355
3563
  function parseTransformStringToParts(s) {
@@ -3483,10 +3691,10 @@ function collectMaskAncestorChains(root, ctx) {
3483
3691
  const interestingNodes = /* @__PURE__ */ new Set();
3484
3692
  const collectInterestingNodes = (n) => {
3485
3693
  var _a, _b;
3486
- const href = (_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.href;
3487
- if (typeof href === "string") {
3694
+ const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.sourceId);
3695
+ if (typeof maskSourceId === "string") {
3488
3696
  interestingNodes.add(n);
3489
- const sourceNode = ctx.idMap.get(href);
3697
+ const sourceNode = ctx.idMap.get(maskSourceId);
3490
3698
  if (sourceNode) interestingNodes.add(sourceNode);
3491
3699
  }
3492
3700
  if (Array.isArray(n.children)) for (const ch of n.children) collectInterestingNodes(ch);
@@ -3512,8 +3720,9 @@ function extractTranslateOnly(node, ctx) {
3512
3720
  if (typeof tr === "string") {
3513
3721
  const parts = parseTranslateOnlyFromString(tr, ctx);
3514
3722
  if (parts) out.translate = parts;
3515
- } else if (tr && typeof tr === "object") {
3516
- const value = tr.value;
3723
+ } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
3724
+ const wrapped = tr.value;
3725
+ const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
3517
3726
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
3518
3727
  out.translate = [value.translate[0] || 0, value.translate[1] || 0];
3519
3728
  }
@@ -3561,17 +3770,17 @@ function parseTranslateOnlyFromString(s, ctx) {
3561
3770
  var CONTENT_SUBREF = "content";
3562
3771
  function applyRefHref(node, clone2, ctx) {
3563
3772
  if (!clone2) return;
3564
- const baseId = clone2.baseId;
3565
- if (!baseId) {
3566
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing baseId");
3773
+ const sourceId = stripHash2(clone2.sourceId);
3774
+ if (!sourceId) {
3775
+ if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
3567
3776
  return;
3568
3777
  }
3569
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
3778
+ const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
3570
3779
  node.href = "#" + targetId;
3571
3780
  }
3572
- function applyRefAndTransformationEffect(node, clone2, transformation, ctx) {
3781
+ function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
3573
3782
  applyRefHref(node, clone2, ctx);
3574
- return applyTransformationEffect(node, transformation, ctx);
3783
+ return applyTransformByEffect(node, transformBy, ctx);
3575
3784
  }
3576
3785
  function applyRepeaterEffect(node, fx, ctx) {
3577
3786
  var _a, _b;
@@ -3594,7 +3803,7 @@ function applyRepeaterEffect(node, fx, ctx) {
3594
3803
  for (let i = 1; i < copies; i++) {
3595
3804
  const baseClone = clone(base);
3596
3805
  const synthFx = synthesisePerCopyFx(fx, i);
3597
- const wrapped = synthFx ? applyTransformationEffect(baseClone, synthFx, ctx) : baseClone;
3806
+ const wrapped = synthFx ? applyTransformByEffect(baseClone, synthFx, ctx) : baseClone;
3598
3807
  children.push(wrapped);
3599
3808
  }
3600
3809
  const wrapper = { type: "g", children };
@@ -3606,10 +3815,13 @@ function applyRepeaterEffect(node, fx, ctx) {
3606
3815
  function synthesisePerCopyFx(fx, i) {
3607
3816
  const out = {};
3608
3817
  if (fx.translate !== void 0) {
3609
- out.translate = mapAnimatableVec2(fx.translate, (v) => [v[0] * i, v[1] * i]);
3818
+ out.translate = mapAnimatable(fx.translate, (v) => [v[0] * i, v[1] * i]);
3610
3819
  }
3611
3820
  if (fx.rotate !== void 0) {
3612
- out.rotate = mapAnimatableNumber(fx.rotate, (v) => v * i);
3821
+ out.rotate = mapAnimatable(fx.rotate, (v) => v * i);
3822
+ }
3823
+ if (fx.skew !== void 0) {
3824
+ out.skew = mapAnimatable(fx.skew, (v) => v * i);
3613
3825
  }
3614
3826
  if (fx.scale !== void 0) {
3615
3827
  out.scale = synthesiseScale(fx.scale, i);
@@ -3619,63 +3831,50 @@ function synthesisePerCopyFx(fx, i) {
3619
3831
  }
3620
3832
  return Object.keys(out).length ? out : void 0;
3621
3833
  }
3622
- function mapAnimatableVec2(raw, fn) {
3623
- if (Array.isArray(raw)) return fn(raw);
3624
- if (raw && typeof raw === "object") {
3625
- const obj = raw;
3626
- if (Array.isArray(obj.keyframes)) {
3627
- return __spreadProps2(__spreadValues2({}, obj), {
3628
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
3629
- });
3630
- }
3631
- if (obj.value !== void 0) {
3632
- return __spreadProps2(__spreadValues2({}, obj), { value: fn(obj.value) });
3633
- }
3634
- }
3635
- return raw;
3636
- }
3637
- function mapAnimatableNumber(raw, fn) {
3638
- if (typeof raw === "number") return fn(raw);
3639
- if (raw && typeof raw === "object") {
3640
- const obj = raw;
3641
- if (Array.isArray(obj.keyframes)) {
3642
- return __spreadProps2(__spreadValues2({}, obj), {
3643
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
3644
- });
3645
- }
3646
- if (obj.value !== void 0) {
3647
- return __spreadProps2(__spreadValues2({}, obj), { value: fn(obj.value) });
3648
- }
3834
+ function mapAnimatable(raw, fn, wrapStatic = false) {
3835
+ const read = readAnimatable(raw);
3836
+ if (read.kind === "absent") return raw;
3837
+ if (read.kind === "static") {
3838
+ const mapped = fn(read.value);
3839
+ const wasRawStatic = typeof raw === "number" || Array.isArray(raw);
3840
+ return wasRawStatic && !wrapStatic ? mapped : { value: mapped };
3649
3841
  }
3650
- return raw;
3842
+ const out = {
3843
+ keyframes: read.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
3844
+ };
3845
+ if (read.loop !== void 0) out.loop = read.loop;
3846
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
3847
+ if (read.base !== void 0) out.value = fn(read.base);
3848
+ return out;
3651
3849
  }
3652
3850
  function synthesiseScale(raw, i) {
3653
- const scalePowerFromPercent = (v) => [Math.pow(v[0] / 100, i), Math.pow(v[1] / 100, i)];
3654
- const scalePowerFromUnits = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
3655
- if (Array.isArray(raw)) {
3656
- return { value: scalePowerFromPercent(raw) };
3657
- }
3658
- if (raw && typeof raw === "object") {
3659
- const obj = raw;
3660
- if (Array.isArray(obj.keyframes)) {
3661
- return __spreadProps2(__spreadValues2({}, obj), {
3662
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: scalePowerFromUnits(kf.value) }) : kf)
3663
- });
3664
- }
3665
- if (obj.value !== void 0) {
3666
- return __spreadProps2(__spreadValues2({}, obj), { value: scalePowerFromPercent(obj.value) });
3667
- }
3668
- }
3669
- return raw;
3851
+ const scalePower = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
3852
+ return mapAnimatable(raw, scalePower, true);
3670
3853
  }
3671
3854
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
3672
3855
  function asRetime(r) {
3673
3856
  var _a, _b;
3674
- if (r.timeCrop) {
3675
- console.warn("retime: `timeCrop` is not supported yet and will be ignored");
3676
- }
3677
3857
  return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
3678
3858
  }
3859
+ var CROP_EDGE_MS = 1;
3860
+ function applyTimeCrop(useNode, crop, ctx) {
3861
+ const [start, end] = crop;
3862
+ if (!Number.isFinite(start) || !Number.isFinite(end)) {
3863
+ ctx.warnings.push("retime: timeCrop is not a pair of finite numbers \u2014 ignored");
3864
+ return;
3865
+ }
3866
+ const keyframes = end <= start ? [{ time: 0, value: 0 }] : [
3867
+ ...start > 0 ? [{ time: Math.max(0, start - CROP_EDGE_MS), value: 0 }] : [],
3868
+ { time: Math.max(0, start), value: 1 },
3869
+ { time: end, value: 1 },
3870
+ { time: end + CROP_EDGE_MS, value: 0 }
3871
+ ];
3872
+ const inner = __spreadValues2({}, useNode);
3873
+ for (const k of Object.keys(useNode)) delete useNode[k];
3874
+ useNode.type = "g";
3875
+ useNode.children = [inner];
3876
+ useNode.animate = { opacity: { keyframes } };
3877
+ }
3679
3878
  function concatRetime(child, parent) {
3680
3879
  return {
3681
3880
  start: parent.start + parent.stretch * child.start,
@@ -3735,8 +3934,10 @@ function applyAllRetimeEffects(root, ctx) {
3735
3934
  for (const useNode of sites) {
3736
3935
  const retime = readCloneRetime(useNode);
3737
3936
  if (!retime) continue;
3937
+ const crop = retime.timeCrop;
3738
3938
  clearCloneRetime(useNode);
3739
3939
  materialiseRetime(useNode, asRetime(retime), ctx);
3940
+ if (crop) applyTimeCrop(useNode, crop, ctx);
3740
3941
  }
3741
3942
  }
3742
3943
  function materialiseRetime(useNode, retime, ctx) {
@@ -3979,14 +4180,11 @@ function createPathSampler(d) {
3979
4180
  }
3980
4181
  var EXTEND_MARGIN_FRAC = 0.15;
3981
4182
  function numRange(v) {
3982
- if (typeof v === "number") return { min: v, max: v };
3983
- if (v && typeof v === "object") {
3984
- const o = v;
3985
- if (typeof o.value === "number") return { min: o.value, max: o.value };
3986
- if (Array.isArray(o.keyframes) && o.keyframes.length) {
3987
- const vals = o.keyframes.map((k) => Number(k.value) || 0);
3988
- return { min: Math.min(...vals), max: Math.max(...vals) };
3989
- }
4183
+ const read = readAnimatable(v);
4184
+ if (read.kind === "static" && typeof read.value === "number") return { min: read.value, max: read.value };
4185
+ if (read.kind === "animated" && read.keyframes.length) {
4186
+ const vals = read.keyframes.map((k) => Number(k.value) || 0);
4187
+ return { min: Math.min(...vals), max: Math.max(...vals) };
3990
4188
  }
3991
4189
  return { min: 0, max: 0 };
3992
4190
  }
@@ -4006,11 +4204,16 @@ function estimateTextAdvance(node) {
4006
4204
  var r3 = (n) => Math.round(n * 1e3) / 1e3;
4007
4205
  function shiftAnimatable(v, by) {
4008
4206
  if (!by || v === void 0 || v === null) return v;
4009
- if (typeof v === "number") return v + by;
4010
- const o = v;
4011
- if (typeof o.value === "number") return __spreadProps2(__spreadValues2({}, o), { value: o.value + by });
4012
- if (Array.isArray(o.keyframes)) return __spreadProps2(__spreadValues2({}, o), { keyframes: o.keyframes.map((k) => __spreadProps2(__spreadValues2({}, k), { value: (Number(k.value) || 0) + by })) });
4013
- return v;
4207
+ const read = readAnimatable(v);
4208
+ if (read.kind === "absent") return v;
4209
+ if (read.kind === "static") return typeof v === "number" ? read.value + by : { value: read.value + by };
4210
+ const out = {
4211
+ keyframes: read.keyframes.map((k) => __spreadProps2(__spreadValues2({}, k), { value: (Number(k.value) || 0) + by }))
4212
+ };
4213
+ if (read.loop !== void 0) out.loop = read.loop;
4214
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
4215
+ if (read.base !== void 0) out.value = read.base + by;
4216
+ return out;
4014
4217
  }
4015
4218
  function extendedPathForBrowser(pathD, opts) {
4016
4219
  var _a;
@@ -4066,26 +4269,7 @@ function applyTextPathEffect(node, fx, ctx) {
4066
4269
  }
4067
4270
  function applyAnimatableNumber(node, attrName, raw) {
4068
4271
  if (raw === void 0 || raw === null) return;
4069
- if (typeof raw === "number") {
4070
- node[attrName] = String(raw);
4071
- return;
4072
- }
4073
- if (typeof raw === "object" && raw !== null) {
4074
- const obj = raw;
4075
- if (Array.isArray(obj.keyframes)) {
4076
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
4077
- const animate = __spreadValues2({}, prevAnimate || {});
4078
- const block = { keyframes: obj.keyframes };
4079
- if (obj.loop !== void 0) block.loop = obj.loop;
4080
- animate[attrName] = block;
4081
- node.animate = animate;
4082
- return;
4083
- }
4084
- if (typeof obj.value === "number") {
4085
- node[attrName] = String(obj.value);
4086
- return;
4087
- }
4088
- }
4272
+ writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
4089
4273
  }
4090
4274
  var jsonElementFactory = (type, props, children) => {
4091
4275
  const node = { type };
@@ -4273,13 +4457,13 @@ function materialiseGlyphTextHorizontal(node, opts) {
4273
4457
  if (y !== void 0) pen.y = y;
4274
4458
  pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
4275
4459
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4276
- const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
4460
+ const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4277
4461
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
4278
4462
  if (el.children) for (const ch of el.children) walk(ch, s);
4279
4463
  };
4280
4464
  const rootStyle = rootStyleOf(node);
4281
4465
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
4282
- const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
4466
+ const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
4283
4467
  if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
4284
4468
  const anchor = str(node.textAnchor);
4285
4469
  if (anchor === "middle" || anchor === "end") {
@@ -4328,7 +4512,7 @@ function layoutGlyphTextChars(node, opts) {
4328
4512
  if (y !== void 0) pen.y = y;
4329
4513
  pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
4330
4514
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4331
- const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
4515
+ const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4332
4516
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
4333
4517
  if (el.children) for (const ch of el.children) walk(ch, s);
4334
4518
  };
@@ -4343,7 +4527,7 @@ function layoutGlyphTextChars(node, opts) {
4343
4527
  boxes.push({ x: pen.x, y: pen.y, width: 0, ascent: ((_d = gf == null ? void 0 : gf.ascent) != null ? _d : 0.9 * upm) * (s.fontSize / upm), fontSize: s.fontSize, line });
4344
4528
  }
4345
4529
  }
4346
- const rootContent = (_e = str(node[TEXT_ATTR])) != null ? _e : str(node[TEXT_CONTENT_ATTR]);
4530
+ const rootContent = (_e = str(node[TEXT_CONTENT_ATTR])) != null ? _e : str(node[TEXT_ATTR]);
4347
4531
  if (rootContent && !((_f = node.children) == null ? void 0 : _f.length)) renderChars(rootContent, rootStyle);
4348
4532
  const anchor = str(node.textAnchor);
4349
4533
  if (anchor === "middle" || anchor === "end") {
@@ -4371,7 +4555,7 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4371
4555
  const walk = (el, parentStyle) => {
4372
4556
  var _a2, _b2, _c;
4373
4557
  const s = resolveStyle2(el, parentStyle);
4374
- const content = (_a2 = str(el[TEXT_ATTR])) != null ? _a2 : str(el[TEXT_CONTENT_ATTR]);
4558
+ const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
4375
4559
  if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
4376
4560
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4377
4561
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
@@ -4425,7 +4609,7 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4425
4609
  const walk = (el, parentStyle) => {
4426
4610
  var _a, _b, _c;
4427
4611
  const s = resolveStyle2(el, parentStyle);
4428
- const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
4612
+ const content = (_a = str(el[TEXT_CONTENT_ATTR])) != null ? _a : str(el[TEXT_ATTR]);
4429
4613
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
4430
4614
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4431
4615
  if (gf) {
@@ -4653,9 +4837,9 @@ function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pat
4653
4837
  }
4654
4838
  return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
4655
4839
  }
4656
- function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4840
+ function applyTrimPathEffect(node, trimPath, ctx) {
4657
4841
  if (!trimPath) return node;
4658
- const trimAllAsOne = !!trimPath.trimAllAsOne;
4842
+ const combined = trimPath.subPaths === PxTrimSubPaths.combined;
4659
4843
  const leafEntries = [];
4660
4844
  const measure = (n) => {
4661
4845
  if (Array.isArray(n.children) && n.children.length > 0) {
@@ -4676,16 +4860,16 @@ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4676
4860
  measure(node);
4677
4861
  if (!leafEntries.length) return node;
4678
4862
  let acc = 0;
4679
- const iterOrder = trimAllAsOne ? [...leafEntries].reverse() : leafEntries;
4863
+ const iterOrder = combined ? [...leafEntries].reverse() : leafEntries;
4680
4864
  for (const entry of iterOrder) {
4681
4865
  for (const sp of entry.subpaths) {
4682
- if (!trimAllAsOne) acc = 0;
4866
+ if (!combined) acc = 0;
4683
4867
  sp.startOffsetPx = acc;
4684
4868
  acc += sp.lengthPx;
4685
4869
  }
4686
4870
  }
4687
4871
  const chainLengthPx = acc;
4688
- if (trimAllAsOne && chainLengthPx < 1e-3) return node;
4872
+ if (combined && chainLengthPx < 1e-3) return node;
4689
4873
  const offsetReadRaw = readAnimatable(trimPath.offset);
4690
4874
  const offsetRead = offsetReadRaw.kind === "absent" ? { kind: "static", value: 0 } : offsetReadRaw;
4691
4875
  const rangeReadRaw = readRangeWithCrossings(trimPath.range);
@@ -4697,18 +4881,18 @@ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4697
4881
  if (leafEntries.length === 1 && leafEntries[0].leaf === node && leafEntries[0].subpaths.length === 1) {
4698
4882
  const entry = leafEntries[0];
4699
4883
  const sp = entry.subpaths[0];
4700
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
4884
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
4701
4885
  if (pathLengthPx < 1e-3) return node;
4702
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
4886
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
4703
4887
  return collapseLeafWithTrim(entry.leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead);
4704
4888
  }
4705
4889
  const replacements = /* @__PURE__ */ new Map();
4706
4890
  for (const entry of leafEntries) {
4707
4891
  const newChildren = [];
4708
4892
  for (const sp of entry.subpaths) {
4709
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
4893
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
4710
4894
  if (pathLengthPx < 1e-3) continue;
4711
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
4895
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
4712
4896
  newChildren.push(...buildSubpathNodes(entry.leaf, sp.subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx));
4713
4897
  }
4714
4898
  replacements.set(entry.leaf, wrapLeafAsGroup(entry.leaf, newChildren));
@@ -4815,22 +4999,8 @@ function computeAnimAttr(read, map) {
4815
4999
  };
4816
5000
  }
4817
5001
  function applyAttr(node, attrName, attr) {
4818
- var _a, _b;
4819
5002
  if (!attr) return;
4820
- if (attr.kind === "static") {
4821
- node[attrName] = attr.value;
4822
- return;
4823
- }
4824
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
4825
- const animate = __spreadValues2({}, prevAnimate || {});
4826
- const block = { keyframes: attr.keyframes };
4827
- if (attr.loop !== void 0) block.loop = attr.loop;
4828
- animate[attrName] = block;
4829
- node.animate = animate;
4830
- const firstKf = attr.keyframes[0];
4831
- if (firstKf && ((_a = firstKf.value) != null ? _a : firstKf.v) !== void 0) {
4832
- node[attrName] = (_b = firstKf.value) != null ? _b : firstKf.v;
4833
- }
5003
+ writeAnimatableChannel(node, attrName, attr);
4834
5004
  }
4835
5005
  var OPACITY_STEP_MS = 10;
4836
5006
  function computeOpacityFromRange(rangeRead) {
@@ -5012,9 +5182,9 @@ function applyPlayerEffects(root) {
5012
5182
  nextId: 0,
5013
5183
  contentRefInnerIds: /* @__PURE__ */ new Map(),
5014
5184
  maskAncestorChains: /* @__PURE__ */ new Map(),
5015
- // Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
5016
- // webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5017
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
5185
+ // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
5186
+ // waapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5187
+ engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi,
5018
5188
  glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
5019
5189
  };
5020
5190
  const working = clone(root);
@@ -5032,8 +5202,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5032
5202
  const originalId = typeof node.id === "string" ? node.id : void 0;
5033
5203
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
5034
5204
  if (!fx && !innerIdForContentRef) return node;
5035
- const { transformation, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5036
- const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
5205
+ const { transformBy, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5037
5206
  if (fx) delete node.effects;
5038
5207
  let n = node;
5039
5208
  let consumedByGlyphs = false;
@@ -5053,15 +5222,15 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5053
5222
  if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
5054
5223
  n = applyFillGradientEffect(n, fillGradient, ctx);
5055
5224
  n = applyStrokeGradientEffect(n, strokeGradient, ctx);
5056
- n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
5225
+ n = applyTrimPathEffect(n, trimPath, ctx);
5057
5226
  n = applyRepeaterEffect(n, repeater, ctx);
5058
- n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
5227
+ n = applyMaskedByEffect(n, maskedBy, transformBy, ctx);
5059
5228
  n = applyClipPathEffect(n, clipPath, ctx);
5060
5229
  if (innerIdForContentRef) {
5061
5230
  applyRefHref(n, cloneFx, ctx);
5062
- n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
5231
+ n = splitForContentRef(n, transformBy, originalId, innerIdForContentRef, ctx);
5063
5232
  } else {
5064
- n = applyRefAndTransformationEffect(n, cloneFx, transformation, ctx);
5233
+ n = applyRefAndTransformationEffect(n, cloneFx, transformBy, ctx);
5065
5234
  }
5066
5235
  if (cloneFx == null ? void 0 : cloneFx.retime) node.effects = { clone: { retime: cloneFx.retime } };
5067
5236
  if (originalId) ctx.idMap.set(originalId, n);
@@ -5076,7 +5245,7 @@ function materialiseAllInTree(doc, engine, opts) {
5076
5245
  let root = applyPlayerEffects(doc).root;
5077
5246
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5078
5247
  root = materialiseInternalLoopsInTree(root, duration);
5079
- if (engine === PxAnimatorEngine.webapi) {
5248
+ if (engine === PxAnimatorEngine.waapi) {
5080
5249
  root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5081
5250
  root = materialiseAnimatedUseInstances(root);
5082
5251
  root = pruneUnreferencedDefs(root);
@@ -5461,6 +5630,7 @@ function evalTransformValue(v, t) {
5461
5630
  if (typeof v === "string") return parseTransformString(v);
5462
5631
  if (v.keyframes) return partsToMatrix(interpParts(v.keyframes, t));
5463
5632
  if (v.value) return partsToMatrix(v.value);
5633
+ if (typeof v === "object" && !Array.isArray(v)) return partsToMatrix(v);
5464
5634
  return IDENTITY;
5465
5635
  }
5466
5636
  function nodeMatrix(node, t) {
@@ -5595,64 +5765,6 @@ function subtractMultiset(a, b) {
5595
5765
  return extra;
5596
5766
  }
5597
5767
 
5598
- // src/PxAnimatorDOM.ts
5599
- var SVG_NS = "http://www.w3.org/2000/svg";
5600
- function createElement(tagName, normalisedProps, style, children, textContent) {
5601
- if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
5602
- console.warn("SVG tag blocked (dangerous): ", tagName);
5603
- return null;
5604
- }
5605
- const element = document.createElementNS(SVG_NS, tagName);
5606
- for (const propName in normalisedProps) {
5607
- const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
5608
- if (sanitised === void 0) continue;
5609
- if (CSS_ONLY_STYLE_PROPS.has(propName)) {
5610
- element.style[propName] = String(sanitised);
5611
- continue;
5612
- }
5613
- element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
5614
- }
5615
- if (style) {
5616
- for (const styleProp in style) {
5617
- element.style[styleProp] = String(style[styleProp]);
5618
- }
5619
- }
5620
- if (children) {
5621
- for (const child of children) {
5622
- element.appendChild(child);
5623
- }
5624
- }
5625
- if (textContent) element.textContent = textContent;
5626
- return element;
5627
- }
5628
- function renderNode(node, defs) {
5629
- if (!node) return null;
5630
- const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
5631
- const feFuncType = props.funcType;
5632
- if (feFuncType !== void 0) delete props.funcType;
5633
- const nodeDefs = getDefs(node) || defs;
5634
- const resolvedStyle = resolveStyle(style, nodeDefs);
5635
- let childElements;
5636
- if (children) {
5637
- for (const ch of children) {
5638
- const child = renderNode(ch, nodeDefs);
5639
- if (child) {
5640
- if (!childElements) childElements = [];
5641
- childElements.push(child);
5642
- }
5643
- }
5644
- }
5645
- const element = createElement(
5646
- type || "g",
5647
- getNormalizedProps(props),
5648
- resolvedStyle,
5649
- childElements,
5650
- props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
5651
- );
5652
- if (element && feFuncType !== void 0) element.setAttribute("type", feFuncType);
5653
- return element;
5654
- }
5655
-
5656
5768
  // src/PxAnimatorTriggers.ts
5657
5769
  function setupAnimationTriggers(api, config) {
5658
5770
  const { startOn, outAction = "continue", scrollIntoViewThreshold = 0 } = config;
@@ -5698,8 +5810,14 @@ function setupAnimationTriggers(api, config) {
5698
5810
  break;
5699
5811
  }
5700
5812
  case "mouseOver": {
5701
- const mouseOverHandler = () => start();
5702
- const mouseOutHandler = () => handleEndAction();
5813
+ let enteredOnce = false;
5814
+ const mouseOverHandler = () => {
5815
+ enteredOnce = true;
5816
+ start();
5817
+ };
5818
+ const mouseOutHandler = () => {
5819
+ if (enteredOnce) handleEndAction();
5820
+ };
5703
5821
  root.addEventListener("mouseenter", mouseOverHandler);
5704
5822
  root.addEventListener("mouseleave", mouseOutHandler);
5705
5823
  break;
@@ -5716,17 +5834,32 @@ function setupAnimationTriggers(api, config) {
5716
5834
  break;
5717
5835
  }
5718
5836
  case "scrollIntoView": {
5837
+ const effectiveRatio = (entry) => {
5838
+ var _a, _b;
5839
+ const target = entry.boundingClientRect;
5840
+ const visible = entry.intersectionRect;
5841
+ if (!(target == null ? void 0 : target.height) || !visible) return entry.intersectionRatio;
5842
+ const live = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : Infinity;
5843
+ const declared = (_b = (_a = entry.rootBounds) == null ? void 0 : _a.height) != null ? _b : Infinity;
5844
+ const viewport = Math.min(live, declared);
5845
+ const denom = Math.min(target.height, Number.isFinite(viewport) ? viewport : target.height);
5846
+ return denom > 0 ? visible.height / denom : entry.intersectionRatio;
5847
+ };
5848
+ const thresholdSteps = Array.from({ length: 21 }, (_, i) => i / 20);
5849
+ let wasIntersecting = false;
5719
5850
  const observer = new IntersectionObserver(
5720
5851
  (entries) => {
5721
5852
  entries.forEach((entry) => {
5722
- if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
5853
+ if (entry.isIntersecting && effectiveRatio(entry) >= scrollIntoViewThreshold) {
5854
+ wasIntersecting = true;
5723
5855
  start();
5724
- } else {
5856
+ } else if (wasIntersecting) {
5857
+ wasIntersecting = false;
5725
5858
  handleEndAction();
5726
5859
  }
5727
5860
  });
5728
5861
  },
5729
- { threshold: scrollIntoViewThreshold }
5862
+ { threshold: thresholdSteps }
5730
5863
  );
5731
5864
  observer.observe(root);
5732
5865
  break;
@@ -5821,7 +5954,7 @@ function createCssKf(kf, t, propName, unsupportedSet) {
5821
5954
  } else {
5822
5955
  cssValue = "" + value;
5823
5956
  }
5824
- if (!CSS.supports(cssKey, cssValue)) unsupportedSet.add(cssKey);
5957
+ if (!CSS.supports(camelCaseToKebabWordIfNeeded(cssKey), cssValue)) unsupportedSet.add(cssKey);
5825
5958
  cssKey = kebabToCamelCaseWord(cssKey);
5826
5959
  cssKf[cssKey] = cssValue;
5827
5960
  return cssKf;
@@ -5898,7 +6031,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5898
6031
  console.warn("createFrameLoopAnimator: No root element provided");
5899
6032
  }
5900
6033
  }
5901
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.webapi);
6034
+ const bindings = getNormalisedBindings(doc, PxAnimatorEngine.waapi);
5902
6035
  const animations = [];
5903
6036
  const _iterations = config.iterations;
5904
6037
  let iterations;
@@ -6044,9 +6177,8 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
6044
6177
  return api;
6045
6178
  }
6046
6179
 
6047
- // src/PxAnimator.ts
6048
- function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
6049
- const animatorConfig = getAnimatorConfig(doc) || {};
6180
+ // src/PxAnimatorBind.ts
6181
+ function finaliseAnimator(animatorConfig, callbacks, make) {
6050
6182
  let apiRef;
6051
6183
  let effectiveCallbacks = callbacks;
6052
6184
  if (animatorConfig.resetOnFinish) {
@@ -6058,29 +6190,99 @@ function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
6058
6190
  }
6059
6191
  });
6060
6192
  }
6061
- let res;
6062
- if (animatorConfig.mode === PxAnimatorMode.frames) {
6063
- res = createFrameLoopAnimator(doc, adapter, effectiveCallbacks, rootElement);
6064
- } else {
6065
- res = createWebApiAnimator(
6066
- doc,
6067
- effectiveCallbacks,
6068
- rootElement,
6069
- animatorConfig.mode === PxAnimatorMode.webapi
6070
- // forcing webapi
6071
- ) || createFrameLoopAnimator(doc, adapter, effectiveCallbacks, rootElement);
6072
- }
6193
+ const res = make(effectiveCallbacks);
6073
6194
  apiRef = res;
6074
6195
  if (animatorConfig.debugInstName) {
6075
6196
  window[animatorConfig.debugInstName] = res;
6076
6197
  }
6077
6198
  return res;
6078
6199
  }
6200
+ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
6201
+ const animatorConfig = getAnimatorConfig(doc) || {};
6202
+ return finaliseAnimator(animatorConfig, callbacks, (cb) => {
6203
+ if (animatorConfig.mode === PxAnimatorMode.frames) {
6204
+ return createFrameLoopAnimator(doc, adapter, cb, rootElement);
6205
+ }
6206
+ return createWebApiAnimator(
6207
+ doc,
6208
+ cb,
6209
+ rootElement,
6210
+ animatorConfig.mode === PxAnimatorMode.waapi
6211
+ // forcing waapi
6212
+ ) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
6213
+ });
6214
+ }
6215
+
6216
+ // src/PxAnimatorDOM.ts
6217
+ var SVG_NS = "http://www.w3.org/2000/svg";
6218
+ function createElement(tagName, normalisedProps, style, children, textContent) {
6219
+ if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
6220
+ console.warn("SVG tag blocked (dangerous): ", tagName);
6221
+ return null;
6222
+ }
6223
+ const element = document.createElementNS(SVG_NS, tagName);
6224
+ for (const propName in normalisedProps) {
6225
+ const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
6226
+ if (sanitised === void 0) continue;
6227
+ if (CSS_ONLY_STYLE_PROPS.has(propName)) {
6228
+ element.style[propName] = String(sanitised);
6229
+ continue;
6230
+ }
6231
+ element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
6232
+ }
6233
+ if (style) {
6234
+ for (const styleProp in style) {
6235
+ element.style[styleProp] = String(style[styleProp]);
6236
+ }
6237
+ }
6238
+ if (children) {
6239
+ for (const child of children) {
6240
+ element.appendChild(child);
6241
+ }
6242
+ }
6243
+ if (textContent) element.textContent = textContent;
6244
+ return element;
6245
+ }
6246
+ function renderNode(node, defs) {
6247
+ if (!node) return null;
6248
+ const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
6249
+ const domType = props.domType;
6250
+ if (domType !== void 0) delete props.domType;
6251
+ const nodeDefs = getDefs(node) || defs;
6252
+ const resolvedStyle = resolveStyle(style, nodeDefs);
6253
+ let childElements;
6254
+ if (children) {
6255
+ for (const ch of children) {
6256
+ const child = renderNode(ch, nodeDefs);
6257
+ if (child) {
6258
+ if (!childElements) childElements = [];
6259
+ childElements.push(child);
6260
+ }
6261
+ }
6262
+ }
6263
+ const element = createElement(
6264
+ type || "g",
6265
+ getNormalizedProps(props),
6266
+ resolvedStyle,
6267
+ childElements,
6268
+ props[TEXT_CONTENT_ATTR] || props[TEXT_ATTR]
6269
+ );
6270
+ if (element && domType !== void 0) element.setAttribute("type", domType);
6271
+ return element;
6272
+ }
6273
+
6274
+ // src/PxAnimatorKeys.ts
6275
+ var PX_ANIMATOR_DATA_KEY = "data";
6276
+
6277
+ // src/PxAnimator.ts
6278
+ function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
6279
+ return bindWithEngineChoice(doc, adapter, callbacks, rootElement);
6280
+ }
6079
6281
  function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
6080
6282
  const effectsWarnings = validateNodeEffects(doc);
6081
6283
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
6082
6284
  const animatorConfig = getAnimatorConfig(doc) || {};
6083
- const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
6285
+ const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi;
6084
6286
  doc = materialiseAllInTree(doc, engine);
6085
6287
  let rootElement = null;
6086
6288
  if (containerElement) {
@@ -6095,7 +6297,6 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
6095
6297
  }
6096
6298
  return createAnimatorFromConfig(doc, adapter, callbacks, rootElement);
6097
6299
  }
6098
- var PX_ANIMATOR_DATA_KEY = "data";
6099
6300
  function createAnimator(options) {
6100
6301
  const { src, data, adapter, callbacks, container } = options;
6101
6302
  if (data !== void 0 && src !== void 0) {
@@ -6203,6 +6404,7 @@ export {
6203
6404
  PxGradientType,
6204
6405
  PxGradientUnits,
6205
6406
  PxKeyframeSchema,
6407
+ PxKeyframeValueSchema,
6206
6408
  PxLoopSchema,
6207
6409
  PxMaskedByEffectSchema,
6208
6410
  PxNodeBase,
@@ -6214,9 +6416,9 @@ export {
6214
6416
  PxSvgNodeExtra,
6215
6417
  PxTextEffectSchema,
6216
6418
  PxTextPathEffectSchema,
6419
+ PxTransformByEffectSchema,
6217
6420
  PxTransformPartsSchema,
6218
6421
  PxTransformValueSchema,
6219
- PxTransformationEffectSchema,
6220
6422
  PxTriggerSchema,
6221
6423
  PxTrimPathEffectSchema,
6222
6424
  STYLE_ATTR_NAMES,