@pixodesk/svg-animator-core 1.0.30 → 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.
package/dist/index.cjs CHANGED
@@ -50,6 +50,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
50
50
  // src/index.ts
51
51
  var index_exports = {};
52
52
  __export(index_exports, {
53
+ BASELINE_PLAYER_VERSION: () => BASELINE_PLAYER_VERSION,
53
54
  COLOUR_ATTR_NAMES: () => COLOUR_ATTR_NAMES,
54
55
  CSS_ONLY_STYLE_PROPS: () => CSS_ONLY_STYLE_PROPS,
55
56
  DEFAULT_DURATION_MS: () => DEFAULT_DURATION_MS,
@@ -58,18 +59,21 @@ __export(index_exports, {
58
59
  LOOP_JUMP_SHIFT_MS: () => LOOP_JUMP_SHIFT_MS,
59
60
  MISSING_GLYPH_CLASS_NAME: () => MISSING_GLYPH_CLASS_NAME,
60
61
  PCT_BASED_ATTR_NAMES: () => PCT_BASED_ATTR_NAMES,
62
+ PLAYER_WIRE_STEPS: () => PLAYER_WIRE_STEPS,
63
+ PLAYER_WIRE_VERSION: () => PLAYER_WIRE_VERSION,
61
64
  PX_ANIM_ATTR_NAME: () => PX_ANIM_ATTR_NAME,
62
65
  PX_ANIM_SRC_ATTR_NAME: () => PX_ANIM_SRC_ATTR_NAME,
66
+ PX_PLAYER_SCHEMA_VERSION: () => PX_PLAYER_SCHEMA_VERSION,
63
67
  PX_TRANSFORM_PART_KEYS: () => PX_TRANSFORM_PART_KEYS,
68
+ PX_UNKNOWN_KEY_ERROR: () => PX_UNKNOWN_KEY_ERROR,
64
69
  PxAnimatedSvgDocumentSchema: () => PxAnimatedSvgDocumentSchema,
65
70
  PxAnimationDefinitionSchema: () => PxAnimationDefinitionSchema,
66
71
  PxAnimatorConfigSchema: () => PxAnimatorConfigSchema,
67
- PxAnimatorEngine: () => PxAnimatorEngine,
68
- PxAnimatorMode: () => PxAnimatorMode,
69
72
  PxAttrValueSchema: () => PxAttrValueSchema,
70
73
  PxBezierPathSchema: () => PxBezierPathSchema,
71
74
  PxBindingSchema: () => PxBindingSchema,
72
75
  PxCloneEffectSchema: () => PxCloneEffectSchema,
76
+ PxCloneWithout: () => PxCloneWithout,
73
77
  PxDefsSchema: () => PxDefsSchema,
74
78
  PxEasingOrRefSchema: () => PxEasingOrRefSchema,
75
79
  PxEffectsSchema: () => PxEffectsSchema,
@@ -81,7 +85,8 @@ __export(index_exports, {
81
85
  PxGradientUnits: () => PxGradientUnits,
82
86
  PxKeyframeSchema: () => PxKeyframeSchema,
83
87
  PxKeyframeValueSchema: () => PxKeyframeValueSchema,
84
- PxLoopExtend: () => PxLoopExtend,
88
+ PxLoopDirection: () => PxLoopDirection,
89
+ PxLoopRepeatAt: () => PxLoopRepeatAt,
85
90
  PxLoopSchema: () => PxLoopSchema,
86
91
  PxMaskedByEffectSchema: () => PxMaskedByEffectSchema,
87
92
  PxNodeBase: () => PxNodeBase,
@@ -98,6 +103,10 @@ __export(index_exports, {
98
103
  PxSvgNodeExtra: () => PxSvgNodeExtra,
99
104
  PxTextEffectSchema: () => PxTextEffectSchema,
100
105
  PxTextPathEffectSchema: () => PxTextPathEffectSchema,
106
+ PxTimelineEngine: () => PxTimelineEngine,
107
+ PxTimelineEngineExtra: () => PxTimelineEngineExtra,
108
+ PxTimelinePinSchema: () => PxTimelinePinSchema,
109
+ PxTimelineSchema: () => PxTimelineSchema,
101
110
  PxTransformByEffectSchema: () => PxTransformByEffectSchema,
102
111
  PxTransformPartsSchema: () => PxTransformPartsSchema,
103
112
  PxTransformValueSchema: () => PxTransformValueSchema,
@@ -106,21 +115,35 @@ __export(index_exports, {
106
115
  TEXT_ATTR: () => TEXT_ATTR,
107
116
  TEXT_CONTENT_ATTR: () => TEXT_CONTENT_ATTR,
108
117
  TRANSFORM_FN_NAMES: () => TRANSFORM_FN_NAMES,
118
+ WIRE_VERSION_KEY: () => WIRE_VERSION_KEY,
119
+ WireStepKind: () => WireStepKind,
120
+ WireVersionRelation: () => WireVersionRelation,
121
+ applyAnimatorConfig: () => applyAnimatorConfig,
109
122
  applyPlayerEffects: () => applyPlayerEffects,
123
+ applyWireSteps: () => applyWireSteps,
124
+ applyWireStepsDown: () => applyWireStepsDown,
110
125
  bezierToSvgPath: () => bezierToSvgPath,
111
126
  calcAnimationValues: () => calcAnimationValues,
112
127
  camelCaseToKebabWordIfNeeded: () => camelCaseToKebabWordIfNeeded,
113
128
  clamp: () => clamp,
114
129
  collectSampleTimes: () => collectSampleTimes,
130
+ compareWireVersion: () => compareWireVersion,
115
131
  composeTransformParts: () => composeTransformParts,
132
+ convertPlayerDocument: () => convertPlayerDocument,
116
133
  createBasicFrameLoopAnimator: () => createBasicFrameLoopAnimator,
117
134
  createPathSampler: () => createPathSampler,
118
135
  cubicBezier: () => cubicBezier,
119
136
  deepClone: () => deepClone,
120
137
  describeSchema: () => describeSchema,
138
+ diagnoseDocument: () => diagnoseDocument,
139
+ diffFieldUniverse: () => diffFieldUniverse,
121
140
  diffInEffect: () => diffInEffect,
141
+ downgradePlayerDocument: () => downgradePlayerDocument,
122
142
  evaluateMotionPathSegment: () => evaluateMotionPathSegment,
123
143
  extendedPathForBrowser: () => extendedPathForBrowser,
144
+ flattenAnimatorTimeline: () => flattenAnimatorTimeline,
145
+ foldAnimatorConfigShortcuts: () => foldAnimatorConfigShortcuts,
146
+ formatWireVersion: () => formatWireVersion,
124
147
  generateNewIds: () => generateNewIds,
125
148
  generateUniqueId: () => generateUniqueId,
126
149
  getAnimatorConfig: () => getAnimatorConfig,
@@ -131,11 +154,17 @@ __export(index_exports, {
131
154
  getNormalizedProps: () => getNormalizedProps,
132
155
  interpolateBeziers: () => interpolateBeziers,
133
156
  interpolateValue: () => interpolateValue,
157
+ isNativeForced: () => isNativeForced,
134
158
  isPxElementFileFormat: () => isPxElementFileFormat,
135
159
  isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
136
160
  isScrollTimeline: () => isScrollTimeline,
137
161
  jsonElementFactory: () => jsonElementFactory,
138
162
  kebabToCamelCaseWord: () => kebabToCamelCaseWord,
163
+ kfEasing: () => kfEasing,
164
+ kfTangentIn: () => kfTangentIn,
165
+ kfTangentOut: () => kfTangentOut,
166
+ kfTime: () => kfTime,
167
+ kfValue: () => kfValue,
139
168
  layoutGlyphTextChars: () => layoutGlyphTextChars,
140
169
  materialiseAllInTree: () => materialiseAllInTree,
141
170
  materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
@@ -146,11 +175,23 @@ __export(index_exports, {
146
175
  materialiseInternalLoopsInTree: () => materialiseInternalLoopsInTree,
147
176
  materialiseMotionPathInPropAnim: () => materialiseMotionPathInPropAnim,
148
177
  materialiseMotionPathsInTree: () => materialiseMotionPathsInTree,
178
+ mayUseNativeScrollTimeline: () => mayUseNativeScrollTimeline,
179
+ mergeAnimatorConfig: () => mergeAnimatorConfig,
180
+ mergeStaticTransformIntoAnimDef: () => mergeStaticTransformIntoAnimDef,
181
+ nestAnimatorTimeline: () => nestAnimatorTimeline,
182
+ parseTransformParts: () => parseTransformParts,
183
+ parseWireVersion: () => parseWireVersion,
184
+ planSchemaRelease: () => planSchemaRelease,
149
185
  propAnimIsMotionPath: () => propAnimIsMotionPath,
150
186
  px: () => px,
187
+ readWireVersion: () => readWireVersion,
188
+ releaseLogProblems: () => releaseLogProblems,
189
+ reportDocumentDiagnostics: () => reportDocumentDiagnostics,
151
190
  resolveStyle: () => resolveStyle,
191
+ resolveTimelineEngine: () => resolveTimelineEngine,
152
192
  reverseEasing: () => reverseEasing,
153
193
  sanitiseAttributeValue: () => sanitiseAttributeValue,
194
+ schemaFieldUniverse: () => schemaFieldUniverse,
154
195
  schemaKeys: () => schemaKeys,
155
196
  scrollOffsetProgress: () => scrollOffsetProgress,
156
197
  scrollPhaseInterval: () => scrollPhaseInterval,
@@ -161,14 +202,16 @@ __export(index_exports, {
161
202
  splitEasing: () => splitEasing,
162
203
  subdivideCubicBezier: () => subdivideCubicBezier,
163
204
  toRGBA: () => toRGBA,
205
+ validateDocument: () => validateDocument,
164
206
  validateNodeEffects: () => validateNodeEffects,
207
+ versionAdvice: () => versionAdvice,
165
208
  visualModelAt: () => visualModelAt
166
209
  });
167
210
  module.exports = __toCommonJS(index_exports);
168
211
 
169
- // src/PxAnimatorUtil.ts
212
+ // src/util/PxAnimatorUtil.ts
170
213
  function bezierToSvgPath(path, forceCurves = false) {
171
- var _a, _b, _c, _d;
214
+ var _a2, _b, _c, _d;
172
215
  const v = path.v;
173
216
  const i = path.i;
174
217
  const o = path.o;
@@ -179,7 +222,7 @@ function bezierToSvgPath(path, forceCurves = false) {
179
222
  d.push("M" + v[0][0] + "," + v[0][1]);
180
223
  for (let idx = 1; idx < len; idx++) {
181
224
  const prevV = v[idx - 1];
182
- const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
225
+ const prevO = (_a2 = o == null ? void 0 : o[idx - 1]) != null ? _a2 : prevV;
183
226
  const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
184
227
  const currV = v[idx];
185
228
  const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
@@ -230,7 +273,7 @@ function interpolateBeziers(paths1, paths2, progress) {
230
273
  return res;
231
274
  }
232
275
  function interpolateBezier(path1, path2, progress) {
233
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
276
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
234
277
  if (!path1 || !path2) return path1 || path2 || { v: [] };
235
278
  const t = Math.min(Math.max(progress, 0), 1);
236
279
  const len = Math.min(path1.v.length, path2.v.length);
@@ -241,7 +284,7 @@ function interpolateBezier(path1, path2, progress) {
241
284
  const v1 = path1.v[idx];
242
285
  const v2 = path2.v[idx];
243
286
  v.push(interpolateVec(v1, v2, t));
244
- const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
287
+ const i1 = (_b = (_a2 = path1.i) == null ? void 0 : _a2[idx]) != null ? _b : v1;
245
288
  const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
246
289
  i.push(interpolateVec(i1, i2, t));
247
290
  const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
@@ -360,8 +403,8 @@ function toRGBA(color) {
360
403
  return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
361
404
  }
362
405
  function parseRgba(s) {
363
- var _a;
364
- const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
406
+ var _a2;
407
+ const inner = (_a2 = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a2[1];
365
408
  if (!inner) throw new Error("Invalid rgb/rgba format");
366
409
  const parts = inner.split(",").map((v) => +v.trim());
367
410
  return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
@@ -400,9 +443,9 @@ var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color",
400
443
  var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
401
444
  var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
402
445
  function composeTransformParts(parts, opts) {
403
- var _a;
446
+ var _a2;
404
447
  if (!parts) return "";
405
- const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
448
+ const withUnits = (_a2 = opts == null ? void 0 : opts.withUnits) != null ? _a2 : true;
406
449
  const segs = [];
407
450
  const t = parts.translate;
408
451
  const o = parts.origin;
@@ -419,6 +462,38 @@ function composeTransformParts(parts, opts) {
419
462
  if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
420
463
  return segs.join("");
421
464
  }
465
+ function parseTransformParts(str2) {
466
+ var _a2, _b;
467
+ if (!str2 || typeof str2 !== "string") return void 0;
468
+ const out = {};
469
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
470
+ const order = ["translate", "rotate", "skewX", "scale"];
471
+ let lastIdx = -1;
472
+ let m;
473
+ while ((m = re.exec(str2)) !== null) {
474
+ const fn = m[1];
475
+ const idx = order.indexOf(fn);
476
+ if (idx < 0 || idx <= lastIdx) return void 0;
477
+ lastIdx = idx;
478
+ const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
479
+ if (nums.some((n) => Number.isNaN(n))) return void 0;
480
+ if (fn === "translate") {
481
+ if (nums.length < 1 || nums.length > 2) return void 0;
482
+ out.translate = [nums[0], (_a2 = nums[1]) != null ? _a2 : 0];
483
+ } else if (fn === "rotate") {
484
+ if (nums.length !== 1) return void 0;
485
+ out.rotate = nums[0];
486
+ } else if (fn === "skewX") {
487
+ if (nums.length !== 1) return void 0;
488
+ out.skew = nums[0];
489
+ } else {
490
+ if (nums.length < 1 || nums.length > 2) return void 0;
491
+ out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
492
+ }
493
+ }
494
+ if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
495
+ return Object.keys(out).length ? out : void 0;
496
+ }
422
497
  var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
423
498
  var DEFAULT_DURATION_MS = 1e3;
424
499
  function kebabToCamelCaseWord(kebab) {
@@ -582,7 +657,7 @@ function invertEasing(easing) {
582
657
  return cubicBezier(flipped);
583
658
  }
584
659
 
585
- // src/PxScrollMath.ts
660
+ // src/playback/PxScrollMath.ts
586
661
  function isScrollTimeline(config) {
587
662
  return (config == null ? void 0 : config.timelineSource) === "scroll";
588
663
  }
@@ -610,8 +685,8 @@ function scrollPhaseInterval(phase, subjectSize, scrollportSize) {
610
685
  }
611
686
  var DEFAULT_PHASE = "cover";
612
687
  function resolveRangePointU(point, defaultFraction, subjectSize, scrollportSize) {
613
- var _a;
614
- const [u0, u1] = scrollPhaseInterval((_a = point == null ? void 0 : point.phase) != null ? _a : DEFAULT_PHASE, subjectSize, scrollportSize);
688
+ var _a2;
689
+ const [u0, u1] = scrollPhaseInterval((_a2 = point == null ? void 0 : point.phase) != null ? _a2 : DEFAULT_PHASE, subjectSize, scrollportSize);
615
690
  const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
616
691
  return u0 + fraction * (u1 - u0);
617
692
  }
@@ -623,9 +698,9 @@ function scrollViewProgress(subjectStart, subjectSize, scrollportSize, range) {
623
698
  return clamp((u - uStart) / (uEnd - uStart), 0, 1);
624
699
  }
625
700
  function scrollOffsetProgress(offset, maxOffset, range) {
626
- var _a, _b;
701
+ var _a2, _b;
627
702
  const raw = maxOffset > 0 ? clamp(offset / maxOffset, 0, 1) : 1;
628
- const start = typeof ((_a = range == null ? void 0 : range.start) == null ? void 0 : _a.fraction) === "number" ? range.start.fraction : 0;
703
+ const start = typeof ((_a2 = range == null ? void 0 : range.start) == null ? void 0 : _a2.fraction) === "number" ? range.start.fraction : 0;
629
704
  const end = typeof ((_b = range == null ? void 0 : range.end) == null ? void 0 : _b.fraction) === "number" ? range.end.fraction : 1;
630
705
  if (end <= start) return raw >= end ? 1 : 0;
631
706
  return clamp((raw - start) / (end - start), 0, 1);
@@ -638,7 +713,8 @@ function scrollResolveAxis(axis, writingMode) {
638
713
  return vertical ? "x" : "y";
639
714
  }
640
715
 
641
- // src/PxSchema.ts
716
+ // src/schema/PxSchema.ts
717
+ var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
642
718
  function pathStr(path) {
643
719
  if (!path.length) return ".";
644
720
  let result = "";
@@ -750,6 +826,8 @@ var Union = class extends Base {
750
826
  constructor(schemas, defaultVal) {
751
827
  super();
752
828
  this.schemas = schemas;
829
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Union from Tuple. */
830
+ this._kind = "union";
753
831
  this._default = defaultVal != null ? defaultVal : schemas[0]._default;
754
832
  }
755
833
  sanitize(raw) {
@@ -759,10 +837,10 @@ var Union = class extends Base {
759
837
  return this._default;
760
838
  }
761
839
  isValid(raw, ctx, path) {
762
- var _a;
840
+ var _a2;
763
841
  const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
764
842
  if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
765
- 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));
843
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
766
844
  return false;
767
845
  }
768
846
  _canSanitize(raw) {
@@ -771,25 +849,31 @@ var Union = class extends Base {
771
849
  };
772
850
  var DiscriminatedUnion = class extends Base {
773
851
  constructor(_key, _schemas, defaultVal) {
852
+ var _a2;
774
853
  super();
775
854
  this._key = _key;
776
855
  this._schemas = _schemas;
856
+ /** Structural tag read by {@link describeSchema}. */
857
+ this._kind = "discriminatedUnion";
777
858
  this._default = defaultVal != null ? defaultVal : _schemas[0]._default;
778
859
  this._map = /* @__PURE__ */ new Map();
779
860
  for (const s of _schemas) {
780
861
  const keySchema = s._shape[_key];
781
- if (keySchema) this._map.set(keySchema._default, s);
862
+ if (!keySchema) continue;
863
+ const literal = (_a2 = keySchema.inner) != null ? _a2 : keySchema;
864
+ this._map.set(literal._default, s);
865
+ if (keySchema.inner) this._absentMember = s;
782
866
  }
783
867
  }
784
868
  _findSchema(raw) {
785
869
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
786
870
  const val = raw[this._key];
787
- if (val === void 0 || val === null) return void 0;
871
+ if (val === void 0 || val === null) return this._absentMember;
788
872
  return this._map.get(val);
789
873
  }
790
874
  sanitize(raw) {
791
- var _a;
792
- return ((_a = this._findSchema(raw)) != null ? _a : this._schemas[0]).sanitize(raw);
875
+ var _a2;
876
+ return ((_a2 = this._findSchema(raw)) != null ? _a2 : this._schemas[0]).sanitize(raw);
793
877
  }
794
878
  isValid(raw, ctx, path) {
795
879
  const schema = this._findSchema(raw);
@@ -818,7 +902,8 @@ var Obj = class extends Base {
818
902
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
819
903
  const out = {};
820
904
  for (const key of Object.keys(this._shape)) {
821
- out[key] = this._shape[key].sanitize(src[key]);
905
+ const v = this._shape[key].sanitize(src[key]);
906
+ if (v !== void 0) out[key] = v;
822
907
  }
823
908
  return out;
824
909
  }
@@ -840,7 +925,7 @@ var Obj = class extends Base {
840
925
  if (key in this._shape) continue;
841
926
  if (obj[key] === void 0) continue;
842
927
  p.push(key);
843
- ctx.errors.push(pathStr(p) + ": unexpected extra key");
928
+ ctx.errors.push(pathStr(p) + ": " + PX_UNKNOWN_KEY_ERROR);
844
929
  p.pop();
845
930
  ok = false;
846
931
  }
@@ -864,7 +949,8 @@ var OpenObj = class extends Base {
864
949
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
865
950
  const out = __spreadValues({}, src);
866
951
  for (const key of Object.keys(this._shape)) {
867
- out[key] = this._shape[key].sanitize(src[key]);
952
+ const v = this._shape[key].sanitize(src[key]);
953
+ if (v !== void 0) out[key] = v;
868
954
  }
869
955
  if (this._openSchema) {
870
956
  for (const key of Object.keys(src)) {
@@ -936,6 +1022,8 @@ var Rec = class extends Base {
936
1022
  constructor(value) {
937
1023
  super();
938
1024
  this.value = value;
1025
+ /** Structural tag read by {@link describeSchema}. */
1026
+ this._kind = "record";
939
1027
  this._default = {};
940
1028
  }
941
1029
  sanitize(raw) {
@@ -1004,8 +1092,8 @@ var Lazy = class extends Base {
1004
1092
  this.resolved = null;
1005
1093
  }
1006
1094
  get schema() {
1007
- var _a;
1008
- return (_a = this.resolved) != null ? _a : this.resolved = this.fn();
1095
+ var _a2;
1096
+ return (_a2 = this.resolved) != null ? _a2 : this.resolved = this.fn();
1009
1097
  }
1010
1098
  sanitize(raw) {
1011
1099
  return this.schema.sanitize(raw);
@@ -1021,6 +1109,8 @@ var Tuple = class extends Base {
1021
1109
  constructor(schemas) {
1022
1110
  super();
1023
1111
  this.schemas = schemas;
1112
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Tuple from Union. */
1113
+ this._kind = "tuple";
1024
1114
  this._default = schemas.map((s) => s._default);
1025
1115
  }
1026
1116
  sanitize(raw) {
@@ -1055,12 +1145,22 @@ function schemaKeys(schema) {
1055
1145
  );
1056
1146
  }
1057
1147
  function describeSchema(schema) {
1058
- var _a;
1148
+ var _a2;
1059
1149
  const s = schema;
1060
- if ("_shape" in s) return { kind: "shape", shape: s._shape };
1150
+ switch (s._kind) {
1151
+ case "union":
1152
+ return { kind: "union", members: s.schemas };
1153
+ case "discriminatedUnion":
1154
+ return { kind: "discriminatedUnion", key: s._key, members: s._schemas };
1155
+ case "record":
1156
+ return { kind: "record", value: s.value };
1157
+ case "tuple":
1158
+ return { kind: "tuple", items: s.schemas };
1159
+ }
1160
+ if ("_shape" in s) return { kind: "shape", shape: s._shape, openValue: s._openSchema };
1061
1161
  if ("item" in s) return { kind: "array", item: s.item };
1062
1162
  if ("inner" in s) return { kind: "optional", inner: s.inner };
1063
- if ("fn" in s) return { kind: "lazy", resolved: (_a = s.resolved) != null ? _a : s.fn() };
1163
+ if ("fn" in s) return { kind: "lazy", resolved: (_a2 = s.resolved) != null ? _a2 : s.resolved = s.fn() };
1064
1164
  return { kind: "leaf" };
1065
1165
  }
1066
1166
  var px = {
@@ -1115,25 +1215,343 @@ var px = {
1115
1215
  lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
1116
1216
  };
1117
1217
 
1118
- // src/PxAnimatorConstants.ts
1218
+ // src/version/PxSchemaVersion.ts
1219
+ var PX_PLAYER_SCHEMA_VERSION = "1.1";
1220
+
1221
+ // src/version/PxWireVersion.ts
1222
+ var WIRE_VERSION_KEY = "version";
1223
+ var ANIMATOR_KEY = "animator";
1224
+ var META_KEY = "meta";
1225
+ var WireVersionRelation = /* @__PURE__ */ ((WireVersionRelation2) => {
1226
+ WireVersionRelation2["unstamped"] = "unstamped";
1227
+ WireVersionRelation2["same"] = "same";
1228
+ WireVersionRelation2["older"] = "older";
1229
+ WireVersionRelation2["newer"] = "newer";
1230
+ WireVersionRelation2["otherGeneration"] = "otherGeneration";
1231
+ return WireVersionRelation2;
1232
+ })(WireVersionRelation || {});
1233
+ var VERSION_RE = /^(\d+)\.(\d+)(?:\.(\d+))?$/;
1234
+ function parseWireVersion(raw) {
1235
+ if (typeof raw !== "string") return void 0;
1236
+ const m = VERSION_RE.exec(raw.trim());
1237
+ if (!m) return void 0;
1238
+ return { a: Number(m[1]), b: Number(m[2]), c: m[3] === void 0 ? 0 : Number(m[3]) };
1239
+ }
1240
+ function formatWireVersion(v) {
1241
+ return v.a + "." + v.b + "." + v.c;
1242
+ }
1243
+ var _a;
1244
+ var PLAYER_WIRE_VERSION = (_a = parseWireVersion(PX_PLAYER_SCHEMA_VERSION)) != null ? _a : { a: 1, b: 1, c: 0 };
1245
+ function getAnimatorBlock(doc) {
1246
+ if (!doc || typeof doc !== "object") return void 0;
1247
+ const atRoot = readObjectProp(doc, ANIMATOR_KEY);
1248
+ if (atRoot) return atRoot;
1249
+ const meta = readObjectProp(doc, META_KEY);
1250
+ return meta ? readObjectProp(meta, ANIMATOR_KEY) : void 0;
1251
+ }
1252
+ function readObjectProp(obj, key) {
1253
+ const value = obj[key];
1254
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1255
+ }
1256
+ function readWireVersion(doc) {
1257
+ const animator = getAnimatorBlock(doc);
1258
+ return animator ? parseWireVersion(animator[WIRE_VERSION_KEY]) : void 0;
1259
+ }
1260
+ function compareWireVersion(file, mine, readerReadsEditorPart) {
1261
+ if (!file) return "unstamped" /* unstamped */;
1262
+ if (file.a !== mine.a) return "otherGeneration" /* otherGeneration */;
1263
+ if (file.b !== mine.b) return file.b > mine.b ? "newer" /* newer */ : "older" /* older */;
1264
+ if (!readerReadsEditorPart || file.c === mine.c) return "same" /* same */;
1265
+ return file.c > mine.c ? "newer" /* newer */ : "older" /* older */;
1266
+ }
1267
+ function versionAdvice(relation, file, mine, isPlayer) {
1268
+ if (!file) return void 0;
1269
+ const target = isPlayer ? "player" : "editor";
1270
+ const gap = "written for schema " + formatWireVersion(file) + ", this " + target + " reads " + formatWireVersion(mine);
1271
+ switch (relation) {
1272
+ case "newer" /* newer */:
1273
+ return "This file is " + gap + ". Update the " + target + " to open it fully.";
1274
+ case "older" /* older */:
1275
+ return "This file is " + gap + ". Saving it from this " + target + " rewrites it in the current format.";
1276
+ case "otherGeneration" /* otherGeneration */:
1277
+ return "This file is " + gap + " \u2014 a different format generation, which no conversion bridges. Open it in a " + target + " of that generation, or accept this document without the parts named above.";
1278
+ default:
1279
+ return void 0;
1280
+ }
1281
+ }
1282
+ var WireStepKind = /* @__PURE__ */ ((WireStepKind2) => {
1283
+ WireStepKind2["additive"] = "additive";
1284
+ WireStepKind2["converted"] = "converted";
1285
+ return WireStepKind2;
1286
+ })(WireStepKind || {});
1287
+ var BASELINE_PLAYER_VERSION = "1.1";
1288
+ var PLAYER_WIRE_STEPS = [];
1289
+ function applyWireSteps(doc, cfg) {
1290
+ const from = readWireVersion(doc);
1291
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1292
+ if (!from || relation !== "older" /* older */) {
1293
+ return {
1294
+ doc,
1295
+ from,
1296
+ relation,
1297
+ applied: [],
1298
+ advice: versionAdvice(relation, from, cfg.target, !cfg.readerReadsEditorPart)
1299
+ };
1300
+ }
1301
+ const due = [];
1302
+ for (const step of cfg.steps) {
1303
+ const stepTo = parseWireVersion(step.to);
1304
+ if (!stepTo) continue;
1305
+ if (compareWireVersion(from, stepTo, cfg.readerReadsEditorPart) !== "older" /* older */) continue;
1306
+ if (!step.up) continue;
1307
+ due.push(step);
1308
+ }
1309
+ if (!due.length || !doc || typeof doc !== "object") return { doc, from, relation, applied: [] };
1310
+ const target = clonePlain(doc);
1311
+ const applied = [];
1312
+ for (const step of due) {
1313
+ try {
1314
+ step.up(target);
1315
+ applied.push(step);
1316
+ } catch (e) {
1317
+ break;
1318
+ }
1319
+ }
1320
+ if (!applied.length) return { doc, from, relation, applied: [] };
1321
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1322
+ return { doc: target, from, relation, applied };
1323
+ }
1324
+ function convertPlayerDocument(doc) {
1325
+ return applyWireSteps(doc, {
1326
+ steps: PLAYER_WIRE_STEPS,
1327
+ target: PLAYER_WIRE_VERSION,
1328
+ readerReadsEditorPart: false
1329
+ });
1330
+ }
1331
+ function clonePlain(value) {
1332
+ const structured = globalThis.structuredClone;
1333
+ return structured ? structured(value) : JSON.parse(JSON.stringify(value));
1334
+ }
1335
+ function stampVersion(doc, target, readerReadsEditorPart) {
1336
+ const animator = getAnimatorBlock(doc);
1337
+ if (!animator) return;
1338
+ const previous = parseWireVersion(animator[WIRE_VERSION_KEY]);
1339
+ animator[WIRE_VERSION_KEY] = formatWireVersion({
1340
+ a: target.a,
1341
+ b: target.b,
1342
+ c: readerReadsEditorPart ? target.c : previous ? previous.c : 0
1343
+ });
1344
+ }
1345
+ function applyWireStepsDown(doc, cfg) {
1346
+ const from = readWireVersion(doc);
1347
+ if (!from) {
1348
+ return { ok: false, blocking: [], reason: "The document carries no version, so there is nothing to convert down from." };
1349
+ }
1350
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1351
+ if (relation === "otherGeneration" /* otherGeneration */) {
1352
+ return {
1353
+ ok: false,
1354
+ blocking: [],
1355
+ reason: "Schema " + formatWireVersion(from) + " and " + formatWireVersion(cfg.target) + " are different generations; no conversion bridges them."
1356
+ };
1357
+ }
1358
+ if (relation !== "newer" /* newer */) return { ok: true, doc, applied: [] };
1359
+ const toUndo = [];
1360
+ for (const step of cfg.steps) {
1361
+ const stepTo = parseWireVersion(step.to);
1362
+ if (!stepTo) continue;
1363
+ if (compareWireVersion(stepTo, cfg.target, cfg.readerReadsEditorPart) !== "newer" /* newer */) continue;
1364
+ if (compareWireVersion(stepTo, from, cfg.readerReadsEditorPart) === "newer" /* newer */) continue;
1365
+ toUndo.push(step);
1366
+ }
1367
+ toUndo.reverse();
1368
+ const blocking = toUndo.filter((s) => s.kind === "converted" /* converted */ && !s.down);
1369
+ if (blocking.length) {
1370
+ return {
1371
+ ok: false,
1372
+ blocking,
1373
+ reason: "Cannot convert down to " + formatWireVersion(cfg.target) + ": " + blocking.map((s) => s.from + " \u2192 " + s.to + " (" + s.reason + ")").join("; ") + " cannot be undone."
1374
+ };
1375
+ }
1376
+ const target = clonePlain(doc);
1377
+ const applied = [];
1378
+ for (const step of toUndo) {
1379
+ if (!step.down) continue;
1380
+ try {
1381
+ step.down(target);
1382
+ applied.push(step);
1383
+ } catch (e) {
1384
+ return {
1385
+ ok: false,
1386
+ blocking: [step],
1387
+ reason: "Undoing " + step.from + " \u2192 " + step.to + " failed: " + String(e)
1388
+ };
1389
+ }
1390
+ }
1391
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1392
+ return { ok: true, doc: target, applied };
1393
+ }
1394
+ function downgradePlayerDocument(doc, target) {
1395
+ return applyWireStepsDown(doc, { steps: PLAYER_WIRE_STEPS, target, readerReadsEditorPart: false });
1396
+ }
1397
+
1398
+ // src/version/PxSchemaFieldUniverse.ts
1399
+ function schemaFieldUniverse(root) {
1400
+ const fields = /* @__PURE__ */ new Set();
1401
+ const enumerated = /* @__PURE__ */ new Set();
1402
+ const queue = [{ schema: root, path: "" }];
1403
+ while (queue.length) {
1404
+ const { schema, path } = queue.shift();
1405
+ const d = describeSchema(schema);
1406
+ switch (d.kind) {
1407
+ case "shape": {
1408
+ if (enumerated.has(schema)) break;
1409
+ enumerated.add(schema);
1410
+ for (const key of Object.keys(d.shape)) {
1411
+ const id = path ? path + "." + key : key;
1412
+ fields.add(id);
1413
+ queue.push({ schema: d.shape[key], path: id });
1414
+ }
1415
+ if (d.openValue) queue.push({ schema: d.openValue, path: path + "{*}" });
1416
+ break;
1417
+ }
1418
+ case "optional":
1419
+ queue.push({ schema: d.inner, path });
1420
+ break;
1421
+ case "array":
1422
+ queue.push({ schema: d.item, path: path + "[]" });
1423
+ break;
1424
+ case "lazy":
1425
+ queue.push({ schema: d.resolved, path });
1426
+ break;
1427
+ case "record":
1428
+ queue.push({ schema: d.value, path: path + "{*}" });
1429
+ break;
1430
+ case "union":
1431
+ d.members.forEach((member, i) => queue.push({ schema: member, path: path + "|" + i }));
1432
+ break;
1433
+ case "discriminatedUnion":
1434
+ for (const member of d.members) queue.push({ schema: member, path: path + "|" + discriminantOf(member, d.key) });
1435
+ break;
1436
+ default:
1437
+ break;
1438
+ }
1439
+ }
1440
+ return [...fields].sort();
1441
+ }
1442
+ function discriminantOf(member, key) {
1443
+ const d = describeSchema(member);
1444
+ if (d.kind !== "shape") return "?";
1445
+ const keySchema = d.shape[key];
1446
+ if (keySchema === void 0) return "?";
1447
+ const kd = describeSchema(keySchema);
1448
+ return String((kd.kind === "optional" ? kd.inner : keySchema)._default);
1449
+ }
1450
+
1451
+ // src/version/PxSchemaRelease.ts
1452
+ function diffFieldUniverse(previous, current) {
1453
+ const prev = new Set(previous);
1454
+ const cur = new Set(current);
1455
+ return {
1456
+ added: current.filter((k) => !prev.has(k)).sort(),
1457
+ removed: previous.filter((k) => !cur.has(k)).sort()
1458
+ };
1459
+ }
1460
+ function planSchemaRelease(p) {
1461
+ const changed = p.added.length > 0 || p.removed.length > 0;
1462
+ const last = parseWireVersion(p.lastReleased);
1463
+ const declared = parseWireVersion(p.declared);
1464
+ if (!last || !declared) return { changed, refuse: "Unparseable version: " + p.lastReleased + " / " + p.declared + "." };
1465
+ const requiredVersion = last.a + "." + (last.b + 1);
1466
+ if (!changed) {
1467
+ if (declared.b === last.b && declared.a === last.a) return { changed };
1468
+ const step2 = p.steps.find((s) => s.to === p.declared);
1469
+ return step2 ? { changed, requiredVersion: p.declared } : { changed, refuse: "The version moved to " + p.declared + " with no key change and no step explaining it." };
1470
+ }
1471
+ const requiredKind = p.removed.length ? "converted" /* converted */ : "additive" /* additive */;
1472
+ const summary = p.added.length + " key(s) added, " + p.removed.length + " removed";
1473
+ if (declared.a !== last.a || declared.b !== last.b + 1) {
1474
+ return {
1475
+ changed,
1476
+ requiredKind,
1477
+ requiredVersion,
1478
+ refuse: "The player schema changed (" + summary + ") but PX_PLAYER_SCHEMA_VERSION is " + p.declared + ". Set it to " + requiredVersion + " and add the PLAYER_WIRE_STEPS entry."
1479
+ };
1480
+ }
1481
+ const step = p.steps.find((s) => s.to === p.declared);
1482
+ if (!step) {
1483
+ return { changed, requiredKind, requiredVersion, refuse: "No PLAYER_WIRE_STEPS entry reaches " + p.declared + "." };
1484
+ }
1485
+ if (requiredKind === "converted" /* converted */ && step.kind !== "converted" /* converted */) {
1486
+ return {
1487
+ changed,
1488
+ requiredKind,
1489
+ requiredVersion,
1490
+ refuse: "Keys were REMOVED (" + p.removed.join(", ") + "), which is never additive \u2014 the " + p.declared + " step must be `converted`, with an up()."
1491
+ };
1492
+ }
1493
+ return { changed, requiredKind, requiredVersion };
1494
+ }
1495
+ function releaseLogProblems(releases, steps, declared, baseline) {
1496
+ const problems = [];
1497
+ if (!releases.length) return ["The release log is empty."];
1498
+ if (!releases[0].baseline || releases[0].version !== baseline) {
1499
+ problems.push("The first release must be the baseline " + baseline + ".");
1500
+ }
1501
+ for (let i = 1; i < releases.length; i++) {
1502
+ const prev = parseWireVersion(releases[i - 1].version);
1503
+ const cur = parseWireVersion(releases[i].version);
1504
+ if (!prev || !cur || cur.a !== prev.a || cur.b !== prev.b + 1) {
1505
+ problems.push("Release " + releases[i].version + " does not follow " + releases[i - 1].version + " by one `b` step.");
1506
+ }
1507
+ if (releases[i].date < releases[i - 1].date) problems.push("Release " + releases[i].version + " is dated before its predecessor.");
1508
+ const step = steps.find((s) => s.to === releases[i].version);
1509
+ if (!step) problems.push("Release " + releases[i].version + " has no PLAYER_WIRE_STEPS entry.");
1510
+ else if (releases[i].removed.length && step.kind !== "converted" /* converted */) {
1511
+ problems.push("Release " + releases[i].version + " removed keys, but its step is not `converted`.");
1512
+ }
1513
+ }
1514
+ const latest = releases[releases.length - 1].version;
1515
+ if (latest !== declared) {
1516
+ problems.push("PX_PLAYER_SCHEMA_VERSION is " + declared + " but the last release record is " + latest + " \u2014 a bump needs its changelog entry (run scripts/schema-release.mjs --apply).");
1517
+ }
1518
+ return problems;
1519
+ }
1520
+
1521
+ // src/format/PxAnimatorConstants.ts
1119
1522
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1120
1523
  var PX_ANIM_ATTR_NAME = "_px_animator";
1121
- var PxAnimatorMode = {
1122
- auto: "auto",
1123
- waapi: "waapi",
1124
- frames: "frames"
1524
+ var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
1525
+ var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
1526
+ var PxTimelineEngine = {
1527
+ native: "native",
1528
+ js: "js"
1125
1529
  };
1126
- var PxAnimatorEngine = {
1127
- waapi: PxAnimatorMode.waapi,
1128
- frames: PxAnimatorMode.frames
1530
+ var PxTimelineEngineExtra = __spreadProps(__spreadValues({}, PxTimelineEngine), {
1531
+ auto: "auto"
1532
+ });
1533
+ function resolveTimelineEngine(engine) {
1534
+ return engine === PxTimelineEngineExtra.js ? PxTimelineEngine.js : PxTimelineEngine.native;
1535
+ }
1536
+ function isNativeForced(engine) {
1537
+ return engine === PxTimelineEngineExtra.native;
1538
+ }
1539
+ function mayUseNativeScrollTimeline(engine) {
1540
+ return engine !== PxTimelineEngineExtra.js;
1541
+ }
1542
+ var PxLoopRepeatAt = {
1543
+ /** Segment from the START; the repetition runs BEFORE the first keyframe
1544
+ * (intro loops that play until the main timeline begins). */
1545
+ start: "start",
1546
+ /** DEFAULT — segment from the END; the repetition runs AFTER the last keyframe
1547
+ * (idle/outro loops that continue once the main timeline has finished). */
1548
+ end: "end"
1129
1549
  };
1130
- var PxLoopExtend = {
1131
- /** Segment from the START; the animation is extended BEFORE the first keyframe
1132
- * (intro loops that run before the main timeline begins). */
1133
- before: "before",
1134
- /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
1135
- * loops that continue once the main timeline has finished). */
1136
- after: "after"
1550
+ var PxLoopDirection = {
1551
+ /** DEFAULT — cycle: every repetition replays the segment the same way round. */
1552
+ normal: "normal",
1553
+ /** Ping-pong: repetitions alternate forward / backward. */
1554
+ alternate: "alternate"
1137
1555
  };
1138
1556
  var PxMaskType = {
1139
1557
  luminance: "luminance",
@@ -1143,8 +1561,9 @@ var PxUnits = {
1143
1561
  userSpaceOnUse: "userSpaceOnUse",
1144
1562
  objectBoundingBox: "objectBoundingBox"
1145
1563
  };
1146
- var PxCloneType = {
1147
- content: "content"
1564
+ var PxCloneWithout = {
1565
+ translate: "translate"
1566
+ // transform: 'transform', // future: drop rotate/scale too (content only)
1148
1567
  };
1149
1568
  var PxPathOverflow = {
1150
1569
  clip: "clip",
@@ -1168,6 +1587,9 @@ var PxStrokeTrimSubPaths = {
1168
1587
  };
1169
1588
  var TEXT_ATTR = "text";
1170
1589
  var TEXT_CONTENT_ATTR = "textContent";
1590
+ var CLASS_ATTR = "class";
1591
+ var TRANSFORM_ATTR = "transform";
1592
+ var OFFSET_DISTANCE_ATTR = "offsetDistance";
1171
1593
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1172
1594
  "type",
1173
1595
  "children",
@@ -1178,7 +1600,18 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1178
1600
  TEXT_ATTR,
1179
1601
  TEXT_CONTENT_ATTR
1180
1602
  ]);
1181
- var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
1603
+ var TRANSFORM_PART = {
1604
+ translate: "translate",
1605
+ rotate: "rotate",
1606
+ scale: "scale",
1607
+ origin: "origin"
1608
+ };
1609
+ var PX_TRANSFORM_PART_KEYS = [
1610
+ TRANSFORM_PART.translate,
1611
+ TRANSFORM_PART.rotate,
1612
+ TRANSFORM_PART.scale,
1613
+ TRANSFORM_PART.origin
1614
+ ];
1182
1615
  var PxGradientUnits = {
1183
1616
  userSpaceOnUse: "userSpaceOnUse",
1184
1617
  objectBoundingBox: "objectBoundingBox"
@@ -1196,29 +1629,140 @@ function isPxElementFileFormat(fileJson) {
1196
1629
  if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
1197
1630
  return false;
1198
1631
  }
1199
- return fileJson["type"] === "svg";
1632
+ return fileJson.type === "svg";
1200
1633
  }
1201
1634
  function getAnimatorConfig(doc) {
1202
- var _a;
1203
- return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
1635
+ var _a2;
1636
+ const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
1637
+ return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1638
+ }
1639
+ var flattenMemo = /* @__PURE__ */ new WeakMap();
1640
+ function flattenAnimatorTimeline(cfg) {
1641
+ const timeline = cfg.timeline;
1642
+ if (timeline === void 0 || timeline === null || typeof timeline !== "object") return cfg;
1643
+ const memoised = flattenMemo.get(cfg);
1644
+ if (memoised) return memoised;
1645
+ const _a2 = cfg, { timeline: _dropped } = _a2, flat = __objRest(_a2, ["timeline"]);
1646
+ if (timeline.engine !== void 0) flat.engine = timeline.engine;
1647
+ if (timeline.frameRate !== void 0) flat.frameRate = timeline.frameRate;
1648
+ if (timeline.type === "scroll" || timeline.type === "view") {
1649
+ flat.timelineSource = "scroll";
1650
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
1651
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1652
+ const scroll = __spreadValues({}, flat.scroll || {});
1653
+ scroll.kind = timeline.type;
1654
+ if (timeline.axis !== void 0) scroll.axis = timeline.axis;
1655
+ if (timeline.source !== void 0) scroll.source = timeline.source;
1656
+ if (timeline.subject !== void 0) scroll.subject = timeline.subject;
1657
+ if (timeline.smoothing !== void 0) scroll.smoothing = timeline.smoothing;
1658
+ if (timeline.range !== void 0) scroll.range = timeline.range;
1659
+ const pin = timeline.pin;
1660
+ if (typeof pin === "boolean") scroll.pin = pin;
1661
+ else if (pin && typeof pin === "object") {
1662
+ scroll.pin = true;
1663
+ if (pin.align !== void 0) scroll.pinAlign = pin.align;
1664
+ if (pin.top !== void 0) scroll.pinTop = pin.top;
1665
+ if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1666
+ }
1667
+ flat.scroll = scroll;
1668
+ } else {
1669
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
1670
+ if (timeline.trigger !== void 0) {
1671
+ const _b = timeline.trigger, { finishAction } = _b, restTrigger = __objRest(_b, ["finishAction"]);
1672
+ if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
1673
+ if (finishAction !== void 0) flat.resetOnFinish = finishAction === "reset";
1674
+ }
1675
+ if (timeline.delay !== void 0) flat.delay = timeline.delay;
1676
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1677
+ if (timeline.direction !== void 0) flat.direction = timeline.direction;
1678
+ if (timeline.fillMode !== void 0) flat.fill = timeline.fillMode;
1679
+ }
1680
+ flattenMemo.set(cfg, flat);
1681
+ return flat;
1682
+ }
1683
+ function scrollKindOrDefault(kind) {
1684
+ return kind === "scroll" ? "scroll" : "view";
1685
+ }
1686
+ function nestAnimatorTimeline(cfg) {
1687
+ if (!cfg || cfg.timeline !== void 0) return cfg;
1688
+ const _a2 = cfg, {
1689
+ timelineSource,
1690
+ scroll,
1691
+ trigger,
1692
+ delay,
1693
+ iterations,
1694
+ direction,
1695
+ fill,
1696
+ resetOnFinish,
1697
+ duration,
1698
+ engine,
1699
+ frameRate
1700
+ } = _a2, shared = __objRest(_a2, [
1701
+ "timelineSource",
1702
+ "scroll",
1703
+ "trigger",
1704
+ "delay",
1705
+ "iterations",
1706
+ "direction",
1707
+ "fill",
1708
+ "resetOnFinish",
1709
+ "duration",
1710
+ "engine",
1711
+ "frameRate"
1712
+ ]);
1713
+ if (timelineSource === "scroll") {
1714
+ const timeline2 = { type: scrollKindOrDefault(scroll == null ? void 0 : scroll.kind) };
1715
+ if (engine !== void 0) timeline2.engine = engine;
1716
+ if (frameRate !== void 0) timeline2.frameRate = frameRate;
1717
+ if (duration !== void 0) timeline2.duration = duration;
1718
+ if (typeof iterations === "number") timeline2.iterations = iterations;
1719
+ if (scroll) {
1720
+ if (scroll.axis !== void 0) timeline2.axis = scroll.axis;
1721
+ if (scroll.source !== void 0) timeline2.source = scroll.source;
1722
+ if (scroll.subject !== void 0) timeline2.subject = scroll.subject;
1723
+ if (scroll.smoothing !== void 0) timeline2.smoothing = scroll.smoothing;
1724
+ if (scroll.range !== void 0) timeline2.range = scroll.range;
1725
+ const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinTop !== void 0 || scroll.pinDistance !== void 0;
1726
+ if (hasPinParams) {
1727
+ timeline2.pin = __spreadValues(__spreadValues(__spreadValues({}, scroll.pinAlign !== void 0 ? { align: scroll.pinAlign } : {}), scroll.pinTop !== void 0 ? { top: scroll.pinTop } : {}), scroll.pinDistance !== void 0 ? { distance: scroll.pinDistance } : {});
1728
+ } else if (scroll.pin !== void 0) {
1729
+ timeline2.pin = scroll.pin;
1730
+ }
1731
+ }
1732
+ return __spreadProps(__spreadValues({}, shared), { timeline: timeline2 });
1733
+ }
1734
+ const timeline = {};
1735
+ if (engine !== void 0) timeline.engine = engine;
1736
+ if (frameRate !== void 0) timeline.frameRate = frameRate;
1737
+ if (duration !== void 0) timeline.duration = duration;
1738
+ if (trigger !== void 0 || resetOnFinish) {
1739
+ const t = __spreadValues({}, trigger || {});
1740
+ if (resetOnFinish) t.finishAction = "reset";
1741
+ timeline.trigger = t;
1742
+ }
1743
+ if (delay !== void 0) timeline.delay = delay;
1744
+ if (iterations !== void 0) timeline.iterations = iterations;
1745
+ if (direction !== void 0) timeline.direction = direction;
1746
+ if (fill !== void 0) timeline.fillMode = fill;
1747
+ return Object.keys(timeline).length > 0 ? __spreadProps(__spreadValues({}, shared), { timeline }) : shared;
1204
1748
  }
1205
1749
  function getDefs(doc) {
1206
- var _a;
1750
+ var _a2;
1207
1751
  if (!doc) return void 0;
1208
- return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
1752
+ return (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
1209
1753
  }
1210
1754
  function getBindings(doc) {
1211
- var _a;
1755
+ var _a2;
1212
1756
  if (!doc) return void 0;
1213
- const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
1757
+ const animateById = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.animateById;
1214
1758
  if (!animateById) return void 0;
1215
- return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));
1759
+ return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
1216
1760
  }
1217
1761
  function getChildren(doc) {
1218
1762
  return doc == null ? void 0 : doc.children;
1219
1763
  }
1220
1764
 
1221
- // src/PxAnimatorTypes.ts
1765
+ // src/format/PxAnimatorTypes.ts
1222
1766
  var PxEasingOrRefSchema = px.union([
1223
1767
  px.string(),
1224
1768
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -1228,39 +1772,54 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
1228
1772
  // e.g. for colors
1229
1773
  px.number(),
1230
1774
  px.array(px.number()),
1231
- px.lazy(() => PxTransformPartsSchema, {}),
1775
+ // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1776
+ // all-optional transform-parts record. In default (non-strict) mode that record accepts
1777
+ // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1778
+ // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1779
+ // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1780
+ // order-independent (`some()`); only sanitize routing depends on this order.
1232
1781
  px.object({ path: px.string() }),
1233
1782
  px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1234
1783
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1235
- px.lazy(() => px.array(PxGradientStopSchema), [])
1784
+ px.lazy(() => px.array(PxGradientStopSchema), []),
1785
+ px.lazy(() => PxTransformPartsSchema, {})
1236
1786
  ]));
1237
1787
  var PxKeyframeSchema = implementsInterface()(px.object({
1238
1788
  time: px.number().optional(),
1239
- t: px.number().optional(),
1240
1789
  value: PxKeyframeValueSchema.optional(),
1241
- v: PxKeyframeValueSchema.optional(),
1242
1790
  easing: PxEasingOrRefSchema.optional(),
1243
- e: PxEasingOrRefSchema.optional(),
1244
1791
  tangentOut: px.tuple([px.number(), px.number()]).optional(),
1245
- to: px.tuple([px.number(), px.number()]).optional(),
1246
- // short alias
1247
- tangentIn: px.tuple([px.number(), px.number()]).optional(),
1248
- ti: px.tuple([px.number(), px.number()]).optional(),
1249
- // short alias
1250
- selected: px.boolean().optional()
1251
- // editor-side UI state (Player ignores it)
1792
+ tangentIn: px.tuple([px.number(), px.number()]).optional()
1793
+ // (`selected` — editor timeline-selection UI state — was REMOVED from the wire
1794
+ // (review §1.3): editor data lives under `meta`. The editor still carries it on
1795
+ // its internal COPY-PASTE payload, which never validates against this schema.)
1252
1796
  }));
1797
+ var anyKf = (kf) => kf;
1798
+ var kfTime = (kf) => {
1799
+ var _a2, _b;
1800
+ return (_b = (_a2 = anyKf(kf).time) != null ? _a2 : anyKf(kf).t) != null ? _b : 0;
1801
+ };
1802
+ var kfValue = (kf) => {
1803
+ var _a2;
1804
+ return (_a2 = anyKf(kf).value) != null ? _a2 : anyKf(kf).v;
1805
+ };
1806
+ var kfEasing = (kf) => {
1807
+ var _a2;
1808
+ return (_a2 = anyKf(kf).easing) != null ? _a2 : anyKf(kf).e;
1809
+ };
1810
+ var kfTangentIn = (kf) => anyKf(kf).tangentIn;
1811
+ var kfTangentOut = (kf) => anyKf(kf).tangentOut;
1253
1812
  var PxLoopSchema = implementsInterface()(px.object({
1254
1813
  segmentCount: px.number().optional(),
1255
- extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
1256
- alternate: px.boolean().optional()
1814
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1815
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1257
1816
  }));
1258
1817
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1259
1818
  value: PxKeyframeValueSchema.optional(),
1260
1819
  keyframes: px.array(PxKeyframeSchema).optional(),
1261
- kfs: px.array(PxKeyframeSchema).optional(),
1262
1820
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1263
- autoOrient: px.boolean().optional()
1821
+ autoOrient: px.boolean().optional(),
1822
+ alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
1264
1823
  }));
1265
1824
  var PxTransformPartsSchema = implementsInterface()(px.object({
1266
1825
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1286,6 +1845,10 @@ var PxElementAnimationSchema = implementsInterface()(px.union([
1286
1845
  var PxTriggerSchema = implementsInterface()(px.object({
1287
1846
  startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1288
1847
  outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1848
+ // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1849
+ // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1850
+ // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1851
+ finishAction: px.enum(["hold", "reset"]).optional(),
1289
1852
  scrollIntoViewThreshold: px.number().optional()
1290
1853
  }));
1291
1854
  var PxGlyphSchema = implementsInterface()(px.object({
@@ -1293,8 +1856,8 @@ var PxGlyphSchema = implementsInterface()(px.object({
1293
1856
  d: px.string()
1294
1857
  }));
1295
1858
  var PxGlyphFontSchema = implementsInterface()(px.object({
1296
- fFamily: px.string(),
1297
- style: px.string(),
1859
+ fontFamily: px.string(),
1860
+ fontStyle: px.string(),
1298
1861
  ascent: px.number(),
1299
1862
  unitsPerEm: px.number(),
1300
1863
  glyphs: px.record(PxGlyphSchema)
@@ -1302,8 +1865,10 @@ var PxGlyphFontSchema = implementsInterface()(px.object({
1302
1865
  var PxDefsSchema = implementsInterface()(px.object({
1303
1866
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1304
1867
  animations: px.record(PxAnimationDefinitionSchema).optional(),
1305
- styles: px.record(px.any()).optional(),
1306
- glyphs: px.record(PxGlyphFontSchema).optional()
1868
+ // Review §2.6: the schema now matches the declared type — a style preset is a flat
1869
+ // record of string|number attribute values, nothing nested.
1870
+ styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1871
+ fonts: px.record(PxGlyphFontSchema).optional()
1307
1872
  }));
1308
1873
  var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1309
1874
  var PxScrollRangePointSchema = implementsInterface()(px.object({
@@ -1315,7 +1880,6 @@ var PxScrollRangeSchema = px.object({
1315
1880
  end: PxScrollRangePointSchema.optional()
1316
1881
  });
1317
1882
  var PxScrollSchema = implementsInterface()(px.object({
1318
- driver: px.enum(["custom", "native"]).optional(),
1319
1883
  kind: px.enum(["view", "scroll"]).optional(),
1320
1884
  axis: px.enum(["block", "inline", "x", "y"]).optional(),
1321
1885
  source: px.enum(["nearest", "root"]).optional(),
@@ -1328,23 +1892,67 @@ var PxScrollSchema = implementsInterface()(px.object({
1328
1892
  pinDistance: px.number().optional(),
1329
1893
  range: PxScrollRangeSchema.optional()
1330
1894
  }));
1331
- var PxAnimatorConfigSchema = implementsInterface()(px.object({
1332
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
1895
+ var PxTimelinePinSchema = implementsInterface()(px.object({
1896
+ align: px.enum(["top", "center", "bottom"]).optional(),
1897
+ top: px.number().optional(),
1898
+ distance: px.number().optional()
1899
+ }));
1900
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
1901
+ var PxTimeTimelineSchema = implementsInterface()(px.object({
1902
+ type: px.literal("time").optional(),
1903
+ engine: PxTimelineEngineSchema,
1904
+ frameRate: px.number().optional(),
1905
+ // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1333
1906
  duration: px.number().optional(),
1907
+ trigger: PxTriggerSchema.optional(),
1334
1908
  delay: px.number().optional(),
1335
- // LAW (SCHEMA-DESIGN R3, S10): the ONE sanctioned string-in-number union
1336
- // (CSS animation-iteration-count familiarity) — do not add more mixed unions.
1337
1909
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1338
- fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1339
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
1910
+ // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1911
+ // — never `fill`, which is paint everywhere else in the format.
1912
+ fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1913
+ direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1914
+ }));
1915
+ var scrollishTimelineShape = {
1916
+ // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1917
+ // span the scroll range maps onto.
1918
+ duration: px.number().optional(),
1919
+ // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1920
+ // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1921
+ iterations: px.number().optional(),
1922
+ engine: PxTimelineEngineSchema,
1340
1923
  frameRate: px.number().optional(),
1341
- trigger: PxTriggerSchema.optional(),
1342
- resetOnFinish: px.boolean().optional(),
1924
+ axis: px.enum(["block", "inline", "x", "y"]).optional(),
1925
+ source: px.enum(["nearest", "root"]).optional(),
1926
+ subject: px.string().optional(),
1927
+ // 'parent' | 'scroller' | any CSS selector
1928
+ smoothing: px.number().optional(),
1929
+ // ms
1930
+ pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1931
+ range: PxScrollRangeSchema.optional()
1932
+ };
1933
+ var PxScrollTimelineSchema = implementsInterface()(
1934
+ px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape))
1935
+ );
1936
+ var PxViewTimelineSchema = implementsInterface()(
1937
+ px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape))
1938
+ );
1939
+ var PxTimelineSchema = px.discriminatedUnion("type", [
1940
+ PxTimeTimelineSchema,
1941
+ // first = the member an absent `type` selects
1942
+ PxScrollTimelineSchema,
1943
+ PxViewTimelineSchema
1944
+ ]);
1945
+ var PxAnimatorConfigSchema = implementsInterface()(px.object({
1946
+ // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1947
+ // at this level only on the runtime view, like the rest of the playback dynamics.)
1948
+ // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1949
+ timeline: PxTimelineSchema.optional(),
1343
1950
  definitions: PxDefsSchema.optional(),
1344
1951
  animateById: px.record(PxElementAnimationSchema).optional(),
1345
- timelineSource: px.string().optional(),
1346
- scroll: PxScrollSchema.optional(),
1347
- debugInstName: px.string().optional()
1952
+ debugGlobalName: px.string().optional(),
1953
+ // Declared HERE because this is a closed object: an undeclared key would be stripped by
1954
+ // `sanitize` and flagged by strict validation on our own files.
1955
+ version: px.string().optional()
1348
1956
  }));
1349
1957
  var PxBindingSchema = implementsInterface()(px.object({
1350
1958
  id: px.string(),
@@ -1362,18 +1970,18 @@ var PxAttrValueSchema = px.union([
1362
1970
  ]);
1363
1971
  var PxAnimatableNumberSchema = px.union([
1364
1972
  px.number(),
1365
- px.object({ value: px.number() }),
1366
- PxPropertyAnimationSchema
1973
+ PxPropertyAnimationSchema,
1974
+ px.object({ value: px.number() })
1367
1975
  ]);
1368
1976
  var PxAnimatableVec2Schema = px.union([
1369
1977
  px.tuple([px.number(), px.number()]),
1370
- px.object({ value: px.tuple([px.number(), px.number()]) }),
1371
- PxPropertyAnimationSchema
1978
+ PxPropertyAnimationSchema,
1979
+ px.object({ value: px.tuple([px.number(), px.number()]) })
1372
1980
  ]);
1373
1981
  var PxAnimatableStringSchema = px.union([
1374
1982
  px.string(),
1375
- px.object({ value: px.string() }),
1376
- PxPropertyAnimationSchema
1983
+ PxPropertyAnimationSchema,
1984
+ px.object({ value: px.string() })
1377
1985
  ]);
1378
1986
  var PxTransformByEffectSchema = implementsInterface()(px.object({
1379
1987
  translate: PxAnimatableVec2Schema.optional(),
@@ -1393,7 +2001,7 @@ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1393
2001
  origin: PxAnimatableVec2Schema.optional()
1394
2002
  }));
1395
2003
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
1396
- sourceId: px.string().optional(),
2004
+ source: px.string().optional(),
1397
2005
  maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1398
2006
  maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1399
2007
  maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
@@ -1403,8 +2011,7 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1403
2011
  height: px.number().optional()
1404
2012
  }));
1405
2013
  var PxClipPathEffectSchema = implementsInterface()(px.object({
1406
- d: PxAnimatableStringSchema.optional(),
1407
- animate: PxPropertyAnimationSchema.optional()
2014
+ d: PxAnimatableStringSchema.optional()
1408
2015
  }));
1409
2016
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1410
2017
  offset: PxAnimatableNumberSchema.optional(),
@@ -1412,15 +2019,15 @@ var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1412
2019
  subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined]).optional()
1413
2020
  }));
1414
2021
  var PxRetimeEffectSchema = implementsInterface()(px.object({
1415
- sourceId: px.string().optional(),
1416
2022
  start: px.number().optional(),
1417
2023
  stretch: px.number().optional(),
1418
2024
  timeCrop: px.tuple([px.number(), px.number()]).optional()
1419
2025
  }));
1420
2026
  var PxCloneEffectSchema = implementsInterface()(px.object({
1421
- // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1422
- type: px.enum([PxCloneType.content]).optional(),
1423
- sourceId: px.string().optional(),
2027
+ // Subtractive on purpose: the `<use>` can only point at one wrapper layer of the
2028
+ // source, so the choices form a ladder — 'translate' now, maybe 'transform' later.
2029
+ without: px.enum([PxCloneWithout.translate]).optional(),
2030
+ source: px.string().optional(),
1424
2031
  retime: PxRetimeEffectSchema.optional()
1425
2032
  }));
1426
2033
  var PxGradientStopSchema = implementsInterface()(px.object({
@@ -1435,11 +2042,11 @@ var PxAnimatableGradientStopsSchema = px.union([
1435
2042
  var PxFillGradientEffectSchema = implementsInterface()(px.object({
1436
2043
  // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1437
2044
  type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1438
- p1: PxAnimatableVec2Schema.optional(),
1439
- p2: PxAnimatableVec2Schema.optional(),
1440
- c: PxAnimatableVec2Schema.optional(),
1441
- r: PxAnimatableNumberSchema.optional(),
1442
- fp: PxAnimatableVec2Schema.optional(),
2045
+ start: PxAnimatableVec2Schema.optional(),
2046
+ end: PxAnimatableVec2Schema.optional(),
2047
+ center: PxAnimatableVec2Schema.optional(),
2048
+ radius: PxAnimatableNumberSchema.optional(),
2049
+ focal: PxAnimatableVec2Schema.optional(),
1443
2050
  stops: PxAnimatableGradientStopsSchema.optional(),
1444
2051
  gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
1445
2052
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
@@ -1447,7 +2054,7 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1447
2054
  }));
1448
2055
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1449
2056
  var PxTextPathEffectSchema = implementsInterface()(px.object({
1450
- path: px.string(),
2057
+ pathData: px.string(),
1451
2058
  pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1452
2059
  lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1453
2060
  method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
@@ -1487,16 +2094,33 @@ function validateNodeEffects(root, opts) {
1487
2094
  walk(root, "root");
1488
2095
  return warnings;
1489
2096
  }
2097
+ function validateDocument(doc) {
2098
+ const ctx = { errors: [], warnings: [], strict: true };
2099
+ const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
2100
+ if (doc && typeof doc === "object") {
2101
+ for (const w of validateNodeEffects(doc, { strict: true })) {
2102
+ if (!problems.includes(w)) problems.push(w);
2103
+ }
2104
+ }
2105
+ return problems;
2106
+ }
1490
2107
  var PxNodeBase = px.openObject({
1491
2108
  // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1492
2109
  // kind of thing is this", discriminated by its CARRIER — here the node TAG
1493
- // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
2110
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1494
2111
  // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1495
2112
  // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1496
2113
  // would add words that all mean "type" and still need the carrier to read.
1497
2114
  // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1498
2115
  // (issues V3), never of distinct key names.
1499
2116
  type: px.string(),
2117
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
2118
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
2119
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
2120
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
2121
+ // documented — because a wire key that is not in a schema is invisible to the
2122
+ // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
2123
+ domType: px.string().optional(),
1500
2124
  id: px.string().optional(),
1501
2125
  meta: px.any().optional(),
1502
2126
  // Player-effects bucket emitted by the Editor's lightweight design format.
@@ -1536,7 +2160,7 @@ function isPxElementFileFormatDeep(fileJson) {
1536
2160
  return { valid, errors: valid ? [] : ["Document failed schema validation"] };
1537
2161
  }
1538
2162
 
1539
- // src/PxIdUtil.ts
2163
+ // src/util/PxIdUtil.ts
1540
2164
  var _idCounter = 0;
1541
2165
  function generateUniqueId() {
1542
2166
  const timestamp = Date.now().toString(36);
@@ -1555,7 +2179,7 @@ function deepClone(value) {
1555
2179
  return cloned;
1556
2180
  }
1557
2181
  function generateNewIds(doc) {
1558
- var _a, _b;
2182
+ var _a2, _b;
1559
2183
  const cloned = deepClone(doc);
1560
2184
  const idMap = /* @__PURE__ */ new Map();
1561
2185
  const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
@@ -1573,7 +2197,8 @@ function generateNewIds(doc) {
1573
2197
  "flood-color",
1574
2198
  "lighting-color"
1575
2199
  ]);
1576
- const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
2200
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
2201
+ const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
1577
2202
  function collectIds(node) {
1578
2203
  if (!node || typeof node !== "object") return;
1579
2204
  if (node.id && typeof node.id === "string") {
@@ -1590,7 +2215,7 @@ function generateNewIds(doc) {
1590
2215
  }
1591
2216
  }
1592
2217
  }
1593
- function updateRefs(node) {
2218
+ function updateRefs(node, parentKey) {
1594
2219
  if (!node || typeof node !== "object") return;
1595
2220
  for (const [key, value] of Object.entries(node)) {
1596
2221
  if (key === "children") {
@@ -1610,7 +2235,7 @@ function generateNewIds(doc) {
1610
2235
  }
1611
2236
  } else if (urlRefAttrs.has(key)) {
1612
2237
  node[key] = replaceUrlRefs(value, idMap);
1613
- } else if (directIdRefAttrs.has(key)) {
2238
+ } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
1614
2239
  const hasHash = value.startsWith("#");
1615
2240
  const newId = idMap.get(hasHash ? value.slice(1) : value);
1616
2241
  if (newId) {
@@ -1626,18 +2251,20 @@ function generateNewIds(doc) {
1626
2251
  }
1627
2252
  }
1628
2253
  } else if (typeof value === "object" && value !== null) {
1629
- updateRefs(value);
2254
+ updateRefs(value, key);
1630
2255
  }
1631
2256
  }
1632
2257
  }
1633
2258
  collectIds(cloned);
1634
2259
  updateRefs(cloned);
1635
- const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
2260
+ const docAnimate = (_a2 = cloned.animator) == null ? void 0 : _a2.animateById;
1636
2261
  if (docAnimate && typeof docAnimate === "object") {
1637
2262
  const updatedAnimate = {};
1638
- for (const [id, anim] of Object.entries(docAnimate)) {
2263
+ for (const [key, anim] of Object.entries(docAnimate)) {
2264
+ const hashed = key.startsWith("#");
2265
+ const id = hashed ? key.slice(1) : key;
1639
2266
  const newId = (_b = idMap.get(id)) != null ? _b : id;
1640
- updatedAnimate[newId] = anim;
2267
+ updatedAnimate[hashed ? "#" + newId : newId] = anim;
1641
2268
  }
1642
2269
  cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animateById: updatedAnimate });
1643
2270
  }
@@ -1650,7 +2277,7 @@ function replaceUrlRefs(value, idMap) {
1650
2277
  });
1651
2278
  }
1652
2279
 
1653
- // src/PxNodeProps.ts
2280
+ // src/util/PxNodeProps.ts
1654
2281
  var DISALLOWED_SVG_TAGS_LOWER = /* @__PURE__ */ new Set([
1655
2282
  "script",
1656
2283
  "foreignobject"
@@ -1714,10 +2341,10 @@ function sanitiseAttributeValue(name, value) {
1714
2341
  return value;
1715
2342
  }
1716
2343
  function resolveStyle(style, defs) {
1717
- var _a;
2344
+ var _a2;
1718
2345
  if (!style) return void 0;
1719
2346
  if (typeof style === "string") {
1720
- return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
2347
+ return (_a2 = defs == null ? void 0 : defs.styles) == null ? void 0 : _a2[style];
1721
2348
  }
1722
2349
  return style;
1723
2350
  }
@@ -1730,16 +2357,16 @@ function getNormalizedProps(props) {
1730
2357
  let value = props[rawKey];
1731
2358
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1732
2359
  propsCopy[key] = toRGBA(value);
1733
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes && !value.kfs) {
2360
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
1734
2361
  const parts = value.value && typeof value.value === "object" ? value.value : value;
1735
- propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
2362
+ propsCopy[TRANSFORM_ATTR] = composeTransformParts(parts, { withUnits: false });
1736
2363
  } else if (TRANSFORM_FN_NAMES.has(key)) {
1737
2364
  if (Array.isArray(value)) {
1738
2365
  if (key === "translate") value = value.map((v) => v + "px");
1739
2366
  value = value.join(",");
1740
2367
  }
1741
2368
  if (key === "rotate") value = value + "deg";
1742
- propsCopy["transform"] = key + "(" + value + ")";
2369
+ propsCopy[TRANSFORM_ATTR] = key + "(" + value + ")";
1743
2370
  } else if (Array.isArray(value)) {
1744
2371
  propsCopy[key] = value.join(",");
1745
2372
  } else if (value !== void 0 && value !== null) {
@@ -1749,10 +2376,9 @@ function getNormalizedProps(props) {
1749
2376
  return propsCopy;
1750
2377
  }
1751
2378
 
1752
- // src/PxMotionPath.ts
2379
+ // src/materialise/PxMotionPath.ts
1753
2380
  function getKfTranslate(kf) {
1754
- var _a;
1755
- const v = (_a = kf.value) != null ? _a : kf.v;
2381
+ const v = kfValue(kf);
1756
2382
  if (!v) return void 0;
1757
2383
  if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
1758
2384
  return [v[0], v[1]];
@@ -1762,31 +2388,27 @@ function getKfTranslate(kf) {
1762
2388
  return void 0;
1763
2389
  }
1764
2390
  function getKfTime(kf) {
1765
- var _a, _b;
1766
- return (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2391
+ return kfTime(kf);
1767
2392
  }
1768
2393
  function getKfEasing(kf) {
1769
- var _a;
1770
- return (_a = kf.easing) != null ? _a : kf.e;
2394
+ return kfEasing(kf);
1771
2395
  }
1772
2396
  function propAnimIsMotionPath(anim) {
1773
- var _a, _b, _c;
1774
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
2397
+ const kfs = anim.keyframes;
1775
2398
  if (!Array.isArray(kfs)) return false;
1776
2399
  if (anim.autoOrient) return true;
1777
2400
  for (const kf of kfs) {
1778
- if (((_b = kf.tangentIn) != null ? _b : kf.ti) || ((_c = kf.tangentOut) != null ? _c : kf.to)) return true;
2401
+ if (kfTangentIn(kf) || kfTangentOut(kf)) return true;
1779
2402
  }
1780
2403
  return false;
1781
2404
  }
1782
2405
  var _segmentCache = /* @__PURE__ */ new WeakMap();
1783
2406
  function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
1784
- var _a, _b;
1785
2407
  let byNext = _segmentCache.get(prevKf);
1786
2408
  const existing = byNext == null ? void 0 : byNext.get(nextKf);
1787
2409
  if (existing) return existing;
1788
- const to = (_a = prevKf.tangentOut) != null ? _a : prevKf.to;
1789
- const ti = (_b = nextKf.tangentIn) != null ? _b : nextKf.ti;
2410
+ const to = kfTangentOut(prevKf);
2411
+ const ti = kfTangentIn(nextKf);
1790
2412
  const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
1791
2413
  const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
1792
2414
  const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
@@ -1836,14 +2458,14 @@ var DEFAULT_FLATNESS_TOL = 0.5;
1836
2458
  var DEFAULT_ROTATION_TOL = 5;
1837
2459
  var DEFAULT_MAX_SAMPLES = 32;
1838
2460
  function materialiseMotionPathInPropAnim(anim, opts) {
1839
- var _a, _b, _c, _d;
2461
+ var _a2, _b, _c;
1840
2462
  if (!propAnimIsMotionPath(anim)) return anim;
1841
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
2463
+ const kfs = anim.keyframes;
1842
2464
  if (!Array.isArray(kfs) || kfs.length < 2) return anim;
1843
2465
  const autoOrient = !!anim.autoOrient;
1844
- const flatnessTol = (_b = opts == null ? void 0 : opts.flatnessTolerance) != null ? _b : DEFAULT_FLATNESS_TOL;
1845
- const rotationTol = (_c = opts == null ? void 0 : opts.rotationTolerance) != null ? _c : DEFAULT_ROTATION_TOL;
1846
- const maxSamples = (_d = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _d : DEFAULT_MAX_SAMPLES;
2466
+ const flatnessTol = (_a2 = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a2 : DEFAULT_FLATNESS_TOL;
2467
+ const rotationTol = (_b = opts == null ? void 0 : opts.rotationTolerance) != null ? _b : DEFAULT_ROTATION_TOL;
2468
+ const maxSamples = (_c = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _c : DEFAULT_MAX_SAMPLES;
1847
2469
  const out = [];
1848
2470
  const firstPos = getKfTranslate(kfs[0]);
1849
2471
  if (!firstPos) return anim;
@@ -1872,15 +2494,14 @@ function materialiseMotionPathInPropAnim(anim, opts) {
1872
2494
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
1873
2495
  if (lastInE) out[out.length - 1].e = lastInE;
1874
2496
  if (autoOrient) unwrapAutoOrientRotations(out);
1875
- const result = { kfs: out };
2497
+ const result = { keyframes: out };
1876
2498
  if (anim.loop !== void 0) result.loop = anim.loop;
1877
2499
  return result;
1878
2500
  }
1879
2501
  function unwrapAutoOrientRotations(kfs) {
1880
- var _a;
1881
2502
  let prev;
1882
2503
  for (const kf of kfs) {
1883
- const v = (_a = kf.v) != null ? _a : kf.value;
2504
+ const v = kfValue(kf);
1884
2505
  if (!v || typeof v.rotate !== "number") continue;
1885
2506
  if (prev === void 0) {
1886
2507
  prev = v.rotate;
@@ -1897,8 +2518,7 @@ function makeOutKf(time, value) {
1897
2518
  return { t: time, v: value };
1898
2519
  }
1899
2520
  function getKfValueParts(kf) {
1900
- var _a;
1901
- const v = (_a = kf.value) != null ? _a : kf.v;
2521
+ const v = kfValue(kf);
1902
2522
  if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
1903
2523
  return v;
1904
2524
  }
@@ -1959,9 +2579,8 @@ function wrappedAngleDelta(a, b) {
1959
2579
  return d;
1960
2580
  }
1961
2581
  function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
1962
- var _a;
1963
2582
  const lastKf = out[out.length - 1];
1964
- const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
2583
+ const lastV = kfValue(lastKf);
1965
2584
  const prevExit = lastV == null ? void 0 : lastV.rotate;
1966
2585
  if (typeof prevExit !== "number") return;
1967
2586
  const boundaryV = getKfValueParts(prevKf);
@@ -2142,7 +2761,7 @@ function walkAndMaterialise(node, opts) {
2142
2761
  return cloned;
2143
2762
  }
2144
2763
 
2145
- // src/PxDefinitions.ts
2764
+ // src/animation/PxDefinitions.ts
2146
2765
  var LOOP_JUMP_SHIFT_MS = 1;
2147
2766
  function deepEqualValue(a, b) {
2148
2767
  if (a === b) return true;
@@ -2274,21 +2893,21 @@ function normalizePathValue(value) {
2274
2893
  return value;
2275
2894
  }
2276
2895
  function resolveEasing(easing, defs) {
2277
- var _a;
2896
+ var _a2;
2278
2897
  if (!easing) return void 0;
2279
2898
  if (Array.isArray(easing)) {
2280
2899
  return easing;
2281
2900
  }
2282
- if ((_a = defs == null ? void 0 : defs.easings) == null ? void 0 : _a[easing]) {
2901
+ if ((_a2 = defs == null ? void 0 : defs.easings) == null ? void 0 : _a2[easing]) {
2283
2902
  return defs.easings[easing];
2284
2903
  }
2285
2904
  console.warn("Unknown easing name: " + easing);
2286
2905
  return void 0;
2287
2906
  }
2288
2907
  function resolveAnimation(animRef, defs) {
2289
- var _a;
2908
+ var _a2;
2290
2909
  if (typeof animRef === "string") {
2291
- const resolved = (_a = defs == null ? void 0 : defs.animations) == null ? void 0 : _a[animRef];
2910
+ const resolved = (_a2 = defs == null ? void 0 : defs.animations) == null ? void 0 : _a2[animRef];
2292
2911
  if (!resolved) {
2293
2912
  console.warn("Unknown animation name: " + animRef);
2294
2913
  }
@@ -2313,9 +2932,9 @@ function resolveElementAnimation(animate, defs) {
2313
2932
  return results;
2314
2933
  }
2315
2934
  function interpolateValue(propName, a, b, t) {
2316
- var _a, _b;
2935
+ var _a2, _b;
2317
2936
  if (propName === "d") {
2318
- const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
2937
+ const aPaths = (_a2 = a == null ? void 0 : a.paths) != null ? _a2 : Array.isArray(a) ? a : [];
2319
2938
  const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2320
2939
  return { paths: interpolateBeziers(aPaths, bPaths, t) };
2321
2940
  }
@@ -2351,11 +2970,11 @@ function interpolateTransformParts(a, b, t) {
2351
2970
  return out;
2352
2971
  }
2353
2972
  function expandLoopKeyframes(propName, keyframes, loop, duration) {
2354
- var _a, _b, _c, _d, _e;
2973
+ var _a2, _b, _c, _d, _e;
2355
2974
  const totalIntervals = keyframes.length - 1;
2356
- const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2975
+ const segCount = clamp((_a2 = loop.segmentCount) != null ? _a2 : totalIntervals, 1, totalIntervals);
2357
2976
  let segKfs;
2358
- if (loop.extend === PxLoopExtend.before) {
2977
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2359
2978
  segKfs = keyframes.slice(0, segCount + 1);
2360
2979
  } else {
2361
2980
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -2363,7 +2982,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2363
2982
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2364
2983
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2365
2984
  let fillStart, fillEnd;
2366
- if (loop.extend === PxLoopExtend.before) {
2985
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2367
2986
  fillStart = 0;
2368
2987
  fillEnd = firstT;
2369
2988
  } else {
@@ -2376,26 +2995,23 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2376
2995
  const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
2377
2996
  const segDuration = segEndT - segStartT;
2378
2997
  if (segDuration <= 0) return keyframes;
2379
- const template = segKfs.map((kf) => {
2380
- var _a2, _b2;
2381
- return {
2382
- relT: (kf.t - segStartT) / segDuration,
2383
- v: kf.v,
2384
- e: kf.e,
2385
- tangentIn: (_a2 = kf.tangentIn) != null ? _a2 : kf.ti,
2386
- tangentOut: (_b2 = kf.tangentOut) != null ? _b2 : kf.to
2387
- };
2388
- });
2998
+ const template = segKfs.map((kf) => ({
2999
+ relT: (kf.t - segStartT) / segDuration,
3000
+ v: kf.v,
3001
+ e: kf.e,
3002
+ tangentIn: kfTangentIn(kf),
3003
+ tangentOut: kfTangentOut(kf)
3004
+ }));
2389
3005
  const fullReps = Math.floor(fillDuration / segDuration);
2390
3006
  const remainder = fillDuration - fullReps * segDuration;
2391
3007
  const partialFraction = remainder / segDuration;
2392
3008
  const looped = [];
2393
- const separateBoundary = loop.extend !== PxLoopExtend.before;
3009
+ const separateBoundary = loop.repeatAt !== PxLoopRepeatAt.start;
2394
3010
  const originalTerminalKf = keyframes[keyframes.length - 1];
2395
3011
  let terminalEasingOverride;
2396
3012
  let hasTerminalEasingOverride = false;
2397
3013
  function appendRep(repStart, isReversed, partial) {
2398
- var _a2;
3014
+ var _a3;
2399
3015
  let entries;
2400
3016
  if (isReversed) {
2401
3017
  entries = [];
@@ -2432,7 +3048,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2432
3048
  return;
2433
3049
  }
2434
3050
  const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2435
- const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
3051
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a3 = prevKf.t) != null ? _a3 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2436
3052
  if (isBoundary) {
2437
3053
  if (deepEqualValue(prevKf.v, entry.v)) {
2438
3054
  if (looped.length > 0) {
@@ -2498,30 +3114,30 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2498
3114
  looped.push(pushed);
2499
3115
  }
2500
3116
  }
2501
- if (loop.extend === PxLoopExtend.before) {
3117
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2502
3118
  if (partialFraction > 1e-9) {
2503
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
3119
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2504
3120
  appendRepTail(fillStart, isReversed, partialFraction);
2505
3121
  }
2506
3122
  for (let rep = 0; rep < fullReps; rep++) {
2507
3123
  const distFromBoundary = fullReps - 1 - rep;
2508
- const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
3124
+ const isReversed = loop.direction === PxLoopDirection.alternate && distFromBoundary % 2 === 0;
2509
3125
  const repStart = fillStart + remainder + rep * segDuration;
2510
3126
  appendRep(repStart, isReversed);
2511
3127
  }
2512
3128
  } else {
2513
3129
  for (let rep = 0; rep < fullReps; rep++) {
2514
- const isReversed = !!loop.alternate && rep % 2 === 0;
3130
+ const isReversed = loop.direction === PxLoopDirection.alternate && rep % 2 === 0;
2515
3131
  const repStart = fillStart + rep * segDuration;
2516
3132
  appendRep(repStart, isReversed);
2517
3133
  }
2518
3134
  if (partialFraction > 1e-9) {
2519
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
3135
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2520
3136
  const repStart = fillStart + fullReps * segDuration;
2521
3137
  appendRep(repStart, isReversed, partialFraction);
2522
3138
  }
2523
3139
  }
2524
- if (loop.extend === PxLoopExtend.before) {
3140
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2525
3141
  return [...looped, ...keyframes];
2526
3142
  } else {
2527
3143
  if (hasTerminalEasingOverride && keyframes.length > 0) {
@@ -2533,34 +3149,34 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2533
3149
  }
2534
3150
  }
2535
3151
  function normalizeKeyframes(propName, propAnim, duration, defs) {
2536
- var _a, _b, _c, _d, _e, _f, _g;
2537
- const keyframes = propAnim.keyframes || propAnim.kfs || [];
3152
+ var _a2;
3153
+ const keyframes = propAnim.keyframes || [];
2538
3154
  const normalized = [];
2539
3155
  for (const kf of keyframes) {
2540
- const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2541
- let value = (_c = kf.value) != null ? _c : kf.v;
2542
- const easing = (_d = kf.easing) != null ? _d : kf.e;
3156
+ const timePct = kfTime(kf);
3157
+ let value = kfValue(kf);
3158
+ const easing = kfEasing(kf);
2543
3159
  if (propName === "d") {
2544
3160
  value = normalizePathValue(value);
2545
3161
  }
2546
3162
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2547
3163
  if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
2548
- value = (_e = parseColor(value)) != null ? _e : value;
3164
+ value = (_a2 = parseColor(value)) != null ? _a2 : value;
2549
3165
  }
2550
3166
  const normKf = {
2551
3167
  t: timePct,
2552
3168
  v: value,
2553
3169
  e: resolveEasing(easing, defs)
2554
3170
  };
2555
- const tIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
2556
- const tOut = (_g = kf.tangentOut) != null ? _g : kf.to;
3171
+ const tIn = kfTangentIn(kf);
3172
+ const tOut = kfTangentOut(kf);
2557
3173
  if (tIn) normKf.tangentIn = tIn;
2558
3174
  if (tOut) normKf.tangentOut = tOut;
2559
3175
  normalized.push(normKf);
2560
3176
  }
2561
3177
  normalized.sort((a, b) => {
2562
- var _a2, _b2;
2563
- return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
3178
+ var _a3, _b;
3179
+ return ((_a3 = a.t) != null ? _a3 : 0) - ((_b = b.t) != null ? _b : 0);
2564
3180
  });
2565
3181
  const loopRaw = propAnim.loop;
2566
3182
  const loop = loopRaw === true ? {} : loopRaw || void 0;
@@ -2579,28 +3195,29 @@ function mergeAnimationDefinitions(animations) {
2579
3195
  return merged;
2580
3196
  }
2581
3197
  function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2582
- var _a;
2583
3198
  const loopRaw = propAnim.loop;
2584
3199
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
2585
3200
  const loop = loopRaw === true ? {} : loopRaw;
2586
- const rawKfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
3201
+ const rawKfs = propAnim.keyframes;
2587
3202
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
2588
3203
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2589
3204
  const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
2590
3205
  const kfs = rawKfs.map((kf) => {
2591
- var _a2, _b, _c, _d, _e, _f, _g, _h;
2592
- const t = (_a2 = kf.t) != null ? _a2 : kf.time;
2593
- let v = (_b = kf.v) != null ? _b : kf.value;
3206
+ var _a2;
3207
+ const t = kfTime(kf);
3208
+ let v = kfValue(kf);
2594
3209
  if (propName === "d") v = normalizePathValue(v);
2595
- if (isColour) v = (_c = parseColor(v)) != null ? _c : v;
2596
- const e = (_d = kf.e) != null ? _d : kf.easing;
3210
+ if (isColour) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3211
+ const e = kfEasing(kf);
2597
3212
  const out2 = { t, v, e };
2598
- if ((_e = kf.tangentIn) != null ? _e : kf.ti) out2.tangentIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
2599
- if ((_g = kf.tangentOut) != null ? _g : kf.to) out2.tangentOut = (_h = kf.tangentOut) != null ? _h : kf.to;
3213
+ const tIn = kfTangentIn(kf);
3214
+ const tOut = kfTangentOut(kf);
3215
+ if (tIn) out2.tangentIn = tIn;
3216
+ if (tOut) out2.tangentOut = tOut;
2600
3217
  return out2;
2601
3218
  });
2602
3219
  const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
2603
- const out = { kfs: expanded };
3220
+ const out = { keyframes: expanded };
2604
3221
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2605
3222
  return out;
2606
3223
  }
@@ -2642,7 +3259,37 @@ var _elementIdCounter = 0;
2642
3259
  function generateElementId() {
2643
3260
  return "_px_el_" + ++_elementIdCounter;
2644
3261
  }
2645
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
3262
+ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
3263
+ if (!animDef) return animDef;
3264
+ const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
3265
+ if (!staticParts || !Object.keys(staticParts).length) return animDef;
3266
+ const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
3267
+ const transformAnim = animDef[TRANSFORM_ATTR];
3268
+ if (transformAnim && typeof transformAnim === "object") {
3269
+ const anim = transformAnim;
3270
+ if (Array.isArray(anim.keyframes)) {
3271
+ const out = __spreadProps(__spreadValues({}, anim), {
3272
+ keyframes: anim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: mergeKfValue(kf.value) }))
3273
+ });
3274
+ if (out.value !== void 0) out.value = mergeKfValue(out.value);
3275
+ return __spreadProps(__spreadValues({}, animDef), { transform: out });
3276
+ }
3277
+ return animDef;
3278
+ }
3279
+ const channels = Object.keys(animDef).filter((k) => TRANSFORM_FN_NAMES.has(k));
3280
+ if (channels.length !== 1) return animDef;
3281
+ const ch = channels[0];
3282
+ const chAnim = animDef[ch];
3283
+ if (!chAnim || typeof chAnim !== "object" || !Array.isArray(chAnim.keyframes)) return animDef;
3284
+ const lifted = __spreadProps(__spreadValues({}, chAnim), {
3285
+ keyframes: chAnim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: __spreadProps(__spreadValues({}, staticParts), { [ch]: kf.value }) }))
3286
+ });
3287
+ if (lifted.value !== void 0) lifted.value = __spreadProps(__spreadValues({}, staticParts), { [ch]: lifted.value });
3288
+ const rest = __spreadValues({}, animDef);
3289
+ delete rest[ch];
3290
+ return __spreadProps(__spreadValues({}, rest), { transform: lifted });
3291
+ }
3292
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimelineEngine.native) {
2646
3293
  const normalized = {};
2647
3294
  for (const [propName, propAnim] of Object.entries(animDef)) {
2648
3295
  if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
@@ -2650,24 +3297,24 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimat
2650
3297
  }
2651
3298
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2652
3299
  if (normalizedKfs.length > 0) {
2653
- const out = { kfs: normalizedKfs };
3300
+ const out = { keyframes: normalizedKfs };
2654
3301
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2655
3302
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2656
- normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
3303
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2657
3304
  }
2658
3305
  }
2659
3306
  return normalized;
2660
3307
  }
2661
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
3308
+ function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
2662
3309
  const animatorConfig = getAnimatorConfig(doc) || {};
2663
3310
  const defs = getDefs(doc);
2664
3311
  const duration = animatorConfig.duration || 1e3;
2665
3312
  const bindings = [];
2666
- const processAnimation = (id, animate) => {
3313
+ const processAnimation = (id, animate, staticTransform) => {
2667
3314
  if (!animate) return null;
2668
3315
  const animDefs = resolveElementAnimation(animate, defs);
2669
3316
  if (animDefs.length === 0) return null;
2670
- const merged = mergeAnimationDefinitions(animDefs);
3317
+ const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);
2671
3318
  const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
2672
3319
  if (Object.keys(normalizedAnim).length === 0) return null;
2673
3320
  return {
@@ -2687,7 +3334,7 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2687
3334
  if (inlineAnim && Object.keys(inlineAnim).length > 0) {
2688
3335
  const nodeId = node.id || generateElementId();
2689
3336
  node.id = nodeId;
2690
- const normalized = processAnimation(nodeId, inlineAnim);
3337
+ const normalized = processAnimation(nodeId, inlineAnim, node.transform);
2691
3338
  if (normalized) bindings.push(normalized);
2692
3339
  }
2693
3340
  if (node.children) {
@@ -2704,12 +3351,12 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2704
3351
  return bindings;
2705
3352
  }
2706
3353
  function getKeyframesPair(keyframes, progress) {
2707
- var _a, _b;
3354
+ var _a2, _b;
2708
3355
  const last = keyframes.length - 1;
2709
3356
  let prevKf = keyframes[0];
2710
3357
  let nextKf = keyframes[last > 0 ? 1 : 0];
2711
3358
  for (let j = 0; j < last; j++) {
2712
- const aOff = (_a = keyframes[j].t) != null ? _a : 0;
3359
+ const aOff = (_a2 = keyframes[j].t) != null ? _a2 : 0;
2713
3360
  const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
2714
3361
  if (aOff <= progress && progress <= bOff) {
2715
3362
  prevKf = keyframes[j];
@@ -2724,13 +3371,13 @@ function getKeyframesPair(keyframes, progress) {
2724
3371
  return { prevKf, nextKf };
2725
3372
  }
2726
3373
  function calcPropertyValue(propName, propAnim, progress) {
2727
- var _a, _b, _c, _d, _e, _f, _g;
2728
- const keyframes = propAnim.kfs || propAnim.keyframes || [];
3374
+ var _a2, _b, _c, _d;
3375
+ const keyframes = propAnim.keyframes || [];
2729
3376
  if (keyframes.length === 0) return null;
2730
3377
  const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
2731
- let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
3378
+ let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a2 = prevKf.t) != null ? _a2 : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
2732
3379
  localProgress = clamp(localProgress, 0, 1);
2733
- const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
3380
+ const easing = kfEasing(prevKf);
2734
3381
  if (easing && Array.isArray(easing)) {
2735
3382
  try {
2736
3383
  localProgress = cubicBezier(easing)(localProgress);
@@ -2739,11 +3386,11 @@ function calcPropertyValue(propName, propAnim, progress) {
2739
3386
  }
2740
3387
  let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2741
3388
  let cssValue = null;
2742
- const prevV = (_d = prevKf == null ? void 0 : prevKf.v) != null ? _d : prevKf == null ? void 0 : prevKf.value;
2743
- const nextV = (_e = nextKf == null ? void 0 : nextKf.v) != null ? _e : nextKf == null ? void 0 : nextKf.value;
3389
+ const prevV = prevKf == null ? void 0 : prevKf.v;
3390
+ const nextV = nextKf == null ? void 0 : nextKf.v;
2744
3391
  if (cssAttrName === "d") {
2745
- const prevPaths = (_f = prevV == null ? void 0 : prevV.paths) != null ? _f : Array.isArray(prevV) ? prevV : [];
2746
- const nextPaths = (_g = nextV == null ? void 0 : nextV.paths) != null ? _g : Array.isArray(nextV) ? nextV : [];
3392
+ const prevPaths = (_c = prevV == null ? void 0 : prevV.paths) != null ? _c : Array.isArray(prevV) ? prevV : [];
3393
+ const nextPaths = (_d = nextV == null ? void 0 : nextV.paths) != null ? _d : Array.isArray(nextV) ? nextV : [];
2747
3394
  cssValue = interpolateBeziers(
2748
3395
  prevPaths,
2749
3396
  nextPaths,
@@ -2846,7 +3493,7 @@ function calcAnimationValues(animDef, progress) {
2846
3493
  return result;
2847
3494
  }
2848
3495
 
2849
- // src/PxNodeCloneUtil.ts
3496
+ // src/util/PxNodeCloneUtil.ts
2850
3497
  function deepClonePxNode(value) {
2851
3498
  if (value === null || typeof value !== "object") return value;
2852
3499
  if (Array.isArray(value)) return value.map(deepClonePxNode);
@@ -2857,13 +3504,13 @@ function deepClonePxNode(value) {
2857
3504
  function regenerateIdsAndRewriteRefs(root, genId3) {
2858
3505
  const oldToNew = /* @__PURE__ */ new Map();
2859
3506
  const walkAssign = (n) => {
2860
- var _a;
3507
+ var _a2;
2861
3508
  if (typeof n.id === "string") {
2862
3509
  const newId = genId3();
2863
3510
  oldToNew.set(n.id, newId);
2864
3511
  n.id = newId;
2865
3512
  }
2866
- (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
3513
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkAssign);
2867
3514
  };
2868
3515
  walkAssign(root);
2869
3516
  const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
@@ -2871,7 +3518,7 @@ function regenerateIdsAndRewriteRefs(root, genId3) {
2871
3518
  return newId ? "url(#" + newId + ")" : m;
2872
3519
  });
2873
3520
  const walkRewrite = (n) => {
2874
- var _a;
3521
+ var _a2;
2875
3522
  if (typeof n.href === "string" && n.href.startsWith("#")) {
2876
3523
  const newId = oldToNew.get(n.href.slice(1));
2877
3524
  if (newId) n.href = "#" + newId;
@@ -2883,7 +3530,7 @@ function regenerateIdsAndRewriteRefs(root, genId3) {
2883
3530
  n[k] = rewriteUrl(v);
2884
3531
  }
2885
3532
  }
2886
- (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
3533
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkRewrite);
2887
3534
  };
2888
3535
  walkRewrite(root);
2889
3536
  return oldToNew;
@@ -2893,7 +3540,7 @@ function toFiniteNum(v) {
2893
3540
  return Number.isFinite(n) ? n : 0;
2894
3541
  }
2895
3542
  function applyUseOffsetToG(gNode) {
2896
- var _a;
3543
+ var _a2;
2897
3544
  const x = toFiniteNum(gNode.x);
2898
3545
  const y = toFiniteNum(gNode.y);
2899
3546
  delete gNode.x;
@@ -2902,7 +3549,7 @@ function applyUseOffsetToG(gNode) {
2902
3549
  const offset = "translate(" + x + "," + y + ")";
2903
3550
  const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
2904
3551
  if (carriesTransform) {
2905
- const inner = { type: "g", transform: offset, children: (_a = gNode.children) != null ? _a : [] };
3552
+ const inner = { type: "g", transform: offset, children: (_a2 = gNode.children) != null ? _a2 : [] };
2906
3553
  gNode.children = [inner];
2907
3554
  } else {
2908
3555
  gNode.transform = offset;
@@ -2910,9 +3557,9 @@ function applyUseOffsetToG(gNode) {
2910
3557
  return gNode;
2911
3558
  }
2912
3559
 
2913
- // src/PxAnimatorUseMaterialiser.ts
3560
+ // src/materialise/PxAnimatorUseMaterialiser.ts
2914
3561
  function materialiseAnimatedUseInstances(root) {
2915
- var _a;
3562
+ var _a2;
2916
3563
  const idMap = buildIdMap(root);
2917
3564
  const animatedIds = computeAnimatedSubtreeIds(root, idMap);
2918
3565
  if (animatedIds.size === 0) return root;
@@ -2923,7 +3570,7 @@ function materialiseAnimatedUseInstances(root) {
2923
3570
  const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
2924
3571
  if (defsCollector.length === 0) return walked;
2925
3572
  const defsNode = { type: "defs", children: defsCollector };
2926
- const newChildren = [...(_a = walked.children) != null ? _a : [], defsNode];
3573
+ const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
2927
3574
  return __spreadProps(__spreadValues({}, walked), { children: newChildren });
2928
3575
  }
2929
3576
  function readRootViewport(root) {
@@ -2945,9 +3592,9 @@ function numericAttr(v) {
2945
3592
  function buildIdMap(root) {
2946
3593
  const map = /* @__PURE__ */ new Map();
2947
3594
  const visit = (n) => {
2948
- var _a;
3595
+ var _a2;
2949
3596
  if (typeof n.id === "string") map.set(n.id, n);
2950
- (_a = n.children) == null ? void 0 : _a.forEach(visit);
3597
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
2951
3598
  };
2952
3599
  visit(root);
2953
3600
  return map;
@@ -2994,11 +3641,11 @@ function stripHash(href) {
2994
3641
  return href.startsWith("#") ? href.slice(1) : href;
2995
3642
  }
2996
3643
  function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
2997
- var _a, _b, _c, _d;
3644
+ var _a2, _b, _c, _d;
2998
3645
  const clone2 = deepClonePxNode(target);
2999
3646
  regenerateIdsAndRewriteRefs(clone2, genId3);
3000
3647
  const symbolViewBox = clone2.type === "symbol" ? parseViewBox(clone2.viewBox) : void 0;
3001
- const useW = (_b = (_a = numericAttr(useNode.width)) != null ? _a : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3648
+ const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3002
3649
  const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
3003
3650
  const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
3004
3651
  const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
@@ -3058,7 +3705,7 @@ function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector, ro
3058
3705
  return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
3059
3706
  }
3060
3707
 
3061
- // src/effects/transformParts.ts
3708
+ // src/effects/shared/transformParts.ts
3062
3709
  function partsRecord(part, value, origin) {
3063
3710
  const rec = {};
3064
3711
  if (part === "translate" /* Translate */) rec.translate = value;
@@ -3069,25 +3716,25 @@ function partsRecord(part, value, origin) {
3069
3716
  return rec;
3070
3717
  }
3071
3718
  function readAnimatable(raw) {
3072
- var _a, _b, _c;
3719
+ var _a2, _b;
3073
3720
  if (raw === void 0) return { kind: "absent" /* Absent */ };
3074
3721
  if (Array.isArray(raw)) return { kind: "static" /* Static */, value: raw };
3075
3722
  if (typeof raw === "object") {
3076
3723
  const obj = raw;
3077
- const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
3724
+ const kfs = obj.keyframes;
3078
3725
  if (kfs) {
3079
3726
  const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3080
- const base = (_b = obj.value) != null ? _b : obj.v;
3727
+ const base = (_a2 = obj.value) != null ? _a2 : obj.v;
3081
3728
  if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
3082
3729
  return out;
3083
3730
  }
3084
- const staticValue = (_c = obj.value) != null ? _c : obj.v;
3731
+ const staticValue = (_b = obj.value) != null ? _b : obj.v;
3085
3732
  if (staticValue !== void 0) return { kind: "static" /* Static */, value: staticValue };
3086
3733
  }
3087
3734
  return { kind: "static" /* Static */, value: raw };
3088
3735
  }
3089
3736
  function writeAnimatableChannel(node, attrName, read, opts) {
3090
- var _a, _b, _c, _d;
3737
+ var _a2, _b, _c, _d;
3091
3738
  const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
3092
3739
  if (read.kind === "absent" /* Absent */) return;
3093
3740
  if (read.kind === "static" /* Static */) {
@@ -3101,7 +3748,7 @@ function writeAnimatableChannel(node, attrName, read, opts) {
3101
3748
  if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
3102
3749
  animate[attrName] = block;
3103
3750
  node.animate = animate;
3104
- 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;
3751
+ const baseline = (_d = (_b = read.base) != null ? _b : (_a2 = read.keyframes[0]) == null ? void 0 : _a2.value) != null ? _d : (_c = read.keyframes[0]) == null ? void 0 : _c.v;
3105
3752
  if (baseline !== void 0) node[attrName] = toOut(baseline);
3106
3753
  }
3107
3754
  function normaliseKeyframe(kf) {
@@ -3119,12 +3766,12 @@ function normaliseKeyframe(kf) {
3119
3766
  return out;
3120
3767
  }
3121
3768
  function readStaticOrigin(raw, ctx) {
3122
- var _a;
3769
+ var _a2;
3123
3770
  const o = readAnimatable(raw);
3124
3771
  if (o.kind === "absent" /* Absent */) return void 0;
3125
3772
  if (o.kind === "static" /* Static */) return o.value;
3126
3773
  ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
3127
- return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
3774
+ return (_a2 = o.keyframes[0]) == null ? void 0 : _a2.value;
3128
3775
  }
3129
3776
  function keyframeWith(kf, value) {
3130
3777
  const out = { value };
@@ -3135,7 +3782,7 @@ function keyframeWith(kf, value) {
3135
3782
  return out;
3136
3783
  }
3137
3784
 
3138
- // src/effects/transformationEffect.ts
3785
+ // src/effects/transform/transformationEffect.ts
3139
3786
  function applyTransformByEffect(node, fx, ctx) {
3140
3787
  if (!fx) return node;
3141
3788
  delete node.transform;
@@ -3226,7 +3873,7 @@ function wrapOrigin(inner, raw, invert) {
3226
3873
  return inner;
3227
3874
  }
3228
3875
 
3229
- // src/effects/util.ts
3876
+ // src/effects/shared/util.ts
3230
3877
  function genId(ctx, prefix) {
3231
3878
  return "_lw_" + prefix + "_" + ctx.nextId++;
3232
3879
  }
@@ -3234,9 +3881,9 @@ function stripHash2(href) {
3234
3881
  return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3235
3882
  }
3236
3883
  function indexById(node, map) {
3237
- var _a;
3884
+ var _a2;
3238
3885
  if (typeof node.id === "string") map.set(node.id, node);
3239
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3886
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((child) => indexById(child, map));
3240
3887
  }
3241
3888
  function spliceDefs(root, defs) {
3242
3889
  if (!defs.length) return;
@@ -3248,11 +3895,11 @@ function regenerateIdsInClone(root, ctx) {
3248
3895
  return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3249
3896
  }
3250
3897
 
3251
- // src/effects/contentRefSplit.ts
3898
+ // src/effects/reference/contentRefSplit.ts
3252
3899
  function identifyContentRefTargets(node, ctx, allocator) {
3253
- var _a, _b, _c;
3254
- if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.type) === "content") {
3255
- const sourceId = stripHash2(node.effects.clone.sourceId);
3900
+ var _a2, _b, _c;
3901
+ if (node.type === "use" && ((_b = (_a2 = node.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.without) === "translate") {
3902
+ const sourceId = stripHash2(node.effects.clone.source);
3256
3903
  if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3257
3904
  ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
3258
3905
  }
@@ -3277,10 +3924,10 @@ function splitForContentRef(node, transformBy, originalId, innerId, ctx) {
3277
3924
  return outerWrapper;
3278
3925
  }
3279
3926
  function liftBodyTranslate(node, transformBy) {
3280
- var _a, _b, _c;
3927
+ var _a2, _b, _c;
3281
3928
  const out = {};
3282
3929
  let didLiftAnimate = false;
3283
- const animTr = (_a = node.animate) == null ? void 0 : _a.transform;
3930
+ const animTr = (_a2 = node.animate) == null ? void 0 : _a2.transform;
3284
3931
  if (animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes)) {
3285
3932
  const kfs = animTr.keyframes;
3286
3933
  const hasTranslate = kfs.some((kf) => kf.value && kf.value.translate);
@@ -3349,7 +3996,7 @@ function liftBodyTranslate(node, transformBy) {
3349
3996
  if (split.rest) node.transform = split.rest;
3350
3997
  else delete node.transform;
3351
3998
  }
3352
- } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes && !node.transform.kfs) {
3999
+ } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes) {
3353
4000
  const wrapped = node.transform.value;
3354
4001
  const isWrapped = !!(wrapped && typeof wrapped === "object");
3355
4002
  const value = isWrapped ? wrapped : node.transform;
@@ -3463,7 +4110,7 @@ function needsOriginOnOuter(translateAnim) {
3463
4110
  return false;
3464
4111
  }
3465
4112
 
3466
- // src/effects/gradientEffect.ts
4113
+ // src/effects/paint/gradientEffect.ts
3467
4114
  function applyFillGradientEffect(node, fx, ctx) {
3468
4115
  return applyGradient(node, fx, ctx, "fill");
3469
4116
  }
@@ -3484,12 +4131,12 @@ function synthesiseGradientDef(fx, id, ctx) {
3484
4131
  id
3485
4132
  };
3486
4133
  if (fx.type === PxGradientType.linear) {
3487
- applyGeomVec(out, "x1", "y1", fx.p1);
3488
- applyGeomVec(out, "x2", "y2", fx.p2);
4134
+ applyGeomVec(out, "x1", "y1", fx.start);
4135
+ applyGeomVec(out, "x2", "y2", fx.end);
3489
4136
  } else {
3490
- applyGeomVec(out, "cx", "cy", fx.c);
3491
- applyGeomNumber(out, "r", fx.r);
3492
- applyGeomVec(out, "fx", "fy", fx.fp);
4137
+ applyGeomVec(out, "cx", "cy", fx.center);
4138
+ applyGeomNumber(out, "r", fx.radius);
4139
+ applyGeomVec(out, "fx", "fy", fx.focal);
3493
4140
  }
3494
4141
  if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
3495
4142
  if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
@@ -3498,7 +4145,7 @@ function synthesiseGradientDef(fx, id, ctx) {
3498
4145
  return out;
3499
4146
  }
3500
4147
  function applyGeomVec(out, xAttr, yAttr, raw) {
3501
- var _a, _b, _c;
4148
+ var _a2, _b, _c;
3502
4149
  const read = readAnimatable(raw);
3503
4150
  if (read.kind === "absent" /* Absent */) return;
3504
4151
  if (read.kind === "static" /* Static */) {
@@ -3517,7 +4164,7 @@ function applyGeomVec(out, xAttr, yAttr, raw) {
3517
4164
  if (read.loop !== void 0) block.loop = read.loop;
3518
4165
  return block;
3519
4166
  };
3520
- const animate = (_a = out.animate) != null ? _a : {};
4167
+ const animate = (_a2 = out.animate) != null ? _a2 : {};
3521
4168
  animate[xAttr] = axisChannel(0);
3522
4169
  animate[yAttr] = axisChannel(1);
3523
4170
  out.animate = animate;
@@ -3533,7 +4180,7 @@ function applyGeomNumber(out, attrName, raw) {
3533
4180
  writeAnimatableChannel(out, attrName, read, { asString: true });
3534
4181
  }
3535
4182
  function buildStopChildren(stops, ctx) {
3536
- var _a, _b, _c, _d;
4183
+ var _a2, _b;
3537
4184
  if (!stops) return [];
3538
4185
  const read = readAnimatable(stops);
3539
4186
  if (read.kind === "absent" /* Absent */) return [];
@@ -3543,14 +4190,14 @@ function buildStopChildren(stops, ctx) {
3543
4190
  const loopFromSource = read.loop;
3544
4191
  let stopCount = 0;
3545
4192
  for (const kf of kfs) {
3546
- const v = (_a = kf.value) != null ? _a : kf.v;
4193
+ const v = kfValue(kf);
3547
4194
  if (Array.isArray(v) && v.length > stopCount) stopCount = v.length;
3548
4195
  }
3549
4196
  if (!stopCount) return [];
3550
- const firstKfValue = (_b = kfs[0].value) != null ? _b : kfs[0].v;
4197
+ const firstKfValue = kfValue(kfs[0]);
3551
4198
  const baselineStops = [];
3552
4199
  for (let i = 0; i < stopCount; i++) {
3553
- const s = (_d = (_c = firstKfValue == null ? void 0 : firstKfValue[i]) != null ? _c : prevDefinedStop(kfs, 0, i)) != null ? _d : { offset: i / Math.max(1, stopCount - 1), color: "#000000" };
4200
+ const s = (_b = (_a2 = firstKfValue == null ? void 0 : firstKfValue[i]) != null ? _a2 : prevDefinedStop(kfs, 0, i)) != null ? _b : { offset: i / Math.max(1, stopCount - 1), color: "#000000" };
3554
4201
  baselineStops.push({ offset: s.offset, color: s.color });
3555
4202
  }
3556
4203
  return baselineStops.map((bs, i) => animatedStopNode(bs, kfs, i, ctx, loopFromSource));
@@ -3563,16 +4210,16 @@ function staticStopNode(s) {
3563
4210
  };
3564
4211
  }
3565
4212
  function animatedStopNode(baseline, kfs, stopIdx, _ctx, loop) {
3566
- var _a, _b, _c, _d, _e;
4213
+ var _a2;
3567
4214
  const colorKfs = [];
3568
4215
  const offsetKfs = [];
3569
4216
  let offsetVaries = false;
3570
4217
  for (const kf of kfs) {
3571
- const t = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
3572
- const arr = (_c = kf.value) != null ? _c : kf.v;
3573
- const sliced = (_d = arr == null ? void 0 : arr[stopIdx]) != null ? _d : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
4218
+ const t = kfTime(kf);
4219
+ const arr = kfValue(kf);
4220
+ const sliced = (_a2 = arr == null ? void 0 : arr[stopIdx]) != null ? _a2 : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
3574
4221
  if (!sliced) continue;
3575
- const easing = (_e = kf.easing) != null ? _e : kf.e;
4222
+ const easing = kfEasing(kf);
3576
4223
  const colorOut = { time: t, value: sliced.color };
3577
4224
  if (easing !== void 0) colorOut.easing = easing;
3578
4225
  colorKfs.push(colorOut);
@@ -3599,13 +4246,12 @@ function animatedStopNode(baseline, kfs, stopIdx, _ctx, loop) {
3599
4246
  return stop;
3600
4247
  }
3601
4248
  function prevDefinedStop(kfs, fromIdx, stopIdx) {
3602
- var _a, _b;
3603
4249
  for (let i = fromIdx; i >= 0; i--) {
3604
- const arr = (_a = kfs[i].value) != null ? _a : kfs[i].v;
4250
+ const arr = kfValue(kfs[i]);
3605
4251
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3606
4252
  }
3607
4253
  for (let i = fromIdx + 1; i < kfs.length; i++) {
3608
- const arr = (_b = kfs[i].value) != null ? _b : kfs[i].v;
4254
+ const arr = kfValue(kfs[i]);
3609
4255
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3610
4256
  }
3611
4257
  return void 0;
@@ -3615,10 +4261,9 @@ function formatOffset(o) {
3615
4261
  return pct + "%";
3616
4262
  }
3617
4263
 
3618
- // src/effects/clipPathEffect.ts
4264
+ // src/effects/clipping/clipPathEffect.ts
3619
4265
  function applyClipPathEffect(node, fx, ctx) {
3620
- var _a, _b;
3621
- if (!fx || !fx.d && !fx.animate) return node;
4266
+ if (!(fx == null ? void 0 : fx.d)) return node;
3622
4267
  const clipId = genId(ctx, "clip");
3623
4268
  const pathChild = { type: "path" };
3624
4269
  const read = readAnimatable(fx.d);
@@ -3630,11 +4275,6 @@ function applyClipPathEffect(node, fx, ctx) {
3630
4275
  if (pathChild.d !== void 0) pathChild.d = pathString(pathChild.d);
3631
4276
  }
3632
4277
  }
3633
- if (fx.animate && !((_a = pathChild.animate) == null ? void 0 : _a.d)) {
3634
- const animate = (_b = pathChild.animate) != null ? _b : {};
3635
- animate.d = fx.animate;
3636
- pathChild.animate = animate;
3637
- }
3638
4278
  ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
3639
4279
  node.clipPath = "url(#" + clipId + ")";
3640
4280
  return node;
@@ -3645,12 +4285,12 @@ function pathString(v) {
3645
4285
  return void 0;
3646
4286
  }
3647
4287
 
3648
- // src/effects/maskedByEffect.ts
4288
+ // src/effects/clipping/maskedByEffect.ts
3649
4289
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
3650
4290
  if (!fx) return node;
3651
- const sourceId = stripHash2(fx.sourceId);
4291
+ const sourceId = stripHash2(fx.source);
3652
4292
  if (!sourceId) {
3653
- ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
4293
+ ctx.errors.push("maskedBy.source missing \u2014 cannot build mask");
3654
4294
  return node;
3655
4295
  }
3656
4296
  const maskId = genId(ctx, "mask");
@@ -3713,16 +4353,16 @@ function invertPartValue(part, value) {
3713
4353
  return [1 / value[0], 1 / value[1]];
3714
4354
  }
3715
4355
  function negatedSpatialTangents(kf) {
3716
- var _a, _b;
4356
+ var _a2, _b;
3717
4357
  const out = {};
3718
- const to = (_a = kf.tangentOut) != null ? _a : kf.to;
4358
+ const to = (_a2 = kf.tangentOut) != null ? _a2 : kf.to;
3719
4359
  const ti = (_b = kf.tangentIn) != null ? _b : kf.ti;
3720
4360
  if (Array.isArray(to)) out.tangentOut = [-to[0], -to[1]];
3721
4361
  if (Array.isArray(ti)) out.tangentIn = [-ti[0], -ti[1]];
3722
4362
  return out;
3723
4363
  }
3724
4364
  function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
3725
- var _a;
4365
+ var _a2;
3726
4366
  const animate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3727
4367
  const animTr = animate == null ? void 0 : animate.transform;
3728
4368
  const kfs = animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes) ? animTr.keyframes : void 0;
@@ -3731,7 +4371,7 @@ function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
3731
4371
  const rotateKfs = [];
3732
4372
  const scaleKfs = [];
3733
4373
  for (const kf of kfs) {
3734
- const v = ((_a = kf.value) != null ? _a : kf.v) || {};
4374
+ const v = ((_a2 = kf.value) != null ? _a2 : kf.v) || {};
3735
4375
  const baseKf = keyframeWith(kf, void 0);
3736
4376
  if (Array.isArray(v.translate)) {
3737
4377
  translateKfs.push(__spreadProps(__spreadValues(__spreadValues({}, baseKf), negatedSpatialTangents(kf)), { value: { translate: [-v.translate[0], -v.translate[1]] } }));
@@ -3779,7 +4419,7 @@ function readTransformationFromBody(node) {
3779
4419
  if (parts.origin) out.origin = parts.origin;
3780
4420
  return Object.keys(out).length ? out : void 0;
3781
4421
  }
3782
- if (node.transform && typeof node.transform === "object" && !node.transform.keyframes && !node.transform.kfs) {
4422
+ if (node.transform && typeof node.transform === "object" && !node.transform.keyframes) {
3783
4423
  const wrapped = node.transform.value;
3784
4424
  const value = wrapped && typeof wrapped === "object" ? wrapped : node.transform;
3785
4425
  if (value && typeof value === "object") {
@@ -3795,7 +4435,7 @@ function readTransformationFromBody(node) {
3795
4435
  return void 0;
3796
4436
  }
3797
4437
  function parseTransformStringToParts(s) {
3798
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
4438
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
3799
4439
  const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
3800
4440
  let m;
3801
4441
  const ops = [];
@@ -3809,7 +4449,7 @@ function parseTransformStringToParts(s) {
3809
4449
  for (let j = ops.length - 2; j >= 0; j--) {
3810
4450
  const cand = ops[j];
3811
4451
  if (cand.name !== "translate") continue;
3812
- const ox = (_a = cand.args[0]) != null ? _a : 0;
4452
+ const ox = (_a2 = cand.args[0]) != null ? _a2 : 0;
3813
4453
  const oy = (_b = cand.args[1]) != null ? _b : 0;
3814
4454
  const lx = (_c = last.args[0]) != null ? _c : 0;
3815
4455
  const ly = (_d = last.args[1]) != null ? _d : 0;
@@ -3924,8 +4564,8 @@ function interpKfs(kfs, t) {
3924
4564
  function collectMaskAncestorChains(root, ctx) {
3925
4565
  const interestingNodes = /* @__PURE__ */ new Set();
3926
4566
  const collectInterestingNodes = (n) => {
3927
- var _a, _b;
3928
- const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.sourceId);
4567
+ var _a2, _b;
4568
+ const maskSourceId = stripHash2((_b = (_a2 = n.effects) == null ? void 0 : _a2.maskedBy) == null ? void 0 : _b.source);
3929
4569
  if (typeof maskSourceId === "string") {
3930
4570
  interestingNodes.add(n);
3931
4571
  const sourceNode = ctx.idMap.get(maskSourceId);
@@ -3946,7 +4586,7 @@ function collectMaskAncestorChains(root, ctx) {
3946
4586
  walk(root, []);
3947
4587
  }
3948
4588
  function extractTranslateOnly(node, ctx) {
3949
- var _a, _b, _c;
4589
+ var _a2, _b, _c;
3950
4590
  const tr = node.transform;
3951
4591
  const animateBlock = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate.transform : void 0;
3952
4592
  if (tr === void 0 && !animateBlock) return void 0;
@@ -3954,7 +4594,7 @@ function extractTranslateOnly(node, ctx) {
3954
4594
  if (typeof tr === "string") {
3955
4595
  const parts = parseTranslateOnlyFromString(tr, ctx);
3956
4596
  if (parts) out.translate = parts;
3957
- } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
4597
+ } else if (tr && typeof tr === "object" && !tr.keyframes) {
3958
4598
  const wrapped = tr.value;
3959
4599
  const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
3960
4600
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
@@ -3968,7 +4608,7 @@ function extractTranslateOnly(node, ctx) {
3968
4608
  const kfs = animateBlock.keyframes;
3969
4609
  const translateKfs = [];
3970
4610
  for (const kf of kfs) {
3971
- const v = (_a = kf.value) != null ? _a : kf.v;
4611
+ const v = (_a2 = kf.value) != null ? _a2 : kf.v;
3972
4612
  const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
3973
4613
  if (v && typeof v === "object" && Array.isArray(v.translate)) {
3974
4614
  translateKfs.push({ time: t, value: [v.translate[0] || 0, v.translate[1] || 0] });
@@ -4002,16 +4642,15 @@ function parseTranslateOnlyFromString(s, ctx) {
4002
4642
  return seen ? [x, y] : void 0;
4003
4643
  }
4004
4644
 
4005
- // src/effects/refEffect.ts
4006
- var CONTENT_SUBREF = "content";
4645
+ // src/effects/reference/refEffect.ts
4007
4646
  function applyRefHref(node, clone2, ctx) {
4008
4647
  if (!clone2) return;
4009
- const sourceId = stripHash2(clone2.sourceId);
4648
+ const sourceId = stripHash2(clone2.source);
4010
4649
  if (!sourceId) {
4011
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
4650
+ if (clone2.without === PxCloneWithout.translate) ctx.errors.push("clone: content ref missing `source`");
4012
4651
  return;
4013
4652
  }
4014
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4653
+ const targetId = clone2.without === PxCloneWithout.translate ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4015
4654
  node.href = "#" + targetId;
4016
4655
  }
4017
4656
  function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
@@ -4019,11 +4658,11 @@ function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
4019
4658
  return applyTransformByEffect(node, transformBy, ctx);
4020
4659
  }
4021
4660
 
4022
- // src/effects/repeaterEffect.ts
4661
+ // src/effects/transform/repeaterEffect.ts
4023
4662
  function applyRepeaterEffect(node, fx, ctx) {
4024
- var _a, _b;
4663
+ var _a2, _b;
4025
4664
  if (!fx) return node;
4026
- const copies = (_a = fx.copies) != null ? _a : 1;
4665
+ const copies = (_a2 = fx.copies) != null ? _a2 : 1;
4027
4666
  if (copies < 1) {
4028
4667
  ctx.errors.push("repeater.copies invalid: " + fx.copies);
4029
4668
  return node;
@@ -4090,11 +4729,11 @@ function synthesiseScale(raw, i) {
4090
4729
  return mapAnimatable(raw, scalePower, true);
4091
4730
  }
4092
4731
 
4093
- // src/effects/retimeEffect.ts
4732
+ // src/effects/reference/retimeEffect.ts
4094
4733
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
4095
4734
  function asRetime(r) {
4096
- var _a, _b;
4097
- return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
4735
+ var _a2, _b;
4736
+ return { start: (_a2 = r.start) != null ? _a2 : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
4098
4737
  }
4099
4738
  var CROP_EDGE_MS = 1;
4100
4739
  function applyTimeCrop(useNode, crop, ctx) {
@@ -4122,12 +4761,12 @@ function concatRetime(child, parent) {
4122
4761
  };
4123
4762
  }
4124
4763
  function readCloneRetime(n) {
4125
- var _a, _b;
4126
- return (_b = (_a = n.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.retime;
4764
+ var _a2, _b;
4765
+ return (_b = (_a2 = n.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.retime;
4127
4766
  }
4128
4767
  function clearCloneRetime(n) {
4129
- var _a;
4130
- const clone2 = (_a = n.effects) == null ? void 0 : _a.clone;
4768
+ var _a2;
4769
+ const clone2 = (_a2 = n.effects) == null ? void 0 : _a2.clone;
4131
4770
  if (!clone2) return;
4132
4771
  delete clone2.retime;
4133
4772
  if (Object.keys(clone2).length === 0) delete n.effects.clone;
@@ -4138,9 +4777,9 @@ function applyAllRetimeEffects(root, ctx) {
4138
4777
  indexById(root, ctx.idMap);
4139
4778
  const sites = [];
4140
4779
  const collect = (n) => {
4141
- var _a;
4780
+ var _a2;
4142
4781
  if (readCloneRetime(n)) sites.push(n);
4143
- (_a = n.children) == null ? void 0 : _a.forEach(collect);
4782
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(collect);
4144
4783
  };
4145
4784
  collect(root);
4146
4785
  const reachCount = /* @__PURE__ */ new Map();
@@ -4148,7 +4787,7 @@ function applyAllRetimeEffects(root, ctx) {
4148
4787
  let count = 0;
4149
4788
  const visited = /* @__PURE__ */ new Set();
4150
4789
  const walk = (n) => {
4151
- var _a;
4790
+ var _a2;
4152
4791
  if (!n) return;
4153
4792
  if (n !== site && readCloneRetime(n)) count++;
4154
4793
  if (n.type === "use" && n.href) {
@@ -4158,7 +4797,7 @@ function applyAllRetimeEffects(root, ctx) {
4158
4797
  walk(ctx.idMap.get(id));
4159
4798
  }
4160
4799
  }
4161
- (_a = n.children) == null ? void 0 : _a.forEach(walk);
4800
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walk);
4162
4801
  };
4163
4802
  const rootId = stripHash2(site.href);
4164
4803
  if (rootId) {
@@ -4168,8 +4807,8 @@ function applyAllRetimeEffects(root, ctx) {
4168
4807
  reachCount.set(site, count);
4169
4808
  }
4170
4809
  sites.sort((a, b) => {
4171
- var _a, _b;
4172
- return ((_a = reachCount.get(b)) != null ? _a : 0) - ((_b = reachCount.get(a)) != null ? _b : 0);
4810
+ var _a2, _b;
4811
+ return ((_a2 = reachCount.get(b)) != null ? _a2 : 0) - ((_b = reachCount.get(a)) != null ? _b : 0);
4173
4812
  });
4174
4813
  for (const useNode of sites) {
4175
4814
  const retime = readCloneRetime(useNode);
@@ -4236,7 +4875,7 @@ function buildChainClone(targetId, accum, ctx, chain) {
4236
4875
  }
4237
4876
  function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4238
4877
  const visit = (n) => {
4239
- var _a;
4878
+ var _a2;
4240
4879
  const retime = readCloneRetime(n);
4241
4880
  if (n.type === "use" && retime && n.href) {
4242
4881
  const subId = stripHash2(n.href);
@@ -4249,14 +4888,14 @@ function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4249
4888
  }
4250
4889
  clearCloneRetime(n);
4251
4890
  }
4252
- (_a = n.children) == null ? void 0 : _a.forEach(visit);
4891
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
4253
4892
  };
4254
4893
  visit(node);
4255
4894
  }
4256
4895
  function remapKeyframeTimes(node, start, stretch) {
4257
- var _a;
4896
+ var _a2;
4258
4897
  remapKeyframeTimesOnly(node, start, stretch);
4259
- (_a = node.children) == null ? void 0 : _a.forEach((c) => remapKeyframeTimes(c, start, stretch));
4898
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => remapKeyframeTimes(c, start, stretch));
4260
4899
  }
4261
4900
  function remapKeyframeTimesOnly(node, start, stretch) {
4262
4901
  const remap2 = (kfs) => {
@@ -4273,7 +4912,7 @@ function remapKeyframeTimesOnly(node, start, stretch) {
4273
4912
  }
4274
4913
  }
4275
4914
 
4276
- // src/effects/pathSampler.ts
4915
+ // src/effects/text/pathSampler.ts
4277
4916
  var LUT_STEPS = 48;
4278
4917
  var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
4279
4918
  function tokenize(d) {
@@ -4421,7 +5060,7 @@ function createPathSampler(d) {
4421
5060
  };
4422
5061
  }
4423
5062
 
4424
- // src/effects/textPathEffect.ts
5063
+ // src/effects/text/textPathEffect.ts
4425
5064
  var EXTEND_MARGIN_FRAC = 0.15;
4426
5065
  function numRange(v) {
4427
5066
  const read = readAnimatable(v);
@@ -4435,8 +5074,8 @@ function numRange(v) {
4435
5074
  function estimateTextAdvance(node) {
4436
5075
  let chars = 0, maxFont = 16;
4437
5076
  const walk = (el) => {
4438
- var _a, _b;
4439
- const fs = parseFloat(String((_a = el.fontSize) != null ? _a : "")) || 0;
5077
+ var _a2, _b;
5078
+ const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
4440
5079
  if (fs) maxFont = Math.max(maxFont, fs);
4441
5080
  const t = (_b = el.text) != null ? _b : el.textContent;
4442
5081
  if (typeof t === "string") chars += t.length;
@@ -4460,14 +5099,14 @@ function shiftAnimatable(v, by) {
4460
5099
  return out;
4461
5100
  }
4462
5101
  function extendedPathForBrowser(pathD, opts) {
4463
- var _a;
5102
+ var _a2;
4464
5103
  if (opts.pathOverflow === "clip") return { d: pathD, startShift: 0 };
4465
5104
  const sampler = createPathSampler(pathD);
4466
5105
  if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };
4467
5106
  const L = sampler.totalLength;
4468
5107
  const margin = EXTEND_MARGIN_FRAC * L;
4469
5108
  const so = numRange(opts.startOffset);
4470
- const runWidth = numRange(opts.textLength).max || ((_a = opts.advance) != null ? _a : 0);
5109
+ const runWidth = numRange(opts.textLength).max || ((_a2 = opts.advance) != null ? _a2 : 0);
4471
5110
  const startOverflow = Math.max(0, -so.min);
4472
5111
  const endOverflow = Math.max(0, so.max + runWidth - L);
4473
5112
  const startExt = startOverflow > 0 ? startOverflow + margin : 0;
@@ -4488,10 +5127,10 @@ function extendedPathForBrowser(pathD, opts) {
4488
5127
  return { d, startShift: startExt };
4489
5128
  }
4490
5129
  function applyTextPathEffect(node, fx, ctx) {
4491
- var _a;
4492
- if (!fx || typeof fx.path !== "string" || !fx.path) return node;
5130
+ var _a2;
5131
+ if (!fx || typeof fx.pathData !== "string" || !fx.pathData) return node;
4493
5132
  const pathId = genId(ctx, "tpath");
4494
- const { d, startShift } = extendedPathForBrowser(fx.path, {
5133
+ const { d, startShift } = extendedPathForBrowser(fx.pathData, {
4495
5134
  pathOverflow: fx.pathOverflow,
4496
5135
  startOffset: fx.startOffset,
4497
5136
  textLength: fx.textLength,
@@ -4501,7 +5140,7 @@ function applyTextPathEffect(node, fx, ctx) {
4501
5140
  const textPath = {
4502
5141
  type: "textPath",
4503
5142
  href: "#" + pathId,
4504
- children: (_a = node.children) != null ? _a : []
5143
+ children: (_a2 = node.children) != null ? _a2 : []
4505
5144
  };
4506
5145
  if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
4507
5146
  if (fx.method !== void 0) textPath.method = fx.method;
@@ -4516,7 +5155,7 @@ function applyAnimatableNumber(node, attrName, raw) {
4516
5155
  writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
4517
5156
  }
4518
5157
 
4519
- // src/effects/elementFactory.ts
5158
+ // src/effects/text/elementFactory.ts
4520
5159
  var jsonElementFactory = (type, props, children) => {
4521
5160
  const node = { type };
4522
5161
  for (const k in props) if (props[k] !== void 0) node[k] = props[k];
@@ -4525,7 +5164,7 @@ var jsonElementFactory = (type, props, children) => {
4525
5164
  return node;
4526
5165
  };
4527
5166
 
4528
- // src/effects/glyphPathBake.ts
5167
+ // src/effects/text/glyphPathBake.ts
4529
5168
  function fmt(v, decimals) {
4530
5169
  return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
4531
5170
  }
@@ -4571,7 +5210,7 @@ function transformPathData(d, m, decimals = 2) {
4571
5210
  return out;
4572
5211
  }
4573
5212
 
4574
- // src/effects/textGlyphsEffect.ts
5213
+ // src/effects/text/textGlyphsEffect.ts
4575
5214
  var DEFAULT_FONT_SIZE = 16;
4576
5215
  var TEXT_ATTR_KEYS = [
4577
5216
  "fontFamily",
@@ -4631,15 +5270,15 @@ function paintAnimateOf(node) {
4631
5270
  return out;
4632
5271
  }
4633
5272
  function resolveStyle2(node, parent) {
4634
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5273
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
4635
5274
  const isTextRoot = node.type === "text";
4636
5275
  const nodeStyle = node.style;
4637
5276
  const own = (key) => {
4638
- var _a2;
4639
- return isTextRoot ? void 0 : (_a2 = node[key]) != null ? _a2 : nodeStyle == null ? void 0 : nodeStyle[key];
5277
+ var _a3;
5278
+ return isTextRoot ? void 0 : (_a3 = node[key]) != null ? _a3 : nodeStyle == null ? void 0 : nodeStyle[key];
4640
5279
  };
4641
5280
  const res = {
4642
- fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
5281
+ fontFamily: (_a2 = str(node.fontFamily)) != null ? _a2 : parent.fontFamily,
4643
5282
  fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
4644
5283
  fill: (_c = node.fill) != null ? _c : parent.fill,
4645
5284
  stroke: (_d = node.stroke) != null ? _d : parent.stroke,
@@ -4656,10 +5295,10 @@ function resolveStyle2(node, parent) {
4656
5295
  return res;
4657
5296
  }
4658
5297
  function rootStyleOf(node) {
4659
- var _a, _b, _c;
5298
+ var _a2, _b, _c;
4660
5299
  return {
4661
5300
  fontFamily: str(node.fontFamily),
4662
- fontSize: (_a = parseLen(node.fontSize)) != null ? _a : DEFAULT_FONT_SIZE,
5301
+ fontSize: (_a2 = parseLen(node.fontSize)) != null ? _a2 : DEFAULT_FONT_SIZE,
4663
5302
  fill: node.fill,
4664
5303
  stroke: node.stroke,
4665
5304
  strokeWidth: node.strokeWidth,
@@ -4680,9 +5319,9 @@ function paintOf(s) {
4680
5319
  return p;
4681
5320
  }
4682
5321
  function glyphFontFor(s, glyphs, soleFont, warnings) {
4683
- var _a;
5322
+ var _a2;
4684
5323
  const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;
4685
- if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a = s.fontFamily) != null ? _a : "") + '"');
5324
+ if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a2 = s.fontFamily) != null ? _a2 : "") + '"');
4686
5325
  return gf;
4687
5326
  }
4688
5327
  function soleFontOf(glyphs) {
@@ -4704,19 +5343,19 @@ function missingGlyphBoxEm(advanceEm, ascentEm) {
4704
5343
  return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
4705
5344
  }
4706
5345
  function materialiseGlyphTextHorizontal(node, opts) {
4707
- var _a, _b, _c, _d;
5346
+ var _a2, _b, _c, _d;
4708
5347
  const { glyphs, create = jsonElementFactory, warnings } = opts;
4709
5348
  const soleFont = soleFontOf(glyphs);
4710
- const pen = { x: (_a = parseLen(node.x)) != null ? _a : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
5349
+ const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
4711
5350
  const placements = [];
4712
5351
  const lines = [{ start: pen.x, end: pen.x }];
4713
5352
  let line = 0;
4714
5353
  const renderChars = (content, s) => {
4715
- var _a2;
5354
+ var _a3;
4716
5355
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4717
5356
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4718
5357
  const scale = s.fontSize / upm;
4719
- const ascentEm = (_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm;
5358
+ const ascentEm = (_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm;
4720
5359
  const paint = paintOf(s);
4721
5360
  for (let i = 0; i < content.length; i++) {
4722
5361
  const ch = content.charAt(i);
@@ -4736,7 +5375,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4736
5375
  }
4737
5376
  };
4738
5377
  const walk = (el, parentStyle) => {
4739
- var _a2, _b2, _c2, _d2;
5378
+ var _a3, _b2, _c2, _d2;
4740
5379
  const s = resolveStyle2(el, parentStyle);
4741
5380
  const x = parseLen(el.x);
4742
5381
  const y = parseLen(el.y);
@@ -4746,7 +5385,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4746
5385
  lines.push({ start: pen.x, end: pen.x });
4747
5386
  }
4748
5387
  if (y !== void 0) pen.y = y;
4749
- pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
5388
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4750
5389
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4751
5390
  const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4752
5391
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
@@ -4767,8 +5406,8 @@ function materialiseGlyphTextHorizontal(node, opts) {
4767
5406
  return toGroup(node, buildPaths(placements, create, warnings), create);
4768
5407
  }
4769
5408
  function layoutGlyphTextChars(node, opts) {
4770
- var _a, _b, _c, _d, _e, _f;
4771
- if ((_a = opts.alongPath) == null ? void 0 : _a.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
5409
+ var _a2, _b, _c, _d, _e, _f;
5410
+ if ((_a2 = opts.alongPath) == null ? void 0 : _a2.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
4772
5411
  const { glyphs, warnings } = opts;
4773
5412
  const soleFont = soleFontOf(glyphs);
4774
5413
  const pen = { x: (_b = parseLen(node.x)) != null ? _b : 0, y: (_c = parseLen(node.y)) != null ? _c : 0 };
@@ -4776,11 +5415,11 @@ function layoutGlyphTextChars(node, opts) {
4776
5415
  const lines = [{ start: pen.x, end: pen.x }];
4777
5416
  let line = 0;
4778
5417
  const renderChars = (content, s) => {
4779
- var _a2;
5418
+ var _a3;
4780
5419
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4781
5420
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4782
5421
  const scale = s.fontSize / upm;
4783
- const ascent = ((_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm) * scale;
5422
+ const ascent = ((_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm) * scale;
4784
5423
  for (let i = 0; i < content.length; i++) {
4785
5424
  const ch = content.charAt(i);
4786
5425
  const g = gf == null ? void 0 : gf.glyphs[ch];
@@ -4791,7 +5430,7 @@ function layoutGlyphTextChars(node, opts) {
4791
5430
  }
4792
5431
  };
4793
5432
  const walk = (el, parentStyle) => {
4794
- var _a2, _b2, _c2, _d2;
5433
+ var _a3, _b2, _c2, _d2;
4795
5434
  const s = resolveStyle2(el, parentStyle);
4796
5435
  const x = parseLen(el.x);
4797
5436
  const y = parseLen(el.y);
@@ -4801,7 +5440,7 @@ function layoutGlyphTextChars(node, opts) {
4801
5440
  lines.push({ start: pen.x, end: pen.x });
4802
5441
  }
4803
5442
  if (y !== void 0) pen.y = y;
4804
- pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
5443
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4805
5444
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4806
5445
  const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4807
5446
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
@@ -4833,7 +5472,7 @@ function layoutGlyphTextChars(node, opts) {
4833
5472
  });
4834
5473
  }
4835
5474
  function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4836
- var _a, _b;
5475
+ var _a2, _b;
4837
5476
  const { glyphs, warnings, alongPath } = opts;
4838
5477
  const sampler = createPathSampler(pathD);
4839
5478
  if (!sampler) {
@@ -4844,9 +5483,9 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4844
5483
  const chars = [];
4845
5484
  let adv = 0;
4846
5485
  const walk = (el, parentStyle) => {
4847
- var _a2, _b2, _c;
5486
+ var _a3, _b2, _c;
4848
5487
  const s = resolveStyle2(el, parentStyle);
4849
- const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
5488
+ const content = (_a3 = str(el[TEXT_CONTENT_ATTR])) != null ? _a3 : str(el[TEXT_ATTR]);
4850
5489
  if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
4851
5490
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4852
5491
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
@@ -4866,7 +5505,7 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4866
5505
  walk(node, rootStyleOf(node));
4867
5506
  const width = adv;
4868
5507
  const tlr = readAnimatable(alongPath == null ? void 0 : alongPath.textLength);
4869
- const tlv = tlr.kind === "animated" /* Animated */ ? Number((_a = tlr.keyframes[0]) == null ? void 0 : _a.value) || 0 : tlr.kind === "static" /* Static */ ? Number(tlr.value) || 0 : 0;
5508
+ const tlv = tlr.kind === "animated" /* Animated */ ? Number((_a2 = tlr.keyframes[0]) == null ? void 0 : _a2.value) || 0 : tlr.kind === "static" /* Static */ ? Number(tlr.value) || 0 : 0;
4870
5509
  const k = tlv > 0 && width > 0 ? tlv / width : 1;
4871
5510
  const so = readAnimatable(alongPath == null ? void 0 : alongPath.startOffset);
4872
5511
  const { along: alongOffset, perp } = alongPathNodeOffsets(node);
@@ -4898,9 +5537,9 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4898
5537
  const cells = [];
4899
5538
  let adv = 0;
4900
5539
  const walk = (el, parentStyle) => {
4901
- var _a, _b, _c;
5540
+ var _a2, _b, _c;
4902
5541
  const s = resolveStyle2(el, parentStyle);
4903
- const content = (_a = str(el[TEXT_CONTENT_ATTR])) != null ? _a : str(el[TEXT_ATTR]);
5542
+ const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
4904
5543
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
4905
5544
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4906
5545
  if (gf) {
@@ -4937,9 +5576,9 @@ function alongAffine(sampler, dist, scale, widthEm, perp = 0) {
4937
5576
  return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];
4938
5577
  }
4939
5578
  function alongPathNodeOffsets(node) {
4940
- var _a, _b, _c;
5579
+ var _a2, _b, _c;
4941
5580
  return {
4942
- along: ((_a = parseLen(node.x)) != null ? _a : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
5581
+ along: ((_a2 = parseLen(node.x)) != null ? _a2 : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
4943
5582
  perp: (_c = parseLen(node.dy)) != null ? _c : 0
4944
5583
  };
4945
5584
  }
@@ -4979,7 +5618,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
4979
5618
  return toGroup(node, buildPaths(placements, create, warnings), create);
4980
5619
  }
4981
5620
  function numTrackOf(raw) {
4982
- var _a;
5621
+ var _a2;
4983
5622
  const r = readAnimatable(raw);
4984
5623
  if (r.kind === "animated" /* Animated */ && r.keyframes.length >= 2) {
4985
5624
  const kfs = [...r.keyframes].sort((k1, k2) => (Number(k1.time) || 0) - (Number(k2.time) || 0));
@@ -5002,7 +5641,7 @@ function numTrackOf(raw) {
5002
5641
  }
5003
5642
  };
5004
5643
  }
5005
- const v = r.kind === "animated" /* Animated */ ? Number((_a = r.keyframes[0]) == null ? void 0 : _a.value) || 0 : r.kind === "static" /* Static */ ? Number(r.value) || 0 : 0;
5644
+ const v = r.kind === "animated" /* Animated */ ? Number((_a2 = r.keyframes[0]) == null ? void 0 : _a2.value) || 0 : r.kind === "static" /* Static */ ? Number(r.value) || 0 : 0;
5006
5645
  return { animated: false, times: [], at: () => v };
5007
5646
  }
5008
5647
  function mergeTrackTimes(a, b) {
@@ -5078,7 +5717,7 @@ function paintProps(paint) {
5078
5717
  return p;
5079
5718
  }
5080
5719
  function missingGlyphProps(isMissing) {
5081
- return isMissing ? { class: MISSING_GLYPH_CLASS_NAME } : {};
5720
+ return isMissing ? { [CLASS_ATTR]: MISSING_GLYPH_CLASS_NAME } : {};
5082
5721
  }
5083
5722
  function buildPaths(placements, create, warnings) {
5084
5723
  if (!placements.length) {
@@ -5122,20 +5761,20 @@ function materialiseGlyphText(node, opts) {
5122
5761
  function applyTextGlyphsEffect(node, fx, ctx) {
5123
5762
  if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
5124
5763
  if (!ctx.glyphs) {
5125
- ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
5764
+ ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
5126
5765
  return node;
5127
5766
  }
5128
5767
  return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5129
5768
  }
5130
5769
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
5131
5770
  if (!ctx.glyphs) {
5132
- ctx.warnings.push("textGlyphs: no definitions.glyphs");
5771
+ ctx.warnings.push("textGlyphs: no definitions.fonts");
5133
5772
  return null;
5134
5773
  }
5135
5774
  return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5136
5775
  }
5137
5776
 
5138
- // src/effects/strokeTrimEffect.ts
5777
+ // src/effects/stroke/strokeTrimEffect.ts
5139
5778
  function applyStrokeTrimEffect(node, strokeTrim, ctx) {
5140
5779
  if (!strokeTrim) return node;
5141
5780
  const combined = strokeTrim.subPaths === PxStrokeTrimSubPaths.combined;
@@ -5271,12 +5910,11 @@ function getOffsetIndexRange(minMaxOffset) {
5271
5910
  ];
5272
5911
  }
5273
5912
  function readScalarValues(r) {
5274
- var _a;
5275
5913
  if (r.kind === "absent" /* Absent */) return [];
5276
5914
  if (r.kind === "static" /* Static */) return [r.value];
5277
5915
  const out = [];
5278
5916
  for (const kf of r.keyframes) {
5279
- const v = (_a = kf.value) != null ? _a : kf.v;
5917
+ const v = kfValue(kf);
5280
5918
  if (typeof v === "number") out.push(v);
5281
5919
  }
5282
5920
  return out;
@@ -5286,14 +5924,11 @@ function computeAnimAttr(read, map) {
5286
5924
  if (read.kind === "static" /* Static */) return { kind: "static" /* Static */, value: map(read.value) };
5287
5925
  return {
5288
5926
  kind: "animated" /* Animated */,
5289
- keyframes: read.keyframes.map((kf) => {
5290
- var _a, _b, _c, _d;
5291
- return {
5292
- time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5293
- value: map((_c = kf.value) != null ? _c : kf.v),
5294
- easing: (_d = kf.easing) != null ? _d : kf.e
5295
- };
5296
- }),
5927
+ keyframes: read.keyframes.map((kf) => ({
5928
+ time: kfTime(kf),
5929
+ value: map(kfValue(kf)),
5930
+ easing: kfEasing(kf)
5931
+ })),
5297
5932
  loop: read.loop
5298
5933
  };
5299
5934
  }
@@ -5303,7 +5938,6 @@ function applyAttr(node, attrName, attr) {
5303
5938
  }
5304
5939
  var OPACITY_STEP_MS = 10;
5305
5940
  function computeOpacityFromRange(rangeRead) {
5306
- var _a, _b, _c, _d, _e, _f;
5307
5941
  const hide = (v) => v[0] === v[1];
5308
5942
  if (rangeRead.kind === "absent" /* Absent */) return void 0;
5309
5943
  if (rangeRead.kind === "static" /* Static */) return hide(rangeRead.value) ? { kind: "static" /* Static */, value: 0 } : void 0;
@@ -5311,7 +5945,7 @@ function computeOpacityFromRange(rangeRead) {
5311
5945
  let anyHide = false;
5312
5946
  let allHide = true;
5313
5947
  for (const kf of kfs) {
5314
- if (hide((_a = kf.value) != null ? _a : kf.v)) anyHide = true;
5948
+ if (hide(kfValue(kf))) anyHide = true;
5315
5949
  else allHide = false;
5316
5950
  }
5317
5951
  if (!anyHide) return void 0;
@@ -5321,10 +5955,10 @@ function computeOpacityFromRange(rangeRead) {
5321
5955
  const kf = kfs[i];
5322
5956
  const prevKf = i > 0 ? kfs[i - 1] : void 0;
5323
5957
  const nextKf = i < kfs.length - 1 ? kfs[i + 1] : void 0;
5324
- const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
5325
- const thisHide = hide((_d = kf.value) != null ? _d : kf.v);
5326
- const prevHide = prevKf ? thisHide && hide((_e = prevKf.value) != null ? _e : prevKf.v) : thisHide;
5327
- const nextHide = nextKf ? thisHide && hide((_f = nextKf.value) != null ? _f : nextKf.v) : thisHide;
5958
+ const t = kfTime(kf);
5959
+ const thisHide = hide(kfValue(kf));
5960
+ const prevHide = prevKf ? thisHide && hide(kfValue(prevKf)) : thisHide;
5961
+ const nextHide = nextKf ? thisHide && hide(kfValue(nextKf)) : thisHide;
5328
5962
  if (prevHide && !nextHide) {
5329
5963
  out.push({ time: t, value: 0 });
5330
5964
  out.push({ time: t + OPACITY_STEP_MS, value: 1 });
@@ -5339,14 +5973,11 @@ function computeOpacityFromRange(rangeRead) {
5339
5973
  function readRangeWithCrossings(raw) {
5340
5974
  const r = readAnimatable(raw);
5341
5975
  if (r.kind !== "animated" /* Animated */) return r;
5342
- const kfs = r.keyframes.map((kf) => {
5343
- var _a, _b, _c, _d;
5344
- return {
5345
- time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5346
- value: (_c = kf.value) != null ? _c : kf.v,
5347
- easing: (_d = kf.easing) != null ? _d : kf.e
5348
- };
5349
- });
5976
+ const kfs = r.keyframes.map((kf) => ({
5977
+ time: kfTime(kf),
5978
+ value: kfValue(kf),
5979
+ easing: kfEasing(kf)
5980
+ }));
5350
5981
  const hasReverse = kfs.some((kf) => kf.value[0] > kf.value[1]);
5351
5982
  if (!hasReverse) {
5352
5983
  return {
@@ -5443,20 +6074,20 @@ function pxBezierPathLength(path) {
5443
6074
  return total;
5444
6075
  }
5445
6076
  function segmentLength(path, from, to) {
5446
- var _a, _b, _c, _d;
6077
+ var _a2, _b, _c, _d;
5447
6078
  const v = path.v;
5448
6079
  const p0 = v[from];
5449
6080
  const p3 = v[to];
5450
- const p1 = (_b = (_a = path.o) == null ? void 0 : _a[from]) != null ? _b : p0;
6081
+ const p1 = (_b = (_a2 = path.o) == null ? void 0 : _a2[from]) != null ? _b : p0;
5451
6082
  const p2 = (_d = (_c = path.i) == null ? void 0 : _c[to]) != null ? _d : p3;
5452
6083
  const lut = bezier2D_arcLengthLUT(p0, p1, p2, p3);
5453
6084
  return lut.ds[lut.ds.length - 1];
5454
6085
  }
5455
6086
  var ARC_KAPPA = 0.5522847498307936;
5456
6087
  function shapeToPathD(node) {
5457
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
6088
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5458
6089
  if (node.type === "rect") {
5459
- const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
6090
+ const x = Number((_a2 = node.x) != null ? _a2 : 0), y = Number((_b = node.y) != null ? _b : 0);
5460
6091
  const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
5461
6092
  return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
5462
6093
  }
@@ -5474,7 +6105,7 @@ function shapeToPathD(node) {
5474
6105
 
5475
6106
  // src/effects/PlayerEffectsUtil.ts
5476
6107
  function applyPlayerEffects(root) {
5477
- var _a, _b;
6108
+ var _a2, _b;
5478
6109
  const ctx = {
5479
6110
  defs: [],
5480
6111
  warnings: [],
@@ -5485,8 +6116,8 @@ function applyPlayerEffects(root) {
5485
6116
  maskAncestorChains: /* @__PURE__ */ new Map(),
5486
6117
  // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
5487
6118
  // waapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5488
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi,
5489
- glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
6119
+ engine: resolveTimelineEngine((_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.engine),
6120
+ glyphs: (_b = getDefs(root)) == null ? void 0 : _b.fonts
5490
6121
  };
5491
6122
  const working = clone(root);
5492
6123
  indexById(working, ctx.idMap);
@@ -5509,7 +6140,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5509
6140
  let consumedByGlyphs = false;
5510
6141
  if (text == null ? void 0 : text.useGlyphs) {
5511
6142
  if (textPath) {
5512
- const pathD = typeof textPath.path === "string" ? textPath.path : void 0;
6143
+ const pathD = typeof textPath.pathData === "string" ? textPath.pathData : void 0;
5513
6144
  const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textPath.startOffset, textPath.textLength, textPath.pathOverflow);
5514
6145
  if (glyphed) {
5515
6146
  n = glyphed;
@@ -5542,27 +6173,7 @@ function applyPlayerEffects_retime(node, ctx) {
5542
6173
  return node;
5543
6174
  }
5544
6175
 
5545
- // src/PxOffsetPathMaterialiser.ts
5546
- var kfTime = (kf) => {
5547
- var _a, _b;
5548
- return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
5549
- };
5550
- var kfValue = (kf) => {
5551
- var _a;
5552
- return (_a = kf.v) != null ? _a : kf.value;
5553
- };
5554
- var kfEasing = (kf) => {
5555
- var _a;
5556
- return (_a = kf.e) != null ? _a : kf.easing;
5557
- };
5558
- var kfTangentIn = (kf) => {
5559
- var _a;
5560
- return (_a = kf.tangentIn) != null ? _a : kf.ti;
5561
- };
5562
- var kfTangentOut = (kf) => {
5563
- var _a;
5564
- return (_a = kf.tangentOut) != null ? _a : kf.to;
5565
- };
6176
+ // src/materialise/PxOffsetPathMaterialiser.ts
5566
6177
  function cubicAt(p0, c1, c2, p1, t) {
5567
6178
  const u = 1 - t;
5568
6179
  const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
@@ -5586,9 +6197,9 @@ var fmt2 = (n) => {
5586
6197
  return Object.is(r, -0) ? "0" : String(r);
5587
6198
  };
5588
6199
  function buildOffsetPath(propAnim) {
5589
- var _a, _b, _c, _d;
6200
+ var _a2, _b, _c;
5590
6201
  if (propAnim.alongPathMode !== "offsetPath") return void 0;
5591
- const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
6202
+ const kfs = propAnim.keyframes;
5592
6203
  if (!kfs || kfs.length < 2) return void 0;
5593
6204
  const first = kfValue(kfs[0]);
5594
6205
  const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
@@ -5599,7 +6210,7 @@ function buildOffsetPath(propAnim) {
5599
6210
  if (!tr || tr.length < 2) return void 0;
5600
6211
  const parts = Object.keys(v);
5601
6212
  if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5602
- const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
6213
+ const o = (_a2 = v == null ? void 0 : v.origin) != null ? _a2 : [0, 0];
5603
6214
  if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5604
6215
  points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5605
6216
  }
@@ -5608,8 +6219,8 @@ function buildOffsetPath(propAnim) {
5608
6219
  const segLens = [];
5609
6220
  for (let i = 0; i < points.length - 1; i++) {
5610
6221
  const p0 = points[i], p1 = points[i + 1];
5611
- const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
5612
- const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
6222
+ const to = (_b = kfTangentOut(kfs[i])) != null ? _b : [0, 0];
6223
+ const ti = (_c = kfTangentIn(kfs[i + 1])) != null ? _c : [0, 0];
5613
6224
  const c1 = [p0[0] + to[0], p0[1] + to[1]];
5614
6225
  const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
5615
6226
  d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
@@ -5630,7 +6241,7 @@ function buildOffsetPath(propAnim) {
5630
6241
  }
5631
6242
  function materialiseOffsetPathsInTree(root) {
5632
6243
  const walk = (node) => {
5633
- var _a;
6244
+ var _a2;
5634
6245
  let out = node;
5635
6246
  const anim = node.animate;
5636
6247
  const transform = anim == null ? void 0 : anim["transform"];
@@ -5638,16 +6249,16 @@ function materialiseOffsetPathsInTree(root) {
5638
6249
  const built = buildOffsetPath(transform);
5639
6250
  if (built) {
5640
6251
  const newAnimate = __spreadValues({}, anim);
5641
- delete newAnimate["transform"];
6252
+ delete newAnimate[TRANSFORM_ATTR];
5642
6253
  const distance = { keyframes: built.distanceKfs };
5643
6254
  if (transform.loop !== void 0) distance.loop = transform.loop;
5644
- newAnimate["offsetDistance"] = distance;
6255
+ newAnimate[OFFSET_DISTANCE_ATTR] = distance;
5645
6256
  const staticTr = node.transform;
5646
6257
  let newTransform = staticTr;
5647
6258
  if (staticTr && typeof staticTr === "object") {
5648
6259
  const t = __spreadValues({}, staticTr);
5649
- delete t["translate"];
5650
- delete t["origin"];
6260
+ delete t[TRANSFORM_PART.translate];
6261
+ delete t[TRANSFORM_PART.origin];
5651
6262
  newTransform = Object.keys(t).length ? t : void 0;
5652
6263
  }
5653
6264
  out = __spreadProps(__spreadValues({}, node), {
@@ -5663,7 +6274,7 @@ function materialiseOffsetPathsInTree(root) {
5663
6274
  else delete out.transform;
5664
6275
  }
5665
6276
  }
5666
- if ((_a = out.children) == null ? void 0 : _a.length) {
6277
+ if ((_a2 = out.children) == null ? void 0 : _a2.length) {
5667
6278
  const children = out.children.map(walk);
5668
6279
  if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
5669
6280
  }
@@ -5672,14 +6283,14 @@ function materialiseOffsetPathsInTree(root) {
5672
6283
  return walk(root);
5673
6284
  }
5674
6285
 
5675
- // src/PxAnimatorMaterialiseAll.ts
6286
+ // src/materialise/PxAnimatorMaterialiseAll.ts
5676
6287
  function materialiseAllInTree(doc, engine, opts) {
5677
- var _a, _b;
6288
+ var _a2, _b;
5678
6289
  let root = applyPlayerEffects(doc).root;
5679
6290
  root = materialiseOffsetPathsInTree(root);
5680
- const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
6291
+ const duration = (_b = (_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.duration) != null ? _b : DEFAULT_DURATION_MS;
5681
6292
  root = materialiseInternalLoopsInTree(root, duration);
5682
- if (engine === PxAnimatorEngine.waapi) {
6293
+ if (engine === PxTimelineEngine.native) {
5683
6294
  root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5684
6295
  root = materialiseAnimatedUseInstances(root);
5685
6296
  root = pruneUnreferencedDefs(root);
@@ -5689,9 +6300,9 @@ function materialiseAllInTree(doc, engine, opts) {
5689
6300
  function pruneUnreferencedDefs(root) {
5690
6301
  const stripHash3 = (h) => h.startsWith("#") ? h.slice(1) : h;
5691
6302
  const walk = (n, fn) => {
5692
- var _a;
6303
+ var _a2;
5693
6304
  fn(n);
5694
- (_a = n.children) == null ? void 0 : _a.forEach((c) => walk(c, fn));
6305
+ (_a2 = n.children) == null ? void 0 : _a2.forEach((c) => walk(c, fn));
5695
6306
  };
5696
6307
  let changed = true;
5697
6308
  while (changed) {
@@ -5716,7 +6327,7 @@ function pruneUnreferencedDefs(root) {
5716
6327
  return root;
5717
6328
  }
5718
6329
 
5719
- // src/PxFrameLoop.ts
6330
+ // src/playback/PxFrameLoop.ts
5720
6331
  function requestFrame(cb) {
5721
6332
  const g = globalThis;
5722
6333
  if (typeof g.requestAnimationFrame === "function") return g.requestAnimationFrame(cb);
@@ -5731,9 +6342,9 @@ function cancelFrame(handle) {
5731
6342
  g.clearTimeout(handle);
5732
6343
  }
5733
6344
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5734
- var _a;
6345
+ var _a2;
5735
6346
  const config = getAnimatorConfig(doc) || {};
5736
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
6347
+ const bindings = getNormalisedBindings(doc, PxTimelineEngine.js);
5737
6348
  const _iterations = config.iterations;
5738
6349
  let iterations = 1;
5739
6350
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -5742,7 +6353,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5742
6353
  const duration = +(config.duration || DEFAULT_DURATION_MS);
5743
6354
  const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
5744
6355
  const direction = config.direction || "normal";
5745
- const fill = (_a = config.fill) != null ? _a : "forwards";
6356
+ const fill = (_a2 = config.fill) != null ? _a2 : "forwards";
5746
6357
  const fillsForwards = fill === "forwards" || fill === "both";
5747
6358
  const fillsBackwards = fill === "backwards" || fill === "both";
5748
6359
  let timerId = null;
@@ -5804,7 +6415,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5804
6415
  }
5805
6416
  }
5806
6417
  const tick = () => {
5807
- var _a2, _b;
6418
+ var _a3, _b;
5808
6419
  if (!adapter.isConnected()) {
5809
6420
  pauseAnim();
5810
6421
  return;
@@ -5820,7 +6431,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5820
6431
  renderFrame(0);
5821
6432
  if (!finishCalled) {
5822
6433
  finishCalled = true;
5823
- (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
6434
+ (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
5824
6435
  }
5825
6436
  return;
5826
6437
  }
@@ -5912,17 +6523,17 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5912
6523
  }
5913
6524
  };
5914
6525
  const cancelAnim = () => {
5915
- var _a2;
6526
+ var _a3;
5916
6527
  pauseAnim();
5917
6528
  timeBeforeLastStartMs = 0;
5918
6529
  lastStartedTs = 0;
5919
6530
  playing = false;
5920
6531
  finishCalled = false;
5921
6532
  renderFrame(timeBeforeLastStartMs);
5922
- (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
6533
+ (_a3 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a3.call(callbacks);
5923
6534
  };
5924
6535
  const finishAnim = (callOnFinish = true) => {
5925
- var _a2;
6536
+ var _a3;
5926
6537
  if (Number.isFinite(totalDuration)) {
5927
6538
  timeBeforeLastStartMs = totalDuration;
5928
6539
  } else {
@@ -5937,7 +6548,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5937
6548
  renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
5938
6549
  if (callOnFinish && !finishCalled) {
5939
6550
  finishCalled = true;
5940
- (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
6551
+ (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
5941
6552
  }
5942
6553
  };
5943
6554
  const api = {
@@ -5947,14 +6558,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5947
6558
  return _isPlaying();
5948
6559
  },
5949
6560
  "play": () => {
5950
- var _a2;
6561
+ var _a3;
5951
6562
  startAnim();
5952
- (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
6563
+ (_a3 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a3.call(callbacks);
5953
6564
  },
5954
6565
  "pause": () => {
5955
- var _a2;
6566
+ var _a3;
5956
6567
  pauseAnim();
5957
- (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
6568
+ (_a3 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a3.call(callbacks);
5958
6569
  },
5959
6570
  "cancel": () => {
5960
6571
  cancelAnim();
@@ -5986,9 +6597,9 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5986
6597
  renderFrame(getAnimCurrentTime());
5987
6598
  },
5988
6599
  "destroy": () => {
5989
- var _a2;
6600
+ var _a3;
5990
6601
  api.cancel();
5991
- (_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
6602
+ (_a3 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a3.call(callbacks);
5992
6603
  }
5993
6604
  };
5994
6605
  return api;
@@ -6044,9 +6655,9 @@ function lerp(a, b, f) {
6044
6655
  return a + (b - a) * f;
6045
6656
  }
6046
6657
  function interpParts(kfs, t) {
6047
- var _a, _b, _c, _d, _e, _f, _g;
6658
+ var _a2, _b, _c, _d, _e, _f, _g;
6048
6659
  if (!kfs.length) return {};
6049
- if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value || {};
6660
+ if (t <= ((_a2 = kfs[0].time) != null ? _a2 : 0)) return kfs[0].value || {};
6050
6661
  if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value || {};
6051
6662
  let i = 0;
6052
6663
  while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
@@ -6077,10 +6688,10 @@ function nodeMatrix(node, t) {
6077
6688
  return IDENTITY;
6078
6689
  }
6079
6690
  function evalScalar(animated, staticVal, fallback, t) {
6080
- var _a, _b, _c, _d, _e, _f;
6691
+ var _a2, _b, _c, _d, _e, _f;
6081
6692
  if (animated && animated.keyframes && animated.keyframes.length) {
6082
6693
  const kfs = animated.keyframes;
6083
- if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value;
6694
+ if (t <= ((_a2 = kfs[0].time) != null ? _a2 : 0)) return kfs[0].value;
6084
6695
  if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value;
6085
6696
  let i = 0;
6086
6697
  while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
@@ -6093,9 +6704,9 @@ function evalScalar(animated, staticVal, fallback, t) {
6093
6704
  var CONTAINER_TYPES = /* @__PURE__ */ new Set(["svg", "g", "symbol"]);
6094
6705
  var SKIP_TYPES = /* @__PURE__ */ new Set(["defs", "mask", "clipPath", "title"]);
6095
6706
  function buildIdMap2(node, map) {
6096
- var _a;
6707
+ var _a2;
6097
6708
  if (typeof node.id === "string") map.set(node.id, node);
6098
- (_a = node.children) == null ? void 0 : _a.forEach((c) => buildIdMap2(c, map));
6709
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => buildIdMap2(c, map));
6099
6710
  }
6100
6711
  function num(v) {
6101
6712
  return v === void 0 || v === null ? 0 : Number(v);
@@ -6104,7 +6715,7 @@ function round(n) {
6104
6715
  return Math.round(n * 100) / 100 + 0;
6105
6716
  }
6106
6717
  function geomKey(node) {
6107
- var _a;
6718
+ var _a2;
6108
6719
  switch (node.type) {
6109
6720
  case "rect":
6110
6721
  return num(node.width) + "," + num(node.height) + "," + num(node.x) + "," + num(node.y);
@@ -6113,14 +6724,14 @@ function geomKey(node) {
6113
6724
  case "circle":
6114
6725
  return num(node.r) + "," + num(node.cx) + "," + num(node.cy);
6115
6726
  case "path":
6116
- return String((_a = node.d) != null ? _a : "");
6727
+ return String((_a2 = node.d) != null ? _a2 : "");
6117
6728
  default:
6118
6729
  return "";
6119
6730
  }
6120
6731
  }
6121
6732
  function describePrimitive(node, m, t) {
6122
- var _a, _b, _c, _d, _e;
6123
- const fill = (_a = node.fill) != null ? _a : "";
6733
+ var _a2, _b, _c, _d, _e;
6734
+ const fill = (_a2 = node.fill) != null ? _a2 : "";
6124
6735
  const stroke = (_b = node.stroke) != null ? _b : "";
6125
6736
  const sw = (_d = (_c = node["stroke-width"]) != null ? _c : node.strokeWidth) != null ? _d : "";
6126
6737
  const opacity = round(evalScalar((_e = node.animate) == null ? void 0 : _e.opacity, node.opacity, 1, t));
@@ -6129,7 +6740,7 @@ function describePrimitive(node, m, t) {
6129
6740
  return node.type + "|" + geomKey(node) + "|[" + mat + "]|f:" + fill + "|s:" + stroke + "|sw:" + (num(sw) || "") + "|o:" + opacity + "|m:" + masked;
6130
6741
  }
6131
6742
  function flatten(node, parent, t, idMap, out) {
6132
- var _a;
6743
+ var _a2;
6133
6744
  const type = node.type || "";
6134
6745
  if (SKIP_TYPES.has(type)) return;
6135
6746
  const m = mul(parent, nodeMatrix(node, t));
@@ -6142,33 +6753,33 @@ function flatten(node, parent, t, idMap, out) {
6142
6753
  return;
6143
6754
  }
6144
6755
  if (CONTAINER_TYPES.has(type)) {
6145
- (_a = node.children) == null ? void 0 : _a.forEach((c) => flatten(c, m, t, idMap, out));
6756
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => flatten(c, m, t, idMap, out));
6146
6757
  return;
6147
6758
  }
6148
6759
  out.push(describePrimitive(node, m, t));
6149
6760
  }
6150
6761
  function collectSampleTimes(node, into) {
6151
- var _a;
6762
+ var _a2;
6152
6763
  into.add(0);
6153
6764
  const scanAnim = (anim) => {
6154
- var _a2;
6765
+ var _a3;
6155
6766
  if (!anim || typeof anim !== "object") return;
6156
6767
  for (const key of Object.keys(anim)) {
6157
- const kfs = (_a2 = anim[key]) == null ? void 0 : _a2.keyframes;
6768
+ const kfs = (_a3 = anim[key]) == null ? void 0 : _a3.keyframes;
6158
6769
  if (Array.isArray(kfs)) kfs.forEach((kf) => {
6159
- var _a3;
6160
- return into.add((_a3 = kf.time) != null ? _a3 : 0);
6770
+ var _a4;
6771
+ return into.add((_a4 = kf.time) != null ? _a4 : 0);
6161
6772
  });
6162
6773
  }
6163
6774
  };
6164
6775
  scanAnim(node.animate);
6165
6776
  if (node.transform && typeof node.transform === "object" && node.transform.keyframes) {
6166
6777
  node.transform.keyframes.forEach((kf) => {
6167
- var _a2;
6168
- return into.add((_a2 = kf.time) != null ? _a2 : 0);
6778
+ var _a3;
6779
+ return into.add((_a3 = kf.time) != null ? _a3 : 0);
6169
6780
  });
6170
6781
  }
6171
- (_a = node.children) == null ? void 0 : _a.forEach((c) => collectSampleTimes(c, into));
6782
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => collectSampleTimes(c, into));
6172
6783
  }
6173
6784
  function visualModelAt(root, t) {
6174
6785
  const idMap = /* @__PURE__ */ new Map();
@@ -6202,8 +6813,196 @@ function subtractMultiset(a, b) {
6202
6813
  }
6203
6814
  return extra;
6204
6815
  }
6816
+
6817
+ // src/playback/PxAnimatorConfigPatch.ts
6818
+ var FLAT_ONLY_KEYS = [
6819
+ "timelineSource",
6820
+ "scroll",
6821
+ "trigger",
6822
+ "delay",
6823
+ "iterations",
6824
+ "direction",
6825
+ "fill",
6826
+ "resetOnFinish",
6827
+ "duration",
6828
+ "mode",
6829
+ "frameRate"
6830
+ ];
6831
+ var CONTENT_KEYS = ["definitions", "animateById"];
6832
+ var isPlainObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
6833
+ var timelineTypeOf = (t) => isPlainObject(t) && typeof t.type === "string" ? t.type : "time";
6834
+ var isScrollish = (type) => type === "scroll" || type === "view";
6835
+ function mergePlain(base, patch) {
6836
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6837
+ for (const key of Object.keys(patch)) {
6838
+ const value = patch[key];
6839
+ if (value === null) {
6840
+ delete out[key];
6841
+ continue;
6842
+ }
6843
+ if (isPlainObject(value)) {
6844
+ out[key] = mergePlain(out[key], value);
6845
+ continue;
6846
+ }
6847
+ out[key] = value;
6848
+ }
6849
+ return out;
6850
+ }
6851
+ function mergeTimeline(base, patch, warn) {
6852
+ const baseType = timelineTypeOf(base);
6853
+ const patchNamesType = isPlainObject(patch) && typeof patch.type === "string";
6854
+ const patchType = patchNamesType ? String(patch.type) : baseType;
6855
+ let merged;
6856
+ if (patchType !== baseType) {
6857
+ const carried = {};
6858
+ if (isPlainObject(base)) {
6859
+ for (const k of PX_TIMELINE_SHARED_KEYS) {
6860
+ if (base[k] !== void 0) carried[k] = base[k];
6861
+ }
6862
+ }
6863
+ merged = mergePlain(carried, patch);
6864
+ } else {
6865
+ merged = mergePlain(base, patch);
6866
+ }
6867
+ if (isScrollish(patchType)) {
6868
+ for (const k of PX_TIME_ONLY_TIMELINE_KEYS) {
6869
+ if (merged[k] === void 0) continue;
6870
+ warn("animator.timeline." + k + ": no slot on a '" + patchType + "' timeline \u2014 dropped");
6871
+ delete merged[k];
6872
+ }
6873
+ if (merged.iterations === "infinite") {
6874
+ warn("animator.timeline.iterations: 'infinite' cannot map onto a scroll range \u2014 dropped");
6875
+ delete merged.iterations;
6876
+ }
6877
+ }
6878
+ return merged;
6879
+ }
6880
+ function foldAnimatorConfigShortcuts(config, shortcuts) {
6881
+ let base;
6882
+ if (typeof config === "string") {
6883
+ try {
6884
+ base = JSON.parse(config);
6885
+ } catch (e) {
6886
+ console.warn("animator config: not valid JSON \u2014 ignored", e);
6887
+ base = void 0;
6888
+ }
6889
+ } else {
6890
+ base = config != null ? config : void 0;
6891
+ }
6892
+ const { duration, delay, iterations, startOn } = shortcuts;
6893
+ if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6894
+ return base;
6895
+ }
6896
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6897
+ const timeline = __spreadValues({}, out.timeline);
6898
+ if (duration !== void 0) timeline.duration = duration;
6899
+ if (delay !== void 0) timeline.delay = delay;
6900
+ if (iterations !== void 0) timeline.iterations = iterations;
6901
+ if (startOn !== void 0) {
6902
+ timeline.trigger = __spreadProps(__spreadValues({}, timeline.trigger), { startOn });
6903
+ }
6904
+ out.timeline = timeline;
6905
+ return out;
6906
+ }
6907
+ function mergeAnimatorConfig(base, patch) {
6908
+ const warnings = [];
6909
+ const warn = (m) => warnings.push(m);
6910
+ if (patch === null) return { config: void 0, warnings };
6911
+ if (!isPlainObject(patch) || Object.keys(patch).length === 0) {
6912
+ return { config: base, warnings };
6913
+ }
6914
+ const flatInBase = isPlainObject(base) ? FLAT_ONLY_KEYS.filter((k) => base[k] !== void 0) : [];
6915
+ if (flatInBase.length) {
6916
+ warn("animator: the base carries the flat runtime spelling (" + flatInBase.join(", ") + "); the patch merges the wire spelling only");
6917
+ }
6918
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6919
+ for (const key of Object.keys(patch)) {
6920
+ const value = patch[key];
6921
+ if (value === null) {
6922
+ delete out[key];
6923
+ continue;
6924
+ }
6925
+ if (key === "timeline") {
6926
+ out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
6927
+ continue;
6928
+ }
6929
+ if (isPlainObject(value)) {
6930
+ out[key] = mergePlain(out[key], value);
6931
+ continue;
6932
+ }
6933
+ out[key] = value;
6934
+ }
6935
+ return { config: out, warnings };
6936
+ }
6937
+ function applyAnimatorConfig(doc, patch, opts) {
6938
+ var _a2, _b;
6939
+ const reset = !!(opts == null ? void 0 : opts.resetDefaults);
6940
+ if (!doc || (patch === void 0 || !reset && (patch === null || !isPlainObject(patch) || !Object.keys(patch).length))) {
6941
+ return { doc, warnings: [] };
6942
+ }
6943
+ const anyDoc = doc;
6944
+ const atRoot = isPlainObject(anyDoc.animator);
6945
+ const atMeta = !atRoot && isPlainObject((_a2 = anyDoc.meta) == null ? void 0 : _a2.animator);
6946
+ const current = atRoot ? anyDoc.animator : atMeta ? anyDoc.meta.animator : void 0;
6947
+ const warnings = [];
6948
+ if (atRoot && isPlainObject((_b = anyDoc.meta) == null ? void 0 : _b.animator)) {
6949
+ warnings.push("animator: doc.meta.animator is shadowed by doc.animator and was not patched");
6950
+ }
6951
+ let base = current;
6952
+ if (reset) {
6953
+ const kept = {};
6954
+ for (const k of CONTENT_KEYS) {
6955
+ if (isPlainObject(current) && current[k] !== void 0) kept[k] = current[k];
6956
+ }
6957
+ base = kept;
6958
+ }
6959
+ const merged = mergeAnimatorConfig(base, patch != null ? patch : {});
6960
+ warnings.push(...merged.warnings);
6961
+ if (merged.config === current) return { doc, warnings };
6962
+ if (atMeta) {
6963
+ return {
6964
+ doc: __spreadProps(__spreadValues({}, anyDoc), { meta: __spreadProps(__spreadValues({}, anyDoc.meta), { animator: merged.config }) }),
6965
+ warnings
6966
+ };
6967
+ }
6968
+ return { doc: __spreadProps(__spreadValues({}, anyDoc), { animator: merged.config }), warnings };
6969
+ }
6970
+
6971
+ // src/format/PxDocumentDiagnostic.ts
6972
+ var MAX_REPORTED = 6;
6973
+ var LEGACY_FLAT_KEYS = [
6974
+ ...PX_TIMELINE_SHARED_KEYS,
6975
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
6976
+ "fill",
6977
+ "resetOnFinish",
6978
+ "timelineSource",
6979
+ "scroll"
6980
+ ];
6981
+ var isLegacyFlatAnimatorKey = (w) => LEGACY_FLAT_KEYS.some((k) => w.indexOf("animator." + k + ":") >= 0);
6982
+ function diagnoseDocument(doc) {
6983
+ let all;
6984
+ try {
6985
+ all = validateDocument(doc);
6986
+ } catch (e) {
6987
+ return { problems: [], legacy: [] };
6988
+ }
6989
+ const problems = [];
6990
+ const legacy = [];
6991
+ for (const w of all) (isLegacyFlatAnimatorKey(w) ? legacy : problems).push(w);
6992
+ return { problems, legacy };
6993
+ }
6994
+ function reportDocumentDiagnostics(doc, where) {
6995
+ const { problems } = diagnoseDocument(doc);
6996
+ if (!problems.length) return;
6997
+ const shown = problems.slice(0, MAX_REPORTED);
6998
+ const more = problems.length - shown.length;
6999
+ console.warn(
7000
+ where + ": this document does not match the animation schema in " + problems.length + " place" + (problems.length === 1 ? "" : "s") + ".\n" + shown.map((p) => " - " + p).join("\n") + (more > 0 ? "\n \u2026 and " + more + " more" : "") + "\n\nIf you did not author these keys, the usual cause is a build that MANGLES PROPERTY NAMES. An animation document is data loaded at runtime, so renaming the property reads inside the player stops them matching the keys in the JSON, and the animation silently does nothing. Feed the published reserved-name list to your minifier \u2014 @pixodesk/svg-animator-web/mangle-reserved.json \u2014 see docs/library/minification.md."
7001
+ );
7002
+ }
6205
7003
  // Annotate the CommonJS export names for ESM import in node:
6206
7004
  0 && (module.exports = {
7005
+ BASELINE_PLAYER_VERSION,
6207
7006
  COLOUR_ATTR_NAMES,
6208
7007
  CSS_ONLY_STYLE_PROPS,
6209
7008
  DEFAULT_DURATION_MS,
@@ -6212,18 +7011,21 @@ function subtractMultiset(a, b) {
6212
7011
  LOOP_JUMP_SHIFT_MS,
6213
7012
  MISSING_GLYPH_CLASS_NAME,
6214
7013
  PCT_BASED_ATTR_NAMES,
7014
+ PLAYER_WIRE_STEPS,
7015
+ PLAYER_WIRE_VERSION,
6215
7016
  PX_ANIM_ATTR_NAME,
6216
7017
  PX_ANIM_SRC_ATTR_NAME,
7018
+ PX_PLAYER_SCHEMA_VERSION,
6217
7019
  PX_TRANSFORM_PART_KEYS,
7020
+ PX_UNKNOWN_KEY_ERROR,
6218
7021
  PxAnimatedSvgDocumentSchema,
6219
7022
  PxAnimationDefinitionSchema,
6220
7023
  PxAnimatorConfigSchema,
6221
- PxAnimatorEngine,
6222
- PxAnimatorMode,
6223
7024
  PxAttrValueSchema,
6224
7025
  PxBezierPathSchema,
6225
7026
  PxBindingSchema,
6226
7027
  PxCloneEffectSchema,
7028
+ PxCloneWithout,
6227
7029
  PxDefsSchema,
6228
7030
  PxEasingOrRefSchema,
6229
7031
  PxEffectsSchema,
@@ -6235,7 +7037,8 @@ function subtractMultiset(a, b) {
6235
7037
  PxGradientUnits,
6236
7038
  PxKeyframeSchema,
6237
7039
  PxKeyframeValueSchema,
6238
- PxLoopExtend,
7040
+ PxLoopDirection,
7041
+ PxLoopRepeatAt,
6239
7042
  PxLoopSchema,
6240
7043
  PxMaskedByEffectSchema,
6241
7044
  PxNodeBase,
@@ -6252,6 +7055,10 @@ function subtractMultiset(a, b) {
6252
7055
  PxSvgNodeExtra,
6253
7056
  PxTextEffectSchema,
6254
7057
  PxTextPathEffectSchema,
7058
+ PxTimelineEngine,
7059
+ PxTimelineEngineExtra,
7060
+ PxTimelinePinSchema,
7061
+ PxTimelineSchema,
6255
7062
  PxTransformByEffectSchema,
6256
7063
  PxTransformPartsSchema,
6257
7064
  PxTransformValueSchema,
@@ -6260,21 +7067,35 @@ function subtractMultiset(a, b) {
6260
7067
  TEXT_ATTR,
6261
7068
  TEXT_CONTENT_ATTR,
6262
7069
  TRANSFORM_FN_NAMES,
7070
+ WIRE_VERSION_KEY,
7071
+ WireStepKind,
7072
+ WireVersionRelation,
7073
+ applyAnimatorConfig,
6263
7074
  applyPlayerEffects,
7075
+ applyWireSteps,
7076
+ applyWireStepsDown,
6264
7077
  bezierToSvgPath,
6265
7078
  calcAnimationValues,
6266
7079
  camelCaseToKebabWordIfNeeded,
6267
7080
  clamp,
6268
7081
  collectSampleTimes,
7082
+ compareWireVersion,
6269
7083
  composeTransformParts,
7084
+ convertPlayerDocument,
6270
7085
  createBasicFrameLoopAnimator,
6271
7086
  createPathSampler,
6272
7087
  cubicBezier,
6273
7088
  deepClone,
6274
7089
  describeSchema,
7090
+ diagnoseDocument,
7091
+ diffFieldUniverse,
6275
7092
  diffInEffect,
7093
+ downgradePlayerDocument,
6276
7094
  evaluateMotionPathSegment,
6277
7095
  extendedPathForBrowser,
7096
+ flattenAnimatorTimeline,
7097
+ foldAnimatorConfigShortcuts,
7098
+ formatWireVersion,
6278
7099
  generateNewIds,
6279
7100
  generateUniqueId,
6280
7101
  getAnimatorConfig,
@@ -6285,11 +7106,17 @@ function subtractMultiset(a, b) {
6285
7106
  getNormalizedProps,
6286
7107
  interpolateBeziers,
6287
7108
  interpolateValue,
7109
+ isNativeForced,
6288
7110
  isPxElementFileFormat,
6289
7111
  isPxElementFileFormatDeep,
6290
7112
  isScrollTimeline,
6291
7113
  jsonElementFactory,
6292
7114
  kebabToCamelCaseWord,
7115
+ kfEasing,
7116
+ kfTangentIn,
7117
+ kfTangentOut,
7118
+ kfTime,
7119
+ kfValue,
6293
7120
  layoutGlyphTextChars,
6294
7121
  materialiseAllInTree,
6295
7122
  materialiseAnimatedUseInstances,
@@ -6300,11 +7127,23 @@ function subtractMultiset(a, b) {
6300
7127
  materialiseInternalLoopsInTree,
6301
7128
  materialiseMotionPathInPropAnim,
6302
7129
  materialiseMotionPathsInTree,
7130
+ mayUseNativeScrollTimeline,
7131
+ mergeAnimatorConfig,
7132
+ mergeStaticTransformIntoAnimDef,
7133
+ nestAnimatorTimeline,
7134
+ parseTransformParts,
7135
+ parseWireVersion,
7136
+ planSchemaRelease,
6303
7137
  propAnimIsMotionPath,
6304
7138
  px,
7139
+ readWireVersion,
7140
+ releaseLogProblems,
7141
+ reportDocumentDiagnostics,
6305
7142
  resolveStyle,
7143
+ resolveTimelineEngine,
6306
7144
  reverseEasing,
6307
7145
  sanitiseAttributeValue,
7146
+ schemaFieldUniverse,
6308
7147
  schemaKeys,
6309
7148
  scrollOffsetProgress,
6310
7149
  scrollPhaseInterval,
@@ -6315,7 +7154,9 @@ function subtractMultiset(a, b) {
6315
7154
  splitEasing,
6316
7155
  subdivideCubicBezier,
6317
7156
  toRGBA,
7157
+ validateDocument,
6318
7158
  validateNodeEffects,
7159
+ versionAdvice,
6319
7160
  visualModelAt
6320
7161
  });
6321
7162
  //# sourceMappingURL=index.cjs.map