@pixodesk/svg-animator-web 1.0.34 → 1.0.35

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.
@@ -55,7 +55,7 @@ var PixodeskAnimator = (() => {
55
55
  setupAnimationTriggers: () => setupAnimationTriggers
56
56
  });
57
57
 
58
- // ../svg-animator-core/src/PxAnimatorUtil.ts
58
+ // ../svg-animator-core/src/util/PxAnimatorUtil.ts
59
59
  function bezierToSvgPath(path, forceCurves = false) {
60
60
  var _a, _b, _c, _d;
61
61
  const v = path.v;
@@ -478,23 +478,563 @@ var PixodeskAnimator = (() => {
478
478
  return cubicBezier(flipped);
479
479
  }
480
480
 
481
- // ../svg-animator-core/src/PxAnimatorConstants.ts
482
- var PxAnimatorMode = {
481
+ // ../svg-animator-core/src/schema/PxSchema.ts
482
+ var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
483
+ function pathStr(path) {
484
+ if (!path.length) return ".";
485
+ let result = "";
486
+ for (const seg of path) {
487
+ if (seg.startsWith("[")) result += seg;
488
+ else result += (result ? "." : "") + seg;
489
+ }
490
+ return result;
491
+ }
492
+ var Base = class {
493
+ _canSanitize(raw) {
494
+ return this.isValid(raw);
495
+ }
496
+ optional() {
497
+ return new Optional(this);
498
+ }
499
+ };
500
+ var Optional = class extends Base {
501
+ constructor(inner) {
502
+ super();
503
+ this.inner = inner;
504
+ this._default = void 0;
505
+ }
506
+ sanitize(raw) {
507
+ if (raw === void 0 || raw === null) return void 0;
508
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
509
+ }
510
+ isValid(raw, ctx, path) {
511
+ if (raw === void 0 || raw === null) return true;
512
+ return this.inner.isValid(raw, ctx, path);
513
+ }
514
+ _canSanitize(raw) {
515
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
516
+ }
517
+ };
518
+ var Str = class extends Base {
519
+ constructor(_default = "") {
520
+ super();
521
+ this._default = _default;
522
+ }
523
+ sanitize(raw) {
524
+ return typeof raw === "string" ? raw : this._default;
525
+ }
526
+ isValid(raw, ctx, path) {
527
+ if (typeof raw === "string") return true;
528
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
529
+ return false;
530
+ }
531
+ };
532
+ var Num = class extends Base {
533
+ constructor(_default = 0) {
534
+ super();
535
+ this._default = _default;
536
+ }
537
+ sanitize(raw) {
538
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
539
+ }
540
+ isValid(raw, ctx, path) {
541
+ if (typeof raw === "number" && isFinite(raw)) return true;
542
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
543
+ return false;
544
+ }
545
+ };
546
+ var Bool = class extends Base {
547
+ constructor(_default = false) {
548
+ super();
549
+ this._default = _default;
550
+ }
551
+ sanitize(raw) {
552
+ return typeof raw === "boolean" ? raw : this._default;
553
+ }
554
+ isValid(raw, ctx, path) {
555
+ if (typeof raw === "boolean") return true;
556
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
557
+ return false;
558
+ }
559
+ };
560
+ var Literal = class extends Base {
561
+ constructor(value) {
562
+ super();
563
+ this.value = value;
564
+ this._default = value;
565
+ }
566
+ sanitize(raw) {
567
+ return raw === this.value ? this.value : this._default;
568
+ }
569
+ isValid(raw, ctx, path) {
570
+ if (raw === this.value) return true;
571
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
572
+ return false;
573
+ }
574
+ };
575
+ var Enum = class extends Base {
576
+ constructor(values, defaultVal) {
577
+ super();
578
+ this.values = values;
579
+ this._default = defaultVal != null ? defaultVal : values[0];
580
+ }
581
+ sanitize(raw) {
582
+ return this.values.includes(raw) ? raw : this._default;
583
+ }
584
+ isValid(raw, ctx, path) {
585
+ if (this.values.includes(raw)) return true;
586
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected one of " + this.values.map((v) => JSON.stringify(v)).join(" | ") + ", got " + JSON.stringify(raw));
587
+ return false;
588
+ }
589
+ };
590
+ var Union = class extends Base {
591
+ constructor(schemas, defaultVal) {
592
+ super();
593
+ this.schemas = schemas;
594
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Union from Tuple. */
595
+ this._kind = "union";
596
+ this._default = defaultVal != null ? defaultVal : schemas[0]._default;
597
+ }
598
+ sanitize(raw) {
599
+ for (const s of this.schemas) {
600
+ if (s.isValid(raw)) return s.sanitize(raw);
601
+ }
602
+ return this._default;
603
+ }
604
+ isValid(raw, ctx, path) {
605
+ var _a;
606
+ const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
607
+ if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
608
+ 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));
609
+ return false;
610
+ }
611
+ _canSanitize(raw) {
612
+ return this.schemas.some((s) => s._canSanitize(raw));
613
+ }
614
+ };
615
+ var DiscriminatedUnion = class extends Base {
616
+ constructor(_key, _schemas, defaultVal) {
617
+ var _a;
618
+ super();
619
+ this._key = _key;
620
+ this._schemas = _schemas;
621
+ /** Structural tag read by {@link describeSchema}. */
622
+ this._kind = "discriminatedUnion";
623
+ this._default = defaultVal != null ? defaultVal : _schemas[0]._default;
624
+ this._map = /* @__PURE__ */ new Map();
625
+ for (const s of _schemas) {
626
+ const keySchema = s._shape[_key];
627
+ if (!keySchema) continue;
628
+ const literal = (_a = keySchema.inner) != null ? _a : keySchema;
629
+ this._map.set(literal._default, s);
630
+ if (keySchema.inner) this._absentMember = s;
631
+ }
632
+ }
633
+ _findSchema(raw) {
634
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
635
+ const val = raw[this._key];
636
+ if (val === void 0 || val === null) return this._absentMember;
637
+ return this._map.get(val);
638
+ }
639
+ sanitize(raw) {
640
+ var _a;
641
+ return ((_a = this._findSchema(raw)) != null ? _a : this._schemas[0]).sanitize(raw);
642
+ }
643
+ isValid(raw, ctx, path) {
644
+ const schema = this._findSchema(raw);
645
+ if (!schema) {
646
+ const val = raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw[this._key] : void 0;
647
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no discriminated union member matched " + this._key + "=" + JSON.stringify(val));
648
+ return false;
649
+ }
650
+ return schema.isValid(raw, ctx, path);
651
+ }
652
+ _canSanitize(raw) {
653
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return false;
654
+ const schema = this._findSchema(raw);
655
+ return schema ? schema._canSanitize(raw) : this._schemas[0]._canSanitize(raw);
656
+ }
657
+ };
658
+ var Obj = class extends Base {
659
+ constructor(_shape) {
660
+ super();
661
+ this._shape = _shape;
662
+ const d = {};
663
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
664
+ this._default = d;
665
+ }
666
+ sanitize(raw) {
667
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
668
+ const out = {};
669
+ for (const key of Object.keys(this._shape)) {
670
+ const v = this._shape[key].sanitize(src[key]);
671
+ if (v !== void 0) out[key] = v;
672
+ }
673
+ return out;
674
+ }
675
+ isValid(raw, ctx, path) {
676
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
677
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
678
+ return false;
679
+ }
680
+ const obj = raw;
681
+ const p = path != null ? path : [];
682
+ let ok = true;
683
+ for (const key of Object.keys(this._shape)) {
684
+ p.push(key);
685
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
686
+ p.pop();
687
+ }
688
+ if (ctx == null ? void 0 : ctx.strict) {
689
+ for (const key of Object.keys(obj)) {
690
+ if (key in this._shape) continue;
691
+ if (obj[key] === void 0) continue;
692
+ p.push(key);
693
+ ctx.errors.push(pathStr(p) + ": " + PX_UNKNOWN_KEY_ERROR);
694
+ p.pop();
695
+ ok = false;
696
+ }
697
+ }
698
+ return ok;
699
+ }
700
+ _canSanitize(raw) {
701
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
702
+ }
703
+ };
704
+ var OpenObj = class extends Base {
705
+ constructor(_shape, _openSchema) {
706
+ super();
707
+ this._shape = _shape;
708
+ this._openSchema = _openSchema;
709
+ const d = {};
710
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
711
+ this._default = d;
712
+ }
713
+ sanitize(raw) {
714
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
715
+ const out = __spreadValues({}, src);
716
+ for (const key of Object.keys(this._shape)) {
717
+ const v = this._shape[key].sanitize(src[key]);
718
+ if (v !== void 0) out[key] = v;
719
+ }
720
+ if (this._openSchema) {
721
+ for (const key of Object.keys(src)) {
722
+ if (!(key in this._shape)) out[key] = this._openSchema.sanitize(src[key]);
723
+ }
724
+ }
725
+ return out;
726
+ }
727
+ isValid(raw, ctx, path) {
728
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
729
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
730
+ return false;
731
+ }
732
+ const obj = raw;
733
+ const p = path != null ? path : [];
734
+ let ok = true;
735
+ for (const key of Object.keys(this._shape)) {
736
+ p.push(key);
737
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
738
+ p.pop();
739
+ }
740
+ if (this._openSchema) {
741
+ for (const key of Object.keys(obj)) {
742
+ if (key in this._shape) continue;
743
+ p.push(key);
744
+ if (!this._openSchema.isValid(obj[key], ctx, p)) ok = false;
745
+ p.pop();
746
+ }
747
+ }
748
+ return ok;
749
+ }
750
+ _canSanitize(raw) {
751
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
752
+ }
753
+ };
754
+ var Arr = class extends Base {
755
+ constructor(item) {
756
+ super();
757
+ this.item = item;
758
+ this._default = [];
759
+ }
760
+ sanitize(raw) {
761
+ if (!Array.isArray(raw)) return [];
762
+ const out = [];
763
+ for (const el of raw) {
764
+ if (this.item._canSanitize(el)) out.push(this.item.sanitize(el));
765
+ }
766
+ return out;
767
+ }
768
+ isValid(raw, ctx, path) {
769
+ if (!Array.isArray(raw)) {
770
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected array, got " + typeof raw);
771
+ return false;
772
+ }
773
+ const p = path != null ? path : [];
774
+ let ok = true;
775
+ for (let i = 0; i < raw.length; i++) {
776
+ p.push("[" + i + "]");
777
+ if (!this.item.isValid(raw[i], ctx, p)) ok = false;
778
+ p.pop();
779
+ }
780
+ return ok;
781
+ }
782
+ _canSanitize(raw) {
783
+ return Array.isArray(raw);
784
+ }
785
+ };
786
+ var Rec = class extends Base {
787
+ constructor(value) {
788
+ super();
789
+ this.value = value;
790
+ /** Structural tag read by {@link describeSchema}. */
791
+ this._kind = "record";
792
+ this._default = {};
793
+ }
794
+ sanitize(raw) {
795
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
796
+ const out = {};
797
+ for (const [k, v] of Object.entries(raw)) {
798
+ if (this.value._canSanitize(v)) out[k] = this.value.sanitize(v);
799
+ }
800
+ return out;
801
+ }
802
+ isValid(raw, ctx, path) {
803
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
804
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object/record, got " + (Array.isArray(raw) ? "array" : typeof raw));
805
+ return false;
806
+ }
807
+ const p = path != null ? path : [];
808
+ let ok = true;
809
+ for (const [k, v] of Object.entries(raw)) {
810
+ p.push(k);
811
+ if (!this.value.isValid(v, ctx, p)) ok = false;
812
+ p.pop();
813
+ }
814
+ return ok;
815
+ }
816
+ _canSanitize(raw) {
817
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
818
+ }
819
+ };
820
+ var Any = class extends Base {
821
+ constructor() {
822
+ super(...arguments);
823
+ this._default = void 0;
824
+ }
825
+ sanitize(raw) {
826
+ return raw;
827
+ }
828
+ isValid(_raw, _ctx, _path) {
829
+ return true;
830
+ }
831
+ _canSanitize(_raw) {
832
+ return true;
833
+ }
834
+ };
835
+ var Defined = class extends Base {
836
+ constructor() {
837
+ super(...arguments);
838
+ this._default = void 0;
839
+ }
840
+ sanitize(raw) {
841
+ return raw;
842
+ }
843
+ isValid(raw, ctx, path) {
844
+ if (raw !== void 0) return true;
845
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": required value is missing");
846
+ return false;
847
+ }
848
+ _canSanitize(raw) {
849
+ return raw !== void 0;
850
+ }
851
+ };
852
+ var Lazy = class extends Base {
853
+ constructor(fn, _default) {
854
+ super();
855
+ this.fn = fn;
856
+ this._default = _default;
857
+ this.resolved = null;
858
+ }
859
+ get schema() {
860
+ var _a;
861
+ return (_a = this.resolved) != null ? _a : this.resolved = this.fn();
862
+ }
863
+ sanitize(raw) {
864
+ return this.schema.sanitize(raw);
865
+ }
866
+ isValid(raw, ctx, path) {
867
+ return this.schema.isValid(raw, ctx, path);
868
+ }
869
+ _canSanitize(raw) {
870
+ return this.schema._canSanitize(raw);
871
+ }
872
+ };
873
+ var Tuple = class extends Base {
874
+ constructor(schemas) {
875
+ super();
876
+ this.schemas = schemas;
877
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Tuple from Union. */
878
+ this._kind = "tuple";
879
+ this._default = schemas.map((s) => s._default);
880
+ }
881
+ sanitize(raw) {
882
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) return this._default;
883
+ return this.schemas.map((s, i) => s.sanitize(raw[i]));
884
+ }
885
+ isValid(raw, ctx, path) {
886
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) {
887
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected tuple of length " + this.schemas.length + ", got " + (Array.isArray(raw) ? "array[" + raw.length + "]" : typeof raw));
888
+ return false;
889
+ }
890
+ const p = path != null ? path : [];
891
+ let ok = true;
892
+ for (let i = 0; i < this.schemas.length; i++) {
893
+ p.push("[" + i + "]");
894
+ if (!this.schemas[i].isValid(raw[i], ctx, p)) ok = false;
895
+ p.pop();
896
+ }
897
+ return ok;
898
+ }
899
+ // Require exact length so wrong-length arrays are dropped rather than repaired to default.
900
+ _canSanitize(raw) {
901
+ return Array.isArray(raw) && raw.length === this.schemas.length;
902
+ }
903
+ };
904
+ function implementsInterface() {
905
+ return (schema) => schema;
906
+ }
907
+ var px = {
908
+ /** Matches a string. Default: '' or provided value. */
909
+ string: (defaultVal = "") => new Str(defaultVal),
910
+ /** Matches a finite number. Default: 0 or provided value. */
911
+ number: (defaultVal = 0) => new Num(defaultVal),
912
+ /** Matches a boolean. Default: false or provided value. */
913
+ boolean: (defaultVal = false) => new Bool(defaultVal),
914
+ /** Matches one exact primitive value; its default is the value itself. */
915
+ literal: (value) => new Literal(value),
916
+ /** Matches one of a fixed set of string/number values. Default: first value. */
917
+ enum: (values, defaultVal) => new Enum(values, defaultVal),
918
+ /**
919
+ * Returns the first schema whose isValid passes.
920
+ * TypeScript infers the union of all member types automatically.
921
+ */
922
+ union: (schemas, defaultVal) => new Union(schemas, defaultVal),
923
+ /**
924
+ * Discriminated union — reads `raw[key]`, finds the member schema whose
925
+ * literal at `key` matches, then delegates sanitize/isValid to that member.
926
+ * Each member must be an object schema with a `px.literal(...)` at `key`.
927
+ * TypeScript infers the union of all member types automatically.
928
+ */
929
+ discriminatedUnion: (key, schemas) => new DiscriminatedUnion(key, schemas),
930
+ /** Typed object — unknown keys are stripped. Required fields fall back to their default. */
931
+ object: (shape) => new Obj(shape),
932
+ /**
933
+ * Open object — validates known keys; passes unknown keys through as-is,
934
+ * or validates/sanitizes them against `openSchema` when provided.
935
+ */
936
+ openObject: (shape, openSchema) => new OpenObj(shape, openSchema),
937
+ /**
938
+ * Creates a new closed object schema by merging a base schema's shape with additional fields.
939
+ * The base can be the result of px.object() or px.openObject() — anything with a _shape property.
940
+ *
941
+ * @example
942
+ * const PxSvgNodeSchema = px.extendedObject(PxNodeBase, { width: px.number().optional() });
943
+ */
944
+ extendedObject: (base, extra) => new Obj(__spreadValues(__spreadValues({}, base._shape), extra)),
945
+ /** Array whose unrecoverable items are filtered out. Default: []. */
946
+ array: (item) => new Arr(item),
947
+ /** String-keyed record whose unrecoverable values are dropped. Default: {}. */
948
+ record: (value) => new Rec(value),
949
+ /** Passes anything through unchanged — always valid. */
950
+ any: () => new Any(),
951
+ /** Anything EXCEPT `undefined` — an open type whose presence is required (V6). */
952
+ defined: () => new Defined(),
953
+ /** Fixed-length tuple — validates element count and each position individually. */
954
+ tuple: (schemas) => new Tuple(schemas),
955
+ /** Defers schema creation — required for recursive types. Must supply a default value. */
956
+ lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
957
+ };
958
+
959
+ // ../svg-animator-core/src/format/PxAnimatorConstants.ts
960
+ var PxTimelineEngine = {
961
+ native: "native",
962
+ js: "js"
963
+ };
964
+ var PxTimelineEngineExtra = __spreadProps(__spreadValues({}, PxTimelineEngine), {
965
+ auto: "auto"
966
+ });
967
+ var PxLoopRepeatAt = {
968
+ /** Segment from the START; the repetition runs BEFORE the first keyframe
969
+ * (intro loops that play until the main timeline begins). */
970
+ start: "start",
971
+ /** DEFAULT — segment from the END; the repetition runs AFTER the last keyframe
972
+ * (idle/outro loops that continue once the main timeline has finished). */
973
+ end: "end"
974
+ };
975
+ var PxLoopDirection = {
976
+ /** DEFAULT — cycle: every repetition replays the segment the same way round. */
977
+ normal: "normal",
978
+ /** Ping-pong: repetitions alternate forward / backward. */
979
+ alternate: "alternate"
980
+ };
981
+ var PxMaskType = {
982
+ luminance: "luminance",
983
+ alpha: "alpha"
984
+ };
985
+ var PxUnits = {
986
+ userSpaceOnUse: "userSpaceOnUse",
987
+ objectBoundingBox: "objectBoundingBox"
988
+ };
989
+ var PxCloneWithout = {
990
+ translate: "translate"
991
+ // transform: 'transform', // future: drop rotate/scale too (content only)
992
+ };
993
+ var PxPathOverflow = {
994
+ clip: "clip",
995
+ extend: "extend"
996
+ };
997
+ var PxLengthAdjust = {
998
+ spacing: "spacing",
999
+ spacingAndGlyphs: "spacingAndGlyphs"
1000
+ };
1001
+ var PxTextPathMethod = {
1002
+ align: "align",
1003
+ stretch: "stretch"
1004
+ };
1005
+ var PxTextPathSpacing = {
483
1006
  auto: "auto",
484
- waapi: "waapi",
485
- frames: "frames"
1007
+ exact: "exact"
1008
+ };
1009
+ var PxStrokeTrimSubPaths = {
1010
+ separate: "separate",
1011
+ combined: "combined"
1012
+ };
1013
+ var TRANSFORM_ATTR = "transform";
1014
+ var TRANSFORM_PART = {
1015
+ translate: "translate",
1016
+ rotate: "rotate",
1017
+ scale: "scale",
1018
+ origin: "origin"
1019
+ };
1020
+ var PX_TRANSFORM_PART_KEYS = [
1021
+ TRANSFORM_PART.translate,
1022
+ TRANSFORM_PART.rotate,
1023
+ TRANSFORM_PART.scale,
1024
+ TRANSFORM_PART.origin
1025
+ ];
1026
+ var PxGradientUnits = {
1027
+ userSpaceOnUse: "userSpaceOnUse",
1028
+ objectBoundingBox: "objectBoundingBox"
486
1029
  };
