@pixodesk/svg-animator-core 1.0.22 → 1.0.25

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
@@ -153,8 +153,9 @@ var Union = class extends Base {
153
153
  }
154
154
  isValid(raw, ctx, path) {
155
155
  var _a;
156
- if (this.schemas.some((s) => s.isValid(raw))) return true;
157
- 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));
156
+ const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
157
+ if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
158
+ 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));
158
159
  return false;
159
160
  }
160
161
  _canSanitize(raw) {
@@ -230,6 +231,7 @@ var Obj = class extends Base {
230
231
  if (ctx == null ? void 0 : ctx.strict) {
231
232
  for (const key of Object.keys(obj)) {
232
233
  if (key in this._shape) continue;
234
+ if (obj[key] === void 0) continue;
233
235
  p.push(key);
234
236
  ctx.errors.push(pathStr(p) + ": unexpected extra key");
235
237
  p.pop();
@@ -370,6 +372,23 @@ var Any = class extends Base {
370
372
  return true;
371
373
  }
372
374
  };
375
+ var Defined = class extends Base {
376
+ constructor() {
377
+ super(...arguments);
378
+ this._default = void 0;
379
+ }
380
+ sanitize(raw) {
381
+ return raw;
382
+ }
383
+ isValid(raw, ctx, path) {
384
+ if (raw !== void 0) return true;
385
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": required value is missing");
386
+ return false;
387
+ }
388
+ _canSanitize(raw) {
389
+ return raw !== void 0;
390
+ }
391
+ };
373
392
  var Lazy = class extends Base {
374
393
  constructor(fn, _default) {
375
394
  super();
@@ -481,24 +500,65 @@ var px = {
481
500
  record: (value) => new Rec(value),
482
501
  /** Passes anything through unchanged — always valid. */
483
502
  any: () => new Any(),
503
+ /** Anything EXCEPT `undefined` — an open type whose presence is required (V6). */
504
+ defined: () => new Defined(),
484
505
  /** Fixed-length tuple — validates element count and each position individually. */
485
506
  tuple: (schemas) => new Tuple(schemas),
486
507
  /** Defers schema creation — required for recursive types. Must supply a default value. */
487
508
  lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
488
509
  };
489
510
 
490
- // src/PxAnimatorTypes.ts
511
+ // src/PxAnimatorConstants.ts
491
512
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
492
513
  var PX_ANIM_ATTR_NAME = "_px_animator";
493
514
  var PxAnimatorMode = {
494
515
  auto: "auto",
495
- webapi: "webapi",
516
+ waapi: "waapi",
496
517
  frames: "frames"
497
518
  };
498
519
  var PxAnimatorEngine = {
499
- webapi: PxAnimatorMode.webapi,
520
+ waapi: PxAnimatorMode.waapi,
500
521
  frames: PxAnimatorMode.frames
501
522
  };
523
+ var PxLoopExtend = {
524
+ /** Segment from the START; the animation is extended BEFORE the first keyframe
525
+ * (intro loops that run before the main timeline begins). */
526
+ before: "before",
527
+ /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
528
+ * loops that continue once the main timeline has finished). */
529
+ after: "after"
530
+ };
531
+ var PxMaskType = {
532
+ luminance: "luminance",
533
+ alpha: "alpha"
534
+ };
535
+ var PxUnits = {
536
+ userSpaceOnUse: "userSpaceOnUse",
537
+ objectBoundingBox: "objectBoundingBox"
538
+ };
539
+ var PxCloneType = {
540
+ content: "content"
541
+ };
542
+ var PxPathOverflow = {
543
+ clip: "clip",
544
+ extend: "extend"
545
+ };
546
+ var PxLengthAdjust = {
547
+ spacing: "spacing",
548
+ spacingAndGlyphs: "spacingAndGlyphs"
549
+ };
550
+ var PxTextPathMethod = {
551
+ align: "align",
552
+ stretch: "stretch"
553
+ };
554
+ var PxTextPathSpacing = {
555
+ auto: "auto",
556
+ exact: "exact"
557
+ };
558
+ var PxTrimSubPaths = {
559
+ separate: "separate",
560
+ combined: "combined"
561
+ };
502
562
  var TEXT_ATTR = "text";
503
563
  var TEXT_CONTENT_ATTR = "textContent";
504
564
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
@@ -507,9 +567,51 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
507
567
  "animator",
508
568
  "meta",
509
569
  "animate",
570
+ "effects",
510
571
  TEXT_ATTR,
511
572
  TEXT_CONTENT_ATTR
512
573
  ]);
574
+ var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
575
+ var PxGradientUnits = {
576
+ userSpaceOnUse: "userSpaceOnUse",
577
+ objectBoundingBox: "objectBoundingBox"
578
+ };
579
+ var PxGradientSpreadMethod = {
580
+ pad: "pad",
581
+ reflect: "reflect",
582
+ repeat: "repeat"
583
+ };
584
+ var PxGradientType = {
585
+ linear: "linear",
586
+ radial: "radial"
587
+ };
588
+ function isPxElementFileFormat(fileJson) {
589
+ if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
590
+ return false;
591
+ }
592
+ return fileJson["type"] === "svg";
593
+ }
594
+ function getAnimatorConfig(doc) {
595
+ var _a;
596
+ return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
597
+ }
598
+ function getDefs(doc) {
599
+ var _a;
600
+ if (!doc) return void 0;
601
+ return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
602
+ }
603
+ function getBindings(doc) {
604
+ var _a;
605
+ if (!doc) return void 0;
606
+ const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
607
+ if (!animateById) return void 0;
608
+ return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));
609
+ }
610
+ function getChildren(doc) {
611
+ return doc == null ? void 0 : doc.children;
612
+ }
613
+
614
+ // src/PxAnimatorTypes.ts
513
615
  var PxEasingOrRefSchema = px.union([
514
616
  px.string(),
515
617
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -521,13 +623,15 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
521
623
  px.array(px.number()),
522
624
  px.lazy(() => PxTransformPartsSchema, {}),
523
625
  px.object({ path: px.string() }),
524
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] })
626
+ px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
627
+ // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
628
+ px.lazy(() => px.array(PxGradientStopSchema), [])
525
629
  ]));
526
630
  var PxKeyframeSchema = implementsInterface()(px.object({
527
631
  time: px.number().optional(),
528
632
  t: px.number().optional(),
529
- value: px.any().optional(),
530
- v: px.any().optional(),
633
+ value: PxKeyframeValueSchema.optional(),
634
+ v: PxKeyframeValueSchema.optional(),
531
635
  easing: PxEasingOrRefSchema.optional(),
532
636
  e: PxEasingOrRefSchema.optional(),
533
637
  tangentOut: px.tuple([px.number(), px.number()]).optional(),
@@ -541,16 +645,16 @@ var PxKeyframeSchema = implementsInterface()(px.object({
541
645
  }));
542
646
  var PxLoopSchema = implementsInterface()(px.object({
543
647
  segmentCount: px.number().optional(),
544
- before: px.boolean().optional(),
648
+ extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
545
649
  alternate: px.boolean().optional()
546
650
  }));
547
651
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
652
+ value: PxKeyframeValueSchema.optional(),
548
653
  keyframes: px.array(PxKeyframeSchema).optional(),
549
654
  kfs: px.array(PxKeyframeSchema).optional(),
550
655
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
551
656
  autoOrient: px.boolean().optional()
552
657
  }));
