@pixodesk/svg-animator-core 1.0.29 → 1.0.34

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
@@ -93,15 +93,17 @@ __export(index_exports, {
93
93
  PxScrollRangeSchema: () => PxScrollRangeSchema,
94
94
  PxScrollSchema: () => PxScrollSchema,
95
95
  PxStrokeGradientEffectSchema: () => PxStrokeGradientEffectSchema,
96
+ PxStrokeTrimEffectSchema: () => PxStrokeTrimEffectSchema,
97
+ PxStrokeTrimSubPaths: () => PxStrokeTrimSubPaths,
96
98
  PxSvgNodeExtra: () => PxSvgNodeExtra,
97
99
  PxTextEffectSchema: () => PxTextEffectSchema,
98
100
  PxTextPathEffectSchema: () => PxTextPathEffectSchema,
101
+ PxTimelinePinSchema: () => PxTimelinePinSchema,
102
+ PxTimelineSchema: () => PxTimelineSchema,
99
103
  PxTransformByEffectSchema: () => PxTransformByEffectSchema,
100
104
  PxTransformPartsSchema: () => PxTransformPartsSchema,
101
105
  PxTransformValueSchema: () => PxTransformValueSchema,
102
106
  PxTriggerSchema: () => PxTriggerSchema,
103
- PxTrimPathEffectSchema: () => PxTrimPathEffectSchema,
104
- PxTrimSubPaths: () => PxTrimSubPaths,
105
107
  STYLE_ATTR_NAMES: () => STYLE_ATTR_NAMES,
106
108
  TEXT_ATTR: () => TEXT_ATTR,
107
109
  TEXT_CONTENT_ATTR: () => TEXT_CONTENT_ATTR,
@@ -121,6 +123,7 @@ __export(index_exports, {
121
123
  diffInEffect: () => diffInEffect,
122
124
  evaluateMotionPathSegment: () => evaluateMotionPathSegment,
123
125
  extendedPathForBrowser: () => extendedPathForBrowser,
126
+ flattenAnimatorTimeline: () => flattenAnimatorTimeline,
124
127
  generateNewIds: () => generateNewIds,
125
128
  generateUniqueId: () => generateUniqueId,
126
129
  getAnimatorConfig: () => getAnimatorConfig,
@@ -146,6 +149,9 @@ __export(index_exports, {
146
149
  materialiseInternalLoopsInTree: () => materialiseInternalLoopsInTree,
147
150
  materialiseMotionPathInPropAnim: () => materialiseMotionPathInPropAnim,
148
151
  materialiseMotionPathsInTree: () => materialiseMotionPathsInTree,
152
+ mergeStaticTransformIntoAnimDef: () => mergeStaticTransformIntoAnimDef,
153
+ nestAnimatorTimeline: () => nestAnimatorTimeline,
154
+ parseTransformParts: () => parseTransformParts,
149
155
  propAnimIsMotionPath: () => propAnimIsMotionPath,
150
156
  px: () => px,
151
157
  resolveStyle: () => resolveStyle,
@@ -419,6 +425,38 @@ function composeTransformParts(parts, opts) {
419
425
  if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
420
426
  return segs.join("");
421
427
  }
428
+ function parseTransformParts(str2) {
429
+ var _a, _b;
430
+ if (!str2 || typeof str2 !== "string") return void 0;
431
+ const out = {};
432
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
433
+ const order = ["translate", "rotate", "skewX", "scale"];
434
+ let lastIdx = -1;
435
+ let m;
436
+ while ((m = re.exec(str2)) !== null) {
437
+ const fn = m[1];
438
+ const idx = order.indexOf(fn);
439
+ if (idx < 0 || idx <= lastIdx) return void 0;
440
+ lastIdx = idx;
441
+ const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
442
+ if (nums.some((n) => Number.isNaN(n))) return void 0;
443
+ if (fn === "translate") {
444
+ if (nums.length < 1 || nums.length > 2) return void 0;
445
+ out.translate = [nums[0], (_a = nums[1]) != null ? _a : 0];
446
+ } else if (fn === "rotate") {
447
+ if (nums.length !== 1) return void 0;
448
+ out.rotate = nums[0];
449
+ } else if (fn === "skewX") {
450
+ if (nums.length !== 1) return void 0;
451
+ out.skew = nums[0];
452
+ } else {
453
+ if (nums.length < 1 || nums.length > 2) return void 0;
454
+ out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
455
+ }
456
+ }
457
+ if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
458
+ return Object.keys(out).length ? out : void 0;
459
+ }
422
460
  var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
423
461
  var DEFAULT_DURATION_MS = 1e3;
424
462
  function kebabToCamelCaseWord(kebab) {
@@ -750,6 +788,8 @@ var Union = class extends Base {
750
788
  constructor(schemas, defaultVal) {
751
789
  super();
752
790
  this.schemas = schemas;
791
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Union from Tuple. */
792
+ this._kind = "union";
753
793
  this._default = defaultVal != null ? defaultVal : schemas[0]._default;
754
794
  }
755
795
  sanitize(raw) {
@@ -774,6 +814,8 @@ var DiscriminatedUnion = class extends Base {
774
814
  super();
775
815
  this._key = _key;
776
816
  this._schemas = _schemas;
817
+ /** Structural tag read by {@link describeSchema}. */
818
+ this._kind = "discriminatedUnion";
777
819
  this._default = defaultVal != null ? defaultVal : _schemas[0]._default;
778
820
  this._map = /* @__PURE__ */ new Map();
779
821
  for (const s of _schemas) {
@@ -936,6 +978,8 @@ var Rec = class extends Base {
936
978
  constructor(value) {
937
979
  super();
938
980
  this.value = value;
981
+ /** Structural tag read by {@link describeSchema}. */
982
+ this._kind = "record";
939
983
  this._default = {};
940
984
  }
941
985
  sanitize(raw) {
@@ -1021,6 +1065,8 @@ var Tuple = class extends Base {
1021
1065
  constructor(schemas) {
1022
1066
  super();
1023
1067
  this.schemas = schemas;
1068
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Tuple from Union. */
1069
+ this._kind = "tuple";
1024
1070
  this._default = schemas.map((s) => s._default);
1025
1071
  }
1026
1072
  sanitize(raw) {
@@ -1057,10 +1103,20 @@ function schemaKeys(schema) {
1057
1103
  function describeSchema(schema) {
1058
1104
  var _a;
1059
1105
  const s = schema;
1060
- if ("_shape" in s) return { kind: "shape", shape: s._shape };
1106
+ switch (s._kind) {
1107
+ case "union":
1108
+ return { kind: "union", members: s.schemas };
1109
+ case "discriminatedUnion":
1110
+ return { kind: "discriminatedUnion", key: s._key, members: s._schemas };
1111
+ case "record":
1112
+ return { kind: "record", value: s.value };
1113
+ case "tuple":
1114
+ return { kind: "tuple", items: s.schemas };
1115
+ }
1116
+ if ("_shape" in s) return { kind: "shape", shape: s._shape, openValue: s._openSchema };
1061
1117
  if ("item" in s) return { kind: "array", item: s.item };
1062
1118
  if ("inner" in s) return { kind: "optional", inner: s.inner };
1063
- if ("fn" in s) return { kind: "lazy", resolved: (_a = s.resolved) != null ? _a : s.fn() };
1119
+ if ("fn" in s) return { kind: "lazy", resolved: (_a = s.resolved) != null ? _a : s.resolved = s.fn() };
1064
1120
  return { kind: "leaf" };
1065
1121
  }
1066
1122
  var px = {
@@ -1162,7 +1218,7 @@ var PxTextPathSpacing = {
1162
1218
  auto: "auto",
1163
1219
  exact: "exact"
1164
1220
  };
1165
- var PxTrimSubPaths = {
1221
+ var PxStrokeTrimSubPaths = {
1166
1222
  separate: "separate",
1167
1223
  combined: "combined"
1168
1224
  };
@@ -1200,7 +1256,107 @@ function isPxElementFileFormat(fileJson) {
1200
1256
  }
1201
1257
  function getAnimatorConfig(doc) {
1202
1258
  var _a;
1203
- return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
1259
+ const cfg = (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
1260
+ return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1261
+ }
1262
+ var flattenMemo = /* @__PURE__ */ new WeakMap();
1263
+ function flattenAnimatorTimeline(cfg) {
1264
+ const timeline = cfg.timeline;
1265
+ if (timeline === void 0 || timeline === null || typeof timeline !== "object") return cfg;
1266
+ const memoised = flattenMemo.get(cfg);
1267
+ if (memoised) return memoised;
1268
+ const _a = cfg, { timeline: _dropped } = _a, flat = __objRest(_a, ["timeline"]);
1269
+ if (timeline.type === "scroll" || timeline.type === "view") {
1270
+ flat.timelineSource = "scroll";
1271
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
1272
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1273
+ const scroll = __spreadValues({}, flat.scroll || {});
1274
+ scroll.kind = timeline.type;
1275
+ if (timeline.engine !== void 0) scroll.driver = timeline.engine;
1276
+ if (timeline.axis !== void 0) scroll.axis = timeline.axis;
1277
+ if (timeline.source !== void 0) scroll.source = timeline.source;
1278
+ if (timeline.subject !== void 0) scroll.subject = timeline.subject;
1279
+ if (timeline.smoothing !== void 0) scroll.smoothing = timeline.smoothing;
1280
+ if (timeline.range !== void 0) scroll.range = timeline.range;
1281
+ const pin = timeline.pin;
1282
+ if (typeof pin === "boolean") scroll.pin = pin;
1283
+ else if (pin && typeof pin === "object") {
1284
+ scroll.pin = true;
1285
+ if (pin.align !== void 0) scroll.pinAlign = pin.align;
1286
+ if (pin.top !== void 0) scroll.pinTop = pin.top;
1287
+ if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1288
+ }
1289
+ flat.scroll = scroll;
1290
+ } else {
1291
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
1292
+ if (timeline.trigger !== void 0) {
1293
+ const _b = timeline.trigger, { onFinish } = _b, restTrigger = __objRest(_b, ["onFinish"]);
1294
+ if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
1295
+ if (onFinish !== void 0) flat.resetOnFinish = onFinish === "reset";
1296
+ }
1297
+ if (timeline.delay !== void 0) flat.delay = timeline.delay;
1298
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1299
+ if (timeline.direction !== void 0) flat.direction = timeline.direction;
1300
+ if (timeline.fill !== void 0) flat.fill = timeline.fill;
1301
+ }
1302
+ flattenMemo.set(cfg, flat);
1303
+ return flat;
1304
+ }
1305
+ function nestAnimatorTimeline(cfg) {
1306
+ if (!cfg || cfg.timeline !== void 0) return cfg;
1307
+ const _a = cfg, {
1308
+ timelineSource,
1309
+ scroll,
1310
+ trigger,
1311
+ delay,
1312
+ iterations,
1313
+ direction,
1314
+ fill,
1315
+ resetOnFinish,
1316
+ duration
1317
+ } = _a, shared = __objRest(_a, [
1318
+ "timelineSource",
1319
+ "scroll",
1320
+ "trigger",
1321
+ "delay",
1322
+ "iterations",
1323
+ "direction",
1324
+ "fill",
1325
+ "resetOnFinish",
1326
+ "duration"
1327
+ ]);
1328
+ if (timelineSource === "scroll") {
1329
+ const timeline2 = { type: (scroll == null ? void 0 : scroll.kind) === "view" ? "view" : "scroll" };
1330
+ if (duration !== void 0) timeline2.duration = duration;
1331
+ if (typeof iterations === "number") timeline2.iterations = iterations;
1332
+ if (scroll) {
1333
+ if (scroll.driver !== void 0) timeline2.engine = scroll.driver;
1334
+ if (scroll.axis !== void 0) timeline2.axis = scroll.axis;
1335
+ if (scroll.source !== void 0) timeline2.source = scroll.source;
1336
+ if (scroll.subject !== void 0) timeline2.subject = scroll.subject;
1337
+ if (scroll.smoothing !== void 0) timeline2.smoothing = scroll.smoothing;
1338
+ if (scroll.range !== void 0) timeline2.range = scroll.range;
1339
+ const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinTop !== void 0 || scroll.pinDistance !== void 0;
1340
+ if (hasPinParams) {
1341
+ 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 } : {});
1342
+ } else if (scroll.pin !== void 0) {
1343
+ timeline2.pin = scroll.pin;
1344
+ }
1345
+ }
1346
+ return __spreadProps(__spreadValues({}, shared), { timeline: timeline2 });
1347
+ }
1348
+ const timeline = { type: "clock" };
1349
+ if (duration !== void 0) timeline.duration = duration;
1350
+ if (trigger !== void 0 || resetOnFinish) {
1351
+ const t = __spreadValues({}, trigger || {});
1352
+ if (resetOnFinish) t.onFinish = "reset";
1353
+ timeline.trigger = t;
1354
+ }
1355
+ if (delay !== void 0) timeline.delay = delay;
1356
+ if (iterations !== void 0) timeline.iterations = iterations;
1357
+ if (direction !== void 0) timeline.direction = direction;
1358
+ if (fill !== void 0) timeline.fill = fill;
1359
+ return Object.keys(timeline).length > 1 ? __spreadProps(__spreadValues({}, shared), { timeline }) : shared;
1204
1360
  }
1205
1361
  function getDefs(doc) {
1206
1362
  var _a;
@@ -1212,7 +1368,7 @@ function getBindings(doc) {
1212
1368
  if (!doc) return void 0;
1213
1369
  const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
1214
1370
  if (!animateById) return void 0;
1215
- return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));
1371
+ return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
1216
1372
  }
1217
1373
  function getChildren(doc) {
1218
1374
  return doc == null ? void 0 : doc.children;
@@ -1228,27 +1384,27 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
1228
1384
  // e.g. for colors
1229
1385
  px.number(),
1230
1386
  px.array(px.number()),
1231
- px.lazy(() => PxTransformPartsSchema, {}),
1387
+ // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1388
+ // all-optional transform-parts record. In default (non-strict) mode that record accepts
1389
+ // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1390
+ // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1391
+ // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1392
+ // order-independent (`some()`); only sanitize routing depends on this order.
1232
1393
  px.object({ path: px.string() }),
1233
1394
  px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1234
1395
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1235
- px.lazy(() => px.array(PxGradientStopSchema), [])
1396
+ px.lazy(() => px.array(PxGradientStopSchema), []),
1397
+ px.lazy(() => PxTransformPartsSchema, {})
1236
1398
  ]));
1237
1399
  var PxKeyframeSchema = implementsInterface()(px.object({
1238
1400
  time: px.number().optional(),
1239
- t: px.number().optional(),
1240
1401
  value: PxKeyframeValueSchema.optional(),
1241
- v: PxKeyframeValueSchema.optional(),
1242
1402
  easing: PxEasingOrRefSchema.optional(),
1243
- e: PxEasingOrRefSchema.optional(),
1244
1403
  tangentOut: px.tuple([px.number(), px.number()]).optional(),
1245
- to: px.tuple([px.number(), px.number()]).optional(),
1246
- // short alias
1247
- tangentIn: px.tuple([px.number(), px.number()]).optional(),
1248
- ti: px.tuple([px.number(), px.number()]).optional(),
1249
- // short alias
1250
- selected: px.boolean().optional()
1251
- // editor-side UI state (Player ignores it)
1404
+ tangentIn: px.tuple([px.number(), px.number()]).optional()
1405
+ // (`selected` — editor timeline-selection UI state — was REMOVED from the wire
1406
+ // (review §1.3): editor data lives under `meta`. The editor still carries it on
1407
+ // its internal COPY-PASTE payload, which never validates against this schema.)
1252
1408
  }));
1253
1409
  var PxLoopSchema = implementsInterface()(px.object({
1254
1410
  segmentCount: px.number().optional(),
@@ -1258,7 +1414,6 @@ var PxLoopSchema = implementsInterface()(px.object({
1258
1414
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1259
1415
  value: PxKeyframeValueSchema.optional(),
1260
1416
  keyframes: px.array(PxKeyframeSchema).optional(),
1261
- kfs: px.array(PxKeyframeSchema).optional(),
1262
1417
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1263
1418
  autoOrient: px.boolean().optional()
1264
1419
  }));
@@ -1286,6 +1441,11 @@ var PxElementAnimationSchema = implementsInterface()(px.union([
1286
1441
  var PxTriggerSchema = implementsInterface()(px.object({
1287
1442
  startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1288
1443
  outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1444
+ // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1445
+ // `fill`) or `'reset'` (snap back to the start state). The trigger-vocabulary home of
1446
+ // the old top-level `resetOnFinish: boolean` (read-legacy) — review §2.3: both
1447
+ // "what happens at the end" knobs now sit side by side and share one style of value.
1448
+ onFinish: px.enum(["hold", "reset"]).optional(),
1289
1449
  scrollIntoViewThreshold: px.number().optional()
1290
1450
  }));
1291
1451
  var PxGlyphSchema = implementsInterface()(px.object({
@@ -1293,8 +1453,8 @@ var PxGlyphSchema = implementsInterface()(px.object({
1293
1453
  d: px.string()
1294
1454
  }));
1295
1455
  var PxGlyphFontSchema = implementsInterface()(px.object({
1296
- fFamily: px.string(),
1297
- style: px.string(),
1456
+ fontFamily: px.string(),
1457
+ fontStyle: px.string(),
1298
1458
  ascent: px.number(),
1299
1459
  unitsPerEm: px.number(),
1300
1460
  glyphs: px.record(PxGlyphSchema)
@@ -1302,7 +1462,9 @@ var PxGlyphFontSchema = implementsInterface()(px.object({
1302
1462
  var PxDefsSchema = implementsInterface()(px.object({
1303
1463
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1304
1464
  animations: px.record(PxAnimationDefinitionSchema).optional(),
1305
- styles: px.record(px.any()).optional(),
1465
+ // Review §2.6: the schema now matches the declared type — a style preset is a flat
1466
+ // record of string|number attribute values, nothing nested.
1467
+ styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1306
1468
  glyphs: px.record(PxGlyphFontSchema).optional()
1307
1469
  }));
1308
1470
  var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
@@ -1328,22 +1490,54 @@ var PxScrollSchema = implementsInterface()(px.object({
1328
1490
  pinDistance: px.number().optional(),
1329
1491
  range: PxScrollRangeSchema.optional()
1330
1492
  }));
1331
- var PxAnimatorConfigSchema = implementsInterface()(px.object({
1332
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
1493
+ var PxTimelinePinSchema = px.object({
1494
+ align: px.enum(["top", "center", "bottom"]).optional(),
1495
+ top: px.number().optional(),
1496
+ distance: px.number().optional()
1497
+ });
1498
+ var PxClockTimelineSchema = px.object({
1499
+ type: px.literal("clock"),
1500
+ // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1333
1501
  duration: px.number().optional(),
1502
+ trigger: PxTriggerSchema.optional(),
1334
1503
  delay: px.number().optional(),
1335
- // LAW (SCHEMA-DESIGN R3, S10): the ONE sanctioned string-in-number union
1336
- // (CSS animation-iteration-count familiarity) — do not add more mixed unions.
1337
1504
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1338
1505
  fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1339
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
1506
+ direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1507
+ });
1508
+ var scrollishTimelineShape = {
1509
+ // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1510
+ // span the scroll range maps onto.
1511
+ duration: px.number().optional(),
1512
+ // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1513
+ // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1514
+ iterations: px.number().optional(),
1515
+ engine: px.enum(["custom", "native"]).optional(),
1516
+ axis: px.enum(["block", "inline", "x", "y"]).optional(),
1517
+ source: px.enum(["nearest", "root"]).optional(),
1518
+ subject: px.string().optional(),
1519
+ // 'parent' | 'scroller' | any CSS selector
1520
+ smoothing: px.number().optional(),
1521
+ // ms
1522
+ pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1523
+ range: PxScrollRangeSchema.optional()
1524
+ };
1525
+ var PxScrollTimelineSchema = px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape));
1526
+ var PxViewTimelineSchema = px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape));
1527
+ var PxTimelineSchema = px.discriminatedUnion("type", [
1528
+ PxClockTimelineSchema,
1529
+ PxScrollTimelineSchema,
1530
+ PxViewTimelineSchema
1531
+ ]);
1532
+ var PxAnimatorConfigSchema = implementsInterface()(px.object({
1533
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
1534
+ // (`duration` lives INSIDE `timeline` on the wire — §2.8; the flat field below
1535
+ // exists only on the runtime view, like the rest of the playback dynamics.)
1340
1536
  frameRate: px.number().optional(),
1341
- trigger: PxTriggerSchema.optional(),
1342
- resetOnFinish: px.boolean().optional(),
1537
+ // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1538
+ timeline: PxTimelineSchema.optional(),
1343
1539
  definitions: PxDefsSchema.optional(),
1344
1540
  animateById: px.record(PxElementAnimationSchema).optional(),
1345
- timelineSource: px.string().optional(),
1346
- scroll: PxScrollSchema.optional(),
1347
1541
  debugInstName: px.string().optional()
1348
1542
  }));
1349
1543
  var PxBindingSchema = implementsInterface()(px.object({
@@ -1362,18 +1556,18 @@ var PxAttrValueSchema = px.union([
1362
1556
  ]);
1363
1557
  var PxAnimatableNumberSchema = px.union([
1364
1558
  px.number(),
1365
- px.object({ value: px.number() }),
1366
- PxPropertyAnimationSchema
1559
+ PxPropertyAnimationSchema,
1560
+ px.object({ value: px.number() })
1367
1561
  ]);
1368
1562
  var PxAnimatableVec2Schema = px.union([
1369
1563
  px.tuple([px.number(), px.number()]),
1370
- px.object({ value: px.tuple([px.number(), px.number()]) }),
1371
- PxPropertyAnimationSchema
1564
+ PxPropertyAnimationSchema,
1565
+ px.object({ value: px.tuple([px.number(), px.number()]) })
1372
1566
  ]);
1373
1567
  var PxAnimatableStringSchema = px.union([
1374
1568
  px.string(),
1375
- px.object({ value: px.string() }),
1376
- PxPropertyAnimationSchema
1569
+ PxPropertyAnimationSchema,
1570
+ px.object({ value: px.string() })
1377
1571
  ]);
1378
1572
  var PxTransformByEffectSchema = implementsInterface()(px.object({
1379
1573
  translate: PxAnimatableVec2Schema.optional(),
@@ -1403,16 +1597,14 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1403
1597
  height: px.number().optional()
1404
1598
  }));
1405
1599
  var PxClipPathEffectSchema = implementsInterface()(px.object({
1406
- d: PxAnimatableStringSchema.optional(),
1407
- animate: PxPropertyAnimationSchema.optional()
1600
+ d: PxAnimatableStringSchema.optional()
1408
1601
  }));
1409
- var PxTrimPathEffectSchema = implementsInterface()(px.object({
1602
+ var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1410
1603
  offset: PxAnimatableNumberSchema.optional(),
1411
1604
  range: PxAnimatableVec2Schema.optional(),
1412
- subPaths: px.enum([PxTrimSubPaths.separate, PxTrimSubPaths.combined]).optional()
1605
+ subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined]).optional()
1413
1606
  }));
1414
1607
  var PxRetimeEffectSchema = implementsInterface()(px.object({
1415
- sourceId: px.string().optional(),
1416
1608
  start: px.number().optional(),
1417
1609
  stretch: px.number().optional(),
1418
1610
  timeCrop: px.tuple([px.number(), px.number()]).optional()
@@ -1435,11 +1627,11 @@ var PxAnimatableGradientStopsSchema = px.union([
1435
1627
  var PxFillGradientEffectSchema = implementsInterface()(px.object({
1436
1628
  // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1437
1629
  type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1438
- p1: PxAnimatableVec2Schema.optional(),
1439
- p2: PxAnimatableVec2Schema.optional(),
1440
- c: PxAnimatableVec2Schema.optional(),
1441
- r: PxAnimatableNumberSchema.optional(),
1442
- fp: PxAnimatableVec2Schema.optional(),
1630
+ start: PxAnimatableVec2Schema.optional(),
1631
+ end: PxAnimatableVec2Schema.optional(),
1632
+ center: PxAnimatableVec2Schema.optional(),
1633
+ radius: PxAnimatableNumberSchema.optional(),
1634
+ focal: PxAnimatableVec2Schema.optional(),
1443
1635
  stops: PxAnimatableGradientStopsSchema.optional(),
1444
1636
  gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
1445
1637
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
@@ -1463,7 +1655,7 @@ var PxEffectsSchema = implementsInterface()(px.object({
1463
1655
  repeater: PxRepeaterEffectSchema.optional(),
1464
1656
  maskedBy: PxMaskedByEffectSchema.optional(),
1465
1657
  clipPath: PxClipPathEffectSchema.optional(),
1466
- trimPath: PxTrimPathEffectSchema.optional(),
1658
+ strokeTrim: PxStrokeTrimEffectSchema.optional(),
1467
1659
  clone: PxCloneEffectSchema.optional(),
1468
1660
  fillGradient: PxFillGradientEffectSchema.optional(),
1469
1661
  strokeGradient: PxStrokeGradientEffectSchema.optional(),
@@ -1635,9 +1827,11 @@ function generateNewIds(doc) {
1635
1827
  const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
1636
1828
  if (docAnimate && typeof docAnimate === "object") {
1637
1829
  const updatedAnimate = {};
1638
- for (const [id, anim] of Object.entries(docAnimate)) {
1830
+ for (const [key, anim] of Object.entries(docAnimate)) {
1831
+ const hashed = key.startsWith("#");
1832
+ const id = hashed ? key.slice(1) : key;
1639
1833
  const newId = (_b = idMap.get(id)) != null ? _b : id;
1640
- updatedAnimate[newId] = anim;
1834
+ updatedAnimate[hashed ? "#" + newId : newId] = anim;
1641
1835
  }
1642
1836
  cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animateById: updatedAnimate });
1643
1837
  }
@@ -1730,7 +1924,7 @@ function getNormalizedProps(props) {
1730
1924
  let value = props[rawKey];
1731
1925
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1732
1926
  propsCopy[key] = toRGBA(value);
1733
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes && !value.kfs) {
1927
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
1734
1928
  const parts = value.value && typeof value.value === "object" ? value.value : value;
1735
1929
  propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
1736
1930
  } else if (TRANSFORM_FN_NAMES.has(key)) {
@@ -1770,12 +1964,12 @@ function getKfEasing(kf) {
1770
1964
  return (_a = kf.easing) != null ? _a : kf.e;
1771
1965
  }
1772
1966
  function propAnimIsMotionPath(anim) {
1773
- var _a, _b, _c;
1774
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
1967
+ var _a, _b;
1968
+ const kfs = anim.keyframes;
1775
1969
  if (!Array.isArray(kfs)) return false;
1776
1970
  if (anim.autoOrient) return true;
1777
1971
  for (const kf of kfs) {
1778
- if (((_b = kf.tangentIn) != null ? _b : kf.ti) || ((_c = kf.tangentOut) != null ? _c : kf.to)) return true;
1972
+ if (((_a = kf.tangentIn) != null ? _a : kf.ti) || ((_b = kf.tangentOut) != null ? _b : kf.to)) return true;
1779
1973
  }
1780
1974
  return false;
1781
1975
  }
@@ -1836,14 +2030,14 @@ var DEFAULT_FLATNESS_TOL = 0.5;
1836
2030
  var DEFAULT_ROTATION_TOL = 5;
1837
2031
  var DEFAULT_MAX_SAMPLES = 32;
1838
2032
  function materialiseMotionPathInPropAnim(anim, opts) {
1839
- var _a, _b, _c, _d;
2033
+ var _a, _b, _c;
1840
2034
  if (!propAnimIsMotionPath(anim)) return anim;
1841
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
2035
+ const kfs = anim.keyframes;
1842
2036
  if (!Array.isArray(kfs) || kfs.length < 2) return anim;
1843
2037
  const autoOrient = !!anim.autoOrient;
1844
- const flatnessTol = (_b = opts == null ? void 0 : opts.flatnessTolerance) != null ? _b : DEFAULT_FLATNESS_TOL;
1845
- const rotationTol = (_c = opts == null ? void 0 : opts.rotationTolerance) != null ? _c : DEFAULT_ROTATION_TOL;
1846
- const maxSamples = (_d = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _d : DEFAULT_MAX_SAMPLES;
2038
+ const flatnessTol = (_a = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a : DEFAULT_FLATNESS_TOL;
2039
+ const rotationTol = (_b = opts == null ? void 0 : opts.rotationTolerance) != null ? _b : DEFAULT_ROTATION_TOL;
2040
+ const maxSamples = (_c = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _c : DEFAULT_MAX_SAMPLES;
1847
2041
  const out = [];
1848
2042
  const firstPos = getKfTranslate(kfs[0]);
1849
2043
  if (!firstPos) return anim;
@@ -1872,7 +2066,7 @@ function materialiseMotionPathInPropAnim(anim, opts) {
1872
2066
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
1873
2067
  if (lastInE) out[out.length - 1].e = lastInE;
1874
2068
  if (autoOrient) unwrapAutoOrientRotations(out);
1875
- const result = { kfs: out };
2069
+ const result = { keyframes: out };
1876
2070
  if (anim.loop !== void 0) result.loop = anim.loop;
1877
2071
  return result;
1878
2072
  }
@@ -2534,7 +2728,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2534
2728
  }
2535
2729
  function normalizeKeyframes(propName, propAnim, duration, defs) {
2536
2730
  var _a, _b, _c, _d, _e, _f, _g;
2537
- const keyframes = propAnim.keyframes || propAnim.kfs || [];
2731
+ const keyframes = propAnim.keyframes || [];
2538
2732
  const normalized = [];
2539
2733
  for (const kf of keyframes) {
2540
2734
  const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
@@ -2579,17 +2773,16 @@ function mergeAnimationDefinitions(animations) {
2579
2773
  return merged;
2580
2774
  }
2581
2775
  function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2582
- var _a;
2583
2776
  const loopRaw = propAnim.loop;
2584
2777
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
2585
2778
  const loop = loopRaw === true ? {} : loopRaw;
2586
- const rawKfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
2779
+ const rawKfs = propAnim.keyframes;
2587
2780
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
2588
2781
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2589
2782
  const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
2590
2783
  const kfs = rawKfs.map((kf) => {
2591
- var _a2, _b, _c, _d, _e, _f, _g, _h;
2592
- const t = (_a2 = kf.t) != null ? _a2 : kf.time;
2784
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2785
+ const t = (_a = kf.t) != null ? _a : kf.time;
2593
2786
  let v = (_b = kf.v) != null ? _b : kf.value;
2594
2787
  if (propName === "d") v = normalizePathValue(v);
2595
2788
  if (isColour) v = (_c = parseColor(v)) != null ? _c : v;
@@ -2600,7 +2793,7 @@ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2600
2793
  return out2;
2601
2794
  });
2602
2795
  const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
2603
- const out = { kfs: expanded };
2796
+ const out = { keyframes: expanded };
2604
2797
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2605
2798
  return out;
2606
2799
  }
@@ -2642,6 +2835,36 @@ var _elementIdCounter = 0;
2642
2835
  function generateElementId() {
2643
2836
  return "_px_el_" + ++_elementIdCounter;
2644
2837
  }
2838
+ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
2839
+ if (!animDef) return animDef;
2840
+ const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
2841
+ if (!staticParts || !Object.keys(staticParts).length) return animDef;
2842
+ const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
2843
+ const transformAnim = animDef["transform"];
2844
+ if (transformAnim && typeof transformAnim === "object") {
2845
+ const anim = transformAnim;
2846
+ if (Array.isArray(anim.keyframes)) {
2847
+ const out = __spreadProps(__spreadValues({}, anim), {
2848
+ keyframes: anim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: mergeKfValue(kf.value) }))
2849
+ });
2850
+ if (out.value !== void 0) out.value = mergeKfValue(out.value);
2851
+ return __spreadProps(__spreadValues({}, animDef), { transform: out });
2852
+ }
2853
+ return animDef;
2854
+ }
2855
+ const channels = Object.keys(animDef).filter((k) => TRANSFORM_FN_NAMES.has(k));
2856
+ if (channels.length !== 1) return animDef;
2857
+ const ch = channels[0];
2858
+ const chAnim = animDef[ch];
2859
+ if (!chAnim || typeof chAnim !== "object" || !Array.isArray(chAnim.keyframes)) return animDef;
2860
+ const lifted = __spreadProps(__spreadValues({}, chAnim), {
2861
+ keyframes: chAnim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: __spreadProps(__spreadValues({}, staticParts), { [ch]: kf.value }) }))
2862
+ });
2863
+ if (lifted.value !== void 0) lifted.value = __spreadProps(__spreadValues({}, staticParts), { [ch]: lifted.value });
2864
+ const rest = __spreadValues({}, animDef);
2865
+ delete rest[ch];
2866
+ return __spreadProps(__spreadValues({}, rest), { transform: lifted });
2867
+ }
2645
2868
  function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2646
2869
  const normalized = {};
2647
2870
  for (const [propName, propAnim] of Object.entries(animDef)) {
@@ -2650,7 +2873,7 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimat
2650
2873
  }
2651
2874
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2652
2875
  if (normalizedKfs.length > 0) {
2653
- const out = { kfs: normalizedKfs };
2876
+ const out = { keyframes: normalizedKfs };
2654
2877
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2655
2878
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2656
2879
  normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
@@ -2663,11 +2886,11 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2663
2886
  const defs = getDefs(doc);
2664
2887
  const duration = animatorConfig.duration || 1e3;
2665
2888
  const bindings = [];
2666
- const processAnimation = (id, animate) => {
2889
+ const processAnimation = (id, animate, staticTransform) => {
2667
2890
  if (!animate) return null;
2668
2891
  const animDefs = resolveElementAnimation(animate, defs);
2669
2892
  if (animDefs.length === 0) return null;
2670
- const merged = mergeAnimationDefinitions(animDefs);
2893
+ const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);
2671
2894
  const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
2672
2895
  if (Object.keys(normalizedAnim).length === 0) return null;
2673
2896
  return {
@@ -2687,7 +2910,7 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2687
2910
  if (inlineAnim && Object.keys(inlineAnim).length > 0) {
2688
2911
  const nodeId = node.id || generateElementId();
2689
2912
  node.id = nodeId;
2690
- const normalized = processAnimation(nodeId, inlineAnim);
2913
+ const normalized = processAnimation(nodeId, inlineAnim, node.transform);
2691
2914
  if (normalized) bindings.push(normalized);
2692
2915
  }
2693
2916
  if (node.children) {
@@ -2725,7 +2948,7 @@ function getKeyframesPair(keyframes, progress) {
2725
2948
  }
2726
2949
  function calcPropertyValue(propName, propAnim, progress) {
2727
2950
  var _a, _b, _c, _d, _e, _f, _g;
2728
- const keyframes = propAnim.kfs || propAnim.keyframes || [];
2951
+ const keyframes = propAnim.keyframes || [];
2729
2952
  if (keyframes.length === 0) return null;
2730
2953
  const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
2731
2954
  let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
@@ -3349,7 +3572,7 @@ function liftBodyTranslate(node, transformBy) {
3349
3572
  if (split.rest) node.transform = split.rest;
3350
3573
  else delete node.transform;
3351
3574
  }
3352
- } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes && !node.transform.kfs) {
3575
+ } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes) {
3353
3576
  const wrapped = node.transform.value;
3354
3577
  const isWrapped = !!(wrapped && typeof wrapped === "object");
3355
3578
  const value = isWrapped ? wrapped : node.transform;
@@ -3484,12 +3707,12 @@ function synthesiseGradientDef(fx, id, ctx) {
3484
3707
  id
3485
3708
  };
3486
3709
  if (fx.type === PxGradientType.linear) {
3487
- applyGeomVec(out, "x1", "y1", fx.p1);
3488
- applyGeomVec(out, "x2", "y2", fx.p2);
3710
+ applyGeomVec(out, "x1", "y1", fx.start);
3711
+ applyGeomVec(out, "x2", "y2", fx.end);
3489
3712
  } else {
3490
- applyGeomVec(out, "cx", "cy", fx.c);
3491
- applyGeomNumber(out, "r", fx.r);
3492
- applyGeomVec(out, "fx", "fy", fx.fp);
3713
+ applyGeomVec(out, "cx", "cy", fx.center);
3714
+ applyGeomNumber(out, "r", fx.radius);
3715
+ applyGeomVec(out, "fx", "fy", fx.focal);
3493
3716
  }
3494
3717
  if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
3495
3718
  if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
@@ -3617,8 +3840,7 @@ function formatOffset(o) {
3617
3840
 
3618
3841
  // src/effects/clipPathEffect.ts
3619
3842
  function applyClipPathEffect(node, fx, ctx) {
3620
- var _a, _b;
3621
- if (!fx || !fx.d && !fx.animate) return node;
3843
+ if (!(fx == null ? void 0 : fx.d)) return node;
3622
3844
  const clipId = genId(ctx, "clip");
3623
3845
  const pathChild = { type: "path" };
3624
3846
  const read = readAnimatable(fx.d);
@@ -3630,11 +3852,6 @@ function applyClipPathEffect(node, fx, ctx) {
3630
3852
  if (pathChild.d !== void 0) pathChild.d = pathString(pathChild.d);
3631
3853
  }
3632
3854
  }
3633
- if (fx.animate && !((_a = pathChild.animate) == null ? void 0 : _a.d)) {
3634
- const animate = (_b = pathChild.animate) != null ? _b : {};
3635
- animate.d = fx.animate;
3636
- pathChild.animate = animate;
3637
- }
3638
3855
  ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
3639
3856
  node.clipPath = "url(#" + clipId + ")";
3640
3857
  return node;
@@ -3779,7 +3996,7 @@ function readTransformationFromBody(node) {
3779
3996
  if (parts.origin) out.origin = parts.origin;
3780
3997
  return Object.keys(out).length ? out : void 0;
3781
3998
  }
3782
- if (node.transform && typeof node.transform === "object" && !node.transform.keyframes && !node.transform.kfs) {
3999
+ if (node.transform && typeof node.transform === "object" && !node.transform.keyframes) {
3783
4000
  const wrapped = node.transform.value;
3784
4001
  const value = wrapped && typeof wrapped === "object" ? wrapped : node.transform;
3785
4002
  if (value && typeof value === "object") {
@@ -5135,10 +5352,10 @@ function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pat
5135
5352
  return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5136
5353
  }
5137
5354
 
5138
- // src/effects/trimPathEffect.ts
5139
- function applyTrimPathEffect(node, trimPath, ctx) {
5140
- if (!trimPath) return node;
5141
- const combined = trimPath.subPaths === PxTrimSubPaths.combined;
5355
+ // src/effects/strokeTrimEffect.ts
5356
+ function applyStrokeTrimEffect(node, strokeTrim, ctx) {
5357
+ if (!strokeTrim) return node;
5358
+ const combined = strokeTrim.subPaths === PxStrokeTrimSubPaths.combined;
5142
5359
  const leafEntries = [];
5143
5360
  const measure = (n) => {
5144
5361
  if (Array.isArray(n.children) && n.children.length > 0) {
@@ -5169,9 +5386,9 @@ function applyTrimPathEffect(node, trimPath, ctx) {
5169
5386
  }
5170
5387
  const chainLengthPx = acc;
5171
5388
  if (combined && chainLengthPx < 1e-3) return node;
5172
- const offsetReadRaw = readAnimatable(trimPath.offset);
5389
+ const offsetReadRaw = readAnimatable(strokeTrim.offset);
5173
5390
  const offsetRead = offsetReadRaw.kind === "absent" /* Absent */ ? { kind: "static" /* Static */, value: 0 } : offsetReadRaw;
5174
- const rangeReadRaw = readRangeWithCrossings(trimPath.range);
5391
+ const rangeReadRaw = readRangeWithCrossings(strokeTrim.range);
5175
5392
  const rangeRead = rangeReadRaw.kind === "absent" /* Absent */ ? { kind: "static" /* Static */, value: [0, 1] } : rangeReadRaw;
5176
5393
  const offsetValues = readScalarValues(offsetRead);
5177
5394
  const minOffset = offsetValues.length ? Math.min(...offsetValues) : 0;
@@ -5503,7 +5720,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5503
5720
  const originalId = typeof node.id === "string" ? node.id : void 0;
5504
5721
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
5505
5722
  if (!fx && !innerIdForContentRef) return node;
5506
- const { transformBy, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5723
+ const { transformBy, repeater, maskedBy, clipPath, strokeTrim, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
5507
5724
  if (fx) delete node.effects;
5508
5725
  let n = node;
5509
5726
  let consumedByGlyphs = false;
@@ -5523,7 +5740,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
5523
5740
  if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
5524
5741
  n = applyFillGradientEffect(n, fillGradient, ctx);
5525
5742
  n = applyStrokeGradientEffect(n, strokeGradient, ctx);
5526
- n = applyTrimPathEffect(n, trimPath, ctx);
5743
+ n = applyStrokeTrimEffect(n, strokeTrim, ctx);
5527
5744
  n = applyRepeaterEffect(n, repeater, ctx);
5528
5745
  n = applyMaskedByEffect(n, maskedBy, transformBy, ctx);
5529
5746
  n = applyClipPathEffect(n, clipPath, ctx);
@@ -5586,9 +5803,9 @@ var fmt2 = (n) => {
5586
5803
  return Object.is(r, -0) ? "0" : String(r);
5587
5804
  };
5588
5805
  function buildOffsetPath(propAnim) {
5589
- var _a, _b, _c, _d;
5806
+ var _a, _b, _c;
5590
5807
  if (propAnim.alongPathMode !== "offsetPath") return void 0;
5591
- const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
5808
+ const kfs = propAnim.keyframes;
5592
5809
  if (!kfs || kfs.length < 2) return void 0;
5593
5810
  const first = kfValue(kfs[0]);
5594
5811
  const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
@@ -5599,7 +5816,7 @@ function buildOffsetPath(propAnim) {
5599
5816
  if (!tr || tr.length < 2) return void 0;
5600
5817
  const parts = Object.keys(v);
5601
5818
  if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5602
- const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
5819
+ const o = (_a = v == null ? void 0 : v.origin) != null ? _a : [0, 0];
5603
5820
  if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5604
5821
  points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5605
5822
  }
@@ -5608,8 +5825,8 @@ function buildOffsetPath(propAnim) {
5608
5825
  const segLens = [];
5609
5826
  for (let i = 0; i < points.length - 1; i++) {
5610
5827
  const p0 = points[i], p1 = points[i + 1];
5611
- const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
5612
- const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
5828
+ const to = (_b = kfTangentOut(kfs[i])) != null ? _b : [0, 0];
5829
+ const ti = (_c = kfTangentIn(kfs[i + 1])) != null ? _c : [0, 0];
5613
5830
  const c1 = [p0[0] + to[0], p0[1] + to[1]];
5614
5831
  const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
5615
5832
  d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
@@ -6247,15 +6464,17 @@ function subtractMultiset(a, b) {
6247
6464
  PxScrollRangeSchema,
6248
6465
  PxScrollSchema,
6249
6466
  PxStrokeGradientEffectSchema,
6467
+ PxStrokeTrimEffectSchema,
6468
+ PxStrokeTrimSubPaths,
6250
6469
  PxSvgNodeExtra,
6251
6470
  PxTextEffectSchema,
6252
6471
  PxTextPathEffectSchema,
6472
+ PxTimelinePinSchema,
6473
+ PxTimelineSchema,
6253
6474
  PxTransformByEffectSchema,
6254
6475
  PxTransformPartsSchema,
6255
6476
  PxTransformValueSchema,
6256
6477
  PxTriggerSchema,
6257
- PxTrimPathEffectSchema,
6258
- PxTrimSubPaths,
6259
6478
  STYLE_ATTR_NAMES,
6260
6479
  TEXT_ATTR,
6261
6480
  TEXT_CONTENT_ATTR,
@@ -6275,6 +6494,7 @@ function subtractMultiset(a, b) {
6275
6494
  diffInEffect,
6276
6495
  evaluateMotionPathSegment,
6277
6496
  extendedPathForBrowser,
6497
+ flattenAnimatorTimeline,
6278
6498
  generateNewIds,
6279
6499
  generateUniqueId,
6280
6500
  getAnimatorConfig,
@@ -6300,6 +6520,9 @@ function subtractMultiset(a, b) {
6300
6520
  materialiseInternalLoopsInTree,
6301
6521
  materialiseMotionPathInPropAnim,
6302
6522
  materialiseMotionPathsInTree,
6523
+ mergeStaticTransformIntoAnimDef,
6524
+ nestAnimatorTimeline,
6525
+ parseTransformParts,
6303
6526
  propAnimIsMotionPath,
6304
6527
  px,
6305
6528
  resolveStyle,