@pixodesk/svg-animator-web 1.0.35 → 1.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -49,70 +49,105 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
49
49
  // src/index.ts
50
50
  var index_exports = {};
51
51
  __export(index_exports, {
52
- COLOUR_ATTR_NAMES: () => COLOUR_ATTR_NAMES,
52
+ BASELINE_PLAYER_VERSION: () => BASELINE_PLAYER_VERSION,
53
+ COLOR_ATTR_NAMES: () => COLOR_ATTR_NAMES,
54
+ DEFAULT_DURATION_MS: () => DEFAULT_DURATION_MS,
53
55
  MISSING_GLYPH_CLASS_NAME: () => MISSING_GLYPH_CLASS_NAME,
54
- PX_ANIMATOR_DATA_KEY: () => PX_ANIMATOR_DATA_KEY,
56
+ PLAYER_WIRE_STEPS: () => PLAYER_WIRE_STEPS,
57
+ PLAYER_WIRE_VERSION: () => PLAYER_WIRE_VERSION,
58
+ PX_ANIMATOR_DOC_KEY: () => PX_ANIMATOR_DOC_KEY,
55
59
  PX_ANIM_ATTR_NAME: () => PX_ANIM_ATTR_NAME,
56
60
  PX_ANIM_SRC_ATTR_NAME: () => PX_ANIM_SRC_ATTR_NAME,
61
+ PX_PLAYER_SCHEMA_VERSION: () => PX_PLAYER_SCHEMA_VERSION,
57
62
  PX_TRANSFORM_PART_KEYS: () => PX_TRANSFORM_PART_KEYS,
63
+ PX_TRIGGER_DEFAULTS: () => PX_TRIGGER_DEFAULTS,
64
+ PxAlongPathMode: () => PxAlongPathMode,
58
65
  PxAnimatedSvgDocumentSchema: () => PxAnimatedSvgDocumentSchema,
59
66
  PxAnimationDefinitionSchema: () => PxAnimationDefinitionSchema,
60
67
  PxAnimatorConfigSchema: () => PxAnimatorConfigSchema,
61
68
  PxAttrValueSchema: () => PxAttrValueSchema,
62
69
  PxBezierPathSchema: () => PxBezierPathSchema,
63
70
  PxBindingSchema: () => PxBindingSchema,
71
+ PxClipPathEffectSchema: () => PxClipPathEffectSchema,
64
72
  PxCloneEffectSchema: () => PxCloneEffectSchema,
65
73
  PxCloneWithout: () => PxCloneWithout,
74
+ PxControlMode: () => PxControlMode,
66
75
  PxDefsSchema: () => PxDefsSchema,
76
+ PxDiagnosticKind: () => PxDiagnosticKind,
67
77
  PxEasingOrRefSchema: () => PxEasingOrRefSchema,
68
78
  PxEffectsSchema: () => PxEffectsSchema,
69
79
  PxElementAnimationSchema: () => PxElementAnimationSchema,
70
80
  PxFillGradientEffectSchema: () => PxFillGradientEffectSchema,
81
+ PxFinishAction: () => PxFinishAction,
71
82
  PxGradientSpreadMethod: () => PxGradientSpreadMethod,
72
83
  PxGradientStopSchema: () => PxGradientStopSchema,
73
84
  PxGradientType: () => PxGradientType,
74
- PxGradientUnits: () => PxGradientUnits,
75
85
  PxKeyframeSchema: () => PxKeyframeSchema,
76
86
  PxKeyframeValueSchema: () => PxKeyframeValueSchema,
87
+ PxLengthAdjust: () => PxLengthAdjust,
77
88
  PxLoopDirection: () => PxLoopDirection,
78
89
  PxLoopRepeatAt: () => PxLoopRepeatAt,
79
90
  PxLoopSchema: () => PxLoopSchema,
91
+ PxMaskType: () => PxMaskType,
80
92
  PxMaskedByEffectSchema: () => PxMaskedByEffectSchema,
81
93
  PxNodeBase: () => PxNodeBase,
82
94
  PxNodeSchema: () => PxNodeSchema,
95
+ PxPathOverflow: () => PxPathOverflow,
96
+ PxPinAlign: () => PxPinAlign,
83
97
  PxPropertyAnimationSchema: () => PxPropertyAnimationSchema,
84
98
  PxRepeaterEffectSchema: () => PxRepeaterEffectSchema,
85
99
  PxRetimeEffectSchema: () => PxRetimeEffectSchema,
100
+ PxScrollAxis: () => PxScrollAxis,
101
+ PxScrollKind: () => PxScrollKind,
102
+ PxScrollPhase: () => PxScrollPhase,
103
+ PxScrollRangePointSchema: () => PxScrollRangePointSchema,
104
+ PxScrollRangeSchema: () => PxScrollRangeSchema,
105
+ PxScrollSchema: () => PxScrollSchema,
106
+ PxScrollSource: () => PxScrollSource,
86
107
  PxStrokeGradientEffectSchema: () => PxStrokeGradientEffectSchema,
87
108
  PxStrokeTrimEffectSchema: () => PxStrokeTrimEffectSchema,
88
109
  PxStrokeTrimSubPaths: () => PxStrokeTrimSubPaths,
89
110
  PxSvgNodeExtra: () => PxSvgNodeExtra,
90
111
  PxTextEffectSchema: () => PxTextEffectSchema,
91
112
  PxTextPathEffectSchema: () => PxTextPathEffectSchema,
113
+ PxTextPathMethod: () => PxTextPathMethod,
114
+ PxTextPathSpacing: () => PxTextPathSpacing,
92
115
  PxTimelineEngine: () => PxTimelineEngine,
93
116
  PxTimelineEngineExtra: () => PxTimelineEngineExtra,
117
+ PxTimelinePinSchema: () => PxTimelinePinSchema,
118
+ PxTimelineSchema: () => PxTimelineSchema,
94
119
  PxTransformByEffectSchema: () => PxTransformByEffectSchema,
95
120
  PxTransformPartsSchema: () => PxTransformPartsSchema,
96
121
  PxTransformValueSchema: () => PxTransformValueSchema,
97
122
  PxTriggerSchema: () => PxTriggerSchema,
123
+ PxUnits: () => PxUnits,
98
124
  STYLE_ATTR_NAMES: () => STYLE_ATTR_NAMES,
99
125
  TRANSFORM_FN_NAMES: () => TRANSFORM_FN_NAMES,
126
+ WIRE_VERSION_KEY: () => WIRE_VERSION_KEY,
127
+ WireStepKind: () => WireStepKind,
128
+ WireVersionRelation: () => WireVersionRelation,
100
129
  applyAnimatorConfig: () => applyAnimatorConfig,
101
130
  applyPlayerEffects: () => applyPlayerEffects,
102
131
  calcAnimationValues: () => calcAnimationValues,
103
132
  camelCaseToKebabWordIfNeeded: () => camelCaseToKebabWordIfNeeded,
104
133
  collectSampleTimes: () => collectSampleTimes,
134
+ compareWireVersion: () => compareWireVersion,
135
+ controlModeTakesOverTrigger: () => controlModeTakesOverTrigger,
136
+ convertPlayerDocument: () => convertPlayerDocument,
105
137
  createAnimator: () => createAnimator,
106
- createAnimatorImpl: () => createAnimatorImpl,
107
138
  createBasicFrameLoopAnimator: () => createBasicFrameLoopAnimator,
139
+ createDiagnostics: () => createDiagnostics,
108
140
  createFrameLoopAnimator: () => createFrameLoopAnimator,
109
141
  createPathSampler: () => createPathSampler,
110
142
  createWebApiAnimator: () => createWebApiAnimator,
111
143
  describeSchema: () => describeSchema,
144
+ diagnoseDocument: () => diagnoseDocument,
112
145
  diffInEffect: () => diffInEffect,
146
+ downgradePlayerDocument: () => downgradePlayerDocument,
113
147
  evaluateMotionPathSegment: () => evaluateMotionPathSegment,
114
148
  extendedPathForBrowser: () => extendedPathForBrowser,
115
- foldAnimatorConfigShortcuts: () => foldAnimatorConfigShortcuts,
149
+ foldTimelineOverride: () => foldTimelineOverride,
150
+ formatWireVersion: () => formatWireVersion,
116
151
  generateNewIds: () => generateNewIds,
117
152
  getAnimatorConfig: () => getAnimatorConfig,
118
153
  getBindings: () => getBindings,
@@ -124,26 +159,33 @@ __export(index_exports, {
124
159
  jsonElementFactory: () => jsonElementFactory,
125
160
  layoutGlyphTextChars: () => layoutGlyphTextChars,
126
161
  loadTagAnimators: () => loadTagAnimators,
127
- materialiseAllInTree: () => materialiseAllInTree,
128
- materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
129
- materialiseGlyphText: () => materialiseGlyphText,
130
- materialiseGlyphTextAlongPath: () => materialiseGlyphTextAlongPath,
131
- materialiseGlyphTextHorizontal: () => materialiseGlyphTextHorizontal,
132
- materialiseInternalLoopsInPropAnim: () => materialiseInternalLoopsInPropAnim,
133
- materialiseInternalLoopsInTree: () => materialiseInternalLoopsInTree,
134
- materialiseMotionPathInPropAnim: () => materialiseMotionPathInPropAnim,
135
- materialiseMotionPathsInTree: () => materialiseMotionPathsInTree,
162
+ materializeAllInTree: () => materializeAllInTree,
163
+ materializeAnimatedUseInstances: () => materializeAnimatedUseInstances,
164
+ materializeGlyphText: () => materializeGlyphText,
165
+ materializeGlyphTextAlongPath: () => materializeGlyphTextAlongPath,
166
+ materializeGlyphTextHorizontal: () => materializeGlyphTextHorizontal,
167
+ materializeInternalLoopsInPropAnim: () => materializeInternalLoopsInPropAnim,
168
+ materializeInternalLoopsInTree: () => materializeInternalLoopsInTree,
169
+ materializeMotionPathInPropAnim: () => materializeMotionPathInPropAnim,
170
+ materializeMotionPathsInTree: () => materializeMotionPathsInTree,
136
171
  mergeAnimatorConfig: () => mergeAnimatorConfig,
137
- normalizeDocument: () => getNormalisedBindings,
172
+ normalizeDocument: () => getNormalizedBindings,
173
+ parseWireVersion: () => parseWireVersion,
174
+ progressToTimeMs: () => progressToTimeMs,
138
175
  propAnimIsMotionPath: () => propAnimIsMotionPath,
139
176
  px: () => px,
177
+ readWireVersion: () => readWireVersion,
140
178
  renderNode: () => renderNode,
179
+ resolveControlMode: () => resolveControlMode,
180
+ resolveTrigger: () => resolveTrigger,
141
181
  schemaKeys: () => schemaKeys,
142
182
  setupAnimationTriggers: () => setupAnimationTriggers,
143
183
  shiftAnimatable: () => shiftAnimatable,
184
+ timeToProgress: () => timeToProgress,
144
185
  toRGBA: () => toRGBA,
145
186
  validateDocument: () => validateDocument,
146
187
  validateNodeEffects: () => validateNodeEffects,
188
+ versionAdvice: () => versionAdvice,
147
189
  visualModelAt: () => visualModelAt
148
190
  });
149
191
  module.exports = __toCommonJS(index_exports);
@@ -410,7 +452,7 @@ function parseColor(s) {
410
452
  }
411
453
  return void 0;
412
454
  }
413
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
455
+ var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
414
456
  var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
415
457
  var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
416
458
  function composeTransformParts(parts, opts) {
@@ -789,6 +831,7 @@ var Enum = class extends Base {
789
831
  return false;
790
832
  }
791
833
  };
834
+ var UNION_MEMBER_ERROR_LIMIT = 4;
792
835
  var Union = class extends Base {
793
836
  constructor(schemas, defaultVal) {
794
837
  super();
@@ -806,7 +849,35 @@ var Union = class extends Base {
806
849
  var _a2;
807
850
  const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
808
851
  if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
809
- 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));
852
+ if (!ctx) return false;
853
+ const base = pathStr(path != null ? path : []);
854
+ ctx.errors.push(base + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
855
+ let best;
856
+ let bestDepth = -1;
857
+ const leafExpectations = [];
858
+ for (const member of this.schemas) {
859
+ const sink = { errors: [], warnings: [], strict: ctx.strict };
860
+ member.isValid(raw, sink, path ? [...path] : void 0);
861
+ if (!sink.errors.length) continue;
862
+ const depth = Math.max(...sink.errors.map((e) => e.slice(0, e.indexOf(":")).length));
863
+ if (depth > bestDepth || depth === bestDepth && best && sink.errors.length < best.length) {
864
+ bestDepth = depth;
865
+ best = sink.errors;
866
+ }
867
+ if (depth <= base.length) {
868
+ for (const e of sink.errors) {
869
+ const m = /: expected (.+?), got /.exec(e);
870
+ if (m && !leafExpectations.includes(m[1])) leafExpectations.push(m[1]);
871
+ }
872
+ }
873
+ }
874
+ if (best && bestDepth > base.length) {
875
+ for (const e of best.slice(0, UNION_MEMBER_ERROR_LIMIT)) {
876
+ if (!ctx.errors.includes(e)) ctx.errors.push(e);
877
+ }
878
+ } else if (leafExpectations.length) {
879
+ ctx.errors.push(base + ": expected " + leafExpectations.join(" | "));
880
+ }
810
881
  return false;
811
882
  }
812
883
  _canSanitize(raw) {
@@ -1178,6 +1249,17 @@ var px = {
1178
1249
  lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
1179
1250
  };
1180
1251
  var PX_PLAYER_SCHEMA_VERSION = "1.1";
1252
+ var WIRE_VERSION_KEY = "version";
1253
+ var ANIMATOR_KEY = "animator";
1254
+ var META_KEY = "meta";
1255
+ var WireVersionRelation = /* @__PURE__ */ ((WireVersionRelation2) => {
1256
+ WireVersionRelation2["unstamped"] = "unstamped";
1257
+ WireVersionRelation2["same"] = "same";
1258
+ WireVersionRelation2["older"] = "older";
1259
+ WireVersionRelation2["newer"] = "newer";
1260
+ WireVersionRelation2["otherGeneration"] = "otherGeneration";
1261
+ return WireVersionRelation2;
1262
+ })(WireVersionRelation || {});
1181
1263
  var VERSION_RE = /^(\d+)\.(\d+)(?:\.(\d+))?$/;
1182
1264
  function parseWireVersion(raw) {
1183
1265
  if (typeof raw !== "string") return void 0;
@@ -1185,12 +1267,235 @@ function parseWireVersion(raw) {
1185
1267
  if (!m) return void 0;
1186
1268
  return { a: Number(m[1]), b: Number(m[2]), c: m[3] === void 0 ? 0 : Number(m[3]) };
1187
1269
  }
1270
+ function formatWireVersion(v) {
1271
+ return v.a + "." + v.b + "." + v.c;
1272
+ }
1188
1273
  var _a;
1189
1274
  var PLAYER_WIRE_VERSION = (_a = parseWireVersion(PX_PLAYER_SCHEMA_VERSION)) != null ? _a : { a: 1, b: 1, c: 0 };
1275
+ function getAnimatorBlock(doc) {
1276
+ if (!doc || typeof doc !== "object") return void 0;
1277
+ const atRoot = readObjectProp(doc, ANIMATOR_KEY);
1278
+ if (atRoot) return atRoot;
1279
+ const meta = readObjectProp(doc, META_KEY);
1280
+ return meta ? readObjectProp(meta, ANIMATOR_KEY) : void 0;
1281
+ }
1282
+ function readObjectProp(obj, key) {
1283
+ const value = obj[key];
1284
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1285
+ }
1286
+ function readWireVersion(doc) {
1287
+ const animator = getAnimatorBlock(doc);
1288
+ return animator ? parseWireVersion(animator[WIRE_VERSION_KEY]) : void 0;
1289
+ }
1290
+ function compareWireVersion(file, mine, readerReadsEditorPart) {
1291
+ if (!file) return "unstamped";
1292
+ if (file.a !== mine.a) return "otherGeneration";
1293
+ if (file.b !== mine.b) return file.b > mine.b ? "newer" : "older";
1294
+ if (!readerReadsEditorPart || file.c === mine.c) return "same";
1295
+ return file.c > mine.c ? "newer" : "older";
1296
+ }
1297
+ function versionAdvice(relation, file, mine, isPlayer) {
1298
+ if (!file) return void 0;
1299
+ const target = isPlayer ? "player" : "editor";
1300
+ const gap = "written for schema " + formatWireVersion(file) + ", this " + target + " reads " + formatWireVersion(mine);
1301
+ switch (relation) {
1302
+ case "newer":
1303
+ return "This file is " + gap + ". Update the " + target + " to open it fully.";
1304
+ case "older":
1305
+ return "This file is " + gap + ". Saving it from this " + target + " rewrites it in the current format.";
1306
+ case "otherGeneration":
1307
+ 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.";
1308
+ default:
1309
+ return void 0;
1310
+ }
1311
+ }
1312
+ var WireStepKind = /* @__PURE__ */ ((WireStepKind2) => {
1313
+ WireStepKind2["additive"] = "additive";
1314
+ WireStepKind2["converted"] = "converted";
1315
+ return WireStepKind2;
1316
+ })(WireStepKind || {});
1317
+ var BASELINE_PLAYER_VERSION = "1.1";
1318
+ var PLAYER_WIRE_STEPS = [];
1319
+ function applyWireSteps(doc, cfg) {
1320
+ const from = readWireVersion(doc);
1321
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1322
+ if (!from || relation !== "older") {
1323
+ return {
1324
+ doc,
1325
+ from,
1326
+ relation,
1327
+ applied: [],
1328
+ advice: versionAdvice(relation, from, cfg.target, !cfg.readerReadsEditorPart)
1329
+ };
1330
+ }
1331
+ const due = [];
1332
+ for (const step of cfg.steps) {
1333
+ const stepTo = parseWireVersion(step.to);
1334
+ if (!stepTo) continue;
1335
+ if (compareWireVersion(from, stepTo, cfg.readerReadsEditorPart) !== "older") continue;
1336
+ if (!step.up) continue;
1337
+ due.push(step);
1338
+ }
1339
+ if (!due.length || !doc || typeof doc !== "object") return { doc, from, relation, applied: [] };
1340
+ const target = clonePlain(doc);
1341
+ const applied = [];
1342
+ for (const step of due) {
1343
+ try {
1344
+ step.up(target);
1345
+ applied.push(step);
1346
+ } catch (e) {
1347
+ break;
1348
+ }
1349
+ }
1350
+ if (!applied.length) return { doc, from, relation, applied: [] };
1351
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1352
+ return { doc: target, from, relation, applied };
1353
+ }
1354
+ function convertPlayerDocument(doc) {
1355
+ return applyWireSteps(doc, {
1356
+ steps: PLAYER_WIRE_STEPS,
1357
+ target: PLAYER_WIRE_VERSION,
1358
+ readerReadsEditorPart: false
1359
+ });
1360
+ }
1361
+ function clonePlain(value) {
1362
+ const structured = globalThis.structuredClone;
1363
+ return structured ? structured(value) : JSON.parse(JSON.stringify(value));
1364
+ }
1365
+ function stampVersion(doc, target, readerReadsEditorPart) {
1366
+ const animator = getAnimatorBlock(doc);
1367
+ if (!animator) return;
1368
+ const previous = parseWireVersion(animator[WIRE_VERSION_KEY]);
1369
+ animator[WIRE_VERSION_KEY] = formatWireVersion({
1370
+ a: target.a,
1371
+ b: target.b,
1372
+ c: readerReadsEditorPart ? target.c : previous ? previous.c : 0
1373
+ });
1374
+ }
1375
+ function applyWireStepsDown(doc, cfg) {
1376
+ const from = readWireVersion(doc);
1377
+ if (!from) {
1378
+ return { ok: false, blocking: [], reason: "The document carries no version, so there is nothing to convert down from." };
1379
+ }
1380
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
1381
+ if (relation === "otherGeneration") {
1382
+ return {
1383
+ ok: false,
1384
+ blocking: [],
1385
+ reason: "Schema " + formatWireVersion(from) + " and " + formatWireVersion(cfg.target) + " are different generations; no conversion bridges them."
1386
+ };
1387
+ }
1388
+ if (relation !== "newer") return { ok: true, doc, applied: [] };
1389
+ const toUndo = [];
1390
+ for (const step of cfg.steps) {
1391
+ const stepTo = parseWireVersion(step.to);
1392
+ if (!stepTo) continue;
1393
+ if (compareWireVersion(stepTo, cfg.target, cfg.readerReadsEditorPart) !== "newer") continue;
1394
+ if (compareWireVersion(stepTo, from, cfg.readerReadsEditorPart) === "newer") continue;
1395
+ toUndo.push(step);
1396
+ }
1397
+ toUndo.reverse();
1398
+ const blocking = toUndo.filter((s) => s.kind === "converted" && !s.down);
1399
+ if (blocking.length) {
1400
+ return {
1401
+ ok: false,
1402
+ blocking,
1403
+ reason: "Cannot convert down to " + formatWireVersion(cfg.target) + ": " + blocking.map((s) => s.from + " \u2192 " + s.to + " (" + s.reason + ")").join("; ") + " cannot be undone."
1404
+ };
1405
+ }
1406
+ const target = clonePlain(doc);
1407
+ const applied = [];
1408
+ for (const step of toUndo) {
1409
+ if (!step.down) continue;
1410
+ try {
1411
+ step.down(target);
1412
+ applied.push(step);
1413
+ } catch (e) {
1414
+ return {
1415
+ ok: false,
1416
+ blocking: [step],
1417
+ reason: "Undoing " + step.from + " \u2192 " + step.to + " failed: " + String(e)
1418
+ };
1419
+ }
1420
+ }
1421
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
1422
+ return { ok: true, doc: target, applied };
1423
+ }
1424
+ function downgradePlayerDocument(doc, target) {
1425
+ return applyWireStepsDown(doc, { steps: PLAYER_WIRE_STEPS, target, readerReadsEditorPart: false });
1426
+ }
1427
+ var PxFillMode = {
1428
+ forwards: "forwards",
1429
+ backwards: "backwards",
1430
+ both: "both",
1431
+ none: "none"
1432
+ };
1433
+ var PxPlaybackDirection = {
1434
+ normal: "normal",
1435
+ reverse: "reverse",
1436
+ alternate: "alternate",
1437
+ alternateReverse: "alternate-reverse"
1438
+ };
1190
1439
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1191
1440
  var PX_ANIM_ATTR_NAME = "_px_animator";
1441
+ var PxStartOn = {
1442
+ load: "load",
1443
+ mouseOver: "mouseOver",
1444
+ click: "click",
1445
+ scrollIntoView: "scrollIntoView",
1446
+ programmatic: "programmatic"
1447
+ };
1448
+ var PxOutAction = {
1449
+ continue: "continue",
1450
+ pause: "pause",
1451
+ reset: "reset",
1452
+ reverse: "reverse"
1453
+ };
1454
+ var PxFinishAction = {
1455
+ hold: "hold",
1456
+ reset: "reset"
1457
+ };
1458
+ var PxScrollKind = {
1459
+ view: "view",
1460
+ scroll: "scroll"
1461
+ };
1462
+ var PxScrollAxis = {
1463
+ block: "block",
1464
+ inline: "inline",
1465
+ x: "x",
1466
+ y: "y"
1467
+ };
1468
+ var PxScrollSource = {
1469
+ nearest: "nearest",
1470
+ root: "root"
1471
+ };
1472
+ var PxPinAlign = {
1473
+ top: "top",
1474
+ center: "center",
1475
+ bottom: "bottom"
1476
+ };
1477
+ var PxScrollPhase = {
1478
+ cover: "cover",
1479
+ contain: "contain",
1480
+ entry: "entry",
1481
+ exit: "exit",
1482
+ entryCrossing: "entry-crossing",
1483
+ exitCrossing: "exit-crossing"
1484
+ };
1485
+ var PxAlongPathMode = {
1486
+ sampled: "sampled",
1487
+ offsetPath: "offsetPath"
1488
+ };
1192
1489
  var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
1193
1490
  var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
1491
+ var PX_FLAT_RUNTIME_VIEW_KEYS = [
1492
+ ...PX_TIMELINE_SHARED_KEYS,
1493
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
1494
+ "fill",
1495
+ "resetOnFinish",
1496
+ "timelineSource",
1497
+ "scroll"
1498
+ ];
1194
1499
  var PxTimelineEngine = {
1195
1500
  native: "native",
1196
1501
  js: "js"
@@ -1207,6 +1512,50 @@ function isNativeForced(engine) {
1207
1512
  function mayUseNativeScrollTimeline(engine) {
1208
1513
  return engine !== PxTimelineEngineExtra.js;
1209
1514
  }
1515
+ var PX_TRIGGER_DEFAULTS = {
1516
+ startOn: "load",
1517
+ outAction: "continue",
1518
+ scrollIntoViewThreshold: 0
1519
+ };
1520
+ var PxControlMode = {
1521
+ /** No control props — the document's trigger decides, and nothing is taken over. */
1522
+ static: "static",
1523
+ /** `progress` / `time` — the host scrubs; the component seeks and stays paused. */
1524
+ fixedTime: "fixedTime",
1525
+ /** `play` / `pause` — the host drives playback with booleans. */
1526
+ play: "play",
1527
+ /** `autoplay` — the document's own trigger starts it. */
1528
+ autoplay: "autoplay"
1529
+ };
1530
+ function resolveControlMode(props) {
1531
+ const hasFixedTime = props.progress !== void 0 || props.time !== void 0;
1532
+ const hasPlayPause = props.play !== void 0 || props.pause !== void 0;
1533
+ const hasAutoplay = !!props.autoplay;
1534
+ const warnings = [];
1535
+ const named = (a, b, winner) => a + " and " + b + " were both set \u2014 " + winner + " wins, " + (winner === a ? b : a) + " is ignored.";
1536
+ if (hasFixedTime) {
1537
+ if (hasPlayPause) warnings.push(named("progress/time", "play/pause", "progress/time"));
1538
+ if (hasAutoplay) warnings.push(named("progress/time", "autoplay", "progress/time"));
1539
+ return { mode: PxControlMode.fixedTime, warnings };
1540
+ }
1541
+ if (hasPlayPause) {
1542
+ if (hasAutoplay) warnings.push(named("play/pause", "autoplay", "play/pause"));
1543
+ return { mode: PxControlMode.play, warnings };
1544
+ }
1545
+ if (hasAutoplay) return { mode: PxControlMode.autoplay, warnings };
1546
+ return { mode: PxControlMode.static, warnings };
1547
+ }
1548
+ function controlModeTakesOverTrigger(mode) {
1549
+ return mode !== PxControlMode.autoplay;
1550
+ }
1551
+ function resolveTrigger(trigger) {
1552
+ var _a2, _b, _c;
1553
+ return {
1554
+ startOn: (_a2 = trigger == null ? void 0 : trigger.startOn) != null ? _a2 : PX_TRIGGER_DEFAULTS.startOn,
1555
+ outAction: (_b = trigger == null ? void 0 : trigger.outAction) != null ? _b : PX_TRIGGER_DEFAULTS.outAction,
1556
+ scrollIntoViewThreshold: (_c = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _c : PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold
1557
+ };
1558
+ }
1210
1559
  var PxLoopRepeatAt = {
1211
1560
  /** Segment from the START; the repetition runs BEFORE the first keyframe
1212
1561
  * (intro loops that play until the main timeline begins). */
@@ -1253,7 +1602,6 @@ var PxStrokeTrimSubPaths = {
1253
1602
  separate: "separate",
1254
1603
  combined: "combined"
1255
1604
  };
1256
- var TEXT_ATTR = "text";
1257
1605
  var TEXT_CONTENT_ATTR = "textContent";
1258
1606
  var CLASS_ATTR = "class";
1259
1607
  var TRANSFORM_ATTR = "transform";
@@ -1265,7 +1613,6 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1265
1613
  "meta",
1266
1614
  "animate",
1267
1615
  "effects",
1268
- TEXT_ATTR,
1269
1616
  TEXT_CONTENT_ATTR
1270
1617
  ]);
1271
1618
  var TRANSFORM_PART = {
@@ -1280,10 +1627,6 @@ var PX_TRANSFORM_PART_KEYS = [
1280
1627
  TRANSFORM_PART.scale,
1281
1628
  TRANSFORM_PART.origin
1282
1629
  ];
1283
- var PxGradientUnits = {
1284
- userSpaceOnUse: "userSpaceOnUse",
1285
- objectBoundingBox: "objectBoundingBox"
1286
- };
1287
1630
  var PxGradientSpreadMethod = {
1288
1631
  pad: "pad",
1289
1632
  reflect: "reflect",
@@ -1302,8 +1645,18 @@ function isPxElementFileFormat(fileJson) {
1302
1645
  function getAnimatorConfig(doc) {
1303
1646
  var _a2;
1304
1647
  const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
1305
- return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1306
- }
1648
+ if (!cfg) return void 0;
1649
+ const memoised = wireViewMemo.get(cfg);
1650
+ if (memoised) return memoised;
1651
+ const wire = cfg;
1652
+ const stray = PX_FLAT_RUNTIME_VIEW_KEYS.filter((k) => wire[k] !== void 0);
1653
+ const source = stray.length ? __spreadValues2({}, wire) : cfg;
1654
+ for (const k of stray) delete source[k];
1655
+ const view = flattenAnimatorTimeline(source);
1656
+ wireViewMemo.set(cfg, view);
1657
+ return view;
1658
+ }
1659
+ var wireViewMemo = /* @__PURE__ */ new WeakMap();
1307
1660
  var flattenMemo = /* @__PURE__ */ new WeakMap();
1308
1661
  function flattenAnimatorTimeline(cfg) {
1309
1662
  const timeline = cfg.timeline;
@@ -1329,7 +1682,7 @@ function flattenAnimatorTimeline(cfg) {
1329
1682
  else if (pin && typeof pin === "object") {
1330
1683
  scroll.pin = true;
1331
1684
  if (pin.align !== void 0) scroll.pinAlign = pin.align;
1332
- if (pin.top !== void 0) scroll.pinTop = pin.top;
1685
+ if (pin.offset !== void 0) scroll.pinOffset = pin.offset;
1333
1686
  if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1334
1687
  }
1335
1688
  flat.scroll = scroll;
@@ -1372,14 +1725,13 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
1372
1725
  // e.g. for colors
1373
1726
  px.number(),
1374
1727
  px.array(px.number()),
1375
- // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1728
+ // ORDER LAW: the key-discriminated object shape (`{pathData}`) comes BEFORE the
1376
1729
  // all-optional transform-parts record. In default (non-strict) mode that record accepts
1377
1730
  // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1378
- // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1731
+ // Union.sanitize route `{pathData}` values into it and strip them to `{}` —
1379
1732
  // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1380
1733
  // order-independent (`some()`); only sanitize routing depends on this order.
1381
- px.object({ path: px.string() }),
1382
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1734
+ px.object({ pathData: px.string() }),
1383
1735
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1384
1736
  px.lazy(() => px.array(PxGradientStopSchema), []),
1385
1737
  px.lazy(() => PxTransformPartsSchema, {})
@@ -1419,7 +1771,7 @@ var PxPropertyAnimationSchema = implementsInterface()(px.object({
1419
1771
  keyframes: px.array(PxKeyframeSchema).optional(),
1420
1772
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1421
1773
  autoOrient: px.boolean().optional(),
1422
- alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
1774
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
1423
1775
  }));
1424
1776
  var PxTransformPartsSchema = implementsInterface()(px.object({
1425
1777
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1443,17 +1795,17 @@ var PxElementAnimationSchema = implementsInterface()(px.union([
1443
1795
  PxAnimationDefinitionSchema
1444
1796
  ]));
1445
1797
  var PxTriggerSchema = implementsInterface()(px.object({
1446
- startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1447
- outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1798
+ startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic], PX_TRIGGER_DEFAULTS.startOn).optional(),
1799
+ outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse], PX_TRIGGER_DEFAULTS.outAction).optional(),
1448
1800
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1449
1801
  // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1450
1802
  // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1451
- finishAction: px.enum(["hold", "reset"]).optional(),
1803
+ finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
1452
1804
  scrollIntoViewThreshold: px.number().optional()
1453
1805
  }));
1454
1806
  var PxGlyphSchema = implementsInterface()(px.object({
1455
1807
  width: px.number(),
1456
- d: px.string()
1808
+ pathData: px.string()
1457
1809
  }));
1458
1810
  var PxGlyphFontSchema = implementsInterface()(px.object({
1459
1811
  fontFamily: px.string(),
@@ -1470,9 +1822,15 @@ var PxDefsSchema = implementsInterface()(px.object({
1470
1822
  styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1471
1823
  fonts: px.record(PxGlyphFontSchema).optional()
1472
1824
  }));
1473
- var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1474
1825
  var PxScrollRangePointSchema = implementsInterface()(px.object({
1475
- phase: px.enum(PX_SCROLL_PHASES).optional(),
1826
+ phase: px.enum([
1827
+ PxScrollPhase.cover,
1828
+ PxScrollPhase.contain,
1829
+ PxScrollPhase.entry,
1830
+ PxScrollPhase.exit,
1831
+ PxScrollPhase.entryCrossing,
1832
+ PxScrollPhase.exitCrossing
1833
+ ]).optional(),
1476
1834
  fraction: px.number().optional()
1477
1835
  }));
1478
1836
  var PxScrollRangeSchema = px.object({
@@ -1480,21 +1838,21 @@ var PxScrollRangeSchema = px.object({
1480
1838
  end: PxScrollRangePointSchema.optional()
1481
1839
  });
1482
1840
  var PxScrollSchema = implementsInterface()(px.object({
1483
- kind: px.enum(["view", "scroll"]).optional(),
1484
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1485
- source: px.enum(["nearest", "root"]).optional(),
1841
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
1842
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1843
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1486
1844
  // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1487
1845
  subject: px.string().optional(),
1488
1846
  smoothing: px.number().optional(),
1489
1847
  pin: px.boolean().optional(),
1490
- pinAlign: px.enum(["top", "center", "bottom"]).optional(),
1491
- pinTop: px.number().optional(),
1848
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1849
+ pinOffset: px.number().optional(),
1492
1850
  pinDistance: px.number().optional(),
1493
1851
  range: PxScrollRangeSchema.optional()
1494
1852
  }));
1495
1853
  var PxTimelinePinSchema = implementsInterface()(px.object({
1496
- align: px.enum(["top", "center", "bottom"]).optional(),
1497
- top: px.number().optional(),
1854
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1855
+ offset: px.number().optional(),
1498
1856
  distance: px.number().optional()
1499
1857
  }));
1500
1858
  var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
@@ -1509,8 +1867,8 @@ var PxTimeTimelineSchema = implementsInterface()(px.object({
1509
1867
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1510
1868
  // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1511
1869
  // — never `fill`, which is paint everywhere else in the format.
1512
- fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1513
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1870
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
1871
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
1514
1872
  }));
1515
1873
  var scrollishTimelineShape = {
1516
1874
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
@@ -1521,8 +1879,8 @@ var scrollishTimelineShape = {
1521
1879
  iterations: px.number().optional(),
1522
1880
  engine: PxTimelineEngineSchema,
1523
1881
  frameRate: px.number().optional(),
1524
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1525
- source: px.enum(["nearest", "root"]).optional(),
1882
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1883
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1526
1884
  subject: px.string().optional(),
1527
1885
  // 'parent' | 'scroller' | any CSS selector
1528
1886
  smoothing: px.number().optional(),
@@ -1611,7 +1969,7 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1611
1969
  height: px.number().optional()
1612
1970
  }));
1613
1971
  var PxClipPathEffectSchema = implementsInterface()(px.object({
1614
- d: PxAnimatableStringSchema.optional()
1972
+ pathData: PxAnimatableStringSchema.optional()
1615
1973
  }));
1616
1974
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1617
1975
  offset: PxAnimatableNumberSchema.optional(),
@@ -1648,7 +2006,7 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1648
2006
  radius: PxAnimatableNumberSchema.optional(),
1649
2007
  focal: PxAnimatableVec2Schema.optional(),
1650
2008
  stops: PxAnimatableGradientStopsSchema.optional(),
1651
- gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
2009
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1652
2010
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1653
2011
  gradientTransform: px.string().optional()
1654
2012
  }));
@@ -1694,11 +2052,71 @@ function validateNodeEffects(root, opts) {
1694
2052
  walk(root, "root");
1695
2053
  return warnings;
1696
2054
  }
1697
- function validateDocument(doc) {
1698
- const ctx = { errors: [], warnings: [], strict: true };
2055
+ function validateGlyphFontRefs(root, fonts) {
2056
+ if (!fonts || !Object.keys(fonts).length) return [];
2057
+ const problems = [];
2058
+ const walk = (node, path, inherited, inGlyphText) => {
2059
+ var _a2, _b;
2060
+ if (!node) return;
2061
+ const own = typeof node.fontFamily === "string" ? node.fontFamily : void 0;
2062
+ const family = own != null ? own : inherited;
2063
+ const isGlyphText = inGlyphText || node.type === "text" && !!((_b = (_a2 = node.effects) == null ? void 0 : _a2.text) == null ? void 0 : _b.useGlyphs);
2064
+ if (isGlyphText && own && !Object.prototype.hasOwnProperty.call(fonts, own)) {
2065
+ const problem = path + ': glyph-mode text uses font-family "' + own + '", which has no entry in animator.definitions.fonts';
2066
+ if (!problems.includes(problem)) problems.push(problem);
2067
+ }
2068
+ if (Array.isArray(node.children)) {
2069
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]", family, isGlyphText));
2070
+ }
2071
+ };
2072
+ walk(root, "root", void 0, false);
2073
+ return problems;
2074
+ }
2075
+ function validateEasingRefs(root, easings) {
2076
+ const problems = [];
2077
+ const walk = (node, path) => {
2078
+ if (Array.isArray(node)) {
2079
+ node.forEach((item, i) => walk(item, path + "[" + i + "]"));
2080
+ return;
2081
+ }
2082
+ if (!node || typeof node !== "object") return;
2083
+ const easing = node.easing;
2084
+ if (typeof easing === "string" && !(easings && Object.prototype.hasOwnProperty.call(easings, easing))) {
2085
+ const problem = path + '.easing: "' + easing + '" names no entry in animator.definitions.easings \u2014 it will play linear';
2086
+ if (!problems.includes(problem)) problems.push(problem);
2087
+ }
2088
+ for (const [key, value] of Object.entries(node)) {
2089
+ if (key === "easing") continue;
2090
+ if (value && typeof value === "object") walk(value, path + "." + key);
2091
+ }
2092
+ };
2093
+ walk(root, "root");
2094
+ return problems;
2095
+ }
2096
+ function validateVersionStamp(doc) {
2097
+ var _a2;
2098
+ const version = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.version;
2099
+ if (version === void 0) return [];
2100
+ if (parseWireVersion(version) !== void 0) return [];
2101
+ return ["root.animator.version: " + JSON.stringify(version) + ' is not a version stamp ("a.b" or "a.b.c") \u2014 it reads as unstamped'];
2102
+ }
2103
+ function validateDocument(doc, opts) {
2104
+ var _a2;
2105
+ const strict = (opts == null ? void 0 : opts.strict) !== false;
2106
+ const ctx = { errors: [], warnings: [], strict };
1699
2107
  const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
1700
2108
  if (doc && typeof doc === "object") {
1701
- for (const w of validateNodeEffects(doc, { strict: true })) {
2109
+ for (const w of validateNodeEffects(doc, { strict })) {
2110
+ if (!problems.includes(w)) problems.push(w);
2111
+ }
2112
+ const defs = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
2113
+ for (const w of validateGlyphFontRefs(doc, defs == null ? void 0 : defs.fonts)) {
2114
+ if (!problems.includes(w)) problems.push(w);
2115
+ }
2116
+ for (const w of validateEasingRefs(doc, defs == null ? void 0 : defs.easings)) {
2117
+ if (!problems.includes(w)) problems.push(w);
2118
+ }
2119
+ for (const w of validateVersionStamp(doc)) {
1702
2120
  if (!problems.includes(w)) problems.push(w);
1703
2121
  }
1704
2122
  }
@@ -1721,10 +2139,13 @@ var PxNodeBase = px.openObject({
1721
2139
  // documented — because a wire key that is not in a schema is invisible to the
1722
2140
  // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1723
2141
  domType: px.string().optional(),
2142
+ // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
2143
+ // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
2144
+ textContent: px.string().optional(),
1724
2145
  id: px.string().optional(),
1725
2146
  meta: px.any().optional(),
1726
2147
  // Player-effects bucket emitted by the Editor's lightweight design format.
1727
- // Consumed and removed by `applyPlayerEffects` before any other normalisation
2148
+ // Consumed and removed by `applyPlayerEffects` before any other normalization
1728
2149
  // (see `createAnimatorImpl`), so downstream code never sees it.
1729
2150
  effects: PxEffectsSchema.optional(),
1730
2151
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
@@ -1756,8 +2177,8 @@ var PxBezierPathSchema = implementsInterface()(px.object({
1756
2177
  c: px.boolean().optional()
1757
2178
  }));
1758
2179
  function isPxElementFileFormatDeep(fileJson) {
1759
- const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
1760
- return { valid, errors: valid ? [] : ["Document failed schema validation"] };
2180
+ const errors = validateDocument(fileJson, { strict: false });
2181
+ return { valid: errors.length === 0, errors };
1761
2182
  }
1762
2183
  var _idCounter = 0;
1763
2184
  function generateUniqueId() {
@@ -1912,7 +2333,7 @@ function isDangerousAttrName(nameLower) {
1912
2333
  if (nameLower.startsWith("on")) return true;
1913
2334
  return false;
1914
2335
  }
1915
- function sanitiseAttributeValue(name, value) {
2336
+ function sanitizeAttributeValue(name, value) {
1916
2337
  const nameLower = name.toLowerCase();
1917
2338
  if (isDangerousAttrName(nameLower)) {
1918
2339
  console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
@@ -1951,7 +2372,7 @@ function getNormalizedProps(props) {
1951
2372
  if (INTERNAL_ATTRS.has(key)) continue;
1952
2373
  if (key === "style") continue;
1953
2374
  let value = props[rawKey];
1954
- if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2375
+ if (COLOR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1955
2376
  propsCopy[key] = toRGBA(value);
1956
2377
  } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
1957
2378
  const parts = value.value && typeof value.value === "object" ? value.value : value;
@@ -2051,7 +2472,7 @@ function tFromArcFraction(lut, arcFrac) {
2051
2472
  var DEFAULT_FLATNESS_TOL = 0.5;
2052
2473
  var DEFAULT_ROTATION_TOL = 5;
2053
2474
  var DEFAULT_MAX_SAMPLES = 32;
2054
- function materialiseMotionPathInPropAnim(anim, opts) {
2475
+ function materializeMotionPathInPropAnim(anim, opts) {
2055
2476
  var _a2, _b, _c;
2056
2477
  if (!propAnimIsMotionPath(anim)) return anim;
2057
2478
  const kfs = anim.keyframes;
@@ -2083,7 +2504,7 @@ function materialiseMotionPathInPropAnim(anim, opts) {
2083
2504
  if (autoOrient && i > 0) {
2084
2505
  insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
2085
2506
  }
2086
- materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2507
+ materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2087
2508
  }
2088
2509
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
2089
2510
  if (lastInE) out[out.length - 1].e = lastInE;
@@ -2197,7 +2618,7 @@ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos,
2197
2618
  out.push(makeOutKf(stepTime, dupValue));
2198
2619
  }
2199
2620
  var CORNER_STEP_AFTER_BOUNDARY_MS = 0.05;
2200
- function materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2621
+ function materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2201
2622
  const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2202
2623
  const prevTime = getKfTime(prevKf);
2203
2624
  const nextTime = getKfTime(nextKf);
@@ -2320,16 +2741,16 @@ function perpDist(q, pA, pB) {
2320
2741
  const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
2321
2742
  return Math.abs(cross) / Math.sqrt(len2);
2322
2743
  }
2323
- function materialiseMotionPathsInTree(root, opts) {
2324
- const out = walkAndMaterialise(root, opts);
2744
+ function materializeMotionPathsInTree(root, opts) {
2745
+ const out = walkAndMaterialize(root, opts);
2325
2746
  return out != null ? out : root;
2326
2747
  }
2327
- function walkAndMaterialise(node, opts) {
2748
+ function walkAndMaterialize(node, opts) {
2328
2749
  let newChildren;
2329
2750
  if (node.children) {
2330
2751
  for (let i = 0; i < node.children.length; i++) {
2331
2752
  const ch = node.children[i];
2332
- const ret = walkAndMaterialise(ch, opts);
2753
+ const ret = walkAndMaterialize(ch, opts);
2333
2754
  if (ret !== null) {
2334
2755
  if (!newChildren) newChildren = node.children.slice();
2335
2756
  newChildren[i] = ret;
@@ -2342,9 +2763,9 @@ function walkAndMaterialise(node, opts) {
2342
2763
  const animDef = animBucket;
2343
2764
  const transformAnim = animDef.transform;
2344
2765
  if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
2345
- const materialised = materialiseMotionPathInPropAnim(transformAnim, opts);
2346
- if (materialised !== transformAnim) {
2347
- newAnimate = __spreadProps2(__spreadValues2({}, animDef), { transform: materialised });
2766
+ const materialized = materializeMotionPathInPropAnim(transformAnim, opts);
2767
+ if (materialized !== transformAnim) {
2768
+ newAnimate = __spreadProps2(__spreadValues2({}, animDef), { transform: materialized });
2348
2769
  }
2349
2770
  }
2350
2771
  }
@@ -2445,8 +2866,8 @@ function isPathString(value) {
2445
2866
  return typeof value === "string" && extractPathData(value) !== void 0;
2446
2867
  }
2447
2868
  function normalizePathValue(value) {
2448
- if (value && typeof value === "object" && typeof value.path === "string") {
2449
- const d = extractPathData(value.path);
2869
+ if (value && typeof value === "object" && typeof value.pathData === "string") {
2870
+ const d = extractPathData(value.pathData);
2450
2871
  return d ? { paths: parseSvgPathToBezier(d) } : value;
2451
2872
  }
2452
2873
  if (value && typeof value === "object" && "paths" in value) {
@@ -2530,7 +2951,7 @@ function interpolateValue(propName, a, b, t) {
2530
2951
  const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2531
2952
  return { paths: interpolateBeziers(aPaths, bPaths, t) };
2532
2953
  }
2533
- if (COLOUR_ATTR_NAMES.has(propName)) {
2954
+ if (COLOR_ATTR_NAMES.has(propName)) {
2534
2955
  return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
2535
2956
  }
2536
2957
  if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
@@ -2752,7 +3173,7 @@ function normalizeKeyframes(propName, propAnim, duration, defs) {
2752
3173
  value = normalizePathValue(value);
2753
3174
  }
2754
3175
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2755
- if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
3176
+ if (COLOR_ATTR_NAMES.has(propNameKebab)) {
2756
3177
  value = (_a2 = parseColor(value)) != null ? _a2 : value;
2757
3178
  }
2758
3179
  const normKf = {
@@ -2786,20 +3207,20 @@ function mergeAnimationDefinitions(animations) {
2786
3207
  }
2787
3208
  return merged;
2788
3209
  }
2789
- function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
3210
+ function materializeInternalLoopsInPropAnim(propName, propAnim, duration) {
2790
3211
  const loopRaw = propAnim.loop;
2791
3212
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
2792
3213
  const loop = loopRaw === true ? {} : loopRaw;
2793
3214
  const rawKfs = propAnim.keyframes;
2794
3215
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
2795
3216
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2796
- const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
3217
+ const isColor = COLOR_ATTR_NAMES.has(propNameKebab);
2797
3218
  const kfs = rawKfs.map((kf) => {
2798
3219
  var _a2;
2799
3220
  const t = kfTime(kf);
2800
3221
  let v = kfValue(kf);
2801
3222
  if (propName === "d") v = normalizePathValue(v);
2802
- if (isColour) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3223
+ if (isColor) v = (_a2 = parseColor(v)) != null ? _a2 : v;
2803
3224
  const e = kfEasing(kf);
2804
3225
  const out2 = { t, v, e };
2805
3226
  const tIn = kfTangentIn(kf);
@@ -2813,15 +3234,15 @@ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2813
3234
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2814
3235
  return out;
2815
3236
  }
2816
- function materialiseInternalLoopsInTree(root, duration) {
2817
- const ret = walkAndMaterialiseLoops(root, duration);
3237
+ function materializeInternalLoopsInTree(root, duration) {
3238
+ const ret = walkAndMaterializeLoops(root, duration);
2818
3239
  return ret != null ? ret : root;
2819
3240
  }
2820
- function walkAndMaterialiseLoops(node, duration) {
3241
+ function walkAndMaterializeLoops(node, duration) {
2821
3242
  let newChildren;
2822
3243
  if (node.children) {
2823
3244
  for (let i = 0; i < node.children.length; i++) {
2824
- const ret = walkAndMaterialiseLoops(node.children[i], duration);
3245
+ const ret = walkAndMaterializeLoops(node.children[i], duration);
2825
3246
  if (ret !== null) {
2826
3247
  if (!newChildren) newChildren = node.children.slice();
2827
3248
  newChildren[i] = ret;
@@ -2834,10 +3255,10 @@ function walkAndMaterialiseLoops(node, duration) {
2834
3255
  const animDef = animBucket;
2835
3256
  for (const propName of Object.keys(animDef)) {
2836
3257
  const propAnim = animDef[propName];
2837
- const materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);
2838
- if (materialised !== propAnim) {
3258
+ const materialized = materializeInternalLoopsInPropAnim(propName, propAnim, duration);
3259
+ if (materialized !== propAnim) {
2839
3260
  if (!newAnimate) newAnimate = __spreadValues2({}, animDef);
2840
- newAnimate[propName] = materialised;
3261
+ newAnimate[propName] = materialized;
2841
3262
  }
2842
3263
  }
2843
3264
  }
@@ -2892,12 +3313,12 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimeli
2892
3313
  const out = { keyframes: normalizedKfs };
2893
3314
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2894
3315
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2895
- normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
3316
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materializeMotionPathInPropAnim(out) : out;
2896
3317
  }
2897
3318
  }
2898
3319
  return normalized;
2899
3320
  }
2900
- function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
3321
+ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
2901
3322
  const animatorConfig = getAnimatorConfig(doc) || {};
2902
3323
  const defs = getDefs(doc);
2903
3324
  const duration = animatorConfig.duration || 1e3;
@@ -2988,7 +3409,7 @@ function calcPropertyValue(propName, propAnim, progress) {
2988
3409
  nextPaths,
2989
3410
  localProgress
2990
3411
  ).map((bz) => bezierToSvgPath(bz)).join("");
2991
- } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
3412
+ } else if (COLOR_ATTR_NAMES.has(cssAttrName)) {
2992
3413
  cssValue = toRGBA(interpolateColor(
2993
3414
  prevV || [0, 0, 0, 1],
2994
3415
  nextV || [0, 0, 0, 1],
@@ -3146,7 +3567,7 @@ function applyUseOffsetToG(gNode) {
3146
3567
  }
3147
3568
  return gNode;
3148
3569
  }
3149
- function materialiseAnimatedUseInstances(root) {
3570
+ function materializeAnimatedUseInstances(root) {
3150
3571
  var _a2;
3151
3572
  const idMap = buildIdMap(root);
3152
3573
  const animatedIds = computeAnimatedSubtreeIds(root, idMap);
@@ -3155,7 +3576,7 @@ function materialiseAnimatedUseInstances(root) {
3155
3576
  const genId3 = () => "_lw_use_mat_" + ++idCounter;
3156
3577
  const rootViewport = readRootViewport(root);
3157
3578
  const defsCollector = [];
3158
- const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3579
+ const walked = walkAndMaterialize2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3159
3580
  if (defsCollector.length === 0) return walked;
3160
3581
  const defsNode = { type: "defs", children: defsCollector };
3161
3582
  const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
@@ -3228,7 +3649,7 @@ function stripHash(href) {
3228
3649
  if (typeof href !== "string") return void 0;
3229
3650
  return href.startsWith("#") ? href.slice(1) : href;
3230
3651
  }
3231
- function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3652
+ function materializeOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3232
3653
  var _a2, _b, _c, _d;
3233
3654
  const clone2 = deepClonePxNode(target);
3234
3655
  regenerateIdsAndRewriteRefs(clone2, genId3);
@@ -3236,8 +3657,8 @@ function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsColl
3236
3657
  const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3237
3658
  const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
3238
3659
  const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
3239
- const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3240
- const newNode = __spreadProps2(__spreadValues2({}, useNode), { type: "g", children: [materialisedClone] });
3660
+ const materializedClone = walkAndMaterialize2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3661
+ const newNode = __spreadProps2(__spreadValues2({}, useNode), { type: "g", children: [materializedClone] });
3241
3662
  delete newNode.href;
3242
3663
  delete newNode.width;
3243
3664
  delete newNode.height;
@@ -3275,18 +3696,18 @@ function parseViewBox(v) {
3275
3696
  if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
3276
3697
  return [parts[0], parts[1], parts[2], parts[3]];
3277
3698
  }
3278
- function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3699
+ function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3279
3700
  if (node.type === "use" && typeof node.href === "string") {
3280
3701
  const targetId = stripHash(node.href);
3281
3702
  if (targetId && animatedIds.has(targetId)) {
3282
3703
  const target = idMap.get(targetId);
3283
- if (target) return materialiseOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
3704
+ if (target) return materializeOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
3284
3705
  }
3285
3706
  }
3286
3707
  if (!node.children) return node;
3287
3708
  let changed = false;
3288
3709
  const newChildren = node.children.map((ch) => {
3289
- const m = walkAndMaterialise2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3710
+ const m = walkAndMaterialize2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3290
3711
  if (m !== ch) changed = true;
3291
3712
  return m;
3292
3713
  });
@@ -3312,7 +3733,7 @@ function readAnimatable(raw) {
3312
3733
  const obj = raw;
3313
3734
  const kfs = obj.keyframes;
3314
3735
  if (kfs) {
3315
- const out = { kind: "animated", keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3736
+ const out = { kind: "animated", keyframes: kfs.map(normalizeKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3316
3737
  const base = (_a2 = obj.value) != null ? _a2 : obj.v;
3317
3738
  if (base !== void 0 && out.kind === "animated") out.base = base;
3318
3739
  return out;
@@ -3340,7 +3761,7 @@ function writeAnimatableChannel(node, attrName, read, opts) {
3340
3761
  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;
3341
3762
  if (baseline !== void 0) node[attrName] = toOut(baseline);
3342
3763
  }
3343
- function normaliseKeyframe(kf) {
3764
+ function normalizeKeyframe(kf) {
3344
3765
  if (!kf || typeof kf !== "object") return kf;
3345
3766
  const k = kf;
3346
3767
  if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
@@ -3842,10 +4263,10 @@ function formatOffset(o) {
3842
4263
  return pct + "%";
3843
4264
  }
3844
4265
  function applyClipPathEffect(node, fx, ctx) {
3845
- if (!(fx == null ? void 0 : fx.d)) return node;
4266
+ if (!(fx == null ? void 0 : fx.pathData)) return node;
3846
4267
  const clipId = genId(ctx, "clip");
3847
4268
  const pathChild = { type: "path" };
3848
- const read = readAnimatable(fx.d);
4269
+ const read = readAnimatable(fx.pathData);
3849
4270
  if (read.kind !== "absent") {
3850
4271
  if (read.kind === "static") {
3851
4272
  pathChild.d = pathString(read.value);
@@ -3860,7 +4281,7 @@ function applyClipPathEffect(node, fx, ctx) {
3860
4281
  }
3861
4282
  function pathString(v) {
3862
4283
  if (typeof v === "string") return v;
3863
- if (v && typeof v === "object" && typeof v.path === "string") return v.path;
4284
+ if (v && typeof v === "object" && typeof v.pathData === "string") return v.pathData;
3864
4285
  return void 0;
3865
4286
  }
3866
4287
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
@@ -3905,8 +4326,8 @@ function wrapInverseTransform(inner, fx, ctx) {
3905
4326
  }
3906
4327
  function wrapInversePart(inner, part, raw, origin, ctx) {
3907
4328
  if (raw === void 0) return inner;
3908
- const normalisedRaw = part === "scale" && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
3909
- const v = readAnimatable(normalisedRaw);
4329
+ const normalizedRaw = part === "scale" && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
4330
+ const v = readAnimatable(normalizedRaw);
3910
4331
  if (v.kind === "static") {
3911
4332
  return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
3912
4333
  }
@@ -4301,7 +4722,7 @@ function synthesiseScale(raw, i) {
4301
4722
  const scalePower = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
4302
4723
  return mapAnimatable(raw, scalePower, true);
4303
4724
  }
4304
- var RETIME_MATERIALISATION_MODE_INLINE_G = false;
4725
+ var RETIME_MATERIALIZATION_MODE_INLINE_G = false;
4305
4726
  function asRetime(r) {
4306
4727
  var _a2, _b;
4307
4728
  return { start: (_a2 = r.start) != null ? _a2 : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
@@ -4386,11 +4807,11 @@ function applyAllRetimeEffects(root, ctx) {
4386
4807
  if (!retime) continue;
4387
4808
  const crop = retime.timeCrop;
4388
4809
  clearCloneRetime(useNode);
4389
- materialiseRetime(useNode, asRetime(retime), ctx);
4810
+ materializeRetime(useNode, asRetime(retime), ctx);
4390
4811
  if (crop) applyTimeCrop(useNode, crop, ctx);
4391
4812
  }
4392
4813
  }
4393
- function materialiseRetime(useNode, retime, ctx) {
4814
+ function materializeRetime(useNode, retime, ctx) {
4394
4815
  const targetId = stripHash2(useNode.href);
4395
4816
  if (!targetId) {
4396
4817
  ctx.errors.push("retime: <use> has no href to follow");
@@ -4398,7 +4819,7 @@ function materialiseRetime(useNode, retime, ctx) {
4398
4819
  }
4399
4820
  const chainRootId = buildChainClone(targetId, retime, ctx, /* @__PURE__ */ new Set());
4400
4821
  if (!chainRootId) return;
4401
- if (RETIME_MATERIALISATION_MODE_INLINE_G) {
4822
+ if (RETIME_MATERIALIZATION_MODE_INLINE_G) {
4402
4823
  const cloneNode = ctx.idMap.get(chainRootId);
4403
4824
  useNode.type = "g";
4404
4825
  delete useNode.href;
@@ -4438,13 +4859,13 @@ function buildChainClone(targetId, accum, ctx, chain) {
4438
4859
  if (subId2) cloneNode.href = "#" + subId2;
4439
4860
  }
4440
4861
  } else {
4441
- materialiseNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4862
+ materializeNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4442
4863
  }
4443
4864
  ctx.defs.push(cloneNode);
4444
4865
  if (typeof cloneNode.id === "string") ctx.idMap.set(cloneNode.id, cloneNode);
4445
4866
  return typeof cloneNode.id === "string" ? cloneNode.id : void 0;
4446
4867
  }
4447
- function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4868
+ function materializeNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4448
4869
  const visit = (n) => {
4449
4870
  var _a2;
4450
4871
  const retime = readCloneRetime(n);
@@ -4641,10 +5062,10 @@ function numRange(v) {
4641
5062
  function estimateTextAdvance(node) {
4642
5063
  let chars = 0, maxFont = 16;
4643
5064
  const walk = (el) => {
4644
- var _a2, _b;
5065
+ var _a2;
4645
5066
  const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
4646
5067
  if (fs) maxFont = Math.max(maxFont, fs);
4647
- const t = (_b = el.text) != null ? _b : el.textContent;
5068
+ const t = el.textContent;
4648
5069
  if (typeof t === "string") chars += t.length;
4649
5070
  if (el.children) for (const c of el.children) walk(c);
4650
5071
  };
@@ -4793,7 +5214,6 @@ var TEXT_ATTR_KEYS = [
4793
5214
  "stroke",
4794
5215
  "strokeWidth",
4795
5216
  "effects",
4796
- TEXT_ATTR,
4797
5217
  TEXT_CONTENT_ATTR,
4798
5218
  "xml:space"
4799
5219
  ];
@@ -4903,8 +5323,8 @@ function missingGlyphBoxEm(advanceEm, ascentEm) {
4903
5323
  const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
4904
5324
  return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
4905
5325
  }
4906
- function materialiseGlyphTextHorizontal(node, opts) {
4907
- var _a2, _b, _c, _d;
5326
+ function materializeGlyphTextHorizontal(node, opts) {
5327
+ var _a2, _b, _c;
4908
5328
  const { glyphs, create = jsonElementFactory, warnings } = opts;
4909
5329
  const soleFont = soleFontOf(glyphs);
4910
5330
  const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
@@ -4921,8 +5341,8 @@ function materialiseGlyphTextHorizontal(node, opts) {
4921
5341
  for (let i = 0; i < content.length; i++) {
4922
5342
  const ch = content.charAt(i);
4923
5343
  const g = gf == null ? void 0 : gf.glyphs[ch];
4924
- if (g && g.d) {
4925
- placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
5344
+ if (g && g.pathData) {
5345
+ placements.push({ glyphD: g.pathData, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
4926
5346
  pen.x += g.width * scale;
4927
5347
  } else if (/\S/.test(ch)) {
4928
5348
  const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
@@ -4936,7 +5356,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4936
5356
  }
4937
5357
  };
4938
5358
  const walk = (el, parentStyle) => {
4939
- var _a3, _b2, _c2, _d2;
5359
+ var _a3, _b2, _c2;
4940
5360
  const s = resolveStyle2(el, parentStyle);
4941
5361
  const x = parseLen(el.x);
4942
5362
  const y = parseLen(el.y);
@@ -4948,14 +5368,14 @@ function materialiseGlyphTextHorizontal(node, opts) {
4948
5368
  if (y !== void 0) pen.y = y;
4949
5369
  pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4950
5370
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4951
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
4952
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5371
+ const content = str(el[TEXT_CONTENT_ATTR]);
5372
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
4953
5373
  if (el.children) for (const ch of el.children) walk(ch, s);
4954
5374
  };
4955
5375
  const rootStyle = rootStyleOf(node);
4956
5376
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
4957
- const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
4958
- if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
5377
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5378
+ if (rootContent && !((_c = node.children) == null ? void 0 : _c.length)) renderChars(rootContent, rootStyle);
4959
5379
  const anchor = str(node.textAnchor);
4960
5380
  if (anchor === "middle" || anchor === "end") {
4961
5381
  for (const p of placements) {
@@ -4967,7 +5387,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4967
5387
  return toGroup(node, buildPaths(placements, create, warnings), create);
4968
5388
  }
4969
5389
  function layoutGlyphTextChars(node, opts) {
4970
- var _a2, _b, _c, _d, _e, _f;
5390
+ var _a2, _b, _c, _d, _e;
4971
5391
  if ((_a2 = opts.alongPath) == null ? void 0 : _a2.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
4972
5392
  const { glyphs, warnings } = opts;
4973
5393
  const soleFont = soleFontOf(glyphs);
@@ -4991,7 +5411,7 @@ function layoutGlyphTextChars(node, opts) {
4991
5411
  }
4992
5412
  };
4993
5413
  const walk = (el, parentStyle) => {
4994
- var _a3, _b2, _c2, _d2;
5414
+ var _a3, _b2, _c2;
4995
5415
  const s = resolveStyle2(el, parentStyle);
4996
5416
  const x = parseLen(el.x);
4997
5417
  const y = parseLen(el.y);
@@ -5003,8 +5423,8 @@ function layoutGlyphTextChars(node, opts) {
5003
5423
  if (y !== void 0) pen.y = y;
5004
5424
  pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
5005
5425
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
5006
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
5007
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5426
+ const content = str(el[TEXT_CONTENT_ATTR]);
5427
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
5008
5428
  if (el.children) for (const ch of el.children) walk(ch, s);
5009
5429
  };
5010
5430
  const rootStyle = rootStyleOf(node);
@@ -5018,8 +5438,8 @@ function layoutGlyphTextChars(node, opts) {
5018
5438
  boxes.push({ x: pen.x, y: pen.y, width: 0, ascent: ((_d = gf == null ? void 0 : gf.ascent) != null ? _d : 0.9 * upm) * (s.fontSize / upm), fontSize: s.fontSize, line });
5019
5439
  }
5020
5440
  }
5021
- const rootContent = (_e = str(node[TEXT_CONTENT_ATTR])) != null ? _e : str(node[TEXT_ATTR]);
5022
- if (rootContent && !((_f = node.children) == null ? void 0 : _f.length)) renderChars(rootContent, rootStyle);
5441
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5442
+ if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
5023
5443
  const anchor = str(node.textAnchor);
5024
5444
  if (anchor === "middle" || anchor === "end") {
5025
5445
  for (const b of boxes) {
@@ -5027,8 +5447,8 @@ function layoutGlyphTextChars(node, opts) {
5027
5447
  b.x += anchor === "middle" ? -w / 2 : -w;
5028
5448
  }
5029
5449
  }
5030
- return boxes.map((_g) => {
5031
- var _h = _g, { line: _l } = _h, b = __objRest2(_h, ["line"]);
5450
+ return boxes.map((_f) => {
5451
+ var _g = _f, { line: _l } = _g, b = __objRest2(_g, ["line"]);
5032
5452
  return b;
5033
5453
  });
5034
5454
  }
@@ -5044,14 +5464,14 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
5044
5464
  const chars = [];
5045
5465
  let adv = 0;
5046
5466
  const walk = (el, parentStyle) => {
5047
- var _a3, _b2, _c;
5467
+ var _a3, _b2;
5048
5468
  const s = resolveStyle2(el, parentStyle);
5049
- const content = (_a3 = str(el[TEXT_CONTENT_ATTR])) != null ? _a3 : str(el[TEXT_ATTR]);
5050
- if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
5469
+ const content = str(el[TEXT_CONTENT_ATTR]);
5470
+ if (content && !((_a3 = el.children) == null ? void 0 : _a3.length)) {
5051
5471
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
5052
5472
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
5053
5473
  const scale = s.fontSize / upm;
5054
- const ascent = ((_c = gf == null ? void 0 : gf.ascent) != null ? _c : 0.9 * upm) * scale;
5474
+ const ascent = ((_b2 = gf == null ? void 0 : gf.ascent) != null ? _b2 : 0.9 * upm) * scale;
5055
5475
  for (let i = 0; i < content.length; i++) {
5056
5476
  const ch = content.charAt(i);
5057
5477
  const g = gf == null ? void 0 : gf.glyphs[ch];
@@ -5098,21 +5518,21 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
5098
5518
  const cells = [];
5099
5519
  let adv = 0;
5100
5520
  const walk = (el, parentStyle) => {
5101
- var _a2, _b, _c;
5521
+ var _a2, _b;
5102
5522
  const s = resolveStyle2(el, parentStyle);
5103
- const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
5104
- if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
5523
+ const content = str(el[TEXT_CONTENT_ATTR]);
5524
+ if (content && !((_a2 = el.children) == null ? void 0 : _a2.length)) {
5105
5525
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
5106
5526
  if (gf) {
5107
5527
  const scale = s.fontSize / gf.unitsPerEm;
5108
- const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
5528
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
5109
5529
  const paint = paintOf(s);
5110
5530
  for (let i = 0; i < content.length; i++) {
5111
5531
  const ch = content.charAt(i);
5112
5532
  const g = gf.glyphs[ch];
5113
- if (g && g.d) {
5533
+ if (g && g.pathData) {
5114
5534
  const glyphAdv = g.width * scale;
5115
- cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
5535
+ cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
5116
5536
  adv += glyphAdv;
5117
5537
  } else if (/\S/.test(ch)) {
5118
5538
  const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
@@ -5143,7 +5563,7 @@ function alongPathNodeOffsets(node) {
5143
5563
  perp: (_c = parseLen(node.dy)) != null ? _c : 0
5144
5564
  };
5145
5565
  }
5146
- function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5566
+ function materializeGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5147
5567
  const { glyphs, create = jsonElementFactory, warnings } = opts;
5148
5568
  const sampler = pathD ? createPathSampler(pathD) : null;
5149
5569
  if (!sampler) {
@@ -5222,8 +5642,8 @@ function buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isC
5222
5642
  const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
5223
5643
  const out = [];
5224
5644
  for (const c of cells) {
5225
- const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5226
- const d = transformPathData(c.glyphD, centred);
5645
+ const centered = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5646
+ const d = transformPathData(c.glyphD, centered);
5227
5647
  const sampleKf = (dist, time) => {
5228
5648
  const { x, y, angle } = sampler.sampleAtDistance(dist);
5229
5649
  const cos = Math.cos(angle), sin = Math.sin(angle);
@@ -5321,9 +5741,9 @@ function toGroup(node, children, create) {
5321
5741
  }
5322
5742
  return create("g", gProps, children);
5323
5743
  }
5324
- function materialiseGlyphText(node, opts) {
5325
- if (opts.alongPath) return materialiseGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5326
- return materialiseGlyphTextHorizontal(node, opts);
5744
+ function materializeGlyphText(node, opts) {
5745
+ if (opts.alongPath) return materializeGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5746
+ return materializeGlyphTextHorizontal(node, opts);
5327
5747
  }
5328
5748
  function applyTextGlyphsEffect(node, fx, ctx) {
5329
5749
  if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
@@ -5331,14 +5751,14 @@ function applyTextGlyphsEffect(node, fx, ctx) {
5331
5751
  ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
5332
5752
  return node;
5333
5753
  }
5334
- return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5754
+ return materializeGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5335
5755
  }
5336
5756
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
5337
5757
  if (!ctx.glyphs) {
5338
5758
  ctx.warnings.push("textGlyphs: no definitions.fonts");
5339
5759
  return null;
5340
5760
  }
5341
- return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5761
+ return materializeGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5342
5762
  }
5343
5763
  function applyStrokeTrimEffect(node, strokeTrim, ctx) {
5344
5764
  if (!strokeTrim) return node;
@@ -5800,7 +6220,7 @@ function buildOffsetPath(propAnim) {
5800
6220
  }
5801
6221
  return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
5802
6222
  }
5803
- function materialiseOffsetPathsInTree(root) {
6223
+ function materializeOffsetPathsInTree(root) {
5804
6224
  const walk = (node) => {
5805
6225
  var _a2;
5806
6226
  let out = node;
@@ -5843,15 +6263,15 @@ function materialiseOffsetPathsInTree(root) {
5843
6263
  };
5844
6264
  return walk(root);
5845
6265
  }
5846
- function materialiseAllInTree(doc, engine, opts) {
6266
+ function materializeAllInTree(doc, engine, opts) {
5847
6267
  var _a2, _b;
5848
6268
  let root = applyPlayerEffects(doc).root;
5849
- root = materialiseOffsetPathsInTree(root);
6269
+ root = materializeOffsetPathsInTree(root);
5850
6270
  const duration = (_b = (_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.duration) != null ? _b : DEFAULT_DURATION_MS;
5851
- root = materialiseInternalLoopsInTree(root, duration);
6271
+ root = materializeInternalLoopsInTree(root, duration);
5852
6272
  if (engine === PxTimelineEngine.native) {
5853
- root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5854
- root = materialiseAnimatedUseInstances(root);
6273
+ root = materializeMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
6274
+ root = materializeAnimatedUseInstances(root);
5855
6275
  root = pruneUnreferencedDefs(root);
5856
6276
  }
5857
6277
  return root;
@@ -5885,6 +6305,38 @@ function pruneUnreferencedDefs(root) {
5885
6305
  }
5886
6306
  return root;
5887
6307
  }
6308
+ var PX_RATE_REJECTED = "setPlaybackRate: rate must be finite and non-zero";
6309
+ function isValidPlaybackRate(rate) {
6310
+ return Number.isFinite(rate) && rate !== 0;
6311
+ }
6312
+ function seekCeilingMs(durationMs, iterations) {
6313
+ if (!(durationMs > 0)) return 0;
6314
+ if (iterations === Infinity) return Infinity;
6315
+ return durationMs * (iterations > 0 ? iterations : 1);
6316
+ }
6317
+ function progressSpanMs(durationMs, iterations) {
6318
+ if (!(durationMs > 0)) return 0;
6319
+ if (iterations === Infinity) return durationMs;
6320
+ return durationMs * (iterations > 0 ? iterations : 1);
6321
+ }
6322
+ function clampSeekMs(timeMs, ceilingMs) {
6323
+ if (Number.isNaN(timeMs) || timeMs < 0) return 0;
6324
+ if (Number.isFinite(ceilingMs)) return timeMs > ceilingMs ? ceilingMs : timeMs;
6325
+ return Number.isFinite(timeMs) ? timeMs : 0;
6326
+ }
6327
+ function timeToProgress(timeMs, durationMs, iterations) {
6328
+ const span = progressSpanMs(durationMs, iterations);
6329
+ if (!(span > 0) || !Number.isFinite(timeMs)) return 0;
6330
+ if (timeMs <= 0) return 0;
6331
+ if (iterations === Infinity) return timeMs % span / span;
6332
+ return timeMs >= span ? 1 : timeMs / span;
6333
+ }
6334
+ function progressToTimeMs(progress, durationMs, iterations) {
6335
+ const span = progressSpanMs(durationMs, iterations);
6336
+ if (!(span > 0) || !Number.isFinite(progress)) return 0;
6337
+ if (progress <= 0) return 0;
6338
+ return progress >= 1 ? span : progress * span;
6339
+ }
5888
6340
  function requestFrame(cb) {
5889
6341
  const g = globalThis;
5890
6342
  if (typeof g.requestAnimationFrame === "function") return g.requestAnimationFrame(cb);
@@ -5901,7 +6353,7 @@ function cancelFrame(handle) {
5901
6353
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5902
6354
  var _a2;
5903
6355
  const config = getAnimatorConfig(doc) || {};
5904
- const bindings = getNormalisedBindings(doc, PxTimelineEngine.js);
6356
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.js);
5905
6357
  const _iterations = config.iterations;
5906
6358
  let iterations = 1;
5907
6359
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -6131,8 +6583,8 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6131
6583
  finishAnim(true);
6132
6584
  },
6133
6585
  "setPlaybackRate": (rate) => {
6134
- if (!isFinite(rate) || rate === 0) {
6135
- console.warn("setPlaybackRate: rate must be finite and non-zero");
6586
+ if (!isValidPlaybackRate(rate)) {
6587
+ console.warn(PX_RATE_REJECTED);
6136
6588
  return;
6137
6589
  }
6138
6590
  let current = getRawAnimTime();
@@ -6146,13 +6598,16 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6146
6598
  return getAnimCurrentTime();
6147
6599
  },
6148
6600
  "setCurrentTime": (newTime) => {
6149
- if (newTime < 0) newTime = 0;
6150
- if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
6601
+ newTime = clampSeekMs(newTime, totalDuration);
6151
6602
  timeBeforeLastStartMs = newTime;
6152
6603
  if (playing) lastStartedTs = Date.now();
6153
6604
  if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
6154
6605
  renderFrame(getAnimCurrentTime());
6155
6606
  },
6607
+ "getCurrentProgress": () => timeToProgress(getAnimCurrentTime(), duration, iterations),
6608
+ "setCurrentProgress": (progress) => {
6609
+ api.setCurrentTime(progressToTimeMs(progress, duration, iterations));
6610
+ },
6156
6611
  "destroy": () => {
6157
6612
  var _a3;
6158
6613
  api.cancel();
@@ -6161,6 +6616,49 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6161
6616
  };
6162
6617
  return api;
6163
6618
  }
6619
+ var PxDiagnosticKind = {
6620
+ /** The document is wrong — regenerate or repair the file. */
6621
+ document: "document",
6622
+ /** The page or app cannot provide what the document asks for — fix the mount. */
6623
+ host: "host",
6624
+ /** The platform cannot do it and the player degraded — usually nothing to fix. */
6625
+ platform: "platform",
6626
+ /** The call is wrong or self-contradictory — fix the options or props you passed. */
6627
+ usage: "usage",
6628
+ /** The player failed where it did not expect to — report it to us. */
6629
+ internal: "internal"
6630
+ };
6631
+ function asError(error) {
6632
+ return typeof error === "string" ? new Error(error) : error;
6633
+ }
6634
+ function isSilenced(silent, kind) {
6635
+ if (!silent) return false;
6636
+ return silent === true || silent.includes(kind);
6637
+ }
6638
+ function createDiagnostics(config, prefix) {
6639
+ const tag = prefix ? prefix + " " : "";
6640
+ return {
6641
+ warn: (kind, message, detail) => {
6642
+ if (config == null ? void 0 : config.onWarn) {
6643
+ config.onWarn({ kind, message, detail });
6644
+ return;
6645
+ }
6646
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6647
+ const line = tag + kind + ": " + message;
6648
+ if (detail === void 0) console.warn(line);
6649
+ else console.warn(line, detail);
6650
+ },
6651
+ error: (kind, error) => {
6652
+ const err = asError(error);
6653
+ if (config == null ? void 0 : config.onError) {
6654
+ config.onError({ kind, message: err.message, error: err });
6655
+ return;
6656
+ }
6657
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6658
+ console.error(tag + kind + ": " + err.message);
6659
+ }
6660
+ };
6661
+ }
6164
6662
  var IDENTITY = [1, 0, 0, 1, 0, 0];
6165
6663
  function mul(m, n) {
6166
6664
  return [
@@ -6430,32 +6928,30 @@ function mergeTimeline(base, patch, warn) {
6430
6928
  }
6431
6929
  return merged;
6432
6930
  }
6433
- function foldAnimatorConfigShortcuts(config, shortcuts) {
6931
+ function foldTimelineOverride(timeline, shortcuts) {
6434
6932
  let base;
6435
- if (typeof config === "string") {
6933
+ if (typeof timeline === "string") {
6436
6934
  try {
6437
- base = JSON.parse(config);
6935
+ base = JSON.parse(timeline);
6438
6936
  } catch (e) {
6439
- console.warn("animator config: not valid JSON \u2014 ignored", e);
6937
+ console.warn("timeline override: not valid JSON \u2014 ignored", e);
6440
6938
  base = void 0;
6441
6939
  }
6442
6940
  } else {
6443
- base = config != null ? config : void 0;
6941
+ base = timeline != null ? timeline : void 0;
6444
6942
  }
6445
6943
  const { duration, delay, iterations, startOn } = shortcuts;
6446
6944
  if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6447
- return base;
6945
+ return base === void 0 ? void 0 : { timeline: base };
6448
6946
  }
6449
6947
  const out = isPlainObject(base) ? __spreadValues2({}, base) : {};
6450
- const timeline = __spreadValues2({}, out.timeline);
6451
- if (duration !== void 0) timeline.duration = duration;
6452
- if (delay !== void 0) timeline.delay = delay;
6453
- if (iterations !== void 0) timeline.iterations = iterations;
6948
+ if (duration !== void 0) out.duration = duration;
6949
+ if (delay !== void 0) out.delay = delay;
6950
+ if (iterations !== void 0) out.iterations = iterations;
6454
6951
  if (startOn !== void 0) {
6455
- timeline.trigger = __spreadProps2(__spreadValues2({}, timeline.trigger), { startOn });
6952
+ out.trigger = __spreadProps2(__spreadValues2({}, out.trigger), { startOn });
6456
6953
  }
6457
- out.timeline = timeline;
6458
- return out;
6954
+ return { timeline: out };
6459
6955
  }
6460
6956
  function mergeAnimatorConfig(base, patch) {
6461
6957
  const warnings = [];
@@ -6521,26 +7017,12 @@ function applyAnimatorConfig(doc, patch, opts) {
6521
7017
  return { doc: __spreadProps2(__spreadValues2({}, anyDoc), { animator: merged.config }), warnings };
6522
7018
  }
6523
7019
  var MAX_REPORTED = 6;
6524
- var LEGACY_FLAT_KEYS = [
6525
- ...PX_TIMELINE_SHARED_KEYS,
6526
- ...PX_TIME_ONLY_TIMELINE_KEYS,
6527
- "fill",
6528
- "resetOnFinish",
6529
- "timelineSource",
6530
- "scroll"
6531
- ];
6532
- var isLegacyFlatAnimatorKey = (w) => LEGACY_FLAT_KEYS.some((k) => w.indexOf("animator." + k + ":") >= 0);
6533
7020
  function diagnoseDocument(doc) {
6534
- let all;
6535
7021
  try {
6536
- all = validateDocument(doc);
7022
+ return { problems: validateDocument(doc) };
6537
7023
  } catch (e) {
6538
- return { problems: [], legacy: [] };
7024
+ return { problems: [] };
6539
7025
  }
6540
- const problems = [];
6541
- const legacy = [];
6542
- for (const w of all) (isLegacyFlatAnimatorKey(w) ? legacy : problems).push(w);
6543
- return { problems, legacy };
6544
7026
  }
6545
7027
  function reportDocumentDiagnostics(doc, where) {
6546
7028
  const { problems } = diagnoseDocument(doc);
@@ -6552,13 +7034,37 @@ function reportDocumentDiagnostics(doc, where) {
6552
7034
  );
6553
7035
  }
6554
7036
 
7037
+ // src/shared/PxAnimatorCallbacks.ts
7038
+ function toEngineCallbacks(inline) {
7039
+ const { onPlay, onPause, onCancel, onFinish, onRemove, onStop, onWarn, onError, silent } = inline != null ? inline : {};
7040
+ const withStop = (own) => own || onStop ? () => {
7041
+ own == null ? void 0 : own();
7042
+ onStop == null ? void 0 : onStop();
7043
+ } : void 0;
7044
+ return {
7045
+ onPlay,
7046
+ onPause: withStop(onPause),
7047
+ onCancel: withStop(onCancel),
7048
+ onFinish: withStop(onFinish),
7049
+ onRemove: withStop(onRemove),
7050
+ onWarn,
7051
+ onError,
7052
+ silent
7053
+ };
7054
+ }
7055
+
6555
7056
  // src/triggers/PxAnimatorTriggers.ts
6556
- function setupAnimationTriggers(api, config) {
6557
- const { startOn, outAction = "continue", scrollIntoViewThreshold = 0 } = config;
7057
+ function setupAnimationTriggers(api, config, diag) {
7058
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
7059
+ const cleanups = [];
7060
+ const dispose = () => {
7061
+ for (const undo of cleanups.splice(0)) undo();
7062
+ };
7063
+ const { startOn, outAction, scrollIntoViewThreshold } = resolveTrigger(config);
6558
7064
  const root = api.getRootElement();
6559
7065
  if (!root) {
6560
- console.warn("setupAnimationTriggers: No root element found for animation.");
6561
- return api;
7066
+ report.warn(PxDiagnosticKind.host, "setupAnimationTriggers: No root element found for animation.");
7067
+ return dispose;
6562
7068
  }
6563
7069
  let reversed = false;
6564
7070
  const start = () => {
@@ -6593,6 +7099,7 @@ function setupAnimationTriggers(api, config) {
6593
7099
  startHandler();
6594
7100
  } else {
6595
7101
  window.addEventListener("load", startHandler, { once: true });
7102
+ cleanups.push(() => window.removeEventListener("load", startHandler));
6596
7103
  }
6597
7104
  break;
6598
7105
  }
@@ -6607,6 +7114,10 @@ function setupAnimationTriggers(api, config) {
6607
7114
  };
6608
7115
  root.addEventListener("mouseenter", mouseOverHandler);
6609
7116
  root.addEventListener("mouseleave", mouseOutHandler);
7117
+ cleanups.push(() => {
7118
+ root.removeEventListener("mouseenter", mouseOverHandler);
7119
+ root.removeEventListener("mouseleave", mouseOutHandler);
7120
+ });
6610
7121
  break;
6611
7122
  }
6612
7123
  case "click": {
@@ -6618,6 +7129,7 @@ function setupAnimationTriggers(api, config) {
6618
7129
  }
6619
7130
  };
6620
7131
  root.addEventListener("click", clickHandler);
7132
+ cleanups.push(() => root.removeEventListener("click", clickHandler));
6621
7133
  break;
6622
7134
  }
6623
7135
  case "scrollIntoView": {
@@ -6649,12 +7161,13 @@ function setupAnimationTriggers(api, config) {
6649
7161
  { threshold: thresholdSteps }
6650
7162
  );
6651
7163
  observer.observe(root);
7164
+ cleanups.push(() => observer.disconnect());
6652
7165
  break;
6653
7166
  }
6654
7167
  case "programmatic":
6655
7168
  break;
6656
7169
  }
6657
- return api;
7170
+ return dispose;
6658
7171
  }
6659
7172
 
6660
7173
  // src/engines/PxAnimatorFrameLoop.ts
@@ -6662,35 +7175,41 @@ function getSelector(id) {
6662
7175
  return "#" + id;
6663
7176
  }
6664
7177
  function createFrameLoopAnimator(doc, adapter, callbacks, rootElement) {
7178
+ var _a2;
6665
7179
  const config = getAnimatorConfig(doc) || {};
7180
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
6666
7181
  if (!rootElement) {
6667
7182
  if (doc.id) {
6668
7183
  const rootSelector = getSelector(doc.id);
6669
7184
  rootElement = document.querySelector(rootSelector);
6670
- if (!rootElement) console.warn("createFrameLoopAnimator: No root element found for selector: ", rootSelector);
7185
+ if (!rootElement) diag.warn(PxDiagnosticKind.host, "createFrameLoopAnimator: No root element found for selector: " + rootSelector);
6671
7186
  } else {
6672
- console.warn("createFrameLoopAnimator: No root element provided");
7187
+ diag.warn(PxDiagnosticKind.host, "createFrameLoopAnimator: No root element provided");
6673
7188
  }
6674
7189
  }
6675
7190
  const basicApi = createBasicFrameLoopAnimator(
6676
7191
  doc,
6677
- adapter || createDomAdapter(rootElement),
7192
+ adapter || createDomAdapter(rootElement, diag),
6678
7193
  callbacks
6679
7194
  );
6680
7195
  const api = __spreadProps(__spreadValues({}, basicApi), {
6681
7196
  "getRootElement": () => rootElement || null
6682
7197
  });
6683
- if (config.trigger) {
6684
- if (isScrollTimeline(config)) {
6685
- console.warn("scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
6686
- } else {
6687
- setupAnimationTriggers(api, config.trigger);
6688
- }
7198
+ if (isScrollTimeline(config)) {
7199
+ if (config.trigger) diag.warn(PxDiagnosticKind.usage, "scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
7200
+ } else {
7201
+ const detachTriggers = setupAnimationTriggers(api, (_a2 = config.trigger) != null ? _a2 : {}, diag);
7202
+ const destroyEngine = api.destroy.bind(api);
7203
+ api.destroy = () => {
7204
+ detachTriggers();
7205
+ destroyEngine();
7206
+ };
6689
7207
  }
6690
7208
  return api;
6691
7209
  }
6692
- function createDomAdapter(rootElement) {
7210
+ function createDomAdapter(rootElement, diag) {
6693
7211
  const warnedSelectors = /* @__PURE__ */ new Set();
7212
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
6694
7213
  const adapter = {
6695
7214
  isConnected: () => {
6696
7215
  if (!rootElement) return true;
@@ -6702,7 +7221,7 @@ function createDomAdapter(rootElement) {
6702
7221
  const elements = (rootElement == null ? void 0 : rootElement.querySelectorAll(selector)) || document.querySelectorAll(selector);
6703
7222
  if (elements.length === 0 && !warnedSelectors.has(selector)) {
6704
7223
  warnedSelectors.add(selector);
6705
- console.warn('setAttribute: No elements found for selector "' + selector + '"');
7224
+ report.warn(PxDiagnosticKind.host, 'setAttribute: No elements found for selector "' + selector + '"');
6706
7225
  }
6707
7226
  for (let i = 0; i < elements.length; i++) {
6708
7227
  const element = elements[i];
@@ -6727,7 +7246,7 @@ function createCssKf(kf, t, propName, unsupportedSet) {
6727
7246
  };
6728
7247
  let cssValue;
6729
7248
  let cssKey = propName;
6730
- if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
7249
+ if (COLOR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
6731
7250
  cssValue = toRGBA(value);
6732
7251
  } else if (propName === "transform" && value !== null && typeof value === "object" && !Array.isArray(value)) {
6733
7252
  cssValue = composeTransformParts(value, { withUnits: true });
@@ -6814,18 +7333,19 @@ function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
6814
7333
  return result;
6815
7334
  }
6816
7335
  function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs, scrollTimeline) {
6817
- var _a2;
7336
+ var _a2, _b;
6818
7337
  const config = getAnimatorConfig(doc) || {};
7338
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
6819
7339
  if (!rootElement) {
6820
7340
  if (doc.id) {
6821
7341
  const rootSelector = getSelector(doc.id);
6822
7342
  rootElement = document.querySelector(rootSelector);
6823
- if (!rootElement) console.warn("createFrameLoopAnimator: No root element found for selector: ", rootSelector);
7343
+ if (!rootElement) diag.warn(PxDiagnosticKind.host, "createWebApiAnimator: No root element found for selector: " + rootSelector);
6824
7344
  } else {
6825
- console.warn("createFrameLoopAnimator: No root element provided");
7345
+ diag.warn(PxDiagnosticKind.host, "createWebApiAnimator: No root element provided");
6826
7346
  }
6827
7347
  }
6828
- const bindings = getNormalisedBindings(doc, PxTimelineEngine.native);
7348
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.native);
6829
7349
  const animations = [];
6830
7350
  const _iterations = config.iterations;
6831
7351
  let iterations;
@@ -6835,18 +7355,18 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
6835
7355
  let finishNotified = false;
6836
7356
  let removeCalled = false;
6837
7357
  if (!(bindings == null ? void 0 : bindings.length)) {
6838
- console.warn("createWebApiAnimator: No animation bindings defined");
7358
+ diag.warn(PxDiagnosticKind.document, "createWebApiAnimator: No animation bindings defined");
6839
7359
  }
6840
7360
  for (const binding of bindings || []) {
6841
7361
  const animDef = binding.animate;
6842
7362
  if (!animDef || typeof animDef !== "object" || Array.isArray(animDef)) {
6843
- console.warn("createWebApiAnimator: Empty or unresolved binding", binding);
7363
+ diag.warn(PxDiagnosticKind.document, "createWebApiAnimator: Empty or unresolved binding", binding);
6844
7364
  continue;
6845
7365
  }
6846
7366
  const selector = getSelector(binding.id);
6847
7367
  const elements = (rootElement == null ? void 0 : rootElement.querySelectorAll(selector)) || document.querySelectorAll(selector);
6848
7368
  if (elements.length === 0) {
6849
- console.warn('createWebApiAnimator: No elements found for selector "' + selector + '"');
7369
+ diag.warn(PxDiagnosticKind.host, 'createWebApiAnimator: No elements found for selector "' + selector + '"');
6850
7370
  }
6851
7371
  const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
6852
7372
  const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
@@ -6895,14 +7415,14 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
6895
7415
  }
6896
7416
  animations.push(anim);
6897
7417
  } catch (e) {
6898
- console.warn(e);
7418
+ diag.warn(PxDiagnosticKind.internal, "createWebApiAnimator: could not build the animation", e);
6899
7419
  }
6900
7420
  }
6901
7421
  }
6902
7422
  }
6903
7423
  }
6904
7424
  if (!forceEvenIfHasUnsupportedAttrs && unsupportedSet.size) {
6905
- console.warn("Unsupported CSS attrs: " + [...unsupportedSet].join(", "));
7425
+ diag.warn(PxDiagnosticKind.platform, "Unsupported CSS attrs: " + [...unsupportedSet].join(", "));
6906
7426
  return null;
6907
7427
  }
6908
7428
  const api = {
@@ -6946,20 +7466,36 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
6946
7466
  }
6947
7467
  },
6948
7468
  "setPlaybackRate": (rate) => {
7469
+ if (!isValidPlaybackRate(rate)) {
7470
+ diag.warn(PxDiagnosticKind.usage, PX_RATE_REJECTED);
7471
+ return api;
7472
+ }
6949
7473
  animations.forEach((a) => a.playbackRate = rate);
6950
7474
  return api;
6951
7475
  },
6952
7476
  "getCurrentTime": () => {
6953
- var _a3, _b;
6954
- const res = (_b = (_a3 = animations[0]) == null ? void 0 : _a3.currentTime) != null ? _b : null;
7477
+ var _a3, _b2;
7478
+ const res = (_b2 = (_a3 = animations[0]) == null ? void 0 : _a3.currentTime) != null ? _b2 : null;
6955
7479
  return res !== null ? +res : null;
6956
7480
  },
6957
7481
  "setCurrentTime": (time) => {
7482
+ var _a3;
7483
+ const ceiling = seekCeilingMs((_a3 = config.duration) != null ? _a3 : 0, iterations != null ? iterations : 1);
7484
+ const seek = ceiling > 0 ? clampSeekMs(time, ceiling) : Math.max(0, time);
6958
7485
  finishNotified = false;
6959
7486
  animations.forEach((a) => {
6960
- a.currentTime = time;
7487
+ a.currentTime = seek;
6961
7488
  });
6962
7489
  },
7490
+ "getCurrentProgress": () => {
7491
+ var _a3;
7492
+ const t = api.getCurrentTime();
7493
+ return t === null ? null : timeToProgress(t, (_a3 = config.duration) != null ? _a3 : 0, iterations != null ? iterations : 1);
7494
+ },
7495
+ "setCurrentProgress": (progress) => {
7496
+ var _a3;
7497
+ api.setCurrentTime(progressToTimeMs(progress, (_a3 = config.duration) != null ? _a3 : 0, iterations != null ? iterations : 1));
7498
+ },
6963
7499
  "destroy": () => {
6964
7500
  var _a3;
6965
7501
  api.cancel();
@@ -6970,12 +7506,15 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
6970
7506
  }
6971
7507
  }
6972
7508
  };
6973
- if (config.trigger) {
6974
- if (config.timelineSource === "scroll") {
6975
- console.warn("scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
6976
- } else {
6977
- setupAnimationTriggers(api, config.trigger);
6978
- }
7509
+ if (config.timelineSource === "scroll") {
7510
+ if (config.trigger) diag.warn(PxDiagnosticKind.usage, "scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
7511
+ } else {
7512
+ const detachTriggers = setupAnimationTriggers(api, (_b = config.trigger) != null ? _b : {}, diag);
7513
+ const destroyEngine = api.destroy.bind(api);
7514
+ api.destroy = () => {
7515
+ detachTriggers();
7516
+ destroyEngine();
7517
+ };
6979
7518
  }
6980
7519
  if (scrollTimeline) {
6981
7520
  animations.forEach((a) => a.play());
@@ -6991,13 +7530,14 @@ function nativeRangeOffset(point, defaultFraction, view) {
6991
7530
  if (pct === void 0) return void 0;
6992
7531
  return view ? { rangeName: (_c = point == null ? void 0 : point.phase) != null ? _c : "cover", offset: pct } : { offset: pct };
6993
7532
  }
6994
- function createNativeScrollTimeline(subject, config) {
7533
+ function createNativeScrollTimeline(subject, config, diag) {
6995
7534
  var _a2, _b, _c, _d;
7535
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
6996
7536
  if (!config || !isScrollTimeline(config)) return null;
6997
7537
  const scroll = config.scroll || {};
6998
7538
  const kind = (_a2 = scroll.kind) != null ? _a2 : "view";
6999
7539
  if (scroll.smoothing) {
7000
- console.warn("scroll timeline: `smoothing` needs the built-in driver \u2014 using the built-in driver instead of the browser timeline");
7540
+ report.warn(PxDiagnosticKind.platform, "scroll timeline: `smoothing` needs the built-in driver \u2014 using the built-in driver instead of the browser timeline");
7001
7541
  return null;
7002
7542
  }
7003
7543
  const g = globalThis;
@@ -7008,13 +7548,13 @@ function createNativeScrollTimeline(subject, config) {
7008
7548
  let timeline;
7009
7549
  try {
7010
7550
  if (view) {
7011
- timeline = new Ctor({ subject: resolveScrollSubject(subject, scroll.subject), axis });
7551
+ timeline = new Ctor({ subject: resolveScrollSubject(subject, scroll.subject, report), axis });
7012
7552
  } else {
7013
7553
  const source = scroll.source === "root" ? documentScroller() : findNearestScroller(subject, "y") || findNearestScroller(subject, "x") || documentScroller();
7014
7554
  timeline = new Ctor({ source, axis });
7015
7555
  }
7016
7556
  } catch (e) {
7017
- console.warn("scroll timeline: native timeline construction failed \u2014 falling back to the player measuring progress itself", e);
7557
+ report.warn(PxDiagnosticKind.platform, "scroll timeline: native timeline construction failed \u2014 falling back to the player measuring progress itself", e);
7018
7558
  return null;
7019
7559
  }
7020
7560
  return {
@@ -7041,8 +7581,9 @@ function documentScroller() {
7041
7581
  }
7042
7582
  var SUBJECT_PARENT = "parent";
7043
7583
  var SUBJECT_SCROLLER = "scroller";
7044
- function resolveScrollSubject(svgRoot, subject) {
7584
+ function resolveScrollSubject(svgRoot, subject, diag) {
7045
7585
  var _a2, _b;
7586
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
7046
7587
  const spec = subject == null ? void 0 : subject.trim();
7047
7588
  if (!spec) return svgRoot;
7048
7589
  if (spec === SUBJECT_PARENT) {
@@ -7060,21 +7601,22 @@ function resolveScrollSubject(svgRoot, subject) {
7060
7601
  try {
7061
7602
  found = document.querySelector(spec);
7062
7603
  } catch (e) {
7063
- console.warn('scroll timeline: subject "' + spec + '" is not a valid selector \u2014 measuring the SVG itself');
7604
+ report.warn(PxDiagnosticKind.document, 'scroll timeline: subject "' + spec + '" is not a valid selector \u2014 measuring the SVG itself');
7064
7605
  return svgRoot;
7065
7606
  }
7066
7607
  if (!found) {
7067
- console.warn('scroll timeline: subject "' + spec + '" matched no element \u2014 measuring the SVG itself');
7608
+ report.warn(PxDiagnosticKind.host, 'scroll timeline: subject "' + spec + '" matched no element \u2014 measuring the SVG itself');
7068
7609
  return svgRoot;
7069
7610
  }
7070
7611
  return found;
7071
7612
  }
7072
- function createScrollDriver(subject, config, onProgress) {
7613
+ function createScrollDriver(subject, config, onProgress, diag) {
7073
7614
  var _a2, _b;
7074
7615
  if (!config || !isScrollTimeline(config)) return null;
7616
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
7075
7617
  const scroll = config.scroll || {};
7076
7618
  const kind = (_a2 = scroll.kind) != null ? _a2 : "view";
7077
- const measured = resolveScrollSubject(subject, scroll.subject);
7619
+ const measured = resolveScrollSubject(subject, scroll.subject, report);
7078
7620
  const nearest = findNearestScroller(subject, "y") || findNearestScroller(subject, "x");
7079
7621
  const scroller = kind === "scroll" && scroll.source === "root" ? documentScroller() : nearest || documentScroller();
7080
7622
  const isRootScroller = scroller === documentScroller();
@@ -7193,7 +7735,7 @@ function applyScrollPin(svgRoot, scroll) {
7193
7735
  const alignFactor = scroll.pinAlign === "center" ? 0.5 : scroll.pinAlign === "bottom" ? 1 : 0;
7194
7736
  const applyTop = () => {
7195
7737
  var _a2;
7196
- const extra = (_a2 = scroll.pinTop) != null ? _a2 : 0;
7738
+ const extra = (_a2 = scroll.pinOffset) != null ? _a2 : 0;
7197
7739
  if (!alignFactor) {
7198
7740
  style.top = extra + "px";
7199
7741
  return;
@@ -7255,6 +7797,7 @@ function finaliseAnimator(animatorConfig, callbacks, make) {
7255
7797
  }
7256
7798
  function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
7257
7799
  const animatorConfig = getAnimatorConfig(doc) || {};
7800
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
7258
7801
  if (isScrollTimeline(animatorConfig)) {
7259
7802
  return finaliseAnimator(animatorConfig, callbacks, (cb) => {
7260
7803
  var _a2;
@@ -7262,7 +7805,7 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
7262
7805
  };
7263
7806
  if (mayUseNativeScrollTimeline(animatorConfig.engine) && rootElement) {
7264
7807
  unpin = applyScrollPin(rootElement, animatorConfig.scroll);
7265
- const native = createNativeScrollTimeline(rootElement, animatorConfig);
7808
+ const native = createNativeScrollTimeline(rootElement, animatorConfig, diag);
7266
7809
  if (native) {
7267
7810
  const api2 = createWebApiAnimator(
7268
7811
  doc,
@@ -7292,7 +7835,8 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
7292
7835
  const driver = createScrollDriver(
7293
7836
  subject,
7294
7837
  animatorConfig,
7295
- (progress) => api.setCurrentTime(progress * totalMs)
7838
+ (progress) => api.setCurrentTime(progress * totalMs),
7839
+ diag
7296
7840
  );
7297
7841
  if (driver) {
7298
7842
  const destroy = api.destroy.bind(api);
@@ -7303,7 +7847,7 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
7303
7847
  };
7304
7848
  }
7305
7849
  } else {
7306
- console.warn("scroll timeline: no root element to observe \u2014 animation will stay at frame 0");
7850
+ diag.warn(PxDiagnosticKind.host, "scroll timeline: no root element to observe \u2014 animation will stay at frame 0");
7307
7851
  }
7308
7852
  return api;
7309
7853
  });
@@ -7323,35 +7867,36 @@ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
7323
7867
 
7324
7868
  // src/dom/PxAnimatorDOM.ts
7325
7869
  var SVG_NS = "http://www.w3.org/2000/svg";
7326
- function createElement(tagName, normalisedProps, style, children, textContent) {
7870
+ function createElement(tagName, normalizedProps, style, children, textContent, diag) {
7327
7871
  if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
7328
- console.warn("SVG tag blocked (dangerous): ", tagName);
7872
+ (diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]")).warn(PxDiagnosticKind.document, "SVG tag blocked (dangerous): " + tagName);
7329
7873
  return null;
7330
7874
  }
7331
7875
  const element = document.createElementNS(SVG_NS, tagName);
7332
- for (const propName in normalisedProps) {
7333
- const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
7334
- if (sanitised === void 0) continue;
7876
+ for (const propName in normalizedProps) {
7877
+ const sanitized = sanitizeAttributeValue(propName, normalizedProps[propName]);
7878
+ if (sanitized === void 0) continue;
7335
7879
  if (CSS_ONLY_STYLE_PROPS.has(propName)) {
7336
- element.style[propName] = String(sanitised);
7880
+ element.style[propName] = String(sanitized);
7337
7881
  continue;
7338
7882
  }
7339
- element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
7883
+ element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitized);
7340
7884
  }
7341
7885
  if (style) {
7342
7886
  for (const styleProp in style) {
7343
7887
  element.style[styleProp] = String(style[styleProp]);
7344
7888
  }
7345
7889
  }
7346
- if (children) {
7890
+ if (children == null ? void 0 : children.length) {
7347
7891
  for (const child of children) {
7348
7892
  element.appendChild(child);
7349
7893
  }
7894
+ } else if (textContent) {
7895
+ element.textContent = textContent;
7350
7896
  }
7351
- if (textContent) element.textContent = textContent;
7352
7897
  return element;
7353
7898
  }
7354
- function renderNode(node, defs) {
7899
+ function renderNode(node, defs, diag) {
7355
7900
  if (!node) return null;
7356
7901
  const _a2 = node, { type, children, style } = _a2, props = __objRest(_a2, ["type", "children", "style"]);
7357
7902
  const domType = props.domType;
@@ -7361,7 +7906,7 @@ function renderNode(node, defs) {
7361
7906
  let childElements;
7362
7907
  if (children) {
7363
7908
  for (const ch of children) {
7364
- const child = renderNode(ch, nodeDefs);
7909
+ const child = renderNode(ch, nodeDefs, diag);
7365
7910
  if (child) {
7366
7911
  if (!childElements) childElements = [];
7367
7912
  childElements.push(child);
@@ -7373,37 +7918,39 @@ function renderNode(node, defs) {
7373
7918
  getNormalizedProps(props),
7374
7919
  resolvedStyle,
7375
7920
  childElements,
7376
- props[TEXT_CONTENT_ATTR] || props[TEXT_ATTR]
7921
+ props[TEXT_CONTENT_ATTR],
7922
+ diag
7377
7923
  );
7378
7924
  if (element && domType !== void 0) element.setAttribute("type", domType);
7379
7925
  return element;
7380
7926
  }
7381
7927
 
7382
7928
  // src/shared/PxAnimatorKeys.ts
7383
- var PX_ANIMATOR_DATA_KEY = "data";
7929
+ var PX_ANIMATOR_DOC_KEY = "doc";
7384
7930
 
7385
7931
  // src/animator/PxAnimator.ts
7386
7932
  function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
7387
7933
  return bindWithEngineChoice(doc, adapter, callbacks, rootElement);
7388
7934
  }
7389
- function createAnimatorImpl(doc, adapter, callbacks, containerElement, config, resetDocDefaults) {
7935
+ function createAnimatorImpl(doc, adapter, callbacks, containerElement, patch, resetTimeline) {
7936
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
7390
7937
  const effectsWarnings = validateNodeEffects(doc);
7391
- for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
7938
+ for (const w of effectsWarnings) diag.warn(PxDiagnosticKind.document, "effects shape: " + w);
7392
7939
  reportDocumentDiagnostics(doc, "[PxAnimator] createAnimator");
7393
- if (config !== void 0 || resetDocDefaults) {
7394
- const patched = applyAnimatorConfig(doc, config != null ? config : {}, { resetDefaults: !!resetDocDefaults });
7395
- for (const w of patched.warnings) console.warn("[PxAnimator] config override:", w);
7940
+ if (patch !== void 0 || resetTimeline) {
7941
+ const patched = applyAnimatorConfig(doc, patch != null ? patch : {}, { resetDefaults: !!resetTimeline });
7942
+ for (const w of patched.warnings) diag.warn(PxDiagnosticKind.usage, "timeline override: " + w);
7396
7943
  doc = patched.doc;
7397
7944
  }
7398
7945
  const animatorConfig = getAnimatorConfig(doc) || {};
7399
7946
  const engine = resolveTimelineEngine(animatorConfig.engine);
7400
- doc = materialiseAllInTree(doc, engine);
7947
+ doc = materializeAllInTree(doc, engine);
7401
7948
  let rootElement = null;
7402
7949
  if (containerElement) {
7403
7950
  doc = generateNewIds(doc);
7404
7951
  const containerEl = typeof containerElement === "string" ? document.querySelector(containerElement) : containerElement;
7405
7952
  if (containerEl) {
7406
- rootElement = renderNode(doc);
7953
+ rootElement = renderNode(doc, void 0, diag);
7407
7954
  if (rootElement) {
7408
7955
  containerEl.replaceChildren(rootElement);
7409
7956
  }
@@ -7420,21 +7967,22 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement, config, r
7420
7967
  }
7421
7968
  return api;
7422
7969
  }
7423
- function resolveAnimatorConfigOption(options) {
7424
- const { config, duration, delay, iterations, startOn } = options;
7425
- return foldAnimatorConfigShortcuts(config, { duration, delay, iterations, startOn });
7970
+ function resolveTimelineOption(options) {
7971
+ const { timeline, duration, delay, iterations, startOn } = options;
7972
+ return foldTimelineOverride(timeline, { duration, delay, iterations, startOn });
7426
7973
  }
7427
7974
  function createAnimator(options) {
7428
- const { src, data, adapter, callbacks, container, resetDocDefaults } = options;
7429
- const config = resolveAnimatorConfigOption(options);
7430
- if (data !== void 0 && src !== void 0) {
7431
- throw new Error("createAnimator: provide either `src` or `data`, not both");
7975
+ const { src, doc, adapter, container, resetTimeline } = options;
7976
+ const patch = resolveTimelineOption(options);
7977
+ const callbacks = toEngineCallbacks(options);
7978
+ if (doc !== void 0 && src !== void 0) {
7979
+ throw new Error("createAnimator: provide either `src` or `doc`, not both");
7432
7980
  }
7433
- if (data === void 0 && src === void 0) {
7434
- throw new Error("createAnimator: either `src` or `data` is required");
7981
+ if (doc === void 0 && src === void 0) {
7982
+ throw new Error("createAnimator: either `src` or `doc` is required");
7435
7983
  }
7436
- if (data !== void 0) {
7437
- return createAnimatorImpl(data, adapter, callbacks, container, config, resetDocDefaults);
7984
+ if (doc !== void 0) {
7985
+ return createAnimatorImpl(doc, adapter, callbacks, container, patch, resetTimeline);
7438
7986
  }
7439
7987
  let animator = null;
7440
7988
  let pending = [];
@@ -7446,19 +7994,27 @@ function createAnimator(options) {
7446
7994
  pending.push(call);
7447
7995
  }
7448
7996
  };
7997
+ const loadDiag = createDiagnostics(callbacks, "[PxAnimator]");
7449
7998
  fetch(src).then((res) => res.json()).then((json) => {
7450
7999
  if (destroyed) return;
7451
8000
  if (isPxElementFileFormat(json)) {
7452
- animator = createAnimatorImpl(json, adapter, callbacks, container, config, resetDocDefaults);
8001
+ animator = createAnimatorImpl(json, adapter, callbacks, container, patch, resetTimeline);
7453
8002
  const queued = pending;
7454
8003
  pending = null;
7455
8004
  queued == null ? void 0 : queued.forEach((call) => call(animator));
7456
8005
  } else {
7457
- console.error('createAnimator: invalid animation document format at "' + src + '"');
8006
+ loadDiag.error(
8007
+ PxDiagnosticKind.document,
8008
+ 'createAnimator: invalid animation document format at "' + src + '"'
8009
+ );
7458
8010
  }
7459
8011
  }).catch((err) => {
8012
+ var _a2;
7460
8013
  pending = null;
7461
- console.error('createAnimator: failed to load "' + src + '"', err);
8014
+ loadDiag.error(
8015
+ PxDiagnosticKind.host,
8016
+ 'createAnimator: failed to load "' + src + '" \u2014 ' + ((_a2 = err == null ? void 0 : err.message) != null ? _a2 : String(err))
8017
+ );
7462
8018
  });
7463
8019
  return {
7464
8020
  "isReady": () => !!animator,
@@ -7483,6 +8039,10 @@ function createAnimator(options) {
7483
8039
  "setCurrentTime": (time) => {
7484
8040
  enqueue((api) => api.setCurrentTime(time));
7485
8041
  },
8042
+ "getCurrentProgress": () => animator ? animator.getCurrentProgress() : null,
8043
+ "setCurrentProgress": (progress) => {
8044
+ enqueue((api) => api.setCurrentProgress(progress));
8045
+ },
7486
8046
  "destroy": () => {
7487
8047
  destroyed = true;
7488
8048
  pending = null;
@@ -7490,89 +8050,119 @@ function createAnimator(options) {
7490
8050
  }
7491
8051
  };
7492
8052
  }
7493
- function loadTagAnimators() {
8053
+ function loadTagAnimators(options) {
7494
8054
  const elements = document.querySelectorAll("[" + PX_ANIM_SRC_ATTR_NAME + "]");
7495
8055
  for (let i = 0; i < elements.length; i++) {
7496
8056
  const element = elements[i];
7497
8057
  if (!element[PX_ANIM_ATTR_NAME]) {
7498
8058
  const src = element.getAttribute(PX_ANIM_SRC_ATTR_NAME);
7499
8059
  if (src) {
7500
- element[PX_ANIM_ATTR_NAME] = createAnimator({ src, container: element });
8060
+ element[PX_ANIM_ATTR_NAME] = createAnimator(__spreadProps(__spreadValues({}, options), { src, container: element }));
7501
8061
  }
7502
8062
  }
7503
8063
  }
7504
8064
  }
7505
- if (typeof window !== "undefined") {
7506
- window["loadTagAnimators"] = loadTagAnimators;
7507
- window["createAnimator"] = createAnimator;
7508
- window["setupAnimationTriggers"] = setupAnimationTriggers;
7509
- }
7510
8065
  // Annotate the CommonJS export names for ESM import in node:
7511
8066
  0 && (module.exports = {
7512
- COLOUR_ATTR_NAMES,
8067
+ BASELINE_PLAYER_VERSION,
8068
+ COLOR_ATTR_NAMES,
8069
+ DEFAULT_DURATION_MS,
7513
8070
  MISSING_GLYPH_CLASS_NAME,
7514
- PX_ANIMATOR_DATA_KEY,
8071
+ PLAYER_WIRE_STEPS,
8072
+ PLAYER_WIRE_VERSION,
8073
+ PX_ANIMATOR_DOC_KEY,
7515
8074
  PX_ANIM_ATTR_NAME,
7516
8075
  PX_ANIM_SRC_ATTR_NAME,
8076
+ PX_PLAYER_SCHEMA_VERSION,
7517
8077
  PX_TRANSFORM_PART_KEYS,
8078
+ PX_TRIGGER_DEFAULTS,
8079
+ PxAlongPathMode,
7518
8080
  PxAnimatedSvgDocumentSchema,
7519
8081
  PxAnimationDefinitionSchema,
7520
8082
  PxAnimatorConfigSchema,
7521
8083
  PxAttrValueSchema,
7522
8084
  PxBezierPathSchema,
7523
8085
  PxBindingSchema,
8086
+ PxClipPathEffectSchema,
7524
8087
  PxCloneEffectSchema,
7525
8088
  PxCloneWithout,
8089
+ PxControlMode,
7526
8090
  PxDefsSchema,
8091
+ PxDiagnosticKind,
7527
8092
  PxEasingOrRefSchema,
7528
8093
  PxEffectsSchema,
7529
8094
  PxElementAnimationSchema,
7530
8095
  PxFillGradientEffectSchema,
8096
+ PxFinishAction,
7531
8097
  PxGradientSpreadMethod,
7532
8098
  PxGradientStopSchema,
7533
8099
  PxGradientType,
7534
- PxGradientUnits,
7535
8100
  PxKeyframeSchema,
7536
8101
  PxKeyframeValueSchema,
8102
+ PxLengthAdjust,
7537
8103
  PxLoopDirection,
7538
8104
  PxLoopRepeatAt,
7539
8105
  PxLoopSchema,
8106
+ PxMaskType,
7540
8107
  PxMaskedByEffectSchema,
7541
8108
  PxNodeBase,
7542
8109
  PxNodeSchema,
8110
+ PxPathOverflow,
8111
+ PxPinAlign,
7543
8112
  PxPropertyAnimationSchema,
7544
8113
  PxRepeaterEffectSchema,
7545
8114
  PxRetimeEffectSchema,
8115
+ PxScrollAxis,
8116
+ PxScrollKind,
8117
+ PxScrollPhase,
8118
+ PxScrollRangePointSchema,
8119
+ PxScrollRangeSchema,
8120
+ PxScrollSchema,
8121
+ PxScrollSource,
7546
8122
  PxStrokeGradientEffectSchema,
7547
8123
  PxStrokeTrimEffectSchema,
7548
8124
  PxStrokeTrimSubPaths,
7549
8125
  PxSvgNodeExtra,
7550
8126
  PxTextEffectSchema,
7551
8127
  PxTextPathEffectSchema,
8128
+ PxTextPathMethod,
8129
+ PxTextPathSpacing,
7552
8130
  PxTimelineEngine,
7553
8131
  PxTimelineEngineExtra,
8132
+ PxTimelinePinSchema,
8133
+ PxTimelineSchema,
7554
8134
  PxTransformByEffectSchema,
7555
8135
  PxTransformPartsSchema,
7556
8136
  PxTransformValueSchema,
7557
8137
  PxTriggerSchema,
8138
+ PxUnits,
7558
8139
  STYLE_ATTR_NAMES,
7559
8140
  TRANSFORM_FN_NAMES,
8141
+ WIRE_VERSION_KEY,
8142
+ WireStepKind,
8143
+ WireVersionRelation,
7560
8144
  applyAnimatorConfig,
7561
8145
  applyPlayerEffects,
7562
8146
  calcAnimationValues,
7563
8147
  camelCaseToKebabWordIfNeeded,
7564
8148
  collectSampleTimes,
8149
+ compareWireVersion,
8150
+ controlModeTakesOverTrigger,
8151
+ convertPlayerDocument,
7565
8152
  createAnimator,
7566
- createAnimatorImpl,
7567
8153
  createBasicFrameLoopAnimator,
8154
+ createDiagnostics,
7568
8155
  createFrameLoopAnimator,
7569
8156
  createPathSampler,
7570
8157
  createWebApiAnimator,
7571
8158
  describeSchema,
8159
+ diagnoseDocument,
7572
8160
  diffInEffect,
8161
+ downgradePlayerDocument,
7573
8162
  evaluateMotionPathSegment,
7574
8163
  extendedPathForBrowser,
7575
- foldAnimatorConfigShortcuts,
8164
+ foldTimelineOverride,
8165
+ formatWireVersion,
7576
8166
  generateNewIds,
7577
8167
  getAnimatorConfig,
7578
8168
  getBindings,
@@ -7584,26 +8174,33 @@ if (typeof window !== "undefined") {
7584
8174
  jsonElementFactory,
7585
8175
  layoutGlyphTextChars,
7586
8176
  loadTagAnimators,
7587
- materialiseAllInTree,
7588
- materialiseAnimatedUseInstances,
7589
- materialiseGlyphText,
7590
- materialiseGlyphTextAlongPath,
7591
- materialiseGlyphTextHorizontal,
7592
- materialiseInternalLoopsInPropAnim,
7593
- materialiseInternalLoopsInTree,
7594
- materialiseMotionPathInPropAnim,
7595
- materialiseMotionPathsInTree,
8177
+ materializeAllInTree,
8178
+ materializeAnimatedUseInstances,
8179
+ materializeGlyphText,
8180
+ materializeGlyphTextAlongPath,
8181
+ materializeGlyphTextHorizontal,
8182
+ materializeInternalLoopsInPropAnim,
8183
+ materializeInternalLoopsInTree,
8184
+ materializeMotionPathInPropAnim,
8185
+ materializeMotionPathsInTree,
7596
8186
  mergeAnimatorConfig,
7597
8187
  normalizeDocument,
8188
+ parseWireVersion,
8189
+ progressToTimeMs,
7598
8190
  propAnimIsMotionPath,
7599
8191
  px,
8192
+ readWireVersion,
7600
8193
  renderNode,
8194
+ resolveControlMode,
8195
+ resolveTrigger,
7601
8196
  schemaKeys,
7602
8197
  setupAnimationTriggers,
7603
8198
  shiftAnimatable,
8199
+ timeToProgress,
7604
8200
  toRGBA,
7605
8201
  validateDocument,
7606
8202
  validateNodeEffects,
8203
+ versionAdvice,
7607
8204
  visualModelAt
7608
8205
  });
7609
8206
  //# sourceMappingURL=index.cjs.map