553
- var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
554
658
  var PxTransformPartsSchema = implementsInterface()(px.object({
555
659
  translate: px.tuple([px.number(), px.number()]).optional(),
556
660
  rotate: px.number().optional(),
@@ -560,6 +664,7 @@ var PxTransformPartsSchema = implementsInterface()(px.object({
560
664
  }));
561
665
  var PxTransformValueSchema = px.union([
562
666
  px.string(),
667
+ PxTransformPartsSchema,
563
668
  px.object({ value: PxTransformPartsSchema }),
564
669
  PxPropertyAnimationSchema
565
670
  ]);
@@ -594,9 +699,11 @@ var PxDefsSchema = implementsInterface()(px.object({
594
699
  glyphs: px.record(PxGlyphFontSchema).optional()
595
700
  }));
596
701
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
597
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
702
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
598
703
  duration: px.number().optional(),
599
704
  delay: px.number().optional(),
705
+ // LAW (SCHEMA-DESIGN R3, S10): the ONE sanctioned string-in-number union
706
+ // (CSS animation-iteration-count familiarity) — do not add more mixed unions.
600
707
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
601
708
  fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
602
709
  direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
@@ -604,9 +711,8 @@ var PxAnimatorConfigSchema = implementsInterface()(px.object({
604
711
  trigger: PxTriggerSchema.optional(),
605
712
  resetOnFinish: px.boolean().optional(),
606
713
  definitions: PxDefsSchema.optional(),
607
- animate: px.record(PxElementAnimationSchema).optional(),
608
- timeline: px.string().optional(),
609
- debug: px.boolean().optional(),
714
+ animateById: px.record(PxElementAnimationSchema).optional(),
715
+ timelineSource: px.string().optional(),
610
716
  debugInstName: px.string().optional()
611
717
  }));
612
718
  var PxBindingSchema = implementsInterface()(px.object({
@@ -616,26 +722,29 @@ var PxBindingSchema = implementsInterface()(px.object({
616
722
  var PxAttrValueSchema = px.union([
617
723
  px.string(),
618
724
  px.number(),
619
- px.object({ value: px.any() }),
620
- PxPropertyAnimationSchema
725
+ px.array(px.number()),
726
+ // Structured static — `{value: …}` (read-accepted transitional spelling, S1).
727
+ // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).
728
+ px.object({ value: px.defined() }),
729
+ // Bare transform parts record — the canonical static `transform` on the wire (T2).
730
+ PxTransformPartsSchema
621
731
  ]);
622
732
  var PxAnimatableNumberSchema = px.union([
623
733
  px.number(),
624
734
  px.object({ value: px.number() }),
625
- px.object({
626
- keyframes: px.array(PxKeyframeSchema),
627
- autoOrient: px.boolean().optional()
628
- })
735
+ PxPropertyAnimationSchema
629
736
  ]);
630
737
  var PxAnimatableVec2Schema = px.union([
631
738
  px.tuple([px.number(), px.number()]),
632
739
  px.object({ value: px.tuple([px.number(), px.number()]) }),
633
- px.object({
634
- keyframes: px.array(PxKeyframeSchema),
635
- autoOrient: px.boolean().optional()
636
- })
740
+ PxPropertyAnimationSchema
741
+ ]);
742
+ var PxAnimatableStringSchema = px.union([
743
+ px.string(),
744
+ px.object({ value: px.string() }),
745
+ PxPropertyAnimationSchema
637
746
  ]);
638
- var PxTransformationEffectSchema = implementsInterface()(px.object({
747
+ var PxTransformByEffectSchema = implementsInterface()(px.object({
639
748
  translate: PxAnimatableVec2Schema.optional(),
640
749
  rotate: PxAnimatableNumberSchema.optional(),
641
750
  scale: PxAnimatableVec2Schema.optional(),
@@ -643,51 +752,46 @@ var PxTransformationEffectSchema = implementsInterface()(px.object({
643
752
  origin: PxAnimatableVec2Schema.optional()
644
753
  }));
645
754
  var PxRepeaterEffectSchema = implementsInterface()(px.object({
755
+ // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
756
+ // once at expansion time and never sampled — plain number, no `keyframes`.
646
757
  copies: px.number().optional(),
647
758
  translate: PxAnimatableVec2Schema.optional(),
648
759
  rotate: PxAnimatableNumberSchema.optional(),
760
+ skew: PxAnimatableNumberSchema.optional(),
649
761
  scale: PxAnimatableVec2Schema.optional(),
650
762
  origin: PxAnimatableVec2Schema.optional()
651
763
  }));
652
764
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
653
- href: px.string().optional(),
654
- maskType: px.string().optional(),
655
- maskUnits: px.string().optional(),
656
- maskContentUnits: px.string().optional()
765
+ sourceId: px.string().optional(),
766
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
767
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
768
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
769
+ x: px.number().optional(),
770
+ y: px.number().optional(),
771
+ width: px.number().optional(),
772
+ height: px.number().optional()
657
773
  }));
658
774
  var PxClipPathEffectSchema = implementsInterface()(px.object({
659
- d: px.string().optional(),
775
+ d: PxAnimatableStringSchema.optional(),
660
776
  animate: PxPropertyAnimationSchema.optional()
661
777
  }));
662
778
  var PxTrimPathEffectSchema = implementsInterface()(px.object({
663
779
  offset: PxAnimatableNumberSchema.optional(),
664
780
  range: PxAnimatableVec2Schema.optional(),
665
- trimAllAsOne: px.boolean().optional()
781
+ subPaths: px.enum([PxTrimSubPaths.separate, PxTrimSubPaths.combined]).optional()
666
782
  }));
667
783
  var PxRetimeEffectSchema = implementsInterface()(px.object({
668
- baseId: px.string().optional(),
784
+ sourceId: px.string().optional(),
669
785
  start: px.number().optional(),
670
786
  stretch: px.number().optional(),
671
787
  timeCrop: px.tuple([px.number(), px.number()]).optional()
672
788
  }));
673
789
  var PxCloneEffectSchema = implementsInterface()(px.object({
674
- type: px.string().optional(),
675
- baseId: px.string().optional(),
790
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
791
+ type: px.enum([PxCloneType.content]).optional(),
792
+ sourceId: px.string().optional(),
676
793
  retime: PxRetimeEffectSchema.optional()
677
794
  }));
678
- var PxGradientUnits = {
679
- userSpaceOnUse: "userSpaceOnUse",
680
- objectBoundingBox: "objectBoundingBox"
681
- };
682
- var PxGradientSpreadMethod = {
683
- pad: "pad",
684
- reflect: "reflect",
685
- repeat: "repeat"
686
- };
687
- var PxGradientType = {
688
- linear: "linear",
689
- radial: "radial"
690
- };
691
795
  var PxGradientStopSchema = implementsInterface()(px.object({
692
796
  offset: px.number(),
693
797
  color: px.string()
@@ -695,39 +799,28 @@ var PxGradientStopSchema = implementsInterface()(px.object({
695
799
  var PxAnimatableGradientStopsSchema = px.union([
696
800
  px.array(PxGradientStopSchema),
697
801
  px.object({ value: px.array(PxGradientStopSchema) }),
698
- px.object({ keyframes: px.array(PxKeyframeSchema) })
802
+ PxPropertyAnimationSchema
699
803
  ]);
700
- var PxGradientGeometryAnimationSchema = implementsInterface()(px.object({
701
- gradientX1: PxPropertyAnimationSchema.optional(),
702
- gradientY1: PxPropertyAnimationSchema.optional(),
703
- gradientX2: PxPropertyAnimationSchema.optional(),
704
- gradientY2: PxPropertyAnimationSchema.optional(),
705
- gradientCx: PxPropertyAnimationSchema.optional(),
706
- gradientCy: PxPropertyAnimationSchema.optional(),
707
- gradientFx: PxPropertyAnimationSchema.optional(),
708
- gradientFy: PxPropertyAnimationSchema.optional(),
709
- gradientR: PxPropertyAnimationSchema.optional()
710
- }));
711
804
  var PxFillGradientEffectSchema = implementsInterface()(px.object({
805
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
712
806
  type: px.enum([PxGradientType.linear, PxGradientType.radial]),
713
- p1: px.tuple([px.number(), px.number()]).optional(),
714
- p2: px.tuple([px.number(), px.number()]).optional(),
715
- c: px.tuple([px.number(), px.number()]).optional(),
716
- r: px.number().optional(),
717
- fp: px.tuple([px.number(), px.number()]).optional(),
807
+ p1: PxAnimatableVec2Schema.optional(),
808
+ p2: PxAnimatableVec2Schema.optional(),
809
+ c: PxAnimatableVec2Schema.optional(),
810
+ r: PxAnimatableNumberSchema.optional(),
811
+ fp: PxAnimatableVec2Schema.optional(),
718
812
  stops: PxAnimatableGradientStopsSchema.optional(),
719
- gradientUnits: px.string().optional(),
720
- spreadMethod: px.string().optional(),
721
- gradientTransform: px.string().optional(),
722
- animate: PxGradientGeometryAnimationSchema.optional()
813
+ gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
814
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
815
+ gradientTransform: px.string().optional()
723
816
  }));
724
817
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
725
818
  var PxTextPathEffectSchema = implementsInterface()(px.object({
726
819
  path: px.string(),
727
- pathOverflow: px.string().optional(),
728
- lengthAdjust: px.string().optional(),
729
- method: px.string().optional(),
730
- spacing: px.string().optional(),
820
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
821
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
822
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
823
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
731
824
  startOffset: PxAnimatableNumberSchema.optional(),
732
825
  textLength: PxAnimatableNumberSchema.optional()
733
826
  }));
@@ -735,13 +828,12 @@ var PxTextEffectSchema = implementsInterface()(px.object({
735
828
  useGlyphs: px.boolean().optional()
736
829
  }));
737
830
  var PxEffectsSchema = implementsInterface()(px.object({
738
- transformation: PxTransformationEffectSchema.optional(),
831
+ transformBy: PxTransformByEffectSchema.optional(),
739
832
  repeater: PxRepeaterEffectSchema.optional(),
740
833
  maskedBy: PxMaskedByEffectSchema.optional(),
741
834
  clipPath: PxClipPathEffectSchema.optional(),
742
835
  trimPath: PxTrimPathEffectSchema.optional(),
743
836
  clone: PxCloneEffectSchema.optional(),
744
- isCombinedShape: px.boolean().optional(),
745
837
  fillGradient: PxFillGradientEffectSchema.optional(),
746
838
  strokeGradient: PxStrokeGradientEffectSchema.optional(),
747
839
  textPath: PxTextPathEffectSchema.optional(),
@@ -765,6 +857,14 @@ function validateNodeEffects(root, opts) {
765
857
  return warnings;
766
858
  }
767
859
  var PxNodeBase = px.openObject({
860
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
861
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
862
+ // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
863
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
864
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
865
+ // would add words that all mean "type" and still need the carrier to read.
866
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
867
+ // (issues V3), never of distinct key names.
768
868
  type: px.string(),
769
869
  id: px.string().optional(),
770
870
  meta: px.any().optional(),
@@ -774,7 +874,7 @@ var PxNodeBase = px.openObject({
774
874
  effects: PxEffectsSchema.optional(),
775
875
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
776
876
  // string ref / array of refs / inline definition / mixed array; mirrors
777
- // `animator.animate` map values and what `processNode` resolves at runtime.
877
+ // `animator.animateById` map values and what `processNode` resolves at runtime.
778
878
  animate: PxElementAnimationSchema.optional(),
779
879
  style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
780
880
  }, PxAttrValueSchema);
@@ -782,8 +882,10 @@ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._sh
782
882
  children: px.lazy(() => px.array(PxNodeSchema), []).optional()
783
883
  }), PxAttrValueSchema);
784
884
  var PxSvgNodeExtra = px.object({
785
- width: px.number().optional(),
786
- height: px.number().optional(),
885
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
886
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
887
+ width: px.union([px.number(), px.string()]).optional(),
888
+ height: px.union([px.number(), px.string()]).optional(),
787
889
  viewBox: px.string().optional(),
788
890
  animator: PxAnimatorConfigSchema.optional()
789
891
  });
@@ -798,35 +900,10 @@ var PxBezierPathSchema = implementsInterface()(px.object({
798
900
  o: px.array(px.array(px.number())).optional(),
799
901
  c: px.boolean().optional()
800
902
  }));
801
- function isPxElementFileFormat(fileJson) {
802
- if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
803
- return false;
804
- }
805
- return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
806
- }
807
903
  function isPxElementFileFormatDeep(fileJson) {
808
904
  const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
809
905
  return { valid, errors: valid ? [] : ["Document failed schema validation"] };
810
906
  }
811
- function getAnimatorConfig(doc) {
812
- var _a, _b;
813
- 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);
814
- }
815
- function getDefs(doc) {
816
- var _a;
817
- if (!doc) return void 0;
818
- return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
819
- }
820
- function getBindings(doc) {
821
- var _a;
822
- if (!doc) return void 0;
823
- const animate = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animate;
824
- if (!animate) return void 0;
825
- return Object.entries(animate).map(([id, anim]) => ({ id, animate: anim }));
826
- }
827
- function getChildren(doc) {
828
- return doc == null ? void 0 : doc.children;
829
- }
830
907
 
831
908
  // src/PxAnimatorUtil.ts
832
909
  function bezierToSvgPath(path, forceCurves = false) {
@@ -1281,7 +1358,7 @@ function generateNewIds(doc) {
1281
1358
  "flood-color",
1282
1359
  "lighting-color"
1283
1360
  ]);
1284
- const directIdRefAttrs = /* @__PURE__ */ new Set(["baseId", "targetId", "boundElementId"]);
1361
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
1285
1362
  function collectIds(node) {
1286
1363
  if (!node || typeof node !== "object") return;
1287
1364
  if (node.id && typeof node.id === "string") {
@@ -1319,9 +1396,10 @@ function generateNewIds(doc) {
1319
1396
  } else if (urlRefAttrs.has(key)) {
1320
1397
  node[key] = replaceUrlRefs(value, idMap);
1321
1398
  } else if (directIdRefAttrs.has(key)) {
1322
- const newId = idMap.get(value);
1399
+ const hasHash = value.startsWith("#");
1400
+ const newId = idMap.get(hasHash ? value.slice(1) : value);
1323
1401
  if (newId) {
1324
- node[key] = newId;
1402
+ node[key] = hasHash ? "#" + newId : newId;
1325
1403
  }
1326
1404
  } else if (value.includes("url(#")) {
1327
1405
  node[key] = replaceUrlRefs(value, idMap);
@@ -1339,14 +1417,14 @@ function generateNewIds(doc) {
1339
1417
  }
1340
1418
  collectIds(cloned);
1341
1419
  updateRefs(cloned);
1342
- const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animate;
1420
+ const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
1343
1421
  if (docAnimate && typeof docAnimate === "object") {
1344
1422
  const updatedAnimate = {};
1345
1423
  for (const [id, anim] of Object.entries(docAnimate)) {
1346
1424
  const newId = (_b = idMap.get(id)) != null ? _b : id;
1347
1425
  updatedAnimate[newId] = anim;
1348
1426
  }
1349
- cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animate: updatedAnimate });
1427
+ cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animateById: updatedAnimate });
1350
1428
  }
1351
1429
  return cloned;
1352
1430
  }
@@ -1437,8 +1515,9 @@ function getNormalizedProps(props) {
1437
1515
  let value = props[rawKey];
1438
1516
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1439
1517
  propsCopy[key] = toRGBA(value);
1440
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
1441
- propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
1518
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes && !value.kfs) {
1519
+ const parts = value.value && typeof value.value === "object" ? value.value : value;
1520
+ propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
1442
1521
  } else if (TRANSFORM_FN_NAMES.has(key)) {
1443
1522
  if (Array.isArray(value)) {
1444
1523
  if (key === "translate") value = value.map((v) => v + "px");
@@ -1446,6 +1525,8 @@ function getNormalizedProps(props) {
1446
1525
  }
1447
1526
  if (key === "rotate") value = value + "deg";
1448
1527
  propsCopy["transform"] = key + "(" + value + ")";
1528
+ } else if (Array.isArray(value)) {
1529
+ propsCopy[key] = value.join(",");
1449
1530
  } else if (value !== void 0 && value !== null) {
1450
1531
  propsCopy[key] = String(value);
1451
1532
  }
@@ -1847,6 +1928,16 @@ function walkAndMaterialise(node, opts) {
1847
1928
  }
1848
1929
 
1849
1930
  // src/PxDefinitions.ts
1931
+ var LOOP_JUMP_SHIFT_MS = 1;
1932
+ function deepEqualValue(a, b) {
1933
+ if (a === b) return true;
1934
+ if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
1935
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
1936
+ const ka = Object.keys(a);
1937
+ const kb = Object.keys(b);
1938
+ if (ka.length !== kb.length) return false;
1939
+ return ka.every((k) => deepEqualValue(a[k], b[k]));
1940
+ }
1850
1941
  function parsePathCommands(d) {
1851
1942
  const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
1852
1943
  const commands = [];
@@ -2049,7 +2140,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2049
2140
  const totalIntervals = keyframes.length - 1;
2050
2141
  const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2051
2142
  let segKfs;
2052
- if (loop.before) {
2143
+ if (loop.extend === PxLoopExtend.before) {
2053
2144
  segKfs = keyframes.slice(0, segCount + 1);
2054
2145
  } else {
2055
2146
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -2057,7 +2148,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2057
2148
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2058
2149
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2059
2150
  let fillStart, fillEnd;
2060
- if (loop.before) {
2151
+ if (loop.extend === PxLoopExtend.before) {
2061
2152
  fillStart = 0;
2062
2153
  fillEnd = firstT;
2063
2154
  } else {
@@ -2084,7 +2175,12 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2084
2175
  const remainder = fillDuration - fullReps * segDuration;
2085
2176
  const partialFraction = remainder / segDuration;
2086
2177
  const looped = [];
2178
+ const separateBoundary = loop.extend !== PxLoopExtend.before;
2179
+ const originalTerminalKf = keyframes[keyframes.length - 1];
2180
+ let terminalEasingOverride;
2181
+ let hasTerminalEasingOverride = false;
2087
2182
  function appendRep(repStart, isReversed, partial) {
2183
+ var _a2;
2088
2184
  let entries;
2089
2185
  if (isReversed) {
2090
2186
  entries = [];
@@ -2120,8 +2216,26 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2120
2216
  looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
2121
2217
  return;
2122
2218
  }
2219
+ const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2220
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2221
+ if (isBoundary) {
2222
+ if (deepEqualValue(prevKf.v, entry.v)) {
2223
+ if (looped.length > 0) {
2224
+ prevKf.e = entry.e;
2225
+ prevKf.tangentOut = entry.tangentOut;
2226
+ } else {
2227
+ terminalEasingOverride = entry.e;
2228
+ hasTerminalEasingOverride = true;
2229
+ }
2230
+ continue;
2231
+ }
2232
+ if (looped.length > 0) {
2233
+ delete prevKf.tangentIn;
2234
+ delete prevKf.tangentOut;
2235
+ }
2236
+ }
2123
2237
  const pushed = {
2124
- t: repStart + entry.relT * segDuration,
2238
+ t: repStart + entry.relT * segDuration + (isBoundary ? LOOP_JUMP_SHIFT_MS : 0),
2125
2239
  v: entry.v,
2126
2240
  e: i < entries.length - 1 ? entry.e : void 0
2127
2241
  };
@@ -2169,7 +2283,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2169
2283
  looped.push(pushed);
2170
2284
  }
2171
2285
  }
2172
- if (loop.before) {
2286
+ if (loop.extend === PxLoopExtend.before) {
2173
2287
  if (partialFraction > 1e-9) {
2174
2288
  const isReversed = !!loop.alternate && fullReps % 2 === 0;
2175
2289
  appendRepTail(fillStart, isReversed, partialFraction);
@@ -2192,9 +2306,14 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2192
2306
  appendRep(repStart, isReversed, partialFraction);
2193
2307
  }
2194
2308
  }
2195
- if (loop.before) {
2309
+ if (loop.extend === PxLoopExtend.before) {
2196
2310
  return [...looped, ...keyframes];
2197
2311
  } else {
2312
+ if (hasTerminalEasingOverride && keyframes.length > 0) {
2313
+ const head = keyframes.slice(0, -1);
2314
+ const tail = __spreadProps(__spreadValues({}, keyframes[keyframes.length - 1]), { e: terminalEasingOverride });
2315
+ return [...head, tail, ...looped];
2316
+ }
2198
2317
  return [...keyframes, ...looped];
2199
2318
  }
2200
2319
  }
@@ -2308,20 +2427,23 @@ var _elementIdCounter = 0;
2308
2427
  function generateElementId() {
2309
2428
  return "_px_el_" + ++_elementIdCounter;
2310
2429
  }
2311
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.webapi) {
2430
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2312
2431
  const normalized = {};
2313
2432
  for (const [propName, propAnim] of Object.entries(animDef)) {
2433
+ if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
2434
+ continue;
2435
+ }
2314
2436
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2315
2437
  if (normalizedKfs.length > 0) {
2316
2438
  const out = { kfs: normalizedKfs };
2317
2439
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2318
2440
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2319
- normalized[propName] = engine === PxAnimatorEngine.webapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2441
+ normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2320
2442
  }
2321
2443
  }
2322
2444
  return normalized;
2323
2445
  }
2324
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.webapi) {
2446
+ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2325
2447
  const animatorConfig = getAnimatorConfig(doc) || {};
2326
2448
  const defs = getDefs(doc);
2327
2449
  const duration = animatorConfig.duration || 1e3;
@@ -2732,20 +2854,41 @@ function partsRecord(part, value, origin) {
2732
2854
  return rec;
2733
2855
  }
2734
2856
  function readAnimatable(raw) {
2735
- var _a, _b;
2857
+ var _a, _b, _c;
2736
2858
  if (raw === void 0) return { kind: "absent" /* Absent */ };
2737
2859
  if (Array.isArray(raw)) return { kind: "static" /* Static */, value: raw };
2738
2860
  if (typeof raw === "object") {
2739
2861
  const obj = raw;
2740
2862
  const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
2741
2863
  if (kfs) {
2742
- return { kind: "animated" /* Animated */, keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
2864
+ const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
2865
+ const base = (_b = obj.value) != null ? _b : obj.v;
2866
+ if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
2867
+ return out;
2743
2868
  }
2744
- const staticValue = (_b = obj.value) != null ? _b : obj.v;
2869
+ const staticValue = (_c = obj.value) != null ? _c : obj.v;
2745
2870
  if (staticValue !== void 0) return { kind: "static" /* Static */, value: staticValue };
2746
2871
  }
2747
2872
  return { kind: "static" /* Static */, value: raw };
2748
2873
  }
2874
+ function writeAnimatableChannel(node, attrName, read, opts) {
2875
+ var _a, _b, _c, _d;
2876
+ const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
2877
+ if (read.kind === "absent" /* Absent */) return;
2878
+ if (read.kind === "static" /* Static */) {
2879
+ node[attrName] = toOut(read.value);
2880
+ return;
2881
+ }
2882
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
2883
+ const animate = __spreadValues({}, prevAnimate || {});
2884
+ const block = { keyframes: read.keyframes };
2885
+ if (read.loop !== void 0) block.loop = read.loop;
2886
+ if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
2887
+ animate[attrName] = block;
2888
+ node.animate = animate;
2889
+ 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;
2890
+ if (baseline !== void 0) node[attrName] = toOut(baseline);
2891
+ }
2749
2892
  function normaliseKeyframe(kf) {
2750
2893
  if (!kf || typeof kf !== "object") return kf;
2751
2894
  const k = kf;
@@ -2765,7 +2908,7 @@ function readStaticOrigin(raw, ctx) {
2765
2908
  const o = readAnimatable(raw);
2766
2909
  if (o.kind === "absent" /* Absent */) return void 0;
2767
2910
  if (o.kind === "static" /* Static */) return o.value;
2768
- ctx.warnings.push("transformation.origin: animated origin approximated by its first keyframe");
2911
+ ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
2769
2912
  return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
2770
2913
  }
2771
2914
  function keyframeWith(kf, value) {
@@ -2778,7 +2921,7 @@ function keyframeWith(kf, value) {
2778
2921
  }
2779
2922
 
2780
2923
  // src/effects/transformationEffect.ts
2781
- function applyTransformationEffect(node, fx, ctx) {
2924
+ function applyTransformByEffect(node, fx, ctx) {
2782
2925
  if (!fx) return node;
2783
2926
  delete node.transform;
2784
2927
  let n = node;
@@ -2814,6 +2957,10 @@ function applyTransformationEffect(node, fx, ctx) {
2814
2957
  } else {
2815
2958
  n = wrapTransformPart(n, "translate" /* Translate */, fx.translate, ctx);
2816
2959
  }
2960
+ if (n !== node && node.id) {
2961
+ n.id = node.id;
2962
+ delete node.id;
2963
+ }
2817
2964
  return n;
2818
2965
  }
2819
2966
  function translateHasAutoOrient(translate) {
@@ -2823,8 +2970,6 @@ function translateHasAutoOrient(translate) {
2823
2970
  return Array.isArray(obj.keyframes) && obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
2824
2971
  }
2825
2972
  function normalizeScale(raw) {
2826
- if (raw === void 0) return void 0;
2827
- if (Array.isArray(raw)) return [raw[0] / 100, raw[1] / 100];
2828
2973
  return raw;
2829
2974
  }
2830
2975
  function wrapTransformPart(inner, part, raw, ctx) {
@@ -2866,35 +3011,57 @@ function wrapOrigin(inner, raw, invert) {
2866
3011
  return inner;
2867
3012
  }
2868
3013
 
3014
+ // src/effects/util.ts
3015
+ function genId(ctx, prefix) {
3016
+ return "_lw_" + prefix + "_" + ctx.nextId++;
3017
+ }
3018
+ function stripHash2(href) {
3019
+ return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3020
+ }
3021
+ function indexById(node, map) {
3022
+ var _a;
3023
+ if (typeof node.id === "string") map.set(node.id, node);
3024
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3025
+ }
3026
+ function spliceDefs(root, defs) {
3027
+ if (!defs.length) return;
3028
+ const existing = root.children || (root.children = []);
3029
+ existing.unshift({ type: "defs", children: defs });
3030
+ }
3031
+ var clone = deepClonePxNode;
3032
+ function regenerateIdsInClone(root, ctx) {
3033
+ return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3034
+ }
3035
+
2869
3036
  // src/effects/contentRefSplit.ts
2870
3037
  function identifyContentRefTargets(node, ctx, allocator) {
2871
3038
  var _a, _b, _c;
2872
3039
  if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.type) === "content") {
2873
- const baseId = node.effects.clone.baseId;
2874
- if (typeof baseId === "string" && baseId && !ctx.contentRefInnerIds.has(baseId)) {
2875
- ctx.contentRefInnerIds.set(baseId, allocator(baseId));
3040
+ const sourceId = stripHash2(node.effects.clone.sourceId);
3041
+ if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3042
+ ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
2876
3043
  }
2877
3044
  }
2878
3045
  (_c = node.children) == null ? void 0 : _c.forEach((c) => identifyContentRefTargets(c, ctx, allocator));
2879
3046
  }
2880
- function splitForContentRef(node, transformation, originalId, innerId, ctx) {
2881
- const outerBody = liftBodyTranslate(node, transformation);
3047
+ function splitForContentRef(node, transformBy, originalId, innerId, ctx) {
3048
+ const outerBody = liftBodyTranslate(node, transformBy);
2882
3049
  if (typeof node.id === "string") delete node.id;
2883
- const { outer: outerTr, inner: innerTr } = splitTransformationEffect(transformation);
3050
+ const { outer: outerTr, inner: innerTr } = splitTransformByEffect(transformBy);
2884
3051
  let innerNode = node;
2885
- innerNode = applyTransformationEffect(innerNode, innerTr, ctx);
3052
+ innerNode = applyTransformByEffect(innerNode, innerTr, ctx);
2886
3053
  const innerWrapper = { type: "g", id: innerId, children: [innerNode] };
2887
3054
  let outerWrapper = { type: "g", id: originalId, children: [innerWrapper] };
2888
3055
  if (outerBody.transform !== void 0) outerWrapper.transform = outerBody.transform;
2889
3056
  if (outerBody.animate !== void 0) outerWrapper.animate = outerBody.animate;
2890
3057
  if (outerTr) {
2891
3058
  delete outerWrapper.id;
2892
- outerWrapper = applyTransformationEffect(outerWrapper, outerTr, ctx);
3059
+ outerWrapper = applyTransformByEffect(outerWrapper, outerTr, ctx);
2893
3060
  outerWrapper.id = originalId;
2894
3061
  }
2895
3062
  return outerWrapper;
2896
3063
  }
2897
- function liftBodyTranslate(node, transformation) {
3064
+ function liftBodyTranslate(node, transformBy) {
2898
3065
  var _a, _b, _c;
2899
3066
  const out = {};
2900
3067
  let didLiftAnimate = false;
@@ -2948,7 +3115,7 @@ function liftBodyTranslate(node, transformation) {
2948
3115
  didLiftAnimate = true;
2949
3116
  }
2950
3117
  }
2951
- const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
3118
+ const transformationHasTranslate = (transformBy == null ? void 0 : transformBy.translate) !== void 0;
2952
3119
  const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
2953
3120
  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);
2954
3121
  if (typeof node.transform === "string") {
@@ -2967,6 +3134,24 @@ function liftBodyTranslate(node, transformation) {
2967
3134
  if (split.rest) node.transform = split.rest;
2968
3135
  else delete node.transform;
2969
3136
  }
3137
+ } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes && !node.transform.kfs) {
3138
+ const wrapped = node.transform.value;
3139
+ const isWrapped = !!(wrapped && typeof wrapped === "object");
3140
+ const value = isWrapped ? wrapped : node.transform;
3141
+ const rewrap = (rec) => isWrapped ? { value: rec } : rec;
3142
+ if (Array.isArray(value.translate)) {
3143
+ const rest = __spreadValues({}, value);
3144
+ delete rest.translate;
3145
+ const hasRest = Object.keys(rest).length > 0;
3146
+ if (stripBodyTranslateOnly) {
3147
+ if (hasRest) node.transform = rewrap(rest);
3148
+ else delete node.transform;
3149
+ } else {
3150
+ out.transform = rewrap({ translate: value.translate });
3151
+ if (hasRest) node.transform = rewrap(rest);
3152
+ else delete node.transform;
3153
+ }
3154
+ }
2970
3155
  }
2971
3156
  return out;
2972
3157
  }
@@ -3036,7 +3221,7 @@ function parseTranslateArgs(translateOp) {
3036
3221
  const nums = m[1].split(/[\s,]+/).filter(Boolean).map(Number);
3037
3222
  return [nums[0] || 0, nums[1] || 0];
3038
3223
  }
3039
- function splitTransformationEffect(fx) {
3224
+ function splitTransformByEffect(fx) {
3040
3225
  if (!fx) return {};
3041
3226
  const originOnOuter = needsOriginOnOuter(fx.translate);
3042
3227
  const innerHasPivotedPart = fx.rotate !== void 0 || fx.scale !== void 0;
@@ -3063,28 +3248,6 @@ function needsOriginOnOuter(translateAnim) {
3063
3248
  return false;
3064
3249
  }
3065
3250
 
3066
- // src/effects/util.ts
3067
- function genId(ctx, prefix) {
3068
- return "_lw_" + prefix + "_" + ctx.nextId++;
3069
- }
3070
- function stripHash2(href) {
3071
- return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3072
- }
3073
- function indexById(node, map) {
3074
- var _a;
3075
- if (typeof node.id === "string") map.set(node.id, node);
3076
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3077
- }
3078
- function spliceDefs(root, defs) {
3079
- if (!defs.length) return;
3080
- const existing = root.children || (root.children = []);
3081
- existing.unshift({ type: "defs", children: defs });
3082
- }
3083
- var clone = deepClonePxNode;
3084
- function regenerateIdsInClone(root, ctx) {
3085
- return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3086
- }
3087
-
3088
3251
  // src/effects/gradientEffect.ts
3089
3252
  function applyFillGradientEffect(node, fx, ctx) {
3090
3253
  return applyGradient(node, fx, ctx, "fill");
@@ -3106,62 +3269,63 @@ function synthesiseGradientDef(fx, id, ctx) {
3106
3269
  id
3107
3270
  };
3108
3271
  if (fx.type === PxGradientType.linear) {
3109
- if (fx.p1) {
3110
- out.x1 = String(fx.p1[0]);
3111
- out.y1 = String(fx.p1[1]);
3112
- }
3113
- if (fx.p2) {
3114
- out.x2 = String(fx.p2[0]);
3115
- out.y2 = String(fx.p2[1]);
3116
- }
3272
+ applyGeomVec(out, "x1", "y1", fx.p1);
3273
+ applyGeomVec(out, "x2", "y2", fx.p2);
3117
3274
  } else {
3118
- if (fx.c) {
3119
- out.cx = String(fx.c[0]);
3120
- out.cy = String(fx.c[1]);
3121
- }
3122
- if (fx.r !== void 0) out.r = String(fx.r);
3123
- if (fx.fp) {
3124
- out.fx = String(fx.fp[0]);
3125
- out.fy = String(fx.fp[1]);
3126
- }
3275
+ applyGeomVec(out, "cx", "cy", fx.c);
3276
+ applyGeomNumber(out, "r", fx.r);
3277
+ applyGeomVec(out, "fx", "fy", fx.fp);
3127
3278
  }
3128
3279
  if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
3129
3280
  if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
3130
3281
  if (fx.gradientTransform) out.gradientTransform = fx.gradientTransform;
3131
- const animate = fx.animate;
3132
- if (animate) {
3133
- const mapped = {};
3134
- for (const wireKey of Object.keys(animate)) {
3135
- const attr = GRADIENT_ANIM_CHANNEL_TO_ATTR[wireKey];
3136
- if (attr) mapped[attr] = animate[wireKey];
3137
- }
3138
- if (Object.keys(mapped).length) out.animate = mapped;
3139
- }
3140
3282
  out.children = buildStopChildren(fx.stops, ctx);
3141
3283
  return out;
3142
3284
  }
3143
- var GRADIENT_ANIM_CHANNEL_TO_ATTR = {
3144
- gradientX1: "x1",
3145
- gradientY1: "y1",
3146
- gradientX2: "x2",
3147
- gradientY2: "y2",
3148
- gradientCx: "cx",
3149
- gradientCy: "cy",
3150
- gradientFx: "fx",
3151
- gradientFy: "fy",
3152
- gradientR: "r"
3153
- };
3285
+ function applyGeomVec(out, xAttr, yAttr, raw) {
3286
+ var _a, _b, _c;
3287
+ const read = readAnimatable(raw);
3288
+ if (read.kind === "absent" /* Absent */) return;
3289
+ if (read.kind === "static" /* Static */) {
3290
+ out[xAttr] = String(read.value[0]);
3291
+ out[yAttr] = String(read.value[1]);
3292
+ return;
3293
+ }
3294
+ const axisChannel = (idx) => {
3295
+ const block = {
3296
+ keyframes: read.keyframes.map((kf) => {
3297
+ const axisKf = { time: kf.time, value: Array.isArray(kf.value) ? kf.value[idx] : void 0 };
3298
+ if (kf.easing !== void 0) axisKf.easing = kf.easing;
3299
+ return axisKf;
3300
+ })
3301
+ };
3302
+ if (read.loop !== void 0) block.loop = read.loop;
3303
+ return block;
3304
+ };
3305
+ const animate = (_a = out.animate) != null ? _a : {};
3306
+ animate[xAttr] = axisChannel(0);
3307
+ animate[yAttr] = axisChannel(1);
3308
+ out.animate = animate;
3309
+ const baseline = (_c = read.base) != null ? _c : (_b = read.keyframes[0]) == null ? void 0 : _b.value;
3310
+ if (Array.isArray(baseline)) {
3311
+ out[xAttr] = String(baseline[0]);
3312
+ out[yAttr] = String(baseline[1]);
3313
+ }
3314
+ }
3315
+ function applyGeomNumber(out, attrName, raw) {
3316
+ const read = readAnimatable(raw);
3317
+ if (read.kind === "absent" /* Absent */) return;
3318
+ writeAnimatableChannel(out, attrName, read, { asString: true });
3319
+ }
3154
3320
  function buildStopChildren(stops, ctx) {
3155
3321
  var _a, _b, _c, _d;
3156
3322
  if (!stops) return [];
3157
- if (Array.isArray(stops)) return stops.map(staticStopNode);
3158
- if (typeof stops === "object" && Array.isArray(stops.value)) {
3159
- return stops.value.map(staticStopNode);
3160
- }
3161
- const animBlock = stops;
3162
- const kfs = animBlock.keyframes;
3163
- if (!Array.isArray(kfs) || !kfs.length) return [];
3164
- const loopFromSource = animBlock.loop;
3323
+ const read = readAnimatable(stops);
3324
+ if (read.kind === "absent" /* Absent */) return [];
3325
+ if (read.kind === "static" /* Static */) return Array.isArray(read.value) ? read.value.map(staticStopNode) : [];
3326
+ const kfs = read.keyframes;
3327
+ if (!kfs.length) return [];
3328
+ const loopFromSource = read.loop;
3165
3329
  let stopCount = 0;
3166
3330
  for (const kf of kfs) {
3167
3331
  const v = (_a = kf.value) != null ? _a : kf.v;
@@ -3238,38 +3402,62 @@ function formatOffset(o) {
3238
3402
 
3239
3403
  // src/effects/clipPathEffect.ts
3240
3404
  function applyClipPathEffect(node, fx, ctx) {
3405
+ var _a, _b;
3241
3406
  if (!fx || !fx.d && !fx.animate) return node;
3242
3407
  const clipId = genId(ctx, "clip");
3243
- const pathChild = { type: "path", d: fx.d };
3244
- if (fx.animate) pathChild.animate = { d: fx.animate };
3408
+ const pathChild = { type: "path" };
3409
+ const read = readAnimatable(fx.d);
3410
+ if (read.kind !== "absent" /* Absent */) {
3411
+ if (read.kind === "static" /* Static */) {
3412
+ pathChild.d = pathString(read.value);
3413
+ } else {
3414
+ writeAnimatableChannel(pathChild, "d", read);
3415
+ if (pathChild.d !== void 0) pathChild.d = pathString(pathChild.d);
3416
+ }
3417
+ }
3418
+ if (fx.animate && !((_a = pathChild.animate) == null ? void 0 : _a.d)) {
3419
+ const animate = (_b = pathChild.animate) != null ? _b : {};
3420
+ animate.d = fx.animate;
3421
+ pathChild.animate = animate;
3422
+ }
3245
3423
  ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
3246
3424
  node.clipPath = "url(#" + clipId + ")";
3247
3425
  return node;
3248
3426
  }
3427
+ function pathString(v) {
3428
+ if (typeof v === "string") return v;
3429
+ if (v && typeof v === "object" && typeof v.path === "string") return v.path;
3430
+ return void 0;
3431
+ }
3249
3432
 
3250
3433
  // src/effects/maskedByEffect.ts
3251
- function applyMaskedByEffect(node, fx, transformation, ctx) {
3434
+ function applyMaskedByEffect(node, fx, transformBy, ctx) {
3252
3435
  if (!fx) return node;
3253
- if (!fx.href) {
3254
- ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
3436
+ const sourceId = stripHash2(fx.sourceId);
3437
+ if (!sourceId) {
3438
+ ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
3255
3439
  return node;
3256
3440
  }
3257
3441
  const maskId = genId(ctx, "mask");
3258
- let content = { type: "use", href: "#" + fx.href };
3259
- if (transformation) {
3260
- content = wrapInverseTransform(content, transformation, ctx);
3442
+ let content = { type: "use", href: "#" + sourceId };
3443
+ if (transformBy) {
3444
+ content = wrapInverseTransform(content, transformBy, ctx);
3261
3445
  } else if (hasAnimateTransform(node)) {
3262
3446
  content = wrapInverseAnimatedBodyTransform(content, node, ctx);
3263
3447
  } else {
3264
3448
  const bodyStatic = readTransformationFromBody(node);
3265
3449
  if (bodyStatic) content = wrapInverseTransform(content, bodyStatic, ctx);
3266
3450
  }
3267
- const includeTargetOwn = transformation === void 0 && !nodeHasBodyTransform(node);
3268
- content = wrapAncestorChainCompensation(content, node, fx.href, ctx, includeTargetOwn);
3451
+ const includeTargetOwn = transformBy === void 0 && !nodeHasBodyTransform(node);
3452
+ content = wrapAncestorChainCompensation(content, node, sourceId, ctx, includeTargetOwn);
3269
3453
  const mask = { type: "mask", id: maskId, children: [content] };
3270
3454
  if (fx.maskType) mask.maskType = fx.maskType;
3271
3455
  if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
3272
3456
  if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
3457
+ if (fx.x !== void 0) mask.x = String(fx.x);
3458
+ if (fx.y !== void 0) mask.y = String(fx.y);
3459
+ if (fx.width !== void 0) mask.width = String(fx.width);
3460
+ if (fx.height !== void 0) mask.height = String(fx.height);
3273
3461
  ctx.defs.push(mask);
3274
3462
  node.mask = "url(#" + maskId + ")";
3275
3463
  return node;
@@ -3376,6 +3564,19 @@ function readTransformationFromBody(node) {
3376
3564
  if (parts.origin) out.origin = parts.origin;
3377
3565
  return Object.keys(out).length ? out : void 0;
3378
3566
  }
3567
+ if (node.transform && typeof node.transform === "object" && !node.transform.keyframes && !node.transform.kfs) {
3568
+ const wrapped = node.transform.value;
3569
+ const value = wrapped && typeof wrapped === "object" ? wrapped : node.transform;
3570
+ if (value && typeof value === "object") {
3571
+ const out = {};
3572
+ if (Array.isArray(value.translate)) out.translate = value.translate;
3573
+ if (typeof value.rotate === "number") out.rotate = value.rotate;
3574
+ if (typeof value.skew === "number") out.skew = value.skew;
3575
+ if (Array.isArray(value.scale)) out.scale = { value: value.scale };
3576
+ if (Array.isArray(value.origin)) out.origin = value.origin;
3577
+ return Object.keys(out).length ? out : void 0;
3578
+ }
3579
+ }
3379
3580
  return void 0;
3380
3581
  }
3381
3582
  function parseTransformStringToParts(s) {
@@ -3509,10 +3710,10 @@ function collectMaskAncestorChains(root, ctx) {
3509
3710
  const interestingNodes = /* @__PURE__ */ new Set();
3510
3711
  const collectInterestingNodes = (n) => {
3511
3712
  var _a, _b;
3512
- const href = (_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.href;
3513
- if (typeof href === "string") {
3713
+ const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.sourceId);
3714
+ if (typeof maskSourceId === "string") {
3514
3715
  interestingNodes.add(n);
3515
- const sourceNode = ctx.idMap.get(href);
3716
+ const sourceNode = ctx.idMap.get(maskSourceId);
3516
3717
  if (sourceNode) interestingNodes.add(sourceNode);
3517
3718
  }
3518
3719
  if (Array.isArray(n.children)) for (const ch of n.children) collectInterestingNodes(ch);
@@ -3538,8 +3739,9 @@ function extractTranslateOnly(node, ctx) {
3538
3739
  if (typeof tr === "string") {
3539
3740
  const parts = parseTranslateOnlyFromString(tr, ctx);
3540
3741
  if (parts) out.translate = parts;
3541
- } else if (tr && typeof tr === "object") {
3542
- const value = tr.value;
3742
+ } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
3743
+ const wrapped = tr.value;
3744
+ const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
3543
3745
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
3544
3746
  out.translate = [value.translate[0] || 0, value.translate[1] || 0];
3545
3747
  }
@@ -3589,17 +3791,17 @@ function parseTranslateOnlyFromString(s, ctx) {
3589
3791
  var CONTENT_SUBREF = "content";
3590
3792
  function applyRefHref(node, clone2, ctx) {
3591
3793
  if (!clone2) return;
3592
- const baseId = clone2.baseId;
3593
- if (!baseId) {
3594
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing baseId");
3794
+ const sourceId = stripHash2(clone2.sourceId);
3795
+ if (!sourceId) {
3796
+ if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
3595
3797
  return;
3596
3798
  }
3597
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
3799
+ const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
3598
3800
  node.href = "#" + targetId;
3599
3801
  }
3600
- function applyRefAndTransformationEffect(node, clone2, transformation, ctx) {
3802
+ function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
3601
3803
  applyRefHref(node, clone2, ctx);
3602
- return applyTransformationEffect(node, transformation, ctx);
3804
+ return applyTransformByEffect(node, transformBy, ctx);
3603
3805
  }
3604
3806
 
3605
3807
  // src/effects/repeaterEffect.ts
@@ -3624,7 +3826,7 @@ function applyRepeaterEffect(node, fx, ctx) {
3624
3826
  for (let i = 1; i < copies; i++) {
3625
3827
  const baseClone = clone(base);
3626
3828
  const synthFx = synthesisePerCopyFx(fx, i);
3627
- const wrapped = synthFx ? applyTransformationEffect(baseClone, synthFx, ctx) : baseClone;
3829
+ const wrapped = synthFx ? applyTransformByEffect(baseClone, synthFx, ctx) : baseClone;
3628
3830
  children.push(wrapped);
3629
3831
  }
3630
3832
  const wrapper = { type: "g", children };
@@ -3636,10 +3838,13 @@ function applyRepeaterEffect(node, fx, ctx) {
3636
3838
  function synthesisePerCopyFx(fx, i) {
3637
3839
  const out = {};
3638
3840
  if (fx.translate !== void 0) {
3639
- out.translate = mapAnimatableVec2(fx.translate, (v) => [v[0] * i, v[1] * i]);
3841
+ out.translate = mapAnimatable(fx.translate, (v) => [v[0] * i, v[1] * i]);
3640
3842
  }
3641
3843
  if (fx.rotate !== void 0) {
3642
- out.rotate = mapAnimatableNumber(fx.rotate, (v) => v * i);
3844
+ out.rotate = mapAnimatable(fx.rotate, (v) => v * i);
3845
+ }
3846
+ if (fx.skew !== void 0) {
3847
+ out.skew = mapAnimatable(fx.skew, (v) => v * i);
3643
3848
  }
3644
3849
  if (fx.scale !== void 0) {
3645
3850
  out.scale = synthesiseScale(fx.scale, i);
@@ -3649,65 +3854,52 @@ function synthesisePerCopyFx(fx, i) {
3649
3854
  }
3650
3855
  return Object.keys(out).length ? out : void 0;
3651
3856
  }
3652
- function mapAnimatableVec2(raw, fn) {
3653
- if (Array.isArray(raw)) return fn(raw);
3654
- if (raw && typeof raw === "object") {
3655
- const obj = raw;
3656
- if (Array.isArray(obj.keyframes)) {
3657
- return __spreadProps(__spreadValues({}, obj), {
3658
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: fn(kf.value) }) : kf)
3659
- });
3660
- }
3661
- if (obj.value !== void 0) {
3662
- return __spreadProps(__spreadValues({}, obj), { value: fn(obj.value) });
3663
- }
3857
+ function mapAnimatable(raw, fn, wrapStatic = false) {
3858
+ const read = readAnimatable(raw);
3859
+ if (read.kind === "absent" /* Absent */) return raw;
3860
+ if (read.kind === "static" /* Static */) {
3861
+ const mapped = fn(read.value);
3862
+ const wasRawStatic = typeof raw === "number" || Array.isArray(raw);
3863
+ return wasRawStatic && !wrapStatic ? mapped : { value: mapped };
3664
3864
  }
3665
- return raw;
3666
- }
3667
- function mapAnimatableNumber(raw, fn) {
3668
- if (typeof raw === "number") return fn(raw);
3669
- if (raw && typeof raw === "object") {
3670
- const obj = raw;
3671
- if (Array.isArray(obj.keyframes)) {
3672
- return __spreadProps(__spreadValues({}, obj), {
3673
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: fn(kf.value) }) : kf)
3674
- });
3675
- }
3676
- if (obj.value !== void 0) {
3677
- return __spreadProps(__spreadValues({}, obj), { value: fn(obj.value) });
3678
- }
3679
- }
3680
- return raw;
3865
+ const out = {
3866
+ keyframes: read.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: fn(kf.value) }) : kf)
3867
+ };
3868
+ if (read.loop !== void 0) out.loop = read.loop;
3869
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
3870
+ if (read.base !== void 0) out.value = fn(read.base);
3871
+ return out;
3681
3872
  }
3682
3873
  function synthesiseScale(raw, i) {
3683
- const scalePowerFromPercent = (v) => [Math.pow(v[0] / 100, i), Math.pow(v[1] / 100, i)];
3684
- const scalePowerFromUnits = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
3685
- if (Array.isArray(raw)) {
3686
- return { value: scalePowerFromPercent(raw) };
3687
- }
3688
- if (raw && typeof raw === "object") {
3689
- const obj = raw;
3690
- if (Array.isArray(obj.keyframes)) {
3691
- return __spreadProps(__spreadValues({}, obj), {
3692
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps(__spreadValues({}, kf), { value: scalePowerFromUnits(kf.value) }) : kf)
3693
- });
3694
- }
3695
- if (obj.value !== void 0) {
3696
- return __spreadProps(__spreadValues({}, obj), { value: scalePowerFromPercent(obj.value) });
3697
- }
3698
- }
3699
- return raw;
3874
+ const scalePower = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
3875
+ return mapAnimatable(raw, scalePower, true);
3700
3876
  }
3701
3877
 
3702
3878
  // src/effects/retimeEffect.ts
3703
3879
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
3704
3880
  function asRetime(r) {
3705
3881
  var _a, _b;
3706
- if (r.timeCrop) {
3707
- console.warn("retime: `timeCrop` is not supported yet and will be ignored");
3708
- }
3709
3882
  return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
3710
3883
  }
3884
+ var CROP_EDGE_MS = 1;
3885
+ function applyTimeCrop(useNode, crop, ctx) {
3886
+ const [start, end] = crop;
3887
+ if (!Number.isFinite(start) || !Number.isFinite(end)) {
3888
+ ctx.warnings.push("retime: timeCrop is not a pair of finite numbers \u2014 ignored");
3889
+ return;
3890
+ }
3891
+ const keyframes = end <= start ? [{ time: 0, value: 0 }] : [
3892
+ ...start > 0 ? [{ time: Math.max(0, start - CROP_EDGE_MS), value: 0 }] : [],
3893
+ { time: Math.max(0, start), value: 1 },
3894
+ { time: end, value: 1 },
3895
+ { time: end + CROP_EDGE_MS, value: 0 }
3896
+ ];
3897
+ const inner = __spreadValues({}, useNode);
3898
+ for (const k of Object.keys(useNode)) delete useNode[k];
3899
+ useNode.type = "g";
3900
+ useNode.children = [inner];
3901
+ useNode.animate = { opacity: { keyframes } };
3902
+ }
3711
3903
  function concatRetime(child, parent) {
3712
3904
  return {
3713
3905
  start: parent.start + parent.stretch * child.start,
@@ -3767,8 +3959,10 @@ function applyAllRetimeEffects(root, ctx) {
3767
3959
  for (const useNode of sites) {
3768
3960
  const retime = readCloneRetime(useNode);
3769
3961
  if (!retime) continue;
3962
+ const crop = retime.timeCrop;
3770
3963
  clearCloneRetime(useNode);
3771
3964
  materialiseRetime(useNode, asRetime(retime), ctx);
3965
+ if (crop) applyTimeCrop(useNode, crop, ctx);
3772
3966
  }
3773
3967
  }
3774
3968
  function materialiseRetime(useNode, retime, ctx) {
@@ -4015,14 +4209,11 @@ function createPathSampler(d) {
4015
4209
  // src/effects/textPathEffect.ts
4016
4210
  var EXTEND_MARGIN_FRAC = 0.15;
4017
4211
  function numRange(v) {
4018
- if (typeof v === "number") return { min: v, max: v };
4019
- if (v && typeof v === "object") {
4020
- const o = v;
4021
- if (typeof o.value === "number") return { min: o.value, max: o.value };
4022
- if (Array.isArray(o.keyframes) && o.keyframes.length) {
4023
- const vals = o.keyframes.map((k) => Number(k.value) || 0);
4024
- return { min: Math.min(...vals), max: Math.max(...vals) };
4025
- }
4212
+ const read = readAnimatable(v);
4213
+ if (read.kind === "static" /* Static */ && typeof read.value === "number") return { min: read.value, max: read.value };
4214
+ if (read.kind === "animated" /* Animated */ && read.keyframes.length) {
4215
+ const vals = read.keyframes.map((k) => Number(k.value) || 0);
4216
+ return { min: Math.min(...vals), max: Math.max(...vals) };
4026
4217
  }
4027
4218
  return { min: 0, max: 0 };
4028
4219
  }
@@ -4042,11 +4233,16 @@ function estimateTextAdvance(node) {
4042
4233
  var r3 = (n) => Math.round(n * 1e3) / 1e3;
4043
4234
  function shiftAnimatable(v, by) {
4044
4235
  if (!by || v === void 0 || v === null) return v;
4045
- if (typeof v === "number") return v + by;
4046
- const o = v;
4047
- if (typeof o.value === "number") return __spreadProps(__spreadValues({}, o), { value: o.value + by });
4048
- if (Array.isArray(o.keyframes)) return __spreadProps(__spreadValues({}, o), { keyframes: o.keyframes.map((k) => __spreadProps(__spreadValues({}, k), { value: (Number(k.value) || 0) + by })) });
4049
- return v;
4236
+ const read = readAnimatable(v);
4237
+ if (read.kind === "absent" /* Absent */) return v;
4238
+ if (read.kind === "static" /* Static */) return typeof v === "number" ? read.value + by : { value: read.value + by };
4239
+ const out = {
4240
+ keyframes: read.keyframes.map((k) => __spreadProps(__spreadValues({}, k), { value: (Number(k.value) || 0) + by }))
4241
+ };
4242
+ if (read.loop !== void 0) out.loop = read.loop;
4243
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
4244
+ if (read.base !== void 0) out.value = read.base + by;
4245
+ return out;
4050
4246
  }
4051
4247
  function extendedPathForBrowser(pathD, opts) {
4052
4248
  var _a;
@@ -4102,26 +4298,7 @@ function applyTextPathEffect(node, fx, ctx) {
4102
4298
  }
4103
4299
  function applyAnimatableNumber(node, attrName, raw) {
4104
4300
  if (raw === void 0 || raw === null) return;
4105
- if (typeof raw === "number") {
4106
- node[attrName] = String(raw);
4107
- return;
4108
- }
4109
- if (typeof raw === "object" && raw !== null) {
4110
- const obj = raw;
4111
- if (Array.isArray(obj.keyframes)) {
4112
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
4113
- const animate = __spreadValues({}, prevAnimate || {});
4114
- const block = { keyframes: obj.keyframes };
4115
- if (obj.loop !== void 0) block.loop = obj.loop;
4116
- animate[attrName] = block;
4117
- node.animate = animate;
4118
- return;
4119
- }
4120
- if (typeof obj.value === "number") {
4121
- node[attrName] = String(obj.value);
4122
- return;
4123
- }
4124
- }
4301
+ writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
4125
4302
  }
4126
4303
 
4127
4304
  // src/effects/elementFactory.ts
@@ -4315,13 +4492,13 @@ function materialiseGlyphTextHorizontal(node, opts) {
4315
4492
  if (y !== void 0) pen.y = y;
4316
4493
  pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
4317
4494
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4318
- const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
4495
+ const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4319
4496
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
4320
4497
  if (el.children) for (const ch of el.children) walk(ch, s);
4321
4498
  };
4322
4499
  const rootStyle = rootStyleOf(node);
4323
4500
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
4324
- const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
4501
+ const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
4325
4502
  if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
4326
4503
  const anchor = str(node.textAnchor);
4327
4504
  if (anchor === "middle" || anchor === "end") {
@@ -4370,7 +4547,7 @@ function layoutGlyphTextChars(node, opts) {
4370
4547
  if (y !== void 0) pen.y = y;
4371
4548
  pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
4372
4549
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4373
- const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
4550
+ const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4374
4551
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
4375
4552
  if (el.children) for (const ch of el.children) walk(ch, s);
4376
4553
  };
@@ -4385,7 +4562,7 @@ function layoutGlyphTextChars(node, opts) {
4385
4562
  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 });
4386
4563
  }
4387
4564
  }
4388
- const rootContent = (_e = str(node[TEXT_ATTR])) != null ? _e : str(node[TEXT_CONTENT_ATTR]);
4565
+ const rootContent = (_e = str(node[TEXT_CONTENT_ATTR])) != null ? _e : str(node[TEXT_ATTR]);
4389
4566
  if (rootContent && !((_f = node.children) == null ? void 0 : _f.length)) renderChars(rootContent, rootStyle);
4390
4567
  const anchor = str(node.textAnchor);
4391
4568
  if (anchor === "middle" || anchor === "end") {
@@ -4413,7 +4590,7 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4413
4590
  const walk = (el, parentStyle) => {
4414
4591
  var _a2, _b2, _c;
4415
4592
  const s = resolveStyle2(el, parentStyle);
4416
- const content = (_a2 = str(el[TEXT_ATTR])) != null ? _a2 : str(el[TEXT_CONTENT_ATTR]);
4593
+ const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
4417
4594
  if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
4418
4595
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4419
4596
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
@@ -4467,7 +4644,7 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4467
4644
  const walk = (el, parentStyle) => {
4468
4645
  var _a, _b, _c;
4469
4646
  const s = resolveStyle2(el, parentStyle);
4470
- const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
4647
+ const content = (_a = str(el[TEXT_CONTENT_ATTR])) != null ? _a : str(el[TEXT_ATTR]);
4471
4648
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
4472
4649
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4473
4650
  if (gf) {
@@ -4691,9 +4868,9 @@ function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pat
4691
4868
  }
4692
4869
 
4693
4870
  // src/effects/trimPathEffect.ts
4694
- function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4871
+ function applyTrimPathEffect(node, trimPath, ctx) {
4695
4872
  if (!trimPath) return node;
4696
- const trimAllAsOne = !!trimPath.trimAllAsOne;
4873
+ const combined = trimPath.subPaths === PxTrimSubPaths.combined;
4697
4874
  const leafEntries = [];
4698
4875
  const measure = (n) => {
4699
4876
  if (Array.isArray(n.children) && n.children.length > 0) {
@@ -4714,16 +4891,16 @@ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4714
4891
  measure(node);
4715
4892
  if (!leafEntries.length) return node;
4716
4893
  let acc = 0;
4717
- const iterOrder = trimAllAsOne ? [...leafEntries].reverse() : leafEntries;
4894
+ const iterOrder = combined ? [...leafEntries].reverse() : leafEntries;
4718
4895
  for (const entry of iterOrder) {
4719
4896
  for (const sp of entry.subpaths) {
4720
- if (!trimAllAsOne) acc = 0;
4897
+ if (!combined) acc = 0;
4721
4898
  sp.startOffsetPx = acc;
4722
4899
  acc += sp.lengthPx;
4723
4900
  }
4724
4901
  }
4725
4902
  const chainLengthPx = acc;
4726
- if (trimAllAsOne && chainLengthPx < 1e-3) return node;
4903
+ if (combined && chainLengthPx < 1e-3) return node;
4727
4904
  const offsetReadRaw = readAnimatable(trimPath.offset);
4728
4905
  const offsetRead = offsetReadRaw.kind === "absent" /* Absent */ ? { kind: "static" /* Static */, value: 0 } : offsetReadRaw;
4729
4906
  const rangeReadRaw = readRangeWithCrossings(trimPath.range);
@@ -4735,18 +4912,18 @@ function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
4735
4912
  if (leafEntries.length === 1 && leafEntries[0].leaf === node && leafEntries[0].subpaths.length === 1) {
4736
4913
  const entry = leafEntries[0];
4737
4914
  const sp = entry.subpaths[0];
4738
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
4915
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
4739
4916
  if (pathLengthPx < 1e-3) return node;
4740
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
4917
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
4741
4918
  return collapseLeafWithTrim(entry.leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead);
4742
4919
  }
4743
4920
  const replacements = /* @__PURE__ */ new Map();
4744
4921
  for (const entry of leafEntries) {
4745
4922
  const newChildren = [];
4746
4923
  for (const sp of entry.subpaths) {
4747
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
4924
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
4748
4925
  if (pathLengthPx < 1e-3) continue;
4749
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
4926
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
4750
4927
  newChildren.push(...buildSubpathNodes(entry.leaf, sp.subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx));
4751
4928
  }
4752
4929
  replacements.set(entry.leaf, wrapLeafAsGroup(entry.leaf, newChildren));
@@ -4853,22 +5030,8 @@ function computeAnimAttr(read, map) {
4853
5030
  };
4854
5031
  }
4855
5032
  function applyAttr(node, attrName, attr) {
4856
- var _a, _b;
4857
5033
  if (!attr) return;
4858
- if (attr.kind === "static" /* Static */) {
4859
- node[attrName] = attr.value;
4860
- return;
4861
- }
4862
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
4863
- const animate = __spreadValues({}, prevAnimate || {});
4864
- const block = { keyframes: attr.keyframes };
4865
- if (attr.loop !== void 0) block.loop = attr.loop;
4866
- animate[attrName] = block;
4867
- node.animate = animate;
4868
- const firstKf = attr.keyframes[0];
4869
- if (firstKf && ((_a = firstKf.value) != null ? _a : firstKf.v) !== void 0) {
4870
- node[attrName] = (_b = firstKf.value) != null ? _b : firstKf.v;
4871
- }
5034
+ writeAnimatableChannel(node, attrName, attr);
4872
5035
  }
4873
5036
  var OPACITY_STEP_MS = 10;
4874
5037
  function computeOpacityFromRange(rangeRead) {
@@ -5052,9 +5215,9 @@ function applyPlayerEffects(root) {
5052
5215
  nextId: 0,
5053
5216
  contentRefInnerIds: /* @__PURE__ */ new Map(),
5054
5217
  maskAncestorChains: /* @__PURE__ */ new Map(),
5055
- // Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
5056
- // webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5057
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
5218
+ // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
5219
+ // waapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5220
+ engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi,
5058
5221
  glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
5059
5222
  };
5060
5223
  const working = clone(root);
@@ -5072,8 +5235,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5072
5235
  const originalId = typeof node.id === "string" ? node.id : void 0;
5073
5236
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
5074
5237
  if (!fx && !innerIdForContentRef) return node;
5075
- const { transformation, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5076
- const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
5238
+ const { transformBy, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5077
5239
  if (fx) delete node.effects;
5078
5240
  let n = node;
5079
5241
  let consumedByGlyphs = false;
@@ -5093,15 +5255,15 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5093
5255
  if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
5094
5256
  n = applyFillGradientEffect(n, fillGradient, ctx);
5095
5257
  n = applyStrokeGradientEffect(n, strokeGradient, ctx);
5096
- n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
5258
+ n = applyTrimPathEffect(n, trimPath, ctx);
5097
5259
  n = applyRepeaterEffect(n, repeater, ctx);
5098
- n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
5260
+ n = applyMaskedByEffect(n, maskedBy, transformBy, ctx);
5099
5261
  n = applyClipPathEffect(n, clipPath, ctx);
5100
5262
  if (innerIdForContentRef) {
5101
5263
  applyRefHref(n, cloneFx, ctx);
5102
- n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
5264
+ n = splitForContentRef(n, transformBy, originalId, innerIdForContentRef, ctx);
5103
5265
  } else {
5104
- n = applyRefAndTransformationEffect(n, cloneFx, transformation, ctx);
5266
+ n = applyRefAndTransformationEffect(n, cloneFx, transformBy, ctx);
5105
5267
  }
5106
5268
  if (cloneFx == null ? void 0 : cloneFx.retime) node.effects = { clone: { retime: cloneFx.retime } };
5107
5269
  if (originalId) ctx.idMap.set(originalId, n);
@@ -5112,13 +5274,144 @@ function applyPlayerEffects_retime(node, ctx) {
5112
5274
  return node;
5113
5275
  }
5114
5276
 
5277
+ // src/PxOffsetPathMaterialiser.ts
5278
+ var kfTime = (kf) => {
5279
+ var _a, _b;
5280
+ return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
5281
+ };
5282
+ var kfValue = (kf) => {
5283
+ var _a;
5284
+ return (_a = kf.v) != null ? _a : kf.value;
5285
+ };
5286
+ var kfEasing = (kf) => {
5287
+ var _a;
5288
+ return (_a = kf.e) != null ? _a : kf.easing;
5289
+ };
5290
+ var kfTangentIn = (kf) => {
5291
+ var _a;
5292
+ return (_a = kf.tangentIn) != null ? _a : kf.ti;
5293
+ };
5294
+ var kfTangentOut = (kf) => {
5295
+ var _a;
5296
+ return (_a = kf.tangentOut) != null ? _a : kf.to;
5297
+ };
5298
+ function cubicAt(p0, c1, c2, p1, t) {
5299
+ const u = 1 - t;
5300
+ const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
5301
+ return [
5302
+ a * p0[0] + b * c1[0] + c * c2[0] + d * p1[0],
5303
+ a * p0[1] + b * c1[1] + c * c2[1] + d * p1[1]
5304
+ ];
5305
+ }
5306
+ function cubicLength(p0, c1, c2, p1, steps = 64) {
5307
+ let len = 0;
5308
+ let prev = p0;
5309
+ for (let i = 1; i <= steps; i++) {
5310
+ const pt = cubicAt(p0, c1, c2, p1, i / steps);
5311
+ len += Math.hypot(pt[0] - prev[0], pt[1] - prev[1]);
5312
+ prev = pt;
5313
+ }
5314
+ return len;
5315
+ }
5316
+ var fmt2 = (n) => {
5317
+ const r = Math.round(n * 1e4) / 1e4;
5318
+ return Object.is(r, -0) ? "0" : String(r);
5319
+ };
5320
+ function buildOffsetPath(propAnim) {
5321
+ var _a, _b, _c, _d;
5322
+ if (propAnim.alongPathMode !== "offsetPath") return void 0;
5323
+ const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
5324
+ if (!kfs || kfs.length < 2) return void 0;
5325
+ const first = kfValue(kfs[0]);
5326
+ const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
5327
+ const points = [];
5328
+ for (const kf of kfs) {
5329
+ const v = kfValue(kf);
5330
+ const tr = v == null ? void 0 : v.translate;
5331
+ if (!tr || tr.length < 2) return void 0;
5332
+ const parts = Object.keys(v);
5333
+ if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5334
+ const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
5335
+ if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5336
+ points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5337
+ }
5338
+ if (!kfs.some((kf) => kfTangentIn(kf) || kfTangentOut(kf))) return void 0;
5339
+ let d = "M" + fmt2(points[0][0]) + "," + fmt2(points[0][1]);
5340
+ const segLens = [];
5341
+ for (let i = 0; i < points.length - 1; i++) {
5342
+ const p0 = points[i], p1 = points[i + 1];
5343
+ const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
5344
+ const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
5345
+ const c1 = [p0[0] + to[0], p0[1] + to[1]];
5346
+ const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
5347
+ d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
5348
+ segLens.push(cubicLength(p0, c1, c2, p1));
5349
+ }
5350
+ const total = segLens.reduce((a, b) => a + b, 0);
5351
+ if (!(total > 0)) return void 0;
5352
+ const distanceKfs = [];
5353
+ let cum = 0;
5354
+ for (let i = 0; i < kfs.length; i++) {
5355
+ if (i > 0) cum += segLens[i - 1];
5356
+ const out = { t: kfTime(kfs[i]), v: cum / total };
5357
+ const e = kfEasing(kfs[i]);
5358
+ if (e !== void 0) out.e = e;
5359
+ distanceKfs.push(out);
5360
+ }
5361
+ return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
5362
+ }
5363
+ function materialiseOffsetPathsInTree(root) {
5364
+ const walk = (node) => {
5365
+ var _a;
5366
+ let out = node;
5367
+ const anim = node.animate;
5368
+ const transform = anim == null ? void 0 : anim["transform"];
5369
+ if (transform) {
5370
+ const built = buildOffsetPath(transform);
5371
+ if (built) {
5372
+ const newAnimate = __spreadValues({}, anim);
5373
+ delete newAnimate["transform"];
5374
+ const distance = { keyframes: built.distanceKfs };
5375
+ if (transform.loop !== void 0) distance.loop = transform.loop;
5376
+ newAnimate["offsetDistance"] = distance;
5377
+ const staticTr = node.transform;
5378
+ let newTransform = staticTr;
5379
+ if (staticTr && typeof staticTr === "object") {
5380
+ const t = __spreadValues({}, staticTr);
5381
+ delete t["translate"];
5382
+ delete t["origin"];
5383
+ newTransform = Object.keys(t).length ? t : void 0;
5384
+ }
5385
+ out = __spreadProps(__spreadValues({}, node), {
5386
+ animate: newAnimate,
5387
+ style: __spreadProps(__spreadValues({}, node.style), {
5388
+ offsetPath: "path('" + built.pathStr + "')",
5389
+ offsetAnchor: fmt2(built.anchor[0]) + "px " + fmt2(built.anchor[1]) + "px",
5390
+ offsetRotate: built.autoOrient ? "auto" : "0deg",
5391
+ offsetDistance: "0%"
5392
+ })
5393
+ });
5394
+ if (newTransform !== void 0) out.transform = newTransform;
5395
+ else delete out.transform;
5396
+ }
5397
+ }
5398
+ if ((_a = out.children) == null ? void 0 : _a.length) {
5399
+ const children = out.children.map(walk);
5400
+ if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
5401
+ }
5402
+ return out;
5403
+ };
5404
+ return walk(root);
5405
+ }
5406
+
5115
5407
  // src/PxAnimatorMaterialiseAll.ts
5116
5408
  function materialiseAllInTree(doc, engine, opts) {
5117
5409
  var _a, _b;
5118
5410
  let root = applyPlayerEffects(doc).root;
5411
+ root = materialiseOffsetPathsInTree(root);
5119
5412
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5120
5413
  root = materialiseInternalLoopsInTree(root, duration);
5121
- if (engine === PxAnimatorEngine.webapi) {
5414
+ if (engine === PxAnimatorEngine.waapi) {
5122
5415
  root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5123
5416
  root = materialiseAnimatedUseInstances(root);
5124
5417
  root = pruneUnreferencedDefs(root);
@@ -5507,6 +5800,7 @@ function evalTransformValue(v, t) {
5507
5800
  if (typeof v === "string") return parseTransformString(v);
5508
5801
  if (v.keyframes) return partsToMatrix(interpParts(v.keyframes, t));
5509
5802
  if (v.value) return partsToMatrix(v.value);
5803
+ if (typeof v === "object" && !Array.isArray(v)) return partsToMatrix(v);
5510
5804
  return IDENTITY;
5511
5805
  }
5512
5806
  function nodeMatrix(node, t) {
@@ -5646,6 +5940,8 @@ export {
5646
5940
  DEFAULT_DURATION_MS,
5647
5941
  DISALLOWED_SVG_TAGS_LOWER,
5648
5942
  INTERNAL_ATTRS,
5943
+ LOOP_JUMP_SHIFT_MS,
5944
+ PCT_BASED_ATTR_NAMES,
5649
5945
  PX_ANIM_ATTR_NAME,
5650
5946
  PX_ANIM_SRC_ATTR_NAME,
5651
5947
  PX_TRANSFORM_PART_KEYS,
@@ -5663,12 +5959,13 @@ export {
5663
5959
  PxEffectsSchema,
5664
5960
  PxElementAnimationSchema,
5665
5961
  PxFillGradientEffectSchema,
5666
- PxGradientGeometryAnimationSchema,
5667
5962
  PxGradientSpreadMethod,
5668
5963
  PxGradientStopSchema,
5669
5964
  PxGradientType,
5670
5965
  PxGradientUnits,
5671
5966
  PxKeyframeSchema,
5967
+ PxKeyframeValueSchema,
5968
+ PxLoopExtend,
5672
5969
  PxLoopSchema,
5673
5970
  PxMaskedByEffectSchema,
5674
5971
  PxNodeBase,
@@ -5680,11 +5977,12 @@ export {
5680
5977
  PxSvgNodeExtra,
5681
5978
  PxTextEffectSchema,
5682
5979
  PxTextPathEffectSchema,
5980
+ PxTransformByEffectSchema,
5683
5981
  PxTransformPartsSchema,
5684
5982
  PxTransformValueSchema,
5685
- PxTransformationEffectSchema,
5686
5983
  PxTriggerSchema,
5687
5984
  PxTrimPathEffectSchema,
5985
+ PxTrimSubPaths,
5688
5986
  STYLE_ATTR_NAMES,
5689
5987
  TEXT_ATTR,
5690
5988
  TEXT_CONTENT_ATTR,