@pixodesk/svg-animator-core 1.0.34 → 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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]] : []];
@@ -265,9 +265,9 @@ var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color",
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 = "";
@@ -658,10 +659,10 @@ var Union = class extends Base {
658
659
  return this._default;
659
660
  }
660
661
  isValid(raw, ctx, path) {
661
- var _a;
662
+ var _a2;
662
663
  const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
663
664
  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));
665
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
665
666
  return false;
666
667
  }
667
668
  _canSanitize(raw) {
@@ -670,6 +671,7 @@ var Union = class extends Base {
670
671
  };
671
672
  var DiscriminatedUnion = class extends Base {
672
673
  constructor(_key, _schemas, defaultVal) {
674
+ var _a2;
673
675
  super();
674
676
  this._key = _key;
675
677
  this._schemas = _schemas;
@@ -679,18 +681,21 @@ var DiscriminatedUnion = class extends Base {
679
681
  this._map = /* @__PURE__ */ new Map();
680
682
  for (const s of _schemas) {
681
683
  const keySchema = s._shape[_key];
682
- if (keySchema) this._map.set(keySchema._default, s);
684
+ if (!keySchema) continue;
685
+ const literal = (_a2 = keySchema.inner) != null ? _a2 : keySchema;
686
+ this._map.set(literal._default, s);
687
+ if (keySchema.inner) this._absentMember = s;
683
688
  }
684
689
  }
685
690
  _findSchema(raw) {
686
691
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
687
692
  const val = raw[this._key];
688
- if (val === void 0 || val === null) return void 0;
693
+ if (val === void 0 || val === null) return this._absentMember;
689
694
  return this._map.get(val);
690
695
  }
691
696
  sanitize(raw) {
692
- var _a;
693
- return ((_a = this._findSchema(raw)) != null ? _a : this._schemas[0]).sanitize(raw);
697
+ var _a2;
698
+ return ((_a2 = this._findSchema(raw)) != null ? _a2 : this._schemas[0]).sanitize(raw);
694
699
  }
695
700
  isValid(raw, ctx, path) {
696
701
  const schema = this._findSchema(raw);
@@ -719,7 +724,8 @@ var Obj = class extends Base {
719
724
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
720
725
  const out = {};
721
726
  for (const key of Object.keys(this._shape)) {
722
- out[key] = this._shape[key].sanitize(src[key]);
727
+ const v = this._shape[key].sanitize(src[key]);
728
+ if (v !== void 0) out[key] = v;
723
729
  }
724
730
  return out;
725
731
  }
@@ -741,7 +747,7 @@ var Obj = class extends Base {
741
747
  if (key in this._shape) continue;
742
748
  if (obj[key] === void 0) continue;
743
749
  p.push(key);
744
- ctx.errors.push(pathStr(p) + ": unexpected extra key");
750
+ ctx.errors.push(pathStr(p) + ": " + PX_UNKNOWN_KEY_ERROR);
745
751
  p.pop();
746
752
  ok = false;
747
753
  }
@@ -765,7 +771,8 @@ var OpenObj = class extends Base {
765
771
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
766
772
  const out = __spreadValues({}, src);
767
773
  for (const key of Object.keys(this._shape)) {
768
- out[key] = this._shape[key].sanitize(src[key]);
774
+ const v = this._shape[key].sanitize(src[key]);
775
+ if (v !== void 0) out[key] = v;
769
776
  }
770
777
  if (this._openSchema) {
771
778
  for (const key of Object.keys(src)) {
@@ -907,8 +914,8 @@ var Lazy = class extends Base {
907
914
  this.resolved = null;
908
915
  }
909
916
  get schema() {
910
- var _a;
911
- return (_a = this.resolved) != null ? _a : this.resolved = this.fn();
917
+ var _a2;
918
+ return (_a2 = this.resolved) != null ? _a2 : this.resolved = this.fn();
912
919
  }
913
920
  sanitize(raw) {
914
921
  return this.schema.sanitize(raw);
@@ -960,7 +967,7 @@ function schemaKeys(schema) {
960
967
  );
961
968
  }
962
969
  function describeSchema(schema) {
963
- var _a;
970
+ var _a2;
964
971
  const s = schema;
965
972
  switch (s._kind) {
966
973
  case "union":
@@ -975,7 +982,7 @@ function describeSchema(schema) {
975
982
  if ("_shape" in s) return { kind: "shape", shape: s._shape, openValue: s._openSchema };
976
983
  if ("item" in s) return { kind: "array", item: s.item };
977
984
  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() };
985
+ if ("fn" in s) return { kind: "lazy", resolved: (_a2 = s.resolved) != null ? _a2 : s.resolved = s.fn() };
979
986
  return { kind: "leaf" };
980
987
  }
981
988
  var px = {
@@ -1030,25 +1037,343 @@ var px = {
1030
1037
  lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
1031
1038
  };
1032
1039
 
1033
- // src/PxAnimatorConstants.ts
1040
+ // src/version/PxSchemaVersion.ts
1041
+ var PX_PLAYER_SCHEMA_VERSION = "1.1";
1042
+
1043
+ // src/version/PxWireVersion.ts
1044
+ var WIRE_VERSION_KEY = "version";
1045
+ var ANIMATOR_KEY = "animator";
1046
+ var META_KEY = "meta";
1047
+ var WireVersionRelation = /* @__PURE__ */ ((WireVersionRelation2) => {
1048
+ WireVersionRelation2["unstamped"] = "unstamped";
1049
+ WireVersionRelation2["same"] = "same";
1050
+ WireVersionRelation2["older"] = "older";
1051
+ WireVersionRelation2["newer"] = "newer";
1052
+ WireVersionRelation2["otherGeneration"] = "otherGeneration";
1053
+ return WireVersionRelation2;
1054
+ })(WireVersionRelation || {});
1055
+ var VERSION_RE = /^(\d+)\.(\d+)(?:\.(\d+))?$/;
1056
+ function parseWireVersion(raw) {
1057
+ if (typeof raw !== "string") return void 0;
1058
+ const m = VERSION_RE.exec(raw.trim());
1059
+ if (!m) return void 0;
1060
+ return { a: Number(m[1]), b: Number(m[2]), c: m[3] === void 0 ? 0 : Number(m[3]) };
1061
+ }
1062
+ function formatWireVersion(v) {
1063
+ return v.a + "." + v.b + "." + v.c;
1064
+ }
1065
+ var _a;
1066
+ var PLAYER_WIRE_VERSION = (_a = parseWireVersion(PX_PLAYER_SCHEMA_VERSION)) != null ? _a : { a: 1, b: 1, c: 0 };
1067
+ function getAnimatorBlock(doc) {
1068
+ if (!doc || typeof doc !== "object") return void 0;
1069
+ const atRoot = readObjectProp(doc, ANIMATOR_KEY);
1070
+ if (atRoot) return atRoot;
1071
+ const meta = readObjectProp(doc, META_KEY);
1072
+ return meta ? readObjectProp(meta, ANIMATOR_KEY) : void 0;
1073
+ }
1074
+ function readObjectProp(obj, key) {
1075
+ const value = obj[key];
1076
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1077
+ }
1078
+ function readWireVersion(doc) {
1079
+ const animator = getAnimatorBlock(doc);
1080
+ return animator ? parseWireVersion(animator[WIRE_VERSION_KEY]) : void 0;
1081
+ }
1082
+ function compareWireVersion(file, mine, readerReadsEditorPart) {
1083
+ if (!file) return "unstamped" /* unstamped */;
1084
+ if (file.a !== mine.a) return "otherGeneration" /* otherGeneration */;
1085
+ if (file.b !== mine.b) return file.b > mine.b ? "newer" /* newer */ : "older" /* older */;
1086
+ if (!readerReadsEditorPart || file.c === mine.c) return "same" /* same */;
1087
+ return file.c > mine.c ? "newer" /* newer */ : "older" /* older */;
1088
+ }
1089
+ function versionAdvice(relation, file, mine, isPlayer) {
1090
+ if (!file) return void 0;
1091
+ const target = isPlayer ? "player" : "editor";
1092
+ const gap = "written for schema " + formatWireVersion(file) + ", this " + target + " reads " + formatWireVersion(mine);
1093
+ switch (relation) {
1094
+ case "newer" /* newer */:
1095
+ return "This file is " + gap + ". Update the " + target + " to open it fully.";
1096
+ case "older" /* older */:
1097
+ return "This file is " + gap + ". Saving it from this " + target + " rewrites it in the current format.";
1098
+ case "otherGeneration" /* otherGeneration */:
1099
+ 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.";
1100
+ default:
1101
+ return void 0;
1102
+ }
1103
+ }
1104
+ var WireStepKind = /* @__PURE__ */ ((WireStepKind2) => {
1105
+ WireStepKind2["additive"] = "additive";
1106
+ WireStepKind2["converted"] = "converted";
1107
+ return WireStepKind2;
1108
+ })(WireStepKind || {});
1109
+ var BASELINE_PLAYER_VERSION = "1.1";
1110
+ var PLAYER_WIRE_STEPS = [];
1111
+ function applyWireSteps(doc, cfg) {
1112
+ const from = readWireVersion(doc);
1113
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1114
+ if (!from || relation !== "older" /* older */) {
1115
+ return {
1116
+ doc,
1117
+ from,
1118
+ relation,
1119
+ applied: [],
1120
+ advice: versionAdvice(relation, from, cfg.target, !cfg.readerReadsEditorPart)
1121
+ };
1122
+ }
1123
+ const due = [];
1124
+ for (const step of cfg.steps) {
1125
+ const stepTo = parseWireVersion(step.to);
1126
+ if (!stepTo) continue;
1127
+ if (compareWireVersion(from, stepTo, cfg.readerReadsEditorPart) !== "older" /* older */) continue;
1128
+ if (!step.up) continue;
1129
+ due.push(step);
1130
+ }
1131
+ if (!due.length || !doc || typeof doc !== "object") return { doc, from, relation, applied: [] };
1132
+ const target = clonePlain(doc);
1133
+ const applied = [];
1134
+ for (const step of due) {
1135
+ try {
1136
+ step.up(target);
1137
+ applied.push(step);
1138
+ } catch (e) {
1139
+ break;
1140
+ }
1141
+ }
1142
+ if (!applied.length) return { doc, from, relation, applied: [] };
1143
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1144
+ return { doc: target, from, relation, applied };
1145
+ }
1146
+ function convertPlayerDocument(doc) {
1147
+ return applyWireSteps(doc, {
1148
+ steps: PLAYER_WIRE_STEPS,
1149
+ target: PLAYER_WIRE_VERSION,
1150
+ readerReadsEditorPart: false
1151
+ });
1152
+ }
1153
+ function clonePlain(value) {
1154
+ const structured = globalThis.structuredClone;
1155
+ return structured ? structured(value) : JSON.parse(JSON.stringify(value));
1156
+ }
1157
+ function stampVersion(doc, target, readerReadsEditorPart) {
1158
+ const animator = getAnimatorBlock(doc);
1159
+ if (!animator) return;
1160
+ const previous = parseWireVersion(animator[WIRE_VERSION_KEY]);
1161
+ animator[WIRE_VERSION_KEY] = formatWireVersion({
1162
+ a: target.a,
1163
+ b: target.b,
1164
+ c: readerReadsEditorPart ? target.c : previous ? previous.c : 0
1165
+ });
1166
+ }
1167
+ function applyWireStepsDown(doc, cfg) {
1168
+ const from = readWireVersion(doc);
1169
+ if (!from) {
1170
+ return { ok: false, blocking: [], reason: "The document carries no version, so there is nothing to convert down from." };
1171
+ }
1172
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1173
+ if (relation === "otherGeneration" /* otherGeneration */) {
1174
+ return {
1175
+ ok: false,
1176
+ blocking: [],
1177
+ reason: "Schema " + formatWireVersion(from) + " and " + formatWireVersion(cfg.target) + " are different generations; no conversion bridges them."
1178
+ };
1179
+ }
1180
+ if (relation !== "newer" /* newer */) return { ok: true, doc, applied: [] };
1181
+ const toUndo = [];
1182
+ for (const step of cfg.steps) {
1183
+ const stepTo = parseWireVersion(step.to);
1184
+ if (!stepTo) continue;
1185
+ if (compareWireVersion(stepTo, cfg.target, cfg.readerReadsEditorPart) !== "newer" /* newer */) continue;
1186
+ if (compareWireVersion(stepTo, from, cfg.readerReadsEditorPart) === "newer" /* newer */) continue;
1187
+ toUndo.push(step);
1188
+ }
1189
+ toUndo.reverse();
1190
+ const blocking = toUndo.filter((s) => s.kind === "converted" /* converted */ && !s.down);
1191
+ if (blocking.length) {
1192
+ return {
1193
+ ok: false,
1194
+ blocking,
1195
+ reason: "Cannot convert down to " + formatWireVersion(cfg.target) + ": " + blocking.map((s) => s.from + " \u2192 " + s.to + " (" + s.reason + ")").join("; ") + " cannot be undone."
1196
+ };
1197
+ }
1198
+ const target = clonePlain(doc);
1199
+ const applied = [];
1200
+ for (const step of toUndo) {
1201
+ if (!step.down) continue;
1202
+ try {
1203
+ step.down(target);
1204
+ applied.push(step);
1205
+ } catch (e) {
1206
+ return {
1207
+ ok: false,
1208
+ blocking: [step],
1209
+ reason: "Undoing " + step.from + " \u2192 " + step.to + " failed: " + String(e)
1210
+ };
1211
+ }
1212
+ }
1213
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1214
+ return { ok: true, doc: target, applied };
1215
+ }
1216
+ function downgradePlayerDocument(doc, target) {
1217
+ return applyWireStepsDown(doc, { steps: PLAYER_WIRE_STEPS, target, readerReadsEditorPart: false });
1218
+ }
1219
+
1220
+ // src/version/PxSchemaFieldUniverse.ts
1221
+ function schemaFieldUniverse(root) {
1222
+ const fields = /* @__PURE__ */ new Set();
1223
+ const enumerated = /* @__PURE__ */ new Set();
1224
+ const queue = [{ schema: root, path: "" }];
1225
+ while (queue.length) {
1226
+ const { schema, path } = queue.shift();
1227
+ const d = describeSchema(schema);
1228
+ switch (d.kind) {
1229
+ case "shape": {
1230
+ if (enumerated.has(schema)) break;
1231
+ enumerated.add(schema);
1232
+ for (const key of Object.keys(d.shape)) {
1233
+ const id = path ? path + "." + key : key;
1234
+ fields.add(id);
1235
+ queue.push({ schema: d.shape[key], path: id });
1236
+ }
1237
+ if (d.openValue) queue.push({ schema: d.openValue, path: path + "{*}" });
1238
+ break;
1239
+ }
1240
+ case "optional":
1241
+ queue.push({ schema: d.inner, path });
1242
+ break;
1243
+ case "array":
1244
+ queue.push({ schema: d.item, path: path + "[]" });
1245
+ break;
1246
+ case "lazy":
1247
+ queue.push({ schema: d.resolved, path });
1248
+ break;
1249
+ case "record":
1250
+ queue.push({ schema: d.value, path: path + "{*}" });
1251
+ break;
1252
+ case "union":
1253
+ d.members.forEach((member, i) => queue.push({ schema: member, path: path + "|" + i }));
1254
+ break;
1255
+ case "discriminatedUnion":
1256
+ for (const member of d.members) queue.push({ schema: member, path: path + "|" + discriminantOf(member, d.key) });
1257
+ break;
1258
+ default:
1259
+ break;
1260
+ }
1261
+ }
1262
+ return [...fields].sort();
1263
+ }
1264
+ function discriminantOf(member, key) {
1265
+ const d = describeSchema(member);
1266
+ if (d.kind !== "shape") return "?";
1267
+ const keySchema = d.shape[key];
1268
+ if (keySchema === void 0) return "?";
1269
+ const kd = describeSchema(keySchema);
1270
+ return String((kd.kind === "optional" ? kd.inner : keySchema)._default);
1271
+ }
1272
+
1273
+ // src/version/PxSchemaRelease.ts
1274
+ function diffFieldUniverse(previous, current) {
1275
+ const prev = new Set(previous);
1276
+ const cur = new Set(current);
1277
+ return {
1278
+ added: current.filter((k) => !prev.has(k)).sort(),
1279
+ removed: previous.filter((k) => !cur.has(k)).sort()
1280
+ };
1281
+ }
1282
+ function planSchemaRelease(p) {
1283
+ const changed = p.added.length > 0 || p.removed.length > 0;
1284
+ const last = parseWireVersion(p.lastReleased);
1285
+ const declared = parseWireVersion(p.declared);
1286
+ if (!last || !declared) return { changed, refuse: "Unparseable version: " + p.lastReleased + " / " + p.declared + "." };
1287
+ const requiredVersion = last.a + "." + (last.b + 1);
1288
+ if (!changed) {
1289
+ if (declared.b === last.b && declared.a === last.a) return { changed };
1290
+ const step2 = p.steps.find((s) => s.to === p.declared);
1291
+ return step2 ? { changed, requiredVersion: p.declared } : { changed, refuse: "The version moved to " + p.declared + " with no key change and no step explaining it." };
1292
+ }
1293
+ const requiredKind = p.removed.length ? "converted" /* converted */ : "additive" /* additive */;
1294
+ const summary = p.added.length + " key(s) added, " + p.removed.length + " removed";
1295
+ if (declared.a !== last.a || declared.b !== last.b + 1) {
1296
+ return {
1297
+ changed,
1298
+ requiredKind,
1299
+ requiredVersion,
1300
+ 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."
1301
+ };
1302
+ }
1303
+ const step = p.steps.find((s) => s.to === p.declared);
1304
+ if (!step) {
1305
+ return { changed, requiredKind, requiredVersion, refuse: "No PLAYER_WIRE_STEPS entry reaches " + p.declared + "." };
1306
+ }
1307
+ if (requiredKind === "converted" /* converted */ && step.kind !== "converted" /* converted */) {
1308
+ return {
1309
+ changed,
1310
+ requiredKind,
1311
+ requiredVersion,
1312
+ refuse: "Keys were REMOVED (" + p.removed.join(", ") + "), which is never additive \u2014 the " + p.declared + " step must be `converted`, with an up()."
1313
+ };
1314
+ }
1315
+ return { changed, requiredKind, requiredVersion };
1316
+ }
1317
+ function releaseLogProblems(releases, steps, declared, baseline) {
1318
+ const problems = [];
1319
+ if (!releases.length) return ["The release log is empty."];
1320
+ if (!releases[0].baseline || releases[0].version !== baseline) {
1321
+ problems.push("The first release must be the baseline " + baseline + ".");
1322
+ }
1323
+ for (let i = 1; i < releases.length; i++) {
1324
+ const prev = parseWireVersion(releases[i - 1].version);
1325
+ const cur = parseWireVersion(releases[i].version);
1326
+ if (!prev || !cur || cur.a !== prev.a || cur.b !== prev.b + 1) {
1327
+ problems.push("Release " + releases[i].version + " does not follow " + releases[i - 1].version + " by one `b` step.");
1328
+ }
1329
+ if (releases[i].date < releases[i - 1].date) problems.push("Release " + releases[i].version + " is dated before its predecessor.");
1330
+ const step = steps.find((s) => s.to === releases[i].version);
1331
+ if (!step) problems.push("Release " + releases[i].version + " has no PLAYER_WIRE_STEPS entry.");
1332
+ else if (releases[i].removed.length && step.kind !== "converted" /* converted */) {
1333
+ problems.push("Release " + releases[i].version + " removed keys, but its step is not `converted`.");
1334
+ }
1335
+ }
1336
+ const latest = releases[releases.length - 1].version;
1337
+ if (latest !== declared) {
1338
+ 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).");
1339
+ }
1340
+ return problems;
1341
+ }
1342
+
1343
+ // src/format/PxAnimatorConstants.ts
1034
1344
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1035
1345
  var PX_ANIM_ATTR_NAME = "_px_animator";
1036
- var PxAnimatorMode = {
1037
- auto: "auto",
1038
- waapi: "waapi",
1039
- frames: "frames"
1346
+ var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
1347
+ var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
1348
+ var PxTimelineEngine = {
1349
+ native: "native",
1350
+ js: "js"
1040
1351
  };
1041
- var PxAnimatorEngine = {
1042
- waapi: PxAnimatorMode.waapi,
1043
- frames: PxAnimatorMode.frames
1352
+ var PxTimelineEngineExtra = __spreadProps(__spreadValues({}, PxTimelineEngine), {
1353
+ auto: "auto"
1354
+ });
1355
+ function resolveTimelineEngine(engine) {
1356
+ return engine === PxTimelineEngineExtra.js ? PxTimelineEngine.js : PxTimelineEngine.native;
1357
+ }
1358
+ function isNativeForced(engine) {
1359
+ return engine === PxTimelineEngineExtra.native;
1360
+ }
1361
+ function mayUseNativeScrollTimeline(engine) {
1362
+ return engine !== PxTimelineEngineExtra.js;
1363
+ }
1364
+ var PxLoopRepeatAt = {
1365
+ /** Segment from the START; the repetition runs BEFORE the first keyframe
1366
+ * (intro loops that play until the main timeline begins). */
1367
+ start: "start",
1368
+ /** DEFAULT — segment from the END; the repetition runs AFTER the last keyframe
1369
+ * (idle/outro loops that continue once the main timeline has finished). */
1370
+ end: "end"
1044
1371
  };
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"
1372
+ var PxLoopDirection = {
1373
+ /** DEFAULT — cycle: every repetition replays the segment the same way round. */
1374
+ normal: "normal",
1375
+ /** Ping-pong: repetitions alternate forward / backward. */
1376
+ alternate: "alternate"
1052
1377
  };
1053
1378
  var PxMaskType = {
1054
1379
  luminance: "luminance",
@@ -1058,8 +1383,9 @@ var PxUnits = {
1058
1383
  userSpaceOnUse: "userSpaceOnUse",
1059
1384
  objectBoundingBox: "objectBoundingBox"
1060
1385
  };
1061
- var PxCloneType = {
1062
- content: "content"
1386
+ var PxCloneWithout = {
1387
+ translate: "translate"
1388
+ // transform: 'transform', // future: drop rotate/scale too (content only)
1063
1389
  };
1064
1390
  var PxPathOverflow = {
1065
1391
  clip: "clip",
@@ -1083,6 +1409,9 @@ var PxStrokeTrimSubPaths = {
1083
1409
  };
1084
1410
  var TEXT_ATTR = "text";
1085
1411
  var TEXT_CONTENT_ATTR = "textContent";
1412
+ var CLASS_ATTR = "class";
1413
+ var TRANSFORM_ATTR = "transform";
1414
+ var OFFSET_DISTANCE_ATTR = "offsetDistance";
1086
1415
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1087
1416
  "type",
1088
1417
  "children",
@@ -1093,7 +1422,18 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1093
1422
  TEXT_ATTR,
1094
1423
  TEXT_CONTENT_ATTR
1095
1424
  ]);
1096
- var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
1425
+ var TRANSFORM_PART = {
1426
+ translate: "translate",
1427
+ rotate: "rotate",
1428
+ scale: "scale",
1429
+ origin: "origin"
1430
+ };
1431
+ var PX_TRANSFORM_PART_KEYS = [
1432
+ TRANSFORM_PART.translate,
1433
+ TRANSFORM_PART.rotate,
1434
+ TRANSFORM_PART.scale,
1435
+ TRANSFORM_PART.origin
1436
+ ];
1097
1437
  var PxGradientUnits = {
1098
1438
  userSpaceOnUse: "userSpaceOnUse",
1099
1439
  objectBoundingBox: "objectBoundingBox"
@@ -1111,11 +1451,11 @@ function isPxElementFileFormat(fileJson) {
1111
1451
  if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
1112
1452
  return false;
1113
1453
  }
1114
- return fileJson["type"] === "svg";
1454
+ return fileJson.type === "svg";
1115
1455
  }
1116
1456
  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);
1457
+ var _a2;
1458
+ const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
1119
1459
  return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1120
1460
  }
1121
1461
  var flattenMemo = /* @__PURE__ */ new WeakMap();
@@ -1124,14 +1464,15 @@ function flattenAnimatorTimeline(cfg) {
1124
1464
  if (timeline === void 0 || timeline === null || typeof timeline !== "object") return cfg;
1125
1465
  const memoised = flattenMemo.get(cfg);
1126
1466
  if (memoised) return memoised;
1127
- const _a = cfg, { timeline: _dropped } = _a, flat = __objRest(_a, ["timeline"]);
1467
+ const _a2 = cfg, { timeline: _dropped } = _a2, flat = __objRest(_a2, ["timeline"]);
1468
+ if (timeline.engine !== void 0) flat.engine = timeline.engine;
1469
+ if (timeline.frameRate !== void 0) flat.frameRate = timeline.frameRate;
1128
1470
  if (timeline.type === "scroll" || timeline.type === "view") {
1129
1471
  flat.timelineSource = "scroll";
1130
1472
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
1131
1473
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1132
1474
  const scroll = __spreadValues({}, flat.scroll || {});
1133
1475
  scroll.kind = timeline.type;
1134
- if (timeline.engine !== void 0) scroll.driver = timeline.engine;
1135
1476
  if (timeline.axis !== void 0) scroll.axis = timeline.axis;
1136
1477
  if (timeline.source !== void 0) scroll.source = timeline.source;
1137
1478
  if (timeline.subject !== void 0) scroll.subject = timeline.subject;
@@ -1149,21 +1490,24 @@ function flattenAnimatorTimeline(cfg) {
1149
1490
  } else {
1150
1491
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
1151
1492
  if (timeline.trigger !== void 0) {
1152
- const _b = timeline.trigger, { onFinish } = _b, restTrigger = __objRest(_b, ["onFinish"]);
1493
+ const _b = timeline.trigger, { finishAction } = _b, restTrigger = __objRest(_b, ["finishAction"]);
1153
1494
  if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
1154
- if (onFinish !== void 0) flat.resetOnFinish = onFinish === "reset";
1495
+ if (finishAction !== void 0) flat.resetOnFinish = finishAction === "reset";
1155
1496
  }
1156
1497
  if (timeline.delay !== void 0) flat.delay = timeline.delay;
1157
1498
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1158
1499
  if (timeline.direction !== void 0) flat.direction = timeline.direction;
1159
- if (timeline.fill !== void 0) flat.fill = timeline.fill;
1500
+ if (timeline.fillMode !== void 0) flat.fill = timeline.fillMode;
1160
1501
  }
1161
1502
  flattenMemo.set(cfg, flat);
1162
1503
  return flat;
1163
1504
  }
1505
+ function scrollKindOrDefault(kind) {
1506
+ return kind === "scroll" ? "scroll" : "view";
1507
+ }
1164
1508
  function nestAnimatorTimeline(cfg) {
1165
1509
  if (!cfg || cfg.timeline !== void 0) return cfg;
1166
- const _a = cfg, {
1510
+ const _a2 = cfg, {
1167
1511
  timelineSource,
1168
1512
  scroll,
1169
1513
  trigger,
@@ -1172,8 +1516,10 @@ function nestAnimatorTimeline(cfg) {
1172
1516
  direction,
1173
1517
  fill,
1174
1518
  resetOnFinish,
1175
- duration
1176
- } = _a, shared = __objRest(_a, [
1519
+ duration,
1520
+ engine,
1521
+ frameRate
1522
+ } = _a2, shared = __objRest(_a2, [
1177
1523
  "timelineSource",
1178
1524
  "scroll",
1179
1525
  "trigger",
@@ -1182,14 +1528,17 @@ function nestAnimatorTimeline(cfg) {
1182
1528
  "direction",
1183
1529
  "fill",
1184
1530
  "resetOnFinish",
1185
- "duration"
1531
+ "duration",
1532
+ "engine",
1533
+ "frameRate"
1186
1534
  ]);
1187
1535
  if (timelineSource === "scroll") {
1188
- const timeline2 = { type: (scroll == null ? void 0 : scroll.kind) === "view" ? "view" : "scroll" };
1536
+ const timeline2 = { type: scrollKindOrDefault(scroll == null ? void 0 : scroll.kind) };
1537
+ if (engine !== void 0) timeline2.engine = engine;
1538
+ if (frameRate !== void 0) timeline2.frameRate = frameRate;
1189
1539
  if (duration !== void 0) timeline2.duration = duration;
1190
1540
  if (typeof iterations === "number") timeline2.iterations = iterations;
1191
1541
  if (scroll) {
1192
- if (scroll.driver !== void 0) timeline2.engine = scroll.driver;
1193
1542
  if (scroll.axis !== void 0) timeline2.axis = scroll.axis;
1194
1543
  if (scroll.source !== void 0) timeline2.source = scroll.source;
1195
1544
  if (scroll.subject !== void 0) timeline2.subject = scroll.subject;
@@ -1204,28 +1553,30 @@ function nestAnimatorTimeline(cfg) {
1204
1553
  }
1205
1554
  return __spreadProps(__spreadValues({}, shared), { timeline: timeline2 });
1206
1555
  }
1207
- const timeline = { type: "clock" };
1556
+ const timeline = {};
1557
+ if (engine !== void 0) timeline.engine = engine;
1558
+ if (frameRate !== void 0) timeline.frameRate = frameRate;
1208
1559
  if (duration !== void 0) timeline.duration = duration;
1209
1560
  if (trigger !== void 0 || resetOnFinish) {
1210
1561
  const t = __spreadValues({}, trigger || {});
1211
- if (resetOnFinish) t.onFinish = "reset";
1562
+ if (resetOnFinish) t.finishAction = "reset";
1212
1563
  timeline.trigger = t;
1213
1564
  }
1214
1565
  if (delay !== void 0) timeline.delay = delay;
1215
1566
  if (iterations !== void 0) timeline.iterations = iterations;
1216
1567
  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;
1568
+ if (fill !== void 0) timeline.fillMode = fill;
1569
+ return Object.keys(timeline).length > 0 ? __spreadProps(__spreadValues({}, shared), { timeline }) : shared;
1219
1570
  }
1220
1571
  function getDefs(doc) {
1221
- var _a;
1572
+ var _a2;
1222
1573
  if (!doc) return void 0;
1223
- return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
1574
+ return (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
1224
1575
  }
1225
1576
  function getBindings(doc) {
1226
- var _a;
1577
+ var _a2;
1227
1578
  if (!doc) return void 0;
1228
- const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
1579
+ const animateById = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.animateById;
1229
1580
  if (!animateById) return void 0;
1230
1581
  return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
1231
1582
  }
@@ -1233,7 +1584,7 @@ function getChildren(doc) {
1233
1584
  return doc == null ? void 0 : doc.children;
1234
1585
  }
1235
1586
 
1236
- // src/PxAnimatorTypes.ts
1587
+ // src/format/PxAnimatorTypes.ts
1237
1588
  var PxEasingOrRefSchema = px.union([
1238
1589
  px.string(),
1239
1590
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -1265,16 +1616,32 @@ var PxKeyframeSchema = implementsInterface()(px.object({
1265
1616
  // (review §1.3): editor data lives under `meta`. The editor still carries it on
1266
1617
  // its internal COPY-PASTE payload, which never validates against this schema.)
1267
1618
  }));
1619
+ var anyKf = (kf) => kf;
1620
+ var kfTime = (kf) => {
1621
+ var _a2, _b;
1622
+ return (_b = (_a2 = anyKf(kf).time) != null ? _a2 : anyKf(kf).t) != null ? _b : 0;
1623
+ };
1624
+ var kfValue = (kf) => {
1625
+ var _a2;
1626
+ return (_a2 = anyKf(kf).value) != null ? _a2 : anyKf(kf).v;
1627
+ };
1628
+ var kfEasing = (kf) => {
1629
+ var _a2;
1630
+ return (_a2 = anyKf(kf).easing) != null ? _a2 : anyKf(kf).e;
1631
+ };
1632
+ var kfTangentIn = (kf) => anyKf(kf).tangentIn;
1633
+ var kfTangentOut = (kf) => anyKf(kf).tangentOut;
1268
1634
  var PxLoopSchema = implementsInterface()(px.object({
1269
1635
  segmentCount: px.number().optional(),
1270
- extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
1271
- alternate: px.boolean().optional()
1636
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1637
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1272
1638
  }));
1273
1639
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1274
1640
  value: PxKeyframeValueSchema.optional(),
1275
1641
  keyframes: px.array(PxKeyframeSchema).optional(),
1276
1642
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1277
- autoOrient: px.boolean().optional()
1643
+ autoOrient: px.boolean().optional(),
1644
+ alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
1278
1645
  }));
1279
1646
  var PxTransformPartsSchema = implementsInterface()(px.object({
1280
1647
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1301,10 +1668,9 @@ var PxTriggerSchema = implementsInterface()(px.object({
1301
1668
  startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1302
1669
  outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1303
1670
  // 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(),
1671
+ // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1672
+ // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1673
+ finishAction: px.enum(["hold", "reset"]).optional(),
1308
1674
  scrollIntoViewThreshold: px.number().optional()
1309
1675
  }));
1310
1676
  var PxGlyphSchema = implementsInterface()(px.object({
@@ -1324,7 +1690,7 @@ var PxDefsSchema = implementsInterface()(px.object({
1324
1690
  // Review §2.6: the schema now matches the declared type — a style preset is a flat
1325
1691
  // record of string|number attribute values, nothing nested.
1326
1692
  styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1327
- glyphs: px.record(PxGlyphFontSchema).optional()
1693
+ fonts: px.record(PxGlyphFontSchema).optional()
1328
1694
  }));
1329
1695
  var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1330
1696
  var PxScrollRangePointSchema = implementsInterface()(px.object({
@@ -1336,7 +1702,6 @@ var PxScrollRangeSchema = px.object({
1336
1702
  end: PxScrollRangePointSchema.optional()
1337
1703
  });
1338
1704
  var PxScrollSchema = implementsInterface()(px.object({
1339
- driver: px.enum(["custom", "native"]).optional(),
1340
1705
  kind: px.enum(["view", "scroll"]).optional(),
1341
1706
  axis: px.enum(["block", "inline", "x", "y"]).optional(),
1342
1707
  source: px.enum(["nearest", "root"]).optional(),
@@ -1349,21 +1714,26 @@ var PxScrollSchema = implementsInterface()(px.object({
1349
1714
  pinDistance: px.number().optional(),
1350
1715
  range: PxScrollRangeSchema.optional()
1351
1716
  }));
1352
- var PxTimelinePinSchema = px.object({
1717
+ var PxTimelinePinSchema = implementsInterface()(px.object({
1353
1718
  align: px.enum(["top", "center", "bottom"]).optional(),
1354
1719
  top: px.number().optional(),
1355
1720
  distance: px.number().optional()
1356
- });
1357
- var PxClockTimelineSchema = px.object({
1358
- type: px.literal("clock"),
1721
+ }));
1722
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
1723
+ var PxTimeTimelineSchema = implementsInterface()(px.object({
1724
+ type: px.literal("time").optional(),
1725
+ engine: PxTimelineEngineSchema,
1726
+ frameRate: px.number().optional(),
1359
1727
  // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1360
1728
  duration: px.number().optional(),
1361
1729
  trigger: PxTriggerSchema.optional(),
1362
1730
  delay: px.number().optional(),
1363
1731
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1364
- fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1732
+ // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1733
+ // — never `fill`, which is paint everywhere else in the format.
1734
+ fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1365
1735
  direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1366
- });
1736
+ }));
1367
1737
  var scrollishTimelineShape = {
1368
1738
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1369
1739
  // span the scroll range maps onto.
@@ -1371,7 +1741,8 @@ var scrollishTimelineShape = {
1371
1741
  // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1372
1742
  // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1373
1743
  iterations: px.number().optional(),
1374
- engine: px.enum(["custom", "native"]).optional(),
1744
+ engine: PxTimelineEngineSchema,
1745
+ frameRate: px.number().optional(),
1375
1746
  axis: px.enum(["block", "inline", "x", "y"]).optional(),
1376
1747
  source: px.enum(["nearest", "root"]).optional(),
1377
1748
  subject: px.string().optional(),
@@ -1381,23 +1752,29 @@ var scrollishTimelineShape = {
1381
1752
  pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1382
1753
  range: PxScrollRangeSchema.optional()
1383
1754
  };
1384
- var PxScrollTimelineSchema = px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape));
1385
- var PxViewTimelineSchema = px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape));
1755
+ var PxScrollTimelineSchema = implementsInterface()(
1756
+ px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape))
1757
+ );
1758
+ var PxViewTimelineSchema = implementsInterface()(
1759
+ px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape))
1760
+ );
1386
1761
  var PxTimelineSchema = px.discriminatedUnion("type", [
1387
- PxClockTimelineSchema,
1762
+ PxTimeTimelineSchema,
1763
+ // first = the member an absent `type` selects
1388
1764
  PxScrollTimelineSchema,
1389
1765
  PxViewTimelineSchema
1390
1766
  ]);
1391
1767
  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(),
1768
+ // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1769
+ // at this level only on the runtime view, like the rest of the playback dynamics.)
1396
1770
  // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1397
1771
  timeline: PxTimelineSchema.optional(),
1398
1772
  definitions: PxDefsSchema.optional(),
1399
1773
  animateById: px.record(PxElementAnimationSchema).optional(),
1400
- debugInstName: px.string().optional()
1774
+ debugGlobalName: px.string().optional(),
1775
+ // Declared HERE because this is a closed object: an undeclared key would be stripped by
1776
+ // `sanitize` and flagged by strict validation on our own files.
1777
+ version: px.string().optional()
1401
1778
  }));
1402
1779
  var PxBindingSchema = implementsInterface()(px.object({
1403
1780
  id: px.string(),
@@ -1446,7 +1823,7 @@ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1446
1823
  origin: PxAnimatableVec2Schema.optional()
1447
1824
  }));
1448
1825
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
1449
- sourceId: px.string().optional(),
1826
+ source: px.string().optional(),
1450
1827
  maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1451
1828
  maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1452
1829
  maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
@@ -1469,9 +1846,10 @@ var PxRetimeEffectSchema = implementsInterface()(px.object({
1469
1846
  timeCrop: px.tuple([px.number(), px.number()]).optional()
1470
1847
  }));
1471
1848
  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(),
1849
+ // Subtractive on purpose: the `<use>` can only point at one wrapper layer of the
1850
+ // source, so the choices form a ladder — 'translate' now, maybe 'transform' later.
1851
+ without: px.enum([PxCloneWithout.translate]).optional(),
1852
+ source: px.string().optional(),
1475
1853
  retime: PxRetimeEffectSchema.optional()
1476
1854
  }));
1477
1855
  var PxGradientStopSchema = implementsInterface()(px.object({
@@ -1498,7 +1876,7 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1498
1876
  }));
1499
1877
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1500
1878
  var PxTextPathEffectSchema = implementsInterface()(px.object({
1501
- path: px.string(),
1879
+ pathData: px.string(),
1502
1880
  pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1503
1881
  lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1504
1882
  method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
@@ -1538,16 +1916,33 @@ function validateNodeEffects(root, opts) {
1538
1916
  walk(root, "root");
1539
1917
  return warnings;
1540
1918
  }
1919
+ function validateDocument(doc) {
1920
+ const ctx = { errors: [], warnings: [], strict: true };
1921
+ const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
1922
+ if (doc && typeof doc === "object") {
1923
+ for (const w of validateNodeEffects(doc, { strict: true })) {
1924
+ if (!problems.includes(w)) problems.push(w);
1925
+ }
1926
+ }
1927
+ return problems;
1928
+ }
1541
1929
  var PxNodeBase = px.openObject({
1542
1930
  // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1543
1931
  // 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`,
1932
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1545
1933
  // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1546
1934
  // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1547
1935
  // would add words that all mean "type" and still need the carrier to read.
1548
1936
  // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1549
1937
  // (issues V3), never of distinct key names.
1550
1938
  type: px.string(),
1939
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
1940
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
1941
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
1942
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
1943
+ // documented — because a wire key that is not in a schema is invisible to the
1944
+ // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1945
+ domType: px.string().optional(),
1551
1946
  id: px.string().optional(),
1552
1947
  meta: px.any().optional(),
1553
1948
  // Player-effects bucket emitted by the Editor's lightweight design format.
@@ -1587,7 +1982,7 @@ function isPxElementFileFormatDeep(fileJson) {
1587
1982
  return { valid, errors: valid ? [] : ["Document failed schema validation"] };
1588
1983
  }
1589
1984
 
1590
- // src/PxIdUtil.ts
1985
+ // src/util/PxIdUtil.ts
1591
1986
  var _idCounter = 0;
1592
1987
  function generateUniqueId() {
1593
1988
  const timestamp = Date.now().toString(36);
@@ -1606,7 +2001,7 @@ function deepClone(value) {
1606
2001
  return cloned;
1607
2002
  }
1608
2003
  function generateNewIds(doc) {
1609
- var _a, _b;
2004
+ var _a2, _b;
1610
2005
  const cloned = deepClone(doc);
1611
2006
  const idMap = /* @__PURE__ */ new Map();
1612
2007
  const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
@@ -1624,7 +2019,8 @@ function generateNewIds(doc) {
1624
2019
  "flood-color",
1625
2020
  "lighting-color"
1626
2021
  ]);
1627
- const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
2022
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
2023
+ const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
1628
2024
  function collectIds(node) {
1629
2025
  if (!node || typeof node !== "object") return;
1630
2026
  if (node.id && typeof node.id === "string") {
@@ -1641,7 +2037,7 @@ function generateNewIds(doc) {
1641
2037
  }
1642
2038
  }
1643
2039
  }
1644
- function updateRefs(node) {
2040
+ function updateRefs(node, parentKey) {
1645
2041
  if (!node || typeof node !== "object") return;
1646
2042
  for (const [key, value] of Object.entries(node)) {
1647
2043
  if (key === "children") {
@@ -1661,7 +2057,7 @@ function generateNewIds(doc) {
1661
2057
  }
1662
2058
  } else if (urlRefAttrs.has(key)) {
1663
2059
  node[key] = replaceUrlRefs(value, idMap);
1664
- } else if (directIdRefAttrs.has(key)) {
2060
+ } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
1665
2061
  const hasHash = value.startsWith("#");
1666
2062
  const newId = idMap.get(hasHash ? value.slice(1) : value);
1667
2063
  if (newId) {
@@ -1677,13 +2073,13 @@ function generateNewIds(doc) {
1677
2073
  }
1678
2074
  }
1679
2075
  } else if (typeof value === "object" && value !== null) {
1680
- updateRefs(value);
2076
+ updateRefs(value, key);
1681
2077
  }
1682
2078
  }
1683
2079
  }
1684
2080
  collectIds(cloned);
1685
2081
  updateRefs(cloned);
1686
- const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
2082
+ const docAnimate = (_a2 = cloned.animator) == null ? void 0 : _a2.animateById;
1687
2083
  if (docAnimate && typeof docAnimate === "object") {
1688
2084
  const updatedAnimate = {};
1689
2085
  for (const [key, anim] of Object.entries(docAnimate)) {
@@ -1703,7 +2099,7 @@ function replaceUrlRefs(value, idMap) {
1703
2099
  });
1704
2100
  }
1705
2101
 
1706
- // src/PxNodeProps.ts
2102
+ // src/util/PxNodeProps.ts
1707
2103
  var DISALLOWED_SVG_TAGS_LOWER = /* @__PURE__ */ new Set([
1708
2104
  "script",
1709
2105
  "foreignobject"
@@ -1767,10 +2163,10 @@ function sanitiseAttributeValue(name, value) {
1767
2163
  return value;
1768
2164
  }
1769
2165
  function resolveStyle(style, defs) {
1770
- var _a;
2166
+ var _a2;
1771
2167
  if (!style) return void 0;
1772
2168
  if (typeof style === "string") {
1773
- return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
2169
+ return (_a2 = defs == null ? void 0 : defs.styles) == null ? void 0 : _a2[style];
1774
2170
  }
1775
2171
  return style;
1776
2172
  }
@@ -1785,14 +2181,14 @@ function getNormalizedProps(props) {
1785
2181
  propsCopy[key] = toRGBA(value);
1786
2182
  } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
1787
2183
  const parts = value.value && typeof value.value === "object" ? value.value : value;
1788
- propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
2184
+ propsCopy[TRANSFORM_ATTR] = composeTransformParts(parts, { withUnits: false });
1789
2185
  } else if (TRANSFORM_FN_NAMES.has(key)) {
1790
2186
  if (Array.isArray(value)) {
1791
2187
  if (key === "translate") value = value.map((v) => v + "px");
1792
2188
  value = value.join(",");
1793
2189
  }
1794
2190
  if (key === "rotate") value = value + "deg";
1795
- propsCopy["transform"] = key + "(" + value + ")";
2191
+ propsCopy[TRANSFORM_ATTR] = key + "(" + value + ")";
1796
2192
  } else if (Array.isArray(value)) {
1797
2193
  propsCopy[key] = value.join(",");
1798
2194
  } else if (value !== void 0 && value !== null) {
@@ -1802,10 +2198,9 @@ function getNormalizedProps(props) {
1802
2198
  return propsCopy;
1803
2199
  }
1804
2200
 
1805
- // src/PxMotionPath.ts
2201
+ // src/materialise/PxMotionPath.ts
1806
2202
  function getKfTranslate(kf) {
1807
- var _a;
1808
- const v = (_a = kf.value) != null ? _a : kf.v;
2203
+ const v = kfValue(kf);
1809
2204
  if (!v) return void 0;
1810
2205
  if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
1811
2206
  return [v[0], v[1]];
@@ -1815,31 +2210,27 @@ function getKfTranslate(kf) {
1815
2210
  return void 0;
1816
2211
  }
1817
2212
  function getKfTime(kf) {
1818
- var _a, _b;
1819
- return (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2213
+ return kfTime(kf);
1820
2214
  }
1821
2215
  function getKfEasing(kf) {
1822
- var _a;
1823
- return (_a = kf.easing) != null ? _a : kf.e;
2216
+ return kfEasing(kf);
1824
2217
  }
1825
2218
  function propAnimIsMotionPath(anim) {
1826
- var _a, _b;
1827
2219
  const kfs = anim.keyframes;
1828
2220
  if (!Array.isArray(kfs)) return false;
1829
2221
  if (anim.autoOrient) return true;
1830
2222
  for (const kf of kfs) {
1831
- if (((_a = kf.tangentIn) != null ? _a : kf.ti) || ((_b = kf.tangentOut) != null ? _b : kf.to)) return true;
2223
+ if (kfTangentIn(kf) || kfTangentOut(kf)) return true;
1832
2224
  }
1833
2225
  return false;
1834
2226
  }
1835
2227
  var _segmentCache = /* @__PURE__ */ new WeakMap();
1836
2228
  function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
1837
- var _a, _b;
1838
2229
  let byNext = _segmentCache.get(prevKf);
1839
2230
  const existing = byNext == null ? void 0 : byNext.get(nextKf);
1840
2231
  if (existing) return existing;
1841
- const to = (_a = prevKf.tangentOut) != null ? _a : prevKf.to;
1842
- const ti = (_b = nextKf.tangentIn) != null ? _b : nextKf.ti;
2232
+ const to = kfTangentOut(prevKf);
2233
+ const ti = kfTangentIn(nextKf);
1843
2234
  const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
1844
2235
  const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
1845
2236
  const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
@@ -1889,12 +2280,12 @@ var DEFAULT_FLATNESS_TOL = 0.5;
1889
2280
  var DEFAULT_ROTATION_TOL = 5;
1890
2281
  var DEFAULT_MAX_SAMPLES = 32;
1891
2282
  function materialiseMotionPathInPropAnim(anim, opts) {
1892
- var _a, _b, _c;
2283
+ var _a2, _b, _c;
1893
2284
  if (!propAnimIsMotionPath(anim)) return anim;
1894
2285
  const kfs = anim.keyframes;
1895
2286
  if (!Array.isArray(kfs) || kfs.length < 2) return anim;
1896
2287
  const autoOrient = !!anim.autoOrient;
1897
- const flatnessTol = (_a = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a : DEFAULT_FLATNESS_TOL;
2288
+ const flatnessTol = (_a2 = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a2 : DEFAULT_FLATNESS_TOL;
1898
2289
  const rotationTol = (_b = opts == null ? void 0 : opts.rotationTolerance) != null ? _b : DEFAULT_ROTATION_TOL;
1899
2290
  const maxSamples = (_c = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _c : DEFAULT_MAX_SAMPLES;
1900
2291
  const out = [];
@@ -1930,10 +2321,9 @@ function materialiseMotionPathInPropAnim(anim, opts) {
1930
2321
  return result;
1931
2322
  }
1932
2323
  function unwrapAutoOrientRotations(kfs) {
1933
- var _a;
1934
2324
  let prev;
1935
2325
  for (const kf of kfs) {
1936
- const v = (_a = kf.v) != null ? _a : kf.value;
2326
+ const v = kfValue(kf);
1937
2327
  if (!v || typeof v.rotate !== "number") continue;
1938
2328
  if (prev === void 0) {
1939
2329
  prev = v.rotate;
@@ -1950,8 +2340,7 @@ function makeOutKf(time, value) {
1950
2340
  return { t: time, v: value };
1951
2341
  }
1952
2342
  function getKfValueParts(kf) {
1953
- var _a;
1954
- const v = (_a = kf.value) != null ? _a : kf.v;
2343
+ const v = kfValue(kf);
1955
2344
  if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
1956
2345
  return v;
1957
2346
  }
@@ -2012,9 +2401,8 @@ function wrappedAngleDelta(a, b) {
2012
2401
  return d;
2013
2402
  }
2014
2403
  function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
2015
- var _a;
2016
2404
  const lastKf = out[out.length - 1];
2017
- const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
2405
+ const lastV = kfValue(lastKf);
2018
2406
  const prevExit = lastV == null ? void 0 : lastV.rotate;
2019
2407
  if (typeof prevExit !== "number") return;
2020
2408
  const boundaryV = getKfValueParts(prevKf);
@@ -2195,7 +2583,7 @@ function walkAndMaterialise(node, opts) {
2195
2583
  return cloned;
2196
2584
  }
2197
2585
 
2198
- // src/PxDefinitions.ts
2586
+ // src/animation/PxDefinitions.ts
2199
2587
  var LOOP_JUMP_SHIFT_MS = 1;
2200
2588
  function deepEqualValue(a, b) {
2201
2589
  if (a === b) return true;
@@ -2327,21 +2715,21 @@ function normalizePathValue(value) {
2327
2715
  return value;
2328
2716
  }
2329
2717
  function resolveEasing(easing, defs) {
2330
- var _a;
2718
+ var _a2;
2331
2719
  if (!easing) return void 0;
2332
2720
  if (Array.isArray(easing)) {
2333
2721
  return easing;
2334
2722
  }
2335
- if ((_a = defs == null ? void 0 : defs.easings) == null ? void 0 : _a[easing]) {
2723
+ if ((_a2 = defs == null ? void 0 : defs.easings) == null ? void 0 : _a2[easing]) {
2336
2724
  return defs.easings[easing];
2337
2725
  }
2338
2726
  console.warn("Unknown easing name: " + easing);
2339
2727
  return void 0;
2340
2728
  }
2341
2729
  function resolveAnimation(animRef, defs) {
2342
- var _a;
2730
+ var _a2;
2343
2731
  if (typeof animRef === "string") {
2344
- const resolved = (_a = defs == null ? void 0 : defs.animations) == null ? void 0 : _a[animRef];
2732
+ const resolved = (_a2 = defs == null ? void 0 : defs.animations) == null ? void 0 : _a2[animRef];
2345
2733
  if (!resolved) {
2346
2734
  console.warn("Unknown animation name: " + animRef);
2347
2735
  }
@@ -2366,9 +2754,9 @@ function resolveElementAnimation(animate, defs) {
2366
2754
  return results;
2367
2755
  }
2368
2756
  function interpolateValue(propName, a, b, t) {
2369
- var _a, _b;
2757
+ var _a2, _b;
2370
2758
  if (propName === "d") {
2371
- const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
2759
+ const aPaths = (_a2 = a == null ? void 0 : a.paths) != null ? _a2 : Array.isArray(a) ? a : [];
2372
2760
  const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2373
2761
  return { paths: interpolateBeziers(aPaths, bPaths, t) };
2374
2762
  }
@@ -2404,11 +2792,11 @@ function interpolateTransformParts(a, b, t) {
2404
2792
  return out;
2405
2793
  }
2406
2794
  function expandLoopKeyframes(propName, keyframes, loop, duration) {
2407
- var _a, _b, _c, _d, _e;
2795
+ var _a2, _b, _c, _d, _e;
2408
2796
  const totalIntervals = keyframes.length - 1;
2409
- const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2797
+ const segCount = clamp((_a2 = loop.segmentCount) != null ? _a2 : totalIntervals, 1, totalIntervals);
2410
2798
  let segKfs;
2411
- if (loop.extend === PxLoopExtend.before) {
2799
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2412
2800
  segKfs = keyframes.slice(0, segCount + 1);
2413
2801
  } else {
2414
2802
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -2416,7 +2804,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2416
2804
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2417
2805
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2418
2806
  let fillStart, fillEnd;
2419
- if (loop.extend === PxLoopExtend.before) {
2807
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2420
2808
  fillStart = 0;
2421
2809
  fillEnd = firstT;
2422
2810
  } else {
@@ -2429,26 +2817,23 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2429
2817
  const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
2430
2818
  const segDuration = segEndT - segStartT;
2431
2819
  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
- });
2820
+ const template = segKfs.map((kf) => ({
2821
+ relT: (kf.t - segStartT) / segDuration,
2822
+ v: kf.v,
2823
+ e: kf.e,
2824
+ tangentIn: kfTangentIn(kf),
2825
+ tangentOut: kfTangentOut(kf)
2826
+ }));
2442
2827
  const fullReps = Math.floor(fillDuration / segDuration);
2443
2828
  const remainder = fillDuration - fullReps * segDuration;
2444
2829
  const partialFraction = remainder / segDuration;
2445
2830
  const looped = [];
2446
- const separateBoundary = loop.extend !== PxLoopExtend.before;
2831
+ const separateBoundary = loop.repeatAt !== PxLoopRepeatAt.start;
2447
2832
  const originalTerminalKf = keyframes[keyframes.length - 1];
2448
2833
  let terminalEasingOverride;
2449
2834
  let hasTerminalEasingOverride = false;
2450
2835
  function appendRep(repStart, isReversed, partial) {
2451
- var _a2;
2836
+ var _a3;
2452
2837
  let entries;
2453
2838
  if (isReversed) {
2454
2839
  entries = [];
@@ -2485,7 +2870,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2485
2870
  return;
2486
2871
  }
2487
2872
  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;
2873
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a3 = prevKf.t) != null ? _a3 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2489
2874
  if (isBoundary) {
2490
2875
  if (deepEqualValue(prevKf.v, entry.v)) {
2491
2876
  if (looped.length > 0) {
@@ -2551,30 +2936,30 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2551
2936
  looped.push(pushed);
2552
2937
  }
2553
2938
  }
2554
- if (loop.extend === PxLoopExtend.before) {
2939
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2555
2940
  if (partialFraction > 1e-9) {
2556
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
2941
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2557
2942
  appendRepTail(fillStart, isReversed, partialFraction);
2558
2943
  }
2559
2944
  for (let rep = 0; rep < fullReps; rep++) {
2560
2945
  const distFromBoundary = fullReps - 1 - rep;
2561
- const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
2946
+ const isReversed = loop.direction === PxLoopDirection.alternate && distFromBoundary % 2 === 0;
2562
2947
  const repStart = fillStart + remainder + rep * segDuration;
2563
2948
  appendRep(repStart, isReversed);
2564
2949
  }
2565
2950
  } else {
2566
2951
  for (let rep = 0; rep < fullReps; rep++) {
2567
- const isReversed = !!loop.alternate && rep % 2 === 0;
2952
+ const isReversed = loop.direction === PxLoopDirection.alternate && rep % 2 === 0;
2568
2953
  const repStart = fillStart + rep * segDuration;
2569
2954
  appendRep(repStart, isReversed);
2570
2955
  }
2571
2956
  if (partialFraction > 1e-9) {
2572
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
2957
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2573
2958
  const repStart = fillStart + fullReps * segDuration;
2574
2959
  appendRep(repStart, isReversed, partialFraction);
2575
2960
  }
2576
2961
  }
2577
- if (loop.extend === PxLoopExtend.before) {
2962
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2578
2963
  return [...looped, ...keyframes];
2579
2964
  } else {
2580
2965
  if (hasTerminalEasingOverride && keyframes.length > 0) {
@@ -2586,34 +2971,34 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2586
2971
  }
2587
2972
  }
2588
2973
  function normalizeKeyframes(propName, propAnim, duration, defs) {
2589
- var _a, _b, _c, _d, _e, _f, _g;
2974
+ var _a2;
2590
2975
  const keyframes = propAnim.keyframes || [];
2591
2976
  const normalized = [];
2592
2977
  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;
2978
+ const timePct = kfTime(kf);
2979
+ let value = kfValue(kf);
2980
+ const easing = kfEasing(kf);
2596
2981
  if (propName === "d") {
2597
2982
  value = normalizePathValue(value);
2598
2983
  }
2599
2984
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2600
2985
  if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
2601
- value = (_e = parseColor(value)) != null ? _e : value;
2986
+ value = (_a2 = parseColor(value)) != null ? _a2 : value;
2602
2987
  }
2603
2988
  const normKf = {
2604
2989
  t: timePct,
2605
2990
  v: value,
2606
2991
  e: resolveEasing(easing, defs)
2607
2992
  };
2608
- const tIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
2609
- const tOut = (_g = kf.tangentOut) != null ? _g : kf.to;
2993
+ const tIn = kfTangentIn(kf);
2994
+ const tOut = kfTangentOut(kf);
2610
2995
  if (tIn) normKf.tangentIn = tIn;
2611
2996
  if (tOut) normKf.tangentOut = tOut;
2612
2997
  normalized.push(normKf);
2613
2998
  }
2614
2999
  normalized.sort((a, b) => {
2615
- var _a2, _b2;
2616
- return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
3000
+ var _a3, _b;
3001
+ return ((_a3 = a.t) != null ? _a3 : 0) - ((_b = b.t) != null ? _b : 0);
2617
3002
  });
2618
3003
  const loopRaw = propAnim.loop;
2619
3004
  const loop = loopRaw === true ? {} : loopRaw || void 0;
@@ -2640,15 +3025,17 @@ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2640
3025
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2641
3026
  const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
2642
3027
  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;
3028
+ var _a2;
3029
+ const t = kfTime(kf);
3030
+ let v = kfValue(kf);
2646
3031
  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;
3032
+ if (isColour) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3033
+ const e = kfEasing(kf);
2649
3034
  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;
3035
+ const tIn = kfTangentIn(kf);
3036
+ const tOut = kfTangentOut(kf);
3037
+ if (tIn) out2.tangentIn = tIn;
3038
+ if (tOut) out2.tangentOut = tOut;
2652
3039
  return out2;
2653
3040
  });
2654
3041
  const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
@@ -2699,7 +3086,7 @@ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
2699
3086
  const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
2700
3087
  if (!staticParts || !Object.keys(staticParts).length) return animDef;
2701
3088
  const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
2702
- const transformAnim = animDef["transform"];
3089
+ const transformAnim = animDef[TRANSFORM_ATTR];
2703
3090
  if (transformAnim && typeof transformAnim === "object") {
2704
3091
  const anim = transformAnim;
2705
3092
  if (Array.isArray(anim.keyframes)) {
@@ -2724,7 +3111,7 @@ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
2724
3111
  delete rest[ch];
2725
3112
  return __spreadProps(__spreadValues({}, rest), { transform: lifted });
2726
3113
  }
2727
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
3114
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimelineEngine.native) {
2728
3115
  const normalized = {};
2729
3116
  for (const [propName, propAnim] of Object.entries(animDef)) {
2730
3117
  if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
@@ -2735,12 +3122,12 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimat
2735
3122
  const out = { keyframes: normalizedKfs };
2736
3123
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2737
3124
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2738
- normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
3125
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2739
3126
  }
2740
3127
  }
2741
3128
  return normalized;
2742
3129
  }
2743
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
3130
+ function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
2744
3131
  const animatorConfig = getAnimatorConfig(doc) || {};
2745
3132
  const defs = getDefs(doc);
2746
3133
  const duration = animatorConfig.duration || 1e3;
@@ -2786,12 +3173,12 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2786
3173
  return bindings;
2787
3174
  }
2788
3175
  function getKeyframesPair(keyframes, progress) {
2789
- var _a, _b;
3176
+ var _a2, _b;
2790
3177
  const last = keyframes.length - 1;
2791
3178
  let prevKf = keyframes[0];
2792
3179
  let nextKf = keyframes[last > 0 ? 1 : 0];
2793
3180
  for (let j = 0; j < last; j++) {
2794
- const aOff = (_a = keyframes[j].t) != null ? _a : 0;
3181
+ const aOff = (_a2 = keyframes[j].t) != null ? _a2 : 0;
2795
3182
  const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
2796
3183
  if (aOff <= progress && progress <= bOff) {
2797
3184
  prevKf = keyframes[j];
@@ -2806,13 +3193,13 @@ function getKeyframesPair(keyframes, progress) {
2806
3193
  return { prevKf, nextKf };
2807
3194
  }
2808
3195
  function calcPropertyValue(propName, propAnim, progress) {
2809
- var _a, _b, _c, _d, _e, _f, _g;
3196
+ var _a2, _b, _c, _d;
2810
3197
  const keyframes = propAnim.keyframes || [];
2811
3198
  if (keyframes.length === 0) return null;
2812
3199
  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);
3200
+ let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a2 = prevKf.t) != null ? _a2 : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
2814
3201
  localProgress = clamp(localProgress, 0, 1);
2815
- const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
3202
+ const easing = kfEasing(prevKf);
2816
3203
  if (easing && Array.isArray(easing)) {
2817
3204
  try {
2818
3205
  localProgress = cubicBezier(easing)(localProgress);
@@ -2821,11 +3208,11 @@ function calcPropertyValue(propName, propAnim, progress) {
2821
3208
  }
2822
3209
  let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2823
3210
  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;
3211
+ const prevV = prevKf == null ? void 0 : prevKf.v;
3212
+ const nextV = nextKf == null ? void 0 : nextKf.v;
2826
3213
  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 : [];
3214
+ const prevPaths = (_c = prevV == null ? void 0 : prevV.paths) != null ? _c : Array.isArray(prevV) ? prevV : [];
3215
+ const nextPaths = (_d = nextV == null ? void 0 : nextV.paths) != null ? _d : Array.isArray(nextV) ? nextV : [];
2829
3216
  cssValue = interpolateBeziers(
2830
3217
  prevPaths,
2831
3218
  nextPaths,
@@ -2928,7 +3315,7 @@ function calcAnimationValues(animDef, progress) {
2928
3315
  return result;
2929
3316
  }
2930
3317
 
2931
- // src/PxNodeCloneUtil.ts
3318
+ // src/util/PxNodeCloneUtil.ts
2932
3319
  function deepClonePxNode(value) {
2933
3320
  if (value === null || typeof value !== "object") return value;
2934
3321
  if (Array.isArray(value)) return value.map(deepClonePxNode);
@@ -2939,13 +3326,13 @@ function deepClonePxNode(value) {
2939
3326
  function regenerateIdsAndRewriteRefs(root, genId3) {
2940
3327
  const oldToNew = /* @__PURE__ */ new Map();
2941
3328
  const walkAssign = (n) => {
2942
- var _a;
3329
+ var _a2;
2943
3330
  if (typeof n.id === "string") {
2944
3331
  const newId = genId3();
2945
3332
  oldToNew.set(n.id, newId);
2946
3333
  n.id = newId;
2947
3334
  }
2948
- (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
3335
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkAssign);
2949
3336
  };
2950
3337
  walkAssign(root);
2951
3338
  const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
@@ -2953,7 +3340,7 @@ function regenerateIdsAndRewriteRefs(root, genId3) {
2953
3340
  return newId ? "url(#" + newId + ")" : m;
2954
3341
  });
2955
3342
  const walkRewrite = (n) => {
2956
- var _a;
3343
+ var _a2;
2957
3344
  if (typeof n.href === "string" && n.href.startsWith("#")) {
2958
3345
  const newId = oldToNew.get(n.href.slice(1));
2959
3346
  if (newId) n.href = "#" + newId;
@@ -2965,7 +3352,7 @@ function regenerateIdsAndRewriteRefs(root, genId3) {
2965
3352
  n[k] = rewriteUrl(v);
2966
3353
  }
2967
3354
  }
2968
- (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
3355
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkRewrite);
2969
3356
  };
2970
3357
  walkRewrite(root);
2971
3358
  return oldToNew;
@@ -2975,7 +3362,7 @@ function toFiniteNum(v) {
2975
3362
  return Number.isFinite(n) ? n : 0;
2976
3363
  }
2977
3364
  function applyUseOffsetToG(gNode) {
2978
- var _a;
3365
+ var _a2;
2979
3366
  const x = toFiniteNum(gNode.x);
2980
3367
  const y = toFiniteNum(gNode.y);
2981
3368
  delete gNode.x;
@@ -2984,7 +3371,7 @@ function applyUseOffsetToG(gNode) {
2984
3371
  const offset = "translate(" + x + "," + y + ")";
2985
3372
  const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
2986
3373
  if (carriesTransform) {
2987
- const inner = { type: "g", transform: offset, children: (_a = gNode.children) != null ? _a : [] };
3374
+ const inner = { type: "g", transform: offset, children: (_a2 = gNode.children) != null ? _a2 : [] };
2988
3375
  gNode.children = [inner];
2989
3376
  } else {
2990
3377
  gNode.transform = offset;
@@ -2992,9 +3379,9 @@ function applyUseOffsetToG(gNode) {
2992
3379
  return gNode;
2993
3380
  }
2994
3381
 
2995
- // src/PxAnimatorUseMaterialiser.ts
3382
+ // src/materialise/PxAnimatorUseMaterialiser.ts
2996
3383
  function materialiseAnimatedUseInstances(root) {
2997
- var _a;
3384
+ var _a2;
2998
3385
  const idMap = buildIdMap(root);
2999
3386
  const animatedIds = computeAnimatedSubtreeIds(root, idMap);
3000
3387
  if (animatedIds.size === 0) return root;
@@ -3005,7 +3392,7 @@ function materialiseAnimatedUseInstances(root) {
3005
3392
  const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3006
3393
  if (defsCollector.length === 0) return walked;
3007
3394
  const defsNode = { type: "defs", children: defsCollector };
3008
- const newChildren = [...(_a = walked.children) != null ? _a : [], defsNode];
3395
+ const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
3009
3396
  return __spreadProps(__spreadValues({}, walked), { children: newChildren });
3010
3397
  }
3011
3398
  function readRootViewport(root) {
@@ -3027,9 +3414,9 @@ function numericAttr(v) {
3027
3414
  function buildIdMap(root) {
3028
3415
  const map = /* @__PURE__ */ new Map();
3029
3416
  const visit = (n) => {
3030
- var _a;
3417
+ var _a2;
3031
3418
  if (typeof n.id === "string") map.set(n.id, n);
3032
- (_a = n.children) == null ? void 0 : _a.forEach(visit);
3419
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
3033
3420
  };
3034
3421
  visit(root);
3035
3422
  return map;
@@ -3076,11 +3463,11 @@ function stripHash(href) {
3076
3463
  return href.startsWith("#") ? href.slice(1) : href;
3077
3464
  }
3078
3465
  function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3079
- var _a, _b, _c, _d;
3466
+ var _a2, _b, _c, _d;
3080
3467
  const clone2 = deepClonePxNode(target);
3081
3468
  regenerateIdsAndRewriteRefs(clone2, genId3);
3082
3469
  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];
3470
+ const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3084
3471
  const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
3085
3472
  const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
3086
3473
  const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
@@ -3140,7 +3527,7 @@ function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector, ro
3140
3527
  return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
3141
3528
  }
3142
3529
 
3143
- // src/effects/transformParts.ts
3530
+ // src/effects/shared/transformParts.ts
3144
3531
  function partsRecord(part, value, origin) {
3145
3532
  const rec = {};
3146
3533
  if (part === "translate" /* Translate */) rec.translate = value;
@@ -3151,25 +3538,25 @@ function partsRecord(part, value, origin) {
3151
3538
  return rec;
3152
3539
  }
3153
3540
  function readAnimatable(raw) {
3154
- var _a, _b, _c;
3541
+ var _a2, _b;
3155
3542
  if (raw === void 0) return { kind: "absent" /* Absent */ };
3156
3543
  if (Array.isArray(raw)) return { kind: "static" /* Static */, value: raw };
3157
3544
  if (typeof raw === "object") {
3158
3545
  const obj = raw;
3159
- const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
3546
+ const kfs = obj.keyframes;
3160
3547
  if (kfs) {
3161
3548
  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;
3549
+ const base = (_a2 = obj.value) != null ? _a2 : obj.v;
3163
3550
  if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
3164
3551
  return out;
3165
3552
  }
3166
- const staticValue = (_c = obj.value) != null ? _c : obj.v;
3553
+ const staticValue = (_b = obj.value) != null ? _b : obj.v;
3167
3554
  if (staticValue !== void 0) return { kind: "static" /* Static */, value: staticValue };
3168
3555
  }
3169
3556
  return { kind: "static" /* Static */, value: raw };
3170
3557
  }
3171
3558
  function writeAnimatableChannel(node, attrName, read, opts) {
3172
- var _a, _b, _c, _d;
3559
+ var _a2, _b, _c, _d;
3173
3560
  const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
3174
3561
  if (read.kind === "absent" /* Absent */) return;
3175
3562
  if (read.kind === "static" /* Static */) {
@@ -3183,7 +3570,7 @@ function writeAnimatableChannel(node, attrName, read, opts) {
3183
3570
  if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
3184
3571
  animate[attrName] = block;
3185
3572
  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;
3573
+ 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
3574
  if (baseline !== void 0) node[attrName] = toOut(baseline);
3188
3575
  }
3189
3576
  function normaliseKeyframe(kf) {
@@ -3201,12 +3588,12 @@ function normaliseKeyframe(kf) {
3201
3588
  return out;
3202
3589
  }
3203
3590
  function readStaticOrigin(raw, ctx) {
3204
- var _a;
3591
+ var _a2;
3205
3592
  const o = readAnimatable(raw);
3206
3593
  if (o.kind === "absent" /* Absent */) return void 0;
3207
3594
  if (o.kind === "static" /* Static */) return o.value;
3208
3595
  ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
3209
- return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
3596
+ return (_a2 = o.keyframes[0]) == null ? void 0 : _a2.value;
3210
3597
  }
3211
3598
  function keyframeWith(kf, value) {
3212
3599
  const out = { value };
@@ -3217,7 +3604,7 @@ function keyframeWith(kf, value) {
3217
3604
  return out;
3218
3605
  }
3219
3606
 
3220
- // src/effects/transformationEffect.ts
3607
+ // src/effects/transform/transformationEffect.ts
3221
3608
  function applyTransformByEffect(node, fx, ctx) {
3222
3609
  if (!fx) return node;
3223
3610
  delete node.transform;
@@ -3308,7 +3695,7 @@ function wrapOrigin(inner, raw, invert) {
3308
3695
  return inner;
3309
3696
  }
3310
3697
 
3311
- // src/effects/util.ts
3698
+ // src/effects/shared/util.ts
3312
3699
  function genId(ctx, prefix) {
3313
3700
  return "_lw_" + prefix + "_" + ctx.nextId++;
3314
3701
  }
@@ -3316,9 +3703,9 @@ function stripHash2(href) {
3316
3703
  return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3317
3704
  }
3318
3705
  function indexById(node, map) {
3319
- var _a;
3706
+ var _a2;
3320
3707
  if (typeof node.id === "string") map.set(node.id, node);
3321
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
3708
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((child) => indexById(child, map));
3322
3709
  }
3323
3710
  function spliceDefs(root, defs) {
3324
3711
  if (!defs.length) return;
@@ -3330,11 +3717,11 @@ function regenerateIdsInClone(root, ctx) {
3330
3717
  return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3331
3718
  }
3332
3719
 
3333
- // src/effects/contentRefSplit.ts
3720
+ // src/effects/reference/contentRefSplit.ts
3334
3721
  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);
3722
+ var _a2, _b, _c;
3723
+ if (node.type === "use" && ((_b = (_a2 = node.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.without) === "translate") {
3724
+ const sourceId = stripHash2(node.effects.clone.source);
3338
3725
  if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3339
3726
  ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
3340
3727
  }
@@ -3359,10 +3746,10 @@ function splitForContentRef(node, transformBy, originalId, innerId, ctx) {
3359
3746
  return outerWrapper;
3360
3747
  }
3361
3748
  function liftBodyTranslate(node, transformBy) {
3362
- var _a, _b, _c;
3749
+ var _a2, _b, _c;
3363
3750
  const out = {};
3364
3751
  let didLiftAnimate = false;
3365
- const animTr = (_a = node.animate) == null ? void 0 : _a.transform;
3752
+ const animTr = (_a2 = node.animate) == null ? void 0 : _a2.transform;
3366
3753
  if (animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes)) {
3367
3754
  const kfs = animTr.keyframes;
3368
3755
  const hasTranslate = kfs.some((kf) => kf.value && kf.value.translate);
@@ -3545,7 +3932,7 @@ function needsOriginOnOuter(translateAnim) {
3545
3932
  return false;
3546
3933
  }
3547
3934
 
3548
- // src/effects/gradientEffect.ts
3935
+ // src/effects/paint/gradientEffect.ts
3549
3936
  function applyFillGradientEffect(node, fx, ctx) {
3550
3937
  return applyGradient(node, fx, ctx, "fill");
3551
3938
  }
@@ -3580,7 +3967,7 @@ function synthesiseGradientDef(fx, id, ctx) {
3580
3967
  return out;
3581
3968
  }
3582
3969
  function applyGeomVec(out, xAttr, yAttr, raw) {
3583
- var _a, _b, _c;
3970
+ var _a2, _b, _c;
3584
3971
  const read = readAnimatable(raw);
3585
3972
  if (read.kind === "absent" /* Absent */) return;
3586
3973
  if (read.kind === "static" /* Static */) {
@@ -3599,7 +3986,7 @@ function applyGeomVec(out, xAttr, yAttr, raw) {
3599
3986
  if (read.loop !== void 0) block.loop = read.loop;
3600
3987
  return block;
3601
3988
  };
3602
- const animate = (_a = out.animate) != null ? _a : {};
3989
+ const animate = (_a2 = out.animate) != null ? _a2 : {};
3603
3990
  animate[xAttr] = axisChannel(0);
3604
3991
  animate[yAttr] = axisChannel(1);
3605
3992
  out.animate = animate;
@@ -3615,7 +4002,7 @@ function applyGeomNumber(out, attrName, raw) {
3615
4002
  writeAnimatableChannel(out, attrName, read, { asString: true });
3616
4003
  }
3617
4004
  function buildStopChildren(stops, ctx) {
3618
- var _a, _b, _c, _d;
4005
+ var _a2, _b;
3619
4006
  if (!stops) return [];
3620
4007
  const read = readAnimatable(stops);
3621
4008
  if (read.kind === "absent" /* Absent */) return [];
@@ -3625,14 +4012,14 @@ function buildStopChildren(stops, ctx) {
3625
4012
  const loopFromSource = read.loop;
3626
4013
  let stopCount = 0;
3627
4014
  for (const kf of kfs) {
3628
- const v = (_a = kf.value) != null ? _a : kf.v;
4015
+ const v = kfValue(kf);
3629
4016
  if (Array.isArray(v) && v.length > stopCount) stopCount = v.length;
3630
4017
  }
3631
4018
  if (!stopCount) return [];
3632
- const firstKfValue = (_b = kfs[0].value) != null ? _b : kfs[0].v;
4019
+ const firstKfValue = kfValue(kfs[0]);
3633
4020
  const baselineStops = [];
3634
4021
  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" };
4022
+ 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
4023
  baselineStops.push({ offset: s.offset, color: s.color });
3637
4024
  }
3638
4025
  return baselineStops.map((bs, i) => animatedStopNode(bs, kfs, i, ctx, loopFromSource));
@@ -3645,16 +4032,16 @@ function staticStopNode(s) {
3645
4032
  };
3646
4033
  }
3647
4034
  function animatedStopNode(baseline, kfs, stopIdx, _ctx, loop) {
3648
- var _a, _b, _c, _d, _e;
4035
+ var _a2;
3649
4036
  const colorKfs = [];
3650
4037
  const offsetKfs = [];
3651
4038
  let offsetVaries = false;
3652
4039
  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);
4040
+ const t = kfTime(kf);
4041
+ const arr = kfValue(kf);
4042
+ const sliced = (_a2 = arr == null ? void 0 : arr[stopIdx]) != null ? _a2 : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
3656
4043
  if (!sliced) continue;
3657
- const easing = (_e = kf.easing) != null ? _e : kf.e;
4044
+ const easing = kfEasing(kf);
3658
4045
  const colorOut = { time: t, value: sliced.color };
3659
4046
  if (easing !== void 0) colorOut.easing = easing;
3660
4047
  colorKfs.push(colorOut);
@@ -3681,13 +4068,12 @@ function animatedStopNode(baseline, kfs, stopIdx, _ctx, loop) {
3681
4068
  return stop;
3682
4069
  }
3683
4070
  function prevDefinedStop(kfs, fromIdx, stopIdx) {
3684
- var _a, _b;
3685
4071
  for (let i = fromIdx; i >= 0; i--) {
3686
- const arr = (_a = kfs[i].value) != null ? _a : kfs[i].v;
4072
+ const arr = kfValue(kfs[i]);
3687
4073
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3688
4074
  }
3689
4075
  for (let i = fromIdx + 1; i < kfs.length; i++) {
3690
- const arr = (_b = kfs[i].value) != null ? _b : kfs[i].v;
4076
+ const arr = kfValue(kfs[i]);
3691
4077
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3692
4078
  }
3693
4079
  return void 0;
@@ -3697,7 +4083,7 @@ function formatOffset(o) {
3697
4083
  return pct + "%";
3698
4084
  }
3699
4085
 
3700
- // src/effects/clipPathEffect.ts
4086
+ // src/effects/clipping/clipPathEffect.ts
3701
4087
  function applyClipPathEffect(node, fx, ctx) {
3702
4088
  if (!(fx == null ? void 0 : fx.d)) return node;
3703
4089
  const clipId = genId(ctx, "clip");
@@ -3721,12 +4107,12 @@ function pathString(v) {
3721
4107
  return void 0;
3722
4108
  }
3723
4109
 
3724
- // src/effects/maskedByEffect.ts
4110
+ // src/effects/clipping/maskedByEffect.ts
3725
4111
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
3726
4112
  if (!fx) return node;
3727
- const sourceId = stripHash2(fx.sourceId);
4113
+ const sourceId = stripHash2(fx.source);
3728
4114
  if (!sourceId) {
3729
- ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
4115
+ ctx.errors.push("maskedBy.source missing \u2014 cannot build mask");
3730
4116
  return node;
3731
4117
  }
3732
4118
  const maskId = genId(ctx, "mask");
@@ -3789,16 +4175,16 @@ function invertPartValue(part, value) {
3789
4175
  return [1 / value[0], 1 / value[1]];
3790
4176
  }
3791
4177
  function negatedSpatialTangents(kf) {
3792
- var _a, _b;
4178
+ var _a2, _b;
3793
4179
  const out = {};
3794
- const to = (_a = kf.tangentOut) != null ? _a : kf.to;
4180
+ const to = (_a2 = kf.tangentOut) != null ? _a2 : kf.to;
3795
4181
  const ti = (_b = kf.tangentIn) != null ? _b : kf.ti;
3796
4182
  if (Array.isArray(to)) out.tangentOut = [-to[0], -to[1]];
3797
4183
  if (Array.isArray(ti)) out.tangentIn = [-ti[0], -ti[1]];
3798
4184
  return out;
3799
4185
  }
3800
4186
  function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
3801
- var _a;
4187
+ var _a2;
3802
4188
  const animate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3803
4189
  const animTr = animate == null ? void 0 : animate.transform;
3804
4190
  const kfs = animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes) ? animTr.keyframes : void 0;
@@ -3807,7 +4193,7 @@ function wrapInverseAnimatedBodyTransform(inner, node, _ctx) {
3807
4193
  const rotateKfs = [];
3808
4194
  const scaleKfs = [];
3809
4195
  for (const kf of kfs) {
3810
- const v = ((_a = kf.value) != null ? _a : kf.v) || {};
4196
+ const v = ((_a2 = kf.value) != null ? _a2 : kf.v) || {};
3811
4197
  const baseKf = keyframeWith(kf, void 0);
3812
4198
  if (Array.isArray(v.translate)) {
3813
4199
  translateKfs.push(__spreadProps(__spreadValues(__spreadValues({}, baseKf), negatedSpatialTangents(kf)), { value: { translate: [-v.translate[0], -v.translate[1]] } }));
@@ -3871,7 +4257,7 @@ function readTransformationFromBody(node) {
3871
4257
  return void 0;
3872
4258
  }
3873
4259
  function parseTransformStringToParts(s) {
3874
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
4260
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
3875
4261
  const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
3876
4262
  let m;
3877
4263
  const ops = [];
@@ -3885,7 +4271,7 @@ function parseTransformStringToParts(s) {
3885
4271
  for (let j = ops.length - 2; j >= 0; j--) {
3886
4272
  const cand = ops[j];
3887
4273
  if (cand.name !== "translate") continue;
3888
- const ox = (_a = cand.args[0]) != null ? _a : 0;
4274
+ const ox = (_a2 = cand.args[0]) != null ? _a2 : 0;
3889
4275
  const oy = (_b = cand.args[1]) != null ? _b : 0;
3890
4276
  const lx = (_c = last.args[0]) != null ? _c : 0;
3891
4277
  const ly = (_d = last.args[1]) != null ? _d : 0;
@@ -4000,8 +4386,8 @@ function interpKfs(kfs, t) {
4000
4386
  function collectMaskAncestorChains(root, ctx) {
4001
4387
  const interestingNodes = /* @__PURE__ */ new Set();
4002
4388
  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);
4389
+ var _a2, _b;
4390
+ const maskSourceId = stripHash2((_b = (_a2 = n.effects) == null ? void 0 : _a2.maskedBy) == null ? void 0 : _b.source);
4005
4391
  if (typeof maskSourceId === "string") {
4006
4392
  interestingNodes.add(n);
4007
4393
  const sourceNode = ctx.idMap.get(maskSourceId);
@@ -4022,7 +4408,7 @@ function collectMaskAncestorChains(root, ctx) {
4022
4408
  walk(root, []);
4023
4409
  }
4024
4410
  function extractTranslateOnly(node, ctx) {
4025
- var _a, _b, _c;
4411
+ var _a2, _b, _c;
4026
4412
  const tr = node.transform;
4027
4413
  const animateBlock = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate.transform : void 0;
4028
4414
  if (tr === void 0 && !animateBlock) return void 0;
@@ -4030,7 +4416,7 @@ function extractTranslateOnly(node, ctx) {
4030
4416
  if (typeof tr === "string") {
4031
4417
  const parts = parseTranslateOnlyFromString(tr, ctx);
4032
4418
  if (parts) out.translate = parts;
4033
- } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
4419
+ } else if (tr && typeof tr === "object" && !tr.keyframes) {
4034
4420
  const wrapped = tr.value;
4035
4421
  const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
4036
4422
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
@@ -4044,7 +4430,7 @@ function extractTranslateOnly(node, ctx) {
4044
4430
  const kfs = animateBlock.keyframes;
4045
4431
  const translateKfs = [];
4046
4432
  for (const kf of kfs) {
4047
- const v = (_a = kf.value) != null ? _a : kf.v;
4433
+ const v = (_a2 = kf.value) != null ? _a2 : kf.v;
4048
4434
  const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
4049
4435
  if (v && typeof v === "object" && Array.isArray(v.translate)) {
4050
4436
  translateKfs.push({ time: t, value: [v.translate[0] || 0, v.translate[1] || 0] });
@@ -4078,16 +4464,15 @@ function parseTranslateOnlyFromString(s, ctx) {
4078
4464
  return seen ? [x, y] : void 0;
4079
4465
  }
4080
4466
 
4081
- // src/effects/refEffect.ts
4082
- var CONTENT_SUBREF = "content";
4467
+ // src/effects/reference/refEffect.ts
4083
4468
  function applyRefHref(node, clone2, ctx) {
4084
4469
  if (!clone2) return;
4085
- const sourceId = stripHash2(clone2.sourceId);
4470
+ const sourceId = stripHash2(clone2.source);
4086
4471
  if (!sourceId) {
4087
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
4472
+ if (clone2.without === PxCloneWithout.translate) ctx.errors.push("clone: content ref missing `source`");
4088
4473
  return;
4089
4474
  }
4090
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4475
+ const targetId = clone2.without === PxCloneWithout.translate ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4091
4476
  node.href = "#" + targetId;
4092
4477
  }
4093
4478
  function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
@@ -4095,11 +4480,11 @@ function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
4095
4480
  return applyTransformByEffect(node, transformBy, ctx);
4096
4481
  }
4097
4482
 
4098
- // src/effects/repeaterEffect.ts
4483
+ // src/effects/transform/repeaterEffect.ts
4099
4484
  function applyRepeaterEffect(node, fx, ctx) {
4100
- var _a, _b;
4485
+ var _a2, _b;
4101
4486
  if (!fx) return node;
4102
- const copies = (_a = fx.copies) != null ? _a : 1;
4487
+ const copies = (_a2 = fx.copies) != null ? _a2 : 1;
4103
4488
  if (copies < 1) {
4104
4489
  ctx.errors.push("repeater.copies invalid: " + fx.copies);
4105
4490
  return node;
@@ -4166,11 +4551,11 @@ function synthesiseScale(raw, i) {
4166
4551
  return mapAnimatable(raw, scalePower, true);
4167
4552
  }
4168
4553
 
4169
- // src/effects/retimeEffect.ts
4554
+ // src/effects/reference/retimeEffect.ts
4170
4555
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
4171
4556
  function asRetime(r) {
4172
- var _a, _b;
4173
- return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
4557
+ var _a2, _b;
4558
+ return { start: (_a2 = r.start) != null ? _a2 : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
4174
4559
  }
4175
4560
  var CROP_EDGE_MS = 1;
4176
4561
  function applyTimeCrop(useNode, crop, ctx) {
@@ -4198,12 +4583,12 @@ function concatRetime(child, parent) {
4198
4583
  };
4199
4584
  }
4200
4585
  function readCloneRetime(n) {
4201
- var _a, _b;
4202
- return (_b = (_a = n.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.retime;
4586
+ var _a2, _b;
4587
+ return (_b = (_a2 = n.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.retime;
4203
4588
  }
4204
4589
  function clearCloneRetime(n) {
4205
- var _a;
4206
- const clone2 = (_a = n.effects) == null ? void 0 : _a.clone;
4590
+ var _a2;
4591
+ const clone2 = (_a2 = n.effects) == null ? void 0 : _a2.clone;
4207
4592
  if (!clone2) return;
4208
4593
  delete clone2.retime;
4209
4594
  if (Object.keys(clone2).length === 0) delete n.effects.clone;
@@ -4214,9 +4599,9 @@ function applyAllRetimeEffects(root, ctx) {
4214
4599
  indexById(root, ctx.idMap);
4215
4600
  const sites = [];
4216
4601
  const collect = (n) => {
4217
- var _a;
4602
+ var _a2;
4218
4603
  if (readCloneRetime(n)) sites.push(n);
4219
- (_a = n.children) == null ? void 0 : _a.forEach(collect);
4604
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(collect);
4220
4605
  };
4221
4606
  collect(root);
4222
4607
  const reachCount = /* @__PURE__ */ new Map();
@@ -4224,7 +4609,7 @@ function applyAllRetimeEffects(root, ctx) {
4224
4609
  let count = 0;
4225
4610
  const visited = /* @__PURE__ */ new Set();
4226
4611
  const walk = (n) => {
4227
- var _a;
4612
+ var _a2;
4228
4613
  if (!n) return;
4229
4614
  if (n !== site && readCloneRetime(n)) count++;
4230
4615
  if (n.type === "use" && n.href) {
@@ -4234,7 +4619,7 @@ function applyAllRetimeEffects(root, ctx) {
4234
4619
  walk(ctx.idMap.get(id));
4235
4620
  }
4236
4621
  }
4237
- (_a = n.children) == null ? void 0 : _a.forEach(walk);
4622
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walk);
4238
4623
  };
4239
4624
  const rootId = stripHash2(site.href);
4240
4625
  if (rootId) {
@@ -4244,8 +4629,8 @@ function applyAllRetimeEffects(root, ctx) {
4244
4629
  reachCount.set(site, count);
4245
4630
  }
4246
4631
  sites.sort((a, b) => {
4247
- var _a, _b;
4248
- return ((_a = reachCount.get(b)) != null ? _a : 0) - ((_b = reachCount.get(a)) != null ? _b : 0);
4632
+ var _a2, _b;
4633
+ return ((_a2 = reachCount.get(b)) != null ? _a2 : 0) - ((_b = reachCount.get(a)) != null ? _b : 0);
4249
4634
  });
4250
4635
  for (const useNode of sites) {
4251
4636
  const retime = readCloneRetime(useNode);
@@ -4312,7 +4697,7 @@ function buildChainClone(targetId, accum, ctx, chain) {
4312
4697
  }
4313
4698
  function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4314
4699
  const visit = (n) => {
4315
- var _a;
4700
+ var _a2;
4316
4701
  const retime = readCloneRetime(n);
4317
4702
  if (n.type === "use" && retime && n.href) {
4318
4703
  const subId = stripHash2(n.href);
@@ -4325,14 +4710,14 @@ function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4325
4710
  }
4326
4711
  clearCloneRetime(n);
4327
4712
  }
4328
- (_a = n.children) == null ? void 0 : _a.forEach(visit);
4713
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
4329
4714
  };
4330
4715
  visit(node);
4331
4716
  }
4332
4717
  function remapKeyframeTimes(node, start, stretch) {
4333
- var _a;
4718
+ var _a2;
4334
4719
  remapKeyframeTimesOnly(node, start, stretch);
4335
- (_a = node.children) == null ? void 0 : _a.forEach((c) => remapKeyframeTimes(c, start, stretch));
4720
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => remapKeyframeTimes(c, start, stretch));
4336
4721
  }
4337
4722
  function remapKeyframeTimesOnly(node, start, stretch) {
4338
4723
  const remap2 = (kfs) => {
@@ -4349,7 +4734,7 @@ function remapKeyframeTimesOnly(node, start, stretch) {
4349
4734
  }
4350
4735
  }
4351
4736
 
4352
- // src/effects/pathSampler.ts
4737
+ // src/effects/text/pathSampler.ts
4353
4738
  var LUT_STEPS = 48;
4354
4739
  var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
4355
4740
  function tokenize(d) {
@@ -4497,7 +4882,7 @@ function createPathSampler(d) {
4497
4882
  };
4498
4883
  }
4499
4884
 
4500
- // src/effects/textPathEffect.ts
4885
+ // src/effects/text/textPathEffect.ts
4501
4886
  var EXTEND_MARGIN_FRAC = 0.15;
4502
4887
  function numRange(v) {
4503
4888
  const read = readAnimatable(v);
@@ -4511,8 +4896,8 @@ function numRange(v) {
4511
4896
  function estimateTextAdvance(node) {
4512
4897
  let chars = 0, maxFont = 16;
4513
4898
  const walk = (el) => {
4514
- var _a, _b;
4515
- const fs = parseFloat(String((_a = el.fontSize) != null ? _a : "")) || 0;
4899
+ var _a2, _b;
4900
+ const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
4516
4901
  if (fs) maxFont = Math.max(maxFont, fs);
4517
4902
  const t = (_b = el.text) != null ? _b : el.textContent;
4518
4903
  if (typeof t === "string") chars += t.length;
@@ -4536,14 +4921,14 @@ function shiftAnimatable(v, by) {
4536
4921
  return out;
4537
4922
  }
4538
4923
  function extendedPathForBrowser(pathD, opts) {
4539
- var _a;
4924
+ var _a2;
4540
4925
  if (opts.pathOverflow === "clip") return { d: pathD, startShift: 0 };
4541
4926
  const sampler = createPathSampler(pathD);
4542
4927
  if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };
4543
4928
  const L = sampler.totalLength;
4544
4929
  const margin = EXTEND_MARGIN_FRAC * L;
4545
4930
  const so = numRange(opts.startOffset);
4546
- const runWidth = numRange(opts.textLength).max || ((_a = opts.advance) != null ? _a : 0);
4931
+ const runWidth = numRange(opts.textLength).max || ((_a2 = opts.advance) != null ? _a2 : 0);
4547
4932
  const startOverflow = Math.max(0, -so.min);
4548
4933
  const endOverflow = Math.max(0, so.max + runWidth - L);
4549
4934
  const startExt = startOverflow > 0 ? startOverflow + margin : 0;
@@ -4564,10 +4949,10 @@ function extendedPathForBrowser(pathD, opts) {
4564
4949
  return { d, startShift: startExt };
4565
4950
  }
4566
4951
  function applyTextPathEffect(node, fx, ctx) {
4567
- var _a;
4568
- if (!fx || typeof fx.path !== "string" || !fx.path) return node;
4952
+ var _a2;
4953
+ if (!fx || typeof fx.pathData !== "string" || !fx.pathData) return node;
4569
4954
  const pathId = genId(ctx, "tpath");
4570
- const { d, startShift } = extendedPathForBrowser(fx.path, {
4955
+ const { d, startShift } = extendedPathForBrowser(fx.pathData, {
4571
4956
  pathOverflow: fx.pathOverflow,
4572
4957
  startOffset: fx.startOffset,
4573
4958
  textLength: fx.textLength,
@@ -4577,7 +4962,7 @@ function applyTextPathEffect(node, fx, ctx) {
4577
4962
  const textPath = {
4578
4963
  type: "textPath",
4579
4964
  href: "#" + pathId,
4580
- children: (_a = node.children) != null ? _a : []
4965
+ children: (_a2 = node.children) != null ? _a2 : []
4581
4966
  };
4582
4967
  if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
4583
4968
  if (fx.method !== void 0) textPath.method = fx.method;
@@ -4592,7 +4977,7 @@ function applyAnimatableNumber(node, attrName, raw) {
4592
4977
  writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
4593
4978
  }
4594
4979
 
4595
- // src/effects/elementFactory.ts
4980
+ // src/effects/text/elementFactory.ts
4596
4981
  var jsonElementFactory = (type, props, children) => {
4597
4982
  const node = { type };
4598
4983
  for (const k in props) if (props[k] !== void 0) node[k] = props[k];
@@ -4601,7 +4986,7 @@ var jsonElementFactory = (type, props, children) => {
4601
4986
  return node;
4602
4987
  };
4603
4988
 
4604
- // src/effects/glyphPathBake.ts
4989
+ // src/effects/text/glyphPathBake.ts
4605
4990
  function fmt(v, decimals) {
4606
4991
  return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
4607
4992
  }
@@ -4647,7 +5032,7 @@ function transformPathData(d, m, decimals = 2) {
4647
5032
  return out;
4648
5033
  }
4649
5034
 
4650
- // src/effects/textGlyphsEffect.ts
5035
+ // src/effects/text/textGlyphsEffect.ts
4651
5036
  var DEFAULT_FONT_SIZE = 16;
4652
5037
  var TEXT_ATTR_KEYS = [
4653
5038
  "fontFamily",
@@ -4707,15 +5092,15 @@ function paintAnimateOf(node) {
4707
5092
  return out;
4708
5093
  }
4709
5094
  function resolveStyle2(node, parent) {
4710
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5095
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
4711
5096
  const isTextRoot = node.type === "text";
4712
5097
  const nodeStyle = node.style;
4713
5098
  const own = (key) => {
4714
- var _a2;
4715
- return isTextRoot ? void 0 : (_a2 = node[key]) != null ? _a2 : nodeStyle == null ? void 0 : nodeStyle[key];
5099
+ var _a3;
5100
+ return isTextRoot ? void 0 : (_a3 = node[key]) != null ? _a3 : nodeStyle == null ? void 0 : nodeStyle[key];
4716
5101
  };
4717
5102
  const res = {
4718
- fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
5103
+ fontFamily: (_a2 = str(node.fontFamily)) != null ? _a2 : parent.fontFamily,
4719
5104
  fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
4720
5105
  fill: (_c = node.fill) != null ? _c : parent.fill,
4721
5106
  stroke: (_d = node.stroke) != null ? _d : parent.stroke,
@@ -4732,10 +5117,10 @@ function resolveStyle2(node, parent) {
4732
5117
  return res;
4733
5118
  }
4734
5119
  function rootStyleOf(node) {
4735
- var _a, _b, _c;
5120
+ var _a2, _b, _c;
4736
5121
  return {
4737
5122
  fontFamily: str(node.fontFamily),
4738
- fontSize: (_a = parseLen(node.fontSize)) != null ? _a : DEFAULT_FONT_SIZE,
5123
+ fontSize: (_a2 = parseLen(node.fontSize)) != null ? _a2 : DEFAULT_FONT_SIZE,
4739
5124
  fill: node.fill,
4740
5125
  stroke: node.stroke,
4741
5126
  strokeWidth: node.strokeWidth,
@@ -4756,9 +5141,9 @@ function paintOf(s) {
4756
5141
  return p;
4757
5142
  }
4758
5143
  function glyphFontFor(s, glyphs, soleFont, warnings) {
4759
- var _a;
5144
+ var _a2;
4760
5145
  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 : "") + '"');
5146
+ if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a2 = s.fontFamily) != null ? _a2 : "") + '"');
4762
5147
  return gf;
4763
5148
  }
4764
5149
  function soleFontOf(glyphs) {
@@ -4780,19 +5165,19 @@ function missingGlyphBoxEm(advanceEm, ascentEm) {
4780
5165
  return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
4781
5166
  }
4782
5167
  function materialiseGlyphTextHorizontal(node, opts) {
4783
- var _a, _b, _c, _d;
5168
+ var _a2, _b, _c, _d;
4784
5169
  const { glyphs, create = jsonElementFactory, warnings } = opts;
4785
5170
  const soleFont = soleFontOf(glyphs);
4786
- const pen = { x: (_a = parseLen(node.x)) != null ? _a : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
5171
+ const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
4787
5172
  const placements = [];
4788
5173
  const lines = [{ start: pen.x, end: pen.x }];
4789
5174
  let line = 0;
4790
5175
  const renderChars = (content, s) => {
4791
- var _a2;
5176
+ var _a3;
4792
5177
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4793
5178
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4794
5179
  const scale = s.fontSize / upm;
4795
- const ascentEm = (_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm;
5180
+ const ascentEm = (_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm;
4796
5181
  const paint = paintOf(s);
4797
5182
  for (let i = 0; i < content.length; i++) {
4798
5183
  const ch = content.charAt(i);
@@ -4812,7 +5197,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4812
5197
  }
4813
5198
  };
4814
5199
  const walk = (el, parentStyle) => {
4815
- var _a2, _b2, _c2, _d2;
5200
+ var _a3, _b2, _c2, _d2;
4816
5201
  const s = resolveStyle2(el, parentStyle);
4817
5202
  const x = parseLen(el.x);
4818
5203
  const y = parseLen(el.y);
@@ -4822,7 +5207,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4822
5207
  lines.push({ start: pen.x, end: pen.x });
4823
5208
  }
4824
5209
  if (y !== void 0) pen.y = y;
4825
- pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
5210
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4826
5211
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4827
5212
  const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4828
5213
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
@@ -4843,8 +5228,8 @@ function materialiseGlyphTextHorizontal(node, opts) {
4843
5228
  return toGroup(node, buildPaths(placements, create, warnings), create);
4844
5229
  }
4845
5230
  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);
5231
+ var _a2, _b, _c, _d, _e, _f;
5232
+ if ((_a2 = opts.alongPath) == null ? void 0 : _a2.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
4848
5233
  const { glyphs, warnings } = opts;
4849
5234
  const soleFont = soleFontOf(glyphs);
4850
5235
  const pen = { x: (_b = parseLen(node.x)) != null ? _b : 0, y: (_c = parseLen(node.y)) != null ? _c : 0 };
@@ -4852,11 +5237,11 @@ function layoutGlyphTextChars(node, opts) {
4852
5237
  const lines = [{ start: pen.x, end: pen.x }];
4853
5238
  let line = 0;
4854
5239
  const renderChars = (content, s) => {
4855
- var _a2;
5240
+ var _a3;
4856
5241
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4857
5242
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4858
5243
  const scale = s.fontSize / upm;
4859
- const ascent = ((_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm) * scale;
5244
+ const ascent = ((_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm) * scale;
4860
5245
  for (let i = 0; i < content.length; i++) {
4861
5246
  const ch = content.charAt(i);
4862
5247
  const g = gf == null ? void 0 : gf.glyphs[ch];
@@ -4867,7 +5252,7 @@ function layoutGlyphTextChars(node, opts) {
4867
5252
  }
4868
5253
  };
4869
5254
  const walk = (el, parentStyle) => {
4870
- var _a2, _b2, _c2, _d2;
5255
+ var _a3, _b2, _c2, _d2;
4871
5256
  const s = resolveStyle2(el, parentStyle);
4872
5257
  const x = parseLen(el.x);
4873
5258
  const y = parseLen(el.y);
@@ -4877,7 +5262,7 @@ function layoutGlyphTextChars(node, opts) {
4877
5262
  lines.push({ start: pen.x, end: pen.x });
4878
5263
  }
4879
5264
  if (y !== void 0) pen.y = y;
4880
- pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
5265
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4881
5266
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4882
5267
  const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4883
5268
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
@@ -4909,7 +5294,7 @@ function layoutGlyphTextChars(node, opts) {
4909
5294
  });
4910
5295
  }
4911
5296
  function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4912
- var _a, _b;
5297
+ var _a2, _b;
4913
5298
  const { glyphs, warnings, alongPath } = opts;
4914
5299
  const sampler = createPathSampler(pathD);
4915
5300
  if (!sampler) {
@@ -4920,9 +5305,9 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4920
5305
  const chars = [];
4921
5306
  let adv = 0;
4922
5307
  const walk = (el, parentStyle) => {
4923
- var _a2, _b2, _c;
5308
+ var _a3, _b2, _c;
4924
5309
  const s = resolveStyle2(el, parentStyle);
4925
- const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
5310
+ const content = (_a3 = str(el[TEXT_CONTENT_ATTR])) != null ? _a3 : str(el[TEXT_ATTR]);
4926
5311
  if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
4927
5312
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4928
5313
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
@@ -4942,7 +5327,7 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4942
5327
  walk(node, rootStyleOf(node));
4943
5328
  const width = adv;
4944
5329
  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;
5330
+ 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
5331
  const k = tlv > 0 && width > 0 ? tlv / width : 1;
4947
5332
  const so = readAnimatable(alongPath == null ? void 0 : alongPath.startOffset);
4948
5333
  const { along: alongOffset, perp } = alongPathNodeOffsets(node);
@@ -4974,9 +5359,9 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4974
5359
  const cells = [];
4975
5360
  let adv = 0;
4976
5361
  const walk = (el, parentStyle) => {
4977
- var _a, _b, _c;
5362
+ var _a2, _b, _c;
4978
5363
  const s = resolveStyle2(el, parentStyle);
4979
- const content = (_a = str(el[TEXT_CONTENT_ATTR])) != null ? _a : str(el[TEXT_ATTR]);
5364
+ const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
4980
5365
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
4981
5366
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4982
5367
  if (gf) {
@@ -5013,9 +5398,9 @@ function alongAffine(sampler, dist, scale, widthEm, perp = 0) {
5013
5398
  return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];
5014
5399
  }
5015
5400
  function alongPathNodeOffsets(node) {
5016
- var _a, _b, _c;
5401
+ var _a2, _b, _c;
5017
5402
  return {
5018
- along: ((_a = parseLen(node.x)) != null ? _a : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
5403
+ along: ((_a2 = parseLen(node.x)) != null ? _a2 : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
5019
5404
  perp: (_c = parseLen(node.dy)) != null ? _c : 0
5020
5405
  };
5021
5406
  }
@@ -5055,7 +5440,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
5055
5440
  return toGroup(node, buildPaths(placements, create, warnings), create);
5056
5441
  }
5057
5442
  function numTrackOf(raw) {
5058
- var _a;
5443
+ var _a2;
5059
5444
  const r = readAnimatable(raw);
5060
5445
  if (r.kind === "animated" /* Animated */ && r.keyframes.length >= 2) {
5061
5446
  const kfs = [...r.keyframes].sort((k1, k2) => (Number(k1.time) || 0) - (Number(k2.time) || 0));
@@ -5078,7 +5463,7 @@ function numTrackOf(raw) {
5078
5463
  }
5079
5464
  };
5080
5465
  }
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;
5466
+ 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
5467
  return { animated: false, times: [], at: () => v };
5083
5468
  }
5084
5469
  function mergeTrackTimes(a, b) {
@@ -5154,7 +5539,7 @@ function paintProps(paint) {
5154
5539
  return p;
5155
5540
  }
5156
5541
  function missingGlyphProps(isMissing) {
5157
- return isMissing ? { class: MISSING_GLYPH_CLASS_NAME } : {};
5542
+ return isMissing ? { [CLASS_ATTR]: MISSING_GLYPH_CLASS_NAME } : {};
5158
5543
  }
5159
5544
  function buildPaths(placements, create, warnings) {
5160
5545
  if (!placements.length) {
@@ -5198,20 +5583,20 @@ function materialiseGlyphText(node, opts) {
5198
5583
  function applyTextGlyphsEffect(node, fx, ctx) {
5199
5584
  if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
5200
5585
  if (!ctx.glyphs) {
5201
- ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
5586
+ ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
5202
5587
  return node;
5203
5588
  }
5204
5589
  return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5205
5590
  }
5206
5591
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
5207
5592
  if (!ctx.glyphs) {
5208
- ctx.warnings.push("textGlyphs: no definitions.glyphs");
5593
+ ctx.warnings.push("textGlyphs: no definitions.fonts");
5209
5594
  return null;
5210
5595
  }
5211
5596
  return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5212
5597
  }
5213
5598
 
5214
- // src/effects/strokeTrimEffect.ts
5599
+ // src/effects/stroke/strokeTrimEffect.ts
5215
5600
  function applyStrokeTrimEffect(node, strokeTrim, ctx) {
5216
5601
  if (!strokeTrim) return node;
5217
5602
  const combined = strokeTrim.subPaths === PxStrokeTrimSubPaths.combined;
@@ -5347,12 +5732,11 @@ function getOffsetIndexRange(minMaxOffset) {
5347
5732
  ];
5348
5733
  }
5349
5734
  function readScalarValues(r) {
5350
- var _a;
5351
5735
  if (r.kind === "absent" /* Absent */) return [];
5352
5736
  if (r.kind === "static" /* Static */) return [r.value];
5353
5737
  const out = [];
5354
5738
  for (const kf of r.keyframes) {
5355
- const v = (_a = kf.value) != null ? _a : kf.v;
5739
+ const v = kfValue(kf);
5356
5740
  if (typeof v === "number") out.push(v);
5357
5741
  }
5358
5742
  return out;
@@ -5362,14 +5746,11 @@ function computeAnimAttr(read, map) {
5362
5746
  if (read.kind === "static" /* Static */) return { kind: "static" /* Static */, value: map(read.value) };
5363
5747
  return {
5364
5748
  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
- }),
5749
+ keyframes: read.keyframes.map((kf) => ({
5750
+ time: kfTime(kf),
5751
+ value: map(kfValue(kf)),
5752
+ easing: kfEasing(kf)
5753
+ })),
5373
5754
  loop: read.loop
5374
5755
  };
5375
5756
  }
@@ -5379,7 +5760,6 @@ function applyAttr(node, attrName, attr) {
5379
5760
  }
5380
5761
  var OPACITY_STEP_MS = 10;
5381
5762
  function computeOpacityFromRange(rangeRead) {
5382
- var _a, _b, _c, _d, _e, _f;
5383
5763
  const hide = (v) => v[0] === v[1];
5384
5764
  if (rangeRead.kind === "absent" /* Absent */) return void 0;
5385
5765
  if (rangeRead.kind === "static" /* Static */) return hide(rangeRead.value) ? { kind: "static" /* Static */, value: 0 } : void 0;
@@ -5387,7 +5767,7 @@ function computeOpacityFromRange(rangeRead) {
5387
5767
  let anyHide = false;
5388
5768
  let allHide = true;
5389
5769
  for (const kf of kfs) {
5390
- if (hide((_a = kf.value) != null ? _a : kf.v)) anyHide = true;
5770
+ if (hide(kfValue(kf))) anyHide = true;
5391
5771
  else allHide = false;
5392
5772
  }
5393
5773
  if (!anyHide) return void 0;
@@ -5397,10 +5777,10 @@ function computeOpacityFromRange(rangeRead) {
5397
5777
  const kf = kfs[i];
5398
5778
  const prevKf = i > 0 ? kfs[i - 1] : void 0;
5399
5779
  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;
5780
+ const t = kfTime(kf);
5781
+ const thisHide = hide(kfValue(kf));
5782
+ const prevHide = prevKf ? thisHide && hide(kfValue(prevKf)) : thisHide;
5783
+ const nextHide = nextKf ? thisHide && hide(kfValue(nextKf)) : thisHide;
5404
5784
  if (prevHide && !nextHide) {
5405
5785
  out.push({ time: t, value: 0 });
5406
5786
  out.push({ time: t + OPACITY_STEP_MS, value: 1 });
@@ -5415,14 +5795,11 @@ function computeOpacityFromRange(rangeRead) {
5415
5795
  function readRangeWithCrossings(raw) {
5416
5796
  const r = readAnimatable(raw);
5417
5797
  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
- });
5798
+ const kfs = r.keyframes.map((kf) => ({
5799
+ time: kfTime(kf),
5800
+ value: kfValue(kf),
5801
+ easing: kfEasing(kf)
5802
+ }));
5426
5803
  const hasReverse = kfs.some((kf) => kf.value[0] > kf.value[1]);
5427
5804
  if (!hasReverse) {
5428
5805
  return {
@@ -5519,20 +5896,20 @@ function pxBezierPathLength(path) {
5519
5896
  return total;
5520
5897
  }
5521
5898
  function segmentLength(path, from, to) {
5522
- var _a, _b, _c, _d;
5899
+ var _a2, _b, _c, _d;
5523
5900
  const v = path.v;
5524
5901
  const p0 = v[from];
5525
5902
  const p3 = v[to];
5526
- const p1 = (_b = (_a = path.o) == null ? void 0 : _a[from]) != null ? _b : p0;
5903
+ const p1 = (_b = (_a2 = path.o) == null ? void 0 : _a2[from]) != null ? _b : p0;
5527
5904
  const p2 = (_d = (_c = path.i) == null ? void 0 : _c[to]) != null ? _d : p3;
5528
5905
  const lut = bezier2D_arcLengthLUT(p0, p1, p2, p3);
5529
5906
  return lut.ds[lut.ds.length - 1];
5530
5907
  }
5531
5908
  var ARC_KAPPA = 0.5522847498307936;
5532
5909
  function shapeToPathD(node) {
5533
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5910
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5534
5911
  if (node.type === "rect") {
5535
- const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
5912
+ const x = Number((_a2 = node.x) != null ? _a2 : 0), y = Number((_b = node.y) != null ? _b : 0);
5536
5913
  const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
5537
5914
  return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
5538
5915
  }
@@ -5550,7 +5927,7 @@ function shapeToPathD(node) {
5550
5927
 
5551
5928
  // src/effects/PlayerEffectsUtil.ts
5552
5929
  function applyPlayerEffects(root) {
5553
- var _a, _b;
5930
+ var _a2, _b;
5554
5931
  const ctx = {
5555
5932
  defs: [],
5556
5933
  warnings: [],
@@ -5561,8 +5938,8 @@ function applyPlayerEffects(root) {
5561
5938
  maskAncestorChains: /* @__PURE__ */ new Map(),
5562
5939
  // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
5563
5940
  // 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
5941
+ engine: resolveTimelineEngine((_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.engine),
5942
+ glyphs: (_b = getDefs(root)) == null ? void 0 : _b.fonts
5566
5943
  };
5567
5944
  const working = clone(root);
5568
5945
  indexById(working, ctx.idMap);
@@ -5585,7 +5962,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5585
5962
  let consumedByGlyphs = false;
5586
5963
  if (text == null ? void 0 : text.useGlyphs) {
5587
5964
  if (textPath) {
5588
- const pathD = typeof textPath.path === "string" ? textPath.path : void 0;
5965
+ const pathD = typeof textPath.pathData === "string" ? textPath.pathData : void 0;
5589
5966
  const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textPath.startOffset, textPath.textLength, textPath.pathOverflow);
5590
5967
  if (glyphed) {
5591
5968
  n = glyphed;
@@ -5618,27 +5995,7 @@ function applyPlayerEffects_retime(node, ctx) {
5618
5995
  return node;
5619
5996
  }
5620
5997
 
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
- };
5998
+ // src/materialise/PxOffsetPathMaterialiser.ts
5642
5999
  function cubicAt(p0, c1, c2, p1, t) {
5643
6000
  const u = 1 - t;
5644
6001
  const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
@@ -5662,7 +6019,7 @@ var fmt2 = (n) => {
5662
6019
  return Object.is(r, -0) ? "0" : String(r);
5663
6020
  };
5664
6021
  function buildOffsetPath(propAnim) {
5665
- var _a, _b, _c;
6022
+ var _a2, _b, _c;
5666
6023
  if (propAnim.alongPathMode !== "offsetPath") return void 0;
5667
6024
  const kfs = propAnim.keyframes;
5668
6025
  if (!kfs || kfs.length < 2) return void 0;
@@ -5675,7 +6032,7 @@ function buildOffsetPath(propAnim) {
5675
6032
  if (!tr || tr.length < 2) return void 0;
5676
6033
  const parts = Object.keys(v);
5677
6034
  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];
6035
+ const o = (_a2 = v == null ? void 0 : v.origin) != null ? _a2 : [0, 0];
5679
6036
  if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5680
6037
  points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5681
6038
  }
@@ -5706,7 +6063,7 @@ function buildOffsetPath(propAnim) {
5706
6063
  }
5707
6064
  function materialiseOffsetPathsInTree(root) {
5708
6065
  const walk = (node) => {
5709
- var _a;
6066
+ var _a2;
5710
6067
  let out = node;
5711
6068
  const anim = node.animate;
5712
6069
  const transform = anim == null ? void 0 : anim["transform"];
@@ -5714,16 +6071,16 @@ function materialiseOffsetPathsInTree(root) {
5714
6071
  const built = buildOffsetPath(transform);
5715
6072
  if (built) {
5716
6073
  const newAnimate = __spreadValues({}, anim);
5717
- delete newAnimate["transform"];
6074
+ delete newAnimate[TRANSFORM_ATTR];
5718
6075
  const distance = { keyframes: built.distanceKfs };
5719
6076
  if (transform.loop !== void 0) distance.loop = transform.loop;
5720
- newAnimate["offsetDistance"] = distance;
6077
+ newAnimate[OFFSET_DISTANCE_ATTR] = distance;
5721
6078
  const staticTr = node.transform;
5722
6079
  let newTransform = staticTr;
5723
6080
  if (staticTr && typeof staticTr === "object") {
5724
6081
  const t = __spreadValues({}, staticTr);
5725
- delete t["translate"];
5726
- delete t["origin"];
6082
+ delete t[TRANSFORM_PART.translate];
6083
+ delete t[TRANSFORM_PART.origin];
5727
6084
  newTransform = Object.keys(t).length ? t : void 0;
5728
6085
  }
5729
6086
  out = __spreadProps(__spreadValues({}, node), {
@@ -5739,7 +6096,7 @@ function materialiseOffsetPathsInTree(root) {
5739
6096
  else delete out.transform;
5740
6097
  }
5741
6098
  }
5742
- if ((_a = out.children) == null ? void 0 : _a.length) {
6099
+ if ((_a2 = out.children) == null ? void 0 : _a2.length) {
5743
6100
  const children = out.children.map(walk);
5744
6101
  if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
5745
6102
  }
@@ -5748,14 +6105,14 @@ function materialiseOffsetPathsInTree(root) {
5748
6105
  return walk(root);
5749
6106
  }
5750
6107
 
5751
- // src/PxAnimatorMaterialiseAll.ts
6108
+ // src/materialise/PxAnimatorMaterialiseAll.ts
5752
6109
  function materialiseAllInTree(doc, engine, opts) {
5753
- var _a, _b;
6110
+ var _a2, _b;
5754
6111
  let root = applyPlayerEffects(doc).root;
5755
6112
  root = materialiseOffsetPathsInTree(root);
5756
- const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
6113
+ const duration = (_b = (_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.duration) != null ? _b : DEFAULT_DURATION_MS;
5757
6114
  root = materialiseInternalLoopsInTree(root, duration);
5758
- if (engine === PxAnimatorEngine.waapi) {
6115
+ if (engine === PxTimelineEngine.native) {
5759
6116
  root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5760
6117
  root = materialiseAnimatedUseInstances(root);
5761
6118
  root = pruneUnreferencedDefs(root);
@@ -5765,9 +6122,9 @@ function materialiseAllInTree(doc, engine, opts) {
5765
6122
  function pruneUnreferencedDefs(root) {
5766
6123
  const stripHash3 = (h) => h.startsWith("#") ? h.slice(1) : h;
5767
6124
  const walk = (n, fn) => {
5768
- var _a;
6125
+ var _a2;
5769
6126
  fn(n);
5770
- (_a = n.children) == null ? void 0 : _a.forEach((c) => walk(c, fn));
6127
+ (_a2 = n.children) == null ? void 0 : _a2.forEach((c) => walk(c, fn));
5771
6128
  };
5772
6129
  let changed = true;
5773
6130
  while (changed) {
@@ -5792,7 +6149,7 @@ function pruneUnreferencedDefs(root) {
5792
6149
  return root;
5793
6150
  }
5794
6151
 
5795
- // src/PxFrameLoop.ts
6152
+ // src/playback/PxFrameLoop.ts
5796
6153
  function requestFrame(cb) {
5797
6154
  const g = globalThis;
5798
6155
  if (typeof g.requestAnimationFrame === "function") return g.requestAnimationFrame(cb);
@@ -5807,9 +6164,9 @@ function cancelFrame(handle) {
5807
6164
  g.clearTimeout(handle);
5808
6165
  }
5809
6166
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5810
- var _a;
6167
+ var _a2;
5811
6168
  const config = getAnimatorConfig(doc) || {};
5812
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
6169
+ const bindings = getNormalisedBindings(doc, PxTimelineEngine.js);
5813
6170
  const _iterations = config.iterations;
5814
6171
  let iterations = 1;
5815
6172
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -5818,7 +6175,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5818
6175
  const duration = +(config.duration || DEFAULT_DURATION_MS);
5819
6176
  const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
5820
6177
  const direction = config.direction || "normal";
5821
- const fill = (_a = config.fill) != null ? _a : "forwards";
6178
+ const fill = (_a2 = config.fill) != null ? _a2 : "forwards";
5822
6179
  const fillsForwards = fill === "forwards" || fill === "both";
5823
6180
  const fillsBackwards = fill === "backwards" || fill === "both";
5824
6181
  let timerId = null;
@@ -5880,7 +6237,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5880
6237
  }
5881
6238
  }
5882
6239
  const tick = () => {
5883
- var _a2, _b;
6240
+ var _a3, _b;
5884
6241
  if (!adapter.isConnected()) {
5885
6242
  pauseAnim();
5886
6243
  return;
@@ -5896,7 +6253,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5896
6253
  renderFrame(0);
5897
6254
  if (!finishCalled) {
5898
6255
  finishCalled = true;
5899
- (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
6256
+ (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
5900
6257
  }
5901
6258
  return;
5902
6259
  }
@@ -5988,17 +6345,17 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5988
6345
  }
5989
6346
  };
5990
6347
  const cancelAnim = () => {
5991
- var _a2;
6348
+ var _a3;
5992
6349
  pauseAnim();
5993
6350
  timeBeforeLastStartMs = 0;
5994
6351
  lastStartedTs = 0;
5995
6352
  playing = false;
5996
6353
  finishCalled = false;
5997
6354
  renderFrame(timeBeforeLastStartMs);
5998
- (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
6355
+ (_a3 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a3.call(callbacks);
5999
6356
  };
6000
6357
  const finishAnim = (callOnFinish = true) => {
6001
- var _a2;
6358
+ var _a3;
6002
6359
  if (Number.isFinite(totalDuration)) {
6003
6360
  timeBeforeLastStartMs = totalDuration;
6004
6361
  } else {
@@ -6013,7 +6370,7 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6013
6370
  renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
6014
6371
  if (callOnFinish && !finishCalled) {
6015
6372
  finishCalled = true;
6016
- (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
6373
+ (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
6017
6374
  }
6018
6375
  };
6019
6376
  const api = {
@@ -6023,14 +6380,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6023
6380
  return _isPlaying();
6024
6381
  },
6025
6382
  "play": () => {
6026
- var _a2;
6383
+ var _a3;
6027
6384
  startAnim();
6028
- (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
6385
+ (_a3 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a3.call(callbacks);
6029
6386
  },
6030
6387
  "pause": () => {
6031
- var _a2;
6388
+ var _a3;
6032
6389
  pauseAnim();
6033
- (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
6390
+ (_a3 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a3.call(callbacks);
6034
6391
  },
6035
6392
  "cancel": () => {
6036
6393
  cancelAnim();
@@ -6062,9 +6419,9 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6062
6419
  renderFrame(getAnimCurrentTime());
6063
6420
  },
6064
6421
  "destroy": () => {
6065
- var _a2;
6422
+ var _a3;
6066
6423
  api.cancel();
6067
- (_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
6424
+ (_a3 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a3.call(callbacks);
6068
6425
  }
6069
6426
  };
6070
6427
  return api;
@@ -6120,9 +6477,9 @@ function lerp(a, b, f) {
6120
6477
  return a + (b - a) * f;
6121
6478
  }
6122
6479
  function interpParts(kfs, t) {
6123
- var _a, _b, _c, _d, _e, _f, _g;
6480
+ var _a2, _b, _c, _d, _e, _f, _g;
6124
6481
  if (!kfs.length) return {};
6125
- if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value || {};
6482
+ if (t <= ((_a2 = kfs[0].time) != null ? _a2 : 0)) return kfs[0].value || {};
6126
6483
  if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value || {};
6127
6484
  let i = 0;
6128
6485
  while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
@@ -6153,10 +6510,10 @@ function nodeMatrix(node, t) {
6153
6510
  return IDENTITY;
6154
6511
  }
6155
6512
  function evalScalar(animated, staticVal, fallback, t) {
6156
- var _a, _b, _c, _d, _e, _f;
6513
+ var _a2, _b, _c, _d, _e, _f;
6157
6514
  if (animated && animated.keyframes && animated.keyframes.length) {
6158
6515
  const kfs = animated.keyframes;
6159
- if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value;
6516
+ if (t <= ((_a2 = kfs[0].time) != null ? _a2 : 0)) return kfs[0].value;
6160
6517
  if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value;
6161
6518
  let i = 0;
6162
6519
  while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
@@ -6169,9 +6526,9 @@ function evalScalar(animated, staticVal, fallback, t) {
6169
6526
  var CONTAINER_TYPES = /* @__PURE__ */ new Set(["svg", "g", "symbol"]);
6170
6527
  var SKIP_TYPES = /* @__PURE__ */ new Set(["defs", "mask", "clipPath", "title"]);
6171
6528
  function buildIdMap2(node, map) {
6172
- var _a;
6529
+ var _a2;
6173
6530
  if (typeof node.id === "string") map.set(node.id, node);
6174
- (_a = node.children) == null ? void 0 : _a.forEach((c) => buildIdMap2(c, map));
6531
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => buildIdMap2(c, map));
6175
6532
  }
6176
6533
  function num(v) {
6177
6534
  return v === void 0 || v === null ? 0 : Number(v);
@@ -6180,7 +6537,7 @@ function round(n) {
6180
6537
  return Math.round(n * 100) / 100 + 0;
6181
6538
  }
6182
6539
  function geomKey(node) {
6183
- var _a;
6540
+ var _a2;
6184
6541
  switch (node.type) {
6185
6542
  case "rect":
6186
6543
  return num(node.width) + "," + num(node.height) + "," + num(node.x) + "," + num(node.y);
@@ -6189,14 +6546,14 @@ function geomKey(node) {
6189
6546
  case "circle":
6190
6547
  return num(node.r) + "," + num(node.cx) + "," + num(node.cy);
6191
6548
  case "path":
6192
- return String((_a = node.d) != null ? _a : "");
6549
+ return String((_a2 = node.d) != null ? _a2 : "");
6193
6550
  default:
6194
6551
  return "";
6195
6552
  }
6196
6553
  }
6197
6554
  function describePrimitive(node, m, t) {
6198
- var _a, _b, _c, _d, _e;
6199
- const fill = (_a = node.fill) != null ? _a : "";
6555
+ var _a2, _b, _c, _d, _e;
6556
+ const fill = (_a2 = node.fill) != null ? _a2 : "";
6200
6557
  const stroke = (_b = node.stroke) != null ? _b : "";
6201
6558
  const sw = (_d = (_c = node["stroke-width"]) != null ? _c : node.strokeWidth) != null ? _d : "";
6202
6559
  const opacity = round(evalScalar((_e = node.animate) == null ? void 0 : _e.opacity, node.opacity, 1, t));
@@ -6205,7 +6562,7 @@ function describePrimitive(node, m, t) {
6205
6562
  return node.type + "|" + geomKey(node) + "|[" + mat + "]|f:" + fill + "|s:" + stroke + "|sw:" + (num(sw) || "") + "|o:" + opacity + "|m:" + masked;
6206
6563
  }
6207
6564
  function flatten(node, parent, t, idMap, out) {
6208
- var _a;
6565
+ var _a2;
6209
6566
  const type = node.type || "";
6210
6567
  if (SKIP_TYPES.has(type)) return;
6211
6568
  const m = mul(parent, nodeMatrix(node, t));
@@ -6218,33 +6575,33 @@ function flatten(node, parent, t, idMap, out) {
6218
6575
  return;
6219
6576
  }
6220
6577
  if (CONTAINER_TYPES.has(type)) {
6221
- (_a = node.children) == null ? void 0 : _a.forEach((c) => flatten(c, m, t, idMap, out));
6578
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => flatten(c, m, t, idMap, out));
6222
6579
  return;
6223
6580
  }
6224
6581
  out.push(describePrimitive(node, m, t));
6225
6582
  }
6226
6583
  function collectSampleTimes(node, into) {
6227
- var _a;
6584
+ var _a2;
6228
6585
  into.add(0);
6229
6586
  const scanAnim = (anim) => {
6230
- var _a2;
6587
+ var _a3;
6231
6588
  if (!anim || typeof anim !== "object") return;
6232
6589
  for (const key of Object.keys(anim)) {
6233
- const kfs = (_a2 = anim[key]) == null ? void 0 : _a2.keyframes;
6590
+ const kfs = (_a3 = anim[key]) == null ? void 0 : _a3.keyframes;
6234
6591
  if (Array.isArray(kfs)) kfs.forEach((kf) => {
6235
- var _a3;
6236
- return into.add((_a3 = kf.time) != null ? _a3 : 0);
6592
+ var _a4;
6593
+ return into.add((_a4 = kf.time) != null ? _a4 : 0);
6237
6594
  });
6238
6595
  }
6239
6596
  };
6240
6597
  scanAnim(node.animate);
6241
6598
  if (node.transform && typeof node.transform === "object" && node.transform.keyframes) {
6242
6599
  node.transform.keyframes.forEach((kf) => {
6243
- var _a2;
6244
- return into.add((_a2 = kf.time) != null ? _a2 : 0);
6600
+ var _a3;
6601
+ return into.add((_a3 = kf.time) != null ? _a3 : 0);
6245
6602
  });
6246
6603
  }
6247
- (_a = node.children) == null ? void 0 : _a.forEach((c) => collectSampleTimes(c, into));
6604
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((c) => collectSampleTimes(c, into));
6248
6605
  }
6249
6606
  function visualModelAt(root, t) {
6250
6607
  const idMap = /* @__PURE__ */ new Map();
@@ -6278,7 +6635,195 @@ function subtractMultiset(a, b) {
6278
6635
  }
6279
6636
  return extra;
6280
6637
  }
6638
+
6639
+ // src/playback/PxAnimatorConfigPatch.ts
6640
+ var FLAT_ONLY_KEYS = [
6641
+ "timelineSource",
6642
+ "scroll",
6643
+ "trigger",
6644
+ "delay",
6645
+ "iterations",
6646
+ "direction",
6647
+ "fill",
6648
+ "resetOnFinish",
6649
+ "duration",
6650
+ "mode",
6651
+ "frameRate"
6652
+ ];
6653
+ var CONTENT_KEYS = ["definitions", "animateById"];
6654
+ var isPlainObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
6655
+ var timelineTypeOf = (t) => isPlainObject(t) && typeof t.type === "string" ? t.type : "time";
6656
+ var isScrollish = (type) => type === "scroll" || type === "view";
6657
+ function mergePlain(base, patch) {
6658
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6659
+ for (const key of Object.keys(patch)) {
6660
+ const value = patch[key];
6661
+ if (value === null) {
6662
+ delete out[key];
6663
+ continue;
6664
+ }
6665
+ if (isPlainObject(value)) {
6666
+ out[key] = mergePlain(out[key], value);
6667
+ continue;
6668
+ }
6669
+ out[key] = value;
6670
+ }
6671
+ return out;
6672
+ }
6673
+ function mergeTimeline(base, patch, warn) {
6674
+ const baseType = timelineTypeOf(base);
6675
+ const patchNamesType = isPlainObject(patch) && typeof patch.type === "string";
6676
+ const patchType = patchNamesType ? String(patch.type) : baseType;
6677
+ let merged;
6678
+ if (patchType !== baseType) {
6679
+ const carried = {};
6680
+ if (isPlainObject(base)) {
6681
+ for (const k of PX_TIMELINE_SHARED_KEYS) {
6682
+ if (base[k] !== void 0) carried[k] = base[k];
6683
+ }
6684
+ }
6685
+ merged = mergePlain(carried, patch);
6686
+ } else {
6687
+ merged = mergePlain(base, patch);
6688
+ }
6689
+ if (isScrollish(patchType)) {
6690
+ for (const k of PX_TIME_ONLY_TIMELINE_KEYS) {
6691
+ if (merged[k] === void 0) continue;
6692
+ warn("animator.timeline." + k + ": no slot on a '" + patchType + "' timeline \u2014 dropped");
6693
+ delete merged[k];
6694
+ }
6695
+ if (merged.iterations === "infinite") {
6696
+ warn("animator.timeline.iterations: 'infinite' cannot map onto a scroll range \u2014 dropped");
6697
+ delete merged.iterations;
6698
+ }
6699
+ }
6700
+ return merged;
6701
+ }
6702
+ function foldAnimatorConfigShortcuts(config, shortcuts) {
6703
+ let base;
6704
+ if (typeof config === "string") {
6705
+ try {
6706
+ base = JSON.parse(config);
6707
+ } catch (e) {
6708
+ console.warn("animator config: not valid JSON \u2014 ignored", e);
6709
+ base = void 0;
6710
+ }
6711
+ } else {
6712
+ base = config != null ? config : void 0;
6713
+ }
6714
+ const { duration, delay, iterations, startOn } = shortcuts;
6715
+ if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6716
+ return base;
6717
+ }
6718
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6719
+ const timeline = __spreadValues({}, out.timeline);
6720
+ if (duration !== void 0) timeline.duration = duration;
6721
+ if (delay !== void 0) timeline.delay = delay;
6722
+ if (iterations !== void 0) timeline.iterations = iterations;
6723
+ if (startOn !== void 0) {
6724
+ timeline.trigger = __spreadProps(__spreadValues({}, timeline.trigger), { startOn });
6725
+ }
6726
+ out.timeline = timeline;
6727
+ return out;
6728
+ }
6729
+ function mergeAnimatorConfig(base, patch) {
6730
+ const warnings = [];
6731
+ const warn = (m) => warnings.push(m);
6732
+ if (patch === null) return { config: void 0, warnings };
6733
+ if (!isPlainObject(patch) || Object.keys(patch).length === 0) {
6734
+ return { config: base, warnings };
6735
+ }
6736
+ const flatInBase = isPlainObject(base) ? FLAT_ONLY_KEYS.filter((k) => base[k] !== void 0) : [];
6737
+ if (flatInBase.length) {
6738
+ warn("animator: the base carries the flat runtime spelling (" + flatInBase.join(", ") + "); the patch merges the wire spelling only");
6739
+ }
6740
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6741
+ for (const key of Object.keys(patch)) {
6742
+ const value = patch[key];
6743
+ if (value === null) {
6744
+ delete out[key];
6745
+ continue;
6746
+ }
6747
+ if (key === "timeline") {
6748
+ out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
6749
+ continue;
6750
+ }
6751
+ if (isPlainObject(value)) {
6752
+ out[key] = mergePlain(out[key], value);
6753
+ continue;
6754
+ }
6755
+ out[key] = value;
6756
+ }
6757
+ return { config: out, warnings };
6758
+ }
6759
+ function applyAnimatorConfig(doc, patch, opts) {
6760
+ var _a2, _b;
6761
+ const reset = !!(opts == null ? void 0 : opts.resetDefaults);
6762
+ if (!doc || (patch === void 0 || !reset && (patch === null || !isPlainObject(patch) || !Object.keys(patch).length))) {
6763
+ return { doc, warnings: [] };
6764
+ }
6765
+ const anyDoc = doc;
6766
+ const atRoot = isPlainObject(anyDoc.animator);
6767
+ const atMeta = !atRoot && isPlainObject((_a2 = anyDoc.meta) == null ? void 0 : _a2.animator);
6768
+ const current = atRoot ? anyDoc.animator : atMeta ? anyDoc.meta.animator : void 0;
6769
+ const warnings = [];
6770
+ if (atRoot && isPlainObject((_b = anyDoc.meta) == null ? void 0 : _b.animator)) {
6771
+ warnings.push("animator: doc.meta.animator is shadowed by doc.animator and was not patched");
6772
+ }
6773
+ let base = current;
6774
+ if (reset) {
6775
+ const kept = {};
6776
+ for (const k of CONTENT_KEYS) {
6777
+ if (isPlainObject(current) && current[k] !== void 0) kept[k] = current[k];
6778
+ }
6779
+ base = kept;
6780
+ }
6781
+ const merged = mergeAnimatorConfig(base, patch != null ? patch : {});
6782
+ warnings.push(...merged.warnings);
6783
+ if (merged.config === current) return { doc, warnings };
6784
+ if (atMeta) {
6785
+ return {
6786
+ doc: __spreadProps(__spreadValues({}, anyDoc), { meta: __spreadProps(__spreadValues({}, anyDoc.meta), { animator: merged.config }) }),
6787
+ warnings
6788
+ };
6789
+ }
6790
+ return { doc: __spreadProps(__spreadValues({}, anyDoc), { animator: merged.config }), warnings };
6791
+ }
6792
+
6793
+ // src/format/PxDocumentDiagnostic.ts
6794
+ var MAX_REPORTED = 6;
6795
+ var LEGACY_FLAT_KEYS = [
6796
+ ...PX_TIMELINE_SHARED_KEYS,
6797
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
6798
+ "fill",
6799
+ "resetOnFinish",
6800
+ "timelineSource",
6801
+ "scroll"
6802
+ ];
6803
+ var isLegacyFlatAnimatorKey = (w) => LEGACY_FLAT_KEYS.some((k) => w.indexOf("animator." + k + ":") >= 0);
6804
+ function diagnoseDocument(doc) {
6805
+ let all;
6806
+ try {
6807
+ all = validateDocument(doc);
6808
+ } catch (e) {
6809
+ return { problems: [], legacy: [] };
6810
+ }
6811
+ const problems = [];
6812
+ const legacy = [];
6813
+ for (const w of all) (isLegacyFlatAnimatorKey(w) ? legacy : problems).push(w);
6814
+ return { problems, legacy };
6815
+ }
6816
+ function reportDocumentDiagnostics(doc, where) {
6817
+ const { problems } = diagnoseDocument(doc);
6818
+ if (!problems.length) return;
6819
+ const shown = problems.slice(0, MAX_REPORTED);
6820
+ const more = problems.length - shown.length;
6821
+ console.warn(
6822
+ 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."
6823
+ );
6824
+ }
6281
6825
  export {
6826
+ BASELINE_PLAYER_VERSION,
6282
6827
  COLOUR_ATTR_NAMES,
6283
6828
  CSS_ONLY_STYLE_PROPS,
6284
6829
  DEFAULT_DURATION_MS,
@@ -6287,18 +6832,21 @@ export {
6287
6832
  LOOP_JUMP_SHIFT_MS,
6288
6833
  MISSING_GLYPH_CLASS_NAME,
6289
6834
  PCT_BASED_ATTR_NAMES,
6835
+ PLAYER_WIRE_STEPS,
6836
+ PLAYER_WIRE_VERSION,
6290
6837
  PX_ANIM_ATTR_NAME,
6291
6838
  PX_ANIM_SRC_ATTR_NAME,
6839
+ PX_PLAYER_SCHEMA_VERSION,
6292
6840
  PX_TRANSFORM_PART_KEYS,
6841
+ PX_UNKNOWN_KEY_ERROR,
6293
6842
  PxAnimatedSvgDocumentSchema,
6294
6843
  PxAnimationDefinitionSchema,
6295
6844
  PxAnimatorConfigSchema,
6296
- PxAnimatorEngine,
6297
- PxAnimatorMode,
6298
6845
  PxAttrValueSchema,
6299
6846
  PxBezierPathSchema,
6300
6847
  PxBindingSchema,
6301
6848
  PxCloneEffectSchema,
6849
+ PxCloneWithout,
6302
6850
  PxDefsSchema,
6303
6851
  PxEasingOrRefSchema,
6304
6852
  PxEffectsSchema,
@@ -6310,7 +6858,8 @@ export {
6310
6858
  PxGradientUnits,
6311
6859
  PxKeyframeSchema,
6312
6860
  PxKeyframeValueSchema,
6313
- PxLoopExtend,
6861
+ PxLoopDirection,
6862
+ PxLoopRepeatAt,
6314
6863
  PxLoopSchema,
6315
6864
  PxMaskedByEffectSchema,
6316
6865
  PxNodeBase,
@@ -6327,6 +6876,8 @@ export {
6327
6876
  PxSvgNodeExtra,
6328
6877
  PxTextEffectSchema,
6329
6878
  PxTextPathEffectSchema,
6879
+ PxTimelineEngine,
6880
+ PxTimelineEngineExtra,
6330
6881
  PxTimelinePinSchema,
6331
6882
  PxTimelineSchema,
6332
6883
  PxTransformByEffectSchema,
@@ -6337,22 +6888,35 @@ export {
6337
6888
  TEXT_ATTR,
6338
6889
  TEXT_CONTENT_ATTR,
6339
6890
  TRANSFORM_FN_NAMES,
6891
+ WIRE_VERSION_KEY,
6892
+ WireStepKind,
6893
+ WireVersionRelation,
6894
+ applyAnimatorConfig,
6340
6895
  applyPlayerEffects,
6896
+ applyWireSteps,
6897
+ applyWireStepsDown,
6341
6898
  bezierToSvgPath,
6342
6899
  calcAnimationValues,
6343
6900
  camelCaseToKebabWordIfNeeded,
6344
6901
  clamp,
6345
6902
  collectSampleTimes,
6903
+ compareWireVersion,
6346
6904
  composeTransformParts,
6905
+ convertPlayerDocument,
6347
6906
  createBasicFrameLoopAnimator,
6348
6907
  createPathSampler,
6349
6908
  cubicBezier,
6350
6909
  deepClone,
6351
6910
  describeSchema,
6911
+ diagnoseDocument,
6912
+ diffFieldUniverse,
6352
6913
  diffInEffect,
6914
+ downgradePlayerDocument,
6353
6915
  evaluateMotionPathSegment,
6354
6916
  extendedPathForBrowser,
6355
6917
  flattenAnimatorTimeline,
6918
+ foldAnimatorConfigShortcuts,
6919
+ formatWireVersion,
6356
6920
  generateNewIds,
6357
6921
  generateUniqueId,
6358
6922
  getAnimatorConfig,
@@ -6363,11 +6927,17 @@ export {
6363
6927
  getNormalizedProps,
6364
6928
  interpolateBeziers,
6365
6929
  interpolateValue,
6930
+ isNativeForced,
6366
6931
  isPxElementFileFormat,
6367
6932
  isPxElementFileFormatDeep,
6368
6933
  isScrollTimeline,
6369
6934
  jsonElementFactory,
6370
6935
  kebabToCamelCaseWord,
6936
+ kfEasing,
6937
+ kfTangentIn,
6938
+ kfTangentOut,
6939
+ kfTime,
6940
+ kfValue,
6371
6941
  layoutGlyphTextChars,
6372
6942
  materialiseAllInTree,
6373
6943
  materialiseAnimatedUseInstances,
@@ -6378,14 +6948,23 @@ export {
6378
6948
  materialiseInternalLoopsInTree,
6379
6949
  materialiseMotionPathInPropAnim,
6380
6950
  materialiseMotionPathsInTree,
6951
+ mayUseNativeScrollTimeline,
6952
+ mergeAnimatorConfig,
6381
6953
  mergeStaticTransformIntoAnimDef,
6382
6954
  nestAnimatorTimeline,
6383
6955
  parseTransformParts,
6956
+ parseWireVersion,
6957
+ planSchemaRelease,
6384
6958
  propAnimIsMotionPath,
6385
6959
  px,
6960
+ readWireVersion,
6961
+ releaseLogProblems,
6962
+ reportDocumentDiagnostics,
6386
6963
  resolveStyle,
6964
+ resolveTimelineEngine,
6387
6965
  reverseEasing,
6388
6966
  sanitiseAttributeValue,
6967
+ schemaFieldUniverse,
6389
6968
  schemaKeys,
6390
6969
  scrollOffsetProgress,
6391
6970
  scrollPhaseInterval,
@@ -6396,7 +6975,9 @@ export {
6396
6975
  splitEasing,
6397
6976
  subdivideCubicBezier,
6398
6977
  toRGBA,
6978
+ validateDocument,
6399
6979
  validateNodeEffects,
6980
+ versionAdvice,
6400
6981
  visualModelAt
6401
6982
  };
6402
6983
  //# sourceMappingURL=index.js.map