@pixodesk/svg-animator-core 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.js CHANGED
@@ -261,7 +261,7 @@ function parseColor(s) {
261
261
  }
262
262
  return void 0;
263
263
  }
264
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
264
+ var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
265
265
  var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
266
266
  var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
267
267
  function composeTransformParts(parts, opts) {
@@ -644,6 +644,7 @@ var Enum = class extends Base {
644
644
  return false;
645
645
  }
646
646
  };
647
+ var UNION_MEMBER_ERROR_LIMIT = 4;
647
648
  var Union = class extends Base {
648
649
  constructor(schemas, defaultVal) {
649
650
  super();
@@ -662,7 +663,35 @@ var Union = class extends Base {
662
663
  var _a2;
663
664
  const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
664
665
  if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
665
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
666
+ if (!ctx) return false;
667
+ const base = pathStr(path != null ? path : []);
668
+ ctx.errors.push(base + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
669
+ let best;
670
+ let bestDepth = -1;
671
+ const leafExpectations = [];
672
+ for (const member of this.schemas) {
673
+ const sink = { errors: [], warnings: [], strict: ctx.strict };
674
+ member.isValid(raw, sink, path ? [...path] : void 0);
675
+ if (!sink.errors.length) continue;
676
+ const depth = Math.max(...sink.errors.map((e) => e.slice(0, e.indexOf(":")).length));
677
+ if (depth > bestDepth || depth === bestDepth && best && sink.errors.length < best.length) {
678
+ bestDepth = depth;
679
+ best = sink.errors;
680
+ }
681
+ if (depth <= base.length) {
682
+ for (const e of sink.errors) {
683
+ const m = /: expected (.+?), got /.exec(e);
684
+ if (m && !leafExpectations.includes(m[1])) leafExpectations.push(m[1]);
685
+ }
686
+ }
687
+ }
688
+ if (best && bestDepth > base.length) {
689
+ for (const e of best.slice(0, UNION_MEMBER_ERROR_LIMIT)) {
690
+ if (!ctx.errors.includes(e)) ctx.errors.push(e);
691
+ }
692
+ } else if (leafExpectations.length) {
693
+ ctx.errors.push(base + ": expected " + leafExpectations.join(" | "));
694
+ }
666
695
  return false;
667
696
  }
668
697
  _canSanitize(raw) {
@@ -1341,10 +1370,78 @@ function releaseLogProblems(releases, steps, declared, baseline) {
1341
1370
  }
1342
1371
 
1343
1372
  // src/format/PxAnimatorConstants.ts
1373
+ var PxFillMode = {
1374
+ forwards: "forwards",
1375
+ backwards: "backwards",
1376
+ both: "both",
1377
+ none: "none"
1378
+ };
1379
+ var PxPlaybackDirection = {
1380
+ normal: "normal",
1381
+ reverse: "reverse",
1382
+ alternate: "alternate",
1383
+ alternateReverse: "alternate-reverse"
1384
+ };
1344
1385
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1345
1386
  var PX_ANIM_ATTR_NAME = "_px_animator";
1387
+ var PxStartOn = {
1388
+ load: "load",
1389
+ mouseOver: "mouseOver",
1390
+ click: "click",
1391
+ scrollIntoView: "scrollIntoView",
1392
+ programmatic: "programmatic"
1393
+ };
1394
+ var PxOutAction = {
1395
+ continue: "continue",
1396
+ pause: "pause",
1397
+ reset: "reset",
1398
+ reverse: "reverse"
1399
+ };
1400
+ var PxFinishAction = {
1401
+ hold: "hold",
1402
+ reset: "reset"
1403
+ };
1404
+ var PxScrollKind = {
1405
+ view: "view",
1406
+ scroll: "scroll"
1407
+ };
1408
+ var PxScrollAxis = {
1409
+ block: "block",
1410
+ inline: "inline",
1411
+ x: "x",
1412
+ y: "y"
1413
+ };
1414
+ var PxScrollSource = {
1415
+ nearest: "nearest",
1416
+ root: "root"
1417
+ };
1418
+ var PxPinAlign = {
1419
+ top: "top",
1420
+ center: "center",
1421
+ bottom: "bottom"
1422
+ };
1423
+ var PxScrollPhase = {
1424
+ cover: "cover",
1425
+ contain: "contain",
1426
+ entry: "entry",
1427
+ exit: "exit",
1428
+ entryCrossing: "entry-crossing",
1429
+ exitCrossing: "exit-crossing"
1430
+ };
1431
+ var PxAlongPathMode = {
1432
+ sampled: "sampled",
1433
+ offsetPath: "offsetPath"
1434
+ };
1346
1435
  var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
1347
1436
  var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
1437
+ var PX_FLAT_RUNTIME_VIEW_KEYS = [
1438
+ ...PX_TIMELINE_SHARED_KEYS,
1439
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
1440
+ "fill",
1441
+ "resetOnFinish",
1442
+ "timelineSource",
1443
+ "scroll"
1444
+ ];
1348
1445
  var PxTimelineEngine = {
1349
1446
  native: "native",
1350
1447
  js: "js"
@@ -1361,6 +1458,50 @@ function isNativeForced(engine) {
1361
1458
  function mayUseNativeScrollTimeline(engine) {
1362
1459
  return engine !== PxTimelineEngineExtra.js;
1363
1460
  }
1461
+ var PX_TRIGGER_DEFAULTS = {
1462
+ startOn: "load",
1463
+ outAction: "continue",
1464
+ scrollIntoViewThreshold: 0
1465
+ };
1466
+ var PxControlMode = {
1467
+ /** No control props — the document's trigger decides, and nothing is taken over. */
1468
+ static: "static",
1469
+ /** `progress` / `time` — the host scrubs; the component seeks and stays paused. */
1470
+ fixedTime: "fixedTime",
1471
+ /** `play` / `pause` — the host drives playback with booleans. */
1472
+ play: "play",
1473
+ /** `autoplay` — the document's own trigger starts it. */
1474
+ autoplay: "autoplay"
1475
+ };
1476
+ function resolveControlMode(props) {
1477
+ const hasFixedTime = props.progress !== void 0 || props.time !== void 0;
1478
+ const hasPlayPause = props.play !== void 0 || props.pause !== void 0;
1479
+ const hasAutoplay = !!props.autoplay;
1480
+ const warnings = [];
1481
+ const named = (a, b, winner) => a + " and " + b + " were both set \u2014 " + winner + " wins, " + (winner === a ? b : a) + " is ignored.";
1482
+ if (hasFixedTime) {
1483
+ if (hasPlayPause) warnings.push(named("progress/time", "play/pause", "progress/time"));
1484
+ if (hasAutoplay) warnings.push(named("progress/time", "autoplay", "progress/time"));
1485
+ return { mode: PxControlMode.fixedTime, warnings };
1486
+ }
1487
+ if (hasPlayPause) {
1488
+ if (hasAutoplay) warnings.push(named("play/pause", "autoplay", "play/pause"));
1489
+ return { mode: PxControlMode.play, warnings };
1490
+ }
1491
+ if (hasAutoplay) return { mode: PxControlMode.autoplay, warnings };
1492
+ return { mode: PxControlMode.static, warnings };
1493
+ }
1494
+ function controlModeTakesOverTrigger(mode) {
1495
+ return mode !== PxControlMode.autoplay;
1496
+ }
1497
+ function resolveTrigger(trigger) {
1498
+ var _a2, _b, _c;
1499
+ return {
1500
+ startOn: (_a2 = trigger == null ? void 0 : trigger.startOn) != null ? _a2 : PX_TRIGGER_DEFAULTS.startOn,
1501
+ outAction: (_b = trigger == null ? void 0 : trigger.outAction) != null ? _b : PX_TRIGGER_DEFAULTS.outAction,
1502
+ scrollIntoViewThreshold: (_c = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _c : PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold
1503
+ };
1504
+ }
1364
1505
  var PxLoopRepeatAt = {
1365
1506
  /** Segment from the START; the repetition runs BEFORE the first keyframe
1366
1507
  * (intro loops that play until the main timeline begins). */
@@ -1407,7 +1548,6 @@ var PxStrokeTrimSubPaths = {
1407
1548
  separate: "separate",
1408
1549
  combined: "combined"
1409
1550
  };
1410
- var TEXT_ATTR = "text";
1411
1551
  var TEXT_CONTENT_ATTR = "textContent";
1412
1552
  var CLASS_ATTR = "class";
1413
1553
  var TRANSFORM_ATTR = "transform";
@@ -1419,7 +1559,6 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1419
1559
  "meta",
1420
1560
  "animate",
1421
1561
  "effects",
1422
- TEXT_ATTR,
1423
1562
  TEXT_CONTENT_ATTR
1424
1563
  ]);
1425
1564
  var TRANSFORM_PART = {
@@ -1434,10 +1573,6 @@ var PX_TRANSFORM_PART_KEYS = [
1434
1573
  TRANSFORM_PART.scale,
1435
1574
  TRANSFORM_PART.origin
1436
1575
  ];
1437
- var PxGradientUnits = {
1438
- userSpaceOnUse: "userSpaceOnUse",
1439
- objectBoundingBox: "objectBoundingBox"
1440
- };
1441
1576
  var PxGradientSpreadMethod = {
1442
1577
  pad: "pad",
1443
1578
  reflect: "reflect",
@@ -1456,8 +1591,18 @@ function isPxElementFileFormat(fileJson) {
1456
1591
  function getAnimatorConfig(doc) {
1457
1592
  var _a2;
1458
1593
  const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
1459
- return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1460
- }
1594
+ if (!cfg) return void 0;
1595
+ const memoised = wireViewMemo.get(cfg);
1596
+ if (memoised) return memoised;
1597
+ const wire = cfg;
1598
+ const stray = PX_FLAT_RUNTIME_VIEW_KEYS.filter((k) => wire[k] !== void 0);
1599
+ const source = stray.length ? __spreadValues({}, wire) : cfg;
1600
+ for (const k of stray) delete source[k];
1601
+ const view = flattenAnimatorTimeline(source);
1602
+ wireViewMemo.set(cfg, view);
1603
+ return view;
1604
+ }
1605
+ var wireViewMemo = /* @__PURE__ */ new WeakMap();
1461
1606
  var flattenMemo = /* @__PURE__ */ new WeakMap();
1462
1607
  function flattenAnimatorTimeline(cfg) {
1463
1608
  const timeline = cfg.timeline;
@@ -1483,7 +1628,7 @@ function flattenAnimatorTimeline(cfg) {
1483
1628
  else if (pin && typeof pin === "object") {
1484
1629
  scroll.pin = true;
1485
1630
  if (pin.align !== void 0) scroll.pinAlign = pin.align;
1486
- if (pin.top !== void 0) scroll.pinTop = pin.top;
1631
+ if (pin.offset !== void 0) scroll.pinOffset = pin.offset;
1487
1632
  if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1488
1633
  }
1489
1634
  flat.scroll = scroll;
@@ -1544,9 +1689,9 @@ function nestAnimatorTimeline(cfg) {
1544
1689
  if (scroll.subject !== void 0) timeline2.subject = scroll.subject;
1545
1690
  if (scroll.smoothing !== void 0) timeline2.smoothing = scroll.smoothing;
1546
1691
  if (scroll.range !== void 0) timeline2.range = scroll.range;
1547
- const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinTop !== void 0 || scroll.pinDistance !== void 0;
1692
+ const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinOffset !== void 0 || scroll.pinDistance !== void 0;
1548
1693
  if (hasPinParams) {
1549
- timeline2.pin = __spreadValues(__spreadValues(__spreadValues({}, scroll.pinAlign !== void 0 ? { align: scroll.pinAlign } : {}), scroll.pinTop !== void 0 ? { top: scroll.pinTop } : {}), scroll.pinDistance !== void 0 ? { distance: scroll.pinDistance } : {});
1694
+ timeline2.pin = __spreadValues(__spreadValues(__spreadValues({}, scroll.pinAlign !== void 0 ? { align: scroll.pinAlign } : {}), scroll.pinOffset !== void 0 ? { offset: scroll.pinOffset } : {}), scroll.pinDistance !== void 0 ? { distance: scroll.pinDistance } : {});
1550
1695
  } else if (scroll.pin !== void 0) {
1551
1696
  timeline2.pin = scroll.pin;
1552
1697
  }
@@ -1594,14 +1739,13 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
1594
1739
  // e.g. for colors
1595
1740
  px.number(),
1596
1741
  px.array(px.number()),
1597
- // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1742
+ // ORDER LAW: the key-discriminated object shape (`{pathData}`) comes BEFORE the
1598
1743
  // all-optional transform-parts record. In default (non-strict) mode that record accepts
1599
1744
  // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1600
- // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1745
+ // Union.sanitize route `{pathData}` values into it and strip them to `{}` —
1601
1746
  // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1602
1747
  // order-independent (`some()`); only sanitize routing depends on this order.
1603
- px.object({ path: px.string() }),
1604
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1748
+ px.object({ pathData: px.string() }),
1605
1749
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1606
1750
  px.lazy(() => px.array(PxGradientStopSchema), []),
1607
1751
  px.lazy(() => PxTransformPartsSchema, {})
@@ -1641,7 +1785,7 @@ var PxPropertyAnimationSchema = implementsInterface()(px.object({
1641
1785
  keyframes: px.array(PxKeyframeSchema).optional(),
1642
1786
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1643
1787
  autoOrient: px.boolean().optional(),
1644
- alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
1788
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
1645
1789
  }));
1646
1790
  var PxTransformPartsSchema = implementsInterface()(px.object({
1647
1791
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1665,17 +1809,17 @@ var PxElementAnimationSchema = implementsInterface()(px.union([
1665
1809
  PxAnimationDefinitionSchema
1666
1810
  ]));
1667
1811
  var PxTriggerSchema = implementsInterface()(px.object({
1668
- startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1669
- outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1812
+ startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic], PX_TRIGGER_DEFAULTS.startOn).optional(),
1813
+ outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse], PX_TRIGGER_DEFAULTS.outAction).optional(),
1670
1814
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1671
1815
  // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1672
1816
  // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1673
- finishAction: px.enum(["hold", "reset"]).optional(),
1817
+ finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
1674
1818
  scrollIntoViewThreshold: px.number().optional()
1675
1819
  }));
1676
1820
  var PxGlyphSchema = implementsInterface()(px.object({
1677
1821
  width: px.number(),
1678
- d: px.string()
1822
+ pathData: px.string()
1679
1823
  }));
1680
1824
  var PxGlyphFontSchema = implementsInterface()(px.object({
1681
1825
  fontFamily: px.string(),
@@ -1692,9 +1836,15 @@ var PxDefsSchema = implementsInterface()(px.object({
1692
1836
  styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1693
1837
  fonts: px.record(PxGlyphFontSchema).optional()
1694
1838
  }));
1695
- var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1696
1839
  var PxScrollRangePointSchema = implementsInterface()(px.object({
1697
- phase: px.enum(PX_SCROLL_PHASES).optional(),
1840
+ phase: px.enum([
1841
+ PxScrollPhase.cover,
1842
+ PxScrollPhase.contain,
1843
+ PxScrollPhase.entry,
1844
+ PxScrollPhase.exit,
1845
+ PxScrollPhase.entryCrossing,
1846
+ PxScrollPhase.exitCrossing
1847
+ ]).optional(),
1698
1848
  fraction: px.number().optional()
1699
1849
  }));
1700
1850
  var PxScrollRangeSchema = px.object({
@@ -1702,21 +1852,21 @@ var PxScrollRangeSchema = px.object({
1702
1852
  end: PxScrollRangePointSchema.optional()
1703
1853
  });
1704
1854
  var PxScrollSchema = implementsInterface()(px.object({
1705
- kind: px.enum(["view", "scroll"]).optional(),
1706
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1707
- source: px.enum(["nearest", "root"]).optional(),
1855
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
1856
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1857
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1708
1858
  // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1709
1859
  subject: px.string().optional(),
1710
1860
  smoothing: px.number().optional(),
1711
1861
  pin: px.boolean().optional(),
1712
- pinAlign: px.enum(["top", "center", "bottom"]).optional(),
1713
- pinTop: px.number().optional(),
1862
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1863
+ pinOffset: px.number().optional(),
1714
1864
  pinDistance: px.number().optional(),
1715
1865
  range: PxScrollRangeSchema.optional()
1716
1866
  }));
1717
1867
  var PxTimelinePinSchema = implementsInterface()(px.object({
1718
- align: px.enum(["top", "center", "bottom"]).optional(),
1719
- top: px.number().optional(),
1868
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1869
+ offset: px.number().optional(),
1720
1870
  distance: px.number().optional()
1721
1871
  }));
1722
1872
  var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
@@ -1731,8 +1881,8 @@ var PxTimeTimelineSchema = implementsInterface()(px.object({
1731
1881
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1732
1882
  // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1733
1883
  // — never `fill`, which is paint everywhere else in the format.
1734
- fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1735
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1884
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
1885
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
1736
1886
  }));
1737
1887
  var scrollishTimelineShape = {
1738
1888
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
@@ -1743,8 +1893,8 @@ var scrollishTimelineShape = {
1743
1893
  iterations: px.number().optional(),
1744
1894
  engine: PxTimelineEngineSchema,
1745
1895
  frameRate: px.number().optional(),
1746
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1747
- source: px.enum(["nearest", "root"]).optional(),
1896
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1897
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1748
1898
  subject: px.string().optional(),
1749
1899
  // 'parent' | 'scroller' | any CSS selector
1750
1900
  smoothing: px.number().optional(),
@@ -1833,7 +1983,7 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1833
1983
  height: px.number().optional()
1834
1984
  }));
1835
1985
  var PxClipPathEffectSchema = implementsInterface()(px.object({
1836
- d: PxAnimatableStringSchema.optional()
1986
+ pathData: PxAnimatableStringSchema.optional()
1837
1987
  }));
1838
1988
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1839
1989
  offset: PxAnimatableNumberSchema.optional(),
@@ -1870,7 +2020,7 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1870
2020
  radius: PxAnimatableNumberSchema.optional(),
1871
2021
  focal: PxAnimatableVec2Schema.optional(),
1872
2022
  stops: PxAnimatableGradientStopsSchema.optional(),
1873
- gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
2023
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1874
2024
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1875
2025
  gradientTransform: px.string().optional()
1876
2026
  }));
@@ -1916,11 +2066,71 @@ function validateNodeEffects(root, opts) {
1916
2066
  walk(root, "root");
1917
2067
  return warnings;
1918
2068
  }
1919
- function validateDocument(doc) {
1920
- const ctx = { errors: [], warnings: [], strict: true };
2069
+ function validateGlyphFontRefs(root, fonts) {
2070
+ if (!fonts || !Object.keys(fonts).length) return [];
2071
+ const problems = [];
2072
+ const walk = (node, path, inherited, inGlyphText) => {
2073
+ var _a2, _b;
2074
+ if (!node) return;
2075
+ const own = typeof node.fontFamily === "string" ? node.fontFamily : void 0;
2076
+ const family = own != null ? own : inherited;
2077
+ const isGlyphText = inGlyphText || node.type === "text" && !!((_b = (_a2 = node.effects) == null ? void 0 : _a2.text) == null ? void 0 : _b.useGlyphs);
2078
+ if (isGlyphText && own && !Object.prototype.hasOwnProperty.call(fonts, own)) {
2079
+ const problem = path + ': glyph-mode text uses font-family "' + own + '", which has no entry in animator.definitions.fonts';
2080
+ if (!problems.includes(problem)) problems.push(problem);
2081
+ }
2082
+ if (Array.isArray(node.children)) {
2083
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]", family, isGlyphText));
2084
+ }
2085
+ };
2086
+ walk(root, "root", void 0, false);
2087
+ return problems;
2088
+ }
2089
+ function validateEasingRefs(root, easings) {
2090
+ const problems = [];
2091
+ const walk = (node, path) => {
2092
+ if (Array.isArray(node)) {
2093
+ node.forEach((item, i) => walk(item, path + "[" + i + "]"));
2094
+ return;
2095
+ }
2096
+ if (!node || typeof node !== "object") return;
2097
+ const easing = node.easing;
2098
+ if (typeof easing === "string" && !(easings && Object.prototype.hasOwnProperty.call(easings, easing))) {
2099
+ const problem = path + '.easing: "' + easing + '" names no entry in animator.definitions.easings \u2014 it will play linear';
2100
+ if (!problems.includes(problem)) problems.push(problem);
2101
+ }
2102
+ for (const [key, value] of Object.entries(node)) {
2103
+ if (key === "easing") continue;
2104
+ if (value && typeof value === "object") walk(value, path + "." + key);
2105
+ }
2106
+ };
2107
+ walk(root, "root");
2108
+ return problems;
2109
+ }
2110
+ function validateVersionStamp(doc) {
2111
+ var _a2;
2112
+ const version = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.version;
2113
+ if (version === void 0) return [];
2114
+ if (parseWireVersion(version) !== void 0) return [];
2115
+ return ["root.animator.version: " + JSON.stringify(version) + ' is not a version stamp ("a.b" or "a.b.c") \u2014 it reads as unstamped'];
2116
+ }
2117
+ function validateDocument(doc, opts) {
2118
+ var _a2;
2119
+ const strict = (opts == null ? void 0 : opts.strict) !== false;
2120
+ const ctx = { errors: [], warnings: [], strict };
1921
2121
  const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
1922
2122
  if (doc && typeof doc === "object") {
1923
- for (const w of validateNodeEffects(doc, { strict: true })) {
2123
+ for (const w of validateNodeEffects(doc, { strict })) {
2124
+ if (!problems.includes(w)) problems.push(w);
2125
+ }
2126
+ const defs = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
2127
+ for (const w of validateGlyphFontRefs(doc, defs == null ? void 0 : defs.fonts)) {
2128
+ if (!problems.includes(w)) problems.push(w);
2129
+ }
2130
+ for (const w of validateEasingRefs(doc, defs == null ? void 0 : defs.easings)) {
2131
+ if (!problems.includes(w)) problems.push(w);
2132
+ }
2133
+ for (const w of validateVersionStamp(doc)) {
1924
2134
  if (!problems.includes(w)) problems.push(w);
1925
2135
  }
1926
2136
  }
@@ -1943,10 +2153,13 @@ var PxNodeBase = px.openObject({
1943
2153
  // documented — because a wire key that is not in a schema is invisible to the
1944
2154
  // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1945
2155
  domType: px.string().optional(),
2156
+ // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
2157
+ // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
2158
+ textContent: px.string().optional(),
1946
2159
  id: px.string().optional(),
1947
2160
  meta: px.any().optional(),
1948
2161
  // Player-effects bucket emitted by the Editor's lightweight design format.
1949
- // Consumed and removed by `applyPlayerEffects` before any other normalisation
2162
+ // Consumed and removed by `applyPlayerEffects` before any other normalization
1950
2163
  // (see `createAnimatorImpl`), so downstream code never sees it.
1951
2164
  effects: PxEffectsSchema.optional(),
1952
2165
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
@@ -1978,8 +2191,8 @@ var PxBezierPathSchema = implementsInterface()(px.object({
1978
2191
  c: px.boolean().optional()
1979
2192
  }));
1980
2193
  function isPxElementFileFormatDeep(fileJson) {
1981
- const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
1982
- return { valid, errors: valid ? [] : ["Document failed schema validation"] };
2194
+ const errors = validateDocument(fileJson, { strict: false });
2195
+ return { valid: errors.length === 0, errors };
1983
2196
  }
1984
2197
 
1985
2198
  // src/util/PxIdUtil.ts
@@ -2138,7 +2351,7 @@ function isDangerousAttrName(nameLower) {
2138
2351
  if (nameLower.startsWith("on")) return true;
2139
2352
  return false;
2140
2353
  }
2141
- function sanitiseAttributeValue(name, value) {
2354
+ function sanitizeAttributeValue(name, value) {
2142
2355
  const nameLower = name.toLowerCase();
2143
2356
  if (isDangerousAttrName(nameLower)) {
2144
2357
  console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
@@ -2177,7 +2390,7 @@ function getNormalizedProps(props) {
2177
2390
  if (INTERNAL_ATTRS.has(key)) continue;
2178
2391
  if (key === "style") continue;
2179
2392
  let value = props[rawKey];
2180
- if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2393
+ if (COLOR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2181
2394
  propsCopy[key] = toRGBA(value);
2182
2395
  } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
2183
2396
  const parts = value.value && typeof value.value === "object" ? value.value : value;
@@ -2198,7 +2411,7 @@ function getNormalizedProps(props) {
2198
2411
  return propsCopy;
2199
2412
  }
2200
2413
 
2201
- // src/materialise/PxMotionPath.ts
2414
+ // src/materialize/PxMotionPath.ts
2202
2415
  function getKfTranslate(kf) {
2203
2416
  const v = kfValue(kf);
2204
2417
  if (!v) return void 0;
@@ -2279,7 +2492,7 @@ function tFromArcFraction(lut, arcFrac) {
2279
2492
  var DEFAULT_FLATNESS_TOL = 0.5;
2280
2493
  var DEFAULT_ROTATION_TOL = 5;
2281
2494
  var DEFAULT_MAX_SAMPLES = 32;
2282
- function materialiseMotionPathInPropAnim(anim, opts) {
2495
+ function materializeMotionPathInPropAnim(anim, opts) {
2283
2496
  var _a2, _b, _c;
2284
2497
  if (!propAnimIsMotionPath(anim)) return anim;
2285
2498
  const kfs = anim.keyframes;
@@ -2311,7 +2524,7 @@ function materialiseMotionPathInPropAnim(anim, opts) {
2311
2524
  if (autoOrient && i > 0) {
2312
2525
  insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
2313
2526
  }
2314
- materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2527
+ materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2315
2528
  }
2316
2529
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
2317
2530
  if (lastInE) out[out.length - 1].e = lastInE;
@@ -2425,7 +2638,7 @@ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos,
2425
2638
  out.push(makeOutKf(stepTime, dupValue));
2426
2639
  }
2427
2640
  var CORNER_STEP_AFTER_BOUNDARY_MS = 0.05;
2428
- function materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2641
+ function materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2429
2642
  const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2430
2643
  const prevTime = getKfTime(prevKf);
2431
2644
  const nextTime = getKfTime(nextKf);
@@ -2548,16 +2761,16 @@ function perpDist(q, pA, pB) {
2548
2761
  const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
2549
2762
  return Math.abs(cross) / Math.sqrt(len2);
2550
2763
  }
2551
- function materialiseMotionPathsInTree(root, opts) {
2552
- const out = walkAndMaterialise(root, opts);
2764
+ function materializeMotionPathsInTree(root, opts) {
2765
+ const out = walkAndMaterialize(root, opts);
2553
2766
  return out != null ? out : root;
2554
2767
  }
2555
- function walkAndMaterialise(node, opts) {
2768
+ function walkAndMaterialize(node, opts) {
2556
2769
  let newChildren;
2557
2770
  if (node.children) {
2558
2771
  for (let i = 0; i < node.children.length; i++) {
2559
2772
  const ch = node.children[i];
2560
- const ret = walkAndMaterialise(ch, opts);
2773
+ const ret = walkAndMaterialize(ch, opts);
2561
2774
  if (ret !== null) {
2562
2775
  if (!newChildren) newChildren = node.children.slice();
2563
2776
  newChildren[i] = ret;
@@ -2570,9 +2783,9 @@ function walkAndMaterialise(node, opts) {
2570
2783
  const animDef = animBucket;
2571
2784
  const transformAnim = animDef.transform;
2572
2785
  if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
2573
- const materialised = materialiseMotionPathInPropAnim(transformAnim, opts);
2574
- if (materialised !== transformAnim) {
2575
- newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialised });
2786
+ const materialized = materializeMotionPathInPropAnim(transformAnim, opts);
2787
+ if (materialized !== transformAnim) {
2788
+ newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialized });
2576
2789
  }
2577
2790
  }
2578
2791
  }
@@ -2675,8 +2888,8 @@ function isPathString(value) {
2675
2888
  return typeof value === "string" && extractPathData(value) !== void 0;
2676
2889
  }
2677
2890
  function normalizePathValue(value) {
2678
- if (value && typeof value === "object" && typeof value.path === "string") {
2679
- const d = extractPathData(value.path);
2891
+ if (value && typeof value === "object" && typeof value.pathData === "string") {
2892
+ const d = extractPathData(value.pathData);
2680
2893
  return d ? { paths: parseSvgPathToBezier(d) } : value;
2681
2894
  }
2682
2895
  if (value && typeof value === "object" && "paths" in value) {
@@ -2760,7 +2973,7 @@ function interpolateValue(propName, a, b, t) {
2760
2973
  const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2761
2974
  return { paths: interpolateBeziers(aPaths, bPaths, t) };
2762
2975
  }
2763
- if (COLOUR_ATTR_NAMES.has(propName)) {
2976
+ if (COLOR_ATTR_NAMES.has(propName)) {
2764
2977
  return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
2765
2978
  }
2766
2979
  if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
@@ -2982,7 +3195,7 @@ function normalizeKeyframes(propName, propAnim, duration, defs) {
2982
3195
  value = normalizePathValue(value);
2983
3196
  }
2984
3197
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2985
- if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
3198
+ if (COLOR_ATTR_NAMES.has(propNameKebab)) {
2986
3199
  value = (_a2 = parseColor(value)) != null ? _a2 : value;
2987
3200
  }
2988
3201
  const normKf = {
@@ -3016,20 +3229,20 @@ function mergeAnimationDefinitions(animations) {
3016
3229
  }
3017
3230
  return merged;
3018
3231
  }
3019
- function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
3232
+ function materializeInternalLoopsInPropAnim(propName, propAnim, duration) {
3020
3233
  const loopRaw = propAnim.loop;
3021
3234
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
3022
3235
  const loop = loopRaw === true ? {} : loopRaw;
3023
3236
  const rawKfs = propAnim.keyframes;
3024
3237
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
3025
3238
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3026
- const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
3239
+ const isColor = COLOR_ATTR_NAMES.has(propNameKebab);
3027
3240
  const kfs = rawKfs.map((kf) => {
3028
3241
  var _a2;
3029
3242
  const t = kfTime(kf);
3030
3243
  let v = kfValue(kf);
3031
3244
  if (propName === "d") v = normalizePathValue(v);
3032
- if (isColour) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3245
+ if (isColor) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3033
3246
  const e = kfEasing(kf);
3034
3247
  const out2 = { t, v, e };
3035
3248
  const tIn = kfTangentIn(kf);
@@ -3043,15 +3256,15 @@ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
3043
3256
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3044
3257
  return out;
3045
3258
  }
3046
- function materialiseInternalLoopsInTree(root, duration) {
3047
- const ret = walkAndMaterialiseLoops(root, duration);
3259
+ function materializeInternalLoopsInTree(root, duration) {
3260
+ const ret = walkAndMaterializeLoops(root, duration);
3048
3261
  return ret != null ? ret : root;
3049
3262
  }
3050
- function walkAndMaterialiseLoops(node, duration) {
3263
+ function walkAndMaterializeLoops(node, duration) {
3051
3264
  let newChildren;
3052
3265
  if (node.children) {
3053
3266
  for (let i = 0; i < node.children.length; i++) {
3054
- const ret = walkAndMaterialiseLoops(node.children[i], duration);
3267
+ const ret = walkAndMaterializeLoops(node.children[i], duration);
3055
3268
  if (ret !== null) {
3056
3269
  if (!newChildren) newChildren = node.children.slice();
3057
3270
  newChildren[i] = ret;
@@ -3064,10 +3277,10 @@ function walkAndMaterialiseLoops(node, duration) {
3064
3277
  const animDef = animBucket;
3065
3278
  for (const propName of Object.keys(animDef)) {
3066
3279
  const propAnim = animDef[propName];
3067
- const materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);
3068
- if (materialised !== propAnim) {
3280
+ const materialized = materializeInternalLoopsInPropAnim(propName, propAnim, duration);
3281
+ if (materialized !== propAnim) {
3069
3282
  if (!newAnimate) newAnimate = __spreadValues({}, animDef);
3070
- newAnimate[propName] = materialised;
3283
+ newAnimate[propName] = materialized;
3071
3284
  }
3072
3285
  }
3073
3286
  }
@@ -3122,12 +3335,12 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimeli
3122
3335
  const out = { keyframes: normalizedKfs };
3123
3336
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3124
3337
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
3125
- normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
3338
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materializeMotionPathInPropAnim(out) : out;
3126
3339
  }
3127
3340
  }
3128
3341
  return normalized;
3129
3342
  }
3130
- function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
3343
+ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
3131
3344
  const animatorConfig = getAnimatorConfig(doc) || {};
3132
3345
  const defs = getDefs(doc);
3133
3346
  const duration = animatorConfig.duration || 1e3;
@@ -3218,7 +3431,7 @@ function calcPropertyValue(propName, propAnim, progress) {
3218
3431
  nextPaths,
3219
3432
  localProgress
3220
3433
  ).map((bz) => bezierToSvgPath(bz)).join("");
3221
- } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
3434
+ } else if (COLOR_ATTR_NAMES.has(cssAttrName)) {
3222
3435
  cssValue = toRGBA(interpolateColor(
3223
3436
  prevV || [0, 0, 0, 1],
3224
3437
  nextV || [0, 0, 0, 1],
@@ -3379,8 +3592,8 @@ function applyUseOffsetToG(gNode) {
3379
3592
  return gNode;
3380
3593
  }
3381
3594
 
3382
- // src/materialise/PxAnimatorUseMaterialiser.ts
3383
- function materialiseAnimatedUseInstances(root) {
3595
+ // src/materialize/PxAnimatorUseMaterializer.ts
3596
+ function materializeAnimatedUseInstances(root) {
3384
3597
  var _a2;
3385
3598
  const idMap = buildIdMap(root);
3386
3599
  const animatedIds = computeAnimatedSubtreeIds(root, idMap);
@@ -3389,7 +3602,7 @@ function materialiseAnimatedUseInstances(root) {
3389
3602
  const genId3 = () => "_lw_use_mat_" + ++idCounter;
3390
3603
  const rootViewport = readRootViewport(root);
3391
3604
  const defsCollector = [];
3392
- const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3605
+ const walked = walkAndMaterialize2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3393
3606
  if (defsCollector.length === 0) return walked;
3394
3607
  const defsNode = { type: "defs", children: defsCollector };
3395
3608
  const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
@@ -3462,7 +3675,7 @@ function stripHash(href) {
3462
3675
  if (typeof href !== "string") return void 0;
3463
3676
  return href.startsWith("#") ? href.slice(1) : href;
3464
3677
  }
3465
- function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3678
+ function materializeOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3466
3679
  var _a2, _b, _c, _d;
3467
3680
  const clone2 = deepClonePxNode(target);
3468
3681
  regenerateIdsAndRewriteRefs(clone2, genId3);
@@ -3470,8 +3683,8 @@ function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsColl
3470
3683
  const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3471
3684
  const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
3472
3685
  const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
3473
- const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3474
- const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materialisedClone] });
3686
+ const materializedClone = walkAndMaterialize2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3687
+ const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materializedClone] });
3475
3688
  delete newNode.href;
3476
3689
  delete newNode.width;
3477
3690
  delete newNode.height;
@@ -3509,18 +3722,18 @@ function parseViewBox(v) {
3509
3722
  if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
3510
3723
  return [parts[0], parts[1], parts[2], parts[3]];
3511
3724
  }
3512
- function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3725
+ function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3513
3726
  if (node.type === "use" && typeof node.href === "string") {
3514
3727
  const targetId = stripHash(node.href);
3515
3728
  if (targetId && animatedIds.has(targetId)) {
3516
3729
  const target = idMap.get(targetId);
3517
- if (target) return materialiseOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
3730
+ if (target) return materializeOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
3518
3731
  }
3519
3732
  }
3520
3733
  if (!node.children) return node;
3521
3734
  let changed = false;
3522
3735
  const newChildren = node.children.map((ch) => {
3523
- const m = walkAndMaterialise2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3736
+ const m = walkAndMaterialize2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3524
3737
  if (m !== ch) changed = true;
3525
3738
  return m;
3526
3739
  });
@@ -3545,7 +3758,7 @@ function readAnimatable(raw) {
3545
3758
  const obj = raw;
3546
3759
  const kfs = obj.keyframes;
3547
3760
  if (kfs) {
3548
- const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3761
+ const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normalizeKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3549
3762
  const base = (_a2 = obj.value) != null ? _a2 : obj.v;
3550
3763
  if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
3551
3764
  return out;
@@ -3573,7 +3786,7 @@ function writeAnimatableChannel(node, attrName, read, opts) {
3573
3786
  const baseline = (_d = (_b = read.base) != null ? _b : (_a2 = read.keyframes[0]) == null ? void 0 : _a2.value) != null ? _d : (_c = read.keyframes[0]) == null ? void 0 : _c.v;
3574
3787
  if (baseline !== void 0) node[attrName] = toOut(baseline);
3575
3788
  }
3576
- function normaliseKeyframe(kf) {
3789
+ function normalizeKeyframe(kf) {
3577
3790
  if (!kf || typeof kf !== "object") return kf;
3578
3791
  const k = kf;
3579
3792
  if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
@@ -4085,10 +4298,10 @@ function formatOffset(o) {
4085
4298
 
4086
4299
  // src/effects/clipping/clipPathEffect.ts
4087
4300
  function applyClipPathEffect(node, fx, ctx) {
4088
- if (!(fx == null ? void 0 : fx.d)) return node;
4301
+ if (!(fx == null ? void 0 : fx.pathData)) return node;
4089
4302
  const clipId = genId(ctx, "clip");
4090
4303
  const pathChild = { type: "path" };
4091
- const read = readAnimatable(fx.d);
4304
+ const read = readAnimatable(fx.pathData);
4092
4305
  if (read.kind !== "absent" /* Absent */) {
4093
4306
  if (read.kind === "static" /* Static */) {
4094
4307
  pathChild.d = pathString(read.value);
@@ -4103,7 +4316,7 @@ function applyClipPathEffect(node, fx, ctx) {
4103
4316
  }
4104
4317
  function pathString(v) {
4105
4318
  if (typeof v === "string") return v;
4106
- if (v && typeof v === "object" && typeof v.path === "string") return v.path;
4319
+ if (v && typeof v === "object" && typeof v.pathData === "string") return v.pathData;
4107
4320
  return void 0;
4108
4321
  }
4109
4322
 
@@ -4150,8 +4363,8 @@ function wrapInverseTransform(inner, fx, ctx) {
4150
4363
  }
4151
4364
  function wrapInversePart(inner, part, raw, origin, ctx) {
4152
4365
  if (raw === void 0) return inner;
4153
- const normalisedRaw = part === "scale" /* Scale */ && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
4154
- const v = readAnimatable(normalisedRaw);
4366
+ const normalizedRaw = part === "scale" /* Scale */ && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
4367
+ const v = readAnimatable(normalizedRaw);
4155
4368
  if (v.kind === "static" /* Static */) {
4156
4369
  return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
4157
4370
  }
@@ -4552,7 +4765,7 @@ function synthesiseScale(raw, i) {
4552
4765
  }
4553
4766
 
4554
4767
  // src/effects/reference/retimeEffect.ts
4555
- var RETIME_MATERIALISATION_MODE_INLINE_G = false;
4768
+ var RETIME_MATERIALIZATION_MODE_INLINE_G = false;
4556
4769
  function asRetime(r) {
4557
4770
  var _a2, _b;
4558
4771
  return { start: (_a2 = r.start) != null ? _a2 : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
@@ -4637,11 +4850,11 @@ function applyAllRetimeEffects(root, ctx) {
4637
4850
  if (!retime) continue;
4638
4851
  const crop = retime.timeCrop;
4639
4852
  clearCloneRetime(useNode);
4640
- materialiseRetime(useNode, asRetime(retime), ctx);
4853
+ materializeRetime(useNode, asRetime(retime), ctx);
4641
4854
  if (crop) applyTimeCrop(useNode, crop, ctx);
4642
4855
  }
4643
4856
  }
4644
- function materialiseRetime(useNode, retime, ctx) {
4857
+ function materializeRetime(useNode, retime, ctx) {
4645
4858
  const targetId = stripHash2(useNode.href);
4646
4859
  if (!targetId) {
4647
4860
  ctx.errors.push("retime: <use> has no href to follow");
@@ -4649,7 +4862,7 @@ function materialiseRetime(useNode, retime, ctx) {
4649
4862
  }
4650
4863
  const chainRootId = buildChainClone(targetId, retime, ctx, /* @__PURE__ */ new Set());
4651
4864
  if (!chainRootId) return;
4652
- if (RETIME_MATERIALISATION_MODE_INLINE_G) {
4865
+ if (RETIME_MATERIALIZATION_MODE_INLINE_G) {
4653
4866
  const cloneNode = ctx.idMap.get(chainRootId);
4654
4867
  useNode.type = "g";
4655
4868
  delete useNode.href;
@@ -4689,13 +4902,13 @@ function buildChainClone(targetId, accum, ctx, chain) {
4689
4902
  if (subId2) cloneNode.href = "#" + subId2;
4690
4903
  }
4691
4904
  } else {
4692
- materialiseNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4905
+ materializeNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4693
4906
  }
4694
4907
  ctx.defs.push(cloneNode);
4695
4908
  if (typeof cloneNode.id === "string") ctx.idMap.set(cloneNode.id, cloneNode);
4696
4909
  return typeof cloneNode.id === "string" ? cloneNode.id : void 0;
4697
4910
  }
4698
- function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4911
+ function materializeNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4699
4912
  const visit = (n) => {
4700
4913
  var _a2;
4701
4914
  const retime = readCloneRetime(n);
@@ -4896,10 +5109,10 @@ function numRange(v) {
4896
5109
  function estimateTextAdvance(node) {
4897
5110
  let chars = 0, maxFont = 16;
4898
5111
  const walk = (el) => {
4899
- var _a2, _b;
5112
+ var _a2;
4900
5113
  const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
4901
5114
  if (fs) maxFont = Math.max(maxFont, fs);
4902
- const t = (_b = el.text) != null ? _b : el.textContent;
5115
+ const t = el.textContent;
4903
5116
  if (typeof t === "string") chars += t.length;
4904
5117
  if (el.children) for (const c of el.children) walk(c);
4905
5118
  };
@@ -5054,7 +5267,6 @@ var TEXT_ATTR_KEYS = [
5054
5267
  "stroke",
5055
5268
  "strokeWidth",
5056
5269
  "effects",
5057
- TEXT_ATTR,
5058
5270
  TEXT_CONTENT_ATTR,
5059
5271
  "xml:space"
5060
5272
  ];
@@ -5164,8 +5376,8 @@ function missingGlyphBoxEm(advanceEm, ascentEm) {
5164
5376
  const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
5165
5377
  return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
5166
5378
  }
5167
- function materialiseGlyphTextHorizontal(node, opts) {
5168
- var _a2, _b, _c, _d;
5379
+ function materializeGlyphTextHorizontal(node, opts) {
5380
+ var _a2, _b, _c;
5169
5381
  const { glyphs, create = jsonElementFactory, warnings } = opts;
5170
5382
  const soleFont = soleFontOf(glyphs);
5171
5383
  const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
@@ -5182,8 +5394,8 @@ function materialiseGlyphTextHorizontal(node, opts) {
5182
5394
  for (let i = 0; i < content.length; i++) {
5183
5395
  const ch = content.charAt(i);
5184
5396
  const g = gf == null ? void 0 : gf.glyphs[ch];
5185
- if (g && g.d) {
5186
- placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
5397
+ if (g && g.pathData) {
5398
+ placements.push({ glyphD: g.pathData, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
5187
5399
  pen.x += g.width * scale;
5188
5400
  } else if (/\S/.test(ch)) {
5189
5401
  const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
@@ -5197,7 +5409,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
5197
5409
  }
5198
5410
  };
5199
5411
  const walk = (el, parentStyle) => {
5200
- var _a3, _b2, _c2, _d2;
5412
+ var _a3, _b2, _c2;
5201
5413
  const s = resolveStyle2(el, parentStyle);
5202
5414
  const x = parseLen(el.x);
5203
5415
  const y = parseLen(el.y);
@@ -5209,14 +5421,14 @@ function materialiseGlyphTextHorizontal(node, opts) {
5209
5421
  if (y !== void 0) pen.y = y;
5210
5422
  pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
5211
5423
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
5212
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
5213
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5424
+ const content = str(el[TEXT_CONTENT_ATTR]);
5425
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
5214
5426
  if (el.children) for (const ch of el.children) walk(ch, s);
5215
5427
  };
5216
5428
  const rootStyle = rootStyleOf(node);
5217
5429
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
5218
- const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
5219
- if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
5430
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5431
+ if (rootContent && !((_c = node.children) == null ? void 0 : _c.length)) renderChars(rootContent, rootStyle);
5220
5432
  const anchor = str(node.textAnchor);
5221
5433
  if (anchor === "middle" || anchor === "end") {
5222
5434
  for (const p of placements) {
@@ -5228,7 +5440,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
5228
5440
  return toGroup(node, buildPaths(placements, create, warnings), create);
5229
5441
  }
5230
5442
  function layoutGlyphTextChars(node, opts) {
5231
- var _a2, _b, _c, _d, _e, _f;
5443
+ var _a2, _b, _c, _d, _e;
5232
5444
  if ((_a2 = opts.alongPath) == null ? void 0 : _a2.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
5233
5445
  const { glyphs, warnings } = opts;
5234
5446
  const soleFont = soleFontOf(glyphs);
@@ -5252,7 +5464,7 @@ function layoutGlyphTextChars(node, opts) {
5252
5464
  }
5253
5465
  };
5254
5466
  const walk = (el, parentStyle) => {
5255
- var _a3, _b2, _c2, _d2;
5467
+ var _a3, _b2, _c2;
5256
5468
  const s = resolveStyle2(el, parentStyle);
5257
5469
  const x = parseLen(el.x);
5258
5470
  const y = parseLen(el.y);
@@ -5264,8 +5476,8 @@ function layoutGlyphTextChars(node, opts) {
5264
5476
  if (y !== void 0) pen.y = y;
5265
5477
  pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
5266
5478
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
5267
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
5268
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5479
+ const content = str(el[TEXT_CONTENT_ATTR]);
5480
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
5269
5481
  if (el.children) for (const ch of el.children) walk(ch, s);
5270
5482
  };
5271
5483
  const rootStyle = rootStyleOf(node);
@@ -5279,8 +5491,8 @@ function layoutGlyphTextChars(node, opts) {
5279
5491
  boxes.push({ x: pen.x, y: pen.y, width: 0, ascent: ((_d = gf == null ? void 0 : gf.ascent) != null ? _d : 0.9 * upm) * (s.fontSize / upm), fontSize: s.fontSize, line });
5280
5492
  }
5281
5493
  }
5282
- const rootContent = (_e = str(node[TEXT_CONTENT_ATTR])) != null ? _e : str(node[TEXT_ATTR]);
5283
- if (rootContent && !((_f = node.children) == null ? void 0 : _f.length)) renderChars(rootContent, rootStyle);
5494
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5495
+ if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
5284
5496
  const anchor = str(node.textAnchor);
5285
5497
  if (anchor === "middle" || anchor === "end") {
5286
5498
  for (const b of boxes) {
@@ -5288,8 +5500,8 @@ function layoutGlyphTextChars(node, opts) {
5288
5500
  b.x += anchor === "middle" ? -w / 2 : -w;
5289
5501
  }
5290
5502
  }
5291
- return boxes.map((_g) => {
5292
- var _h = _g, { line: _l } = _h, b = __objRest(_h, ["line"]);
5503
+ return boxes.map((_f) => {
5504
+ var _g = _f, { line: _l } = _g, b = __objRest(_g, ["line"]);
5293
5505
  return b;
5294
5506
  });
5295
5507
  }
@@ -5305,14 +5517,14 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
5305
5517
  const chars = [];
5306
5518
  let adv = 0;
5307
5519
  const walk = (el, parentStyle) => {
5308
- var _a3, _b2, _c;
5520
+ var _a3, _b2;
5309
5521
  const s = resolveStyle2(el, parentStyle);
5310
- const content = (_a3 = str(el[TEXT_CONTENT_ATTR])) != null ? _a3 : str(el[TEXT_ATTR]);
5311
- if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
5522
+ const content = str(el[TEXT_CONTENT_ATTR]);
5523
+ if (content && !((_a3 = el.children) == null ? void 0 : _a3.length)) {
5312
5524
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
5313
5525
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
5314
5526
  const scale = s.fontSize / upm;
5315
- const ascent = ((_c = gf == null ? void 0 : gf.ascent) != null ? _c : 0.9 * upm) * scale;
5527
+ const ascent = ((_b2 = gf == null ? void 0 : gf.ascent) != null ? _b2 : 0.9 * upm) * scale;
5316
5528
  for (let i = 0; i < content.length; i++) {
5317
5529
  const ch = content.charAt(i);
5318
5530
  const g = gf == null ? void 0 : gf.glyphs[ch];
@@ -5359,21 +5571,21 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
5359
5571
  const cells = [];
5360
5572
  let adv = 0;
5361
5573
  const walk = (el, parentStyle) => {
5362
- var _a2, _b, _c;
5574
+ var _a2, _b;
5363
5575
  const s = resolveStyle2(el, parentStyle);
5364
- const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
5365
- if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
5576
+ const content = str(el[TEXT_CONTENT_ATTR]);
5577
+ if (content && !((_a2 = el.children) == null ? void 0 : _a2.length)) {
5366
5578
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
5367
5579
  if (gf) {
5368
5580
  const scale = s.fontSize / gf.unitsPerEm;
5369
- const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
5581
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
5370
5582
  const paint = paintOf(s);
5371
5583
  for (let i = 0; i < content.length; i++) {
5372
5584
  const ch = content.charAt(i);
5373
5585
  const g = gf.glyphs[ch];
5374
- if (g && g.d) {
5586
+ if (g && g.pathData) {
5375
5587
  const glyphAdv = g.width * scale;
5376
- cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
5588
+ cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
5377
5589
  adv += glyphAdv;
5378
5590
  } else if (/\S/.test(ch)) {
5379
5591
  const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
@@ -5404,7 +5616,7 @@ function alongPathNodeOffsets(node) {
5404
5616
  perp: (_c = parseLen(node.dy)) != null ? _c : 0
5405
5617
  };
5406
5618
  }
5407
- function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5619
+ function materializeGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5408
5620
  const { glyphs, create = jsonElementFactory, warnings } = opts;
5409
5621
  const sampler = pathD ? createPathSampler(pathD) : null;
5410
5622
  if (!sampler) {
@@ -5483,8 +5695,8 @@ function buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isC
5483
5695
  const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
5484
5696
  const out = [];
5485
5697
  for (const c of cells) {
5486
- const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5487
- const d = transformPathData(c.glyphD, centred);
5698
+ const centered = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5699
+ const d = transformPathData(c.glyphD, centered);
5488
5700
  const sampleKf = (dist, time) => {
5489
5701
  const { x, y, angle } = sampler.sampleAtDistance(dist);
5490
5702
  const cos = Math.cos(angle), sin = Math.sin(angle);
@@ -5576,9 +5788,9 @@ function toGroup(node, children, create) {
5576
5788
  }
5577
5789
  return create("g", gProps, children);
5578
5790
  }
5579
- function materialiseGlyphText(node, opts) {
5580
- if (opts.alongPath) return materialiseGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5581
- return materialiseGlyphTextHorizontal(node, opts);
5791
+ function materializeGlyphText(node, opts) {
5792
+ if (opts.alongPath) return materializeGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5793
+ return materializeGlyphTextHorizontal(node, opts);
5582
5794
  }
5583
5795
  function applyTextGlyphsEffect(node, fx, ctx) {
5584
5796
  if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
@@ -5586,14 +5798,14 @@ function applyTextGlyphsEffect(node, fx, ctx) {
5586
5798
  ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
5587
5799
  return node;
5588
5800
  }
5589
- return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5801
+ return materializeGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5590
5802
  }
5591
5803
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
5592
5804
  if (!ctx.glyphs) {
5593
5805
  ctx.warnings.push("textGlyphs: no definitions.fonts");
5594
5806
  return null;
5595
5807
  }
5596
- return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5808
+ return materializeGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5597
5809
  }
5598
5810
 
5599
5811
  // src/effects/stroke/strokeTrimEffect.ts
@@ -5995,7 +6207,7 @@ function applyPlayerEffects_retime(node, ctx) {
5995
6207
  return node;
5996
6208
  }
5997
6209
 
5998
- // src/materialise/PxOffsetPathMaterialiser.ts
6210
+ // src/materialize/PxOffsetPathMaterializer.ts
5999
6211
  function cubicAt(p0, c1, c2, p1, t) {
6000
6212
  const u = 1 - t;
6001
6213
  const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
@@ -6061,7 +6273,7 @@ function buildOffsetPath(propAnim) {
6061
6273
  }
6062
6274
  return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
6063
6275
  }
6064
- function materialiseOffsetPathsInTree(root) {
6276
+ function materializeOffsetPathsInTree(root) {
6065
6277
  const walk = (node) => {
6066
6278
  var _a2;
6067
6279
  let out = node;
@@ -6105,16 +6317,16 @@ function materialiseOffsetPathsInTree(root) {
6105
6317
  return walk(root);
6106
6318
  }
6107
6319
 
6108
- // src/materialise/PxAnimatorMaterialiseAll.ts
6109
- function materialiseAllInTree(doc, engine, opts) {
6320
+ // src/materialize/PxAnimatorMaterializeAll.ts
6321
+ function materializeAllInTree(doc, engine, opts) {
6110
6322
  var _a2, _b;
6111
6323
  let root = applyPlayerEffects(doc).root;
6112
- root = materialiseOffsetPathsInTree(root);
6324
+ root = materializeOffsetPathsInTree(root);
6113
6325
  const duration = (_b = (_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.duration) != null ? _b : DEFAULT_DURATION_MS;
6114
- root = materialiseInternalLoopsInTree(root, duration);
6326
+ root = materializeInternalLoopsInTree(root, duration);
6115
6327
  if (engine === PxTimelineEngine.native) {
6116
- root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
6117
- root = materialiseAnimatedUseInstances(root);
6328
+ root = materializeMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
6329
+ root = materializeAnimatedUseInstances(root);
6118
6330
  root = pruneUnreferencedDefs(root);
6119
6331
  }
6120
6332
  return root;
@@ -6149,6 +6361,66 @@ function pruneUnreferencedDefs(root) {
6149
6361
  return root;
6150
6362
  }
6151
6363
 
6364
+ // src/playback/PxPlaybackTime.ts
6365
+ var PX_RATE_REJECTED = "setPlaybackRate: rate must be finite and non-zero";
6366
+ function isValidPlaybackRate(rate) {
6367
+ return Number.isFinite(rate) && rate !== 0;
6368
+ }
6369
+ function seekCeilingMs(durationMs, iterations) {
6370
+ if (!(durationMs > 0)) return 0;
6371
+ if (iterations === Infinity) return Infinity;
6372
+ return durationMs * (iterations > 0 ? iterations : 1);
6373
+ }
6374
+ function progressSpanMs(durationMs, iterations) {
6375
+ if (!(durationMs > 0)) return 0;
6376
+ if (iterations === Infinity) return durationMs;
6377
+ return durationMs * (iterations > 0 ? iterations : 1);
6378
+ }
6379
+ function clampSeekMs(timeMs, ceilingMs) {
6380
+ if (Number.isNaN(timeMs) || timeMs < 0) return 0;
6381
+ if (Number.isFinite(ceilingMs)) return timeMs > ceilingMs ? ceilingMs : timeMs;
6382
+ return Number.isFinite(timeMs) ? timeMs : 0;
6383
+ }
6384
+ function timeToProgress(timeMs, durationMs, iterations) {
6385
+ const span = progressSpanMs(durationMs, iterations);
6386
+ if (!(span > 0) || !Number.isFinite(timeMs)) return 0;
6387
+ if (timeMs <= 0) return 0;
6388
+ if (iterations === Infinity) return timeMs % span / span;
6389
+ return timeMs >= span ? 1 : timeMs / span;
6390
+ }
6391
+ function progressToTimeMs(progress, durationMs, iterations) {
6392
+ const span = progressSpanMs(durationMs, iterations);
6393
+ if (!(span > 0) || !Number.isFinite(progress)) return 0;
6394
+ if (progress <= 0) return 0;
6395
+ return progress >= 1 ? span : progress * span;
6396
+ }
6397
+ function createRunClock(ceilingMs, nowFn = Date.now) {
6398
+ let baseMs = 0;
6399
+ let startedAt = 0;
6400
+ let running = false;
6401
+ let rate = 1;
6402
+ const value = () => running ? clampSeekMs(baseMs + (nowFn() - startedAt) * rate, ceilingMs) : clampSeekMs(baseMs, ceilingMs);
6403
+ return {
6404
+ now: value,
6405
+ isRunning: () => running,
6406
+ start: (r, atMs) => {
6407
+ baseMs = clampSeekMs(atMs != null ? atMs : value(), ceilingMs);
6408
+ rate = isValidPlaybackRate(r) ? r : 1;
6409
+ startedAt = nowFn();
6410
+ running = true;
6411
+ },
6412
+ stop: () => {
6413
+ baseMs = value();
6414
+ startedAt = 0;
6415
+ running = false;
6416
+ },
6417
+ seek: (ms) => {
6418
+ baseMs = clampSeekMs(ms, ceilingMs);
6419
+ if (running) startedAt = nowFn();
6420
+ }
6421
+ };
6422
+ }
6423
+
6152
6424
  // src/playback/PxFrameLoop.ts
6153
6425
  function requestFrame(cb) {
6154
6426
  const g = globalThis;
@@ -6166,7 +6438,7 @@ function cancelFrame(handle) {
6166
6438
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6167
6439
  var _a2;
6168
6440
  const config = getAnimatorConfig(doc) || {};
6169
- const bindings = getNormalisedBindings(doc, PxTimelineEngine.js);
6441
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.js);
6170
6442
  const _iterations = config.iterations;
6171
6443
  let iterations = 1;
6172
6444
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -6396,8 +6668,8 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6396
6668
  finishAnim(true);
6397
6669
  },
6398
6670
  "setPlaybackRate": (rate) => {
6399
- if (!isFinite(rate) || rate === 0) {
6400
- console.warn("setPlaybackRate: rate must be finite and non-zero");
6671
+ if (!isValidPlaybackRate(rate)) {
6672
+ console.warn(PX_RATE_REJECTED);
6401
6673
  return;
6402
6674
  }
6403
6675
  let current = getRawAnimTime();
@@ -6411,13 +6683,16 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6411
6683
  return getAnimCurrentTime();
6412
6684
  },
6413
6685
  "setCurrentTime": (newTime) => {
6414
- if (newTime < 0) newTime = 0;
6415
- if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
6686
+ newTime = clampSeekMs(newTime, totalDuration);
6416
6687
  timeBeforeLastStartMs = newTime;
6417
6688
  if (playing) lastStartedTs = Date.now();
6418
6689
  if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
6419
6690
  renderFrame(getAnimCurrentTime());
6420
6691
  },
6692
+ "getCurrentProgress": () => timeToProgress(getAnimCurrentTime(), duration, iterations),
6693
+ "setCurrentProgress": (progress) => {
6694
+ api.setCurrentTime(progressToTimeMs(progress, duration, iterations));
6695
+ },
6421
6696
  "destroy": () => {
6422
6697
  var _a3;
6423
6698
  api.cancel();
@@ -6427,6 +6702,51 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6427
6702
  return api;
6428
6703
  }
6429
6704
 
6705
+ // src/playback/PxDiagnostics.ts
6706
+ var PxDiagnosticKind = {
6707
+ /** The document is wrong — regenerate or repair the file. */
6708
+ document: "document",
6709
+ /** The page or app cannot provide what the document asks for — fix the mount. */
6710
+ host: "host",
6711
+ /** The platform cannot do it and the player degraded — usually nothing to fix. */
6712
+ platform: "platform",
6713
+ /** The call is wrong or self-contradictory — fix the options or props you passed. */
6714
+ usage: "usage",
6715
+ /** The player failed where it did not expect to — report it to us. */
6716
+ internal: "internal"
6717
+ };
6718
+ function asError(error) {
6719
+ return typeof error === "string" ? new Error(error) : error;
6720
+ }
6721
+ function isSilenced(silent, kind) {
6722
+ if (!silent) return false;
6723
+ return silent === true || silent.includes(kind);
6724
+ }
6725
+ function createDiagnostics(config, prefix) {
6726
+ const tag = prefix ? prefix + " " : "";
6727
+ return {
6728
+ warn: (kind, message, detail) => {
6729
+ if (config == null ? void 0 : config.onWarn) {
6730
+ config.onWarn({ kind, message, detail });
6731
+ return;
6732
+ }
6733
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6734
+ const line = tag + kind + ": " + message;
6735
+ if (detail === void 0) console.warn(line);
6736
+ else console.warn(line, detail);
6737
+ },
6738
+ error: (kind, error) => {
6739
+ const err = asError(error);
6740
+ if (config == null ? void 0 : config.onError) {
6741
+ config.onError({ kind, message: err.message, error: err });
6742
+ return;
6743
+ }
6744
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6745
+ console.error(tag + kind + ": " + err.message);
6746
+ }
6747
+ };
6748
+ }
6749
+
6430
6750
  // src/effects/PlayerEffectsUtil.visualModel.ts
6431
6751
  var IDENTITY = [1, 0, 0, 1, 0, 0];
6432
6752
  function mul(m, n) {
@@ -6699,32 +7019,30 @@ function mergeTimeline(base, patch, warn) {
6699
7019
  }
6700
7020
  return merged;
6701
7021
  }
6702
- function foldAnimatorConfigShortcuts(config, shortcuts) {
7022
+ function foldTimelineOverride(timeline, shortcuts) {
6703
7023
  let base;
6704
- if (typeof config === "string") {
7024
+ if (typeof timeline === "string") {
6705
7025
  try {
6706
- base = JSON.parse(config);
7026
+ base = JSON.parse(timeline);
6707
7027
  } catch (e) {
6708
- console.warn("animator config: not valid JSON \u2014 ignored", e);
7028
+ console.warn("timeline override: not valid JSON \u2014 ignored", e);
6709
7029
  base = void 0;
6710
7030
  }
6711
7031
  } else {
6712
- base = config != null ? config : void 0;
7032
+ base = timeline != null ? timeline : void 0;
6713
7033
  }
6714
7034
  const { duration, delay, iterations, startOn } = shortcuts;
6715
7035
  if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6716
- return base;
7036
+ return base === void 0 ? void 0 : { timeline: base };
6717
7037
  }
6718
7038
  const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6719
- const timeline = __spreadValues({}, out.timeline);
6720
- if (duration !== void 0) timeline.duration = duration;
6721
- if (delay !== void 0) timeline.delay = delay;
6722
- if (iterations !== void 0) timeline.iterations = iterations;
7039
+ if (duration !== void 0) out.duration = duration;
7040
+ if (delay !== void 0) out.delay = delay;
7041
+ if (iterations !== void 0) out.iterations = iterations;
6723
7042
  if (startOn !== void 0) {
6724
- timeline.trigger = __spreadProps(__spreadValues({}, timeline.trigger), { startOn });
7043
+ out.trigger = __spreadProps(__spreadValues({}, out.trigger), { startOn });
6725
7044
  }
6726
- out.timeline = timeline;
6727
- return out;
7045
+ return { timeline: out };
6728
7046
  }
6729
7047
  function mergeAnimatorConfig(base, patch) {
6730
7048
  const warnings = [];
@@ -6792,26 +7110,12 @@ function applyAnimatorConfig(doc, patch, opts) {
6792
7110
 
6793
7111
  // src/format/PxDocumentDiagnostic.ts
6794
7112
  var MAX_REPORTED = 6;
6795
- var LEGACY_FLAT_KEYS = [
6796
- ...PX_TIMELINE_SHARED_KEYS,
6797
- ...PX_TIME_ONLY_TIMELINE_KEYS,
6798
- "fill",
6799
- "resetOnFinish",
6800
- "timelineSource",
6801
- "scroll"
6802
- ];
6803
- var isLegacyFlatAnimatorKey = (w) => LEGACY_FLAT_KEYS.some((k) => w.indexOf("animator." + k + ":") >= 0);
6804
7113
  function diagnoseDocument(doc) {
6805
- let all;
6806
7114
  try {
6807
- all = validateDocument(doc);
7115
+ return { problems: validateDocument(doc) };
6808
7116
  } catch (e) {
6809
- return { problems: [], legacy: [] };
7117
+ return { problems: [] };
6810
7118
  }
6811
- const problems = [];
6812
- const legacy = [];
6813
- for (const w of all) (isLegacyFlatAnimatorKey(w) ? legacy : problems).push(w);
6814
- return { problems, legacy };
6815
7119
  }
6816
7120
  function reportDocumentDiagnostics(doc, where) {
6817
7121
  const { problems } = diagnoseDocument(doc);
@@ -6824,7 +7128,7 @@ function reportDocumentDiagnostics(doc, where) {
6824
7128
  }
6825
7129
  export {
6826
7130
  BASELINE_PLAYER_VERSION,
6827
- COLOUR_ATTR_NAMES,
7131
+ COLOR_ATTR_NAMES,
6828
7132
  CSS_ONLY_STYLE_PROPS,
6829
7133
  DEFAULT_DURATION_MS,
6830
7134
  DISALLOWED_SVG_TAGS_LOWER,
@@ -6837,45 +7141,65 @@ export {
6837
7141
  PX_ANIM_ATTR_NAME,
6838
7142
  PX_ANIM_SRC_ATTR_NAME,
6839
7143
  PX_PLAYER_SCHEMA_VERSION,
7144
+ PX_RATE_REJECTED,
6840
7145
  PX_TRANSFORM_PART_KEYS,
7146
+ PX_TRIGGER_DEFAULTS,
6841
7147
  PX_UNKNOWN_KEY_ERROR,
7148
+ PxAlongPathMode,
6842
7149
  PxAnimatedSvgDocumentSchema,
6843
7150
  PxAnimationDefinitionSchema,
6844
7151
  PxAnimatorConfigSchema,
6845
7152
  PxAttrValueSchema,
6846
7153
  PxBezierPathSchema,
6847
7154
  PxBindingSchema,
7155
+ PxClipPathEffectSchema,
6848
7156
  PxCloneEffectSchema,
6849
7157
  PxCloneWithout,
7158
+ PxControlMode,
6850
7159
  PxDefsSchema,
7160
+ PxDiagnosticKind,
6851
7161
  PxEasingOrRefSchema,
6852
7162
  PxEffectsSchema,
6853
7163
  PxElementAnimationSchema,
6854
7164
  PxFillGradientEffectSchema,
7165
+ PxFillMode,
7166
+ PxFinishAction,
6855
7167
  PxGradientSpreadMethod,
6856
7168
  PxGradientStopSchema,
6857
7169
  PxGradientType,
6858
- PxGradientUnits,
6859
7170
  PxKeyframeSchema,
6860
7171
  PxKeyframeValueSchema,
7172
+ PxLengthAdjust,
6861
7173
  PxLoopDirection,
6862
7174
  PxLoopRepeatAt,
6863
7175
  PxLoopSchema,
7176
+ PxMaskType,
6864
7177
  PxMaskedByEffectSchema,
6865
7178
  PxNodeBase,
6866
7179
  PxNodeSchema,
7180
+ PxOutAction,
7181
+ PxPathOverflow,
7182
+ PxPinAlign,
7183
+ PxPlaybackDirection,
6867
7184
  PxPropertyAnimationSchema,
6868
7185
  PxRepeaterEffectSchema,
6869
7186
  PxRetimeEffectSchema,
7187
+ PxScrollAxis,
7188
+ PxScrollKind,
7189
+ PxScrollPhase,
6870
7190
  PxScrollRangePointSchema,
6871
7191
  PxScrollRangeSchema,
6872
7192
  PxScrollSchema,
7193
+ PxScrollSource,
7194
+ PxStartOn,
6873
7195
  PxStrokeGradientEffectSchema,
6874
7196
  PxStrokeTrimEffectSchema,
6875
7197
  PxStrokeTrimSubPaths,
6876
7198
  PxSvgNodeExtra,
6877
7199
  PxTextEffectSchema,
6878
7200
  PxTextPathEffectSchema,
7201
+ PxTextPathMethod,
7202
+ PxTextPathSpacing,
6879
7203
  PxTimelineEngine,
6880
7204
  PxTimelineEngineExtra,
6881
7205
  PxTimelinePinSchema,
@@ -6884,8 +7208,8 @@ export {
6884
7208
  PxTransformPartsSchema,
6885
7209
  PxTransformValueSchema,
6886
7210
  PxTriggerSchema,
7211
+ PxUnits,
6887
7212
  STYLE_ATTR_NAMES,
6888
- TEXT_ATTR,
6889
7213
  TEXT_CONTENT_ATTR,
6890
7214
  TRANSFORM_FN_NAMES,
6891
7215
  WIRE_VERSION_KEY,
@@ -6899,12 +7223,16 @@ export {
6899
7223
  calcAnimationValues,
6900
7224
  camelCaseToKebabWordIfNeeded,
6901
7225
  clamp,
7226
+ clampSeekMs,
6902
7227
  collectSampleTimes,
6903
7228
  compareWireVersion,
6904
7229
  composeTransformParts,
7230
+ controlModeTakesOverTrigger,
6905
7231
  convertPlayerDocument,
6906
7232
  createBasicFrameLoopAnimator,
7233
+ createDiagnostics,
6907
7234
  createPathSampler,
7235
+ createRunClock,
6908
7236
  cubicBezier,
6909
7237
  deepClone,
6910
7238
  describeSchema,
@@ -6915,7 +7243,7 @@ export {
6915
7243
  evaluateMotionPathSegment,
6916
7244
  extendedPathForBrowser,
6917
7245
  flattenAnimatorTimeline,
6918
- foldAnimatorConfigShortcuts,
7246
+ foldTimelineOverride,
6919
7247
  formatWireVersion,
6920
7248
  generateNewIds,
6921
7249
  generateUniqueId,
@@ -6923,7 +7251,7 @@ export {
6923
7251
  getBindings,
6924
7252
  getChildren,
6925
7253
  getDefs,
6926
- getNormalisedBindings,
7254
+ getNormalizedBindings,
6927
7255
  getNormalizedProps,
6928
7256
  interpolateBeziers,
6929
7257
  interpolateValue,
@@ -6931,6 +7259,7 @@ export {
6931
7259
  isPxElementFileFormat,
6932
7260
  isPxElementFileFormatDeep,
6933
7261
  isScrollTimeline,
7262
+ isValidPlaybackRate,
6934
7263
  jsonElementFactory,
6935
7264
  kebabToCamelCaseWord,
6936
7265
  kfEasing,
@@ -6939,15 +7268,15 @@ export {
6939
7268
  kfTime,
6940
7269
  kfValue,
6941
7270
  layoutGlyphTextChars,
6942
- materialiseAllInTree,
6943
- materialiseAnimatedUseInstances,
6944
- materialiseGlyphText,
6945
- materialiseGlyphTextAlongPath,
6946
- materialiseGlyphTextHorizontal,
6947
- materialiseInternalLoopsInPropAnim,
6948
- materialiseInternalLoopsInTree,
6949
- materialiseMotionPathInPropAnim,
6950
- materialiseMotionPathsInTree,
7271
+ materializeAllInTree,
7272
+ materializeAnimatedUseInstances,
7273
+ materializeGlyphText,
7274
+ materializeGlyphTextAlongPath,
7275
+ materializeGlyphTextHorizontal,
7276
+ materializeInternalLoopsInPropAnim,
7277
+ materializeInternalLoopsInTree,
7278
+ materializeMotionPathInPropAnim,
7279
+ materializeMotionPathsInTree,
6951
7280
  mayUseNativeScrollTimeline,
6952
7281
  mergeAnimatorConfig,
6953
7282
  mergeStaticTransformIntoAnimDef,
@@ -6955,15 +7284,19 @@ export {
6955
7284
  parseTransformParts,
6956
7285
  parseWireVersion,
6957
7286
  planSchemaRelease,
7287
+ progressSpanMs,
7288
+ progressToTimeMs,
6958
7289
  propAnimIsMotionPath,
6959
7290
  px,
6960
7291
  readWireVersion,
6961
7292
  releaseLogProblems,
6962
7293
  reportDocumentDiagnostics,
7294
+ resolveControlMode,
6963
7295
  resolveStyle,
6964
7296
  resolveTimelineEngine,
7297
+ resolveTrigger,
6965
7298
  reverseEasing,
6966
- sanitiseAttributeValue,
7299
+ sanitizeAttributeValue,
6967
7300
  schemaFieldUniverse,
6968
7301
  schemaKeys,
6969
7302
  scrollOffsetProgress,
@@ -6971,9 +7304,11 @@ export {
6971
7304
  scrollResolveAxis,
6972
7305
  scrollTotalDurationMs,
6973
7306
  scrollViewProgress,
7307
+ seekCeilingMs,
6974
7308
  shiftAnimatable,
6975
7309
  splitEasing,
6976
7310
  subdivideCubicBezier,
7311
+ timeToProgress,
6977
7312
  toRGBA,
6978
7313
  validateDocument,
6979
7314
  validateNodeEffects,