@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.cjs CHANGED
@@ -73,6 +73,7 @@ __export(index_exports, {
73
73
  PxGradientType: () => PxGradientType,
74
74
  PxGradientUnits: () => PxGradientUnits,
75
75
  PxKeyframeSchema: () => PxKeyframeSchema,
76
+ PxKeyframeValueSchema: () => PxKeyframeValueSchema,
76
77
  PxLoopSchema: () => PxLoopSchema,
77
78
  PxMaskedByEffectSchema: () => PxMaskedByEffectSchema,
78
79
  PxNodeBase: () => PxNodeBase,
@@ -84,9 +85,9 @@ __export(index_exports, {
84
85
  PxSvgNodeExtra: () => PxSvgNodeExtra,
85
86
  PxTextEffectSchema: () => PxTextEffectSchema,
86
87
  PxTextPathEffectSchema: () => PxTextPathEffectSchema,
88
+ PxTransformByEffectSchema: () => PxTransformByEffectSchema,
87
89
  PxTransformPartsSchema: () => PxTransformPartsSchema,
88
90
  PxTransformValueSchema: () => PxTransformValueSchema,
89
- PxTransformationEffectSchema: () => PxTransformationEffectSchema,
90
91
  PxTriggerSchema: () => PxTriggerSchema,
91
92
  PxTrimPathEffectSchema: () => PxTrimPathEffectSchema,
92
93
  STYLE_ATTR_NAMES: () => STYLE_ATTR_NAMES,
@@ -292,8 +293,9 @@ var Union = class extends Base {
292
293
  }
293
294
  isValid(raw, ctx, path) {
294
295
  var _a;
295
- if (this.schemas.some((s) => s.isValid(raw))) return true;
296
- 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));
296
+ const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
297
+ if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
298
+ 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));
297
299
  return false;
298
300
  }
299
301
  _canSanitize(raw) {
@@ -369,6 +371,7 @@ var Obj = class extends Base {
369
371
  if (ctx == null ? void 0 : ctx.strict) {
370
372
  for (const key of Object.keys(obj)) {
371
373
  if (key in this._shape) continue;
374
+ if (obj[key] === void 0) continue;
372
375
  p.push(key);
373
376
  ctx.errors.push(pathStr(p) + ": unexpected extra key");
374
377
  p.pop();
@@ -509,6 +512,23 @@ var Any = class extends Base {
509
512
  return true;
510
513
  }
511
514
  };
515
+ var Defined = class extends Base {
516
+ constructor() {
517
+ super(...arguments);
518
+ this._default = void 0;
519
+ }
520
+ sanitize(raw) {
521
+ return raw;
522
+ }
523
+ isValid(raw, ctx, path) {
524
+ if (raw !== void 0) return true;
525
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": required value is missing");
526
+ return false;
527
+ }
528
+ _canSanitize(raw) {
529
+ return raw !== void 0;
530
+ }
531
+ };
512
532
  var Lazy = class extends Base {
513
533
  constructor(fn, _default) {
514
534
  super();
@@ -620,6 +640,8 @@ var px = {
620
640
  record: (value) => new Rec(value),
621
641
  /** Passes anything through unchanged — always valid. */
622
642
  any: () => new Any(),
643
+ /** Anything EXCEPT `undefined` — an open type whose presence is required (V6). */
644
+ defined: () => new Defined(),
623
645
  /** Fixed-length tuple — validates element count and each position individually. */
624
646
  tuple: (schemas) => new Tuple(schemas),
625
647
  /** Defers schema creation — required for recursive types. Must supply a default value. */
@@ -629,13 +651,52 @@ var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
629
651
  var PX_ANIM_ATTR_NAME = "_px_animator";
630
652
  var PxAnimatorMode = {
631
653
  auto: "auto",
632
- webapi: "webapi",
654
+ waapi: "waapi",
633
655
  frames: "frames"
634
656
  };
635
657
  var PxAnimatorEngine = {
636
- webapi: PxAnimatorMode.webapi,
658
+ waapi: PxAnimatorMode.waapi,
637
659
  frames: PxAnimatorMode.frames
638
660
  };
661
+ var PxLoopExtend = {
662
+ /** Segment from the START; the animation is extended BEFORE the first keyframe
663
+ * (intro loops that run before the main timeline begins). */
664
+ before: "before",
665
+ /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
666
+ * loops that continue once the main timeline has finished). */
667
+ after: "after"
668
+ };
669
+ var PxMaskType = {
670
+ luminance: "luminance",
671
+ alpha: "alpha"
672
+ };
673
+ var PxUnits = {
674
+ userSpaceOnUse: "userSpaceOnUse",
675
+ objectBoundingBox: "objectBoundingBox"
676
+ };
677
+ var PxCloneType = {
678
+ content: "content"
679
+ };
680
+ var PxPathOverflow = {
681
+ clip: "clip",
682
+ extend: "extend"
683
+ };
684
+ var PxLengthAdjust = {
685
+ spacing: "spacing",
686
+ spacingAndGlyphs: "spacingAndGlyphs"
687
+ };
688
+ var PxTextPathMethod = {
689
+ align: "align",
690
+ stretch: "stretch"
691
+ };
692
+ var PxTextPathSpacing = {
693
+ auto: "auto",
694
+ exact: "exact"
695
+ };
696
+ var PxTrimSubPaths = {
697
+ separate: "separate",
698
+ combined: "combined"
699
+ };
639
700
  var TEXT_ATTR = "text";
640
701
  var TEXT_CONTENT_ATTR = "textContent";
641
702
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
@@ -644,9 +705,49 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
644
705
  "animator",
645
706
  "meta",
646
707
  "animate",
708
+ "effects",
647
709
  TEXT_ATTR,
648
710
  TEXT_CONTENT_ATTR
649
711
  ]);
712
+ var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
713
+ var PxGradientUnits = {
714
+ userSpaceOnUse: "userSpaceOnUse",
715
+ objectBoundingBox: "objectBoundingBox"
716
+ };
717
+ var PxGradientSpreadMethod = {
718
+ pad: "pad",
719
+ reflect: "reflect",
720
+ repeat: "repeat"
721
+ };
722
+ var PxGradientType = {
723
+ linear: "linear",
724
+ radial: "radial"
725
+ };
726
+ function isPxElementFileFormat(fileJson) {
727
+ if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
728
+ return false;
729
+ }
730
+ return fileJson["type"] === "svg";
731
+ }
732
+ function getAnimatorConfig(doc) {
733
+ var _a;
734
+ return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
735
+ }
736
+ function getDefs(doc) {
737
+ var _a;
738
+ if (!doc) return void 0;
739
+ return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
740
+ }
741
+ function getBindings(doc) {
742
+ var _a;
743
+ if (!doc) return void 0;
744
+ const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
745
+ if (!animateById) return void 0;
746
+ return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));
747
+ }
748
+ function getChildren(doc) {
749
+ return doc == null ? void 0 : doc.children;
750
+ }
650
751
  var PxEasingOrRefSchema = px.union([
651
752
  px.string(),
652
753
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -658,13 +759,15 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
658
759
  px.array(px.number()),
659
760
  px.lazy(() => PxTransformPartsSchema, {}),
660
761
  px.object({ path: px.string() }),
661
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] })
762
+ px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
763
+ // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
764
+ px.lazy(() => px.array(PxGradientStopSchema), [])
662
765
  ]));
663
766
  var PxKeyframeSchema = implementsInterface()(px.object({
664
767
  time: px.number().optional(),
665
768
  t: px.number().optional(),
666
- value: px.any().optional(),
667
- v: px.any().optional(),
769
+ value: PxKeyframeValueSchema.optional(),
770
+ v: PxKeyframeValueSchema.optional(),
668
771
  easing: PxEasingOrRefSchema.optional(),
669
772
  e: PxEasingOrRefSchema.optional(),
670
773
  tangentOut: px.tuple([px.number(), px.number()]).optional(),
@@ -678,16 +781,16 @@ var PxKeyframeSchema = implementsInterface()(px.object({
678
781
  }));
679
782
  var PxLoopSchema = implementsInterface()(px.object({
680
783
  segmentCount: px.number().optional(),
681
- before: px.boolean().optional(),
784
+ extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
682
785
  alternate: px.boolean().optional()
683
786
  }));
684
787
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
788
+ value: PxKeyframeValueSchema.optional(),
685
789
  keyframes: px.array(PxKeyframeSchema).optional(),
686
790
  kfs: px.array(PxKeyframeSchema).optional(),
687
791
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
688
792
  autoOrient: px.boolean().optional()
689
793
  }));
