@pixodesk/svg-animator-core 1.0.34 → 1.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,9 +31,9 @@ var __objRest = (source, exclude) => {
31
31
  return target;
32
32
  };
33
33
 
34
- // src/PxAnimatorUtil.ts
34
+ // src/util/PxAnimatorUtil.ts
35
35
  function bezierToSvgPath(path, forceCurves = false) {
36
- var _a, _b, _c, _d;
36
+ var _a2, _b, _c, _d;
37
37
  const v = path.v;
38
38
  const i = path.i;
39
39
  const o = path.o;
@@ -44,7 +44,7 @@ function bezierToSvgPath(path, forceCurves = false) {
44
44
  d.push("M" + v[0][0] + "," + v[0][1]);
45
45
  for (let idx = 1; idx < len; idx++) {
46
46
  const prevV = v[idx - 1];
47
- const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
47
+ const prevO = (_a2 = o == null ? void 0 : o[idx - 1]) != null ? _a2 : prevV;
48
48
  const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
49
49
  const currV = v[idx];
50
50
  const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
@@ -95,7 +95,7 @@ function interpolateBeziers(paths1, paths2, progress) {
95
95
  return res;
96
96
  }
97
97
  function interpolateBezier(path1, path2, progress) {
98
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
98
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
99
99
  if (!path1 || !path2) return path1 || path2 || { v: [] };
100
100
  const t = Math.min(Math.max(progress, 0), 1);
101
101
  const len = Math.min(path1.v.length, path2.v.length);
@@ -106,7 +106,7 @@ function interpolateBezier(path1, path2, progress) {
106
106
  const v1 = path1.v[idx];
107
107
  const v2 = path2.v[idx];
108
108
  v.push(interpolateVec(v1, v2, t));
109
- const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
109
+ const i1 = (_b = (_a2 = path1.i) == null ? void 0 : _a2[idx]) != null ? _b : v1;
110
110
  const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
111
111
  i.push(interpolateVec(i1, i2, t));
112
112
  const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
@@ -225,8 +225,8 @@ function toRGBA(color) {
225
225
  return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
226
226
  }
227
227
  function parseRgba(s) {
228
- var _a;
229
- const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
228
+ var _a2;
229
+ const inner = (_a2 = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a2[1];
230
230
  if (!inner) throw new Error("Invalid rgb/rgba format");
231
231
  const parts = inner.split(",").map((v) => +v.trim());
232
232
  return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
@@ -261,13 +261,13 @@ function parseColor(s) {
261
261
  }
262
262
  return void 0;
263
263
  }
264
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
264
+ var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
265
265
  var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
266
266
  var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
267
267
  function composeTransformParts(parts, opts) {
268
- var _a;
268
+ var _a2;
269
269
  if (!parts) return "";
270
- const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
270
+ const withUnits = (_a2 = opts == null ? void 0 : opts.withUnits) != null ? _a2 : true;
271
271
  const segs = [];
272
272
  const t = parts.translate;
273
273
  const o = parts.origin;
@@ -285,7 +285,7 @@ function composeTransformParts(parts, opts) {
285
285
  return segs.join("");
286
286
  }
287
287
  function parseTransformParts(str2) {
288
- var _a, _b;
288
+ var _a2, _b;
289
289
  if (!str2 || typeof str2 !== "string") return void 0;
290
290
  const out = {};
291
291
  const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
@@ -301,7 +301,7 @@ function parseTransformParts(str2) {
301
301
  if (nums.some((n) => Number.isNaN(n))) return void 0;
302
302
  if (fn === "translate") {
303
303
  if (nums.length < 1 || nums.length > 2) return void 0;
304
- out.translate = [nums[0], (_a = nums[1]) != null ? _a : 0];
304
+ out.translate = [nums[0], (_a2 = nums[1]) != null ? _a2 : 0];
305
305
  } else if (fn === "rotate") {
306
306
  if (nums.length !== 1) return void 0;
307
307
  out.rotate = nums[0];
@@ -479,7 +479,7 @@ function invertEasing(easing) {
479
479
  return cubicBezier(flipped);
480
480
  }
481
481
 
482
- // src/PxScrollMath.ts
482
+ // src/playback/PxScrollMath.ts
483
483
  function isScrollTimeline(config) {
484
484
  return (config == null ? void 0 : config.timelineSource) === "scroll";
485
485
  }
@@ -507,8 +507,8 @@ function scrollPhaseInterval(phase, subjectSize, scrollportSize) {
507
507
  }
508
508
  var DEFAULT_PHASE = "cover";
509
509
  function resolveRangePointU(point, defaultFraction, subjectSize, scrollportSize) {
510
- var _a;
511
- const [u0, u1] = scrollPhaseInterval((_a = point == null ? void 0 : point.phase) != null ? _a : DEFAULT_PHASE, subjectSize, scrollportSize);
510
+ var _a2;
511
+ const [u0, u1] = scrollPhaseInterval((_a2 = point == null ? void 0 : point.phase) != null ? _a2 : DEFAULT_PHASE, subjectSize, scrollportSize);
512
512
  const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
513
513
  return u0 + fraction * (u1 - u0);
514
514
  }
@@ -520,9 +520,9 @@ function scrollViewProgress(subjectStart, subjectSize, scrollportSize, range) {
520
520
  return clamp((u - uStart) / (uEnd - uStart), 0, 1);
521
521
  }
522
522
  function scrollOffsetProgress(offset, maxOffset, range) {
523
- var _a, _b;
523
+ var _a2, _b;
524
524
  const raw = maxOffset > 0 ? clamp(offset / maxOffset, 0, 1) : 1;
525
- const start = typeof ((_a = range == null ? void 0 : range.start) == null ? void 0 : _a.fraction) === "number" ? range.start.fraction : 0;
525
+ const start = typeof ((_a2 = range == null ? void 0 : range.start) == null ? void 0 : _a2.fraction) === "number" ? range.start.fraction : 0;
526
526
  const end = typeof ((_b = range == null ? void 0 : range.end) == null ? void 0 : _b.fraction) === "number" ? range.end.fraction : 1;
527
527
  if (end <= start) return raw >= end ? 1 : 0;
528
528
  return clamp((raw - start) / (end - start), 0, 1);
@@ -535,7 +535,8 @@ function scrollResolveAxis(axis, writingMode) {
535
535
  return vertical ? "x" : "y";
536
536
  }
537
537
 
538
- // src/PxSchema.ts
538
+ // src/schema/PxSchema.ts
539
+ var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
539
540
  function pathStr(path) {
540
541
  if (!path.length) return ".";
541
542
  let result = "";
@@ -643,6 +644,7 @@ var Enum = class extends Base {
643
644
  return false;
644
645
  }
645
646
  };
647
+ var UNION_MEMBER_ERROR_LIMIT = 4;
646
648
  var Union = class extends Base {
647
649
  constructor(schemas, defaultVal) {
648
650
  super();
@@ -658,10 +660,38 @@ var Union = class extends Base {
658
660
  return this._default;
659
661
  }
660
662
  isValid(raw, ctx, path) {
661
- var _a;
663
+ var _a2;
662
664
  const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
663
665
  if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
664
- 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));
666
+ if (!ctx) return false;
667
+ const base = pathStr(path != null ? path : []);
668
+ ctx.errors.push(base + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
669
+ let best;
670
+ let bestDepth = -1;
671
+ const leafExpectations = [];
672
+ for (const member of this.schemas) {
673
+ const sink = { errors: [], warnings: [], strict: ctx.strict };
674
+ member.isValid(raw, sink, path ? [...path] : void 0);
675
+ if (!sink.errors.length) continue;
676
+ const depth = Math.max(...sink.errors.map((e) => e.slice(0, e.indexOf(":")).length));
677
+ if (depth > bestDepth || depth === bestDepth && best && sink.errors.length < best.length) {
678
+ bestDepth = depth;
679
+ best = sink.errors;
680
+ }
681
+ if (depth <= base.length) {
682
+ for (const e of sink.errors) {
683
+ const m = /: expected (.+?), got /.exec(e);
684
+ if (m && !leafExpectations.includes(m[1])) leafExpectations.push(m[1]);
685
+ }
686
+ }
687
+ }
688
+ if (best && bestDepth > base.length) {
689
+ for (const e of best.slice(0, UNION_MEMBER_ERROR_LIMIT)) {
690
+ if (!ctx.errors.includes(e)) ctx.errors.push(e);
691
+ }
692
+ } else if (leafExpectations.length) {
693
+ ctx.errors.push(base + ": expected " + leafExpectations.join(" | "));
694
+ }
665
695
  return false;
666
696
  }
667
697
  _canSanitize(raw) {
@@ -670,6 +700,7 @@ var Union = class extends Base {
670
700
  };
671
701
  var DiscriminatedUnion = class extends Base {
672
702
  constructor(_key, _schemas, defaultVal) {
703
+ var _a2;
673
704
  super();
674
705
  this._key = _key;
675
706
  this._schemas = _schemas;
@@ -679,18 +710,21 @@ var DiscriminatedUnion = class extends Base {
679
710
  this._map = /* @__PURE__ */ new Map();
680
711
  for (const s of _schemas) {
681
712
  const keySchema = s._shape[_key];
682
- if (keySchema) this._map.set(keySchema._default, s);
713
+ if (!keySchema) continue;
714
+ const literal = (_a2 = keySchema.inner) != null ? _a2 : keySchema;
715
+ this._map.set(literal._default, s);
716
+ if (keySchema.inner) this._absentMember = s;
683
717
  }
684
718
  }
685
719
  _findSchema(raw) {
686
720
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
687
721
  const val = raw[this._key];
688
- if (val === void 0 || val === null) return void 0;
722
+ if (val === void 0 || val === null) return this._absentMember;
689
723
  return this._map.get(val);
690
724
  }
691
725
  sanitize(raw) {
692
- var _a;
693
- return ((_a = this._findSchema(raw)) != null ? _a : this._schemas[0]).sanitize(raw);
726
+ var _a2;
727
+ return ((_a2 = this._findSchema(raw)) != null ? _a2 : this._schemas[0]).sanitize(raw);
694
728
  }
695
729
  isValid(raw, ctx, path) {
696
730
  const schema = this._findSchema(raw);
@@ -719,7 +753,8 @@ var Obj = class extends Base {
719
753
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
720
754
  const out = {};
721
755
  for (const key of Object.keys(this._shape)) {
722
- out[key] = this._shape[key].sanitize(src[key]);
756
+ const v = this._shape[key].sanitize(src[key]);
757
+ if (v !== void 0) out[key] = v;
723
758
  }
724
759
  return out;
725
760
  }
@@ -741,7 +776,7 @@ var Obj = class extends Base {
741
776
  if (key in this._shape) continue;
742
777
  if (obj[key] === void 0) continue;
743
778
  p.push(key);
744
- ctx.errors.push(pathStr(p) + ": unexpected extra key");
779
+ ctx.errors.push(pathStr(p) + ": " + PX_UNKNOWN_KEY_ERROR);
745
780
  p.pop();
746
781
  ok = false;
747
782
  }
@@ -765,7 +800,8 @@ var OpenObj = class extends Base {
765
800
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
766
801
  const out = __spreadValues({}, src);
767
802
  for (const key of Object.keys(this._shape)) {
768
- out[key] = this._shape[key].sanitize(src[key]);
803
+ const v = this._shape[key].sanitize(src[key]);
804
+ if (v !== void 0) out[key] = v;
769
805
  }
770
806
  if (this._openSchema) {
771
807
  for (const key of Object.keys(src)) {
@@ -907,8 +943,8 @@ var Lazy = class extends Base {
907
943
  this.resolved = null;
908
944
  }
909
945
  get schema() {
910
- var _a;
911
- return (_a = this.resolved) != null ? _a : this.resolved = this.fn();
946
+ var _a2;
947
+ return (_a2 = this.resolved) != null ? _a2 : this.resolved = this.fn();
912
948
  }
913
949
  sanitize(raw) {
914
950
  return this.schema.sanitize(raw);
@@ -960,7 +996,7 @@ function schemaKeys(schema) {
960
996
  );
961
997
  }
962
998
  function describeSchema(schema) {
963
- var _a;
999
+ var _a2;
964
1000
  const s = schema;
965
1001
  switch (s._kind) {
966
1002
  case "union":
@@ -975,7 +1011,7 @@ function describeSchema(schema) {
975
1011
  if ("_shape" in s) return { kind: "shape", shape: s._shape, openValue: s._openSchema };
976
1012
  if ("item" in s) return { kind: "array", item: s.item };
977
1013
  if ("inner" in s) return { kind: "optional", inner: s.inner };
978
- if ("fn" in s) return { kind: "lazy", resolved: (_a = s.resolved) != null ? _a : s.resolved = s.fn() };
1014
+ if ("fn" in s) return { kind: "lazy", resolved: (_a2 = s.resolved) != null ? _a2 : s.resolved = s.fn() };
979
1015
  return { kind: "leaf" };
980
1016
  }
981
1017
  var px = {
@@ -1030,25 +1066,455 @@ var px = {
1030
1066
  lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
1031
1067
  };
1032
1068
 
1033
- // src/PxAnimatorConstants.ts
1069
+ // src/version/PxSchemaVersion.ts
1070
+ var PX_PLAYER_SCHEMA_VERSION = "1.1";
1071
+
1072
+ // src/version/PxWireVersion.ts
1073
+ var WIRE_VERSION_KEY = "version";
1074
+ var ANIMATOR_KEY = "animator";
1075
+ var META_KEY = "meta";
1076
+ var WireVersionRelation = /* @__PURE__ */ ((WireVersionRelation2) => {
1077
+ WireVersionRelation2["unstamped"] = "unstamped";
1078
+ WireVersionRelation2["same"] = "same";
1079
+ WireVersionRelation2["older"] = "older";
1080
+ WireVersionRelation2["newer"] = "newer";
1081
+ WireVersionRelation2["otherGeneration"] = "otherGeneration";
1082
+ return WireVersionRelation2;
1083
+ })(WireVersionRelation || {});
1084
+ var VERSION_RE = /^(\d+)\.(\d+)(?:\.(\d+))?$/;
1085
+ function parseWireVersion(raw) {
1086
+ if (typeof raw !== "string") return void 0;
1087
+ const m = VERSION_RE.exec(raw.trim());
1088
+ if (!m) return void 0;
1089
+ return { a: Number(m[1]), b: Number(m[2]), c: m[3] === void 0 ? 0 : Number(m[3]) };
1090
+ }
1091
+ function formatWireVersion(v) {
1092
+ return v.a + "." + v.b + "." + v.c;
1093
+ }
1094
+ var _a;
1095
+ var PLAYER_WIRE_VERSION = (_a = parseWireVersion(PX_PLAYER_SCHEMA_VERSION)) != null ? _a : { a: 1, b: 1, c: 0 };
1096
+ function getAnimatorBlock(doc) {
1097
+ if (!doc || typeof doc !== "object") return void 0;
1098
+ const atRoot = readObjectProp(doc, ANIMATOR_KEY);
1099
+ if (atRoot) return atRoot;
1100
+ const meta = readObjectProp(doc, META_KEY);
1101
+ return meta ? readObjectProp(meta, ANIMATOR_KEY) : void 0;
1102
+ }
1103
+ function readObjectProp(obj, key) {
1104
+ const value = obj[key];
1105
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1106
+ }
1107
+ function readWireVersion(doc) {
1108
+ const animator = getAnimatorBlock(doc);
1109
+ return animator ? parseWireVersion(animator[WIRE_VERSION_KEY]) : void 0;
1110
+ }
1111
+ function compareWireVersion(file, mine, readerReadsEditorPart) {
1112
+ if (!file) return "unstamped" /* unstamped */;
1113
+ if (file.a !== mine.a) return "otherGeneration" /* otherGeneration */;
1114
+ if (file.b !== mine.b) return file.b > mine.b ? "newer" /* newer */ : "older" /* older */;
1115
+ if (!readerReadsEditorPart || file.c === mine.c) return "same" /* same */;
1116
+ return file.c > mine.c ? "newer" /* newer */ : "older" /* older */;
1117
+ }
1118
+ function versionAdvice(relation, file, mine, isPlayer) {
1119
+ if (!file) return void 0;
1120
+ const target = isPlayer ? "player" : "editor";
1121
+ const gap = "written for schema " + formatWireVersion(file) + ", this " + target + " reads " + formatWireVersion(mine);
1122
+ switch (relation) {
1123
+ case "newer" /* newer */:
1124
+ return "This file is " + gap + ". Update the " + target + " to open it fully.";
1125
+ case "older" /* older */:
1126
+ return "This file is " + gap + ". Saving it from this " + target + " rewrites it in the current format.";
1127
+ case "otherGeneration" /* otherGeneration */:
1128
+ 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.";
1129
+ default:
1130
+ return void 0;
1131
+ }
1132
+ }
1133
+ var WireStepKind = /* @__PURE__ */ ((WireStepKind2) => {
1134
+ WireStepKind2["additive"] = "additive";
1135
+ WireStepKind2["converted"] = "converted";
1136
+ return WireStepKind2;
1137
+ })(WireStepKind || {});
1138
+ var BASELINE_PLAYER_VERSION = "1.1";
1139
+ var PLAYER_WIRE_STEPS = [];
1140
+ function applyWireSteps(doc, cfg) {
1141
+ const from = readWireVersion(doc);
1142
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1143
+ if (!from || relation !== "older" /* older */) {
1144
+ return {
1145
+ doc,
1146
+ from,
1147
+ relation,
1148
+ applied: [],
1149
+ advice: versionAdvice(relation, from, cfg.target, !cfg.readerReadsEditorPart)
1150
+ };
1151
+ }
1152
+ const due = [];
1153
+ for (const step of cfg.steps) {
1154
+ const stepTo = parseWireVersion(step.to);
1155
+ if (!stepTo) continue;
1156
+ if (compareWireVersion(from, stepTo, cfg.readerReadsEditorPart) !== "older" /* older */) continue;
1157
+ if (!step.up) continue;
1158
+ due.push(step);
1159
+ }
1160
+ if (!due.length || !doc || typeof doc !== "object") return { doc, from, relation, applied: [] };
1161
+ const target = clonePlain(doc);
1162
+ const applied = [];
1163
+ for (const step of due) {
1164
+ try {
1165
+ step.up(target);
1166
+ applied.push(step);
1167
+ } catch (e) {
1168
+ break;
1169
+ }
1170
+ }
1171
+ if (!applied.length) return { doc, from, relation, applied: [] };
1172
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1173
+ return { doc: target, from, relation, applied };
1174
+ }
1175
+ function convertPlayerDocument(doc) {
1176
+ return applyWireSteps(doc, {
1177
+ steps: PLAYER_WIRE_STEPS,
1178
+ target: PLAYER_WIRE_VERSION,
1179
+ readerReadsEditorPart: false
1180
+ });
1181
+ }
1182
+ function clonePlain(value) {
1183
+ const structured = globalThis.structuredClone;
1184
+ return structured ? structured(value) : JSON.parse(JSON.stringify(value));
1185
+ }
1186
+ function stampVersion(doc, target, readerReadsEditorPart) {
1187
+ const animator = getAnimatorBlock(doc);
1188
+ if (!animator) return;
1189
+ const previous = parseWireVersion(animator[WIRE_VERSION_KEY]);
1190
+ animator[WIRE_VERSION_KEY] = formatWireVersion({
1191
+ a: target.a,
1192
+ b: target.b,
1193
+ c: readerReadsEditorPart ? target.c : previous ? previous.c : 0
1194
+ });
1195
+ }
1196
+ function applyWireStepsDown(doc, cfg) {
1197
+ const from = readWireVersion(doc);
1198
+ if (!from) {
1199
+ return { ok: false, blocking: [], reason: "The document carries no version, so there is nothing to convert down from." };
1200
+ }
1201
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1202
+ if (relation === "otherGeneration" /* otherGeneration */) {
1203
+ return {
1204
+ ok: false,
1205
+ blocking: [],
1206
+ reason: "Schema " + formatWireVersion(from) + " and " + formatWireVersion(cfg.target) + " are different generations; no conversion bridges them."
1207
+ };
1208
+ }
1209
+ if (relation !== "newer" /* newer */) return { ok: true, doc, applied: [] };
1210
+ const toUndo = [];
1211
+ for (const step of cfg.steps) {
1212
+ const stepTo = parseWireVersion(step.to);
1213
+ if (!stepTo) continue;
1214
+ if (compareWireVersion(stepTo, cfg.target, cfg.readerReadsEditorPart) !== "newer" /* newer */) continue;
1215
+ if (compareWireVersion(stepTo, from, cfg.readerReadsEditorPart) === "newer" /* newer */) continue;
1216
+ toUndo.push(step);
1217
+ }
1218
+ toUndo.reverse();
1219
+ const blocking = toUndo.filter((s) => s.kind === "converted" /* converted */ && !s.down);
1220
+ if (blocking.length) {
1221
+ return {
1222
+ ok: false,
1223
+ blocking,
1224
+ reason: "Cannot convert down to " + formatWireVersion(cfg.target) + ": " + blocking.map((s) => s.from + " \u2192 " + s.to + " (" + s.reason + ")").join("; ") + " cannot be undone."
1225
+ };
1226
+ }
1227
+ const target = clonePlain(doc);
1228
+ const applied = [];
1229
+ for (const step of toUndo) {
1230
+ if (!step.down) continue;
1231
+ try {
1232
+ step.down(target);
1233
+ applied.push(step);
1234
+ } catch (e) {
1235
+ return {
1236
+ ok: false,
1237
+ blocking: [step],
1238
+ reason: "Undoing " + step.from + " \u2192 " + step.to + " failed: " + String(e)
1239
+ };
1240
+ }
1241
+ }
1242
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1243
+ return { ok: true, doc: target, applied };
1244
+ }
1245
+ function downgradePlayerDocument(doc, target) {
1246
+ return applyWireStepsDown(doc, { steps: PLAYER_WIRE_STEPS, target, readerReadsEditorPart: false });
1247
+ }
1248
+
1249
+ // src/version/PxSchemaFieldUniverse.ts
1250
+ function schemaFieldUniverse(root) {
1251
+ const fields = /* @__PURE__ */ new Set();
1252
+ const enumerated = /* @__PURE__ */ new Set();
1253
+ const queue = [{ schema: root, path: "" }];
1254
+ while (queue.length) {
1255
+ const { schema, path } = queue.shift();
1256
+ const d = describeSchema(schema);
1257
+ switch (d.kind) {
1258
+ case "shape": {
1259
+ if (enumerated.has(schema)) break;
1260
+ enumerated.add(schema);
1261
+ for (const key of Object.keys(d.shape)) {
1262
+ const id = path ? path + "." + key : key;
1263
+ fields.add(id);
1264
+ queue.push({ schema: d.shape[key], path: id });
1265
+ }
1266
+ if (d.openValue) queue.push({ schema: d.openValue, path: path + "{*}" });
1267
+ break;
1268
+ }
1269
+ case "optional":
1270
+ queue.push({ schema: d.inner, path });
1271
+ break;
1272
+ case "array":
1273
+ queue.push({ schema: d.item, path: path + "[]" });
1274
+ break;
1275
+ case "lazy":
1276
+ queue.push({ schema: d.resolved, path });
1277
+ break;
1278
+ case "record":
1279
+ queue.push({ schema: d.value, path: path + "{*}" });
1280
+ break;
1281
+ case "union":
1282
+ d.members.forEach((member, i) => queue.push({ schema: member, path: path + "|" + i }));
1283
+ break;
1284
+ case "discriminatedUnion":
1285
+ for (const member of d.members) queue.push({ schema: member, path: path + "|" + discriminantOf(member, d.key) });
1286
+ break;
1287
+ default:
1288
+ break;
1289
+ }
1290
+ }
1291
+ return [...fields].sort();
1292
+ }
1293
+ function discriminantOf(member, key) {
1294
+ const d = describeSchema(member);
1295
+ if (d.kind !== "shape") return "?";
1296
+ const keySchema = d.shape[key];
1297
+ if (keySchema === void 0) return "?";
1298
+ const kd = describeSchema(keySchema);
1299
+ return String((kd.kind === "optional" ? kd.inner : keySchema)._default);
1300
+ }
1301
+
1302
+ // src/version/PxSchemaRelease.ts
1303
+ function diffFieldUniverse(previous, current) {
1304
+ const prev = new Set(previous);
1305
+ const cur = new Set(current);
1306
+ return {
1307
+ added: current.filter((k) => !prev.has(k)).sort(),
1308
+ removed: previous.filter((k) => !cur.has(k)).sort()
1309
+ };
1310
+ }
1311
+ function planSchemaRelease(p) {
1312
+ const changed = p.added.length > 0 || p.removed.length > 0;
1313
+ const last = parseWireVersion(p.lastReleased);
1314
+ const declared = parseWireVersion(p.declared);
1315
+ if (!last || !declared) return { changed, refuse: "Unparseable version: " + p.lastReleased + " / " + p.declared + "." };
1316
+ const requiredVersion = last.a + "." + (last.b + 1);
1317
+ if (!changed) {
1318
+ if (declared.b === last.b && declared.a === last.a) return { changed };
1319
+ const step2 = p.steps.find((s) => s.to === p.declared);
1320
+ return step2 ? { changed, requiredVersion: p.declared } : { changed, refuse: "The version moved to " + p.declared + " with no key change and no step explaining it." };
1321
+ }
1322
+ const requiredKind = p.removed.length ? "converted" /* converted */ : "additive" /* additive */;
1323
+ const summary = p.added.length + " key(s) added, " + p.removed.length + " removed";
1324
+ if (declared.a !== last.a || declared.b !== last.b + 1) {
1325
+ return {
1326
+ changed,
1327
+ requiredKind,
1328
+ requiredVersion,
1329
+ 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."
1330
+ };
1331
+ }
1332
+ const step = p.steps.find((s) => s.to === p.declared);
1333
+ if (!step) {
1334
+ return { changed, requiredKind, requiredVersion, refuse: "No PLAYER_WIRE_STEPS entry reaches " + p.declared + "." };
1335
+ }
1336
+ if (requiredKind === "converted" /* converted */ && step.kind !== "converted" /* converted */) {
1337
+ return {
1338
+ changed,
1339
+ requiredKind,
1340
+ requiredVersion,
1341
+ refuse: "Keys were REMOVED (" + p.removed.join(", ") + "), which is never additive \u2014 the " + p.declared + " step must be `converted`, with an up()."
1342
+ };
1343
+ }
1344
+ return { changed, requiredKind, requiredVersion };
1345
+ }
1346
+ function releaseLogProblems(releases, steps, declared, baseline) {
1347
+ const problems = [];
1348
+ if (!releases.length) return ["The release log is empty."];
1349
+ if (!releases[0].baseline || releases[0].version !== baseline) {
1350
+ problems.push("The first release must be the baseline " + baseline + ".");
1351
+ }
1352
+ for (let i = 1; i < releases.length; i++) {
1353
+ const prev = parseWireVersion(releases[i - 1].version);
1354
+ const cur = parseWireVersion(releases[i].version);
1355
+ if (!prev || !cur || cur.a !== prev.a || cur.b !== prev.b + 1) {
1356
+ problems.push("Release " + releases[i].version + " does not follow " + releases[i - 1].version + " by one `b` step.");
1357
+ }
1358
+ if (releases[i].date < releases[i - 1].date) problems.push("Release " + releases[i].version + " is dated before its predecessor.");
1359
+ const step = steps.find((s) => s.to === releases[i].version);
1360
+ if (!step) problems.push("Release " + releases[i].version + " has no PLAYER_WIRE_STEPS entry.");
1361
+ else if (releases[i].removed.length && step.kind !== "converted" /* converted */) {
1362
+ problems.push("Release " + releases[i].version + " removed keys, but its step is not `converted`.");
1363
+ }
1364
+ }
1365
+ const latest = releases[releases.length - 1].version;
1366
+ if (latest !== declared) {
1367
+ 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).");
1368
+ }
1369
+ return problems;
1370
+ }
1371
+
1372
+ // src/format/PxAnimatorConstants.ts
1373
+ var PxFillMode = {
1374
+ forwards: "forwards",
1375
+ backwards: "backwards",
1376
+ both: "both",
1377
+ none: "none"
1378
+ };
1379
+ var PxPlaybackDirection = {
1380
+ normal: "normal",
1381
+ reverse: "reverse",
1382
+ alternate: "alternate",
1383
+ alternateReverse: "alternate-reverse"
1384
+ };
1034
1385
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1035
1386
  var PX_ANIM_ATTR_NAME = "_px_animator";
1036
- var PxAnimatorMode = {
1037
- auto: "auto",
1038
- waapi: "waapi",
1039
- frames: "frames"
1387
+ var PxStartOn = {
1388
+ load: "load",
1389
+ mouseOver: "mouseOver",
1390
+ click: "click",
1391
+ scrollIntoView: "scrollIntoView",
1392
+ programmatic: "programmatic"
1393
+ };
1394
+ var PxOutAction = {
1395
+ continue: "continue",
1396
+ pause: "pause",
1397
+ reset: "reset",
1398
+ reverse: "reverse"
1399
+ };
1400
+ var PxFinishAction = {
1401
+ hold: "hold",
1402
+ reset: "reset"
1403
+ };
1404
+ var PxScrollKind = {
1405
+ view: "view",
1406
+ scroll: "scroll"
1407
+ };
1408
+ var PxScrollAxis = {
1409
+ block: "block",
1410
+ inline: "inline",
1411
+ x: "x",
1412
+ y: "y"
1040
1413
  };
1041
- var PxAnimatorEngine = {
1042
- waapi: PxAnimatorMode.waapi,
1043
- frames: PxAnimatorMode.frames
1414
+ var PxScrollSource = {
1415
+ nearest: "nearest",
1416
+ root: "root"
1417
+ };
1418
+ var PxPinAlign = {
1419
+ top: "top",
1420
+ center: "center",
1421
+ bottom: "bottom"
1422
+ };
1423
+ var PxScrollPhase = {
1424
+ cover: "cover",
1425
+ contain: "contain",
1426
+ entry: "entry",
1427
+ exit: "exit",
1428
+ entryCrossing: "entry-crossing",
1429
+ exitCrossing: "exit-crossing"
1430
+ };
1431
+ var PxAlongPathMode = {
1432
+ sampled: "sampled",
1433
+ offsetPath: "offsetPath"
1434
+ };
1435
+ var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
1436
+ var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
1437
+ var PX_FLAT_RUNTIME_VIEW_KEYS = [
1438
+ ...PX_TIMELINE_SHARED_KEYS,
1439
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
1440
+ "fill",
1441
+ "resetOnFinish",
1442
+ "timelineSource",
1443
+ "scroll"
1444
+ ];
1445
+ var PxTimelineEngine = {
1446
+ native: "native",
1447
+ js: "js"
1448
+ };
1449
+ var PxTimelineEngineExtra = __spreadProps(__spreadValues({}, PxTimelineEngine), {
1450
+ auto: "auto"
1451
+ });
1452
+ function resolveTimelineEngine(engine) {
1453
+ return engine === PxTimelineEngineExtra.js ? PxTimelineEngine.js : PxTimelineEngine.native;
1454
+ }
1455
+ function isNativeForced(engine) {
1456
+ return engine === PxTimelineEngineExtra.native;
1457
+ }
1458
+ function mayUseNativeScrollTimeline(engine) {
1459
+ return engine !== PxTimelineEngineExtra.js;
1460
+ }
1461
+ var PX_TRIGGER_DEFAULTS = {
1462
+ startOn: "load",
1463
+ outAction: "continue",
1464
+ scrollIntoViewThreshold: 0
1465
+ };
1466
+ var PxControlMode = {
1467
+ /** No control props — the document's trigger decides, and nothing is taken over. */
1468
+ static: "static",
1469
+ /** `progress` / `time` — the host scrubs; the component seeks and stays paused. */
1470
+ fixedTime: "fixedTime",
1471
+ /** `play` / `pause` — the host drives playback with booleans. */
1472
+ play: "play",
1473
+ /** `autoplay` — the document's own trigger starts it. */
1474
+ autoplay: "autoplay"
1475
+ };
1476
+ function resolveControlMode(props) {
1477
+ const hasFixedTime = props.progress !== void 0 || props.time !== void 0;
1478
+ const hasPlayPause = props.play !== void 0 || props.pause !== void 0;
1479
+ const hasAutoplay = !!props.autoplay;
1480
+ const warnings = [];
1481
+ const named = (a, b, winner) => a + " and " + b + " were both set \u2014 " + winner + " wins, " + (winner === a ? b : a) + " is ignored.";
1482
+ if (hasFixedTime) {
1483
+ if (hasPlayPause) warnings.push(named("progress/time", "play/pause", "progress/time"));
1484
+ if (hasAutoplay) warnings.push(named("progress/time", "autoplay", "progress/time"));
1485
+ return { mode: PxControlMode.fixedTime, warnings };
1486
+ }
1487
+ if (hasPlayPause) {
1488
+ if (hasAutoplay) warnings.push(named("play/pause", "autoplay", "play/pause"));
1489
+ return { mode: PxControlMode.play, warnings };
1490
+ }
1491
+ if (hasAutoplay) return { mode: PxControlMode.autoplay, warnings };
1492
+ return { mode: PxControlMode.static, warnings };
1493
+ }
1494
+ function controlModeTakesOverTrigger(mode) {
1495
+ return mode !== PxControlMode.autoplay;
1496
+ }
1497
+ function resolveTrigger(trigger) {
1498
+ var _a2, _b, _c;
1499
+ return {
1500
+ startOn: (_a2 = trigger == null ? void 0 : trigger.startOn) != null ? _a2 : PX_TRIGGER_DEFAULTS.startOn,
1501
+ outAction: (_b = trigger == null ? void 0 : trigger.outAction) != null ? _b : PX_TRIGGER_DEFAULTS.outAction,
1502
+ scrollIntoViewThreshold: (_c = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _c : PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold
1503
+ };
1504
+ }
1505
+ var PxLoopRepeatAt = {
1506
+ /** Segment from the START; the repetition runs BEFORE the first keyframe
1507
+ * (intro loops that play until the main timeline begins). */
1508
+ start: "start",
1509
+ /** DEFAULT — segment from the END; the repetition runs AFTER the last keyframe
1510
+ * (idle/outro loops that continue once the main timeline has finished). */
1511
+ end: "end"
1044
1512
  };
1045
- var PxLoopExtend = {
1046
- /** Segment from the START; the animation is extended BEFORE the first keyframe
1047
- * (intro loops that run before the main timeline begins). */
1048
- before: "before",
1049
- /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
1050
- * loops that continue once the main timeline has finished). */
1051
- after: "after"
1513
+ var PxLoopDirection = {
1514
+ /** DEFAULT — cycle: every repetition replays the segment the same way round. */
1515
+ normal: "normal",
1516
+ /** Ping-pong: repetitions alternate forward / backward. */
1517
+ alternate: "alternate"
1052
1518
  };
1053
1519
  var PxMaskType = {
1054
1520
  luminance: "luminance",
@@ -1058,8 +1524,9 @@ var PxUnits = {
1058
1524
  userSpaceOnUse: "userSpaceOnUse",
1059
1525
  objectBoundingBox: "objectBoundingBox"
1060
1526
  };
1061
- var PxCloneType = {
1062
- content: "content"
1527
+ var PxCloneWithout = {
1528
+ translate: "translate"
1529
+ // transform: 'transform', // future: drop rotate/scale too (content only)
1063
1530
  };
1064
1531
  var PxPathOverflow = {
1065
1532
  clip: "clip",
@@ -1081,8 +1548,10 @@ var PxStrokeTrimSubPaths = {
1081
1548
  separate: "separate",
1082
1549
  combined: "combined"
1083
1550
  };
1084
- var TEXT_ATTR = "text";
1085
1551
  var TEXT_CONTENT_ATTR = "textContent";
1552
+ var CLASS_ATTR = "class";
1553
+ var TRANSFORM_ATTR = "transform";
1554
+ var OFFSET_DISTANCE_ATTR = "offsetDistance";
1086
1555
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1087
1556
  "type",
1088
1557
  "children",
@@ -1090,14 +1559,20 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1090
1559
  "meta",
1091
1560
  "animate",
1092
1561
  "effects",
1093
- TEXT_ATTR,
1094
1562
  TEXT_CONTENT_ATTR
1095
1563
  ]);
1096
- var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
1097
- var PxGradientUnits = {
1098
- userSpaceOnUse: "userSpaceOnUse",
1099
- objectBoundingBox: "objectBoundingBox"
1564
+ var TRANSFORM_PART = {
1565
+ translate: "translate",
1566
+ rotate: "rotate",
1567
+ scale: "scale",
1568
+ origin: "origin"
1100
1569
  };
1570
+ var PX_TRANSFORM_PART_KEYS = [
1571
+ TRANSFORM_PART.translate,
1572
+ TRANSFORM_PART.rotate,
1573
+ TRANSFORM_PART.scale,
1574
+ TRANSFORM_PART.origin
1575
+ ];
1101
1576
  var PxGradientSpreadMethod = {
1102
1577
  pad: "pad",
1103
1578
  reflect: "reflect",
@@ -1111,27 +1586,38 @@ function isPxElementFileFormat(fileJson) {
1111
1586
  if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
1112
1587
  return false;
1113
1588
  }
1114
- return fileJson["type"] === "svg";
1589
+ return fileJson.type === "svg";
1115
1590
  }
1116
1591
  function getAnimatorConfig(doc) {
1117
- var _a;
1118
- const cfg = (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
1119
- return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1120
- }
1592
+ var _a2;
1593
+ const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
1594
+ if (!cfg) return void 0;
1595
+ const memoised = wireViewMemo.get(cfg);
1596
+ if (memoised) return memoised;
1597
+ const wire = cfg;
1598
+ const stray = PX_FLAT_RUNTIME_VIEW_KEYS.filter((k) => wire[k] !== void 0);
1599
+ const source = stray.length ? __spreadValues({}, wire) : cfg;
1600
+ for (const k of stray) delete source[k];
1601
+ const view = flattenAnimatorTimeline(source);
1602
+ wireViewMemo.set(cfg, view);
1603
+ return view;
1604
+ }
1605
+ var wireViewMemo = /* @__PURE__ */ new WeakMap();
1121
1606
  var flattenMemo = /* @__PURE__ */ new WeakMap();
1122
1607
  function flattenAnimatorTimeline(cfg) {
1123
1608
  const timeline = cfg.timeline;
1124
1609
  if (timeline === void 0 || timeline === null || typeof timeline !== "object") return cfg;
1125
1610
  const memoised = flattenMemo.get(cfg);
1126
1611
  if (memoised) return memoised;
1127
- const _a = cfg, { timeline: _dropped } = _a, flat = __objRest(_a, ["timeline"]);
1612
+ const _a2 = cfg, { timeline: _dropped } = _a2, flat = __objRest(_a2, ["timeline"]);
1613
+ if (timeline.engine !== void 0) flat.engine = timeline.engine;
1614
+ if (timeline.frameRate !== void 0) flat.frameRate = timeline.frameRate;
1128
1615
  if (timeline.type === "scroll" || timeline.type === "view") {
1129
1616
  flat.timelineSource = "scroll";
1130
1617
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
1131
1618
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1132
1619
  const scroll = __spreadValues({}, flat.scroll || {});
1133
1620
  scroll.kind = timeline.type;
1134
- if (timeline.engine !== void 0) scroll.driver = timeline.engine;
1135
1621
  if (timeline.axis !== void 0) scroll.axis = timeline.axis;
1136
1622
  if (timeline.source !== void 0) scroll.source = timeline.source;
1137
1623
  if (timeline.subject !== void 0) scroll.subject = timeline.subject;
@@ -1142,28 +1628,31 @@ function flattenAnimatorTimeline(cfg) {
1142
1628
  else if (pin && typeof pin === "object") {
1143
1629
  scroll.pin = true;
1144
1630
  if (pin.align !== void 0) scroll.pinAlign = pin.align;
1145
- if (pin.top !== void 0) scroll.pinTop = pin.top;
1631
+ if (pin.offset !== void 0) scroll.pinOffset = pin.offset;
1146
1632
  if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1147
1633
  }
1148
1634
  flat.scroll = scroll;
1149
1635
  } else {
1150
1636
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
1151
1637
  if (timeline.trigger !== void 0) {
1152
- const _b = timeline.trigger, { onFinish } = _b, restTrigger = __objRest(_b, ["onFinish"]);
1638
+ const _b = timeline.trigger, { finishAction } = _b, restTrigger = __objRest(_b, ["finishAction"]);
1153
1639
  if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
1154
- if (onFinish !== void 0) flat.resetOnFinish = onFinish === "reset";
1640
+ if (finishAction !== void 0) flat.resetOnFinish = finishAction === "reset";
1155
1641
  }
1156
1642
  if (timeline.delay !== void 0) flat.delay = timeline.delay;
1157
1643
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1158
1644
  if (timeline.direction !== void 0) flat.direction = timeline.direction;
1159
- if (timeline.fill !== void 0) flat.fill = timeline.fill;
1645
+ if (timeline.fillMode !== void 0) flat.fill = timeline.fillMode;
1160
1646
  }
1161
1647
  flattenMemo.set(cfg, flat);
1162
1648
  return flat;
1163
1649
  }
1650
+ function scrollKindOrDefault(kind) {
1651
+ return kind === "scroll" ? "scroll" : "view";
1652
+ }
1164
1653
  function nestAnimatorTimeline(cfg) {
1165
1654
  if (!cfg || cfg.timeline !== void 0) return cfg;
1166
- const _a = cfg, {
1655
+ const _a2 = cfg, {
1167
1656
  timelineSource,
1168
1657
  scroll,
1169
1658
  trigger,
@@ -1172,8 +1661,10 @@ function nestAnimatorTimeline(cfg) {
1172
1661
  direction,
1173
1662
  fill,
1174
1663
  resetOnFinish,
1175
- duration
1176
- } = _a, shared = __objRest(_a, [
1664
+ duration,
1665
+ engine,
1666
+ frameRate
1667
+ } = _a2, shared = __objRest(_a2, [
1177
1668
  "timelineSource",
1178
1669
  "scroll",
1179
1670
  "trigger",
@@ -1182,50 +1673,55 @@ function nestAnimatorTimeline(cfg) {
1182
1673
  "direction",
1183
1674
  "fill",
1184
1675
  "resetOnFinish",
1185
- "duration"
1676
+ "duration",
1677
+ "engine",
1678
+ "frameRate"
1186
1679
  ]);
1187
1680
  if (timelineSource === "scroll") {
1188
- const timeline2 = { type: (scroll == null ? void 0 : scroll.kind) === "view" ? "view" : "scroll" };
1681
+ const timeline2 = { type: scrollKindOrDefault(scroll == null ? void 0 : scroll.kind) };
1682
+ if (engine !== void 0) timeline2.engine = engine;
1683
+ if (frameRate !== void 0) timeline2.frameRate = frameRate;
1189
1684
  if (duration !== void 0) timeline2.duration = duration;
1190
1685
  if (typeof iterations === "number") timeline2.iterations = iterations;
1191
1686
  if (scroll) {
1192
- if (scroll.driver !== void 0) timeline2.engine = scroll.driver;
1193
1687
  if (scroll.axis !== void 0) timeline2.axis = scroll.axis;
1194
1688
  if (scroll.source !== void 0) timeline2.source = scroll.source;
1195
1689
  if (scroll.subject !== void 0) timeline2.subject = scroll.subject;
1196
1690
  if (scroll.smoothing !== void 0) timeline2.smoothing = scroll.smoothing;
1197
1691
  if (scroll.range !== void 0) timeline2.range = scroll.range;
1198
- const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinTop !== void 0 || scroll.pinDistance !== void 0;
1692
+ const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinOffset !== void 0 || scroll.pinDistance !== void 0;
1199
1693
  if (hasPinParams) {
1200
- 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 } : {});
1694
+ timeline2.pin = __spreadValues(__spreadValues(__spreadValues({}, scroll.pinAlign !== void 0 ? { align: scroll.pinAlign } : {}), scroll.pinOffset !== void 0 ? { offset: scroll.pinOffset } : {}), scroll.pinDistance !== void 0 ? { distance: scroll.pinDistance } : {});
1201
1695
  } else if (scroll.pin !== void 0) {
1202
1696
  timeline2.pin = scroll.pin;
1203
1697
  }
1204
1698
  }
1205
1699
  return __spreadProps(__spreadValues({}, shared), { timeline: timeline2 });
1206
1700
  }
1207
- const timeline = { type: "clock" };
1701
+ const timeline = {};
1702
+ if (engine !== void 0) timeline.engine = engine;
1703
+ if (frameRate !== void 0) timeline.frameRate = frameRate;
1208
1704
  if (duration !== void 0) timeline.duration = duration;
1209
1705
  if (trigger !== void 0 || resetOnFinish) {
1210
1706
  const t = __spreadValues({}, trigger || {});
1211
- if (resetOnFinish) t.onFinish = "reset";
1707
+ if (resetOnFinish) t.finishAction = "reset";
1212
1708
  timeline.trigger = t;
1213
1709
  }
1214
1710
  if (delay !== void 0) timeline.delay = delay;
1215
1711
  if (iterations !== void 0) timeline.iterations = iterations;
1216
1712
  if (direction !== void 0) timeline.direction = direction;
1217
- if (fill !== void 0) timeline.fill = fill;
1218
- return Object.keys(timeline).length > 1 ? __spreadProps(__spreadValues({}, shared), { timeline }) : shared;
1713
+ if (fill !== void 0) timeline.fillMode = fill;
1714
+ return Object.keys(timeline).length > 0 ? __spreadProps(__spreadValues({}, shared), { timeline }) : shared;
1219
1715
  }
1220
1716
  function getDefs(doc) {
1221
- var _a;
1717
+ var _a2;
1222
1718
  if (!doc) return void 0;
1223
- return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
1719
+ return (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
1224
1720
  }
1225
1721
  function getBindings(doc) {
1226
- var _a;
1722
+ var _a2;
1227
1723
  if (!doc) return void 0;
1228
- const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
1724
+ const animateById = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.animateById;
1229
1725
  if (!animateById) return void 0;
1230
1726
  return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
1231
1727
  }
@@ -1233,7 +1729,7 @@ function getChildren(doc) {
1233
1729
  return doc == null ? void 0 : doc.children;
1234
1730
  }
1235
1731
 
1236
- // src/PxAnimatorTypes.ts
1732
+ // src/format/PxAnimatorTypes.ts
1237
1733
  var PxEasingOrRefSchema = px.union([
1238
1734
  px.string(),
1239
1735
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -1243,14 +1739,13 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
1243
1739
  // e.g. for colors
1244
1740
  px.number(),
1245
1741
  px.array(px.number()),
1246
- // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1742
+ // ORDER LAW: the key-discriminated object shape (`{pathData}`) comes BEFORE the
1247
1743
  // all-optional transform-parts record. In default (non-strict) mode that record accepts
1248
1744
  // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1249
- // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1745
+ // Union.sanitize route `{pathData}` values into it and strip them to `{}` —
1250
1746
  // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1251
1747
  // order-independent (`some()`); only sanitize routing depends on this order.
1252
- px.object({ path: px.string() }),
1253
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1748
+ px.object({ pathData: px.string() }),
1254
1749
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1255
1750
  px.lazy(() => px.array(PxGradientStopSchema), []),
1256
1751
  px.lazy(() => PxTransformPartsSchema, {})
@@ -1265,16 +1760,32 @@ var PxKeyframeSchema = implementsInterface()(px.object({
1265
1760
  // (review §1.3): editor data lives under `meta`. The editor still carries it on
1266
1761
  // its internal COPY-PASTE payload, which never validates against this schema.)
1267
1762
  }));
1763
+ var anyKf = (kf) => kf;
1764
+ var kfTime = (kf) => {
1765
+ var _a2, _b;
1766
+ return (_b = (_a2 = anyKf(kf).time) != null ? _a2 : anyKf(kf).t) != null ? _b : 0;
1767
+ };
1768
+ var kfValue = (kf) => {
1769
+ var _a2;
1770
+ return (_a2 = anyKf(kf).value) != null ? _a2 : anyKf(kf).v;
1771
+ };
1772
+ var kfEasing = (kf) => {
1773
+ var _a2;
1774
+ return (_a2 = anyKf(kf).easing) != null ? _a2 : anyKf(kf).e;
1775
+ };
1776
+ var kfTangentIn = (kf) => anyKf(kf).tangentIn;
1777
+ var kfTangentOut = (kf) => anyKf(kf).tangentOut;
1268
1778
  var PxLoopSchema = implementsInterface()(px.object({
1269
1779
  segmentCount: px.number().optional(),
1270
- extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
1271
- alternate: px.boolean().optional()
1780
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1781
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1272
1782
  }));
1273
1783
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1274
1784
  value: PxKeyframeValueSchema.optional(),
1275
1785
  keyframes: px.array(PxKeyframeSchema).optional(),
1276
1786
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1277
- autoOrient: px.boolean().optional()
1787
+ autoOrient: px.boolean().optional(),
1788
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
1278
1789
  }));
1279
1790
  var PxTransformPartsSchema = implementsInterface()(px.object({
1280
1791
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1298,18 +1809,17 @@ var PxElementAnimationSchema = implementsInterface()(px.union([
1298
1809
  PxAnimationDefinitionSchema
1299
1810
  ]));
1300
1811
  var PxTriggerSchema = implementsInterface()(px.object({
1301
- startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1302
- outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1812
+ startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic], PX_TRIGGER_DEFAULTS.startOn).optional(),
1813
+ outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse], PX_TRIGGER_DEFAULTS.outAction).optional(),
1303
1814
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1304
- // `fill`) or `'reset'` (snap back to the start state). The trigger-vocabulary home of
1305
- // the old top-level `resetOnFinish: boolean` (read-legacy) — review §2.3: both
1306
- // "what happens at the end" knobs now sit side by side and share one style of value.
1307
- onFinish: px.enum(["hold", "reset"]).optional(),
1815
+ // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1816
+ // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1817
+ finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
1308
1818
  scrollIntoViewThreshold: px.number().optional()
1309
1819
  }));
1310
1820
  var PxGlyphSchema = implementsInterface()(px.object({
1311
1821
  width: px.number(),
1312
- d: px.string()
1822
+ pathData: px.string()
1313
1823
  }));
1314
1824
  var PxGlyphFontSchema = implementsInterface()(px.object({
1315
1825
  fontFamily: px.string(),
@@ -1324,11 +1834,17 @@ var PxDefsSchema = implementsInterface()(px.object({
1324
1834
  // Review §2.6: the schema now matches the declared type — a style preset is a flat
1325
1835
  // record of string|number attribute values, nothing nested.
1326
1836
  styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1327
- glyphs: px.record(PxGlyphFontSchema).optional()
1837
+ fonts: px.record(PxGlyphFontSchema).optional()
1328
1838
  }));
1329
- var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1330
1839
  var PxScrollRangePointSchema = implementsInterface()(px.object({
1331
- phase: px.enum(PX_SCROLL_PHASES).optional(),
1840
+ phase: px.enum([
1841
+ PxScrollPhase.cover,
1842
+ PxScrollPhase.contain,
1843
+ PxScrollPhase.entry,
1844
+ PxScrollPhase.exit,
1845
+ PxScrollPhase.entryCrossing,
1846
+ PxScrollPhase.exitCrossing
1847
+ ]).optional(),
1332
1848
  fraction: px.number().optional()
1333
1849
  }));
1334
1850
  var PxScrollRangeSchema = px.object({
@@ -1336,34 +1852,38 @@ var PxScrollRangeSchema = px.object({
1336
1852
  end: PxScrollRangePointSchema.optional()
1337
1853
  });
1338
1854
  var PxScrollSchema = implementsInterface()(px.object({
1339
- driver: px.enum(["custom", "native"]).optional(),
1340
- kind: px.enum(["view", "scroll"]).optional(),
1341
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1342
- source: px.enum(["nearest", "root"]).optional(),
1855
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
1856
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1857
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1343
1858
  // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1344
1859
  subject: px.string().optional(),
1345
1860
  smoothing: px.number().optional(),
1346
1861
  pin: px.boolean().optional(),
1347
- pinAlign: px.enum(["top", "center", "bottom"]).optional(),
1348
- pinTop: px.number().optional(),
1862
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1863
+ pinOffset: px.number().optional(),
1349
1864
  pinDistance: px.number().optional(),
1350
1865
  range: PxScrollRangeSchema.optional()
1351
1866
  }));
1352
- var PxTimelinePinSchema = px.object({
1353
- align: px.enum(["top", "center", "bottom"]).optional(),
1354
- top: px.number().optional(),
1867
+ var PxTimelinePinSchema = implementsInterface()(px.object({
1868
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1869
+ offset: px.number().optional(),
1355
1870
  distance: px.number().optional()
1356
- });
1357
- var PxClockTimelineSchema = px.object({
1358
- type: px.literal("clock"),
1871
+ }));
1872
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
1873
+ var PxTimeTimelineSchema = implementsInterface()(px.object({
1874
+ type: px.literal("time").optional(),
1875
+ engine: PxTimelineEngineSchema,
1876
+ frameRate: px.number().optional(),
1359
1877
  // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1360
1878
  duration: px.number().optional(),
1361
1879
  trigger: PxTriggerSchema.optional(),
1362
1880
  delay: px.number().optional(),
1363
1881
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1364
- fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1365
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1366
- });
1882
+ // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1883
+ // — never `fill`, which is paint everywhere else in the format.
1884
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
1885
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
1886
+ }));
1367
1887
  var scrollishTimelineShape = {
1368
1888
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1369
1889
  // span the scroll range maps onto.
@@ -1371,9 +1891,10 @@ var scrollishTimelineShape = {
1371
1891
  // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1372
1892
  // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1373
1893
  iterations: px.number().optional(),
1374
- engine: px.enum(["custom", "native"]).optional(),
1375
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1376
- source: px.enum(["nearest", "root"]).optional(),
1894
+ engine: PxTimelineEngineSchema,
1895
+ frameRate: px.number().optional(),
1896
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1897
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1377
1898
  subject: px.string().optional(),
1378
1899
  // 'parent' | 'scroller' | any CSS selector
1379
1900
  smoothing: px.number().optional(),
@@ -1381,23 +1902,29 @@ var scrollishTimelineShape = {
1381
1902
  pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1382
1903
  range: PxScrollRangeSchema.optional()
1383
1904
  };
1384
- var PxScrollTimelineSchema = px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape));
1385
- var PxViewTimelineSchema = px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape));
1905
+ var PxScrollTimelineSchema = implementsInterface()(
1906
+ px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape))
1907
+ );
1908
+ var PxViewTimelineSchema = implementsInterface()(
1909
+ px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape))
1910
+ );
1386
1911
  var PxTimelineSchema = px.discriminatedUnion("type", [
1387
- PxClockTimelineSchema,
1912
+ PxTimeTimelineSchema,
1913
+ // first = the member an absent `type` selects
1388
1914
  PxScrollTimelineSchema,
1389
1915
  PxViewTimelineSchema
1390
1916
  ]);
1391
1917
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
1392
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
1393
- // (`duration` lives INSIDE `timeline` on the wire — §2.8; the flat field below
1394
- // exists only on the runtime view, like the rest of the playback dynamics.)
1395
- frameRate: px.number().optional(),
1918
+ // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1919
+ // at this level only on the runtime view, like the rest of the playback dynamics.)
1396
1920
  // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1397
1921
  timeline: PxTimelineSchema.optional(),
1398
1922
  definitions: PxDefsSchema.optional(),
1399
1923
  animateById: px.record(PxElementAnimationSchema).optional(),
1400
- debugInstName: px.string().optional()
1924
+ debugGlobalName: px.string().optional(),
1925
+ // Declared HERE because this is a closed object: an undeclared key would be stripped by
1926
+ // `sanitize` and flagged by strict validation on our own files.
1927
+ version: px.string().optional()
1401
1928
  }));
1402
1929
  var PxBindingSchema = implementsInterface()(px.object({
1403
1930
  id: px.string(),
@@ -1446,7 +1973,7 @@ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1446
1973
  origin: PxAnimatableVec2Schema.optional()
1447
1974
  }));
1448
1975
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
1449
- sourceId: px.string().optional(),
1976
+ source: px.string().optional(),
1450
1977
  maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1451
1978
  maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1452
1979
  maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
@@ -1456,7 +1983,7 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1456
1983
  height: px.number().optional()
1457
1984
  }));
1458
1985
  var PxClipPathEffectSchema = implementsInterface()(px.object({
1459
- d: PxAnimatableStringSchema.optional()
1986
+ pathData: PxAnimatableStringSchema.optional()
1460
1987
  }));
1461
1988
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1462
1989
  offset: PxAnimatableNumberSchema.optional(),
@@ -1469,9 +1996,10 @@ var PxRetimeEffectSchema = implementsInterface()(px.object({
1469
1996
  timeCrop: px.tuple([px.number(), px.number()]).optional()
1470
1997
  }));
1471
1998
  var PxCloneEffectSchema = implementsInterface()(px.object({
1472
- // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1473
- type: px.enum([PxCloneType.content]).optional(),
1474
- sourceId: px.string().optional(),
1999
+ // Subtractive on purpose: the `<use>` can only point at one wrapper layer of the
2000
+ // source, so the choices form a ladder — 'translate' now, maybe 'transform' later.
2001
+ without: px.enum([PxCloneWithout.translate]).optional(),
2002
+ source: px.string().optional(),
1475
2003
  retime: PxRetimeEffectSchema.optional()
1476
2004
  }));
1477
2005
  var PxGradientStopSchema = implementsInterface()(px.object({
@@ -1492,13 +2020,13 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1492
2020
  radius: PxAnimatableNumberSchema.optional(),
1493
2021
  focal: PxAnimatableVec2Schema.optional(),
1494
2022
  stops: PxAnimatableGradientStopsSchema.optional(),
1495
- gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
2023
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1496
2024
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1497
2025
  gradientTransform: px.string().optional()
1498
2026
  }));
1499
2027
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1500
2028
  var PxTextPathEffectSchema = implementsInterface()(px.object({
1501
- path: px.string(),
2029
+ pathData: px.string(),
1502
2030
  pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1503
2031
  lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1504
2032
  method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
@@ -1538,20 +2066,100 @@ function validateNodeEffects(root, opts) {
1538
2066
  walk(root, "root");
1539
2067
  return warnings;
1540
2068
  }
2069
+ function validateGlyphFontRefs(root, fonts) {
2070
+ if (!fonts || !Object.keys(fonts).length) return [];
2071
+ const problems = [];
2072
+ const walk = (node, path, inherited, inGlyphText) => {
2073
+ var _a2, _b;
2074
+ if (!node) return;
2075
+ const own = typeof node.fontFamily === "string" ? node.fontFamily : void 0;
2076
+ const family = own != null ? own : inherited;
2077
+ const isGlyphText = inGlyphText || node.type === "text" && !!((_b = (_a2 = node.effects) == null ? void 0 : _a2.text) == null ? void 0 : _b.useGlyphs);
2078
+ if (isGlyphText && own && !Object.prototype.hasOwnProperty.call(fonts, own)) {
2079
+ const problem = path + ': glyph-mode text uses font-family "' + own + '", which has no entry in animator.definitions.fonts';
2080
+ if (!problems.includes(problem)) problems.push(problem);
2081
+ }
2082
+ if (Array.isArray(node.children)) {
2083
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]", family, isGlyphText));
2084
+ }
2085
+ };
2086
+ walk(root, "root", void 0, false);
2087
+ return problems;
2088
+ }
2089
+ function validateEasingRefs(root, easings) {
2090
+ const problems = [];
2091
+ const walk = (node, path) => {
2092
+ if (Array.isArray(node)) {
2093
+ node.forEach((item, i) => walk(item, path + "[" + i + "]"));
2094
+ return;
2095
+ }
2096
+ if (!node || typeof node !== "object") return;
2097
+ const easing = node.easing;
2098
+ if (typeof easing === "string" && !(easings && Object.prototype.hasOwnProperty.call(easings, easing))) {
2099
+ const problem = path + '.easing: "' + easing + '" names no entry in animator.definitions.easings \u2014 it will play linear';
2100
+ if (!problems.includes(problem)) problems.push(problem);
2101
+ }
2102
+ for (const [key, value] of Object.entries(node)) {
2103
+ if (key === "easing") continue;
2104
+ if (value && typeof value === "object") walk(value, path + "." + key);
2105
+ }
2106
+ };
2107
+ walk(root, "root");
2108
+ return problems;
2109
+ }
2110
+ function validateVersionStamp(doc) {
2111
+ var _a2;
2112
+ const version = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.version;
2113
+ if (version === void 0) return [];
2114
+ if (parseWireVersion(version) !== void 0) return [];
2115
+ return ["root.animator.version: " + JSON.stringify(version) + ' is not a version stamp ("a.b" or "a.b.c") \u2014 it reads as unstamped'];
2116
+ }
2117
+ function validateDocument(doc, opts) {
2118
+ var _a2;
2119
+ const strict = (opts == null ? void 0 : opts.strict) !== false;
2120
+ const ctx = { errors: [], warnings: [], strict };
2121
+ const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
2122
+ if (doc && typeof doc === "object") {
2123
+ for (const w of validateNodeEffects(doc, { strict })) {
2124
+ if (!problems.includes(w)) problems.push(w);
2125
+ }
2126
+ const defs = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
2127
+ for (const w of validateGlyphFontRefs(doc, defs == null ? void 0 : defs.fonts)) {
2128
+ if (!problems.includes(w)) problems.push(w);
2129
+ }
2130
+ for (const w of validateEasingRefs(doc, defs == null ? void 0 : defs.easings)) {
2131
+ if (!problems.includes(w)) problems.push(w);
2132
+ }
2133
+ for (const w of validateVersionStamp(doc)) {
2134
+ if (!problems.includes(w)) problems.push(w);
2135
+ }
2136
+ }
2137
+ return problems;
2138
+ }
1541
2139
  var PxNodeBase = px.openObject({
1542
2140
  // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1543
2141
  // kind of thing is this", discriminated by its CARRIER — here the node TAG
1544
- // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
2142
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1545
2143
  // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1546
2144
  // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1547
2145
  // would add words that all mean "type" and still need the carrier to read.
1548
2146
  // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1549
2147
  // (issues V3), never of distinct key names.
1550
2148
  type: px.string(),
2149
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
2150
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
2151
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
2152
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
2153
+ // documented — because a wire key that is not in a schema is invisible to the
2154
+ // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
2155
+ domType: px.string().optional(),
2156
+ // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
2157
+ // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
2158
+ textContent: px.string().optional(),
1551
2159
  id: px.string().optional(),
1552
2160
  meta: px.any().optional(),
1553
2161
  // Player-effects bucket emitted by the Editor's lightweight design format.
1554
- // Consumed and removed by `applyPlayerEffects` before any other normalisation
2162
+ // Consumed and removed by `applyPlayerEffects` before any other normalization
1555
2163
  // (see `createAnimatorImpl`), so downstream code never sees it.
1556
2164
  effects: PxEffectsSchema.optional(),
1557
2165
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
@@ -1583,11 +2191,11 @@ var PxBezierPathSchema = implementsInterface()(px.object({
1583
2191
  c: px.boolean().optional()
1584
2192
  }));
1585
2193
  function isPxElementFileFormatDeep(fileJson) {
1586
- const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
1587
- return { valid, errors: valid ? [] : ["Document failed schema validation"] };
2194
+ const errors = validateDocument(fileJson, { strict: false });
2195
+ return { valid: errors.length === 0, errors };
1588
2196
  }
1589
2197
 
1590
- // src/PxIdUtil.ts
2198
+ // src/util/PxIdUtil.ts
1591
2199
  var _idCounter = 0;
1592
2200
  function generateUniqueId() {
1593
2201
  const timestamp = Date.now().toString(36);
@@ -1606,7 +2214,7 @@ function deepClone(value) {
1606
2214
  return cloned;
1607
2215
  }
1608
2216
  function generateNewIds(doc) {
1609
- var _a, _b;
2217
+ var _a2, _b;
1610
2218
  const cloned = deepClone(doc);
1611
2219
  const idMap = /* @__PURE__ */ new Map();
1612
2220
  const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
@@ -1624,7 +2232,8 @@ function generateNewIds(doc) {
1624
2232
  "flood-color",
1625
2233
  "lighting-color"
1626
2234
  ]);
1627
- const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
2235
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
2236
+ const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
1628
2237
  function collectIds(node) {
1629
2238
  if (!node || typeof node !== "object") return;
1630
2239
  if (node.id && typeof node.id === "string") {
@@ -1641,7 +2250,7 @@ function generateNewIds(doc) {
1641
2250
  }
1642
2251
  }
1643
2252
  }
1644
- function updateRefs(node) {
2253
+ function updateRefs(node, parentKey) {
1645
2254
  if (!node || typeof node !== "object") return;
1646
2255
  for (const [key, value] of Object.entries(node)) {
1647
2256
  if (key === "children") {
@@ -1661,7 +2270,7 @@ function generateNewIds(doc) {
1661
2270
  }
1662
2271
  } else if (urlRefAttrs.has(key)) {
1663
2272
  node[key] = replaceUrlRefs(value, idMap);
1664
- } else if (directIdRefAttrs.has(key)) {
2273
+ } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
1665
2274
  const hasHash = value.startsWith("#");
1666
2275
  const newId = idMap.get(hasHash ? value.slice(1) : value);
1667
2276
  if (newId) {
@@ -1677,13 +2286,13 @@ function generateNewIds(doc) {
1677
2286
  }
1678
2287
  }
1679
2288
  } else if (typeof value === "object" && value !== null) {
1680
- updateRefs(value);
2289
+ updateRefs(value, key);
1681
2290
  }
1682
2291
  }
1683
2292
  }
1684
2293
  collectIds(cloned);
1685
2294
  updateRefs(cloned);
1686
- const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
2295
+ const docAnimate = (_a2 = cloned.animator) == null ? void 0 : _a2.animateById;
1687
2296
  if (docAnimate && typeof docAnimate === "object") {
1688
2297
  const updatedAnimate = {};
1689
2298
  for (const [key, anim] of Object.entries(docAnimate)) {
@@ -1703,7 +2312,7 @@ function replaceUrlRefs(value, idMap) {
1703
2312
  });
1704
2313
  }
1705
2314
 
1706
- // src/PxNodeProps.ts
2315
+ // src/util/PxNodeProps.ts
1707
2316
  var DISALLOWED_SVG_TAGS_LOWER = /* @__PURE__ */ new Set([
1708
2317
  "script",
1709
2318
  "foreignobject"
@@ -1742,7 +2351,7 @@ function isDangerousAttrName(nameLower) {
1742
2351
  if (nameLower.startsWith("on")) return true;
1743
2352
  return false;
1744
2353
  }
1745
- function sanitiseAttributeValue(name, value) {
2354
+ function sanitizeAttributeValue(name, value) {
1746
2355
  const nameLower = name.toLowerCase();
1747
2356
  if (isDangerousAttrName(nameLower)) {
1748
2357
  console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
@@ -1767,10 +2376,10 @@ function sanitiseAttributeValue(name, value) {
1767
2376
  return value;
1768
2377
  }
1769
2378
  function resolveStyle(style, defs) {
1770
- var _a;
2379
+ var _a2;
1771
2380
  if (!style) return void 0;
1772
2381
  if (typeof style === "string") {
1773
- return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
2382
+ return (_a2 = defs == null ? void 0 : defs.styles) == null ? void 0 : _a2[style];
1774
2383
  }
1775
2384
  return style;
1776
2385
  }
@@ -1781,18 +2390,18 @@ function getNormalizedProps(props) {
1781
2390
  if (INTERNAL_ATTRS.has(key)) continue;
1782
2391
  if (key === "style") continue;
1783
2392
  let value = props[rawKey];
1784
- if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2393
+ if (COLOR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1785
2394
  propsCopy[key] = toRGBA(value);
1786
2395
  } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
1787
2396
  const parts = value.value && typeof value.value === "object" ? value.value : value;
1788
- propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
2397
+ propsCopy[TRANSFORM_ATTR] = composeTransformParts(parts, { withUnits: false });
1789
2398
  } else if (TRANSFORM_FN_NAMES.has(key)) {
1790
2399
  if (Array.isArray(value)) {
1791
2400
  if (key === "translate") value = value.map((v) => v + "px");
1792
2401
  value = value.join(",");
1793
2402
  }
1794
2403
  if (key === "rotate") value = value + "deg";
1795
- propsCopy["transform"] = key + "(" + value + ")";
2404
+ propsCopy[TRANSFORM_ATTR] = key + "(" + value + ")";
1796
2405
  } else if (Array.isArray(value)) {
1797
2406
  propsCopy[key] = value.join(",");
1798
2407
  } else if (value !== void 0 && value !== null) {
@@ -1802,10 +2411,9 @@ function getNormalizedProps(props) {
1802
2411
  return propsCopy;
1803
2412
  }
1804
2413
 
1805
- // src/PxMotionPath.ts
2414
+ // src/materialize/PxMotionPath.ts
1806
2415
  function getKfTranslate(kf) {
1807
- var _a;
1808
- const v = (_a = kf.value) != null ? _a : kf.v;
2416
+ const v = kfValue(kf);
1809
2417
  if (!v) return void 0;
1810
2418
  if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
1811
2419
  return [v[0], v[1]];
@@ -1815,31 +2423,27 @@ function getKfTranslate(kf) {
1815
2423
  return void 0;
1816
2424
  }
1817
2425
  function getKfTime(kf) {
1818
- var _a, _b;
1819
- return (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2426
+ return kfTime(kf);
1820
2427
  }
1821
2428
  function getKfEasing(kf) {
1822
- var _a;
1823
- return (_a = kf.easing) != null ? _a : kf.e;
2429
+ return kfEasing(kf);
1824
2430
  }
1825
2431
  function propAnimIsMotionPath(anim) {
1826
- var _a, _b;
1827
2432
  const kfs = anim.keyframes;
1828
2433
  if (!Array.isArray(kfs)) return false;
1829
2434
  if (anim.autoOrient) return true;
1830
2435
  for (const kf of kfs) {
1831
- if (((_a = kf.tangentIn) != null ? _a : kf.ti) || ((_b = kf.tangentOut) != null ? _b : kf.to)) return true;
2436
+ if (kfTangentIn(kf) || kfTangentOut(kf)) return true;
1832
2437
  }
1833
2438
  return false;
1834
2439
  }
1835
2440
  var _segmentCache = /* @__PURE__ */ new WeakMap();
1836
2441
  function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
1837
- var _a, _b;
1838
2442
  let byNext = _segmentCache.get(prevKf);
1839
2443
  const existing = byNext == null ? void 0 : byNext.get(nextKf);
1840
2444
  if (existing) return existing;
1841
- const to = (_a = prevKf.tangentOut) != null ? _a : prevKf.to;
1842
- const ti = (_b = nextKf.tangentIn) != null ? _b : nextKf.ti;
2445
+ const to = kfTangentOut(prevKf);
2446
+ const ti = kfTangentIn(nextKf);
1843
2447
  const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
1844
2448
  const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
1845
2449
  const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
@@ -1888,13 +2492,13 @@ function tFromArcFraction(lut, arcFrac) {
1888
2492
  var DEFAULT_FLATNESS_TOL = 0.5;
1889
2493
  var DEFAULT_ROTATION_TOL = 5;
1890
2494
  var DEFAULT_MAX_SAMPLES = 32;
1891
- function materialiseMotionPathInPropAnim(anim, opts) {
1892
- var _a, _b, _c;
2495
+ function materializeMotionPathInPropAnim(anim, opts) {
2496
+ var _a2, _b, _c;
1893
2497
  if (!propAnimIsMotionPath(anim)) return anim;
1894
2498
  const kfs = anim.keyframes;
1895
2499
  if (!Array.isArray(kfs) || kfs.length < 2) return anim;
1896
2500
  const autoOrient = !!anim.autoOrient;
1897
- const flatnessTol = (_a = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a : DEFAULT_FLATNESS_TOL;
2501
+ const flatnessTol = (_a2 = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a2 : DEFAULT_FLATNESS_TOL;
1898
2502
  const rotationTol = (_b = opts == null ? void 0 : opts.rotationTolerance) != null ? _b : DEFAULT_ROTATION_TOL;
1899
2503
  const maxSamples = (_c = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _c : DEFAULT_MAX_SAMPLES;
1900
2504
  const out = [];
@@ -1920,7 +2524,7 @@ function materialiseMotionPathInPropAnim(anim, opts) {
1920
2524
  if (autoOrient && i > 0) {
1921
2525
  insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
1922
2526
  }
1923
- materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2527
+ materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
1924
2528
  }
1925
2529
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
1926
2530
  if (lastInE) out[out.length - 1].e = lastInE;
@@ -1930,10 +2534,9 @@ function materialiseMotionPathInPropAnim(anim, opts) {
1930
2534
  return result;
1931
2535
  }
1932
2536
  function unwrapAutoOrientRotations(kfs) {
1933
- var _a;
1934
2537
  let prev;
1935
2538
  for (const kf of kfs) {
1936
- const v = (_a = kf.v) != null ? _a : kf.value;
2539
+ const v = kfValue(kf);
1937
2540
  if (!v || typeof v.rotate !== "number") continue;
1938
2541
  if (prev === void 0) {
1939
2542
  prev = v.rotate;
@@ -1950,8 +2553,7 @@ function makeOutKf(time, value) {
1950
2553
  return { t: time, v: value };
1951
2554
  }
1952
2555
  function getKfValueParts(kf) {
1953
- var _a;
1954
- const v = (_a = kf.value) != null ? _a : kf.v;
2556
+ const v = kfValue(kf);
1955
2557
  if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
1956
2558
  return v;
1957
2559
  }
@@ -2012,9 +2614,8 @@ function wrappedAngleDelta(a, b) {
2012
2614
  return d;
2013
2615
  }
2014
2616
  function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
2015
- var _a;
2016
2617
  const lastKf = out[out.length - 1];
2017
- const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
2618
+ const lastV = kfValue(lastKf);
2018
2619
  const prevExit = lastV == null ? void 0 : lastV.rotate;
2019
2620
  if (typeof prevExit !== "number") return;
2020
2621
  const boundaryV = getKfValueParts(prevKf);
@@ -2037,7 +2638,7 @@ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos,
2037
2638
  out.push(makeOutKf(stepTime, dupValue));
2038
2639
  }
2039
2640
  var CORNER_STEP_AFTER_BOUNDARY_MS = 0.05;
2040
- function materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2641
+ function materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2041
2642
  const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2042
2643
  const prevTime = getKfTime(prevKf);
2043
2644
  const nextTime = getKfTime(nextKf);
@@ -2160,16 +2761,16 @@ function perpDist(q, pA, pB) {
2160
2761
  const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
2161
2762
  return Math.abs(cross) / Math.sqrt(len2);
2162
2763
  }
2163
- function materialiseMotionPathsInTree(root, opts) {
2164
- const out = walkAndMaterialise(root, opts);
2764
+ function materializeMotionPathsInTree(root, opts) {
2765
+ const out = walkAndMaterialize(root, opts);
2165
2766
  return out != null ? out : root;
2166
2767
  }
2167
- function walkAndMaterialise(node, opts) {
2768
+ function walkAndMaterialize(node, opts) {
2168
2769
  let newChildren;
2169
2770
  if (node.children) {
2170
2771
  for (let i = 0; i < node.children.length; i++) {
2171
2772
  const ch = node.children[i];
2172
- const ret = walkAndMaterialise(ch, opts);
2773
+ const ret = walkAndMaterialize(ch, opts);
2173
2774
  if (ret !== null) {
2174
2775
  if (!newChildren) newChildren = node.children.slice();
2175
2776
  newChildren[i] = ret;
@@ -2182,9 +2783,9 @@ function walkAndMaterialise(node, opts) {
2182
2783
  const animDef = animBucket;
2183
2784
  const transformAnim = animDef.transform;
2184
2785
  if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
2185
- const materialised = materialiseMotionPathInPropAnim(transformAnim, opts);
2186
- if (materialised !== transformAnim) {
2187
- newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialised });
2786
+ const materialized = materializeMotionPathInPropAnim(transformAnim, opts);
2787
+ if (materialized !== transformAnim) {
2788
+ newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialized });
2188
2789
  }
2189
2790
  }
2190
2791
  }
@@ -2195,7 +2796,7 @@ function walkAndMaterialise(node, opts) {
2195
2796
  return cloned;
2196
2797
  }
2197
2798
 
2198
- // src/PxDefinitions.ts
2799
+ // src/animation/PxDefinitions.ts
2199
2800
  var LOOP_JUMP_SHIFT_MS = 1;
2200
2801
  function deepEqualValue(a, b) {
2201
2802
  if (a === b) return true;
@@ -2287,8 +2888,8 @@ function isPathString(value) {
2287
2888
  return typeof value === "string" && extractPathData(value) !== void 0;
2288
2889
  }
2289
2890
  function normalizePathValue(value) {
2290
- if (value && typeof value === "object" && typeof value.path === "string") {
2291
- const d = extractPathData(value.path);
2891
+ if (value && typeof value === "object" && typeof value.pathData === "string") {
2892
+ const d = extractPathData(value.pathData);
2292
2893
  return d ? { paths: parseSvgPathToBezier(d) } : value;
2293
2894
  }
2294
2895
  if (value && typeof value === "object" && "paths" in value) {
@@ -2327,21 +2928,21 @@ function normalizePathValue(value) {
2327
2928
  return value;
2328
2929
  }
2329
2930
  function resolveEasing(easing, defs) {
2330
- var _a;
2931
+ var _a2;
2331
2932
  if (!easing) return void 0;
2332
2933
  if (Array.isArray(easing)) {
2333
2934
  return easing;
2334
2935
  }
2335
- if ((_a = defs == null ? void 0 : defs.easings) == null ? void 0 : _a[easing]) {
2936
+ if ((_a2 = defs == null ? void 0 : defs.easings) == null ? void 0 : _a2[easing]) {
2336
2937
  return defs.easings[easing];
2337
2938
  }
2338
2939
  console.warn("Unknown easing name: " + easing);
2339
2940
  return void 0;
2340
2941
  }
2341
2942
  function resolveAnimation(animRef, defs) {
2342
- var _a;
2943
+ var _a2;
2343
2944
  if (typeof animRef === "string") {
2344
- const resolved = (_a = defs == null ? void 0 : defs.animations) == null ? void 0 : _a[animRef];
2945
+ const resolved = (_a2 = defs == null ? void 0 : defs.animations) == null ? void 0 : _a2[animRef];
2345
2946
  if (!resolved) {
2346
2947
  console.warn("Unknown animation name: " + animRef);
2347
2948
  }
@@ -2366,13 +2967,13 @@ function resolveElementAnimation(animate, defs) {
2366
2967
  return results;
2367
2968
  }
2368
2969
  function interpolateValue(propName, a, b, t) {
2369
- var _a, _b;
2970
+ var _a2, _b;
2370
2971
  if (propName === "d") {
2371
- const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
2972
+ const aPaths = (_a2 = a == null ? void 0 : a.paths) != null ? _a2 : Array.isArray(a) ? a : [];
2372
2973
  const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2373
2974
  return { paths: interpolateBeziers(aPaths, bPaths, t) };
2374
2975
  }
2375
- if (COLOUR_ATTR_NAMES.has(propName)) {
2976
+ if (COLOR_ATTR_NAMES.has(propName)) {
2376
2977
  return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
2377
2978
  }
2378
2979
  if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
@@ -2404,11 +3005,11 @@ function interpolateTransformParts(a, b, t) {
2404
3005
  return out;
2405
3006
  }
2406
3007
  function expandLoopKeyframes(propName, keyframes, loop, duration) {
2407
- var _a, _b, _c, _d, _e;
3008
+ var _a2, _b, _c, _d, _e;
2408
3009
  const totalIntervals = keyframes.length - 1;
2409
- const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
3010
+ const segCount = clamp((_a2 = loop.segmentCount) != null ? _a2 : totalIntervals, 1, totalIntervals);
2410
3011
  let segKfs;
2411
- if (loop.extend === PxLoopExtend.before) {
3012
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2412
3013
  segKfs = keyframes.slice(0, segCount + 1);
2413
3014
  } else {
2414
3015
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -2416,7 +3017,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2416
3017
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2417
3018
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2418
3019
  let fillStart, fillEnd;
2419
- if (loop.extend === PxLoopExtend.before) {
3020
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2420
3021
  fillStart = 0;
2421
3022
  fillEnd = firstT;
2422
3023
  } else {
@@ -2429,26 +3030,23 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2429
3030
  const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
2430
3031
  const segDuration = segEndT - segStartT;
2431
3032
  if (segDuration <= 0) return keyframes;
2432
- const template = segKfs.map((kf) => {
2433
- var _a2, _b2;
2434
- return {
2435
- relT: (kf.t - segStartT) / segDuration,
2436
- v: kf.v,
2437
- e: kf.e,
2438
- tangentIn: (_a2 = kf.tangentIn) != null ? _a2 : kf.ti,
2439
- tangentOut: (_b2 = kf.tangentOut) != null ? _b2 : kf.to
2440
- };
2441
- });
3033
+ const template = segKfs.map((kf) => ({
3034
+ relT: (kf.t - segStartT) / segDuration,
3035
+ v: kf.v,
3036
+ e: kf.e,
3037
+ tangentIn: kfTangentIn(kf),
3038
+ tangentOut: kfTangentOut(kf)
3039
+ }));
2442
3040
  const fullReps = Math.floor(fillDuration / segDuration);
2443
3041
  const remainder = fillDuration - fullReps * segDuration;
2444
3042
  const partialFraction = remainder / segDuration;
2445
3043
  const looped = [];
2446
- const separateBoundary = loop.extend !== PxLoopExtend.before;
3044
+ const separateBoundary = loop.repeatAt !== PxLoopRepeatAt.start;
2447
3045
  const originalTerminalKf = keyframes[keyframes.length - 1];
2448
3046
  let terminalEasingOverride;
2449
3047
  let hasTerminalEasingOverride = false;
2450
3048
  function appendRep(repStart, isReversed, partial) {
2451
- var _a2;
3049
+ var _a3;
2452
3050
  let entries;
2453
3051
  if (isReversed) {
2454
3052
  entries = [];
@@ -2485,7 +3083,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2485
3083
  return;
2486
3084
  }
2487
3085
  const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2488
- const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
3086
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a3 = prevKf.t) != null ? _a3 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2489
3087
  if (isBoundary) {
2490
3088
  if (deepEqualValue(prevKf.v, entry.v)) {
2491
3089
  if (looped.length > 0) {
@@ -2551,30 +3149,30 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2551
3149
  looped.push(pushed);
2552
3150
  }
2553
3151
  }
2554
- if (loop.extend === PxLoopExtend.before) {
3152
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2555
3153
  if (partialFraction > 1e-9) {
2556
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
3154
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2557
3155
  appendRepTail(fillStart, isReversed, partialFraction);
2558
3156
  }
2559
3157
  for (let rep = 0; rep < fullReps; rep++) {
2560
3158
  const distFromBoundary = fullReps - 1 - rep;
2561
- const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
3159
+ const isReversed = loop.direction === PxLoopDirection.alternate && distFromBoundary % 2 === 0;
2562
3160
  const repStart = fillStart + remainder + rep * segDuration;
2563
3161
  appendRep(repStart, isReversed);
2564
3162
  }
2565
3163
  } else {
2566
3164
  for (let rep = 0; rep < fullReps; rep++) {
2567
- const isReversed = !!loop.alternate && rep % 2 === 0;
3165
+ const isReversed = loop.direction === PxLoopDirection.alternate && rep % 2 === 0;
2568
3166
  const repStart = fillStart + rep * segDuration;
2569
3167
  appendRep(repStart, isReversed);
2570
3168
  }
2571
3169
  if (partialFraction > 1e-9) {
2572
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
3170
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2573
3171
  const repStart = fillStart + fullReps * segDuration;
2574
3172
  appendRep(repStart, isReversed, partialFraction);
2575
3173
  }
2576
3174
  }
2577
- if (loop.extend === PxLoopExtend.before) {
3175
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2578
3176
  return [...looped, ...keyframes];
2579
3177
  } else {
2580
3178
  if (hasTerminalEasingOverride && keyframes.length > 0) {
@@ -2586,34 +3184,34 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2586
3184
  }
2587
3185
  }
2588
3186
  function normalizeKeyframes(propName, propAnim, duration, defs) {
2589
- var _a, _b, _c, _d, _e, _f, _g;
3187
+ var _a2;
2590
3188
  const keyframes = propAnim.keyframes || [];
2591
3189
  const normalized = [];
2592
3190
  for (const kf of keyframes) {
2593
- const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2594
- let value = (_c = kf.value) != null ? _c : kf.v;
2595
- const easing = (_d = kf.easing) != null ? _d : kf.e;
3191
+ const timePct = kfTime(kf);
3192
+ let value = kfValue(kf);
3193
+ const easing = kfEasing(kf);
2596
3194
  if (propName === "d") {
2597
3195
  value = normalizePathValue(value);
2598
3196
  }
2599
3197
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2600
- if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
2601
- value = (_e = parseColor(value)) != null ? _e : value;
3198
+ if (COLOR_ATTR_NAMES.has(propNameKebab)) {
3199
+ value = (_a2 = parseColor(value)) != null ? _a2 : value;
2602
3200
  }
2603
3201
  const normKf = {
2604
3202
  t: timePct,
2605
3203
  v: value,
2606
3204
  e: resolveEasing(easing, defs)
2607
3205
  };
2608
- const tIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
2609
- const tOut = (_g = kf.tangentOut) != null ? _g : kf.to;
3206
+ const tIn = kfTangentIn(kf);
3207
+ const tOut = kfTangentOut(kf);
2610
3208
  if (tIn) normKf.tangentIn = tIn;
2611
3209
  if (tOut) normKf.tangentOut = tOut;
2612
3210
  normalized.push(normKf);
2613
3211
  }
2614
3212
  normalized.sort((a, b) => {
2615
- var _a2, _b2;
2616
- return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
3213
+ var _a3, _b;
3214
+ return ((_a3 = a.t) != null ? _a3 : 0) - ((_b = b.t) != null ? _b : 0);
2617
3215
  });
2618
3216
  const loopRaw = propAnim.loop;
2619
3217
  const loop = loopRaw === true ? {} : loopRaw || void 0;
@@ -2631,24 +3229,26 @@ function mergeAnimationDefinitions(animations) {
2631
3229
  }
2632
3230
  return merged;
2633
3231
  }
2634
- function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
3232
+ function materializeInternalLoopsInPropAnim(propName, propAnim, duration) {
2635
3233
  const loopRaw = propAnim.loop;
2636
3234
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
2637
3235
  const loop = loopRaw === true ? {} : loopRaw;
2638
3236
  const rawKfs = propAnim.keyframes;
2639
3237
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
2640
3238
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2641
- const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
3239
+ const isColor = COLOR_ATTR_NAMES.has(propNameKebab);
2642
3240
  const kfs = rawKfs.map((kf) => {
2643
- var _a, _b, _c, _d, _e, _f, _g, _h;
2644
- const t = (_a = kf.t) != null ? _a : kf.time;
2645
- let v = (_b = kf.v) != null ? _b : kf.value;
3241
+ var _a2;
3242
+ const t = kfTime(kf);
3243
+ let v = kfValue(kf);
2646
3244
  if (propName === "d") v = normalizePathValue(v);
2647
- if (isColour) v = (_c = parseColor(v)) != null ? _c : v;
2648
- const e = (_d = kf.e) != null ? _d : kf.easing;
3245
+ if (isColor) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3246
+ const e = kfEasing(kf);
2649
3247
  const out2 = { t, v, e };
2650
- if ((_e = kf.tangentIn) != null ? _e : kf.ti) out2.tangentIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
2651
- if ((_g = kf.tangentOut) != null ? _g : kf.to) out2.tangentOut = (_h = kf.tangentOut) != null ? _h : kf.to;
3248
+ const tIn = kfTangentIn(kf);
3249
+ const tOut = kfTangentOut(kf);
3250
+ if (tIn) out2.tangentIn = tIn;
3251
+ if (tOut) out2.tangentOut = tOut;
2652
3252
  return out2;
2653
3253
  });
2654
3254
  const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
@@ -2656,15 +3256,15 @@ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2656
3256
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2657
3257
  return out;
2658
3258
  }
2659
- function materialiseInternalLoopsInTree(root, duration) {
2660
- const ret = walkAndMaterialiseLoops(root, duration);
3259
+ function materializeInternalLoopsInTree(root, duration) {
3260
+ const ret = walkAndMaterializeLoops(root, duration);
2661
3261
  return ret != null ? ret : root;
2662
3262
  }
2663
- function walkAndMaterialiseLoops(node, duration) {
3263
+ function walkAndMaterializeLoops(node, duration) {
2664
3264
  let newChildren;
2665
3265
  if (node.children) {
2666
3266
  for (let i = 0; i < node.children.length; i++) {
2667
- const ret = walkAndMaterialiseLoops(node.children[i], duration);
3267
+ const ret = walkAndMaterializeLoops(node.children[i], duration);
2668
3268
  if (ret !== null) {
2669
3269
  if (!newChildren) newChildren = node.children.slice();
2670
3270
  newChildren[i] = ret;
@@ -2677,10 +3277,10 @@ function walkAndMaterialiseLoops(node, duration) {
2677
3277
  const animDef = animBucket;
2678
3278
  for (const propName of Object.keys(animDef)) {
2679
3279
  const propAnim = animDef[propName];
2680
- const materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);
2681
- if (materialised !== propAnim) {
3280
+ const materialized = materializeInternalLoopsInPropAnim(propName, propAnim, duration);
3281
+ if (materialized !== propAnim) {
2682
3282
  if (!newAnimate) newAnimate = __spreadValues({}, animDef);
2683
- newAnimate[propName] = materialised;
3283
+ newAnimate[propName] = materialized;
2684
3284
  }
2685
3285
  }
2686
3286
  }
@@ -2699,7 +3299,7 @@ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
2699
3299
  const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
2700
3300
  if (!staticParts || !Object.keys(staticParts).length) return animDef;
2701
3301
  const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
2702
- const transformAnim = animDef["transform"];
3302
+ const transformAnim = animDef[TRANSFORM_ATTR];
2703
3303
  if (transformAnim && typeof transformAnim === "object") {
2704
3304
  const anim = transformAnim;
2705
3305
  if (Array.isArray(anim.keyframes)) {
@@ -2724,7 +3324,7 @@ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
2724
3324
  delete rest[ch];
2725
3325
  return __spreadProps(__spreadValues({}, rest), { transform: lifted });
2726
3326
  }
2727
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
3327
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimelineEngine.native) {
2728
3328
  const normalized = {};
2729
3329
  for (const [propName, propAnim] of Object.entries(animDef)) {
2730
3330
  if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
@@ -2735,12 +3335,12 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimat
2735
3335
  const out = { keyframes: normalizedKfs };
2736
3336
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2737
3337
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2738
- normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
3338
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materializeMotionPathInPropAnim(out) : out;
2739
3339
  }
2740
3340
  }
2741
3341
  return normalized;
2742
3342
  }
2743
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
3343
+ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
2744
3344
  const animatorConfig = getAnimatorConfig(doc) || {};
2745
3345
  const defs = getDefs(doc);
2746
3346
  const duration = animatorConfig.duration || 1e3;
@@ -2786,12 +3386,12 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2786
3386
  return bindings;
2787
3387
  }
2788
3388
  function getKeyframesPair(keyframes, progress) {
2789
- var _a, _b;
3389
+ var _a2, _b;
2790
3390
  const last = keyframes.length - 1;
2791
3391
  let prevKf = keyframes[0];
2792
3392
  let nextKf = keyframes[last > 0 ? 1 : 0];
2793
3393
  for (let j = 0; j < last; j++) {
2794
- const aOff = (_a = keyframes[j].t) != null ? _a : 0;
3394
+ const aOff = (_a2 = keyframes[j].t) != null ? _a2 : 0;
2795
3395
  const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
2796
3396
  if (aOff <= progress && progress <= bOff) {
2797
3397
  prevKf = keyframes[j];
@@ -2806,13 +3406,13 @@ function getKeyframesPair(keyframes, progress) {
2806
3406
  return { prevKf, nextKf };
2807
3407
  }
2808
3408
  function calcPropertyValue(propName, propAnim, progress) {
2809
- var _a, _b, _c, _d, _e, _f, _g;
3409
+ var _a2, _b, _c, _d;
2810
3410
  const keyframes = propAnim.keyframes || [];
2811
3411
  if (keyframes.length === 0) return null;
2812
3412
  const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
2813
- let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
3413
+ let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a2 = prevKf.t) != null ? _a2 : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
2814
3414
  localProgress = clamp(localProgress, 0, 1);
2815
- const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
3415
+ const easing = kfEasing(prevKf);
2816
3416
  if (easing && Array.isArray(easing)) {
2817
3417
  try {
2818
3418
  localProgress = cubicBezier(easing)(localProgress);
@@ -2821,17 +3421,17 @@ function calcPropertyValue(propName, propAnim, progress) {
2821
3421
  }
2822
3422
  let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2823
3423
  let cssValue = null;
2824
- const prevV = (_d = prevKf == null ? void 0 : prevKf.v) != null ? _d : prevKf == null ? void 0 : prevKf.value;
2825
- const nextV = (_e = nextKf == null ? void 0 : nextKf.v) != null ? _e : nextKf == null ? void 0 : nextKf.value;
3424
+ const prevV = prevKf == null ? void 0 : prevKf.v;
3425
+ const nextV = nextKf == null ? void 0 : nextKf.v;
2826
3426
  if (cssAttrName === "d") {
2827
- const prevPaths = (_f = prevV == null ? void 0 : prevV.paths) != null ? _f : Array.isArray(prevV) ? prevV : [];
2828
- const nextPaths = (_g = nextV == null ? void 0 : nextV.paths) != null ? _g : Array.isArray(nextV) ? nextV : [];
3427
+ const prevPaths = (_c = prevV == null ? void 0 : prevV.paths) != null ? _c : Array.isArray(prevV) ? prevV : [];
3428
+ const nextPaths = (_d = nextV == null ? void 0 : nextV.paths) != null ? _d : Array.isArray(nextV) ? nextV : [];
2829
3429
  cssValue = interpolateBeziers(
2830
3430
  prevPaths,
2831
3431
  nextPaths,
2832
3432
  localProgress
2833
3433
  ).map((bz) => bezierToSvgPath(bz)).join("");
2834
- } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
3434
+ } else if (COLOR_ATTR_NAMES.has(cssAttrName)) {
2835
3435
  cssValue = toRGBA(interpolateColor(
2836
3436
  prevV || [0, 0, 0, 1],
2837
3437
  nextV || [0, 0, 0, 1],
@@ -2928,7 +3528,7 @@ function calcAnimationValues(animDef, progress) {
2928
3528
  return result;
2929
3529
  }
2930
3530
 
2931
- // src/PxNodeCloneUtil.ts
3531
+ // src/util/PxNodeCloneUtil.ts
2932
3532
  function deepClonePxNode(value) {
2933
3533
  if (value === null || typeof value !== "object") return value;
2934
3534
  if (Array.isArray(value)) return value.map(deepClonePxNode);
@@ -2939,13 +3539,13 @@ function deepClonePxNode(value) {
2939
3539
  function regenerateIdsAndRewriteRefs(root, genId3) {
2940
3540
  const oldToNew = /* @__PURE__ */ new Map();
2941
3541
  const walkAssign = (n) => {
2942
- var _a;
3542
+ var _a2;
2943
3543
  if (typeof n.id === "string") {
2944
3544
  const newId = genId3();
2945
3545
  oldToNew.set(n.id, newId);
2946
3546
  n.id = newId;
2947
3547
  }
2948
- (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
3548
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkAssign);
2949
3549
  };
2950
3550
  walkAssign(root);
2951
3551
  const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
@@ -2953,7 +3553,7 @@ function regenerateIdsAndRewriteRefs(root, genId3) {
2953
3553
  return newId ? "url(#" + newId + ")" : m;
2954
3554
  });
2955
3555
  const walkRewrite = (n) => {
2956
- var _a;
3556
+ var _a2;
2957
3557
  if (typeof n.href === "string" && n.href.startsWith("#")) {
2958
3558
  const newId = oldToNew.get(n.href.slice(1));
2959
3559
  if (newId) n.href = "#" + newId;
@@ -2965,7 +3565,7 @@ function regenerateIdsAndRewriteRefs(root, genId3) {
2965
3565
  n[k] = rewriteUrl(v);
2966
3566
  }
2967
3567
  }
2968
- (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
3568
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkRewrite);
2969
3569
  };
2970
3570
  walkRewrite(root);
2971
3571
  return oldToNew;
@@ -2975,7 +3575,7 @@ function toFiniteNum(v) {
2975
3575
  return Number.isFinite(n) ? n : 0;
2976
3576
  }
2977
3577
  function applyUseOffsetToG(gNode) {
2978
- var _a;
3578
+ var _a2;
2979
3579
  const x = toFiniteNum(gNode.x);
2980
3580
  const y = toFiniteNum(gNode.y);
2981
3581
  delete gNode.x;
@@ -2984,7 +3584,7 @@ function applyUseOffsetToG(gNode) {
2984
3584
  const offset = "translate(" + x + "," + y + ")";
2985
3585
  const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
2986
3586
  if (carriesTransform) {
2987
- const inner = { type: "g", transform: offset, children: (_a = gNode.children) != null ? _a : [] };
3587
+ const inner = { type: "g", transform: offset, children: (_a2 = gNode.children) != null ? _a2 : [] };
2988
3588
  gNode.children = [inner];
2989
3589
  } else {
2990
3590
  gNode.transform = offset;
@@ -2992,9 +3592,9 @@ function applyUseOffsetToG(gNode) {
2992
3592
  return gNode;
2993
3593
  }
2994
3594
 
2995
- // src/PxAnimatorUseMaterialiser.ts
2996
- function materialiseAnimatedUseInstances(root) {
2997
- var _a;
3595
+ // src/materialize/PxAnimatorUseMaterializer.ts
3596
+ function materializeAnimatedUseInstances(root) {
3597
+ var _a2;
2998
3598
  const idMap = buildIdMap(root);
2999
3599
  const animatedIds = computeAnimatedSubtreeIds(root, idMap);
3000
3600
  if (animatedIds.size === 0) return root;
@@ -3002,10 +3602,10 @@ function materialiseAnimatedUseInstances(root) {
3002
3602
  const genId3 = () => "_lw_use_mat_" + ++idCounter;
3003
3603
  const rootViewport = readRootViewport(root);
3004
3604
  const defsCollector = [];
3005
- const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3605
+ const walked = walkAndMaterialize2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3006
3606
  if (defsCollector.length === 0) return walked;
3007
3607
  const defsNode = { type: "defs", children: defsCollector };
3008
- const newChildren = [...(_a = walked.children) != null ? _a : [], defsNode];
3608
+ const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
3009
3609
  return __spreadProps(__spreadValues({}, walked), { children: newChildren });
3010
3610
  }
3011
3611
  function readRootViewport(root) {
@@ -3027,9 +3627,9 @@ function numericAttr(v) {
3027
3627
  function buildIdMap(root) {
3028
3628
  const map = /* @__PURE__ */ new Map();
3029
3629
  const visit = (n) => {
3030
- var _a;
3630
+ var _a2;
3031
3631
  if (typeof n.id === "string") map.set(n.id, n);
3032
- (_a = n.children) == null ? void 0 : _a.forEach(visit);
3632
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
3033
3633
  };
3034
3634
  visit(root);
3035
3635
  return map;
@@ -3075,16 +3675,16 @@ function stripHash(href) {
3075
3675
  if (typeof href !== "string") return void 0;
3076
3676
  return href.startsWith("#") ? href.slice(1) : href;
3077
3677
  }
3078
- function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3079
- var _a, _b, _c, _d;
3678
+ function materializeOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3679
+ var _a2, _b, _c, _d;
3080
3680
  const clone2 = deepClonePxNode(target);
3081
3681
  regenerateIdsAndRewriteRefs(clone2, genId3);
3082
3682
  const symbolViewBox = clone2.type === "symbol" ? parseViewBox(clone2.viewBox) : void 0;
3083
- const useW = (_b = (_a = numericAttr(useNode.width)) != null ? _a : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3683
+ const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3084
3684
  const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
3085
3685
  const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
3086
- const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3087
- const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materialisedClone] });
3686
+ const materializedClone = walkAndMaterialize2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3687
+ const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materializedClone] });
3088
3688
  delete newNode.href;
3089
3689
  delete newNode.width;
3090
3690
  delete newNode.height;
@@ -3122,25 +3722,25 @@ function parseViewBox(v) {
3122
3722
  if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
3123
3723
  return [parts[0], parts[1], parts[2], parts[3]];
3124
3724
  }
3125
- function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3725
+ function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3126
3726
  if (node.type === "use" && typeof node.href === "string") {
3127
3727
  const targetId = stripHash(node.href);
3128
3728
  if (targetId && animatedIds.has(targetId)) {
3129
3729
  const target = idMap.get(targetId);
3130
- if (target) return materialiseOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
3730
+ if (target) return materializeOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
3131
3731
  }
3132
3732
  }
3133
3733
  if (!node.children) return node;
3134
3734
  let changed = false;
3135
3735
  const newChildren = node.children.map((ch) => {
3136
- const m = walkAndMaterialise2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3736
+ const m = walkAndMaterialize2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3137
3737
  if (m !== ch) changed = true;
3138
3738
  return m;
3139
3739
  });
3140
3740
  return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
3141
3741
  }
3142
3742
 
3143
- // src/effects/transformParts.ts
3743
+ // src/effects/shared/transformParts.ts
3144
3744
  function partsRecord(part, value, origin) {
3145
3745
  const rec = {};
3146
3746
  if (part === "translate" /* Translate */) rec.translate = value;
@@ -3151,25 +3751,25 @@ function partsRecord(part, value, origin) {
3151
3751
  return rec;
3152
3752
  }
3153
3753
  function readAnimatable(raw) {
3154
- var _a, _b, _c;
3754
+ var _a2, _b;
3155
3755
  if (raw === void 0) return { kind: "absent" /* Absent */ };
3156
3756
  if (Array.isArray(raw)) return { kind: "static" /* Static */, value: raw };
3157
3757
  if (typeof raw === "object") {
3158
3758
  const obj = raw;
3159
- const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
3759
+ const kfs = obj.keyframes;
3160
3760
  if (kfs) {
3161
- const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3162
- const base = (_b = obj.value) != null ? _b : obj.v;
3761
+ const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normalizeKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3762
+ const base = (_a2 = obj.value) != null ? _a2 : obj.v;
3163
3763
  if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
3164
3764
  return out;
3165
3765
  }
3166
- const staticValue = (_c = obj.value) != null ? _c : obj.v;
3766
+ const staticValue = (_b = obj.value) != null ? _b : obj.v;
3167
3767
  if (staticValue !== void 0) return { kind: "static" /* Static */, value: staticValue };
3168
3768
  }
3169
3769
  return { kind: "static" /* Static */, value: raw };
3170
3770
  }
3171
3771
  function writeAnimatableChannel(node, attrName, read, opts) {
3172
- var _a, _b, _c, _d;
3772
+ var _a2, _b, _c, _d;
3173
3773
  const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
3174
3774
  if (read.kind === "absent" /* Absent */) return;
3175
3775
  if (read.kind === "static" /* Static */) {
@@ -3183,10 +3783,10 @@ function writeAnimatableChannel(node, attrName, read, opts) {
3183
3783
  if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
3184
3784
  animate[attrName] = block;
3185
3785
  node.animate = animate;
3186
- 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;
3786
+ 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;
3187
3787
  if (baseline !== void 0) node[attrName] = toOut(baseline);
3188
3788
  }
3189
- function normaliseKeyframe(kf) {
3789
+ function normalizeKeyframe(kf) {
3190
3790
  if (!kf || typeof kf !== "object") return kf;
3191
3791
  const k = kf;
3192
3792
  if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
@@ -3201,12 +3801,12 @@ function normaliseKeyframe(kf) {
3201
3801
  return out;
3202
3802
  }
3203
3803
  function readStaticOrigin(raw, ctx) {
3204
- var _a;
3804
+ var _a2;
3205
3805
  const o = readAnimatable(raw);
3206
3806
  if (o.kind === "absent" /* Absent */) return void 0;
3207
3807
  if (o.kind === "static" /* Static */) return o.value;
3208
3808
  ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
3209
- return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
3809
+ return (_a2 = o.keyframes[0]) == null ? void 0 : _a2.value;
3210
3810
  }
3211
3811
  function keyframeWith(kf, value) {
3212
3812
  const out = { value };
@@ -3217,7 +3817,7 @@ function keyframeWith(kf, value) {
3217
3817
  return out;
3218
3818
  }
3219
3819
 
3220
- // src/effects/transformationEffect.ts
3820
+ // src/effects/transform/transformationEffect.ts
3221
3821
  function applyTransformByEffect(node, fx, ctx) {
3222
3822
  if (!fx) return node;
3223
3823
  delete node.transform;
@@ -3308,7 +3908,7 @@ function wrapOrigin(inner, raw, invert) {
3308
3908
  return inner;
3309
3909
  }
3310
3910
 
3311
- // src/effects/util.ts
3911
+ // src/effects/shared/util.ts
3312
3912
  function genId(ctx, prefix) {
3313
3913
  return "_lw_" + prefix + "_" + ctx.nextId++;
3314
3914
  }
@@ -3316,9 +3916,9 @@ function stripHash2(href) {
3316
3916
  return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3317
3917
  }
3318
3918
  function indexById(node, map) {
3319
- var _a;
3919
+ var _a2;
3320
3920
  if (typeof node.id === "string") map.set(node.id, node);
3321
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3921
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((child) => indexById(child, map));
3322
3922
  }
3323
3923
  function spliceDefs(root, defs) {
3324
3924
  if (!defs.length) return;
@@ -3330,11 +3930,11 @@ function regenerateIdsInClone(root, ctx) {
3330
3930
  return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3331
3931
  }
3332
3932
 
3333
- // src/effects/contentRefSplit.ts
3933
+ // src/effects/reference/contentRefSplit.ts
3334
3934
  function identifyContentRefTargets(node, ctx, allocator) {
3335
- var _a, _b, _c;
3336
- if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.type) === "content") {
3337
- const sourceId = stripHash2(node.effects.clone.sourceId);
3935
+ var _a2, _b, _c;
3936
+ if (node.type === "use" && ((_b = (_a2 = node.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.without) === "translate") {
3937
+ const sourceId = stripHash2(node.effects.clone.source);
3338
3938
  if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3339
3939
  ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
3340
3940
  }
@@ -3359,10 +3959,10 @@ function splitForContentRef(node, transformBy, originalId, innerId, ctx) {
3359
3959
  return outerWrapper;
3360
3960
  }
3361
3961
  function liftBodyTranslate(node, transformBy) {
3362
- var _a, _b, _c;
3962
+ var _a2, _b, _c;
3363
3963
  const out = {};
3364
3964
  let didLiftAnimate = false;
3365
- const animTr = (_a = node.animate) == null ? void 0 : _a.transform;
3965
+ const animTr = (_a2 = node.animate) == null ? void 0 : _a2.transform;
3366
3966
  if (animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes)) {
3367
3967
  const kfs = animTr.keyframes;
3368
3968
  const hasTranslate = kfs.some((kf) => kf.value && kf.value.translate);
@@ -3545,7 +4145,7 @@ function needsOriginOnOuter(translateAnim) {
3545
4145
  return false;
3546
4146
  }
3547
4147
 
3548
- // src/effects/gradientEffect.ts
4148
+ // src/effects/paint/gradientEffect.ts
3549
4149
  function applyFillGradientEffect(node, fx, ctx) {
3550
4150
  return applyGradient(node, fx, ctx, "fill");
3551
4151
  }
@@ -3580,7 +4180,7 @@ function synthesiseGradientDef(fx, id, ctx) {
3580
4180
  return out;
3581
4181
  }
3582
4182
  function applyGeomVec(out, xAttr, yAttr, raw) {
3583
- var _a, _b, _c;
4183
+ var _a2, _b, _c;
3584
4184
  const read = readAnimatable(raw);
3585
4185
  if (read.kind === "absent" /* Absent */) return;
3586
4186
  if (read.kind === "static" /* Static */) {
@@ -3599,7 +4199,7 @@ function applyGeomVec(out, xAttr, yAttr, raw) {
3599
4199
  if (read.loop !== void 0) block.loop = read.loop;
3600
4200
  return block;
3601
4201
  };
3602
- const animate = (_a = out.animate) != null ? _a : {};
4202
+ const animate = (_a2 = out.animate) != null ? _a2 : {};
3603
4203
  animate[xAttr] = axisChannel(0);
3604
4204
  animate[yAttr] = axisChannel(1);
3605
4205
  out.animate = animate;
@@ -3615,7 +4215,7 @@ function applyGeomNumber(out, attrName, raw) {
3615
4215
  writeAnimatableChannel(out, attrName, read, { asString: true });
3616
4216
  }
3617
4217
  function buildStopChildren(stops, ctx) {
3618
- var _a, _b, _c, _d;
4218
+ var _a2, _b;
3619
4219
  if (!stops) return [];
3620
4220
  const read = readAnimatable(stops);
3621
4221
  if (read.kind === "absent" /* Absent */) return [];
@@ -3625,14 +4225,14 @@ function buildStopChildren(stops, ctx) {
3625
4225
  const loopFromSource = read.loop;
3626
4226
  let stopCount = 0;
3627
4227
  for (const kf of kfs) {
3628
- const v = (_a = kf.value) != null ? _a : kf.v;
4228
+ const v = kfValue(kf);
3629
4229
  if (Array.isArray(v) && v.length > stopCount) stopCount = v.length;
3630
4230
  }
3631
4231
  if (!stopCount) return [];
3632
- const firstKfValue = (_b = kfs[0].value) != null ? _b : kfs[0].v;
4232
+ const firstKfValue = kfValue(kfs[0]);
3633
4233
  const baselineStops = [];
3634
4234
  for (let i = 0; i < stopCount; i++) {
3635
- 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" };
4235
+ 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" };
3636
4236
  baselineStops.push({ offset: s.offset, color: s.color });
3637
4237
  }
3638
4238
  return baselineStops.map((bs, i) => animatedStopNode(bs, kfs, i, ctx, loopFromSource));
@@ -3645,16 +4245,16 @@ function staticStopNode(s) {
3645
4245
  };
3646
4246
  }
3647
4247
  function animatedStopNode(baseline, kfs, stopIdx, _ctx, loop) {
3648
- var _a, _b, _c, _d, _e;
4248
+ var _a2;
3649
4249
  const colorKfs = [];
3650
4250
  const offsetKfs = [];
3651
4251
  let offsetVaries = false;
3652
4252
  for (const kf of kfs) {
3653
- const t = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
3654
- const arr = (_c = kf.value) != null ? _c : kf.v;
3655
- const sliced = (_d = arr == null ? void 0 : arr[stopIdx]) != null ? _d : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
4253
+ const t = kfTime(kf);
4254
+ const arr = kfValue(kf);
4255
+ const sliced = (_a2 = arr == null ? void 0 : arr[stopIdx]) != null ? _a2 : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
3656
4256
  if (!sliced) continue;
3657
- const easing = (_e = kf.easing) != null ? _e : kf.e;
4257
+ const easing = kfEasing(kf);
3658
4258
  const colorOut = { time: t, value: sliced.color };
3659
4259
  if (easing !== void 0) colorOut.easing = easing;
3660
4260
  colorKfs.push(colorOut);
@@ -3681,13 +4281,12 @@ function animatedStopNode(baseline, kfs, stopIdx, _ctx, loop) {
3681
4281
  return stop;
3682
4282
  }
3683
4283
  function prevDefinedStop(kfs, fromIdx, stopIdx) {
3684
- var _a, _b;
3685
4284
  for (let i = fromIdx; i >= 0; i--) {
3686
- const arr = (_a = kfs[i].value) != null ? _a : kfs[i].v;
4285
+ const arr = kfValue(kfs[i]);
3687
4286
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3688
4287
  }
3689
4288
  for (let i = fromIdx + 1; i < kfs.length; i++) {
3690
- const arr = (_b = kfs[i].value) != null ? _b : kfs[i].v;
4289
+ const arr = kfValue(kfs[i]);
3691
4290
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3692
4291
  }
3693
4292
  return void 0;
@@ -3697,12 +4296,12 @@ function formatOffset(o) {
3697
4296
  return pct + "%";
3698
4297
  }
3699
4298
 
3700
- // src/effects/clipPathEffect.ts
4299
+ // src/effects/clipping/clipPathEffect.ts
3701
4300
  function applyClipPathEffect(node, fx, ctx) {
3702
- if (!(fx == null ? void 0 : fx.d)) return node;
4301
+ if (!(fx == null ? void 0 : fx.pathData)) return node;
3703
4302
  const clipId = genId(ctx, "clip");
3704
4303
  const pathChild = { type: "path" };
3705
- const read = readAnimatable(fx.d);
4304
+ const read = readAnimatable(fx.pathData);
3706
4305
  if (read.kind !== "absent" /* Absent */) {
3707
4306
  if (read.kind === "static" /* Static */) {
3708
4307
  pathChild.d = pathString(read.value);
@@ -3717,16 +4316,16 @@ function applyClipPathEffect(node, fx, ctx) {
3717
4316
  }
3718
4317
  function pathString(v) {
3719
4318
  if (typeof v === "string") return v;
3720
- if (v && typeof v === "object" && typeof v.path === "string") return v.path;
4319
+ if (v && typeof v === "object" && typeof v.pathData === "string") return v.pathData;
3721
4320
  return void 0;
3722
4321
  }
3723
4322
 
3724
- // src/effects/maskedByEffect.ts
4323
+ // src/effects/clipping/maskedByEffect.ts
3725
4324
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
3726
4325
  if (!fx) return node;
3727
- const sourceId = stripHash2(fx.sourceId);
4326
+ const sourceId = stripHash2(fx.source);
3728
4327
  if (!sourceId) {
3729
- ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
4328
+ ctx.errors.push("maskedBy.source missing \u2014 cannot build mask");
3730
4329
  return node;
3731
4330
  }
3732
4331
  const maskId = genId(ctx, "mask");
@@ -3764,8 +4363,8 @@ function wrapInverseTransform(inner, fx, ctx) {
3764
4363
  }
3765
4364
  function wrapInversePart(inner, part, raw, origin, ctx) {
3766
4365
  if (raw === void 0) return inner;
3767
- const normalisedRaw = part === "scale" /* Scale */ && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
3768
- const v = readAnimatable(normalisedRaw);
4366
+ const normalizedRaw = part === "scale" /* Scale */ && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
4367
+ const v = readAnimatable(normalizedRaw);
3769
4368
  if (v.kind === "static" /* Static */) {
3770
4369
  return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
3771
4370
  }
@@ -3789,16 +4388,16 @@ function invertPartValue(part, value) {
3789
4388
  return [1 / value[0], 1 / value[1]];
3790
4389
  }
3791
4390
  function negatedSpatialTangents(kf) {
3792
- var _a, _b;
4391
+ var _a2, _b;
3793
4392
  const out = {};
3794
- const to = (_a = kf.tangentOut) != null ? _a : kf.to;
4393
+ const to = (_a2 = kf.tangentOut) != null ? _a2 : kf.to;
3795
4394
  const ti = (_b = kf.tangentIn) != null ? _b : kf.ti;
3796
4395
  if (Array.isArray(to)) out.tangentOut = [-to[0], -to[1]];
3797
4396
  if (Array.isArray(ti)) out.tangentIn = [-ti[0], -ti[1]];
3798
4397
  return out;
3799
4398
  }
3800
4399
  function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
3801
- var _a;
4400
+ var _a2;
3802
4401
  const animate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3803
4402
  const animTr = animate == null ? void 0 : animate.transform;
3804
4403
  const kfs = animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes) ? animTr.keyframes : void 0;
@@ -3807,7 +4406,7 @@ function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
3807
4406
  const rotateKfs = [];
3808
4407
  const scaleKfs = [];
3809
4408
  for (const kf of kfs) {
3810
- const v = ((_a = kf.value) != null ? _a : kf.v) || {};
4409
+ const v = ((_a2 = kf.value) != null ? _a2 : kf.v) || {};
3811
4410
  const baseKf = keyframeWith(kf, void 0);
3812
4411
  if (Array.isArray(v.translate)) {
3813
4412
  translateKfs.push(__spreadProps(__spreadValues(__spreadValues({}, baseKf), negatedSpatialTangents(kf)), { value: { translate: [-v.translate[0], -v.translate[1]] } }));
@@ -3871,7 +4470,7 @@ function readTransformationFromBody(node) {
3871
4470
  return void 0;
3872
4471
  }
3873
4472
  function parseTransformStringToParts(s) {
3874
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
4473
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
3875
4474
  const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
3876
4475
  let m;
3877
4476
  const ops = [];
@@ -3885,7 +4484,7 @@ function parseTransformStringToParts(s) {
3885
4484
  for (let j = ops.length - 2; j >= 0; j--) {
3886
4485
  const cand = ops[j];
3887
4486
  if (cand.name !== "translate") continue;
3888
- const ox = (_a = cand.args[0]) != null ? _a : 0;
4487
+ const ox = (_a2 = cand.args[0]) != null ? _a2 : 0;
3889
4488
  const oy = (_b = cand.args[1]) != null ? _b : 0;
3890
4489
  const lx = (_c = last.args[0]) != null ? _c : 0;
3891
4490
  const ly = (_d = last.args[1]) != null ? _d : 0;
@@ -4000,8 +4599,8 @@ function interpKfs(kfs, t) {
4000
4599
  function collectMaskAncestorChains(root, ctx) {
4001
4600
  const interestingNodes = /* @__PURE__ */ new Set();
4002
4601
  const collectInterestingNodes = (n) => {
4003
- var _a, _b;
4004
- const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.sourceId);
4602
+ var _a2, _b;
4603
+ const maskSourceId = stripHash2((_b = (_a2 = n.effects) == null ? void 0 : _a2.maskedBy) == null ? void 0 : _b.source);
4005
4604
  if (typeof maskSourceId === "string") {
4006
4605
  interestingNodes.add(n);
4007
4606
  const sourceNode = ctx.idMap.get(maskSourceId);
@@ -4022,7 +4621,7 @@ function collectMaskAncestorChains(root, ctx) {
4022
4621
  walk(root, []);
4023
4622
  }
4024
4623
  function extractTranslateOnly(node, ctx) {
4025
- var _a, _b, _c;
4624
+ var _a2, _b, _c;
4026
4625
  const tr = node.transform;
4027
4626
  const animateBlock = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate.transform : void 0;
4028
4627
  if (tr === void 0 && !animateBlock) return void 0;
@@ -4030,7 +4629,7 @@ function extractTranslateOnly(node, ctx) {
4030
4629
  if (typeof tr === "string") {
4031
4630
  const parts = parseTranslateOnlyFromString(tr, ctx);
4032
4631
  if (parts) out.translate = parts;
4033
- } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
4632
+ } else if (tr && typeof tr === "object" && !tr.keyframes) {
4034
4633
  const wrapped = tr.value;
4035
4634
  const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
4036
4635
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
@@ -4044,7 +4643,7 @@ function extractTranslateOnly(node, ctx) {
4044
4643
  const kfs = animateBlock.keyframes;
4045
4644
  const translateKfs = [];
4046
4645
  for (const kf of kfs) {
4047
- const v = (_a = kf.value) != null ? _a : kf.v;
4646
+ const v = (_a2 = kf.value) != null ? _a2 : kf.v;
4048
4647
  const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
4049
4648
  if (v && typeof v === "object" && Array.isArray(v.translate)) {
4050
4649
  translateKfs.push({ time: t, value: [v.translate[0] || 0, v.translate[1] || 0] });
@@ -4078,16 +4677,15 @@ function parseTranslateOnlyFromString(s, ctx) {
4078
4677
  return seen ? [x, y] : void 0;
4079
4678
  }
4080
4679
 
4081
- // src/effects/refEffect.ts
4082
- var CONTENT_SUBREF = "content";
4680
+ // src/effects/reference/refEffect.ts
4083
4681
  function applyRefHref(node, clone2, ctx) {
4084
4682
  if (!clone2) return;
4085
- const sourceId = stripHash2(clone2.sourceId);
4683
+ const sourceId = stripHash2(clone2.source);
4086
4684
  if (!sourceId) {
4087
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
4685
+ if (clone2.without === PxCloneWithout.translate) ctx.errors.push("clone: content ref missing `source`");
4088
4686
  return;
4089
4687
  }
4090
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4688
+ const targetId = clone2.without === PxCloneWithout.translate ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4091
4689
  node.href = "#" + targetId;
4092
4690
  }
4093
4691
  function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
@@ -4095,11 +4693,11 @@ function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
4095
4693
  return applyTransformByEffect(node, transformBy, ctx);
4096
4694
  }
4097
4695
 
4098
- // src/effects/repeaterEffect.ts
4696
+ // src/effects/transform/repeaterEffect.ts
4099
4697
  function applyRepeaterEffect(node, fx, ctx) {
4100
- var _a, _b;
4698
+ var _a2, _b;
4101
4699
  if (!fx) return node;
4102
- const copies = (_a = fx.copies) != null ? _a : 1;
4700
+ const copies = (_a2 = fx.copies) != null ? _a2 : 1;
4103
4701
  if (copies < 1) {
4104
4702
  ctx.errors.push("repeater.copies invalid: " + fx.copies);
4105
4703
  return node;
@@ -4166,11 +4764,11 @@ function synthesiseScale(raw, i) {
4166
4764
  return mapAnimatable(raw, scalePower, true);
4167
4765
  }
4168
4766
 
4169
- // src/effects/retimeEffect.ts
4170
- var RETIME_MATERIALISATION_MODE_INLINE_G = false;
4767
+ // src/effects/reference/retimeEffect.ts
4768
+ var RETIME_MATERIALIZATION_MODE_INLINE_G = false;
4171
4769
  function asRetime(r) {
4172
- var _a, _b;
4173
- return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
4770
+ var _a2, _b;
4771
+ return { start: (_a2 = r.start) != null ? _a2 : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
4174
4772
  }
4175
4773
  var CROP_EDGE_MS = 1;
4176
4774
  function applyTimeCrop(useNode, crop, ctx) {
@@ -4198,12 +4796,12 @@ function concatRetime(child, parent) {
4198
4796
  };
4199
4797
  }
4200
4798
  function readCloneRetime(n) {
4201
- var _a, _b;
4202
- return (_b = (_a = n.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.retime;
4799
+ var _a2, _b;
4800
+ return (_b = (_a2 = n.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.retime;
4203
4801
  }
4204
4802
  function clearCloneRetime(n) {
4205
- var _a;
4206
- const clone2 = (_a = n.effects) == null ? void 0 : _a.clone;
4803
+ var _a2;
4804
+ const clone2 = (_a2 = n.effects) == null ? void 0 : _a2.clone;
4207
4805
  if (!clone2) return;
4208
4806
  delete clone2.retime;
4209
4807
  if (Object.keys(clone2).length === 0) delete n.effects.clone;
@@ -4214,9 +4812,9 @@ function applyAllRetimeEffects(root, ctx) {
4214
4812
  indexById(root, ctx.idMap);
4215
4813
  const sites = [];
4216
4814
  const collect = (n) => {
4217
- var _a;
4815
+ var _a2;
4218
4816
  if (readCloneRetime(n)) sites.push(n);
4219
- (_a = n.children) == null ? void 0 : _a.forEach(collect);
4817
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(collect);
4220
4818
  };
4221
4819
  collect(root);
4222
4820
  const reachCount = /* @__PURE__ */ new Map();
@@ -4224,7 +4822,7 @@ function applyAllRetimeEffects(root, ctx) {
4224
4822
  let count = 0;
4225
4823
  const visited = /* @__PURE__ */ new Set();
4226
4824
  const walk = (n) => {
4227
- var _a;
4825
+ var _a2;
4228
4826
  if (!n) return;
4229
4827
  if (n !== site && readCloneRetime(n)) count++;
4230
4828
  if (n.type === "use" && n.href) {
@@ -4234,7 +4832,7 @@ function applyAllRetimeEffects(root, ctx) {
4234
4832
  walk(ctx.idMap.get(id));
4235
4833
  }
4236
4834
  }
4237
- (_a = n.children) == null ? void 0 : _a.forEach(walk);
4835
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walk);
4238
4836
  };
4239
4837
  const rootId = stripHash2(site.href);
4240
4838
  if (rootId) {
@@ -4244,19 +4842,19 @@ function applyAllRetimeEffects(root, ctx) {
4244
4842
  reachCount.set(site, count);
4245
4843
  }
4246
4844
  sites.sort((a, b) => {
4247
- var _a, _b;
4248
- return ((_a = reachCount.get(b)) != null ? _a : 0) - ((_b = reachCount.get(a)) != null ? _b : 0);
4845
+ var _a2, _b;
4846
+ return ((_a2 = reachCount.get(b)) != null ? _a2 : 0) - ((_b = reachCount.get(a)) != null ? _b : 0);
4249
4847
  });
4250
4848
  for (const useNode of sites) {
4251
4849
  const retime = readCloneRetime(useNode);
4252
4850
  if (!retime) continue;
4253
4851
  const crop = retime.timeCrop;
4254
4852
  clearCloneRetime(useNode);
4255
- materialiseRetime(useNode, asRetime(retime), ctx);
4853
+ materializeRetime(useNode, asRetime(retime), ctx);
4256
4854
  if (crop) applyTimeCrop(useNode, crop, ctx);
4257
4855
  }
4258
4856
  }
4259
- function materialiseRetime(useNode, retime, ctx) {
4857
+ function materializeRetime(useNode, retime, ctx) {
4260
4858
  const targetId = stripHash2(useNode.href);
4261
4859
  if (!targetId) {
4262
4860
  ctx.errors.push("retime: <use> has no href to follow");
@@ -4264,7 +4862,7 @@ function materialiseRetime(useNode, retime, ctx) {
4264
4862
  }
4265
4863
  const chainRootId = buildChainClone(targetId, retime, ctx, /* @__PURE__ */ new Set());
4266
4864
  if (!chainRootId) return;
4267
- if (RETIME_MATERIALISATION_MODE_INLINE_G) {
4865
+ if (RETIME_MATERIALIZATION_MODE_INLINE_G) {
4268
4866
  const cloneNode = ctx.idMap.get(chainRootId);
4269
4867
  useNode.type = "g";
4270
4868
  delete useNode.href;
@@ -4304,15 +4902,15 @@ function buildChainClone(targetId, accum, ctx, chain) {
4304
4902
  if (subId2) cloneNode.href = "#" + subId2;
4305
4903
  }
4306
4904
  } else {
4307
- materialiseNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4905
+ materializeNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4308
4906
  }
4309
4907
  ctx.defs.push(cloneNode);
4310
4908
  if (typeof cloneNode.id === "string") ctx.idMap.set(cloneNode.id, cloneNode);
4311
4909
  return typeof cloneNode.id === "string" ? cloneNode.id : void 0;
4312
4910
  }
4313
- function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4911
+ function materializeNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4314
4912
  const visit = (n) => {
4315
- var _a;
4913
+ var _a2;
4316
4914
  const retime = readCloneRetime(n);
4317
4915
  if (n.type === "use" && retime && n.href) {
4318
4916
  const subId = stripHash2(n.href);
@@ -4325,14 +4923,14 @@ function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4325
4923
  }
4326
4924
  clearCloneRetime(n);
4327
4925
  }
4328
- (_a = n.children) == null ? void 0 : _a.forEach(visit);
4926
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
4329
4927
  };
4330
4928
  visit(node);
4331
4929
  }
4332
4930
  function remapKeyframeTimes(node, start, stretch) {
4333
- var _a;
4931
+ var _a2;
4334
4932
  remapKeyframeTimesOnly(node, start, stretch);
4335
- (_a = node.children) == null ? void 0 : _a.forEach((c) => remapKeyframeTimes(c, start, stretch));
4933
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => remapKeyframeTimes(c, start, stretch));
4336
4934
  }
4337
4935
  function remapKeyframeTimesOnly(node, start, stretch) {
4338
4936
  const remap2 = (kfs) => {
@@ -4349,7 +4947,7 @@ function remapKeyframeTimesOnly(node, start, stretch) {
4349
4947
  }
4350
4948
  }
4351
4949
 
4352
- // src/effects/pathSampler.ts
4950
+ // src/effects/text/pathSampler.ts
4353
4951
  var LUT_STEPS = 48;
4354
4952
  var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
4355
4953
  function tokenize(d) {
@@ -4497,7 +5095,7 @@ function createPathSampler(d) {
4497
5095
  };
4498
5096
  }
4499
5097
 
4500
- // src/effects/textPathEffect.ts
5098
+ // src/effects/text/textPathEffect.ts
4501
5099
  var EXTEND_MARGIN_FRAC = 0.15;
4502
5100
  function numRange(v) {
4503
5101
  const read = readAnimatable(v);
@@ -4511,10 +5109,10 @@ function numRange(v) {
4511
5109
  function estimateTextAdvance(node) {
4512
5110
  let chars = 0, maxFont = 16;
4513
5111
  const walk = (el) => {
4514
- var _a, _b;
4515
- const fs = parseFloat(String((_a = el.fontSize) != null ? _a : "")) || 0;
5112
+ var _a2;
5113
+ const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
4516
5114
  if (fs) maxFont = Math.max(maxFont, fs);
4517
- const t = (_b = el.text) != null ? _b : el.textContent;
5115
+ const t = el.textContent;
4518
5116
  if (typeof t === "string") chars += t.length;
4519
5117
  if (el.children) for (const c of el.children) walk(c);
4520
5118
  };
@@ -4536,14 +5134,14 @@ function shiftAnimatable(v, by) {
4536
5134
  return out;
4537
5135
  }
4538
5136
  function extendedPathForBrowser(pathD, opts) {
4539
- var _a;
5137
+ var _a2;
4540
5138
  if (opts.pathOverflow === "clip") return { d: pathD, startShift: 0 };
4541
5139
  const sampler = createPathSampler(pathD);
4542
5140
  if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };
4543
5141
  const L = sampler.totalLength;
4544
5142
  const margin = EXTEND_MARGIN_FRAC * L;
4545
5143
  const so = numRange(opts.startOffset);
4546
- const runWidth = numRange(opts.textLength).max || ((_a = opts.advance) != null ? _a : 0);
5144
+ const runWidth = numRange(opts.textLength).max || ((_a2 = opts.advance) != null ? _a2 : 0);
4547
5145
  const startOverflow = Math.max(0, -so.min);
4548
5146
  const endOverflow = Math.max(0, so.max + runWidth - L);
4549
5147
  const startExt = startOverflow > 0 ? startOverflow + margin : 0;
@@ -4564,10 +5162,10 @@ function extendedPathForBrowser(pathD, opts) {
4564
5162
  return { d, startShift: startExt };
4565
5163
  }
4566
5164
  function applyTextPathEffect(node, fx, ctx) {
4567
- var _a;
4568
- if (!fx || typeof fx.path !== "string" || !fx.path) return node;
5165
+ var _a2;
5166
+ if (!fx || typeof fx.pathData !== "string" || !fx.pathData) return node;
4569
5167
  const pathId = genId(ctx, "tpath");
4570
- const { d, startShift } = extendedPathForBrowser(fx.path, {
5168
+ const { d, startShift } = extendedPathForBrowser(fx.pathData, {
4571
5169
  pathOverflow: fx.pathOverflow,
4572
5170
  startOffset: fx.startOffset,
4573
5171
  textLength: fx.textLength,
@@ -4577,7 +5175,7 @@ function applyTextPathEffect(node, fx, ctx) {
4577
5175
  const textPath = {
4578
5176
  type: "textPath",
4579
5177
  href: "#" + pathId,
4580
- children: (_a = node.children) != null ? _a : []
5178
+ children: (_a2 = node.children) != null ? _a2 : []
4581
5179
  };
4582
5180
  if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
4583
5181
  if (fx.method !== void 0) textPath.method = fx.method;
@@ -4592,7 +5190,7 @@ function applyAnimatableNumber(node, attrName, raw) {
4592
5190
  writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
4593
5191
  }
4594
5192
 
4595
- // src/effects/elementFactory.ts
5193
+ // src/effects/text/elementFactory.ts
4596
5194
  var jsonElementFactory = (type, props, children) => {
4597
5195
  const node = { type };
4598
5196
  for (const k in props) if (props[k] !== void 0) node[k] = props[k];
@@ -4601,7 +5199,7 @@ var jsonElementFactory = (type, props, children) => {
4601
5199
  return node;
4602
5200
  };
4603
5201
 
4604
- // src/effects/glyphPathBake.ts
5202
+ // src/effects/text/glyphPathBake.ts
4605
5203
  function fmt(v, decimals) {
4606
5204
  return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
4607
5205
  }
@@ -4647,7 +5245,7 @@ function transformPathData(d, m, decimals = 2) {
4647
5245
  return out;
4648
5246
  }
4649
5247
 
4650
- // src/effects/textGlyphsEffect.ts
5248
+ // src/effects/text/textGlyphsEffect.ts
4651
5249
  var DEFAULT_FONT_SIZE = 16;
4652
5250
  var TEXT_ATTR_KEYS = [
4653
5251
  "fontFamily",
@@ -4669,7 +5267,6 @@ var TEXT_ATTR_KEYS = [
4669
5267
  "stroke",
4670
5268
  "strokeWidth",
4671
5269
  "effects",
4672
- TEXT_ATTR,
4673
5270
  TEXT_CONTENT_ATTR,
4674
5271
  "xml:space"
4675
5272
  ];
@@ -4707,15 +5304,15 @@ function paintAnimateOf(node) {
4707
5304
  return out;
4708
5305
  }
4709
5306
  function resolveStyle2(node, parent) {
4710
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5307
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
4711
5308
  const isTextRoot = node.type === "text";
4712
5309
  const nodeStyle = node.style;
4713
5310
  const own = (key) => {
4714
- var _a2;
4715
- return isTextRoot ? void 0 : (_a2 = node[key]) != null ? _a2 : nodeStyle == null ? void 0 : nodeStyle[key];
5311
+ var _a3;
5312
+ return isTextRoot ? void 0 : (_a3 = node[key]) != null ? _a3 : nodeStyle == null ? void 0 : nodeStyle[key];
4716
5313
  };
4717
5314
  const res = {
4718
- fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
5315
+ fontFamily: (_a2 = str(node.fontFamily)) != null ? _a2 : parent.fontFamily,
4719
5316
  fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
4720
5317
  fill: (_c = node.fill) != null ? _c : parent.fill,
4721
5318
  stroke: (_d = node.stroke) != null ? _d : parent.stroke,
@@ -4732,10 +5329,10 @@ function resolveStyle2(node, parent) {
4732
5329
  return res;
4733
5330
  }
4734
5331
  function rootStyleOf(node) {
4735
- var _a, _b, _c;
5332
+ var _a2, _b, _c;
4736
5333
  return {
4737
5334
  fontFamily: str(node.fontFamily),
4738
- fontSize: (_a = parseLen(node.fontSize)) != null ? _a : DEFAULT_FONT_SIZE,
5335
+ fontSize: (_a2 = parseLen(node.fontSize)) != null ? _a2 : DEFAULT_FONT_SIZE,
4739
5336
  fill: node.fill,
4740
5337
  stroke: node.stroke,
4741
5338
  strokeWidth: node.strokeWidth,
@@ -4756,9 +5353,9 @@ function paintOf(s) {
4756
5353
  return p;
4757
5354
  }
4758
5355
  function glyphFontFor(s, glyphs, soleFont, warnings) {
4759
- var _a;
5356
+ var _a2;
4760
5357
  const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;
4761
- if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a = s.fontFamily) != null ? _a : "") + '"');
5358
+ if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a2 = s.fontFamily) != null ? _a2 : "") + '"');
4762
5359
  return gf;
4763
5360
  }
4764
5361
  function soleFontOf(glyphs) {
@@ -4779,26 +5376,26 @@ function missingGlyphBoxEm(advanceEm, ascentEm) {
4779
5376
  const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
4780
5377
  return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
4781
5378
  }
4782
- function materialiseGlyphTextHorizontal(node, opts) {
4783
- var _a, _b, _c, _d;
5379
+ function materializeGlyphTextHorizontal(node, opts) {
5380
+ var _a2, _b, _c;
4784
5381
  const { glyphs, create = jsonElementFactory, warnings } = opts;
4785
5382
  const soleFont = soleFontOf(glyphs);
4786
- const pen = { x: (_a = parseLen(node.x)) != null ? _a : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
5383
+ const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
4787
5384
  const placements = [];
4788
5385
  const lines = [{ start: pen.x, end: pen.x }];
4789
5386
  let line = 0;
4790
5387
  const renderChars = (content, s) => {
4791
- var _a2;
5388
+ var _a3;
4792
5389
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4793
5390
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4794
5391
  const scale = s.fontSize / upm;
4795
- const ascentEm = (_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm;
5392
+ const ascentEm = (_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm;
4796
5393
  const paint = paintOf(s);
4797
5394
  for (let i = 0; i < content.length; i++) {
4798
5395
  const ch = content.charAt(i);
4799
5396
  const g = gf == null ? void 0 : gf.glyphs[ch];
4800
- if (g && g.d) {
4801
- placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
5397
+ if (g && g.pathData) {
5398
+ placements.push({ glyphD: g.pathData, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
4802
5399
  pen.x += g.width * scale;
4803
5400
  } else if (/\S/.test(ch)) {
4804
5401
  const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
@@ -4812,7 +5409,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4812
5409
  }
4813
5410
  };
4814
5411
  const walk = (el, parentStyle) => {
4815
- var _a2, _b2, _c2, _d2;
5412
+ var _a3, _b2, _c2;
4816
5413
  const s = resolveStyle2(el, parentStyle);
4817
5414
  const x = parseLen(el.x);
4818
5415
  const y = parseLen(el.y);
@@ -4822,16 +5419,16 @@ function materialiseGlyphTextHorizontal(node, opts) {
4822
5419
  lines.push({ start: pen.x, end: pen.x });
4823
5420
  }
4824
5421
  if (y !== void 0) pen.y = y;
4825
- pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
5422
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4826
5423
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4827
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4828
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5424
+ const content = str(el[TEXT_CONTENT_ATTR]);
5425
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
4829
5426
  if (el.children) for (const ch of el.children) walk(ch, s);
4830
5427
  };
4831
5428
  const rootStyle = rootStyleOf(node);
4832
5429
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
4833
- const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
4834
- if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
5430
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5431
+ if (rootContent && !((_c = node.children) == null ? void 0 : _c.length)) renderChars(rootContent, rootStyle);
4835
5432
  const anchor = str(node.textAnchor);
4836
5433
  if (anchor === "middle" || anchor === "end") {
4837
5434
  for (const p of placements) {
@@ -4843,8 +5440,8 @@ function materialiseGlyphTextHorizontal(node, opts) {
4843
5440
  return toGroup(node, buildPaths(placements, create, warnings), create);
4844
5441
  }
4845
5442
  function layoutGlyphTextChars(node, opts) {
4846
- var _a, _b, _c, _d, _e, _f;
4847
- if ((_a = opts.alongPath) == null ? void 0 : _a.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
5443
+ var _a2, _b, _c, _d, _e;
5444
+ if ((_a2 = opts.alongPath) == null ? void 0 : _a2.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
4848
5445
  const { glyphs, warnings } = opts;
4849
5446
  const soleFont = soleFontOf(glyphs);
4850
5447
  const pen = { x: (_b = parseLen(node.x)) != null ? _b : 0, y: (_c = parseLen(node.y)) != null ? _c : 0 };
@@ -4852,11 +5449,11 @@ function layoutGlyphTextChars(node, opts) {
4852
5449
  const lines = [{ start: pen.x, end: pen.x }];
4853
5450
  let line = 0;
4854
5451
  const renderChars = (content, s) => {
4855
- var _a2;
5452
+ var _a3;
4856
5453
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4857
5454
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4858
5455
  const scale = s.fontSize / upm;
4859
- const ascent = ((_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm) * scale;
5456
+ const ascent = ((_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm) * scale;
4860
5457
  for (let i = 0; i < content.length; i++) {
4861
5458
  const ch = content.charAt(i);
4862
5459
  const g = gf == null ? void 0 : gf.glyphs[ch];
@@ -4867,7 +5464,7 @@ function layoutGlyphTextChars(node, opts) {
4867
5464
  }
4868
5465
  };
4869
5466
  const walk = (el, parentStyle) => {
4870
- var _a2, _b2, _c2, _d2;
5467
+ var _a3, _b2, _c2;
4871
5468
  const s = resolveStyle2(el, parentStyle);
4872
5469
  const x = parseLen(el.x);
4873
5470
  const y = parseLen(el.y);
@@ -4877,10 +5474,10 @@ function layoutGlyphTextChars(node, opts) {
4877
5474
  lines.push({ start: pen.x, end: pen.x });
4878
5475
  }
4879
5476
  if (y !== void 0) pen.y = y;
4880
- pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
5477
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4881
5478
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4882
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4883
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5479
+ const content = str(el[TEXT_CONTENT_ATTR]);
5480
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
4884
5481
  if (el.children) for (const ch of el.children) walk(ch, s);
4885
5482
  };
4886
5483
  const rootStyle = rootStyleOf(node);
@@ -4894,8 +5491,8 @@ function layoutGlyphTextChars(node, opts) {
4894
5491
  boxes.push({ x: pen.x, y: pen.y, width: 0, ascent: ((_d = gf == null ? void 0 : gf.ascent) != null ? _d : 0.9 * upm) * (s.fontSize / upm), fontSize: s.fontSize, line });
4895
5492
  }
4896
5493
  }
4897
- const rootContent = (_e = str(node[TEXT_CONTENT_ATTR])) != null ? _e : str(node[TEXT_ATTR]);
4898
- if (rootContent && !((_f = node.children) == null ? void 0 : _f.length)) renderChars(rootContent, rootStyle);
5494
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5495
+ if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
4899
5496
  const anchor = str(node.textAnchor);
4900
5497
  if (anchor === "middle" || anchor === "end") {
4901
5498
  for (const b of boxes) {
@@ -4903,13 +5500,13 @@ function layoutGlyphTextChars(node, opts) {
4903
5500
  b.x += anchor === "middle" ? -w / 2 : -w;
4904
5501
  }
4905
5502
  }
4906
- return boxes.map((_g) => {
4907
- var _h = _g, { line: _l } = _h, b = __objRest(_h, ["line"]);
5503
+ return boxes.map((_f) => {
5504
+ var _g = _f, { line: _l } = _g, b = __objRest(_g, ["line"]);
4908
5505
  return b;
4909
5506
  });
4910
5507
  }
4911
5508
  function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4912
- var _a, _b;
5509
+ var _a2, _b;
4913
5510
  const { glyphs, warnings, alongPath } = opts;
4914
5511
  const sampler = createPathSampler(pathD);
4915
5512
  if (!sampler) {
@@ -4920,14 +5517,14 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4920
5517
  const chars = [];
4921
5518
  let adv = 0;
4922
5519
  const walk = (el, parentStyle) => {
4923
- var _a2, _b2, _c;
5520
+ var _a3, _b2;
4924
5521
  const s = resolveStyle2(el, parentStyle);
4925
- const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
4926
- if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
5522
+ const content = str(el[TEXT_CONTENT_ATTR]);
5523
+ if (content && !((_a3 = el.children) == null ? void 0 : _a3.length)) {
4927
5524
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4928
5525
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4929
5526
  const scale = s.fontSize / upm;
4930
- const ascent = ((_c = gf == null ? void 0 : gf.ascent) != null ? _c : 0.9 * upm) * scale;
5527
+ const ascent = ((_b2 = gf == null ? void 0 : gf.ascent) != null ? _b2 : 0.9 * upm) * scale;
4931
5528
  for (let i = 0; i < content.length; i++) {
4932
5529
  const ch = content.charAt(i);
4933
5530
  const g = gf == null ? void 0 : gf.glyphs[ch];
@@ -4942,7 +5539,7 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4942
5539
  walk(node, rootStyleOf(node));
4943
5540
  const width = adv;
4944
5541
  const tlr = readAnimatable(alongPath == null ? void 0 : alongPath.textLength);
4945
- 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;
5542
+ 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;
4946
5543
  const k = tlv > 0 && width > 0 ? tlv / width : 1;
4947
5544
  const so = readAnimatable(alongPath == null ? void 0 : alongPath.startOffset);
4948
5545
  const { along: alongOffset, perp } = alongPathNodeOffsets(node);
@@ -4974,21 +5571,21 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4974
5571
  const cells = [];
4975
5572
  let adv = 0;
4976
5573
  const walk = (el, parentStyle) => {
4977
- var _a, _b, _c;
5574
+ var _a2, _b;
4978
5575
  const s = resolveStyle2(el, parentStyle);
4979
- const content = (_a = str(el[TEXT_CONTENT_ATTR])) != null ? _a : str(el[TEXT_ATTR]);
4980
- if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
5576
+ const content = str(el[TEXT_CONTENT_ATTR]);
5577
+ if (content && !((_a2 = el.children) == null ? void 0 : _a2.length)) {
4981
5578
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4982
5579
  if (gf) {
4983
5580
  const scale = s.fontSize / gf.unitsPerEm;
4984
- const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
5581
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
4985
5582
  const paint = paintOf(s);
4986
5583
  for (let i = 0; i < content.length; i++) {
4987
5584
  const ch = content.charAt(i);
4988
5585
  const g = gf.glyphs[ch];
4989
- if (g && g.d) {
5586
+ if (g && g.pathData) {
4990
5587
  const glyphAdv = g.width * scale;
4991
- cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
5588
+ cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
4992
5589
  adv += glyphAdv;
4993
5590
  } else if (/\S/.test(ch)) {
4994
5591
  const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
@@ -5013,13 +5610,13 @@ function alongAffine(sampler, dist, scale, widthEm, perp = 0) {
5013
5610
  return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];
5014
5611
  }
5015
5612
  function alongPathNodeOffsets(node) {
5016
- var _a, _b, _c;
5613
+ var _a2, _b, _c;
5017
5614
  return {
5018
- along: ((_a = parseLen(node.x)) != null ? _a : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
5615
+ along: ((_a2 = parseLen(node.x)) != null ? _a2 : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
5019
5616
  perp: (_c = parseLen(node.dy)) != null ? _c : 0
5020
5617
  };
5021
5618
  }
5022
- function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5619
+ function materializeGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5023
5620
  const { glyphs, create = jsonElementFactory, warnings } = opts;
5024
5621
  const sampler = pathD ? createPathSampler(pathD) : null;
5025
5622
  if (!sampler) {
@@ -5055,7 +5652,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
5055
5652
  return toGroup(node, buildPaths(placements, create, warnings), create);
5056
5653
  }
5057
5654
  function numTrackOf(raw) {
5058
- var _a;
5655
+ var _a2;
5059
5656
  const r = readAnimatable(raw);
5060
5657
  if (r.kind === "animated" /* Animated */ && r.keyframes.length >= 2) {
5061
5658
  const kfs = [...r.keyframes].sort((k1, k2) => (Number(k1.time) || 0) - (Number(k2.time) || 0));
@@ -5078,7 +5675,7 @@ function numTrackOf(raw) {
5078
5675
  }
5079
5676
  };
5080
5677
  }
5081
- 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;
5678
+ 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;
5082
5679
  return { animated: false, times: [], at: () => v };
5083
5680
  }
5084
5681
  function mergeTrackTimes(a, b) {
@@ -5098,8 +5695,8 @@ function buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isC
5098
5695
  const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
5099
5696
  const out = [];
5100
5697
  for (const c of cells) {
5101
- const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5102
- const d = transformPathData(c.glyphD, centred);
5698
+ const centered = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5699
+ const d = transformPathData(c.glyphD, centered);
5103
5700
  const sampleKf = (dist, time) => {
5104
5701
  const { x, y, angle } = sampler.sampleAtDistance(dist);
5105
5702
  const cos = Math.cos(angle), sin = Math.sin(angle);
@@ -5154,7 +5751,7 @@ function paintProps(paint) {
5154
5751
  return p;
5155
5752
  }
5156
5753
  function missingGlyphProps(isMissing) {
5157
- return isMissing ? { class: MISSING_GLYPH_CLASS_NAME } : {};
5754
+ return isMissing ? { [CLASS_ATTR]: MISSING_GLYPH_CLASS_NAME } : {};
5158
5755
  }
5159
5756
  function buildPaths(placements, create, warnings) {
5160
5757
  if (!placements.length) {
@@ -5191,27 +5788,27 @@ function toGroup(node, children, create) {
5191
5788
  }
5192
5789
  return create("g", gProps, children);
5193
5790
  }
5194
- function materialiseGlyphText(node, opts) {
5195
- if (opts.alongPath) return materialiseGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5196
- return materialiseGlyphTextHorizontal(node, opts);
5791
+ function materializeGlyphText(node, opts) {
5792
+ if (opts.alongPath) return materializeGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5793
+ return materializeGlyphTextHorizontal(node, opts);
5197
5794
  }
5198
5795
  function applyTextGlyphsEffect(node, fx, ctx) {
5199
5796
  if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
5200
5797
  if (!ctx.glyphs) {
5201
- ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
5798
+ ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
5202
5799
  return node;
5203
5800
  }
5204
- return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5801
+ return materializeGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5205
5802
  }
5206
5803
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
5207
5804
  if (!ctx.glyphs) {
5208
- ctx.warnings.push("textGlyphs: no definitions.glyphs");
5805
+ ctx.warnings.push("textGlyphs: no definitions.fonts");
5209
5806
  return null;
5210
5807
  }
5211
- return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5808
+ return materializeGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5212
5809
  }
5213
5810
 
5214
- // src/effects/strokeTrimEffect.ts
5811
+ // src/effects/stroke/strokeTrimEffect.ts
5215
5812
  function applyStrokeTrimEffect(node, strokeTrim, ctx) {
5216
5813
  if (!strokeTrim) return node;
5217
5814
  const combined = strokeTrim.subPaths === PxStrokeTrimSubPaths.combined;
@@ -5347,12 +5944,11 @@ function getOffsetIndexRange(minMaxOffset) {
5347
5944
  ];
5348
5945
  }
5349
5946
  function readScalarValues(r) {
5350
- var _a;
5351
5947
  if (r.kind === "absent" /* Absent */) return [];
5352
5948
  if (r.kind === "static" /* Static */) return [r.value];
5353
5949
  const out = [];
5354
5950
  for (const kf of r.keyframes) {
5355
- const v = (_a = kf.value) != null ? _a : kf.v;
5951
+ const v = kfValue(kf);
5356
5952
  if (typeof v === "number") out.push(v);
5357
5953
  }
5358
5954
  return out;
@@ -5362,14 +5958,11 @@ function computeAnimAttr(read, map) {
5362
5958
  if (read.kind === "static" /* Static */) return { kind: "static" /* Static */, value: map(read.value) };
5363
5959
  return {
5364
5960
  kind: "animated" /* Animated */,
5365
- keyframes: read.keyframes.map((kf) => {
5366
- var _a, _b, _c, _d;
5367
- return {
5368
- time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5369
- value: map((_c = kf.value) != null ? _c : kf.v),
5370
- easing: (_d = kf.easing) != null ? _d : kf.e
5371
- };
5372
- }),
5961
+ keyframes: read.keyframes.map((kf) => ({
5962
+ time: kfTime(kf),
5963
+ value: map(kfValue(kf)),
5964
+ easing: kfEasing(kf)
5965
+ })),
5373
5966
  loop: read.loop
5374
5967
  };
5375
5968
  }
@@ -5379,7 +5972,6 @@ function applyAttr(node, attrName, attr) {
5379
5972
  }
5380
5973
  var OPACITY_STEP_MS = 10;
5381
5974
  function computeOpacityFromRange(rangeRead) {
5382
- var _a, _b, _c, _d, _e, _f;
5383
5975
  const hide = (v) => v[0] === v[1];
5384
5976
  if (rangeRead.kind === "absent" /* Absent */) return void 0;
5385
5977
  if (rangeRead.kind === "static" /* Static */) return hide(rangeRead.value) ? { kind: "static" /* Static */, value: 0 } : void 0;
@@ -5387,7 +5979,7 @@ function computeOpacityFromRange(rangeRead) {
5387
5979
  let anyHide = false;
5388
5980
  let allHide = true;
5389
5981
  for (const kf of kfs) {
5390
- if (hide((_a = kf.value) != null ? _a : kf.v)) anyHide = true;
5982
+ if (hide(kfValue(kf))) anyHide = true;
5391
5983
  else allHide = false;
5392
5984
  }
5393
5985
  if (!anyHide) return void 0;
@@ -5397,10 +5989,10 @@ function computeOpacityFromRange(rangeRead) {
5397
5989
  const kf = kfs[i];
5398
5990
  const prevKf = i > 0 ? kfs[i - 1] : void 0;
5399
5991
  const nextKf = i < kfs.length - 1 ? kfs[i + 1] : void 0;
5400
- const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
5401
- const thisHide = hide((_d = kf.value) != null ? _d : kf.v);
5402
- const prevHide = prevKf ? thisHide && hide((_e = prevKf.value) != null ? _e : prevKf.v) : thisHide;
5403
- const nextHide = nextKf ? thisHide && hide((_f = nextKf.value) != null ? _f : nextKf.v) : thisHide;
5992
+ const t = kfTime(kf);
5993
+ const thisHide = hide(kfValue(kf));
5994
+ const prevHide = prevKf ? thisHide && hide(kfValue(prevKf)) : thisHide;
5995
+ const nextHide = nextKf ? thisHide && hide(kfValue(nextKf)) : thisHide;
5404
5996
  if (prevHide && !nextHide) {
5405
5997
  out.push({ time: t, value: 0 });
5406
5998
  out.push({ time: t + OPACITY_STEP_MS, value: 1 });
@@ -5415,14 +6007,11 @@ function computeOpacityFromRange(rangeRead) {
5415
6007
  function readRangeWithCrossings(raw) {
5416
6008
  const r = readAnimatable(raw);
5417
6009
  if (r.kind !== "animated" /* Animated */) return r;
5418
- const kfs = r.keyframes.map((kf) => {
5419
- var _a, _b, _c, _d;
5420
- return {
5421
- time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5422
- value: (_c = kf.value) != null ? _c : kf.v,
5423
- easing: (_d = kf.easing) != null ? _d : kf.e
5424
- };
5425
- });
6010
+ const kfs = r.keyframes.map((kf) => ({
6011
+ time: kfTime(kf),
6012
+ value: kfValue(kf),
6013
+ easing: kfEasing(kf)
6014
+ }));
5426
6015
  const hasReverse = kfs.some((kf) => kf.value[0] > kf.value[1]);
5427
6016
  if (!hasReverse) {
5428
6017
  return {
@@ -5519,20 +6108,20 @@ function pxBezierPathLength(path) {
5519
6108
  return total;
5520
6109
  }
5521
6110
  function segmentLength(path, from, to) {
5522
- var _a, _b, _c, _d;
6111
+ var _a2, _b, _c, _d;
5523
6112
  const v = path.v;
5524
6113
  const p0 = v[from];
5525
6114
  const p3 = v[to];
5526
- const p1 = (_b = (_a = path.o) == null ? void 0 : _a[from]) != null ? _b : p0;
6115
+ const p1 = (_b = (_a2 = path.o) == null ? void 0 : _a2[from]) != null ? _b : p0;
5527
6116
  const p2 = (_d = (_c = path.i) == null ? void 0 : _c[to]) != null ? _d : p3;
5528
6117
  const lut = bezier2D_arcLengthLUT(p0, p1, p2, p3);
5529
6118
  return lut.ds[lut.ds.length - 1];
5530
6119
  }
5531
6120
  var ARC_KAPPA = 0.5522847498307936;
5532
6121
  function shapeToPathD(node) {
5533
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
6122
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5534
6123
  if (node.type === "rect") {
5535
- const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
6124
+ const x = Number((_a2 = node.x) != null ? _a2 : 0), y = Number((_b = node.y) != null ? _b : 0);
5536
6125
  const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
5537
6126
  return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
5538
6127
  }
@@ -5550,7 +6139,7 @@ function shapeToPathD(node) {
5550
6139
 
5551
6140
  // src/effects/PlayerEffectsUtil.ts
5552
6141
  function applyPlayerEffects(root) {
5553
- var _a, _b;
6142
+ var _a2, _b;
5554
6143
  const ctx = {
5555
6144
  defs: [],
5556
6145
  warnings: [],
@@ -5561,8 +6150,8 @@ function applyPlayerEffects(root) {
5561
6150
  maskAncestorChains: /* @__PURE__ */ new Map(),
5562
6151
  // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
5563
6152
  // waapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5564
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi,
5565
- glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
6153
+ engine: resolveTimelineEngine((_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.engine),
6154
+ glyphs: (_b = getDefs(root)) == null ? void 0 : _b.fonts
5566
6155
  };
5567
6156
  const working = clone(root);
5568
6157
  indexById(working, ctx.idMap);
@@ -5585,7 +6174,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5585
6174
  let consumedByGlyphs = false;
5586
6175
  if (text == null ? void 0 : text.useGlyphs) {
5587
6176
  if (textPath) {
5588
- const pathD = typeof textPath.path === "string" ? textPath.path : void 0;
6177
+ const pathD = typeof textPath.pathData === "string" ? textPath.pathData : void 0;
5589
6178
  const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textPath.startOffset, textPath.textLength, textPath.pathOverflow);
5590
6179
  if (glyphed) {
5591
6180
  n = glyphed;
@@ -5618,27 +6207,7 @@ function applyPlayerEffects_retime(node, ctx) {
5618
6207
  return node;
5619
6208
  }
5620
6209
 
5621
- // src/PxOffsetPathMaterialiser.ts
5622
- var kfTime = (kf) => {
5623
- var _a, _b;
5624
- return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
5625
- };
5626
- var kfValue = (kf) => {
5627
- var _a;
5628
- return (_a = kf.v) != null ? _a : kf.value;
5629
- };
5630
- var kfEasing = (kf) => {
5631
- var _a;
5632
- return (_a = kf.e) != null ? _a : kf.easing;
5633
- };
5634
- var kfTangentIn = (kf) => {
5635
- var _a;
5636
- return (_a = kf.tangentIn) != null ? _a : kf.ti;
5637
- };
5638
- var kfTangentOut = (kf) => {
5639
- var _a;
5640
- return (_a = kf.tangentOut) != null ? _a : kf.to;
5641
- };
6210
+ // src/materialize/PxOffsetPathMaterializer.ts
5642
6211
  function cubicAt(p0, c1, c2, p1, t) {
5643
6212
  const u = 1 - t;
5644
6213
  const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
@@ -5662,7 +6231,7 @@ var fmt2 = (n) => {
5662
6231
  return Object.is(r, -0) ? "0" : String(r);
5663
6232
  };
5664
6233
  function buildOffsetPath(propAnim) {
5665
- var _a, _b, _c;
6234
+ var _a2, _b, _c;
5666
6235
  if (propAnim.alongPathMode !== "offsetPath") return void 0;
5667
6236
  const kfs = propAnim.keyframes;
5668
6237
  if (!kfs || kfs.length < 2) return void 0;
@@ -5675,7 +6244,7 @@ function buildOffsetPath(propAnim) {
5675
6244
  if (!tr || tr.length < 2) return void 0;
5676
6245
  const parts = Object.keys(v);
5677
6246
  if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5678
- const o = (_a = v == null ? void 0 : v.origin) != null ? _a : [0, 0];
6247
+ const o = (_a2 = v == null ? void 0 : v.origin) != null ? _a2 : [0, 0];
5679
6248
  if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5680
6249
  points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5681
6250
  }
@@ -5704,9 +6273,9 @@ function buildOffsetPath(propAnim) {
5704
6273
  }
5705
6274
  return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
5706
6275
  }
5707
- function materialiseOffsetPathsInTree(root) {
6276
+ function materializeOffsetPathsInTree(root) {
5708
6277
  const walk = (node) => {
5709
- var _a;
6278
+ var _a2;
5710
6279
  let out = node;
5711
6280
  const anim = node.animate;
5712
6281
  const transform = anim == null ? void 0 : anim["transform"];
@@ -5714,16 +6283,16 @@ function materialiseOffsetPathsInTree(root) {
5714
6283
  const built = buildOffsetPath(transform);
5715
6284
  if (built) {
5716
6285
  const newAnimate = __spreadValues({}, anim);
5717
- delete newAnimate["transform"];
6286
+ delete newAnimate[TRANSFORM_ATTR];
5718
6287
  const distance = { keyframes: built.distanceKfs };
5719
6288
  if (transform.loop !== void 0) distance.loop = transform.loop;
5720
- newAnimate["offsetDistance"] = distance;
6289
+ newAnimate[OFFSET_DISTANCE_ATTR] = distance;
5721
6290
  const staticTr = node.transform;
5722
6291
  let newTransform = staticTr;
5723
6292
  if (staticTr && typeof staticTr === "object") {
5724
6293
  const t = __spreadValues({}, staticTr);
5725
- delete t["translate"];
5726
- delete t["origin"];
6294
+ delete t[TRANSFORM_PART.translate];
6295
+ delete t[TRANSFORM_PART.origin];
5727
6296
  newTransform = Object.keys(t).length ? t : void 0;
5728
6297
  }
5729
6298
  out = __spreadProps(__spreadValues({}, node), {
@@ -5739,7 +6308,7 @@ function materialiseOffsetPathsInTree(root) {
5739
6308
  else delete out.transform;
5740
6309
  }
5741
6310
  }
5742
- if ((_a = out.children) == null ? void 0 : _a.length) {
6311
+ if ((_a2 = out.children) == null ? void 0 : _a2.length) {
5743
6312
  const children = out.children.map(walk);
5744
6313
  if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
5745
6314
  }
@@ -5748,16 +6317,16 @@ function materialiseOffsetPathsInTree(root) {
5748
6317
  return walk(root);
5749
6318
  }
5750
6319
 
5751
- // src/PxAnimatorMaterialiseAll.ts
5752
- function materialiseAllInTree(doc, engine, opts) {
5753
- var _a, _b;
6320
+ // src/materialize/PxAnimatorMaterializeAll.ts
6321
+ function materializeAllInTree(doc, engine, opts) {
6322
+ var _a2, _b;
5754
6323
  let root = applyPlayerEffects(doc).root;
5755
- root = materialiseOffsetPathsInTree(root);
5756
- const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5757
- root = materialiseInternalLoopsInTree(root, duration);
5758
- if (engine === PxAnimatorEngine.waapi) {
5759
- root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5760
- root = materialiseAnimatedUseInstances(root);
6324
+ root = materializeOffsetPathsInTree(root);
6325
+ const duration = (_b = (_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.duration) != null ? _b : DEFAULT_DURATION_MS;
6326
+ root = materializeInternalLoopsInTree(root, duration);
6327
+ if (engine === PxTimelineEngine.native) {
6328
+ root = materializeMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
6329
+ root = materializeAnimatedUseInstances(root);
5761
6330
  root = pruneUnreferencedDefs(root);
5762
6331
  }
5763
6332
  return root;
@@ -5765,9 +6334,9 @@ function materialiseAllInTree(doc, engine, opts) {
5765
6334
  function pruneUnreferencedDefs(root) {
5766
6335
  const stripHash3 = (h) => h.startsWith("#") ? h.slice(1) : h;
5767
6336
  const walk = (n, fn) => {
5768
- var _a;
6337
+ var _a2;
5769
6338
  fn(n);
5770
- (_a = n.children) == null ? void 0 : _a.forEach((c) => walk(c, fn));
6339
+ (_a2 = n.children) == null ? void 0 : _a2.forEach((c) => walk(c, fn));
5771
6340
  };
5772
6341
  let changed = true;
5773
6342
  while (changed) {
@@ -5792,7 +6361,67 @@ function pruneUnreferencedDefs(root) {
5792
6361
  return root;
5793
6362
  }
5794
6363
 
5795
- // src/PxFrameLoop.ts
6364
+ // src/playback/PxPlaybackTime.ts
6365
+ var PX_RATE_REJECTED = "setPlaybackRate: rate must be finite and non-zero";
6366
+ function isValidPlaybackRate(rate) {
6367
+ return Number.isFinite(rate) && rate !== 0;
6368
+ }
6369
+ function seekCeilingMs(durationMs, iterations) {
6370
+ if (!(durationMs > 0)) return 0;
6371
+ if (iterations === Infinity) return Infinity;
6372
+ return durationMs * (iterations > 0 ? iterations : 1);
6373
+ }
6374
+ function progressSpanMs(durationMs, iterations) {
6375
+ if (!(durationMs > 0)) return 0;
6376
+ if (iterations === Infinity) return durationMs;
6377
+ return durationMs * (iterations > 0 ? iterations : 1);
6378
+ }
6379
+ function clampSeekMs(timeMs, ceilingMs) {
6380
+ if (Number.isNaN(timeMs) || timeMs < 0) return 0;
6381
+ if (Number.isFinite(ceilingMs)) return timeMs > ceilingMs ? ceilingMs : timeMs;
6382
+ return Number.isFinite(timeMs) ? timeMs : 0;
6383
+ }
6384
+ function timeToProgress(timeMs, durationMs, iterations) {
6385
+ const span = progressSpanMs(durationMs, iterations);
6386
+ if (!(span > 0) || !Number.isFinite(timeMs)) return 0;
6387
+ if (timeMs <= 0) return 0;
6388
+ if (iterations === Infinity) return timeMs % span / span;
6389
+ return timeMs >= span ? 1 : timeMs / span;
6390
+ }
6391
+ function progressToTimeMs(progress, durationMs, iterations) {
6392
+ const span = progressSpanMs(durationMs, iterations);
6393
+ if (!(span > 0) || !Number.isFinite(progress)) return 0;
6394
+ if (progress <= 0) return 0;
6395
+ return progress >= 1 ? span : progress * span;
6396
+ }
6397
+ function createRunClock(ceilingMs, nowFn = Date.now) {
6398
+ let baseMs = 0;
6399
+ let startedAt = 0;
6400
+ let running = false;
6401
+ let rate = 1;
6402
+ const value = () => running ? clampSeekMs(baseMs + (nowFn() - startedAt) * rate, ceilingMs) : clampSeekMs(baseMs, ceilingMs);
6403
+ return {
6404
+ now: value,
6405
+ isRunning: () => running,
6406
+ start: (r, atMs) => {
6407
+ baseMs = clampSeekMs(atMs != null ? atMs : value(), ceilingMs);
6408
+ rate = isValidPlaybackRate(r) ? r : 1;
6409
+ startedAt = nowFn();
6410
+ running = true;
6411
+ },
6412
+ stop: () => {
6413
+ baseMs = value();
6414
+ startedAt = 0;
6415
+ running = false;
6416
+ },
6417
+ seek: (ms) => {
6418
+ baseMs = clampSeekMs(ms, ceilingMs);
6419
+ if (running) startedAt = nowFn();
6420
+ }
6421
+ };
6422
+ }
6423
+
6424
+ // src/playback/PxFrameLoop.ts
5796
6425
  function requestFrame(cb) {
5797
6426
  const g = globalThis;
5798
6427
  if (typeof g.requestAnimationFrame === "function") return g.requestAnimationFrame(cb);
@@ -5807,9 +6436,9 @@ function cancelFrame(handle) {
5807
6436
  g.clearTimeout(handle);
5808
6437
  }
5809
6438
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5810
- var _a;
6439
+ var _a2;
5811
6440
  const config = getAnimatorConfig(doc) || {};
5812
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
6441
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.js);
5813
6442
  const _iterations = config.iterations;
5814
6443
  let iterations = 1;
5815
6444
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -5818,7 +6447,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5818
6447
  const duration = +(config.duration || DEFAULT_DURATION_MS);
5819
6448
  const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
5820
6449
  const direction = config.direction || "normal";
5821
- const fill = (_a = config.fill) != null ? _a : "forwards";
6450
+ const fill = (_a2 = config.fill) != null ? _a2 : "forwards";
5822
6451
  const fillsForwards = fill === "forwards" || fill === "both";
5823
6452
  const fillsBackwards = fill === "backwards" || fill === "both";
5824
6453
  let timerId = null;
@@ -5880,7 +6509,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5880
6509
  }
5881
6510
  }
5882
6511
  const tick = () => {
5883
- var _a2, _b;
6512
+ var _a3, _b;
5884
6513
  if (!adapter.isConnected()) {
5885
6514
  pauseAnim();
5886
6515
  return;
@@ -5896,7 +6525,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5896
6525
  renderFrame(0);
5897
6526
  if (!finishCalled) {
5898
6527
  finishCalled = true;
5899
- (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
6528
+ (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
5900
6529
  }
5901
6530
  return;
5902
6531
  }
@@ -5988,17 +6617,17 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5988
6617
  }
5989
6618
  };
5990
6619
  const cancelAnim = () => {
5991
- var _a2;
6620
+ var _a3;
5992
6621
  pauseAnim();
5993
6622
  timeBeforeLastStartMs = 0;
5994
6623
  lastStartedTs = 0;
5995
6624
  playing = false;
5996
6625
  finishCalled = false;
5997
6626
  renderFrame(timeBeforeLastStartMs);
5998
- (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
6627
+ (_a3 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a3.call(callbacks);
5999
6628
  };
6000
6629
  const finishAnim = (callOnFinish = true) => {
6001
- var _a2;
6630
+ var _a3;
6002
6631
  if (Number.isFinite(totalDuration)) {
6003
6632
  timeBeforeLastStartMs = totalDuration;
6004
6633
  } else {
@@ -6013,7 +6642,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6013
6642
  renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
6014
6643
  if (callOnFinish && !finishCalled) {
6015
6644
  finishCalled = true;
6016
- (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
6645
+ (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
6017
6646
  }
6018
6647
  };
6019
6648
  const api = {
@@ -6023,14 +6652,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6023
6652
  return _isPlaying();
6024
6653
  },
6025
6654
  "play": () => {
6026
- var _a2;
6655
+ var _a3;
6027
6656
  startAnim();
6028
- (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
6657
+ (_a3 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a3.call(callbacks);
6029
6658
  },
6030
6659
  "pause": () => {
6031
- var _a2;
6660
+ var _a3;
6032
6661
  pauseAnim();
6033
- (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
6662
+ (_a3 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a3.call(callbacks);
6034
6663
  },
6035
6664
  "cancel": () => {
6036
6665
  cancelAnim();
@@ -6039,8 +6668,8 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6039
6668
  finishAnim(true);
6040
6669
  },
6041
6670
  "setPlaybackRate": (rate) => {
6042
- if (!isFinite(rate) || rate === 0) {
6043
- console.warn("setPlaybackRate: rate must be finite and non-zero");
6671
+ if (!isValidPlaybackRate(rate)) {
6672
+ console.warn(PX_RATE_REJECTED);
6044
6673
  return;
6045
6674
  }
6046
6675
  let current = getRawAnimTime();
@@ -6054,22 +6683,70 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6054
6683
  return getAnimCurrentTime();
6055
6684
  },
6056
6685
  "setCurrentTime": (newTime) => {
6057
- if (newTime < 0) newTime = 0;
6058
- if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
6686
+ newTime = clampSeekMs(newTime, totalDuration);
6059
6687
  timeBeforeLastStartMs = newTime;
6060
6688
  if (playing) lastStartedTs = Date.now();
6061
6689
  if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
6062
6690
  renderFrame(getAnimCurrentTime());
6063
6691
  },
6692
+ "getCurrentProgress": () => timeToProgress(getAnimCurrentTime(), duration, iterations),
6693
+ "setCurrentProgress": (progress) => {
6694
+ api.setCurrentTime(progressToTimeMs(progress, duration, iterations));
6695
+ },
6064
6696
  "destroy": () => {
6065
- var _a2;
6697
+ var _a3;
6066
6698
  api.cancel();
6067
- (_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
6699
+ (_a3 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a3.call(callbacks);
6068
6700
  }
6069
6701
  };
6070
6702
  return api;
6071
6703
  }
6072
6704
 
6705
+ // src/playback/PxDiagnostics.ts
6706
+ var PxDiagnosticKind = {
6707
+ /** The document is wrong — regenerate or repair the file. */
6708
+ document: "document",
6709
+ /** The page or app cannot provide what the document asks for — fix the mount. */
6710
+ host: "host",
6711
+ /** The platform cannot do it and the player degraded — usually nothing to fix. */
6712
+ platform: "platform",
6713
+ /** The call is wrong or self-contradictory — fix the options or props you passed. */
6714
+ usage: "usage",
6715
+ /** The player failed where it did not expect to — report it to us. */
6716
+ internal: "internal"
6717
+ };
6718
+ function asError(error) {
6719
+ return typeof error === "string" ? new Error(error) : error;
6720
+ }
6721
+ function isSilenced(silent, kind) {
6722
+ if (!silent) return false;
6723
+ return silent === true || silent.includes(kind);
6724
+ }
6725
+ function createDiagnostics(config, prefix) {
6726
+ const tag = prefix ? prefix + " " : "";
6727
+ return {
6728
+ warn: (kind, message, detail) => {
6729
+ if (config == null ? void 0 : config.onWarn) {
6730
+ config.onWarn({ kind, message, detail });
6731
+ return;
6732
+ }
6733
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6734
+ const line = tag + kind + ": " + message;
6735
+ if (detail === void 0) console.warn(line);
6736
+ else console.warn(line, detail);
6737
+ },
6738
+ error: (kind, error) => {
6739
+ const err = asError(error);
6740
+ if (config == null ? void 0 : config.onError) {
6741
+ config.onError({ kind, message: err.message, error: err });
6742
+ return;
6743
+ }
6744
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6745
+ console.error(tag + kind + ": " + err.message);
6746
+ }
6747
+ };
6748
+ }
6749
+
6073
6750
  // src/effects/PlayerEffectsUtil.visualModel.ts
6074
6751
  var IDENTITY = [1, 0, 0, 1, 0, 0];
6075
6752
  function mul(m, n) {
@@ -6120,9 +6797,9 @@ function lerp(a, b, f) {
6120
6797
  return a + (b - a) * f;
6121
6798
  }
6122
6799
  function interpParts(kfs, t) {
6123
- var _a, _b, _c, _d, _e, _f, _g;
6800
+ var _a2, _b, _c, _d, _e, _f, _g;
6124
6801
  if (!kfs.length) return {};
6125
- if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value || {};
6802
+ if (t <= ((_a2 = kfs[0].time) != null ? _a2 : 0)) return kfs[0].value || {};
6126
6803
  if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value || {};
6127
6804
  let i = 0;
6128
6805
  while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
@@ -6153,10 +6830,10 @@ function nodeMatrix(node, t) {
6153
6830
  return IDENTITY;
6154
6831
  }
6155
6832
  function evalScalar(animated, staticVal, fallback, t) {
6156
- var _a, _b, _c, _d, _e, _f;
6833
+ var _a2, _b, _c, _d, _e, _f;
6157
6834
  if (animated && animated.keyframes && animated.keyframes.length) {
6158
6835
  const kfs = animated.keyframes;
6159
- if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value;
6836
+ if (t <= ((_a2 = kfs[0].time) != null ? _a2 : 0)) return kfs[0].value;
6160
6837
  if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value;
6161
6838
  let i = 0;
6162
6839
  while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
@@ -6169,9 +6846,9 @@ function evalScalar(animated, staticVal, fallback, t) {
6169
6846
  var CONTAINER_TYPES = /* @__PURE__ */ new Set(["svg", "g", "symbol"]);
6170
6847
  var SKIP_TYPES = /* @__PURE__ */ new Set(["defs", "mask", "clipPath", "title"]);
6171
6848
  function buildIdMap2(node, map) {
6172
- var _a;
6849
+ var _a2;
6173
6850
  if (typeof node.id === "string") map.set(node.id, node);
6174
- (_a = node.children) == null ? void 0 : _a.forEach((c) => buildIdMap2(c, map));
6851
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => buildIdMap2(c, map));
6175
6852
  }
6176
6853
  function num(v) {
6177
6854
  return v === void 0 || v === null ? 0 : Number(v);
@@ -6180,7 +6857,7 @@ function round(n) {
6180
6857
  return Math.round(n * 100) / 100 + 0;
6181
6858
  }
6182
6859
  function geomKey(node) {
6183
- var _a;
6860
+ var _a2;
6184
6861
  switch (node.type) {
6185
6862
  case "rect":
6186
6863
  return num(node.width) + "," + num(node.height) + "," + num(node.x) + "," + num(node.y);
@@ -6189,14 +6866,14 @@ function geomKey(node) {
6189
6866
  case "circle":
6190
6867
  return num(node.r) + "," + num(node.cx) + "," + num(node.cy);
6191
6868
  case "path":
6192
- return String((_a = node.d) != null ? _a : "");
6869
+ return String((_a2 = node.d) != null ? _a2 : "");
6193
6870
  default:
6194
6871
  return "";
6195
6872
  }
6196
6873
  }
6197
6874
  function describePrimitive(node, m, t) {
6198
- var _a, _b, _c, _d, _e;
6199
- const fill = (_a = node.fill) != null ? _a : "";
6875
+ var _a2, _b, _c, _d, _e;
6876
+ const fill = (_a2 = node.fill) != null ? _a2 : "";
6200
6877
  const stroke = (_b = node.stroke) != null ? _b : "";
6201
6878
  const sw = (_d = (_c = node["stroke-width"]) != null ? _c : node.strokeWidth) != null ? _d : "";
6202
6879
  const opacity = round(evalScalar((_e = node.animate) == null ? void 0 : _e.opacity, node.opacity, 1, t));
@@ -6205,7 +6882,7 @@ function describePrimitive(node, m, t) {
6205
6882
  return node.type + "|" + geomKey(node) + "|[" + mat + "]|f:" + fill + "|s:" + stroke + "|sw:" + (num(sw) || "") + "|o:" + opacity + "|m:" + masked;
6206
6883
  }
6207
6884
  function flatten(node, parent, t, idMap, out) {
6208
- var _a;
6885
+ var _a2;
6209
6886
  const type = node.type || "";
6210
6887
  if (SKIP_TYPES.has(type)) return;
6211
6888
  const m = mul(parent, nodeMatrix(node, t));
@@ -6218,33 +6895,33 @@ function flatten(node, parent, t, idMap, out) {
6218
6895
  return;
6219
6896
  }
6220
6897
  if (CONTAINER_TYPES.has(type)) {
6221
- (_a = node.children) == null ? void 0 : _a.forEach((c) => flatten(c, m, t, idMap, out));
6898
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => flatten(c, m, t, idMap, out));
6222
6899
  return;
6223
6900
  }
6224
6901
  out.push(describePrimitive(node, m, t));
6225
6902
  }
6226
6903
  function collectSampleTimes(node, into) {
6227
- var _a;
6904
+ var _a2;
6228
6905
  into.add(0);
6229
6906
  const scanAnim = (anim) => {
6230
- var _a2;
6907
+ var _a3;
6231
6908
  if (!anim || typeof anim !== "object") return;
6232
6909
  for (const key of Object.keys(anim)) {
6233
- const kfs = (_a2 = anim[key]) == null ? void 0 : _a2.keyframes;
6910
+ const kfs = (_a3 = anim[key]) == null ? void 0 : _a3.keyframes;
6234
6911
  if (Array.isArray(kfs)) kfs.forEach((kf) => {
6235
- var _a3;
6236
- return into.add((_a3 = kf.time) != null ? _a3 : 0);
6912
+ var _a4;
6913
+ return into.add((_a4 = kf.time) != null ? _a4 : 0);
6237
6914
  });
6238
6915
  }
6239
6916
  };
6240
6917
  scanAnim(node.animate);
6241
6918
  if (node.transform && typeof node.transform === "object" && node.transform.keyframes) {
6242
6919
  node.transform.keyframes.forEach((kf) => {
6243
- var _a2;
6244
- return into.add((_a2 = kf.time) != null ? _a2 : 0);
6920
+ var _a3;
6921
+ return into.add((_a3 = kf.time) != null ? _a3 : 0);
6245
6922
  });
6246
6923
  }
6247
- (_a = node.children) == null ? void 0 : _a.forEach((c) => collectSampleTimes(c, into));
6924
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => collectSampleTimes(c, into));
6248
6925
  }
6249
6926
  function visualModelAt(root, t) {
6250
6927
  const idMap = /* @__PURE__ */ new Map();
@@ -6278,8 +6955,180 @@ function subtractMultiset(a, b) {
6278
6955
  }
6279
6956
  return extra;
6280
6957
  }
6958
+
6959
+ // src/playback/PxAnimatorConfigPatch.ts
6960
+ var FLAT_ONLY_KEYS = [
6961
+ "timelineSource",
6962
+ "scroll",
6963
+ "trigger",
6964
+ "delay",
6965
+ "iterations",
6966
+ "direction",
6967
+ "fill",
6968
+ "resetOnFinish",
6969
+ "duration",
6970
+ "mode",
6971
+ "frameRate"
6972
+ ];
6973
+ var CONTENT_KEYS = ["definitions", "animateById"];
6974
+ var isPlainObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
6975
+ var timelineTypeOf = (t) => isPlainObject(t) && typeof t.type === "string" ? t.type : "time";
6976
+ var isScrollish = (type) => type === "scroll" || type === "view";
6977
+ function mergePlain(base, patch) {
6978
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6979
+ for (const key of Object.keys(patch)) {
6980
+ const value = patch[key];
6981
+ if (value === null) {
6982
+ delete out[key];
6983
+ continue;
6984
+ }
6985
+ if (isPlainObject(value)) {
6986
+ out[key] = mergePlain(out[key], value);
6987
+ continue;
6988
+ }
6989
+ out[key] = value;
6990
+ }
6991
+ return out;
6992
+ }
6993
+ function mergeTimeline(base, patch, warn) {
6994
+ const baseType = timelineTypeOf(base);
6995
+ const patchNamesType = isPlainObject(patch) && typeof patch.type === "string";
6996
+ const patchType = patchNamesType ? String(patch.type) : baseType;
6997
+ let merged;
6998
+ if (patchType !== baseType) {
6999
+ const carried = {};
7000
+ if (isPlainObject(base)) {
7001
+ for (const k of PX_TIMELINE_SHARED_KEYS) {
7002
+ if (base[k] !== void 0) carried[k] = base[k];
7003
+ }
7004
+ }
7005
+ merged = mergePlain(carried, patch);
7006
+ } else {
7007
+ merged = mergePlain(base, patch);
7008
+ }
7009
+ if (isScrollish(patchType)) {
7010
+ for (const k of PX_TIME_ONLY_TIMELINE_KEYS) {
7011
+ if (merged[k] === void 0) continue;
7012
+ warn("animator.timeline." + k + ": no slot on a '" + patchType + "' timeline \u2014 dropped");
7013
+ delete merged[k];
7014
+ }
7015
+ if (merged.iterations === "infinite") {
7016
+ warn("animator.timeline.iterations: 'infinite' cannot map onto a scroll range \u2014 dropped");
7017
+ delete merged.iterations;
7018
+ }
7019
+ }
7020
+ return merged;
7021
+ }
7022
+ function foldTimelineOverride(timeline, shortcuts) {
7023
+ let base;
7024
+ if (typeof timeline === "string") {
7025
+ try {
7026
+ base = JSON.parse(timeline);
7027
+ } catch (e) {
7028
+ console.warn("timeline override: not valid JSON \u2014 ignored", e);
7029
+ base = void 0;
7030
+ }
7031
+ } else {
7032
+ base = timeline != null ? timeline : void 0;
7033
+ }
7034
+ const { duration, delay, iterations, startOn } = shortcuts;
7035
+ if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
7036
+ return base === void 0 ? void 0 : { timeline: base };
7037
+ }
7038
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
7039
+ if (duration !== void 0) out.duration = duration;
7040
+ if (delay !== void 0) out.delay = delay;
7041
+ if (iterations !== void 0) out.iterations = iterations;
7042
+ if (startOn !== void 0) {
7043
+ out.trigger = __spreadProps(__spreadValues({}, out.trigger), { startOn });
7044
+ }
7045
+ return { timeline: out };
7046
+ }
7047
+ function mergeAnimatorConfig(base, patch) {
7048
+ const warnings = [];
7049
+ const warn = (m) => warnings.push(m);
7050
+ if (patch === null) return { config: void 0, warnings };
7051
+ if (!isPlainObject(patch) || Object.keys(patch).length === 0) {
7052
+ return { config: base, warnings };
7053
+ }
7054
+ const flatInBase = isPlainObject(base) ? FLAT_ONLY_KEYS.filter((k) => base[k] !== void 0) : [];
7055
+ if (flatInBase.length) {
7056
+ warn("animator: the base carries the flat runtime spelling (" + flatInBase.join(", ") + "); the patch merges the wire spelling only");
7057
+ }
7058
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
7059
+ for (const key of Object.keys(patch)) {
7060
+ const value = patch[key];
7061
+ if (value === null) {
7062
+ delete out[key];
7063
+ continue;
7064
+ }
7065
+ if (key === "timeline") {
7066
+ out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
7067
+ continue;
7068
+ }
7069
+ if (isPlainObject(value)) {
7070
+ out[key] = mergePlain(out[key], value);
7071
+ continue;
7072
+ }
7073
+ out[key] = value;
7074
+ }
7075
+ return { config: out, warnings };
7076
+ }
7077
+ function applyAnimatorConfig(doc, patch, opts) {
7078
+ var _a2, _b;
7079
+ const reset = !!(opts == null ? void 0 : opts.resetDefaults);
7080
+ if (!doc || (patch === void 0 || !reset && (patch === null || !isPlainObject(patch) || !Object.keys(patch).length))) {
7081
+ return { doc, warnings: [] };
7082
+ }
7083
+ const anyDoc = doc;
7084
+ const atRoot = isPlainObject(anyDoc.animator);
7085
+ const atMeta = !atRoot && isPlainObject((_a2 = anyDoc.meta) == null ? void 0 : _a2.animator);
7086
+ const current = atRoot ? anyDoc.animator : atMeta ? anyDoc.meta.animator : void 0;
7087
+ const warnings = [];
7088
+ if (atRoot && isPlainObject((_b = anyDoc.meta) == null ? void 0 : _b.animator)) {
7089
+ warnings.push("animator: doc.meta.animator is shadowed by doc.animator and was not patched");
7090
+ }
7091
+ let base = current;
7092
+ if (reset) {
7093
+ const kept = {};
7094
+ for (const k of CONTENT_KEYS) {
7095
+ if (isPlainObject(current) && current[k] !== void 0) kept[k] = current[k];
7096
+ }
7097
+ base = kept;
7098
+ }
7099
+ const merged = mergeAnimatorConfig(base, patch != null ? patch : {});
7100
+ warnings.push(...merged.warnings);
7101
+ if (merged.config === current) return { doc, warnings };
7102
+ if (atMeta) {
7103
+ return {
7104
+ doc: __spreadProps(__spreadValues({}, anyDoc), { meta: __spreadProps(__spreadValues({}, anyDoc.meta), { animator: merged.config }) }),
7105
+ warnings
7106
+ };
7107
+ }
7108
+ return { doc: __spreadProps(__spreadValues({}, anyDoc), { animator: merged.config }), warnings };
7109
+ }
7110
+
7111
+ // src/format/PxDocumentDiagnostic.ts
7112
+ var MAX_REPORTED = 6;
7113
+ function diagnoseDocument(doc) {
7114
+ try {
7115
+ return { problems: validateDocument(doc) };
7116
+ } catch (e) {
7117
+ return { problems: [] };
7118
+ }
7119
+ }
7120
+ function reportDocumentDiagnostics(doc, where) {
7121
+ const { problems } = diagnoseDocument(doc);
7122
+ if (!problems.length) return;
7123
+ const shown = problems.slice(0, MAX_REPORTED);
7124
+ const more = problems.length - shown.length;
7125
+ console.warn(
7126
+ 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."
7127
+ );
7128
+ }
6281
7129
  export {
6282
- COLOUR_ATTR_NAMES,
7130
+ BASELINE_PLAYER_VERSION,
7131
+ COLOR_ATTR_NAMES,
6283
7132
  CSS_ONLY_STYLE_PROPS,
6284
7133
  DEFAULT_DURATION_MS,
6285
7134
  DISALLOWED_SVG_TAGS_LOWER,
@@ -6287,116 +7136,183 @@ export {
6287
7136
  LOOP_JUMP_SHIFT_MS,
6288
7137
  MISSING_GLYPH_CLASS_NAME,
6289
7138
  PCT_BASED_ATTR_NAMES,
7139
+ PLAYER_WIRE_STEPS,
7140
+ PLAYER_WIRE_VERSION,
6290
7141
  PX_ANIM_ATTR_NAME,
6291
7142
  PX_ANIM_SRC_ATTR_NAME,
7143
+ PX_PLAYER_SCHEMA_VERSION,
7144
+ PX_RATE_REJECTED,
6292
7145
  PX_TRANSFORM_PART_KEYS,
7146
+ PX_TRIGGER_DEFAULTS,
7147
+ PX_UNKNOWN_KEY_ERROR,
7148
+ PxAlongPathMode,
6293
7149
  PxAnimatedSvgDocumentSchema,
6294
7150
  PxAnimationDefinitionSchema,
6295
7151
  PxAnimatorConfigSchema,
6296
- PxAnimatorEngine,
6297
- PxAnimatorMode,
6298
7152
  PxAttrValueSchema,
6299
7153
  PxBezierPathSchema,
6300
7154
  PxBindingSchema,
7155
+ PxClipPathEffectSchema,
6301
7156
  PxCloneEffectSchema,
7157
+ PxCloneWithout,
7158
+ PxControlMode,
6302
7159
  PxDefsSchema,
7160
+ PxDiagnosticKind,
6303
7161
  PxEasingOrRefSchema,
6304
7162
  PxEffectsSchema,
6305
7163
  PxElementAnimationSchema,
6306
7164
  PxFillGradientEffectSchema,
7165
+ PxFillMode,
7166
+ PxFinishAction,
6307
7167
  PxGradientSpreadMethod,
6308
7168
  PxGradientStopSchema,
6309
7169
  PxGradientType,
6310
- PxGradientUnits,
6311
7170
  PxKeyframeSchema,
6312
7171
  PxKeyframeValueSchema,
6313
- PxLoopExtend,
7172
+ PxLengthAdjust,
7173
+ PxLoopDirection,
7174
+ PxLoopRepeatAt,
6314
7175
  PxLoopSchema,
7176
+ PxMaskType,
6315
7177
  PxMaskedByEffectSchema,
6316
7178
  PxNodeBase,
6317
7179
  PxNodeSchema,
7180
+ PxOutAction,
7181
+ PxPathOverflow,
7182
+ PxPinAlign,
7183
+ PxPlaybackDirection,
6318
7184
  PxPropertyAnimationSchema,
6319
7185
  PxRepeaterEffectSchema,
6320
7186
  PxRetimeEffectSchema,
7187
+ PxScrollAxis,
7188
+ PxScrollKind,
7189
+ PxScrollPhase,
6321
7190
  PxScrollRangePointSchema,
6322
7191
  PxScrollRangeSchema,
6323
7192
  PxScrollSchema,
7193
+ PxScrollSource,
7194
+ PxStartOn,
6324
7195
  PxStrokeGradientEffectSchema,
6325
7196
  PxStrokeTrimEffectSchema,
6326
7197
  PxStrokeTrimSubPaths,
6327
7198
  PxSvgNodeExtra,
6328
7199
  PxTextEffectSchema,
6329
7200
  PxTextPathEffectSchema,
7201
+ PxTextPathMethod,
7202
+ PxTextPathSpacing,
7203
+ PxTimelineEngine,
7204
+ PxTimelineEngineExtra,
6330
7205
  PxTimelinePinSchema,
6331
7206
  PxTimelineSchema,
6332
7207
  PxTransformByEffectSchema,
6333
7208
  PxTransformPartsSchema,
6334
7209
  PxTransformValueSchema,
6335
7210
  PxTriggerSchema,
7211
+ PxUnits,
6336
7212
  STYLE_ATTR_NAMES,
6337
- TEXT_ATTR,
6338
7213
  TEXT_CONTENT_ATTR,
6339
7214
  TRANSFORM_FN_NAMES,
7215
+ WIRE_VERSION_KEY,
7216
+ WireStepKind,
7217
+ WireVersionRelation,
7218
+ applyAnimatorConfig,
6340
7219
  applyPlayerEffects,
7220
+ applyWireSteps,
7221
+ applyWireStepsDown,
6341
7222
  bezierToSvgPath,
6342
7223
  calcAnimationValues,
6343
7224
  camelCaseToKebabWordIfNeeded,
6344
7225
  clamp,
7226
+ clampSeekMs,
6345
7227
  collectSampleTimes,
7228
+ compareWireVersion,
6346
7229
  composeTransformParts,
7230
+ controlModeTakesOverTrigger,
7231
+ convertPlayerDocument,
6347
7232
  createBasicFrameLoopAnimator,
7233
+ createDiagnostics,
6348
7234
  createPathSampler,
7235
+ createRunClock,
6349
7236
  cubicBezier,
6350
7237
  deepClone,
6351
7238
  describeSchema,
7239
+ diagnoseDocument,
7240
+ diffFieldUniverse,
6352
7241
  diffInEffect,
7242
+ downgradePlayerDocument,
6353
7243
  evaluateMotionPathSegment,
6354
7244
  extendedPathForBrowser,
6355
7245
  flattenAnimatorTimeline,
7246
+ foldTimelineOverride,
7247
+ formatWireVersion,
6356
7248
  generateNewIds,
6357
7249
  generateUniqueId,
6358
7250
  getAnimatorConfig,
6359
7251
  getBindings,
6360
7252
  getChildren,
6361
7253
  getDefs,
6362
- getNormalisedBindings,
7254
+ getNormalizedBindings,
6363
7255
  getNormalizedProps,
6364
7256
  interpolateBeziers,
6365
7257
  interpolateValue,
7258
+ isNativeForced,
6366
7259
  isPxElementFileFormat,
6367
7260
  isPxElementFileFormatDeep,
6368
7261
  isScrollTimeline,
7262
+ isValidPlaybackRate,
6369
7263
  jsonElementFactory,
6370
7264
  kebabToCamelCaseWord,
7265
+ kfEasing,
7266
+ kfTangentIn,
7267
+ kfTangentOut,
7268
+ kfTime,
7269
+ kfValue,
6371
7270
  layoutGlyphTextChars,
6372
- materialiseAllInTree,
6373
- materialiseAnimatedUseInstances,
6374
- materialiseGlyphText,
6375
- materialiseGlyphTextAlongPath,
6376
- materialiseGlyphTextHorizontal,
6377
- materialiseInternalLoopsInPropAnim,
6378
- materialiseInternalLoopsInTree,
6379
- materialiseMotionPathInPropAnim,
6380
- materialiseMotionPathsInTree,
7271
+ materializeAllInTree,
7272
+ materializeAnimatedUseInstances,
7273
+ materializeGlyphText,
7274
+ materializeGlyphTextAlongPath,
7275
+ materializeGlyphTextHorizontal,
7276
+ materializeInternalLoopsInPropAnim,
7277
+ materializeInternalLoopsInTree,
7278
+ materializeMotionPathInPropAnim,
7279
+ materializeMotionPathsInTree,
7280
+ mayUseNativeScrollTimeline,
7281
+ mergeAnimatorConfig,
6381
7282
  mergeStaticTransformIntoAnimDef,
6382
7283
  nestAnimatorTimeline,
6383
7284
  parseTransformParts,
7285
+ parseWireVersion,
7286
+ planSchemaRelease,
7287
+ progressSpanMs,
7288
+ progressToTimeMs,
6384
7289
  propAnimIsMotionPath,
6385
7290
  px,
7291
+ readWireVersion,
7292
+ releaseLogProblems,
7293
+ reportDocumentDiagnostics,
7294
+ resolveControlMode,
6386
7295
  resolveStyle,
7296
+ resolveTimelineEngine,
7297
+ resolveTrigger,
6387
7298
  reverseEasing,
6388
- sanitiseAttributeValue,
7299
+ sanitizeAttributeValue,
7300
+ schemaFieldUniverse,
6389
7301
  schemaKeys,
6390
7302
  scrollOffsetProgress,
6391
7303
  scrollPhaseInterval,
6392
7304
  scrollResolveAxis,
6393
7305
  scrollTotalDurationMs,
6394
7306
  scrollViewProgress,
7307
+ seekCeilingMs,
6395
7308
  shiftAnimatable,
6396
7309
  splitEasing,
6397
7310
  subdivideCubicBezier,
7311
+ timeToProgress,
6398
7312
  toRGBA,
7313
+ validateDocument,
6399
7314
  validateNodeEffects,
7315
+ versionAdvice,
6400
7316
  visualModelAt
6401
7317
  };
6402
7318
  //# sourceMappingURL=index.js.map