487
- var PxAnimatorEngine = {
488
- waapi: PxAnimatorMode.waapi,
489
- frames: PxAnimatorMode.frames
1030
+ var PxGradientSpreadMethod = {
1031
+ pad: "pad",
1032
+ reflect: "reflect",
1033
+ repeat: "repeat"
490
1034
  };
491
- var PxLoopExtend = {
492
- /** Segment from the START; the animation is extended BEFORE the first keyframe
493
- * (intro loops that run before the main timeline begins). */
494
- before: "before",
495
- /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
496
- * loops that continue once the main timeline has finished). */
497
- after: "after"
1035
+ var PxGradientType = {
1036
+ linear: "linear",
1037
+ radial: "radial"
498
1038
  };
499
1039
  function getAnimatorConfig(doc) {
500
1040
  var _a;
@@ -508,13 +1048,14 @@ var PixodeskAnimator = (() => {
508
1048
  const memoised = flattenMemo.get(cfg);
509
1049
  if (memoised) return memoised;
510
1050
  const _a = cfg, { timeline: _dropped } = _a, flat = __objRest(_a, ["timeline"]);
1051
+ if (timeline.engine !== void 0) flat.engine = timeline.engine;
1052
+ if (timeline.frameRate !== void 0) flat.frameRate = timeline.frameRate;
511
1053
  if (timeline.type === "scroll" || timeline.type === "view") {
512
1054
  flat.timelineSource = "scroll";
513
1055
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
514
1056
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
515
1057
  const scroll = __spreadValues({}, flat.scroll || {});
516
1058
  scroll.kind = timeline.type;
517
- if (timeline.engine !== void 0) scroll.driver = timeline.engine;
518
1059
  if (timeline.axis !== void 0) scroll.axis = timeline.axis;
519
1060
  if (timeline.source !== void 0) scroll.source = timeline.source;
520
1061
  if (timeline.subject !== void 0) scroll.subject = timeline.subject;
@@ -532,14 +1073,14 @@ var PixodeskAnimator = (() => {
532
1073
  } else {
533
1074
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
534
1075
  if (timeline.trigger !== void 0) {
535
- const _b = timeline.trigger, { onFinish } = _b, restTrigger = __objRest(_b, ["onFinish"]);
1076
+ const _b = timeline.trigger, { finishAction } = _b, restTrigger = __objRest(_b, ["finishAction"]);
536
1077
  if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
537
- if (onFinish !== void 0) flat.resetOnFinish = onFinish === "reset";
1078
+ if (finishAction !== void 0) flat.resetOnFinish = finishAction === "reset";
538
1079
  }
539
1080
  if (timeline.delay !== void 0) flat.delay = timeline.delay;
540
1081
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
541
1082
  if (timeline.direction !== void 0) flat.direction = timeline.direction;
542
- if (timeline.fill !== void 0) flat.fill = timeline.fill;
1083
+ if (timeline.fillMode !== void 0) flat.fill = timeline.fillMode;
543
1084
  }
544
1085
  flattenMemo.set(cfg, flat);
545
1086
  return flat;
@@ -557,10 +1098,376 @@ var PixodeskAnimator = (() => {
557
1098
  return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
558
1099
  }
559
1100
 
560
- // ../svg-animator-core/src/PxMotionPath.ts
561
- function getKfTranslate(kf) {
1101
+ // ../svg-animator-core/src/format/PxAnimatorTypes.ts
1102
+ var PxEasingOrRefSchema = px.union([
1103
+ px.string(),
1104
+ px.tuple([px.number(), px.number(), px.number(), px.number()])
1105
+ ]);
1106
+ var PxKeyframeValueSchema = implementsInterface()(px.union([
1107
+ px.string(),
1108
+ // e.g. for colors
1109
+ px.number(),
1110
+ px.array(px.number()),
1111
+ // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1112
+ // all-optional transform-parts record. In default (non-strict) mode that record accepts
1113
+ // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1114
+ // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1115
+ // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1116
+ // order-independent (`some()`); only sanitize routing depends on this order.
1117
+ px.object({ path: px.string() }),
1118
+ px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1119
+ // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1120
+ px.lazy(() => px.array(PxGradientStopSchema), []),
1121
+ px.lazy(() => PxTransformPartsSchema, {})
1122
+ ]));
1123
+ var PxKeyframeSchema = implementsInterface()(px.object({
1124
+ time: px.number().optional(),
1125
+ value: PxKeyframeValueSchema.optional(),
1126
+ easing: PxEasingOrRefSchema.optional(),
1127
+ tangentOut: px.tuple([px.number(), px.number()]).optional(),
1128
+ tangentIn: px.tuple([px.number(), px.number()]).optional()
1129
+ // (`selected` — editor timeline-selection UI state — was REMOVED from the wire
1130
+ // (review §1.3): editor data lives under `meta`. The editor still carries it on
1131
+ // its internal COPY-PASTE payload, which never validates against this schema.)
1132
+ }));
1133
+ var anyKf = (kf) => kf;
1134
+ var kfTime = (kf) => {
1135
+ var _a, _b;
1136
+ return (_b = (_a = anyKf(kf).time) != null ? _a : anyKf(kf).t) != null ? _b : 0;
1137
+ };
1138
+ var kfValue = (kf) => {
562
1139
  var _a;
563
- const v = (_a = kf.value) != null ? _a : kf.v;
1140
+ return (_a = anyKf(kf).value) != null ? _a : anyKf(kf).v;
1141
+ };
1142
+ var kfEasing = (kf) => {
1143
+ var _a;
1144
+ return (_a = anyKf(kf).easing) != null ? _a : anyKf(kf).e;
1145
+ };
1146
+ var kfTangentIn = (kf) => anyKf(kf).tangentIn;
1147
+ var kfTangentOut = (kf) => anyKf(kf).tangentOut;
1148
+ var PxLoopSchema = implementsInterface()(px.object({
1149
+ segmentCount: px.number().optional(),
1150
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1151
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1152
+ }));
1153
+ var PxPropertyAnimationSchema = implementsInterface()(px.object({
1154
+ value: PxKeyframeValueSchema.optional(),
1155
+ keyframes: px.array(PxKeyframeSchema).optional(),
1156
+ loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1157
+ autoOrient: px.boolean().optional(),
1158
+ alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
1159
+ }));
1160
+ var PxTransformPartsSchema = implementsInterface()(px.object({
1161
+ translate: px.tuple([px.number(), px.number()]).optional(),
1162
+ rotate: px.number().optional(),
1163
+ skew: px.number().optional(),
1164
+ scale: px.tuple([px.number(), px.number()]).optional(),
1165
+ origin: px.tuple([px.number(), px.number()]).optional()
1166
+ }));
1167
+ var PxTransformValueSchema = px.union([
1168
+ px.string(),
1169
+ PxTransformPartsSchema,
1170
+ px.object({ value: PxTransformPartsSchema }),
1171
+ PxPropertyAnimationSchema
1172
+ ]);
1173
+ var PxAnimationDefinitionSchema = implementsInterface()(
1174
+ px.record(PxPropertyAnimationSchema)
1175
+ );
1176
+ var PxElementAnimationSchema = implementsInterface()(px.union([
1177
+ px.string(),
1178
+ px.array(px.union([px.string(), PxAnimationDefinitionSchema])),
1179
+ PxAnimationDefinitionSchema
1180
+ ]));
1181
+ var PxTriggerSchema = implementsInterface()(px.object({
1182
+ startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1183
+ outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1184
+ // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1185
+ // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1186
+ // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1187
+ finishAction: px.enum(["hold", "reset"]).optional(),
1188
+ scrollIntoViewThreshold: px.number().optional()
1189
+ }));
1190
+ var PxGlyphSchema = implementsInterface()(px.object({
1191
+ width: px.number(),
1192
+ d: px.string()
1193
+ }));
1194
+ var PxGlyphFontSchema = implementsInterface()(px.object({
1195
+ fontFamily: px.string(),
1196
+ fontStyle: px.string(),
1197
+ ascent: px.number(),
1198
+ unitsPerEm: px.number(),
1199
+ glyphs: px.record(PxGlyphSchema)
1200
+ }));
1201
+ var PxDefsSchema = implementsInterface()(px.object({
1202
+ easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1203
+ animations: px.record(PxAnimationDefinitionSchema).optional(),
1204
+ // Review §2.6: the schema now matches the declared type — a style preset is a flat
1205
+ // record of string|number attribute values, nothing nested.
1206
+ styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1207
+ fonts: px.record(PxGlyphFontSchema).optional()
1208
+ }));
1209
+ var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1210
+ var PxScrollRangePointSchema = implementsInterface()(px.object({
1211
+ phase: px.enum(PX_SCROLL_PHASES).optional(),
1212
+ fraction: px.number().optional()
1213
+ }));
1214
+ var PxScrollRangeSchema = px.object({
1215
+ start: PxScrollRangePointSchema.optional(),
1216
+ end: PxScrollRangePointSchema.optional()
1217
+ });
1218
+ var PxScrollSchema = implementsInterface()(px.object({
1219
+ kind: px.enum(["view", "scroll"]).optional(),
1220
+ axis: px.enum(["block", "inline", "x", "y"]).optional(),
1221
+ source: px.enum(["nearest", "root"]).optional(),
1222
+ // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1223
+ subject: px.string().optional(),
1224
+ smoothing: px.number().optional(),
1225
+ pin: px.boolean().optional(),
1226
+ pinAlign: px.enum(["top", "center", "bottom"]).optional(),
1227
+ pinTop: px.number().optional(),
1228
+ pinDistance: px.number().optional(),
1229
+ range: PxScrollRangeSchema.optional()
1230
+ }));
1231
+ var PxTimelinePinSchema = implementsInterface()(px.object({
1232
+ align: px.enum(["top", "center", "bottom"]).optional(),
1233
+ top: px.number().optional(),
1234
+ distance: px.number().optional()
1235
+ }));
1236
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
1237
+ var PxTimeTimelineSchema = implementsInterface()(px.object({
1238
+ type: px.literal("time").optional(),
1239
+ engine: PxTimelineEngineSchema,
1240
+ frameRate: px.number().optional(),
1241
+ // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1242
+ duration: px.number().optional(),
1243
+ trigger: PxTriggerSchema.optional(),
1244
+ delay: px.number().optional(),
1245
+ iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1246
+ // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1247
+ // — never `fill`, which is paint everywhere else in the format.
1248
+ fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1249
+ direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1250
+ }));
1251
+ var scrollishTimelineShape = {
1252
+ // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1253
+ // span the scroll range maps onto.
1254
+ duration: px.number().optional(),
1255
+ // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1256
+ // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1257
+ iterations: px.number().optional(),
1258
+ engine: PxTimelineEngineSchema,
1259
+ frameRate: px.number().optional(),
1260
+ axis: px.enum(["block", "inline", "x", "y"]).optional(),
1261
+ source: px.enum(["nearest", "root"]).optional(),
1262
+ subject: px.string().optional(),
1263
+ // 'parent' | 'scroller' | any CSS selector
1264
+ smoothing: px.number().optional(),
1265
+ // ms
1266
+ pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1267
+ range: PxScrollRangeSchema.optional()
1268
+ };
1269
+ var PxScrollTimelineSchema = implementsInterface()(
1270
+ px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape))
1271
+ );
1272
+ var PxViewTimelineSchema = implementsInterface()(
1273
+ px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape))
1274
+ );
1275
+ var PxTimelineSchema = px.discriminatedUnion("type", [
1276
+ PxTimeTimelineSchema,
1277
+ // first = the member an absent `type` selects
1278
+ PxScrollTimelineSchema,
1279
+ PxViewTimelineSchema
1280
+ ]);
1281
+ var PxAnimatorConfigSchema = implementsInterface()(px.object({
1282
+ // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1283
+ // at this level only on the runtime view, like the rest of the playback dynamics.)
1284
+ // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1285
+ timeline: PxTimelineSchema.optional(),
1286
+ definitions: PxDefsSchema.optional(),
1287
+ animateById: px.record(PxElementAnimationSchema).optional(),
1288
+ debugGlobalName: px.string().optional(),
1289
+ // Declared HERE because this is a closed object: an undeclared key would be stripped by
1290
+ // `sanitize` and flagged by strict validation on our own files.
1291
+ version: px.string().optional()
1292
+ }));
1293
+ var PxBindingSchema = implementsInterface()(px.object({
1294
+ id: px.string(),
1295
+ animate: PxElementAnimationSchema
1296
+ }));
1297
+ var PxAttrValueSchema = px.union([
1298
+ px.string(),
1299
+ px.number(),
1300
+ px.array(px.number()),
1301
+ // Structured static — `{value: …}` (read-accepted transitional spelling, S1).
1302
+ // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).
1303
+ px.object({ value: px.defined() }),
1304
+ // Bare transform parts record — the canonical static `transform` on the wire (T2).
1305
+ PxTransformPartsSchema
1306
+ ]);
1307
+ var PxAnimatableNumberSchema = px.union([
1308
+ px.number(),
1309
+ PxPropertyAnimationSchema,
1310
+ px.object({ value: px.number() })
1311
+ ]);
1312
+ var PxAnimatableVec2Schema = px.union([
1313
+ px.tuple([px.number(), px.number()]),
1314
+ PxPropertyAnimationSchema,
1315
+ px.object({ value: px.tuple([px.number(), px.number()]) })
1316
+ ]);
1317
+ var PxAnimatableStringSchema = px.union([
1318
+ px.string(),
1319
+ PxPropertyAnimationSchema,
1320
+ px.object({ value: px.string() })
1321
+ ]);
1322
+ var PxTransformByEffectSchema = implementsInterface()(px.object({
1323
+ translate: PxAnimatableVec2Schema.optional(),
1324
+ rotate: PxAnimatableNumberSchema.optional(),
1325
+ scale: PxAnimatableVec2Schema.optional(),
1326
+ skew: PxAnimatableNumberSchema.optional(),
1327
+ origin: PxAnimatableVec2Schema.optional()
1328
+ }));
1329
+ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1330
+ // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
1331
+ // once at expansion time and never sampled — plain number, no `keyframes`.
1332
+ copies: px.number().optional(),
1333
+ translate: PxAnimatableVec2Schema.optional(),
1334
+ rotate: PxAnimatableNumberSchema.optional(),
1335
+ skew: PxAnimatableNumberSchema.optional(),
1336
+ scale: PxAnimatableVec2Schema.optional(),
1337
+ origin: PxAnimatableVec2Schema.optional()
1338
+ }));
1339
+ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1340
+ source: px.string().optional(),
1341
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1342
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1343
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1344
+ x: px.number().optional(),
1345
+ y: px.number().optional(),
1346
+ width: px.number().optional(),
1347
+ height: px.number().optional()
1348
+ }));
1349
+ var PxClipPathEffectSchema = implementsInterface()(px.object({
1350
+ d: PxAnimatableStringSchema.optional()
1351
+ }));
1352
+ var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1353
+ offset: PxAnimatableNumberSchema.optional(),
1354
+ range: PxAnimatableVec2Schema.optional(),
1355
+ subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined]).optional()
1356
+ }));
1357
+ var PxRetimeEffectSchema = implementsInterface()(px.object({
1358
+ start: px.number().optional(),
1359
+ stretch: px.number().optional(),
1360
+ timeCrop: px.tuple([px.number(), px.number()]).optional()
1361
+ }));
1362
+ var PxCloneEffectSchema = implementsInterface()(px.object({
1363
+ // Subtractive on purpose: the `<use>` can only point at one wrapper layer of the
1364
+ // source, so the choices form a ladder — 'translate' now, maybe 'transform' later.
1365
+ without: px.enum([PxCloneWithout.translate]).optional(),
1366
+ source: px.string().optional(),
1367
+ retime: PxRetimeEffectSchema.optional()
1368
+ }));
1369
+ var PxGradientStopSchema = implementsInterface()(px.object({
1370
+ offset: px.number(),
1371
+ color: px.string()
1372
+ }));
1373
+ var PxAnimatableGradientStopsSchema = px.union([
1374
+ px.array(PxGradientStopSchema),
1375
+ px.object({ value: px.array(PxGradientStopSchema) }),
1376
+ PxPropertyAnimationSchema
1377
+ ]);
1378
+ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1379
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1380
+ type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1381
+ start: PxAnimatableVec2Schema.optional(),
1382
+ end: PxAnimatableVec2Schema.optional(),
1383
+ center: PxAnimatableVec2Schema.optional(),
1384
+ radius: PxAnimatableNumberSchema.optional(),
1385
+ focal: PxAnimatableVec2Schema.optional(),
1386
+ stops: PxAnimatableGradientStopsSchema.optional(),
1387
+ gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
1388
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1389
+ gradientTransform: px.string().optional()
1390
+ }));
1391
+ var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1392
+ var PxTextPathEffectSchema = implementsInterface()(px.object({
1393
+ pathData: px.string(),
1394
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1395
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1396
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
1397
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
1398
+ startOffset: PxAnimatableNumberSchema.optional(),
1399
+ textLength: PxAnimatableNumberSchema.optional()
1400
+ }));
1401
+ var PxTextEffectSchema = implementsInterface()(px.object({
1402
+ useGlyphs: px.boolean().optional()
1403
+ }));
1404
+ var PxEffectsSchema = implementsInterface()(px.object({
1405
+ transformBy: PxTransformByEffectSchema.optional(),
1406
+ repeater: PxRepeaterEffectSchema.optional(),
1407
+ maskedBy: PxMaskedByEffectSchema.optional(),
1408
+ clipPath: PxClipPathEffectSchema.optional(),
1409
+ strokeTrim: PxStrokeTrimEffectSchema.optional(),
1410
+ clone: PxCloneEffectSchema.optional(),
1411
+ fillGradient: PxFillGradientEffectSchema.optional(),
1412
+ strokeGradient: PxStrokeGradientEffectSchema.optional(),
1413
+ textPath: PxTextPathEffectSchema.optional(),
1414
+ text: PxTextEffectSchema.optional()
1415
+ }));
1416
+ var PxNodeBase = px.openObject({
1417
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1418
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
1419
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1420
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1421
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1422
+ // would add words that all mean "type" and still need the carrier to read.
1423
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1424
+ // (issues V3), never of distinct key names.
1425
+ type: px.string(),
1426
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
1427
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
1428
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
1429
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
1430
+ // documented — because a wire key that is not in a schema is invisible to the
1431
+ // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1432
+ domType: px.string().optional(),
1433
+ id: px.string().optional(),
1434
+ meta: px.any().optional(),
1435
+ // Player-effects bucket emitted by the Editor's lightweight design format.
1436
+ // Consumed and removed by `applyPlayerEffects` before any other normalisation
1437
+ // (see `createAnimatorImpl`), so downstream code never sees it.
1438
+ effects: PxEffectsSchema.optional(),
1439
+ // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
1440
+ // string ref / array of refs / inline definition / mixed array; mirrors
1441
+ // `animator.animateById` map values and what `processNode` resolves at runtime.
1442
+ animate: PxElementAnimationSchema.optional(),
1443
+ style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
1444
+ }, PxAttrValueSchema);
1445
+ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
1446
+ children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1447
+ }), PxAttrValueSchema);
1448
+ var PxSvgNodeExtra = px.object({
1449
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
1450
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
1451
+ width: px.union([px.number(), px.string()]).optional(),
1452
+ height: px.union([px.number(), px.string()]).optional(),
1453
+ viewBox: px.string().optional(),
1454
+ animator: PxAnimatorConfigSchema.optional()
1455
+ });
1456
+ var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
1457
+ type: px.literal("svg"),
1458
+ // override string → literal to require 'svg'
1459
+ children: px.array(PxNodeSchema).optional()
1460
+ }), PxAttrValueSchema);
1461
+ var PxBezierPathSchema = implementsInterface()(px.object({
1462
+ v: px.array(px.array(px.number())),
1463
+ i: px.array(px.array(px.number())).optional(),
1464
+ o: px.array(px.array(px.number())).optional(),
1465
+ c: px.boolean().optional()
1466
+ }));
1467
+
1468
+ // ../svg-animator-core/src/materialise/PxMotionPath.ts
1469
+ function getKfTranslate(kf) {
1470
+ const v = kfValue(kf);
564
1471
  if (!v) return void 0;
565
1472
  if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
566
1473
  return [v[0], v[1]];
@@ -570,31 +1477,27 @@ var PixodeskAnimator = (() => {
570
1477
  return void 0;
571
1478
  }
572
1479
  function getKfTime(kf) {
573
- var _a, _b;
574
- return (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
1480
+ return kfTime(kf);
575
1481
  }
576
1482
  function getKfEasing(kf) {
577
- var _a;
578
- return (_a = kf.easing) != null ? _a : kf.e;
1483
+ return kfEasing(kf);
579
1484
  }
580
1485
  function propAnimIsMotionPath(anim) {
581
- var _a, _b;
582
1486
  const kfs = anim.keyframes;
583
1487
  if (!Array.isArray(kfs)) return false;
584
1488
  if (anim.autoOrient) return true;
585
1489
  for (const kf of kfs) {
586
- if (((_a = kf.tangentIn) != null ? _a : kf.ti) || ((_b = kf.tangentOut) != null ? _b : kf.to)) return true;
1490
+ if (kfTangentIn(kf) || kfTangentOut(kf)) return true;
587
1491
  }
588
1492
  return false;
589
1493
  }
590
1494
  var _segmentCache = /* @__PURE__ */ new WeakMap();
591
1495
  function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
592
- var _a, _b;
593
1496
  let byNext = _segmentCache.get(prevKf);
594
1497
  const existing = byNext == null ? void 0 : byNext.get(nextKf);
595
1498
  if (existing) return existing;
596
- const to = (_a = prevKf.tangentOut) != null ? _a : prevKf.to;
597
- const ti = (_b = nextKf.tangentIn) != null ? _b : nextKf.ti;
1499
+ const to = kfTangentOut(prevKf);
1500
+ const ti = kfTangentIn(nextKf);
598
1501
  const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
599
1502
  const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
600
1503
  const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
@@ -658,10 +1561,9 @@ var PixodeskAnimator = (() => {
658
1561
  return result;
659
1562
  }
660
1563
  function unwrapAutoOrientRotations(kfs) {
661
- var _a;
662
1564
  let prev;
663
1565
  for (const kf of kfs) {
664
- const v = (_a = kf.v) != null ? _a : kf.value;
1566
+ const v = kfValue(kf);
665
1567
  if (!v || typeof v.rotate !== "number") continue;
666
1568
  if (prev === void 0) {
667
1569
  prev = v.rotate;
@@ -678,8 +1580,7 @@ var PixodeskAnimator = (() => {
678
1580
  return { t: time, v: value };
679
1581
  }
680
1582
  function getKfValueParts(kf) {
681
- var _a;
682
- const v = (_a = kf.value) != null ? _a : kf.v;
1583
+ const v = kfValue(kf);
683
1584
  if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
684
1585
  return v;
685
1586
  }
@@ -740,9 +1641,8 @@ var PixodeskAnimator = (() => {
740
1641
  return d;
741
1642
  }
742
1643
  function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
743
- var _a;
744
1644
  const lastKf = out[out.length - 1];
745
- const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
1645
+ const lastV = kfValue(lastKf);
746
1646
  const prevExit = lastV == null ? void 0 : lastV.rotate;
747
1647
  if (typeof prevExit !== "number") return;
748
1648
  const boundaryV = getKfValueParts(prevKf);
@@ -889,7 +1789,7 @@ var PixodeskAnimator = (() => {
889
1789
  return Math.abs(cross) / Math.sqrt(len2);
890
1790
  }
891
1791
 
892
- // ../svg-animator-core/src/PxDefinitions.ts
1792
+ // ../svg-animator-core/src/animation/PxDefinitions.ts
893
1793
  var LOOP_JUMP_SHIFT_MS = 1;
894
1794
  function deepEqualValue(a, b) {
895
1795
  if (a === b) return true;
@@ -990,8 +1890,8 @@ var PixodeskAnimator = (() => {
990
1890
  if (Array.isArray(pathsArray) && pathsArray.length > 0) {
991
1891
  if (isPathString(pathsArray[0])) {
992
1892
  const paths = [];
993
- for (const pathStr of pathsArray) {
994
- const d = extractPathData(pathStr);
1893
+ for (const pathStr2 of pathsArray) {
1894
+ const d = extractPathData(pathStr2);
995
1895
  if (d) {
996
1896
  paths.push(...parseSvgPathToBezier(d));
997
1897
  }
@@ -1004,8 +1904,8 @@ var PixodeskAnimator = (() => {
1004
1904
  if (Array.isArray(value)) {
1005
1905
  if (value.length > 0 && isPathString(value[0])) {
1006
1906
  const paths = [];
1007
- for (const pathStr of value) {
1008
- const d = extractPathData(pathStr);
1907
+ for (const pathStr2 of value) {
1908
+ const d = extractPathData(pathStr2);
1009
1909
  if (d) {
1010
1910
  paths.push(...parseSvgPathToBezier(d));
1011
1911
  }
@@ -1102,7 +2002,7 @@ var PixodeskAnimator = (() => {
1102
2002
  const totalIntervals = keyframes.length - 1;
1103
2003
  const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
1104
2004
  let segKfs;
1105
- if (loop.extend === PxLoopExtend.before) {
2005
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
1106
2006
  segKfs = keyframes.slice(0, segCount + 1);
1107
2007
  } else {
1108
2008
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -1110,7 +2010,7 @@ var PixodeskAnimator = (() => {
1110
2010
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
1111
2011
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
1112
2012
  let fillStart, fillEnd;
1113
- if (loop.extend === PxLoopExtend.before) {
2013
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
1114
2014
  fillStart = 0;
1115
2015
  fillEnd = firstT;
1116
2016
  } else {
@@ -1123,21 +2023,18 @@ var PixodeskAnimator = (() => {
1123
2023
  const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
1124
2024
  const segDuration = segEndT - segStartT;
1125
2025
  if (segDuration <= 0) return keyframes;
1126
- const template = segKfs.map((kf) => {
1127
- var _a2, _b2;
1128
- return {
1129
- relT: (kf.t - segStartT) / segDuration,
1130
- v: kf.v,
1131
- e: kf.e,
1132
- tangentIn: (_a2 = kf.tangentIn) != null ? _a2 : kf.ti,
1133
- tangentOut: (_b2 = kf.tangentOut) != null ? _b2 : kf.to
1134
- };
1135
- });
2026
+ const template = segKfs.map((kf) => ({
2027
+ relT: (kf.t - segStartT) / segDuration,
2028
+ v: kf.v,
2029
+ e: kf.e,
2030
+ tangentIn: kfTangentIn(kf),
2031
+ tangentOut: kfTangentOut(kf)
2032
+ }));
1136
2033
  const fullReps = Math.floor(fillDuration / segDuration);
1137
2034
  const remainder = fillDuration - fullReps * segDuration;
1138
2035
  const partialFraction = remainder / segDuration;
1139
2036
  const looped = [];
1140
- const separateBoundary = loop.extend !== PxLoopExtend.before;
2037
+ const separateBoundary = loop.repeatAt !== PxLoopRepeatAt.start;
1141
2038
  const originalTerminalKf = keyframes[keyframes.length - 1];
1142
2039
  let terminalEasingOverride;
1143
2040
  let hasTerminalEasingOverride = false;
@@ -1245,30 +2142,30 @@ var PixodeskAnimator = (() => {
1245
2142
  looped.push(pushed);
1246
2143
  }
1247
2144
  }
1248
- if (loop.extend === PxLoopExtend.before) {
2145
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
1249
2146
  if (partialFraction > 1e-9) {
1250
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
2147
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
1251
2148
  appendRepTail(fillStart, isReversed, partialFraction);
1252
2149
  }
1253
2150
  for (let rep = 0; rep < fullReps; rep++) {
1254
2151
  const distFromBoundary = fullReps - 1 - rep;
1255
- const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
2152
+ const isReversed = loop.direction === PxLoopDirection.alternate && distFromBoundary % 2 === 0;
1256
2153
  const repStart = fillStart + remainder + rep * segDuration;
1257
2154
  appendRep(repStart, isReversed);
1258
2155
  }
1259
2156
  } else {
1260
2157
  for (let rep = 0; rep < fullReps; rep++) {
1261
- const isReversed = !!loop.alternate && rep % 2 === 0;
2158
+ const isReversed = loop.direction === PxLoopDirection.alternate && rep % 2 === 0;
1262
2159
  const repStart = fillStart + rep * segDuration;
1263
2160
  appendRep(repStart, isReversed);
1264
2161
  }
1265
2162
  if (partialFraction > 1e-9) {
1266
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
2163
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
1267
2164
  const repStart = fillStart + fullReps * segDuration;
1268
2165
  appendRep(repStart, isReversed, partialFraction);
1269
2166
  }
1270
2167
  }
1271
- if (loop.extend === PxLoopExtend.before) {
2168
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
1272
2169
  return [...looped, ...keyframes];
1273
2170
  } else {
1274
2171
  if (hasTerminalEasingOverride && keyframes.length > 0) {
@@ -1280,34 +2177,34 @@ var PixodeskAnimator = (() => {
1280
2177
  }
1281
2178
  }
1282
2179
  function normalizeKeyframes(propName, propAnim, duration, defs) {
1283
- var _a, _b, _c, _d, _e, _f, _g;
2180
+ var _a;
1284
2181
  const keyframes = propAnim.keyframes || [];
1285
2182
  const normalized = [];
1286
2183
  for (const kf of keyframes) {
1287
- const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
1288
- let value = (_c = kf.value) != null ? _c : kf.v;
1289
- const easing = (_d = kf.easing) != null ? _d : kf.e;
2184
+ const timePct = kfTime(kf);
2185
+ let value = kfValue(kf);
2186
+ const easing = kfEasing(kf);
1290
2187
  if (propName === "d") {
1291
2188
  value = normalizePathValue(value);
1292
2189
  }
1293
2190
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
1294
2191
  if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
1295
- value = (_e = parseColor(value)) != null ? _e : value;
2192
+ value = (_a = parseColor(value)) != null ? _a : value;
1296
2193
  }
1297
2194
  const normKf = {
1298
2195
  t: timePct,
1299
2196
  v: value,
1300
2197
  e: resolveEasing(easing, defs)
1301
2198
  };
1302
- const tIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
1303
- const tOut = (_g = kf.tangentOut) != null ? _g : kf.to;
2199
+ const tIn = kfTangentIn(kf);
2200
+ const tOut = kfTangentOut(kf);
1304
2201
  if (tIn) normKf.tangentIn = tIn;
1305
2202
  if (tOut) normKf.tangentOut = tOut;
1306
2203
  normalized.push(normKf);
1307
2204
  }
1308
2205
  normalized.sort((a, b) => {
1309
- var _a2, _b2;
1310
- return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
2206
+ var _a2, _b;
2207
+ return ((_a2 = a.t) != null ? _a2 : 0) - ((_b = b.t) != null ? _b : 0);
1311
2208
  });
1312
2209
  const loopRaw = propAnim.loop;
1313
2210
  const loop = loopRaw === true ? {} : loopRaw || void 0;
@@ -1334,7 +2231,7 @@ var PixodeskAnimator = (() => {
1334
2231
  const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
1335
2232
  if (!staticParts || !Object.keys(staticParts).length) return animDef;
1336
2233
  const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
1337
- const transformAnim = animDef["transform"];
2234
+ const transformAnim = animDef[TRANSFORM_ATTR];
1338
2235
  if (transformAnim && typeof transformAnim === "object") {
1339
2236
  const anim = transformAnim;
1340
2237
  if (Array.isArray(anim.keyframes)) {
@@ -1359,7 +2256,7 @@ var PixodeskAnimator = (() => {
1359
2256
  delete rest[ch];
1360
2257
  return __spreadProps(__spreadValues({}, rest), { transform: lifted });
1361
2258
  }
1362
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2259
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimelineEngine.native) {
1363
2260
  const normalized = {};
1364
2261
  for (const [propName, propAnim] of Object.entries(animDef)) {
1365
2262
  if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
@@ -1370,12 +2267,12 @@ var PixodeskAnimator = (() => {
1370
2267
  const out = { keyframes: normalizedKfs };
1371
2268
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
1372
2269
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
1373
- normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2270
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
1374
2271
  }
1375
2272
  }
1376
2273
  return normalized;
1377
2274
  }
1378
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2275
+ function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
1379
2276
  const animatorConfig = getAnimatorConfig(doc) || {};
1380
2277
  const defs = getDefs(doc);
1381
2278
  const duration = animatorConfig.duration || 1e3;
@@ -1421,7 +2318,7 @@ var PixodeskAnimator = (() => {
1421
2318
  return bindings;
1422
2319
  }
1423
2320
 
1424
- // src/PxAnimatorTriggers.ts
2321
+ // src/triggers/PxAnimatorTriggers.ts
1425
2322
  function setupAnimationTriggers(api, config) {
1426
2323
  const { startOn, outAction = "continue", scrollIntoViewThreshold = 0 } = config;
1427
2324
  const root = api.getRootElement();
@@ -1526,16 +2423,15 @@ var PixodeskAnimator = (() => {
1526
2423
  return api;
1527
2424
  }
1528
2425
 
1529
- // src/PxAnimatorFrameLoop.ts
2426
+ // src/engines/PxAnimatorFrameLoop.ts
1530
2427
  function getSelector(id) {
1531
2428
  return "#" + id;
1532
2429
  }
1533
2430
 
1534
- // src/PxAnimatorWebApi.ts
2431
+ // src/engines/PxAnimatorWebApi.ts
1535
2432
  function createCssKf(kf, t, propName, unsupportedSet) {
1536
- var _a, _b;
1537
- let value = (_a = kf.v) != null ? _a : kf.value;
1538
- const e = (_b = kf.e) != null ? _b : kf.easing;
2433
+ let value = kfValue(kf);
2434
+ const e = kfEasing(kf);
1539
2435
  const cssKf = {
1540
2436
  offset: t,
1541
2437
  easing: e && Array.isArray(e) ? "cubic-bezier(" + e.join(",") + ")" : void 0
@@ -1640,7 +2536,7 @@ var PixodeskAnimator = (() => {
1640
2536
  console.warn("createFrameLoopAnimator: No root element provided");
1641
2537
  }
1642
2538
  }
1643
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.waapi);
2539
+ const bindings = getNormalisedBindings(doc, PxTimelineEngine.native);
1644
2540
  const animations = [];
1645
2541
  const _iterations = config.iterations;
1646
2542
  let iterations;
@@ -1798,7 +2694,7 @@ var PixodeskAnimator = (() => {
1798
2694
  return api;
1799
2695
  }
1800
2696
 
1801
- // src/PxAnimatorBind.ts
2697
+ // src/engines/PxAnimatorBind.ts
1802
2698
  function finaliseAnimator(animatorConfig, callbacks, make) {
1803
2699
  let apiRef;
1804
2700
  let effectiveCallbacks = callbacks;
@@ -1813,8 +2709,8 @@ var PixodeskAnimator = (() => {
1813
2709
  }
1814
2710
  const res = make(effectiveCallbacks);
1815
2711
  apiRef = res;
1816
- if (animatorConfig.debugInstName) {
1817
- window[animatorConfig.debugInstName] = res;
2712
+ if (animatorConfig.debugGlobalName) {
2713
+ window[animatorConfig.debugGlobalName] = res;
1818
2714
  }
1819
2715
  return res;
1820
2716
  }
@@ -1832,7 +2728,7 @@ var PixodeskAnimator = (() => {
1832
2728
  );
1833
2729
  }
1834
2730
 
1835
- // src/PxAnimatorKeys.ts
2731
+ // src/shared/PxAnimatorKeys.ts
1836
2732
  var PX_ANIMATOR_DATA_KEY = "data";
1837
2733
  return __toCommonJS(index_prerendered_waapi_exports);
1838
2734
  })();