690
- var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
691
794
  var PxTransformPartsSchema = implementsInterface()(px.object({
692
795
  translate: px.tuple([px.number(), px.number()]).optional(),
693
796
  rotate: px.number().optional(),
@@ -697,6 +800,7 @@ var PxTransformPartsSchema = implementsInterface()(px.object({
697
800
  }));
698
801
  var PxTransformValueSchema = px.union([
699
802
  px.string(),
803
+ PxTransformPartsSchema,
700
804
  px.object({ value: PxTransformPartsSchema }),
701
805
  PxPropertyAnimationSchema
702
806
  ]);
@@ -731,9 +835,11 @@ var PxDefsSchema = implementsInterface()(px.object({
731
835
  glyphs: px.record(PxGlyphFontSchema).optional()
732
836
  }));
733
837
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
734
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
838
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
735
839
  duration: px.number().optional(),
736
840
  delay: px.number().optional(),
841
+ // LAW (SCHEMA-DESIGN R3, S10): the ONE sanctioned string-in-number union
842
+ // (CSS animation-iteration-count familiarity) — do not add more mixed unions.
737
843
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
738
844
  fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
739
845
  direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
@@ -741,8 +847,8 @@ var PxAnimatorConfigSchema = implementsInterface()(px.object({
741
847
  trigger: PxTriggerSchema.optional(),
742
848
  resetOnFinish: px.boolean().optional(),
743
849
  definitions: PxDefsSchema.optional(),
744
- animate: px.record(PxElementAnimationSchema).optional(),
745
- debug: px.boolean().optional(),
850
+ animateById: px.record(PxElementAnimationSchema).optional(),
851
+ timelineSource: px.string().optional(),
746
852
  debugInstName: px.string().optional()
747
853
  }));
748
854
  var PxBindingSchema = implementsInterface()(px.object({
@@ -752,26 +858,29 @@ var PxBindingSchema = implementsInterface()(px.object({
752
858
  var PxAttrValueSchema = px.union([
753
859
  px.string(),
754
860
  px.number(),
755
- px.object({ value: px.any() }),
756
- PxPropertyAnimationSchema
861
+ px.array(px.number()),
862
+ // Structured static — `{value: …}` (read-accepted transitional spelling, S1).
863
+ // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).
864
+ px.object({ value: px.defined() }),
865
+ // Bare transform parts record — the canonical static `transform` on the wire (T2).
866
+ PxTransformPartsSchema
757
867
  ]);
758
868
  var PxAnimatableNumberSchema = px.union([
759
869
  px.number(),
760
870
  px.object({ value: px.number() }),
761
- px.object({
762
- keyframes: px.array(PxKeyframeSchema),
763
- autoOrient: px.boolean().optional()
764
- })
871
+ PxPropertyAnimationSchema
765
872
  ]);
766
873
  var PxAnimatableVec2Schema = px.union([
767
874
  px.tuple([px.number(), px.number()]),
768
875
  px.object({ value: px.tuple([px.number(), px.number()]) }),
769
- px.object({
770
- keyframes: px.array(PxKeyframeSchema),
771
- autoOrient: px.boolean().optional()
772
- })
876
+ PxPropertyAnimationSchema
773
877
  ]);
774
- var PxTransformationEffectSchema = implementsInterface()(px.object({
878
+ var PxAnimatableStringSchema = px.union([
879
+ px.string(),
880
+ px.object({ value: px.string() }),
881
+ PxPropertyAnimationSchema
882
+ ]);
883
+ var PxTransformByEffectSchema = implementsInterface()(px.object({
775
884
  translate: PxAnimatableVec2Schema.optional(),
776
885
  rotate: PxAnimatableNumberSchema.optional(),
777
886
  scale: PxAnimatableVec2Schema.optional(),
@@ -779,51 +888,46 @@ var PxTransformationEffectSchema = implementsInterface()(px.object({
779
888
  origin: PxAnimatableVec2Schema.optional()
780
889
  }));
781
890
  var PxRepeaterEffectSchema = implementsInterface()(px.object({
891
+ // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
892
+ // once at expansion time and never sampled — plain number, no `keyframes`.
782
893
  copies: px.number().optional(),
783
894
  translate: PxAnimatableVec2Schema.optional(),
784
895
  rotate: PxAnimatableNumberSchema.optional(),
896
+ skew: PxAnimatableNumberSchema.optional(),
785
897
  scale: PxAnimatableVec2Schema.optional(),
786
898
  origin: PxAnimatableVec2Schema.optional()
787
899
  }));
788
900
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
789
- href: px.string().optional(),
790
- maskType: px.string().optional(),
791
- maskUnits: px.string().optional(),
792
- maskContentUnits: px.string().optional()
901
+ sourceId: px.string().optional(),
902
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
903
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
904
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
905
+ x: px.number().optional(),
906
+ y: px.number().optional(),
907
+ width: px.number().optional(),
908
+ height: px.number().optional()
793
909
  }));
794
910
  var PxClipPathEffectSchema = implementsInterface()(px.object({
795
- d: px.string().optional(),
911
+ d: PxAnimatableStringSchema.optional(),
796
912
  animate: PxPropertyAnimationSchema.optional()
797
913
  }));
798
914
  var PxTrimPathEffectSchema = implementsInterface()(px.object({
799
915
  offset: PxAnimatableNumberSchema.optional(),
800
916
  range: PxAnimatableVec2Schema.optional(),
801
- trimAllAsOne: px.boolean().optional()
917
+ subPaths: px.enum([PxTrimSubPaths.separate, PxTrimSubPaths.combined]).optional()
802
918
  }));
803
919
  var PxRetimeEffectSchema = implementsInterface()(px.object({
804
- baseId: px.string().optional(),
920
+ sourceId: px.string().optional(),
805
921
  start: px.number().optional(),
806
922
  stretch: px.number().optional(),
807
923
  timeCrop: px.tuple([px.number(), px.number()]).optional()
808
924
  }));
809
925
  var PxCloneEffectSchema = implementsInterface()(px.object({
810
- type: px.string().optional(),
811
- baseId: px.string().optional(),
926
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
927
+ type: px.enum([PxCloneType.content]).optional(),
928
+ sourceId: px.string().optional(),
812
929
  retime: PxRetimeEffectSchema.optional()
813
930
  }));
814
- var PxGradientUnits = {
815
- userSpaceOnUse: "userSpaceOnUse",
816
- objectBoundingBox: "objectBoundingBox"
817
- };
818
- var PxGradientSpreadMethod = {
819
- pad: "pad",
820
- reflect: "reflect",
821
- repeat: "repeat"
822
- };
823
- var PxGradientType = {
824
- linear: "linear",
825
- radial: "radial"
826
- };
827
931
  var PxGradientStopSchema = implementsInterface()(px.object({
828
932
  offset: px.number(),
829
933
  color: px.string()
@@ -831,27 +935,28 @@ var PxGradientStopSchema = implementsInterface()(px.object({
831
935
  var PxAnimatableGradientStopsSchema = px.union([
832
936
  px.array(PxGradientStopSchema),
833
937
  px.object({ value: px.array(PxGradientStopSchema) }),
834
- px.object({ keyframes: px.array(PxKeyframeSchema) })
938
+ PxPropertyAnimationSchema
835
939
  ]);
836
940
  var PxFillGradientEffectSchema = implementsInterface()(px.object({
941
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
837
942
  type: px.enum([PxGradientType.linear, PxGradientType.radial]),
838
- p1: px.tuple([px.number(), px.number()]).optional(),
839
- p2: px.tuple([px.number(), px.number()]).optional(),
840
- c: px.tuple([px.number(), px.number()]).optional(),
841
- r: px.number().optional(),
842
- fp: px.tuple([px.number(), px.number()]).optional(),
943
+ p1: PxAnimatableVec2Schema.optional(),
944
+ p2: PxAnimatableVec2Schema.optional(),
945
+ c: PxAnimatableVec2Schema.optional(),
946
+ r: PxAnimatableNumberSchema.optional(),
947
+ fp: PxAnimatableVec2Schema.optional(),
843
948
  stops: PxAnimatableGradientStopsSchema.optional(),
844
- gradientUnits: px.string().optional(),
845
- spreadMethod: px.string().optional(),
949
+ gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
950
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
846
951
  gradientTransform: px.string().optional()
847
952
  }));
848
953
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
849
954
  var PxTextPathEffectSchema = implementsInterface()(px.object({
850
955
  path: px.string(),
851
- pathOverflow: px.string().optional(),
852
- lengthAdjust: px.string().optional(),
853
- method: px.string().optional(),
854
- spacing: px.string().optional(),
956
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
957
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
958
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
959
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
855
960
  startOffset: PxAnimatableNumberSchema.optional(),
856
961
  textLength: PxAnimatableNumberSchema.optional()
857
962
  }));
@@ -859,13 +964,12 @@ var PxTextEffectSchema = implementsInterface()(px.object({
859
964
  useGlyphs: px.boolean().optional()
860
965
  }));
861
966
  var PxEffectsSchema = implementsInterface()(px.object({
862
- transformation: PxTransformationEffectSchema.optional(),
967
+ transformBy: PxTransformByEffectSchema.optional(),
863
968
  repeater: PxRepeaterEffectSchema.optional(),
864
969
  maskedBy: PxMaskedByEffectSchema.optional(),
865
970
  clipPath: PxClipPathEffectSchema.optional(),
866
971
  trimPath: PxTrimPathEffectSchema.optional(),
867
972
  clone: PxCloneEffectSchema.optional(),
868
- isCombinedShape: px.boolean().optional(),
869
973
  fillGradient: PxFillGradientEffectSchema.optional(),
870
974
  strokeGradient: PxStrokeGradientEffectSchema.optional(),
871
975
  textPath: PxTextPathEffectSchema.optional(),
@@ -889,6 +993,14 @@ function validateNodeEffects(root, opts) {
889
993
  return warnings;
890
994
  }
891
995
  var PxNodeBase = px.openObject({
996
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
997
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
998
+ // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
999
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1000
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1001
+ // would add words that all mean "type" and still need the carrier to read.
1002
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1003
+ // (issues V3), never of distinct key names.
892
1004
  type: px.string(),
893
1005
  id: px.string().optional(),
894
1006
  meta: px.any().optional(),
@@ -898,7 +1010,7 @@ var PxNodeBase = px.openObject({
898
1010
  effects: PxEffectsSchema.optional(),
899
1011
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
900
1012
  // string ref / array of refs / inline definition / mixed array; mirrors
901
- // `animator.animate` map values and what `processNode` resolves at runtime.
1013
+ // `animator.animateById` map values and what `processNode` resolves at runtime.
902
1014
  animate: PxElementAnimationSchema.optional(),
903
1015
  style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
904
1016
  }, PxAttrValueSchema);
@@ -922,35 +1034,10 @@ var PxBezierPathSchema = implementsInterface()(px.object({
922
1034
  o: px.array(px.array(px.number())).optional(),
923
1035
  c: px.boolean().optional()
924
1036
  }));
925
- function isPxElementFileFormat(fileJson) {
926
- if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
927
- return false;
928
- }
929
- return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
930
- }
931
1037
  function isPxElementFileFormatDeep(fileJson) {
932
1038
  const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
933
1039
  return { valid, errors: valid ? [] : ["Document failed schema validation"] };
934
1040
  }
935
- function getAnimatorConfig(doc) {
936
- var _a, _b;
937
- 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);
938
- }
939
- function getDefs(doc) {
940
- var _a;
941
- if (!doc) return void 0;
942
- return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
943
- }
944
- function getBindings(doc) {
945
- var _a;
946
- if (!doc) return void 0;
947
- const animate = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animate;
948
- if (!animate) return void 0;
949
- return Object.entries(animate).map(([id, anim]) => ({ id, animate: anim }));
950
- }
951
- function getChildren(doc) {
952
- return doc == null ? void 0 : doc.children;
953
- }
954
1041
  function bezierToSvgPath(path, forceCurves = false) {
955
1042
  var _a, _b, _c, _d;
956
1043
  const v = path.v;
@@ -1401,7 +1488,7 @@ function generateNewIds(doc) {
1401
1488
  "flood-color",
1402
1489
  "lighting-color"
1403
1490
  ]);
1404
- const directIdRefAttrs = /* @__PURE__ */ new Set(["baseId", "targetId", "boundElementId"]);
1491
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
1405
1492
  function collectIds(node) {
1406
1493
  if (!node || typeof node !== "object") return;
1407
1494
  if (node.id && typeof node.id === "string") {
@@ -1439,9 +1526,10 @@ function generateNewIds(doc) {
1439
1526
  } else if (urlRefAttrs.has(key)) {
1440
1527
  node[key] = replaceUrlRefs(value, idMap);
1441
1528
  } else if (directIdRefAttrs.has(key)) {
1442
- const newId = idMap.get(value);
1529
+ const hasHash = value.startsWith("#");
1530
+ const newId = idMap.get(hasHash ? value.slice(1) : value);
1443
1531
  if (newId) {
1444
- node[key] = newId;
1532
+ node[key] = hasHash ? "#" + newId : newId;
1445
1533
  }
1446
1534
  } else if (value.includes("url(#")) {
1447
1535
  node[key] = replaceUrlRefs(value, idMap);
@@ -1459,14 +1547,14 @@ function generateNewIds(doc) {
1459
1547
  }
1460
1548
  collectIds(cloned);
1461
1549
  updateRefs(cloned);
1462
- const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animate;
1550
+ const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
1463
1551
  if (docAnimate && typeof docAnimate === "object") {
1464
1552
  const updatedAnimate = {};
1465
1553
  for (const [id, anim] of Object.entries(docAnimate)) {
1466
1554
  const newId = (_b = idMap.get(id)) != null ? _b : id;
1467
1555
  updatedAnimate[newId] = anim;
1468
1556
  }
1469
- cloned.animator = __spreadProps2(__spreadValues2({}, cloned.animator), { animate: updatedAnimate });
1557
+ cloned.animator = __spreadProps2(__spreadValues2({}, cloned.animator), { animateById: updatedAnimate });
1470
1558
  }
1471
1559
  return cloned;
1472
1560
  }
@@ -1555,8 +1643,9 @@ function getNormalizedProps(props) {
1555
1643
  let value = props[rawKey];
1556
1644
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1557
1645
  propsCopy[key] = toRGBA(value);
1558
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
1559
- propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
1646
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes && !value.kfs) {
1647
+ const parts = value.value && typeof value.value === "object" ? value.value : value;
1648
+ propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
1560
1649
  } else if (TRANSFORM_FN_NAMES.has(key)) {
1561
1650
  if (Array.isArray(value)) {
1562
1651
  if (key === "translate") value = value.map((v) => v + "px");
@@ -1564,6 +1653,8 @@ function getNormalizedProps(props) {
1564
1653
  }
1565
1654
  if (key === "rotate") value = value + "deg";
1566
1655
  propsCopy["transform"] = key + "(" + value + ")";
1656
+ } else if (Array.isArray(value)) {
1657
+ propsCopy[key] = value.join(",");
1567
1658
  } else if (value !== void 0 && value !== null) {
1568
1659
  propsCopy[key] = String(value);
1569
1660
  }
@@ -1961,6 +2052,16 @@ function walkAndMaterialise(node, opts) {
1961
2052
  if (newAnimate) cloned.animate = newAnimate;
1962
2053
  return cloned;
1963
2054
  }
2055
+ var LOOP_JUMP_SHIFT_MS = 10;
2056
+ function deepEqualValue(a, b) {
2057
+ if (a === b) return true;
2058
+ if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
2059
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
2060
+ const ka = Object.keys(a);
2061
+ const kb = Object.keys(b);
2062
+ if (ka.length !== kb.length) return false;
2063
+ return ka.every((k) => deepEqualValue(a[k], b[k]));
2064
+ }
1964
2065
  function parsePathCommands(d) {
1965
2066
  const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
1966
2067
  const commands = [];
@@ -2163,7 +2264,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2163
2264
  const totalIntervals = keyframes.length - 1;
2164
2265
  const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2165
2266
  let segKfs;
2166
- if (loop.before) {
2267
+ if (loop.extend === PxLoopExtend.before) {
2167
2268
  segKfs = keyframes.slice(0, segCount + 1);
2168
2269
  } else {
2169
2270
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -2171,7 +2272,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2171
2272
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2172
2273
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2173
2274
  let fillStart, fillEnd;
2174
- if (loop.before) {
2275
+ if (loop.extend === PxLoopExtend.before) {
2175
2276
  fillStart = 0;
2176
2277
  fillEnd = firstT;
2177
2278
  } else {
@@ -2198,7 +2299,10 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2198
2299
  const remainder = fillDuration - fullReps * segDuration;
2199
2300
  const partialFraction = remainder / segDuration;
2200
2301
  const looped = [];
2302
+ const separateBoundary = loop.extend !== PxLoopExtend.before;
2303
+ const originalTerminalKf = keyframes[keyframes.length - 1];
2201
2304
  function appendRep(repStart, isReversed, partial) {
2305
+ var _a2;
2202
2306
  let entries;
2203
2307
  if (isReversed) {
2204
2308
  entries = [];
@@ -2234,8 +2338,17 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2234
2338
  looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
2235
2339
  return;
2236
2340
  }
2341
+ const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2342
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2343
+ if (isBoundary) {
2344
+ if (deepEqualValue(prevKf.v, entry.v)) continue;
2345
+ if (looped.length > 0) {
2346
+ delete prevKf.tangentIn;
2347
+ delete prevKf.tangentOut;
2348
+ }
2349
+ }
2237
2350
  const pushed = {
2238
- t: repStart + entry.relT * segDuration,
2351
+ t: repStart + entry.relT * segDuration + (isBoundary ? LOOP_JUMP_SHIFT_MS : 0),
2239
2352
  v: entry.v,
2240
2353
  e: i < entries.length - 1 ? entry.e : void 0
2241
2354
  };
@@ -2283,7 +2396,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2283
2396
  looped.push(pushed);
2284
2397
  }
2285
2398
  }
2286
- if (loop.before) {
2399
+ if (loop.extend === PxLoopExtend.before) {
2287
2400
  if (partialFraction > 1e-9) {
2288
2401
  const isReversed = !!loop.alternate && fullReps % 2 === 0;
2289
2402
  appendRepTail(fillStart, isReversed, partialFraction);
@@ -2306,7 +2419,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2306
2419
  appendRep(repStart, isReversed, partialFraction);
2307
2420
  }
2308
2421
  }
2309
- if (loop.before) {
2422
+ if (loop.extend === PxLoopExtend.before) {
2310
2423
  return [...looped, ...keyframes];
2311
2424
  } else {
2312
2425
  return [...keyframes, ...looped];
@@ -2422,7 +2535,7 @@ var _elementIdCounter = 0;
2422
2535
  function generateElementId() {
2423
2536
  return "_px_el_" + ++_elementIdCounter;
2424
2537
  }
2425
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.webapi) {
2538
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2426
2539
  const normalized = {};
2427
2540
  for (const [propName, propAnim] of Object.entries(animDef)) {
2428
2541
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
@@ -2430,12 +2543,12 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimat
2430
2543
  const out = { kfs: normalizedKfs };
2431
2544
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2432
2545
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2433
- normalized[propName] = engine === PxAnimatorEngine.webapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2546
+ normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2434
2547
  }
2435
2548
  }
2436
2549
  return normalized;
2437
2550
  }
2438
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.webapi) {
2551
+ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2439
2552
  const animatorConfig = getAnimatorConfig(doc) || {};
2440
2553
  const defs = getDefs(doc);
2441
2554
  const duration = animatorConfig.duration || 1e3;
@@ -2840,6 +2953,7 @@ function partsRecord(part, value, origin) {
2840
2953
  return rec;
2841
2954
  }
2842
2955
  function readAnimatable(raw) {
2956
+ var _a, _b, _c;
2843
2957
  if (raw === void 0) return {
2844
2958
  kind: "absent"
2845
2959
  /* Absent */
@@ -2847,19 +2961,56 @@ function readAnimatable(raw) {
2847
2961
  if (Array.isArray(raw)) return { kind: "static", value: raw };
2848
2962
  if (typeof raw === "object") {
2849
2963
  const obj = raw;
2850
- if (obj.keyframes) {
2851
- return { kind: "animated", keyframes: obj.keyframes, autoOrient: obj.autoOrient, loop: obj.loop };
2964
+ const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
2965
+ if (kfs) {
2966
+ const out = { kind: "animated", keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
2967
+ const base = (_b = obj.value) != null ? _b : obj.v;
2968
+ if (base !== void 0 && out.kind === "animated") out.base = base;
2969
+ return out;
2852
2970
  }
2853
- if (obj.value !== void 0) return { kind: "static", value: obj.value };
2971
+ const staticValue = (_c = obj.value) != null ? _c : obj.v;
2972
+ if (staticValue !== void 0) return { kind: "static", value: staticValue };
2854
2973
  }
2855
2974
  return { kind: "static", value: raw };
2856
2975
  }
2976
+ function writeAnimatableChannel(node, attrName, read, opts) {
2977
+ var _a, _b, _c, _d;
2978
+ const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
2979
+ if (read.kind === "absent") return;
2980
+ if (read.kind === "static") {
2981
+ node[attrName] = toOut(read.value);
2982
+ return;
2983
+ }
2984
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
2985
+ const animate = __spreadValues2({}, prevAnimate || {});
2986
+ const block = { keyframes: read.keyframes };
2987
+ if (read.loop !== void 0) block.loop = read.loop;
2988
+ if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
2989
+ animate[attrName] = block;
2990
+ node.animate = animate;
2991
+ 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;
2992
+ if (baseline !== void 0) node[attrName] = toOut(baseline);
2993
+ }
2994
+ function normaliseKeyframe(kf) {
2995
+ if (!kf || typeof kf !== "object") return kf;
2996
+ const k = kf;
2997
+ if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
2998
+ return kf;
2999
+ }
3000
+ const out = __spreadValues2({}, k);
3001
+ if (out.time === void 0 && k.t !== void 0) out.time = k.t;
3002
+ if (out.value === void 0 && k.v !== void 0) out.value = k.v;
3003
+ if (out.easing === void 0 && k.e !== void 0) out.easing = k.e;
3004
+ if (out.tangentOut === void 0 && k.to !== void 0) out.tangentOut = k.to;
3005
+ if (out.tangentIn === void 0 && k.ti !== void 0) out.tangentIn = k.ti;
3006
+ return out;
3007
+ }
2857
3008
  function readStaticOrigin(raw, ctx) {
2858
3009
  var _a;
2859
3010
  const o = readAnimatable(raw);
2860
3011
  if (o.kind === "absent") return void 0;
2861
3012
  if (o.kind === "static") return o.value;
2862
- ctx.warnings.push("transformation.origin: animated origin approximated by its first keyframe");
3013
+ ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
2863
3014
  return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
2864
3015
  }
2865
3016
  function keyframeWith(kf, value) {
@@ -2870,7 +3021,7 @@ function keyframeWith(kf, value) {
2870
3021
  if (kf.tangentIn !== void 0) out.tangentIn = kf.tangentIn;
2871
3022
  return out;
2872
3023
  }
2873
- function applyTransformationEffect(node, fx, ctx) {
3024
+ function applyTransformByEffect(node, fx, ctx) {
2874
3025
  if (!fx) return node;
2875
3026
  delete node.transform;
2876
3027
  let n = node;
@@ -2906,6 +3057,10 @@ function applyTransformationEffect(node, fx, ctx) {
2906
3057
  } else {
2907
3058
  n = wrapTransformPart(n, "translate", fx.translate, ctx);
2908
3059
  }
3060
+ if (n !== node && node.id) {
3061
+ n.id = node.id;
3062
+ delete node.id;
3063
+ }
2909
3064
  return n;
2910
3065
  }
2911
3066
  function translateHasAutoOrient(translate) {
@@ -2915,8 +3070,6 @@ function translateHasAutoOrient(translate) {
2915
3070
  return Array.isArray(obj.keyframes) && obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
2916
3071
  }
2917
3072
  function normalizeScale(raw) {
2918
- if (raw === void 0) return void 0;
2919
- if (Array.isArray(raw)) return [raw[0] / 100, raw[1] / 100];
2920
3073
  return raw;
2921
3074
  }
2922
3075
  function wrapTransformPart(inner, part, raw, ctx) {
@@ -2957,34 +3110,54 @@ function wrapOrigin(inner, raw, invert) {
2957
3110
  }
2958
3111
  return inner;
2959
3112
  }
3113
+ function genId(ctx, prefix) {
3114
+ return "_lw_" + prefix + "_" + ctx.nextId++;
3115
+ }
3116
+ function stripHash2(href) {
3117
+ return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3118
+ }
3119
+ function indexById(node, map) {
3120
+ var _a;
3121
+ if (typeof node.id === "string") map.set(node.id, node);
3122
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3123
+ }
3124
+ function spliceDefs(root, defs) {
3125
+ if (!defs.length) return;
3126
+ const existing = root.children || (root.children = []);
3127
+ existing.unshift({ type: "defs", children: defs });
3128
+ }
3129
+ var clone = deepClonePxNode;
3130
+ function regenerateIdsInClone(root, ctx) {
3131
+ return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3132
+ }
2960
3133
  function identifyContentRefTargets(node, ctx, allocator) {
2961
3134
  var _a, _b, _c;
2962
3135
  if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.type) === "content") {
2963
- const baseId = node.effects.clone.baseId;
2964
- if (typeof baseId === "string" && baseId && !ctx.contentRefInnerIds.has(baseId)) {
2965
- ctx.contentRefInnerIds.set(baseId, allocator(baseId));
3136
+ const sourceId = stripHash2(node.effects.clone.sourceId);
3137
+ if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3138
+ ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
2966
3139
  }
2967
3140
  }
2968
3141
  (_c = node.children) == null ? void 0 : _c.forEach((c) => identifyContentRefTargets(c, ctx, allocator));
2969
3142
  }
2970
- function splitForContentRef(node, transformation, originalId, innerId, ctx) {
2971
- const outerBody = liftBodyTranslate(node, transformation);
3143
+ function splitForContentRef(node, transformBy, originalId, innerId, ctx) {
3144
+ const outerBody = liftBodyTranslate(node, transformBy);
2972
3145
  if (typeof node.id === "string") delete node.id;
2973
- const { outer: outerTr, inner: innerTr } = splitTransformationEffect(transformation);
3146
+ const { outer: outerTr, inner: innerTr } = splitTransformByEffect(transformBy);
2974
3147
  let innerNode = node;
2975
- innerNode = applyTransformationEffect(innerNode, innerTr, ctx);
3148
+ innerNode = applyTransformByEffect(innerNode, innerTr, ctx);
2976
3149
  const innerWrapper = { type: "g", id: innerId, children: [innerNode] };
2977
3150
  let outerWrapper = { type: "g", id: originalId, children: [innerWrapper] };
2978
3151
  if (outerBody.transform !== void 0) outerWrapper.transform = outerBody.transform;
2979
3152
  if (outerBody.animate !== void 0) outerWrapper.animate = outerBody.animate;
2980
3153
  if (outerTr) {
2981
3154
  delete outerWrapper.id;
2982
- outerWrapper = applyTransformationEffect(outerWrapper, outerTr, ctx);
3155
+ outerWrapper = applyTransformByEffect(outerWrapper, outerTr, ctx);
2983
3156
  outerWrapper.id = originalId;
2984
3157
  }
2985
3158
  return outerWrapper;
2986
3159
  }
2987
- function liftBodyTranslate(node, transformation) {
3160
+ function liftBodyTranslate(node, transformBy) {
2988
3161
  var _a, _b, _c;
2989
3162
  const out = {};
2990
3163
  let didLiftAnimate = false;
@@ -3038,7 +3211,7 @@ function liftBodyTranslate(node, transformation) {
3038
3211
  didLiftAnimate = true;
3039
3212
  }
3040
3213
  }
3041
- const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
3214
+ const transformationHasTranslate = (transformBy == null ? void 0 : transformBy.translate) !== void 0;
3042
3215
  const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
3043
3216
  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);
3044
3217
  if (typeof node.transform === "string") {
@@ -3057,6 +3230,24 @@ function liftBodyTranslate(node, transformation) {
3057
3230
  if (split.rest) node.transform = split.rest;
3058
3231
  else delete node.transform;
3059
3232
  }
3233
+ } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes && !node.transform.kfs) {
3234
+ const wrapped = node.transform.value;
3235
+ const isWrapped = !!(wrapped && typeof wrapped === "object");
3236
+ const value = isWrapped ? wrapped : node.transform;
3237
+ const rewrap = (rec) => isWrapped ? { value: rec } : rec;
3238
+ if (Array.isArray(value.translate)) {
3239
+ const rest = __spreadValues2({}, value);
3240
+ delete rest.translate;
3241
+ const hasRest = Object.keys(rest).length > 0;
3242
+ if (stripBodyTranslateOnly) {
3243
+ if (hasRest) node.transform = rewrap(rest);
3244
+ else delete node.transform;
3245
+ } else {
3246
+ out.transform = rewrap({ translate: value.translate });
3247
+ if (hasRest) node.transform = rewrap(rest);
3248
+ else delete node.transform;
3249
+ }
3250
+ }
3060
3251
  }
3061
3252
  return out;
3062
3253
  }
@@ -3126,7 +3317,7 @@ function parseTranslateArgs(translateOp) {
3126
3317
  const nums = m[1].split(/[\s,]+/).filter(Boolean).map(Number);
3127
3318
  return [nums[0] || 0, nums[1] || 0];
3128
3319
  }
3129
- function splitTransformationEffect(fx) {
3320
+ function splitTransformByEffect(fx) {
3130
3321
  if (!fx) return {};
3131
3322
  const originOnOuter = needsOriginOnOuter(fx.translate);
3132
3323
  const innerHasPivotedPart = fx.rotate !== void 0 || fx.scale !== void 0;
@@ -3152,26 +3343,6 @@ function needsOriginOnOuter(translateAnim) {
3152
3343
  }
3153
3344
  return false;
3154
3345
  }
3155
- function genId(ctx, prefix) {
3156
- return "_lw_" + prefix + "_" + ctx.nextId++;
3157
- }
3158
- function stripHash2(href) {
3159
- return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3160
- }
3161
- function indexById(node, map) {
3162
- var _a;
3163
- if (typeof node.id === "string") map.set(node.id, node);
3164
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3165
- }
3166
- function spliceDefs(root, defs) {
3167
- if (!defs.length) return;
3168
- const existing = root.children || (root.children = []);
3169
- existing.unshift({ type: "defs", children: defs });
3170
- }
3171
- var clone = deepClonePxNode;
3172
- function regenerateIdsInClone(root, ctx) {
3173
- return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3174
- }
3175
3346
  function applyFillGradientEffect(node, fx, ctx) {
3176
3347
  return applyGradient(node, fx, ctx, "fill");
3177
3348
  }
@@ -3192,62 +3363,63 @@ function synthesiseGradientDef(fx, id, ctx) {
3192
3363
  id
3193
3364
  };
3194
3365
  if (fx.type === PxGradientType.linear) {
3195
- if (fx.p1) {
3196
- out.x1 = String(fx.p1[0]);
3197
- out.y1 = String(fx.p1[1]);
3198
- }
3199
- if (fx.p2) {
3200
- out.x2 = String(fx.p2[0]);
3201
- out.y2 = String(fx.p2[1]);
3202
- }
3366
+ applyGeomVec(out, "x1", "y1", fx.p1);
3367
+ applyGeomVec(out, "x2", "y2", fx.p2);
3203
3368
  } else {
3204
- if (fx.c) {
3205
- out.cx = String(fx.c[0]);
3206
- out.cy = String(fx.c[1]);
3207
- }
3208
- if (fx.r !== void 0) out.r = String(fx.r);
3209
- if (fx.fp) {
3210
- out.fx = String(fx.fp[0]);
3211
- out.fy = String(fx.fp[1]);
3212
- }
3369
+ applyGeomVec(out, "cx", "cy", fx.c);
3370
+ applyGeomNumber(out, "r", fx.r);
3371
+ applyGeomVec(out, "fx", "fy", fx.fp);
3213
3372
  }
3214
3373
  if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
3215
3374
  if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
3216
3375
  if (fx.gradientTransform) out.gradientTransform = fx.gradientTransform;
3217
- const animate = fx.animate;
3218
- if (animate) {
3219
- const mapped = {};
3220
- for (const wireKey of Object.keys(animate)) {
3221
- const attr = GRADIENT_ANIM_CHANNEL_TO_ATTR[wireKey];
3222
- if (attr) mapped[attr] = animate[wireKey];
3223
- }
3224
- if (Object.keys(mapped).length) out.animate = mapped;
3225
- }
3226
3376
  out.children = buildStopChildren(fx.stops, ctx);
3227
3377
  return out;
3228
3378
  }
3229
- var GRADIENT_ANIM_CHANNEL_TO_ATTR = {
3230
- gradientX1: "x1",
3231
- gradientY1: "y1",
3232
- gradientX2: "x2",
3233
- gradientY2: "y2",
3234
- gradientCx: "cx",
3235
- gradientCy: "cy",
3236
- gradientFx: "fx",
3237
- gradientFy: "fy",
3238
- gradientR: "r"
3239
- };
3379
+ function applyGeomVec(out, xAttr, yAttr, raw) {
3380
+ var _a, _b, _c;
3381
+ const read = readAnimatable(raw);
3382
+ if (read.kind === "absent") return;
3383
+ if (read.kind === "static") {
3384
+ out[xAttr] = String(read.value[0]);
3385
+ out[yAttr] = String(read.value[1]);
3386
+ return;
3387
+ }
3388
+ const axisChannel = (idx) => {
3389
+ const block = {
3390
+ keyframes: read.keyframes.map((kf) => {
3391
+ const axisKf = { time: kf.time, value: Array.isArray(kf.value) ? kf.value[idx] : void 0 };
3392
+ if (kf.easing !== void 0) axisKf.easing = kf.easing;
3393
+ return axisKf;
3394
+ })
3395
+ };
3396
+ if (read.loop !== void 0) block.loop = read.loop;
3397
+ return block;
3398
+ };
3399
+ const animate = (_a = out.animate) != null ? _a : {};
3400
+ animate[xAttr] = axisChannel(0);
3401
+ animate[yAttr] = axisChannel(1);
3402
+ out.animate = animate;
3403
+ const baseline = (_c = read.base) != null ? _c : (_b = read.keyframes[0]) == null ? void 0 : _b.value;
3404
+ if (Array.isArray(baseline)) {
3405
+ out[xAttr] = String(baseline[0]);
3406
+ out[yAttr] = String(baseline[1]);
3407
+ }
3408
+ }
3409
+ function applyGeomNumber(out, attrName, raw) {
3410
+ const read = readAnimatable(raw);
3411
+ if (read.kind === "absent") return;
3412
+ writeAnimatableChannel(out, attrName, read, { asString: true });
3413
+ }
3240
3414
  function buildStopChildren(stops, ctx) {
3241
3415
  var _a, _b, _c, _d;
3242
3416
  if (!stops) return [];
3243
- if (Array.isArray(stops)) return stops.map(staticStopNode);
3244
- if (typeof stops === "object" && Array.isArray(stops.value)) {
3245
- return stops.value.map(staticStopNode);
3246
- }
3247
- const animBlock = stops;
3248
- const kfs = animBlock.keyframes;
3249
- if (!Array.isArray(kfs) || !kfs.length) return [];
3250
- const loopFromSource = animBlock.loop;
3417
+ const read = readAnimatable(stops);
3418
+ if (read.kind === "absent") return [];
3419
+ if (read.kind === "static") return Array.isArray(read.value) ? read.value.map(staticStopNode) : [];
3420
+ const kfs = read.keyframes;
3421
+ if (!kfs.length) return [];
3422
+ const loopFromSource = read.loop;
3251
3423
  let stopCount = 0;
3252
3424
  for (const kf of kfs) {
3253
3425
  const v = (_a = kf.value) != null ? _a : kf.v;
@@ -3322,36 +3494,60 @@ function formatOffset(o) {
3322
3494
  return pct + "%";
3323
3495
  }
3324
3496
  function applyClipPathEffect(node, fx, ctx) {
3497
+ var _a, _b;
3325
3498
  if (!fx || !fx.d && !fx.animate) return node;
3326
3499
  const clipId = genId(ctx, "clip");
3327
- const pathChild = { type: "path", d: fx.d };
3328
- if (fx.animate) pathChild.animate = { d: fx.animate };
3500
+ const pathChild = { type: "path" };
3501
+ const read = readAnimatable(fx.d);
3502
+ if (read.kind !== "absent") {
3503
+ if (read.kind === "static") {
3504
+ pathChild.d = pathString(read.value);
3505
+ } else {
3506
+ writeAnimatableChannel(pathChild, "d", read);
3507
+ if (pathChild.d !== void 0) pathChild.d = pathString(pathChild.d);
3508
+ }
3509
+ }
3510
+ if (fx.animate && !((_a = pathChild.animate) == null ? void 0 : _a.d)) {
3511
+ const animate = (_b = pathChild.animate) != null ? _b : {};
3512
+ animate.d = fx.animate;
3513
+ pathChild.animate = animate;
3514
+ }
3329
3515
  ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
3330
3516
  node.clipPath = "url(#" + clipId + ")";
3331
3517
  return node;
3332
3518
  }
3333
- function applyMaskedByEffect(node, fx, transformation, ctx) {
3519
+ function pathString(v) {
3520
+ if (typeof v === "string") return v;
3521
+ if (v && typeof v === "object" && typeof v.path === "string") return v.path;
3522
+ return void 0;
3523
+ }
3524
+ function applyMaskedByEffect(node, fx, transformBy, ctx) {
3334
3525
  if (!fx) return node;
3335
- if (!fx.href) {
3336
- ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
3526
+ const sourceId = stripHash2(fx.sourceId);
3527
+ if (!sourceId) {
3528
+ ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
3337
3529
  return node;
3338
3530
  }
3339
3531
  const maskId = genId(ctx, "mask");
3340
- let content = { type: "use", href: "#" + fx.href };
3341
- if (transformation) {
3342
- content = wrapInverseTransform(content, transformation, ctx);
3532
+ let content = { type: "use", href: "#" + sourceId };
3533
+ if (transformBy) {
3534
+ content = wrapInverseTransform(content, transformBy, ctx);
3343
3535
  } else if (hasAnimateTransform(node)) {
3344
3536
  content = wrapInverseAnimatedBodyTransform(content, node, ctx);
3345
3537
  } else {
3346
3538
  const bodyStatic = readTransformationFromBody(node);
3347
3539
  if (bodyStatic) content = wrapInverseTransform(content, bodyStatic, ctx);
3348
3540
  }
3349
- const includeTargetOwn = transformation === void 0 && !nodeHasBodyTransform(node);
3350
- content = wrapAncestorChainCompensation(content, node, fx.href, ctx, includeTargetOwn);
3541
+ const includeTargetOwn = transformBy === void 0 && !nodeHasBodyTransform(node);
3542
+ content = wrapAncestorChainCompensation(content, node, sourceId, ctx, includeTargetOwn);
3351
3543
  const mask = { type: "mask", id: maskId, children: [content] };
3352
3544
  if (fx.maskType) mask.maskType = fx.maskType;
3353
3545
  if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
3354
3546
  if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
3547
+ if (fx.x !== void 0) mask.x = String(fx.x);
3548
+ if (fx.y !== void 0) mask.y = String(fx.y);
3549
+ if (fx.width !== void 0) mask.width = String(fx.width);
3550
+ if (fx.height !== void 0) mask.height = String(fx.height);
3355
3551
  ctx.defs.push(mask);
3356
3552
  node.mask = "url(#" + maskId + ")";
3357
3553
  return node;
@@ -3458,6 +3654,19 @@ function readTransformationFromBody(node) {
3458
3654
  if (parts.origin) out.origin = parts.origin;
3459
3655
  return Object.keys(out).length ? out : void 0;
3460
3656
  }
3657
+ if (node.transform && typeof node.transform === "object" && !node.transform.keyframes && !node.transform.kfs) {
3658
+ const wrapped = node.transform.value;
3659
+ const value = wrapped && typeof wrapped === "object" ? wrapped : node.transform;
3660
+ if (value && typeof value === "object") {
3661
+ const out = {};
3662
+ if (Array.isArray(value.translate)) out.translate = value.translate;
3663
+ if (typeof value.rotate === "number") out.rotate = value.rotate;
3664
+ if (typeof value.skew === "number") out.skew = value.skew;
3665
+ if (Array.isArray(value.scale)) out.scale = { value: value.scale };
3666
+ if (Array.isArray(value.origin)) out.origin = value.origin;
3667
+ return Object.keys(out).length ? out : void 0;
3668
+ }
3669
+ }
3461
3670
  return void 0;
3462
3671
  }
3463
3672
  function parseTransformStringToParts(s) {
@@ -3591,10 +3800,10 @@ function collectMaskAncestorChains(root, ctx) {
3591
3800
  const interestingNodes = /* @__PURE__ */ new Set();
3592
3801
  const collectInterestingNodes = (n) => {
3593
3802
  var _a, _b;
3594
- const href = (_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.href;
3595
- if (typeof href === "string") {
3803
+ const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.sourceId);
3804
+ if (typeof maskSourceId === "string") {
3596
3805
  interestingNodes.add(n);
3597
- const sourceNode = ctx.idMap.get(href);
3806
+ const sourceNode = ctx.idMap.get(maskSourceId);
3598
3807
  if (sourceNode) interestingNodes.add(sourceNode);
3599
3808
  }
3600
3809
  if (Array.isArray(n.children)) for (const ch of n.children) collectInterestingNodes(ch);
@@ -3620,8 +3829,9 @@ function extractTranslateOnly(node, ctx) {
3620
3829
  if (typeof tr === "string") {
3621
3830
  const parts = parseTranslateOnlyFromString(tr, ctx);
3622
3831
  if (parts) out.translate = parts;
3623
- } else if (tr && typeof tr === "object") {
3624
- const value = tr.value;
3832
+ } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
3833
+ const wrapped = tr.value;
3834
+ const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
3625
3835
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
3626
3836
  out.translate = [value.translate[0] || 0, value.translate[1] || 0];
3627
3837
  }
@@ -3669,17 +3879,17 @@ function parseTranslateOnlyFromString(s, ctx) {
3669
3879
  var CONTENT_SUBREF = "content";
3670
3880
  function applyRefHref(node, clone2, ctx) {
3671
3881
  if (!clone2) return;
3672
- const baseId = clone2.baseId;
3673
- if (!baseId) {
3674
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing baseId");
3882
+ const sourceId = stripHash2(clone2.sourceId);
3883
+ if (!sourceId) {
3884
+ if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
3675
3885
  return;
3676
3886
  }
3677
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
3887
+ const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
3678
3888
  node.href = "#" + targetId;
3679
3889
  }
3680
- function applyRefAndTransformationEffect(node, clone2, transformation, ctx) {
3890
+ function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
3681
3891
  applyRefHref(node, clone2, ctx);
3682
- return applyTransformationEffect(node, transformation, ctx);
3892
+ return applyTransformByEffect(node, transformBy, ctx);
3683
3893
  }
3684
3894
  function applyRepeaterEffect(node, fx, ctx) {
3685
3895
  var _a, _b;
@@ -3702,7 +3912,7 @@ function applyRepeaterEffect(node, fx, ctx) {
3702
3912
  for (let i = 1; i < copies; i++) {
3703
3913
  const baseClone = clone(base);
3704
3914
  const synthFx = synthesisePerCopyFx(fx, i);
3705
- const wrapped = synthFx ? applyTransformationEffect(baseClone, synthFx, ctx) : baseClone;
3915
+ const wrapped = synthFx ? applyTransformByEffect(baseClone, synthFx, ctx) : baseClone;
3706
3916
  children.push(wrapped);
3707
3917
  }
3708
3918
  const wrapper = { type: "g", children };
@@ -3714,10 +3924,13 @@ function applyRepeaterEffect(node, fx, ctx) {
3714
3924
  function synthesisePerCopyFx(fx, i) {
3715
3925
  const out = {};
3716
3926
  if (fx.translate !== void 0) {
3717
- out.translate = mapAnimatableVec2(fx.translate, (v) => [v[0] * i, v[1] * i]);
3927
+ out.translate = mapAnimatable(fx.translate, (v) => [v[0] * i, v[1] * i]);
3718
3928
  }
3719
3929
  if (fx.rotate !== void 0) {
3720
- out.rotate = mapAnimatableNumber(fx.rotate, (v) => v * i);
3930
+ out.rotate = mapAnimatable(fx.rotate, (v) => v * i);
3931
+ }
3932
+ if (fx.skew !== void 0) {
3933
+ out.skew = mapAnimatable(fx.skew, (v) => v * i);
3721
3934
  }
3722
3935
  if (fx.scale !== void 0) {
3723
3936
  out.scale = synthesiseScale(fx.scale, i);
@@ -3727,63 +3940,50 @@ function synthesisePerCopyFx(fx, i) {
3727
3940
  }
3728
3941
  return Object.keys(out).length ? out : void 0;
3729
3942
  }
3730
- function mapAnimatableVec2(raw, fn) {
3731
- if (Array.isArray(raw)) return fn(raw);
3732
- if (raw && typeof raw === "object") {
3733
- const obj = raw;
3734
- if (Array.isArray(obj.keyframes)) {
3735
- return __spreadProps2(__spreadValues2({}, obj), {
3736
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
3737
- });
3738
- }
3739
- if (obj.value !== void 0) {
3740
- return __spreadProps2(__spreadValues2({}, obj), { value: fn(obj.value) });
3741
- }
3742
- }
3743
- return raw;
3744
- }
3745
- function mapAnimatableNumber(raw, fn) {
3746
- if (typeof raw === "number") return fn(raw);
3747
- if (raw && typeof raw === "object") {
3748
- const obj = raw;
3749
- if (Array.isArray(obj.keyframes)) {
3750
- return __spreadProps2(__spreadValues2({}, obj), {
3751
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
3752
- });
3753
- }
3754
- if (obj.value !== void 0) {
3755
- return __spreadProps2(__spreadValues2({}, obj), { value: fn(obj.value) });
3756
- }
3943
+ function mapAnimatable(raw, fn, wrapStatic = false) {
3944
+ const read = readAnimatable(raw);
3945
+ if (read.kind === "absent") return raw;
3946
+ if (read.kind === "static") {
3947
+ const mapped = fn(read.value);
3948
+ const wasRawStatic = typeof raw === "number" || Array.isArray(raw);
3949
+ return wasRawStatic && !wrapStatic ? mapped : { value: mapped };
3757
3950
  }
3758
- return raw;
3951
+ const out = {
3952
+ keyframes: read.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
3953
+ };
3954
+ if (read.loop !== void 0) out.loop = read.loop;
3955
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
3956
+ if (read.base !== void 0) out.value = fn(read.base);
3957
+ return out;
3759
3958
  }
3760
3959
  function synthesiseScale(raw, i) {
3761
- const scalePowerFromPercent = (v) => [Math.pow(v[0] / 100, i), Math.pow(v[1] / 100, i)];
3762
- const scalePowerFromUnits = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
3763
- if (Array.isArray(raw)) {
3764
- return { value: scalePowerFromPercent(raw) };
3765
- }
3766
- if (raw && typeof raw === "object") {
3767
- const obj = raw;
3768
- if (Array.isArray(obj.keyframes)) {
3769
- return __spreadProps2(__spreadValues2({}, obj), {
3770
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: scalePowerFromUnits(kf.value) }) : kf)
3771
- });
3772
- }
3773
- if (obj.value !== void 0) {
3774
- return __spreadProps2(__spreadValues2({}, obj), { value: scalePowerFromPercent(obj.value) });
3775
- }
3776
- }
3777
- return raw;
3960
+ const scalePower = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
3961
+ return mapAnimatable(raw, scalePower, true);
3778
3962
  }
3779
3963
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
3780
3964
  function asRetime(r) {
3781
3965
  var _a, _b;
3782
- if (r.timeCrop) {
3783
- console.warn("retime: `timeCrop` is not supported yet and will be ignored");
3784
- }
3785
3966
  return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
3786
3967
  }
3968
+ var CROP_EDGE_MS = 1;
3969
+ function applyTimeCrop(useNode, crop, ctx) {
3970
+ const [start, end] = crop;
3971
+ if (!Number.isFinite(start) || !Number.isFinite(end)) {
3972
+ ctx.warnings.push("retime: timeCrop is not a pair of finite numbers \u2014 ignored");
3973
+ return;
3974
+ }
3975
+ const keyframes = end <= start ? [{ time: 0, value: 0 }] : [
3976
+ ...start > 0 ? [{ time: Math.max(0, start - CROP_EDGE_MS), value: 0 }] : [],
3977
+ { time: Math.max(0, start), value: 1 },
3978
+ { time: end, value: 1 },
3979
+ { time: end + CROP_EDGE_MS, value: 0 }
3980
+ ];
3981
+ const inner = __spreadValues2({}, useNode);
3982
+ for (const k of Object.keys(useNode)) delete useNode[k];
3983
+ useNode.type = "g";
3984
+ useNode.children = [inner];
3985
+ useNode.animate = { opacity: { keyframes } };
3986
+ }
3787
3987
  function concatRetime(child, parent) {
3788
3988
  return {
3789
3989
  start: parent.start + parent.stretch * child.start,
@@ -3843,8 +4043,10 @@ function applyAllRetimeEffects(root, ctx) {
3843
4043
  for (const useNode of sites) {
3844
4044
  const retime = readCloneRetime(useNode);
3845
4045
  if (!retime) continue;
4046
+ const crop = retime.timeCrop;
3846
4047
  clearCloneRetime(useNode);
3847
4048
  materialiseRetime(useNode, asRetime(retime), ctx);
4049
+ if (crop) applyTimeCrop(useNode, crop, ctx);
3848
4050
  }
3849
4051
  }
3850
4052
  function materialiseRetime(useNode, retime, ctx) {
@@ -4087,14 +4289,11 @@ function createPathSampler(d) {
4087
4289
  }
4088
4290
  var EXTEND_MARGIN_FRAC = 0.15;
4089
4291
  function numRange(v) {
4090
- if (typeof v === "number") return { min: v, max: v };
4091
- if (v && typeof v === "object") {
4092
- const o = v;
4093
- if (typeof o.value === "number") return { min: o.value, max: o.value };
4094
- if (Array.isArray(o.keyframes) && o.keyframes.length) {
4095
- const vals = o.keyframes.map((k) => Number(k.value) || 0);
4096
- return { min: Math.min(...vals), max: Math.max(...vals) };
4097
- }
4292
+ const read = readAnimatable(v);
4293
+ if (read.kind === "static" && typeof read.value === "number") return { min: read.value, max: read.value };
4294
+ if (read.kind === "animated" && read.keyframes.length) {
4295
+ const vals = read.keyframes.map((k) => Number(k.value) || 0);
4296
+ return { min: Math.min(...vals), max: Math.max(...vals) };
4098
4297
  }
4099
4298
  return { min: 0, max: 0 };
4100
4299
  }
@@ -4114,11 +4313,16 @@ function estimateTextAdvance(node) {
4114
4313
  var r3 = (n) => Math.round(n * 1e3) / 1e3;
4115
4314
  function shiftAnimatable(v, by) {
4116
4315
  if (!by || v === void 0 || v === null) return v;
4117
- if (typeof v === "number") return v + by;
4118
- const o = v;
4119
- if (typeof o.value === "number") return __spreadProps2(__spreadValues2({}, o), { value: o.value + by });
4120
- if (Array.isArray(o.keyframes)) return __spreadProps2(__spreadValues2({}, o), { keyframes: o.keyframes.map((k) => __spreadProps2(__spreadValues2({}, k), { value: (Number(k.value) || 0) + by })) });
4121
- return v;
4316
+ const read = readAnimatable(v);
4317
+ if (read.kind === "absent") return v;
4318
+ if (read.kind === "static") return typeof v === "number" ? read.value + by : { value: read.value + by };
4319
+ const out = {
4320
+ keyframes: read.keyframes.map((k) => __spreadProps2(__spreadValues2({}, k), { value: (Number(k.value) || 0) + by }))
4321
+ };
4322
+ if (read.loop !== void 0) out.loop = read.loop;
4323
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
4324
+ if (read.base !== void 0) out.value = read.base + by;
4325
+ return out;
4122
4326
  }
4123
4327
  function extendedPathForBrowser(pathD, opts) {
4124
4328
  var _a;
@@ -4174,26 +4378,7 @@ function applyTextPathEffect(node, fx, ctx) {
4174
4378
  }
4175
4379
  function applyAnimatableNumber(node, attrName, raw) {
4176
4380
  if (raw === void 0 || raw === null) return;
4177
- if (typeof raw === "number") {
4178
- node[attrName] = String(raw);
4179
- return;
4180
- }
4181
- if (typeof raw === "object" && raw !== null) {
4182
- const obj = raw;
4183
- if (Array.isArray(obj.keyframes)) {
4184
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
4185
- const animate = __spreadValues2({}, prevAnimate || {});
4186
- const block = { keyframes: obj.keyframes };
4187
- if (obj.loop !== void 0) block.loop = obj.loop;
4188
- animate[attrName] = block;
4189
- node.animate = animate;
4190
- return;
4191
- }
4192
- if (typeof obj.value === "number") {
4193
- node[attrName] = String(obj.value);
4194
- return;
4195
- }
4196
- }
4381
+ writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
4197
4382
  }
4198
4383
  var jsonElementFactory = (type, props, children) => {
4199
4384
  const node = { type };
@@ -4381,13 +4566,13 @@ function materialiseGlyphTextHorizontal(node, opts) {
4381
4566
  if (y !== void 0) pen.y = y;
4382
4567
  pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
4383
4568
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4384
- const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
4569
+ const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4385
4570
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
4386
4571
  if (el.children) for (const ch of el.children) walk(ch, s);
4387
4572
  };
4388
4573
  const rootStyle = rootStyleOf(node);
4389
4574
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
4390
- const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
4575
+ const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
4391
4576
  if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
4392
4577
  const anchor = str(node.textAnchor);
4393
4578
  if (anchor === "middle" || anchor === "end") {
@@ -4436,7 +4621,7 @@ function layoutGlyphTextChars(node, opts) {
4436
4621
  if (y !== void 0) pen.y = y;
4437
4622
  pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
4438
4623
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4439
- const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
4624
+ const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4440
4625
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
4441
4626
  if (el.children) for (const ch of el.children) walk(ch, s);
4442
4627
  };
@@ -4451,7 +4636,7 @@ function layoutGlyphTextChars(node, opts) {
4451
4636
  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 });
4452
4637
  }
4453
4638
  }
4454
- const rootContent = (_e = str(node[TEXT_ATTR])) != null ? _e : str(node[TEXT_CONTENT_ATTR]);
4639
+ const rootContent = (_e = str(node[TEXT_CONTENT_ATTR])) != null ? _e : str(node[TEXT_ATTR]);
4455
4640
  if (rootContent && !((_f = node.children) == null ? void 0 : _f.length)) renderChars(rootContent, rootStyle);
4456
4641
  const anchor = str(node.textAnchor);
4457
4642
  if (anchor === "middle" || anchor === "end") {
@@ -4479,7 +4664,7 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4479
4664
  const walk = (el, parentStyle) => {
4480
4665
  var _a2, _b2, _c;
4481
4666
  const s = resolveStyle2(el, parentStyle);
4482
- const content = (_a2 = str(el[TEXT_ATTR])) != null ? _a2 : str(el[TEXT_CONTENT_ATTR]);
4667
+ const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
4483
4668
  if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
4484
4669
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4485
4670
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
@@ -4533,7 +4718,7 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4533
4718
  const walk = (el, parentStyle) => {
4534
4719
  var _a, _b, _c;
4535
4720
  const s = resolveStyle2(el, parentStyle);
4536
- const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
4721
+ const content = (_a = str(el[TEXT_CONTENT_ATTR])) != null ? _a : str(el[TEXT_ATTR]);
4537
4722
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
4538
4723
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4539
4724
  if (gf) {
@@ -4761,9 +4946,9 @@ function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pat
4761
4946
  }
4762
4947
  return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
4763
4948
  }
4764
- function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4949
+ function applyTrimPathEffect(node, trimPath, ctx) {
4765
4950
  if (!trimPath) return node;
4766
- const trimAllAsOne = !!trimPath.trimAllAsOne;
4951
+ const combined = trimPath.subPaths === PxTrimSubPaths.combined;
4767
4952
  const leafEntries = [];
4768
4953
  const measure = (n) => {
4769
4954
  if (Array.isArray(n.children) && n.children.length > 0) {
@@ -4784,16 +4969,16 @@ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4784
4969
  measure(node);
4785
4970
  if (!leafEntries.length) return node;
4786
4971
  let acc = 0;
4787
- const iterOrder = trimAllAsOne ? [...leafEntries].reverse() : leafEntries;
4972
+ const iterOrder = combined ? [...leafEntries].reverse() : leafEntries;
4788
4973
  for (const entry of iterOrder) {
4789
4974
  for (const sp of entry.subpaths) {
4790
- if (!trimAllAsOne) acc = 0;
4975
+ if (!combined) acc = 0;
4791
4976
  sp.startOffsetPx = acc;
4792
4977
  acc += sp.lengthPx;
4793
4978
  }
4794
4979
  }
4795
4980
  const chainLengthPx = acc;
4796
- if (trimAllAsOne && chainLengthPx < 1e-3) return node;
4981
+ if (combined && chainLengthPx < 1e-3) return node;
4797
4982
  const offsetReadRaw = readAnimatable(trimPath.offset);
4798
4983
  const offsetRead = offsetReadRaw.kind === "absent" ? { kind: "static", value: 0 } : offsetReadRaw;
4799
4984
  const rangeReadRaw = readRangeWithCrossings(trimPath.range);
@@ -4805,18 +4990,18 @@ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4805
4990
  if (leafEntries.length === 1 && leafEntries[0].leaf === node && leafEntries[0].subpaths.length === 1) {
4806
4991
  const entry = leafEntries[0];
4807
4992
  const sp = entry.subpaths[0];
4808
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
4993
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
4809
4994
  if (pathLengthPx < 1e-3) return node;
4810
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
4995
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
4811
4996
  return collapseLeafWithTrim(entry.leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead);
4812
4997
  }
4813
4998
  const replacements = /* @__PURE__ */ new Map();
4814
4999
  for (const entry of leafEntries) {
4815
5000
  const newChildren = [];
4816
5001
  for (const sp of entry.subpaths) {
4817
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
5002
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
4818
5003
  if (pathLengthPx < 1e-3) continue;
4819
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
5004
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
4820
5005
  newChildren.push(...buildSubpathNodes(entry.leaf, sp.subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx));
4821
5006
  }
4822
5007
  replacements.set(entry.leaf, wrapLeafAsGroup(entry.leaf, newChildren));
@@ -4923,22 +5108,8 @@ function computeAnimAttr(read, map) {
4923
5108
  };
4924
5109
  }
4925
5110
  function applyAttr(node, attrName, attr) {
4926
- var _a, _b;
4927
5111
  if (!attr) return;
4928
- if (attr.kind === "static") {
4929
- node[attrName] = attr.value;
4930
- return;
4931
- }
4932
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
4933
- const animate = __spreadValues2({}, prevAnimate || {});
4934
- const block = { keyframes: attr.keyframes };
4935
- if (attr.loop !== void 0) block.loop = attr.loop;
4936
- animate[attrName] = block;
4937
- node.animate = animate;
4938
- const firstKf = attr.keyframes[0];
4939
- if (firstKf && ((_a = firstKf.value) != null ? _a : firstKf.v) !== void 0) {
4940
- node[attrName] = (_b = firstKf.value) != null ? _b : firstKf.v;
4941
- }
5112
+ writeAnimatableChannel(node, attrName, attr);
4942
5113
  }
4943
5114
  var OPACITY_STEP_MS = 10;
4944
5115
  function computeOpacityFromRange(rangeRead) {
@@ -5120,9 +5291,9 @@ function applyPlayerEffects(root) {
5120
5291
  nextId: 0,
5121
5292
  contentRefInnerIds: /* @__PURE__ */ new Map(),
5122
5293
  maskAncestorChains: /* @__PURE__ */ new Map(),
5123
- // Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
5124
- // webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5125
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
5294
+ // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
5295
+ // waapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5296
+ engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi,
5126
5297
  glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
5127
5298
  };
5128
5299
  const working = clone(root);
@@ -5140,8 +5311,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5140
5311
  const originalId = typeof node.id === "string" ? node.id : void 0;
5141
5312
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
5142
5313
  if (!fx && !innerIdForContentRef) return node;
5143
- const { transformation, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5144
- const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
5314
+ const { transformBy, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5145
5315
  if (fx) delete node.effects;
5146
5316
  let n = node;
5147
5317
  let consumedByGlyphs = false;
@@ -5161,15 +5331,15 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5161
5331
  if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
5162
5332
  n = applyFillGradientEffect(n, fillGradient, ctx);
5163
5333
  n = applyStrokeGradientEffect(n, strokeGradient, ctx);
5164
- n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
5334
+ n = applyTrimPathEffect(n, trimPath, ctx);
5165
5335
  n = applyRepeaterEffect(n, repeater, ctx);
5166
- n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
5336
+ n = applyMaskedByEffect(n, maskedBy, transformBy, ctx);
5167
5337
  n = applyClipPathEffect(n, clipPath, ctx);
5168
5338
  if (innerIdForContentRef) {
5169
5339
  applyRefHref(n, cloneFx, ctx);
5170
- n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
5340
+ n = splitForContentRef(n, transformBy, originalId, innerIdForContentRef, ctx);
5171
5341
  } else {
5172
- n = applyRefAndTransformationEffect(n, cloneFx, transformation, ctx);
5342
+ n = applyRefAndTransformationEffect(n, cloneFx, transformBy, ctx);
5173
5343
  }
5174
5344
  if (cloneFx == null ? void 0 : cloneFx.retime) node.effects = { clone: { retime: cloneFx.retime } };
5175
5345
  if (originalId) ctx.idMap.set(originalId, n);
@@ -5184,7 +5354,7 @@ function materialiseAllInTree(doc, engine, opts) {
5184
5354
  let root = applyPlayerEffects(doc).root;
5185
5355
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5186
5356
  root = materialiseInternalLoopsInTree(root, duration);
5187
- if (engine === PxAnimatorEngine.webapi) {
5357
+ if (engine === PxAnimatorEngine.waapi) {
5188
5358
  root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5189
5359
  root = materialiseAnimatedUseInstances(root);
5190
5360
  root = pruneUnreferencedDefs(root);
@@ -5569,6 +5739,7 @@ function evalTransformValue(v, t) {
5569
5739
  if (typeof v === "string") return parseTransformString(v);
5570
5740
  if (v.keyframes) return partsToMatrix(interpParts(v.keyframes, t));
5571
5741
  if (v.value) return partsToMatrix(v.value);
5742
+ if (typeof v === "object" && !Array.isArray(v)) return partsToMatrix(v);
5572
5743
  return IDENTITY;
5573
5744
  }
5574
5745
  function nodeMatrix(node, t) {
@@ -5703,64 +5874,6 @@ function subtractMultiset(a, b) {
5703
5874
  return extra;
5704
5875
  }
5705
5876
 
5706
- // src/PxAnimatorDOM.ts
5707
- var SVG_NS = "http://www.w3.org/2000/svg";
5708
- function createElement(tagName, normalisedProps, style, children, textContent) {
5709
- if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
5710
- console.warn("SVG tag blocked (dangerous): ", tagName);
5711
- return null;
5712
- }
5713
- const element = document.createElementNS(SVG_NS, tagName);
5714
- for (const propName in normalisedProps) {
5715
- const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
5716
- if (sanitised === void 0) continue;
5717
- if (CSS_ONLY_STYLE_PROPS.has(propName)) {
5718
- element.style[propName] = String(sanitised);
5719
- continue;
5720
- }
5721
- element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
5722
- }
5723
- if (style) {
5724
- for (const styleProp in style) {
5725
- element.style[styleProp] = String(style[styleProp]);
5726
- }
5727
- }
5728
- if (children) {
5729
- for (const child of children) {
5730
- element.appendChild(child);
5731
- }
5732
- }
5733
- if (textContent) element.textContent = textContent;
5734
- return element;
5735
- }
5736
- function renderNode(node, defs) {
5737
- if (!node) return null;
5738
- const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
5739
- const feFuncType = props.funcType;
5740
- if (feFuncType !== void 0) delete props.funcType;
5741
- const nodeDefs = getDefs(node) || defs;
5742
- const resolvedStyle = resolveStyle(style, nodeDefs);
5743
- let childElements;
5744
- if (children) {
5745
- for (const ch of children) {
5746
- const child = renderNode(ch, nodeDefs);
5747
- if (child) {
5748
- if (!childElements) childElements = [];
5749
- childElements.push(child);
5750
- }
5751
- }
5752
- }
5753
- const element = createElement(
5754
- type || "g",
5755
- getNormalizedProps(props),
5756
- resolvedStyle,
5757
- childElements,
5758
- props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
5759
- );
5760
- if (element && feFuncType !== void 0) element.setAttribute("type", feFuncType);
5761
- return element;
5762
- }
5763
-
5764
5877
  // src/PxAnimatorTriggers.ts
5765
5878
  function setupAnimationTriggers(api, config) {
5766
5879
  const { startOn, outAction = "continue", scrollIntoViewThreshold = 0 } = config;
@@ -5806,8 +5919,14 @@ function setupAnimationTriggers(api, config) {
5806
5919
  break;
5807
5920
  }
5808
5921
  case "mouseOver": {
5809
- const mouseOverHandler = () => start();
5810
- const mouseOutHandler = () => handleEndAction();
5922
+ let enteredOnce = false;
5923
+ const mouseOverHandler = () => {
5924
+ enteredOnce = true;
5925
+ start();
5926
+ };
5927
+ const mouseOutHandler = () => {
5928
+ if (enteredOnce) handleEndAction();
5929
+ };
5811
5930
  root.addEventListener("mouseenter", mouseOverHandler);
5812
5931
  root.addEventListener("mouseleave", mouseOutHandler);
5813
5932
  break;
@@ -5824,17 +5943,32 @@ function setupAnimationTriggers(api, config) {
5824
5943
  break;
5825
5944
  }
5826
5945
  case "scrollIntoView": {
5946
+ const effectiveRatio = (entry) => {
5947
+ var _a, _b;
5948
+ const target = entry.boundingClientRect;
5949
+ const visible = entry.intersectionRect;
5950
+ if (!(target == null ? void 0 : target.height) || !visible) return entry.intersectionRatio;
5951
+ const live = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : Infinity;
5952
+ const declared = (_b = (_a = entry.rootBounds) == null ? void 0 : _a.height) != null ? _b : Infinity;
5953
+ const viewport = Math.min(live, declared);
5954
+ const denom = Math.min(target.height, Number.isFinite(viewport) ? viewport : target.height);
5955
+ return denom > 0 ? visible.height / denom : entry.intersectionRatio;
5956
+ };
5957
+ const thresholdSteps = Array.from({ length: 21 }, (_, i) => i / 20);
5958
+ let wasIntersecting = false;
5827
5959
  const observer = new IntersectionObserver(
5828
5960
  (entries) => {
5829
5961
  entries.forEach((entry) => {
5830
- if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
5962
+ if (entry.isIntersecting && effectiveRatio(entry) >= scrollIntoViewThreshold) {
5963
+ wasIntersecting = true;
5831
5964
  start();
5832
- } else {
5965
+ } else if (wasIntersecting) {
5966
+ wasIntersecting = false;
5833
5967
  handleEndAction();
5834
5968
  }
5835
5969
  });
5836
5970
  },
5837
- { threshold: scrollIntoViewThreshold }
5971
+ { threshold: thresholdSteps }
5838
5972
  );
5839
5973
  observer.observe(root);
5840
5974
  break;
@@ -5929,7 +6063,7 @@ function createCssKf(kf, t, propName, unsupportedSet) {
5929
6063
  } else {
5930
6064
  cssValue = "" + value;
5931
6065
  }
5932
- if (!CSS.supports(cssKey, cssValue)) unsupportedSet.add(cssKey);
6066
+ if (!CSS.supports(camelCaseToKebabWordIfNeeded(cssKey), cssValue)) unsupportedSet.add(cssKey);
5933
6067
  cssKey = kebabToCamelCaseWord(cssKey);
5934
6068
  cssKf[cssKey] = cssValue;
5935
6069
  return cssKf;
@@ -6006,7 +6140,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
6006
6140
  console.warn("createFrameLoopAnimator: No root element provided");
6007
6141
  }
6008
6142
  }
6009
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.webapi);
6143
+ const bindings = getNormalisedBindings(doc, PxAnimatorEngine.waapi);
6010
6144
  const animations = [];
6011
6145
  const _iterations = config.iterations;
6012
6146
  let iterations;
@@ -6152,9 +6286,8 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
6152
6286
  return api;
6153
6287
  }
6154
6288
 
6155
- // src/PxAnimator.ts
6156
- function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
6157
- const animatorConfig = getAnimatorConfig(doc) || {};
6289
+ // src/PxAnimatorBind.ts
6290
+ function finaliseAnimator(animatorConfig, callbacks, make) {
6158
6291
  let apiRef;
6159
6292
  let effectiveCallbacks = callbacks;
6160
6293
  if (animatorConfig.resetOnFinish) {
@@ -6166,29 +6299,99 @@ function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
6166
6299
  }
6167
6300
  });
6168
6301
  }
6169
- let res;
6170
- if (animatorConfig.mode === PxAnimatorMode.frames) {
6171
- res = createFrameLoopAnimator(doc, adapter, effectiveCallbacks, rootElement);
6172
- } else {
6173
- res = createWebApiAnimator(
6174
- doc,
6175
- effectiveCallbacks,
6176
- rootElement,
6177
- animatorConfig.mode === PxAnimatorMode.webapi
6178
- // forcing webapi
6179
- ) || createFrameLoopAnimator(doc, adapter, effectiveCallbacks, rootElement);
6180
- }
6302
+ const res = make(effectiveCallbacks);
6181
6303
  apiRef = res;
6182
6304
  if (animatorConfig.debugInstName) {
6183
6305
  window[animatorConfig.debugInstName] = res;
6184
6306
  }
6185
6307
  return res;
6186
6308
  }
6309
+ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
6310
+ const animatorConfig = getAnimatorConfig(doc) || {};
6311
+ return finaliseAnimator(animatorConfig, callbacks, (cb) => {
6312
+ if (animatorConfig.mode === PxAnimatorMode.frames) {
6313
+ return createFrameLoopAnimator(doc, adapter, cb, rootElement);
6314
+ }
6315
+ return createWebApiAnimator(
6316
+ doc,
6317
+ cb,
6318
+ rootElement,
6319
+ animatorConfig.mode === PxAnimatorMode.waapi
6320
+ // forcing waapi
6321
+ ) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
6322
+ });
6323
+ }
6324
+
6325
+ // src/PxAnimatorDOM.ts
6326
+ var SVG_NS = "http://www.w3.org/2000/svg";
6327
+ function createElement(tagName, normalisedProps, style, children, textContent) {
6328
+ if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
6329
+ console.warn("SVG tag blocked (dangerous): ", tagName);
6330
+ return null;
6331
+ }
6332
+ const element = document.createElementNS(SVG_NS, tagName);
6333
+ for (const propName in normalisedProps) {
6334
+ const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
6335
+ if (sanitised === void 0) continue;
6336
+ if (CSS_ONLY_STYLE_PROPS.has(propName)) {
6337
+ element.style[propName] = String(sanitised);
6338
+ continue;
6339
+ }
6340
+ element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
6341
+ }
6342
+ if (style) {
6343
+ for (const styleProp in style) {
6344
+ element.style[styleProp] = String(style[styleProp]);
6345
+ }
6346
+ }
6347
+ if (children) {
6348
+ for (const child of children) {
6349
+ element.appendChild(child);
6350
+ }
6351
+ }
6352
+ if (textContent) element.textContent = textContent;
6353
+ return element;
6354
+ }
6355
+ function renderNode(node, defs) {
6356
+ if (!node) return null;
6357
+ const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
6358
+ const domType = props.domType;
6359
+ if (domType !== void 0) delete props.domType;
6360
+ const nodeDefs = getDefs(node) || defs;
6361
+ const resolvedStyle = resolveStyle(style, nodeDefs);
6362
+ let childElements;
6363
+ if (children) {
6364
+ for (const ch of children) {
6365
+ const child = renderNode(ch, nodeDefs);
6366
+ if (child) {
6367
+ if (!childElements) childElements = [];
6368
+ childElements.push(child);
6369
+ }
6370
+ }
6371
+ }
6372
+ const element = createElement(
6373
+ type || "g",
6374
+ getNormalizedProps(props),
6375
+ resolvedStyle,
6376
+ childElements,
6377
+ props[TEXT_CONTENT_ATTR] || props[TEXT_ATTR]
6378
+ );
6379
+ if (element && domType !== void 0) element.setAttribute("type", domType);
6380
+ return element;
6381
+ }
6382
+
6383
+ // src/PxAnimatorKeys.ts
6384
+ var PX_ANIMATOR_DATA_KEY = "data";
6385
+
6386
+ // src/PxAnimator.ts
6387
+ function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
6388
+ return bindWithEngineChoice(doc, adapter, callbacks, rootElement);
6389
+ }
6187
6390
  function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
6188
6391
  const effectsWarnings = validateNodeEffects(doc);
6189
6392
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
6190
6393
  const animatorConfig = getAnimatorConfig(doc) || {};
6191
- const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
6394
+ const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi;
6192
6395
  doc = materialiseAllInTree(doc, engine);
6193
6396
  let rootElement = null;
6194
6397
  if (containerElement) {
@@ -6203,7 +6406,6 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
6203
6406
  }
6204
6407
  return createAnimatorFromConfig(doc, adapter, callbacks, rootElement);
6205
6408
  }
6206
- var PX_ANIMATOR_DATA_KEY = "data";
6207
6409
  function createAnimator(options) {
6208
6410
  const { src, data, adapter, callbacks, container } = options;
6209
6411
  if (data !== void 0 && src !== void 0) {
@@ -6312,6 +6514,7 @@ if (typeof window !== "undefined") {
6312
6514
  PxGradientType,
6313
6515
  PxGradientUnits,
6314
6516
  PxKeyframeSchema,
6517
+ PxKeyframeValueSchema,
6315
6518
  PxLoopSchema,
6316
6519
  PxMaskedByEffectSchema,
6317
6520
  PxNodeBase,
@@ -6323,9 +6526,9 @@ if (typeof window !== "undefined") {
6323
6526
  PxSvgNodeExtra,
6324
6527
  PxTextEffectSchema,
6325
6528
  PxTextPathEffectSchema,
6529
+ PxTransformByEffectSchema,
6326
6530
  PxTransformPartsSchema,
6327
6531
  PxTransformValueSchema,
6328
- PxTransformationEffectSchema,
6329
6532
  PxTriggerSchema,
6330
6533
  PxTrimPathEffectSchema,
6331
6534
  STYLE_ATTR_NAMES,