@pixodesk/svg-animator-web 1.0.34 → 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,16 +54,17 @@ var PixodeskAnimator = (() => {
54
54
  PX_ANIMATOR_DATA_KEY: () => PX_ANIMATOR_DATA_KEY,
55
55
  PX_ANIM_ATTR_NAME: () => PX_ANIM_ATTR_NAME,
56
56
  PX_ANIM_SRC_ATTR_NAME: () => PX_ANIM_SRC_ATTR_NAME,
57
- PxAnimatorEngine: () => PxAnimatorEngine,
58
- PxAnimatorMode: () => PxAnimatorMode,
57
+ PxTimelineEngine: () => PxTimelineEngine,
58
+ PxTimelineEngineExtra: () => PxTimelineEngineExtra,
59
59
  createAnimator: () => createAnimator,
60
60
  createAnimatorImpl: () => createAnimatorImpl,
61
61
  generateNewIds: () => generateNewIds,
62
62
  loadTagAnimators: () => loadTagAnimators,
63
- setupAnimationTriggers: () => setupAnimationTriggers
63
+ setupAnimationTriggers: () => setupAnimationTriggers,
64
+ validateDocument: () => validateDocument
64
65
  });
65
66
 
66
- // ../svg-animator-core/src/PxAnimatorUtil.ts
67
+ // ../svg-animator-core/src/util/PxAnimatorUtil.ts
67
68
  function bezierToSvgPath(path, forceCurves = false) {
68
69
  var _a, _b, _c, _d;
69
70
  const v = path.v;
@@ -511,7 +512,7 @@ var PixodeskAnimator = (() => {
511
512
  return cubicBezier(flipped);
512
513
  }
513
514
 
514
- // ../svg-animator-core/src/PxScrollMath.ts
515
+ // ../svg-animator-core/src/playback/PxScrollMath.ts
515
516
  function isScrollTimeline(config) {
516
517
  return (config == null ? void 0 : config.timelineSource) === "scroll";
517
518
  }
@@ -567,7 +568,8 @@ var PixodeskAnimator = (() => {
567
568
  return vertical ? "x" : "y";
568
569
  }
569
570
 
570
- // ../svg-animator-core/src/PxSchema.ts
571
+ // ../svg-animator-core/src/schema/PxSchema.ts
572
+ var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
571
573
  function pathStr(path) {
572
574
  if (!path.length) return ".";
573
575
  let result = "";
@@ -702,6 +704,7 @@ var PixodeskAnimator = (() => {
702
704
  };
703
705
  var DiscriminatedUnion = class extends Base {
704
706
  constructor(_key, _schemas, defaultVal) {
707
+ var _a;
705
708
  super();
706
709
  this._key = _key;
707
710
  this._schemas = _schemas;
@@ -711,13 +714,16 @@ var PixodeskAnimator = (() => {
711
714
  this._map = /* @__PURE__ */ new Map();
712
715
  for (const s of _schemas) {
713
716
  const keySchema = s._shape[_key];
714
- if (keySchema) this._map.set(keySchema._default, s);
717
+ if (!keySchema) continue;
718
+ const literal = (_a = keySchema.inner) != null ? _a : keySchema;
719
+ this._map.set(literal._default, s);
720
+ if (keySchema.inner) this._absentMember = s;
715
721
  }
716
722
  }
717
723
  _findSchema(raw) {
718
724
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
719
725
  const val = raw[this._key];
720
- if (val === void 0 || val === null) return void 0;
726
+ if (val === void 0 || val === null) return this._absentMember;
721
727
  return this._map.get(val);
722
728
  }
723
729
  sanitize(raw) {
@@ -751,7 +757,8 @@ var PixodeskAnimator = (() => {
751
757
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
752
758
  const out = {};
753
759
  for (const key of Object.keys(this._shape)) {
754
- out[key] = this._shape[key].sanitize(src[key]);
760
+ const v = this._shape[key].sanitize(src[key]);
761
+ if (v !== void 0) out[key] = v;
755
762
  }
756
763
  return out;
757
764
  }
@@ -773,7 +780,7 @@ var PixodeskAnimator = (() => {
773
780
  if (key in this._shape) continue;
774
781
  if (obj[key] === void 0) continue;
775
782
  p.push(key);
776
- ctx.errors.push(pathStr(p) + ": unexpected extra key");
783
+ ctx.errors.push(pathStr(p) + ": " + PX_UNKNOWN_KEY_ERROR);
777
784
  p.pop();
778
785
  ok = false;
779
786
  }
@@ -797,7 +804,8 @@ var PixodeskAnimator = (() => {
797
804
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
798
805
  const out = __spreadValues({}, src);
799
806
  for (const key of Object.keys(this._shape)) {
800
- out[key] = this._shape[key].sanitize(src[key]);
807
+ const v = this._shape[key].sanitize(src[key]);
808
+ if (v !== void 0) out[key] = v;
801
809
  }
802
810
  if (this._openSchema) {
803
811
  for (const key of Object.keys(src)) {
@@ -1038,25 +1046,40 @@ var PixodeskAnimator = (() => {
1038
1046
  lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
1039
1047
  };
1040
1048
 
1041
- // ../svg-animator-core/src/PxAnimatorConstants.ts
1049
+ // ../svg-animator-core/src/format/PxAnimatorConstants.ts
1042
1050
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1043
1051
  var PX_ANIM_ATTR_NAME = "_px_animator";
1044
- var PxAnimatorMode = {
1045
- auto: "auto",
1046
- waapi: "waapi",
1047
- frames: "frames"
1052
+ var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
1053
+ var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
1054
+ var PxTimelineEngine = {
1055
+ native: "native",
1056
+ js: "js"
1048
1057
  };
1049
- var PxAnimatorEngine = {
1050
- waapi: PxAnimatorMode.waapi,
1051
- frames: PxAnimatorMode.frames
1058
+ var PxTimelineEngineExtra = __spreadProps(__spreadValues({}, PxTimelineEngine), {
1059
+ auto: "auto"
1060
+ });
1061
+ function resolveTimelineEngine(engine) {
1062
+ return engine === PxTimelineEngineExtra.js ? PxTimelineEngine.js : PxTimelineEngine.native;
1063
+ }
1064
+ function isNativeForced(engine) {
1065
+ return engine === PxTimelineEngineExtra.native;
1066
+ }
1067
+ function mayUseNativeScrollTimeline(engine) {
1068
+ return engine !== PxTimelineEngineExtra.js;
1069
+ }
1070
+ var PxLoopRepeatAt = {
1071
+ /** Segment from the START; the repetition runs BEFORE the first keyframe
1072
+ * (intro loops that play until the main timeline begins). */
1073
+ start: "start",
1074
+ /** DEFAULT — segment from the END; the repetition runs AFTER the last keyframe
1075
+ * (idle/outro loops that continue once the main timeline has finished). */
1076
+ end: "end"
1052
1077
  };
1053
- var PxLoopExtend = {
1054
- /** Segment from the START; the animation is extended BEFORE the first keyframe
1055
- * (intro loops that run before the main timeline begins). */
1056
- before: "before",
1057
- /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
1058
- * loops that continue once the main timeline has finished). */
1059
- after: "after"
1078
+ var PxLoopDirection = {
1079
+ /** DEFAULT — cycle: every repetition replays the segment the same way round. */
1080
+ normal: "normal",
1081
+ /** Ping-pong: repetitions alternate forward / backward. */
1082
+ alternate: "alternate"
1060
1083
  };
1061
1084
  var PxMaskType = {
1062
1085
  luminance: "luminance",
@@ -1066,8 +1089,9 @@ var PixodeskAnimator = (() => {
1066
1089
  userSpaceOnUse: "userSpaceOnUse",
1067
1090
  objectBoundingBox: "objectBoundingBox"
1068
1091
  };
1069
- var PxCloneType = {
1070
- content: "content"
1092
+ var PxCloneWithout = {
1093
+ translate: "translate"
1094
+ // transform: 'transform', // future: drop rotate/scale too (content only)
1071
1095
  };
1072
1096
  var PxPathOverflow = {
1073
1097
  clip: "clip",
@@ -1091,6 +1115,9 @@ var PixodeskAnimator = (() => {
1091
1115
  };
1092
1116
  var TEXT_ATTR = "text";
1093
1117
  var TEXT_CONTENT_ATTR = "textContent";
1118
+ var CLASS_ATTR = "class";
1119
+ var TRANSFORM_ATTR = "transform";
1120
+ var OFFSET_DISTANCE_ATTR = "offsetDistance";
1094
1121
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1095
1122
  "type",
1096
1123
  "children",
@@ -1101,6 +1128,18 @@ var PixodeskAnimator = (() => {
1101
1128
  TEXT_ATTR,
1102
1129
  TEXT_CONTENT_ATTR
1103
1130
  ]);
1131
+ var TRANSFORM_PART = {
1132
+ translate: "translate",
1133
+ rotate: "rotate",
1134
+ scale: "scale",
1135
+ origin: "origin"
1136
+ };
1137
+ var PX_TRANSFORM_PART_KEYS = [
1138
+ TRANSFORM_PART.translate,
1139
+ TRANSFORM_PART.rotate,
1140
+ TRANSFORM_PART.scale,
1141
+ TRANSFORM_PART.origin
1142
+ ];
1104
1143
  var PxGradientUnits = {
1105
1144
  userSpaceOnUse: "userSpaceOnUse",
1106
1145
  objectBoundingBox: "objectBoundingBox"
@@ -1118,7 +1157,7 @@ var PixodeskAnimator = (() => {
1118
1157
  if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
1119
1158
  return false;
1120
1159
  }
1121
- return fileJson["type"] === "svg";
1160
+ return fileJson.type === "svg";
1122
1161
  }
1123
1162
  function getAnimatorConfig(doc) {
1124
1163
  var _a;
@@ -1132,13 +1171,14 @@ var PixodeskAnimator = (() => {
1132
1171
  const memoised = flattenMemo.get(cfg);
1133
1172
  if (memoised) return memoised;
1134
1173
  const _a = cfg, { timeline: _dropped } = _a, flat = __objRest(_a, ["timeline"]);
1174
+ if (timeline.engine !== void 0) flat.engine = timeline.engine;
1175
+ if (timeline.frameRate !== void 0) flat.frameRate = timeline.frameRate;
1135
1176
  if (timeline.type === "scroll" || timeline.type === "view") {
1136
1177
  flat.timelineSource = "scroll";
1137
1178
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
1138
1179
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1139
1180
  const scroll = __spreadValues({}, flat.scroll || {});
1140
1181
  scroll.kind = timeline.type;
1141
- if (timeline.engine !== void 0) scroll.driver = timeline.engine;
1142
1182
  if (timeline.axis !== void 0) scroll.axis = timeline.axis;
1143
1183
  if (timeline.source !== void 0) scroll.source = timeline.source;
1144
1184
  if (timeline.subject !== void 0) scroll.subject = timeline.subject;
@@ -1156,14 +1196,14 @@ var PixodeskAnimator = (() => {
1156
1196
  } else {
1157
1197
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
1158
1198
  if (timeline.trigger !== void 0) {
1159
- const _b = timeline.trigger, { onFinish } = _b, restTrigger = __objRest(_b, ["onFinish"]);
1199
+ const _b = timeline.trigger, { finishAction } = _b, restTrigger = __objRest(_b, ["finishAction"]);
1160
1200
  if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
1161
- if (onFinish !== void 0) flat.resetOnFinish = onFinish === "reset";
1201
+ if (finishAction !== void 0) flat.resetOnFinish = finishAction === "reset";
1162
1202
  }
1163
1203
  if (timeline.delay !== void 0) flat.delay = timeline.delay;
1164
1204
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1165
1205
  if (timeline.direction !== void 0) flat.direction = timeline.direction;
1166
- if (timeline.fill !== void 0) flat.fill = timeline.fill;
1206
+ if (timeline.fillMode !== void 0) flat.fill = timeline.fillMode;
1167
1207
  }
1168
1208
  flattenMemo.set(cfg, flat);
1169
1209
  return flat;
@@ -1181,7 +1221,7 @@ var PixodeskAnimator = (() => {
1181
1221
  return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
1182
1222
  }
1183
1223
 
1184
- // ../svg-animator-core/src/PxAnimatorTypes.ts
1224
+ // ../svg-animator-core/src/format/PxAnimatorTypes.ts
1185
1225
  var PxEasingOrRefSchema = px.union([
1186
1226
  px.string(),
1187
1227
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -1213,16 +1253,32 @@ var PixodeskAnimator = (() => {
1213
1253
  // (review §1.3): editor data lives under `meta`. The editor still carries it on
1214
1254
  // its internal COPY-PASTE payload, which never validates against this schema.)
1215
1255
  }));
1256
+ var anyKf = (kf) => kf;
1257
+ var kfTime = (kf) => {
1258
+ var _a, _b;
1259
+ return (_b = (_a = anyKf(kf).time) != null ? _a : anyKf(kf).t) != null ? _b : 0;
1260
+ };
1261
+ var kfValue = (kf) => {
1262
+ var _a;
1263
+ return (_a = anyKf(kf).value) != null ? _a : anyKf(kf).v;
1264
+ };
1265
+ var kfEasing = (kf) => {
1266
+ var _a;
1267
+ return (_a = anyKf(kf).easing) != null ? _a : anyKf(kf).e;
1268
+ };
1269
+ var kfTangentIn = (kf) => anyKf(kf).tangentIn;
1270
+ var kfTangentOut = (kf) => anyKf(kf).tangentOut;
1216
1271
  var PxLoopSchema = implementsInterface()(px.object({
1217
1272
  segmentCount: px.number().optional(),
1218
- extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
1219
- alternate: px.boolean().optional()
1273
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1274
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1220
1275
  }));
1221
1276
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1222
1277
  value: PxKeyframeValueSchema.optional(),
1223
1278
  keyframes: px.array(PxKeyframeSchema).optional(),
1224
1279
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1225
- autoOrient: px.boolean().optional()
1280
+ autoOrient: px.boolean().optional(),
1281
+ alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
1226
1282
  }));
1227
1283
  var PxTransformPartsSchema = implementsInterface()(px.object({
1228
1284
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1249,10 +1305,9 @@ var PixodeskAnimator = (() => {
1249
1305
  startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1250
1306
  outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1251
1307
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1252
- // `fill`) or `'reset'` (snap back to the start state). The trigger-vocabulary home of
1253
- // the old top-level `resetOnFinish: boolean` (read-legacy) — review §2.3: both
1254
- // "what happens at the end" knobs now sit side by side and share one style of value.
1255
- onFinish: px.enum(["hold", "reset"]).optional(),
1308
+ // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1309
+ // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1310
+ finishAction: px.enum(["hold", "reset"]).optional(),
1256
1311
  scrollIntoViewThreshold: px.number().optional()
1257
1312
  }));
1258
1313
  var PxGlyphSchema = implementsInterface()(px.object({
@@ -1272,7 +1327,7 @@ var PixodeskAnimator = (() => {
1272
1327
  // Review §2.6: the schema now matches the declared type — a style preset is a flat
1273
1328
  // record of string|number attribute values, nothing nested.
1274
1329
  styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1275
- glyphs: px.record(PxGlyphFontSchema).optional()
1330
+ fonts: px.record(PxGlyphFontSchema).optional()
1276
1331
  }));
1277
1332
  var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1278
1333
  var PxScrollRangePointSchema = implementsInterface()(px.object({
@@ -1284,7 +1339,6 @@ var PixodeskAnimator = (() => {
1284
1339
  end: PxScrollRangePointSchema.optional()
1285
1340
  });
1286
1341
  var PxScrollSchema = implementsInterface()(px.object({
1287
- driver: px.enum(["custom", "native"]).optional(),
1288
1342
  kind: px.enum(["view", "scroll"]).optional(),
1289
1343
  axis: px.enum(["block", "inline", "x", "y"]).optional(),
1290
1344
  source: px.enum(["nearest", "root"]).optional(),
@@ -1297,21 +1351,26 @@ var PixodeskAnimator = (() => {
1297
1351
  pinDistance: px.number().optional(),
1298
1352
  range: PxScrollRangeSchema.optional()
1299
1353
  }));
1300
- var PxTimelinePinSchema = px.object({
1354
+ var PxTimelinePinSchema = implementsInterface()(px.object({
1301
1355
  align: px.enum(["top", "center", "bottom"]).optional(),
1302
1356
  top: px.number().optional(),
1303
1357
  distance: px.number().optional()
1304
- });
1305
- var PxClockTimelineSchema = px.object({
1306
- type: px.literal("clock"),
1358
+ }));
1359
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
1360
+ var PxTimeTimelineSchema = implementsInterface()(px.object({
1361
+ type: px.literal("time").optional(),
1362
+ engine: PxTimelineEngineSchema,
1363
+ frameRate: px.number().optional(),
1307
1364
  // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1308
1365
  duration: px.number().optional(),
1309
1366
  trigger: PxTriggerSchema.optional(),
1310
1367
  delay: px.number().optional(),
1311
1368
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1312
- fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1369
+ // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1370
+ // — never `fill`, which is paint everywhere else in the format.
1371
+ fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1313
1372
  direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1314
- });
1373
+ }));
1315
1374
  var scrollishTimelineShape = {
1316
1375
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1317
1376
  // span the scroll range maps onto.
@@ -1319,7 +1378,8 @@ var PixodeskAnimator = (() => {
1319
1378
  // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1320
1379
  // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1321
1380
  iterations: px.number().optional(),
1322
- engine: px.enum(["custom", "native"]).optional(),
1381
+ engine: PxTimelineEngineSchema,
1382
+ frameRate: px.number().optional(),
1323
1383
  axis: px.enum(["block", "inline", "x", "y"]).optional(),
1324
1384
  source: px.enum(["nearest", "root"]).optional(),
1325
1385
  subject: px.string().optional(),
@@ -1329,23 +1389,29 @@ var PixodeskAnimator = (() => {
1329
1389
  pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1330
1390
  range: PxScrollRangeSchema.optional()
1331
1391
  };
1332
- var PxScrollTimelineSchema = px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape));
1333
- var PxViewTimelineSchema = px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape));
1392
+ var PxScrollTimelineSchema = implementsInterface()(
1393
+ px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape))
1394
+ );
1395
+ var PxViewTimelineSchema = implementsInterface()(
1396
+ px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape))
1397
+ );
1334
1398
  var PxTimelineSchema = px.discriminatedUnion("type", [
1335
- PxClockTimelineSchema,
1399
+ PxTimeTimelineSchema,
1400
+ // first = the member an absent `type` selects
1336
1401
  PxScrollTimelineSchema,
1337
1402
  PxViewTimelineSchema
1338
1403
  ]);
1339
1404
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
1340
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
1341
- // (`duration` lives INSIDE `timeline` on the wire — §2.8; the flat field below
1342
- // exists only on the runtime view, like the rest of the playback dynamics.)
1343
- frameRate: px.number().optional(),
1405
+ // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1406
+ // at this level only on the runtime view, like the rest of the playback dynamics.)
1344
1407
  // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1345
1408
  timeline: PxTimelineSchema.optional(),
1346
1409
  definitions: PxDefsSchema.optional(),
1347
1410
  animateById: px.record(PxElementAnimationSchema).optional(),
1348
- debugInstName: px.string().optional()
1411
+ debugGlobalName: px.string().optional(),
1412
+ // Declared HERE because this is a closed object: an undeclared key would be stripped by
1413
+ // `sanitize` and flagged by strict validation on our own files.
1414
+ version: px.string().optional()
1349
1415
  }));
1350
1416
  var PxBindingSchema = implementsInterface()(px.object({
1351
1417
  id: px.string(),
@@ -1394,7 +1460,7 @@ var PixodeskAnimator = (() => {
1394
1460
  origin: PxAnimatableVec2Schema.optional()
1395
1461
  }));
1396
1462
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
1397
- sourceId: px.string().optional(),
1463
+ source: px.string().optional(),
1398
1464
  maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1399
1465
  maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1400
1466
  maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
@@ -1417,9 +1483,10 @@ var PixodeskAnimator = (() => {
1417
1483
  timeCrop: px.tuple([px.number(), px.number()]).optional()
1418
1484
  }));
1419
1485
  var PxCloneEffectSchema = implementsInterface()(px.object({
1420
- // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1421
- type: px.enum([PxCloneType.content]).optional(),
1422
- sourceId: px.string().optional(),
1486
+ // Subtractive on purpose: the `<use>` can only point at one wrapper layer of the
1487
+ // source, so the choices form a ladder — 'translate' now, maybe 'transform' later.
1488
+ without: px.enum([PxCloneWithout.translate]).optional(),
1489
+ source: px.string().optional(),
1423
1490
  retime: PxRetimeEffectSchema.optional()
1424
1491
  }));
1425
1492
  var PxGradientStopSchema = implementsInterface()(px.object({
@@ -1446,7 +1513,7 @@ var PixodeskAnimator = (() => {
1446
1513
  }));
1447
1514
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1448
1515
  var PxTextPathEffectSchema = implementsInterface()(px.object({
1449
- path: px.string(),
1516
+ pathData: px.string(),
1450
1517
  pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1451
1518
  lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1452
1519
  method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
@@ -1486,16 +1553,33 @@ var PixodeskAnimator = (() => {
1486
1553
  walk(root, "root");
1487
1554
  return warnings;
1488
1555
  }
1556
+ function validateDocument(doc) {
1557
+ const ctx = { errors: [], warnings: [], strict: true };
1558
+ const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
1559
+ if (doc && typeof doc === "object") {
1560
+ for (const w of validateNodeEffects(doc, { strict: true })) {
1561
+ if (!problems.includes(w)) problems.push(w);
1562
+ }
1563
+ }
1564
+ return problems;
1565
+ }
1489
1566
  var PxNodeBase = px.openObject({
1490
1567
  // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1491
1568
  // kind of thing is this", discriminated by its CARRIER — here the node TAG
1492
- // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
1569
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1493
1570
  // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1494
1571
  // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1495
1572
  // would add words that all mean "type" and still need the carrier to read.
1496
1573
  // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1497
1574
  // (issues V3), never of distinct key names.
1498
1575
  type: px.string(),
1576
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
1577
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
1578
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
1579
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
1580
+ // documented — because a wire key that is not in a schema is invisible to the
1581
+ // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1582
+ domType: px.string().optional(),
1499
1583
  id: px.string().optional(),
1500
1584
  meta: px.any().optional(),
1501
1585
  // Player-effects bucket emitted by the Editor's lightweight design format.
@@ -1531,7 +1615,7 @@ var PixodeskAnimator = (() => {
1531
1615
  c: px.boolean().optional()
1532
1616
  }));
1533
1617
 
1534
- // ../svg-animator-core/src/PxIdUtil.ts
1618
+ // ../svg-animator-core/src/util/PxIdUtil.ts
1535
1619
  var _idCounter = 0;
1536
1620
  function generateUniqueId() {
1537
1621
  const timestamp = Date.now().toString(36);
@@ -1568,7 +1652,8 @@ var PixodeskAnimator = (() => {
1568
1652
  "flood-color",
1569
1653
  "lighting-color"
1570
1654
  ]);
1571
- const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
1655
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
1656
+ const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
1572
1657
  function collectIds(node) {
1573
1658
  if (!node || typeof node !== "object") return;
1574
1659
  if (node.id && typeof node.id === "string") {
@@ -1585,7 +1670,7 @@ var PixodeskAnimator = (() => {
1585
1670
  }
1586
1671
  }
1587
1672
  }
1588
- function updateRefs(node) {
1673
+ function updateRefs(node, parentKey) {
1589
1674
  if (!node || typeof node !== "object") return;
1590
1675
  for (const [key, value] of Object.entries(node)) {
1591
1676
  if (key === "children") {
@@ -1605,7 +1690,7 @@ var PixodeskAnimator = (() => {
1605
1690
  }
1606
1691
  } else if (urlRefAttrs.has(key)) {
1607
1692
  node[key] = replaceUrlRefs(value, idMap);
1608
- } else if (directIdRefAttrs.has(key)) {
1693
+ } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
1609
1694
  const hasHash = value.startsWith("#");
1610
1695
  const newId = idMap.get(hasHash ? value.slice(1) : value);
1611
1696
  if (newId) {
@@ -1621,7 +1706,7 @@ var PixodeskAnimator = (() => {
1621
1706
  }
1622
1707
  }
1623
1708
  } else if (typeof value === "object" && value !== null) {
1624
- updateRefs(value);
1709
+ updateRefs(value, key);
1625
1710
  }
1626
1711
  }
1627
1712
  }
@@ -1647,7 +1732,7 @@ var PixodeskAnimator = (() => {
1647
1732
  });
1648
1733
  }
1649
1734
 
1650
- // ../svg-animator-core/src/PxNodeProps.ts
1735
+ // ../svg-animator-core/src/util/PxNodeProps.ts
1651
1736
  var DISALLOWED_SVG_TAGS_LOWER = /* @__PURE__ */ new Set([
1652
1737
  "script",
1653
1738
  "foreignobject"
@@ -1729,14 +1814,14 @@ var PixodeskAnimator = (() => {
1729
1814
  propsCopy[key] = toRGBA(value);
1730
1815
  } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
1731
1816
  const parts = value.value && typeof value.value === "object" ? value.value : value;
1732
- propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
1817
+ propsCopy[TRANSFORM_ATTR] = composeTransformParts(parts, { withUnits: false });
1733
1818
  } else if (TRANSFORM_FN_NAMES.has(key)) {
1734
1819
  if (Array.isArray(value)) {
1735
1820
  if (key === "translate") value = value.map((v) => v + "px");
1736
1821
  value = value.join(",");
1737
1822
  }
1738
1823
  if (key === "rotate") value = value + "deg";
1739
- propsCopy["transform"] = key + "(" + value + ")";
1824
+ propsCopy[TRANSFORM_ATTR] = key + "(" + value + ")";
1740
1825
  } else if (Array.isArray(value)) {
1741
1826
  propsCopy[key] = value.join(",");
1742
1827
  } else if (value !== void 0 && value !== null) {
@@ -1746,10 +1831,9 @@ var PixodeskAnimator = (() => {
1746
1831
  return propsCopy;
1747
1832
  }
1748
1833
 
1749
- // ../svg-animator-core/src/PxMotionPath.ts
1834
+ // ../svg-animator-core/src/materialise/PxMotionPath.ts
1750
1835
  function getKfTranslate(kf) {
1751
- var _a;
1752
- const v = (_a = kf.value) != null ? _a : kf.v;
1836
+ const v = kfValue(kf);
1753
1837
  if (!v) return void 0;
1754
1838
  if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
1755
1839
  return [v[0], v[1]];
@@ -1759,31 +1843,27 @@ var PixodeskAnimator = (() => {
1759
1843
  return void 0;
1760
1844
  }
1761
1845
  function getKfTime(kf) {
1762
- var _a, _b;
1763
- return (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
1846
+ return kfTime(kf);
1764
1847
  }
1765
1848
  function getKfEasing(kf) {
1766
- var _a;
1767
- return (_a = kf.easing) != null ? _a : kf.e;
1849
+ return kfEasing(kf);
1768
1850
  }
1769
1851
  function propAnimIsMotionPath(anim) {
1770
- var _a, _b;
1771
1852
  const kfs = anim.keyframes;
1772
1853
  if (!Array.isArray(kfs)) return false;
1773
1854
  if (anim.autoOrient) return true;
1774
1855
  for (const kf of kfs) {
1775
- if (((_a = kf.tangentIn) != null ? _a : kf.ti) || ((_b = kf.tangentOut) != null ? _b : kf.to)) return true;
1856
+ if (kfTangentIn(kf) || kfTangentOut(kf)) return true;
1776
1857
  }
1777
1858
  return false;
1778
1859
  }
1779
1860
  var _segmentCache = /* @__PURE__ */ new WeakMap();
1780
1861
  function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
1781
- var _a, _b;
1782
1862
  let byNext = _segmentCache.get(prevKf);
1783
1863
  const existing = byNext == null ? void 0 : byNext.get(nextKf);
1784
1864
  if (existing) return existing;
1785
- const to = (_a = prevKf.tangentOut) != null ? _a : prevKf.to;
1786
- const ti = (_b = nextKf.tangentIn) != null ? _b : nextKf.ti;
1865
+ const to = kfTangentOut(prevKf);
1866
+ const ti = kfTangentIn(nextKf);
1787
1867
  const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
1788
1868
  const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
1789
1869
  const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
@@ -1874,10 +1954,9 @@ var PixodeskAnimator = (() => {
1874
1954
  return result;
1875
1955
  }
1876
1956
  function unwrapAutoOrientRotations(kfs) {
1877
- var _a;
1878
1957
  let prev;
1879
1958
  for (const kf of kfs) {
1880
- const v = (_a = kf.v) != null ? _a : kf.value;
1959
+ const v = kfValue(kf);
1881
1960
  if (!v || typeof v.rotate !== "number") continue;
1882
1961
  if (prev === void 0) {
1883
1962
  prev = v.rotate;
@@ -1894,8 +1973,7 @@ var PixodeskAnimator = (() => {
1894
1973
  return { t: time, v: value };
1895
1974
  }
1896
1975
  function getKfValueParts(kf) {
1897
- var _a;
1898
- const v = (_a = kf.value) != null ? _a : kf.v;
1976
+ const v = kfValue(kf);
1899
1977
  if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
1900
1978
  return v;
1901
1979
  }
@@ -1956,9 +2034,8 @@ var PixodeskAnimator = (() => {
1956
2034
  return d;
1957
2035
  }
1958
2036
  function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
1959
- var _a;
1960
2037
  const lastKf = out[out.length - 1];
1961
- const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
2038
+ const lastV = kfValue(lastKf);
1962
2039
  const prevExit = lastV == null ? void 0 : lastV.rotate;
1963
2040
  if (typeof prevExit !== "number") return;
1964
2041
  const boundaryV = getKfValueParts(prevKf);
@@ -2139,7 +2216,7 @@ var PixodeskAnimator = (() => {
2139
2216
  return cloned;
2140
2217
  }
2141
2218
 
2142
- // ../svg-animator-core/src/PxDefinitions.ts
2219
+ // ../svg-animator-core/src/animation/PxDefinitions.ts
2143
2220
  var LOOP_JUMP_SHIFT_MS = 1;
2144
2221
  function deepEqualValue(a, b) {
2145
2222
  if (a === b) return true;
@@ -2352,7 +2429,7 @@ var PixodeskAnimator = (() => {
2352
2429
  const totalIntervals = keyframes.length - 1;
2353
2430
  const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
2354
2431
  let segKfs;
2355
- if (loop.extend === PxLoopExtend.before) {
2432
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2356
2433
  segKfs = keyframes.slice(0, segCount + 1);
2357
2434
  } else {
2358
2435
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -2360,7 +2437,7 @@ var PixodeskAnimator = (() => {
2360
2437
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2361
2438
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2362
2439
  let fillStart, fillEnd;
2363
- if (loop.extend === PxLoopExtend.before) {
2440
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2364
2441
  fillStart = 0;
2365
2442
  fillEnd = firstT;
2366
2443
  } else {
@@ -2373,21 +2450,18 @@ var PixodeskAnimator = (() => {
2373
2450
  const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
2374
2451
  const segDuration = segEndT - segStartT;
2375
2452
  if (segDuration <= 0) return keyframes;
2376
- const template = segKfs.map((kf) => {
2377
- var _a2, _b2;
2378
- return {
2379
- relT: (kf.t - segStartT) / segDuration,
2380
- v: kf.v,
2381
- e: kf.e,
2382
- tangentIn: (_a2 = kf.tangentIn) != null ? _a2 : kf.ti,
2383
- tangentOut: (_b2 = kf.tangentOut) != null ? _b2 : kf.to
2384
- };
2385
- });
2453
+ const template = segKfs.map((kf) => ({
2454
+ relT: (kf.t - segStartT) / segDuration,
2455
+ v: kf.v,
2456
+ e: kf.e,
2457
+ tangentIn: kfTangentIn(kf),
2458
+ tangentOut: kfTangentOut(kf)
2459
+ }));
2386
2460
  const fullReps = Math.floor(fillDuration / segDuration);
2387
2461
  const remainder = fillDuration - fullReps * segDuration;
2388
2462
  const partialFraction = remainder / segDuration;
2389
2463
  const looped = [];
2390
- const separateBoundary = loop.extend !== PxLoopExtend.before;
2464
+ const separateBoundary = loop.repeatAt !== PxLoopRepeatAt.start;
2391
2465
  const originalTerminalKf = keyframes[keyframes.length - 1];
2392
2466
  let terminalEasingOverride;
2393
2467
  let hasTerminalEasingOverride = false;
@@ -2495,30 +2569,30 @@ var PixodeskAnimator = (() => {
2495
2569
  looped.push(pushed);
2496
2570
  }
2497
2571
  }
2498
- if (loop.extend === PxLoopExtend.before) {
2572
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2499
2573
  if (partialFraction > 1e-9) {
2500
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
2574
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2501
2575
  appendRepTail(fillStart, isReversed, partialFraction);
2502
2576
  }
2503
2577
  for (let rep = 0; rep < fullReps; rep++) {
2504
2578
  const distFromBoundary = fullReps - 1 - rep;
2505
- const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
2579
+ const isReversed = loop.direction === PxLoopDirection.alternate && distFromBoundary % 2 === 0;
2506
2580
  const repStart = fillStart + remainder + rep * segDuration;
2507
2581
  appendRep(repStart, isReversed);
2508
2582
  }
2509
2583
  } else {
2510
2584
  for (let rep = 0; rep < fullReps; rep++) {
2511
- const isReversed = !!loop.alternate && rep % 2 === 0;
2585
+ const isReversed = loop.direction === PxLoopDirection.alternate && rep % 2 === 0;
2512
2586
  const repStart = fillStart + rep * segDuration;
2513
2587
  appendRep(repStart, isReversed);
2514
2588
  }
2515
2589
  if (partialFraction > 1e-9) {
2516
- const isReversed = !!loop.alternate && fullReps % 2 === 0;
2590
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2517
2591
  const repStart = fillStart + fullReps * segDuration;
2518
2592
  appendRep(repStart, isReversed, partialFraction);
2519
2593
  }
2520
2594
  }
2521
- if (loop.extend === PxLoopExtend.before) {
2595
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2522
2596
  return [...looped, ...keyframes];
2523
2597
  } else {
2524
2598
  if (hasTerminalEasingOverride && keyframes.length > 0) {
@@ -2530,34 +2604,34 @@ var PixodeskAnimator = (() => {
2530
2604
  }
2531
2605
  }
2532
2606
  function normalizeKeyframes(propName, propAnim, duration, defs) {
2533
- var _a, _b, _c, _d, _e, _f, _g;
2607
+ var _a;
2534
2608
  const keyframes = propAnim.keyframes || [];
2535
2609
  const normalized = [];
2536
2610
  for (const kf of keyframes) {
2537
- const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
2538
- let value = (_c = kf.value) != null ? _c : kf.v;
2539
- const easing = (_d = kf.easing) != null ? _d : kf.e;
2611
+ const timePct = kfTime(kf);
2612
+ let value = kfValue(kf);
2613
+ const easing = kfEasing(kf);
2540
2614
  if (propName === "d") {
2541
2615
  value = normalizePathValue(value);
2542
2616
  }
2543
2617
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2544
2618
  if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
2545
- value = (_e = parseColor(value)) != null ? _e : value;
2619
+ value = (_a = parseColor(value)) != null ? _a : value;
2546
2620
  }
2547
2621
  const normKf = {
2548
2622
  t: timePct,
2549
2623
  v: value,
2550
2624
  e: resolveEasing(easing, defs)
2551
2625
  };
2552
- const tIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
2553
- const tOut = (_g = kf.tangentOut) != null ? _g : kf.to;
2626
+ const tIn = kfTangentIn(kf);
2627
+ const tOut = kfTangentOut(kf);
2554
2628
  if (tIn) normKf.tangentIn = tIn;
2555
2629
  if (tOut) normKf.tangentOut = tOut;
2556
2630
  normalized.push(normKf);
2557
2631
  }
2558
2632
  normalized.sort((a, b) => {
2559
- var _a2, _b2;
2560
- return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
2633
+ var _a2, _b;
2634
+ return ((_a2 = a.t) != null ? _a2 : 0) - ((_b = b.t) != null ? _b : 0);
2561
2635
  });
2562
2636
  const loopRaw = propAnim.loop;
2563
2637
  const loop = loopRaw === true ? {} : loopRaw || void 0;
@@ -2584,15 +2658,17 @@ var PixodeskAnimator = (() => {
2584
2658
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2585
2659
  const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
2586
2660
  const kfs = rawKfs.map((kf) => {
2587
- var _a, _b, _c, _d, _e, _f, _g, _h;
2588
- const t = (_a = kf.t) != null ? _a : kf.time;
2589
- let v = (_b = kf.v) != null ? _b : kf.value;
2661
+ var _a;
2662
+ const t = kfTime(kf);
2663
+ let v = kfValue(kf);
2590
2664
  if (propName === "d") v = normalizePathValue(v);
2591
- if (isColour) v = (_c = parseColor(v)) != null ? _c : v;
2592
- const e = (_d = kf.e) != null ? _d : kf.easing;
2665
+ if (isColour) v = (_a = parseColor(v)) != null ? _a : v;
2666
+ const e = kfEasing(kf);
2593
2667
  const out2 = { t, v, e };
2594
- if ((_e = kf.tangentIn) != null ? _e : kf.ti) out2.tangentIn = (_f = kf.tangentIn) != null ? _f : kf.ti;
2595
- if ((_g = kf.tangentOut) != null ? _g : kf.to) out2.tangentOut = (_h = kf.tangentOut) != null ? _h : kf.to;
2668
+ const tIn = kfTangentIn(kf);
2669
+ const tOut = kfTangentOut(kf);
2670
+ if (tIn) out2.tangentIn = tIn;
2671
+ if (tOut) out2.tangentOut = tOut;
2596
2672
  return out2;
2597
2673
  });
2598
2674
  const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
@@ -2643,7 +2719,7 @@ var PixodeskAnimator = (() => {
2643
2719
  const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
2644
2720
  if (!staticParts || !Object.keys(staticParts).length) return animDef;
2645
2721
  const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
2646
- const transformAnim = animDef["transform"];
2722
+ const transformAnim = animDef[TRANSFORM_ATTR];
2647
2723
  if (transformAnim && typeof transformAnim === "object") {
2648
2724
  const anim = transformAnim;
2649
2725
  if (Array.isArray(anim.keyframes)) {
@@ -2668,7 +2744,7 @@ var PixodeskAnimator = (() => {
2668
2744
  delete rest[ch];
2669
2745
  return __spreadProps(__spreadValues({}, rest), { transform: lifted });
2670
2746
  }
2671
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2747
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimelineEngine.native) {
2672
2748
  const normalized = {};
2673
2749
  for (const [propName, propAnim] of Object.entries(animDef)) {
2674
2750
  if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
@@ -2679,12 +2755,12 @@ var PixodeskAnimator = (() => {
2679
2755
  const out = { keyframes: normalizedKfs };
2680
2756
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2681
2757
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2682
- normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2758
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
2683
2759
  }
2684
2760
  }
2685
2761
  return normalized;
2686
2762
  }
2687
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2763
+ function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
2688
2764
  const animatorConfig = getAnimatorConfig(doc) || {};
2689
2765
  const defs = getDefs(doc);
2690
2766
  const duration = animatorConfig.duration || 1e3;
@@ -2750,13 +2826,13 @@ var PixodeskAnimator = (() => {
2750
2826
  return { prevKf, nextKf };
2751
2827
  }
2752
2828
  function calcPropertyValue(propName, propAnim, progress) {
2753
- var _a, _b, _c, _d, _e, _f, _g;
2829
+ var _a, _b, _c, _d;
2754
2830
  const keyframes = propAnim.keyframes || [];
2755
2831
  if (keyframes.length === 0) return null;
2756
2832
  const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
2757
2833
  let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
2758
2834
  localProgress = clamp(localProgress, 0, 1);
2759
- const easing = (_c = prevKf.e) != null ? _c : prevKf.easing;
2835
+ const easing = kfEasing(prevKf);
2760
2836
  if (easing && Array.isArray(easing)) {
2761
2837
  try {
2762
2838
  localProgress = cubicBezier(easing)(localProgress);
@@ -2765,11 +2841,11 @@ var PixodeskAnimator = (() => {
2765
2841
  }
2766
2842
  let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2767
2843
  let cssValue = null;
2768
- const prevV = (_d = prevKf == null ? void 0 : prevKf.v) != null ? _d : prevKf == null ? void 0 : prevKf.value;
2769
- const nextV = (_e = nextKf == null ? void 0 : nextKf.v) != null ? _e : nextKf == null ? void 0 : nextKf.value;
2844
+ const prevV = prevKf == null ? void 0 : prevKf.v;
2845
+ const nextV = nextKf == null ? void 0 : nextKf.v;
2770
2846
  if (cssAttrName === "d") {
2771
- const prevPaths = (_f = prevV == null ? void 0 : prevV.paths) != null ? _f : Array.isArray(prevV) ? prevV : [];
2772
- const nextPaths = (_g = nextV == null ? void 0 : nextV.paths) != null ? _g : Array.isArray(nextV) ? nextV : [];
2847
+ const prevPaths = (_c = prevV == null ? void 0 : prevV.paths) != null ? _c : Array.isArray(prevV) ? prevV : [];
2848
+ const nextPaths = (_d = nextV == null ? void 0 : nextV.paths) != null ? _d : Array.isArray(nextV) ? nextV : [];
2773
2849
  cssValue = interpolateBeziers(
2774
2850
  prevPaths,
2775
2851
  nextPaths,
@@ -2872,7 +2948,7 @@ var PixodeskAnimator = (() => {
2872
2948
  return result;
2873
2949
  }
2874
2950
 
2875
- // ../svg-animator-core/src/PxNodeCloneUtil.ts
2951
+ // ../svg-animator-core/src/util/PxNodeCloneUtil.ts
2876
2952
  function deepClonePxNode(value) {
2877
2953
  if (value === null || typeof value !== "object") return value;
2878
2954
  if (Array.isArray(value)) return value.map(deepClonePxNode);
@@ -2936,7 +3012,7 @@ var PixodeskAnimator = (() => {
2936
3012
  return gNode;
2937
3013
  }
2938
3014
 
2939
- // ../svg-animator-core/src/PxAnimatorUseMaterialiser.ts
3015
+ // ../svg-animator-core/src/materialise/PxAnimatorUseMaterialiser.ts
2940
3016
  function materialiseAnimatedUseInstances(root) {
2941
3017
  var _a;
2942
3018
  const idMap = buildIdMap(root);
@@ -3084,7 +3160,7 @@ var PixodeskAnimator = (() => {
3084
3160
  return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
3085
3161
  }
3086
3162
 
3087
- // ../svg-animator-core/src/effects/transformParts.ts
3163
+ // ../svg-animator-core/src/effects/shared/transformParts.ts
3088
3164
  function partsRecord(part, value, origin) {
3089
3165
  const rec = {};
3090
3166
  if (part === "translate" /* Translate */) rec.translate = value;
@@ -3095,19 +3171,19 @@ var PixodeskAnimator = (() => {
3095
3171
  return rec;
3096
3172
  }
3097
3173
  function readAnimatable(raw) {
3098
- var _a, _b, _c;
3174
+ var _a, _b;
3099
3175
  if (raw === void 0) return { kind: "absent" /* Absent */ };
3100
3176
  if (Array.isArray(raw)) return { kind: "static" /* Static */, value: raw };
3101
3177
  if (typeof raw === "object") {
3102
3178
  const obj = raw;
3103
- const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
3179
+ const kfs = obj.keyframes;
3104
3180
  if (kfs) {
3105
3181
  const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3106
- const base = (_b = obj.value) != null ? _b : obj.v;
3182
+ const base = (_a = obj.value) != null ? _a : obj.v;
3107
3183
  if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
3108
3184
  return out;
3109
3185
  }
3110
- const staticValue = (_c = obj.value) != null ? _c : obj.v;
3186
+ const staticValue = (_b = obj.value) != null ? _b : obj.v;
3111
3187
  if (staticValue !== void 0) return { kind: "static" /* Static */, value: staticValue };
3112
3188
  }
3113
3189
  return { kind: "static" /* Static */, value: raw };
@@ -3161,7 +3237,7 @@ var PixodeskAnimator = (() => {
3161
3237
  return out;
3162
3238
  }
3163
3239
 
3164
- // ../svg-animator-core/src/effects/transformationEffect.ts
3240
+ // ../svg-animator-core/src/effects/transform/transformationEffect.ts
3165
3241
  function applyTransformByEffect(node, fx, ctx) {
3166
3242
  if (!fx) return node;
3167
3243
  delete node.transform;
@@ -3252,7 +3328,7 @@ var PixodeskAnimator = (() => {
3252
3328
  return inner;
3253
3329
  }
3254
3330
 
3255
- // ../svg-animator-core/src/effects/util.ts
3331
+ // ../svg-animator-core/src/effects/shared/util.ts
3256
3332
  function genId(ctx, prefix) {
3257
3333
  return "_lw_" + prefix + "_" + ctx.nextId++;
3258
3334
  }
@@ -3274,11 +3350,11 @@ var PixodeskAnimator = (() => {
3274
3350
  return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3275
3351
  }
3276
3352
 
3277
- // ../svg-animator-core/src/effects/contentRefSplit.ts
3353
+ // ../svg-animator-core/src/effects/reference/contentRefSplit.ts
3278
3354
  function identifyContentRefTargets(node, ctx, allocator) {
3279
3355
  var _a, _b, _c;
3280
- if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.type) === "content") {
3281
- const sourceId = stripHash2(node.effects.clone.sourceId);
3356
+ if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.without) === "translate") {
3357
+ const sourceId = stripHash2(node.effects.clone.source);
3282
3358
  if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3283
3359
  ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
3284
3360
  }
@@ -3489,7 +3565,7 @@ var PixodeskAnimator = (() => {
3489
3565
  return false;
3490
3566
  }
3491
3567
 
3492
- // ../svg-animator-core/src/effects/gradientEffect.ts
3568
+ // ../svg-animator-core/src/effects/paint/gradientEffect.ts
3493
3569
  function applyFillGradientEffect(node, fx, ctx) {
3494
3570
  return applyGradient(node, fx, ctx, "fill");
3495
3571
  }
@@ -3559,7 +3635,7 @@ var PixodeskAnimator = (() => {
3559
3635
  writeAnimatableChannel(out, attrName, read, { asString: true });
3560
3636
  }
3561
3637
  function buildStopChildren(stops, ctx) {
3562
- var _a, _b, _c, _d;
3638
+ var _a, _b;
3563
3639
  if (!stops) return [];
3564
3640
  const read = readAnimatable(stops);
3565
3641
  if (read.kind === "absent" /* Absent */) return [];
@@ -3569,14 +3645,14 @@ var PixodeskAnimator = (() => {
3569
3645
  const loopFromSource = read.loop;
3570
3646
  let stopCount = 0;
3571
3647
  for (const kf of kfs) {
3572
- const v = (_a = kf.value) != null ? _a : kf.v;
3648
+ const v = kfValue(kf);
3573
3649
  if (Array.isArray(v) && v.length > stopCount) stopCount = v.length;
3574
3650
  }
3575
3651
  if (!stopCount) return [];
3576
- const firstKfValue = (_b = kfs[0].value) != null ? _b : kfs[0].v;
3652
+ const firstKfValue = kfValue(kfs[0]);
3577
3653
  const baselineStops = [];
3578
3654
  for (let i = 0; i < stopCount; i++) {
3579
- const s = (_d = (_c = firstKfValue == null ? void 0 : firstKfValue[i]) != null ? _c : prevDefinedStop(kfs, 0, i)) != null ? _d : { offset: i / Math.max(1, stopCount - 1), color: "#000000" };
3655
+ const s = (_b = (_a = firstKfValue == null ? void 0 : firstKfValue[i]) != null ? _a : prevDefinedStop(kfs, 0, i)) != null ? _b : { offset: i / Math.max(1, stopCount - 1), color: "#000000" };
3580
3656
  baselineStops.push({ offset: s.offset, color: s.color });
3581
3657
  }
3582
3658
  return baselineStops.map((bs, i) => animatedStopNode(bs, kfs, i, ctx, loopFromSource));
@@ -3589,16 +3665,16 @@ var PixodeskAnimator = (() => {
3589
3665
  };
3590
3666
  }
3591
3667
  function animatedStopNode(baseline, kfs, stopIdx, _ctx, loop) {
3592
- var _a, _b, _c, _d, _e;
3668
+ var _a;
3593
3669
  const colorKfs = [];
3594
3670
  const offsetKfs = [];
3595
3671
  let offsetVaries = false;
3596
3672
  for (const kf of kfs) {
3597
- const t = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
3598
- const arr = (_c = kf.value) != null ? _c : kf.v;
3599
- const sliced = (_d = arr == null ? void 0 : arr[stopIdx]) != null ? _d : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
3673
+ const t = kfTime(kf);
3674
+ const arr = kfValue(kf);
3675
+ const sliced = (_a = arr == null ? void 0 : arr[stopIdx]) != null ? _a : prevDefinedStop(kfs, kfs.indexOf(kf), stopIdx);
3600
3676
  if (!sliced) continue;
3601
- const easing = (_e = kf.easing) != null ? _e : kf.e;
3677
+ const easing = kfEasing(kf);
3602
3678
  const colorOut = { time: t, value: sliced.color };
3603
3679
  if (easing !== void 0) colorOut.easing = easing;
3604
3680
  colorKfs.push(colorOut);
@@ -3625,13 +3701,12 @@ var PixodeskAnimator = (() => {
3625
3701
  return stop;
3626
3702
  }
3627
3703
  function prevDefinedStop(kfs, fromIdx, stopIdx) {
3628
- var _a, _b;
3629
3704
  for (let i = fromIdx; i >= 0; i--) {
3630
- const arr = (_a = kfs[i].value) != null ? _a : kfs[i].v;
3705
+ const arr = kfValue(kfs[i]);
3631
3706
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3632
3707
  }
3633
3708
  for (let i = fromIdx + 1; i < kfs.length; i++) {
3634
- const arr = (_b = kfs[i].value) != null ? _b : kfs[i].v;
3709
+ const arr = kfValue(kfs[i]);
3635
3710
  if (arr == null ? void 0 : arr[stopIdx]) return arr[stopIdx];
3636
3711
  }
3637
3712
  return void 0;
@@ -3641,7 +3716,7 @@ var PixodeskAnimator = (() => {
3641
3716
  return pct + "%";
3642
3717
  }
3643
3718
 
3644
- // ../svg-animator-core/src/effects/clipPathEffect.ts
3719
+ // ../svg-animator-core/src/effects/clipping/clipPathEffect.ts
3645
3720
  function applyClipPathEffect(node, fx, ctx) {
3646
3721
  if (!(fx == null ? void 0 : fx.d)) return node;
3647
3722
  const clipId = genId(ctx, "clip");
@@ -3665,12 +3740,12 @@ var PixodeskAnimator = (() => {
3665
3740
  return void 0;
3666
3741
  }
3667
3742
 
3668
- // ../svg-animator-core/src/effects/maskedByEffect.ts
3743
+ // ../svg-animator-core/src/effects/clipping/maskedByEffect.ts
3669
3744
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
3670
3745
  if (!fx) return node;
3671
- const sourceId = stripHash2(fx.sourceId);
3746
+ const sourceId = stripHash2(fx.source);
3672
3747
  if (!sourceId) {
3673
- ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
3748
+ ctx.errors.push("maskedBy.source missing \u2014 cannot build mask");
3674
3749
  return node;
3675
3750
  }
3676
3751
  const maskId = genId(ctx, "mask");
@@ -3945,7 +4020,7 @@ var PixodeskAnimator = (() => {
3945
4020
  const interestingNodes = /* @__PURE__ */ new Set();
3946
4021
  const collectInterestingNodes = (n) => {
3947
4022
  var _a, _b;
3948
- const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.sourceId);
4023
+ const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.source);
3949
4024
  if (typeof maskSourceId === "string") {
3950
4025
  interestingNodes.add(n);
3951
4026
  const sourceNode = ctx.idMap.get(maskSourceId);
@@ -3974,7 +4049,7 @@ var PixodeskAnimator = (() => {
3974
4049
  if (typeof tr === "string") {
3975
4050
  const parts = parseTranslateOnlyFromString(tr, ctx);
3976
4051
  if (parts) out.translate = parts;
3977
- } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
4052
+ } else if (tr && typeof tr === "object" && !tr.keyframes) {
3978
4053
  const wrapped = tr.value;
3979
4054
  const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
3980
4055
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
@@ -4022,16 +4097,15 @@ var PixodeskAnimator = (() => {
4022
4097
  return seen ? [x, y] : void 0;
4023
4098
  }
4024
4099
 
4025
- // ../svg-animator-core/src/effects/refEffect.ts
4026
- var CONTENT_SUBREF = "content";
4100
+ // ../svg-animator-core/src/effects/reference/refEffect.ts
4027
4101
  function applyRefHref(node, clone2, ctx) {
4028
4102
  if (!clone2) return;
4029
- const sourceId = stripHash2(clone2.sourceId);
4103
+ const sourceId = stripHash2(clone2.source);
4030
4104
  if (!sourceId) {
4031
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
4105
+ if (clone2.without === PxCloneWithout.translate) ctx.errors.push("clone: content ref missing `source`");
4032
4106
  return;
4033
4107
  }
4034
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4108
+ const targetId = clone2.without === PxCloneWithout.translate ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
4035
4109
  node.href = "#" + targetId;
4036
4110
  }
4037
4111
  function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
@@ -4039,7 +4113,7 @@ var PixodeskAnimator = (() => {
4039
4113
  return applyTransformByEffect(node, transformBy, ctx);
4040
4114
  }
4041
4115
 
4042
- // ../svg-animator-core/src/effects/repeaterEffect.ts
4116
+ // ../svg-animator-core/src/effects/transform/repeaterEffect.ts
4043
4117
  function applyRepeaterEffect(node, fx, ctx) {
4044
4118
  var _a, _b;
4045
4119
  if (!fx) return node;
@@ -4110,7 +4184,7 @@ var PixodeskAnimator = (() => {
4110
4184
  return mapAnimatable(raw, scalePower, true);
4111
4185
  }
4112
4186
 
4113
- // ../svg-animator-core/src/effects/retimeEffect.ts
4187
+ // ../svg-animator-core/src/effects/reference/retimeEffect.ts
4114
4188
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
4115
4189
  function asRetime(r) {
4116
4190
  var _a, _b;
@@ -4293,7 +4367,7 @@ var PixodeskAnimator = (() => {
4293
4367
  }
4294
4368
  }
4295
4369
 
4296
- // ../svg-animator-core/src/effects/pathSampler.ts
4370
+ // ../svg-animator-core/src/effects/text/pathSampler.ts
4297
4371
  var LUT_STEPS = 48;
4298
4372
  var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
4299
4373
  function tokenize(d) {
@@ -4441,7 +4515,7 @@ var PixodeskAnimator = (() => {
4441
4515
  };
4442
4516
  }
4443
4517
 
4444
- // ../svg-animator-core/src/effects/textPathEffect.ts
4518
+ // ../svg-animator-core/src/effects/text/textPathEffect.ts
4445
4519
  var EXTEND_MARGIN_FRAC = 0.15;
4446
4520
  function numRange(v) {
4447
4521
  const read = readAnimatable(v);
@@ -4509,9 +4583,9 @@ var PixodeskAnimator = (() => {
4509
4583
  }
4510
4584
  function applyTextPathEffect(node, fx, ctx) {
4511
4585
  var _a;
4512
- if (!fx || typeof fx.path !== "string" || !fx.path) return node;
4586
+ if (!fx || typeof fx.pathData !== "string" || !fx.pathData) return node;
4513
4587
  const pathId = genId(ctx, "tpath");
4514
- const { d, startShift } = extendedPathForBrowser(fx.path, {
4588
+ const { d, startShift } = extendedPathForBrowser(fx.pathData, {
4515
4589
  pathOverflow: fx.pathOverflow,
4516
4590
  startOffset: fx.startOffset,
4517
4591
  textLength: fx.textLength,
@@ -4536,7 +4610,7 @@ var PixodeskAnimator = (() => {
4536
4610
  writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
4537
4611
  }
4538
4612
 
4539
- // ../svg-animator-core/src/effects/elementFactory.ts
4613
+ // ../svg-animator-core/src/effects/text/elementFactory.ts
4540
4614
  var jsonElementFactory = (type, props, children) => {
4541
4615
  const node = { type };
4542
4616
  for (const k in props) if (props[k] !== void 0) node[k] = props[k];
@@ -4545,7 +4619,7 @@ var PixodeskAnimator = (() => {
4545
4619
  return node;
4546
4620
  };
4547
4621
 
4548
- // ../svg-animator-core/src/effects/glyphPathBake.ts
4622
+ // ../svg-animator-core/src/effects/text/glyphPathBake.ts
4549
4623
  function fmt(v, decimals) {
4550
4624
  return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
4551
4625
  }
@@ -4591,7 +4665,7 @@ var PixodeskAnimator = (() => {
4591
4665
  return out;
4592
4666
  }
4593
4667
 
4594
- // ../svg-animator-core/src/effects/textGlyphsEffect.ts
4668
+ // ../svg-animator-core/src/effects/text/textGlyphsEffect.ts
4595
4669
  var DEFAULT_FONT_SIZE = 16;
4596
4670
  var TEXT_ATTR_KEYS = [
4597
4671
  "fontFamily",
@@ -4970,7 +5044,7 @@ var PixodeskAnimator = (() => {
4970
5044
  return p;
4971
5045
  }
4972
5046
  function missingGlyphProps(isMissing) {
4973
- return isMissing ? { class: MISSING_GLYPH_CLASS_NAME } : {};
5047
+ return isMissing ? { [CLASS_ATTR]: MISSING_GLYPH_CLASS_NAME } : {};
4974
5048
  }
4975
5049
  function buildPaths(placements, create, warnings) {
4976
5050
  if (!placements.length) {
@@ -5010,20 +5084,20 @@ var PixodeskAnimator = (() => {
5010
5084
  function applyTextGlyphsEffect(node, fx, ctx) {
5011
5085
  if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
5012
5086
  if (!ctx.glyphs) {
5013
- ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
5087
+ ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
5014
5088
  return node;
5015
5089
  }
5016
5090
  return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5017
5091
  }
5018
5092
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
5019
5093
  if (!ctx.glyphs) {
5020
- ctx.warnings.push("textGlyphs: no definitions.glyphs");
5094
+ ctx.warnings.push("textGlyphs: no definitions.fonts");
5021
5095
  return null;
5022
5096
  }
5023
5097
  return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5024
5098
  }
5025
5099
 
5026
- // ../svg-animator-core/src/effects/strokeTrimEffect.ts
5100
+ // ../svg-animator-core/src/effects/stroke/strokeTrimEffect.ts
5027
5101
  function applyStrokeTrimEffect(node, strokeTrim, ctx) {
5028
5102
  if (!strokeTrim) return node;
5029
5103
  const combined = strokeTrim.subPaths === PxStrokeTrimSubPaths.combined;
@@ -5159,12 +5233,11 @@ var PixodeskAnimator = (() => {
5159
5233
  ];
5160
5234
  }
5161
5235
  function readScalarValues(r) {
5162
- var _a;
5163
5236
  if (r.kind === "absent" /* Absent */) return [];
5164
5237
  if (r.kind === "static" /* Static */) return [r.value];
5165
5238
  const out = [];
5166
5239
  for (const kf of r.keyframes) {
5167
- const v = (_a = kf.value) != null ? _a : kf.v;
5240
+ const v = kfValue(kf);
5168
5241
  if (typeof v === "number") out.push(v);
5169
5242
  }
5170
5243
  return out;
@@ -5174,14 +5247,11 @@ var PixodeskAnimator = (() => {
5174
5247
  if (read.kind === "static" /* Static */) return { kind: "static" /* Static */, value: map(read.value) };
5175
5248
  return {
5176
5249
  kind: "animated" /* Animated */,
5177
- keyframes: read.keyframes.map((kf) => {
5178
- var _a, _b, _c, _d;
5179
- return {
5180
- time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5181
- value: map((_c = kf.value) != null ? _c : kf.v),
5182
- easing: (_d = kf.easing) != null ? _d : kf.e
5183
- };
5184
- }),
5250
+ keyframes: read.keyframes.map((kf) => ({
5251
+ time: kfTime(kf),
5252
+ value: map(kfValue(kf)),
5253
+ easing: kfEasing(kf)
5254
+ })),
5185
5255
  loop: read.loop
5186
5256
  };
5187
5257
  }
@@ -5191,7 +5261,6 @@ var PixodeskAnimator = (() => {
5191
5261
  }
5192
5262
  var OPACITY_STEP_MS = 10;
5193
5263
  function computeOpacityFromRange(rangeRead) {
5194
- var _a, _b, _c, _d, _e, _f;
5195
5264
  const hide = (v) => v[0] === v[1];
5196
5265
  if (rangeRead.kind === "absent" /* Absent */) return void 0;
5197
5266
  if (rangeRead.kind === "static" /* Static */) return hide(rangeRead.value) ? { kind: "static" /* Static */, value: 0 } : void 0;
@@ -5199,7 +5268,7 @@ var PixodeskAnimator = (() => {
5199
5268
  let anyHide = false;
5200
5269
  let allHide = true;
5201
5270
  for (const kf of kfs) {
5202
- if (hide((_a = kf.value) != null ? _a : kf.v)) anyHide = true;
5271
+ if (hide(kfValue(kf))) anyHide = true;
5203
5272
  else allHide = false;
5204
5273
  }
5205
5274
  if (!anyHide) return void 0;
@@ -5209,10 +5278,10 @@ var PixodeskAnimator = (() => {
5209
5278
  const kf = kfs[i];
5210
5279
  const prevKf = i > 0 ? kfs[i - 1] : void 0;
5211
5280
  const nextKf = i < kfs.length - 1 ? kfs[i + 1] : void 0;
5212
- const t = (_c = (_b = kf.time) != null ? _b : kf.t) != null ? _c : 0;
5213
- const thisHide = hide((_d = kf.value) != null ? _d : kf.v);
5214
- const prevHide = prevKf ? thisHide && hide((_e = prevKf.value) != null ? _e : prevKf.v) : thisHide;
5215
- const nextHide = nextKf ? thisHide && hide((_f = nextKf.value) != null ? _f : nextKf.v) : thisHide;
5281
+ const t = kfTime(kf);
5282
+ const thisHide = hide(kfValue(kf));
5283
+ const prevHide = prevKf ? thisHide && hide(kfValue(prevKf)) : thisHide;
5284
+ const nextHide = nextKf ? thisHide && hide(kfValue(nextKf)) : thisHide;
5216
5285
  if (prevHide && !nextHide) {
5217
5286
  out.push({ time: t, value: 0 });
5218
5287
  out.push({ time: t + OPACITY_STEP_MS, value: 1 });
@@ -5227,14 +5296,11 @@ var PixodeskAnimator = (() => {
5227
5296
  function readRangeWithCrossings(raw) {
5228
5297
  const r = readAnimatable(raw);
5229
5298
  if (r.kind !== "animated" /* Animated */) return r;
5230
- const kfs = r.keyframes.map((kf) => {
5231
- var _a, _b, _c, _d;
5232
- return {
5233
- time: (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0,
5234
- value: (_c = kf.value) != null ? _c : kf.v,
5235
- easing: (_d = kf.easing) != null ? _d : kf.e
5236
- };
5237
- });
5299
+ const kfs = r.keyframes.map((kf) => ({
5300
+ time: kfTime(kf),
5301
+ value: kfValue(kf),
5302
+ easing: kfEasing(kf)
5303
+ }));
5238
5304
  const hasReverse = kfs.some((kf) => kf.value[0] > kf.value[1]);
5239
5305
  if (!hasReverse) {
5240
5306
  return {
@@ -5373,8 +5439,8 @@ var PixodeskAnimator = (() => {
5373
5439
  maskAncestorChains: /* @__PURE__ */ new Map(),
5374
5440
  // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
5375
5441
  // waapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
5376
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi,
5377
- glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
5442
+ engine: resolveTimelineEngine((_a = getAnimatorConfig(root)) == null ? void 0 : _a.engine),
5443
+ glyphs: (_b = getDefs(root)) == null ? void 0 : _b.fonts
5378
5444
  };
5379
5445
  const working = clone(root);
5380
5446
  indexById(working, ctx.idMap);
@@ -5397,7 +5463,7 @@ var PixodeskAnimator = (() => {
5397
5463
  let consumedByGlyphs = false;
5398
5464
  if (text == null ? void 0 : text.useGlyphs) {
5399
5465
  if (textPath) {
5400
- const pathD = typeof textPath.path === "string" ? textPath.path : void 0;
5466
+ const pathD = typeof textPath.pathData === "string" ? textPath.pathData : void 0;
5401
5467
  const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textPath.startOffset, textPath.textLength, textPath.pathOverflow);
5402
5468
  if (glyphed) {
5403
5469
  n = glyphed;
@@ -5430,27 +5496,7 @@ var PixodeskAnimator = (() => {
5430
5496
  return node;
5431
5497
  }
5432
5498
 
5433
- // ../svg-animator-core/src/PxOffsetPathMaterialiser.ts
5434
- var kfTime = (kf) => {
5435
- var _a, _b;
5436
- return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
5437
- };
5438
- var kfValue = (kf) => {
5439
- var _a;
5440
- return (_a = kf.v) != null ? _a : kf.value;
5441
- };
5442
- var kfEasing = (kf) => {
5443
- var _a;
5444
- return (_a = kf.e) != null ? _a : kf.easing;
5445
- };
5446
- var kfTangentIn = (kf) => {
5447
- var _a;
5448
- return (_a = kf.tangentIn) != null ? _a : kf.ti;
5449
- };
5450
- var kfTangentOut = (kf) => {
5451
- var _a;
5452
- return (_a = kf.tangentOut) != null ? _a : kf.to;
5453
- };
5499
+ // ../svg-animator-core/src/materialise/PxOffsetPathMaterialiser.ts
5454
5500
  function cubicAt(p0, c1, c2, p1, t) {
5455
5501
  const u = 1 - t;
5456
5502
  const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
@@ -5526,16 +5572,16 @@ var PixodeskAnimator = (() => {
5526
5572
  const built = buildOffsetPath(transform);
5527
5573
  if (built) {
5528
5574
  const newAnimate = __spreadValues({}, anim);
5529
- delete newAnimate["transform"];
5575
+ delete newAnimate[TRANSFORM_ATTR];
5530
5576
  const distance = { keyframes: built.distanceKfs };
5531
5577
  if (transform.loop !== void 0) distance.loop = transform.loop;
5532
- newAnimate["offsetDistance"] = distance;
5578
+ newAnimate[OFFSET_DISTANCE_ATTR] = distance;
5533
5579
  const staticTr = node.transform;
5534
5580
  let newTransform = staticTr;
5535
5581
  if (staticTr && typeof staticTr === "object") {
5536
5582
  const t = __spreadValues({}, staticTr);
5537
- delete t["translate"];
5538
- delete t["origin"];
5583
+ delete t[TRANSFORM_PART.translate];
5584
+ delete t[TRANSFORM_PART.origin];
5539
5585
  newTransform = Object.keys(t).length ? t : void 0;
5540
5586
  }
5541
5587
  out = __spreadProps(__spreadValues({}, node), {
@@ -5560,14 +5606,14 @@ var PixodeskAnimator = (() => {
5560
5606
  return walk(root);
5561
5607
  }
5562
5608
 
5563
- // ../svg-animator-core/src/PxAnimatorMaterialiseAll.ts
5609
+ // ../svg-animator-core/src/materialise/PxAnimatorMaterialiseAll.ts
5564
5610
  function materialiseAllInTree(doc, engine, opts) {
5565
5611
  var _a, _b;
5566
5612
  let root = applyPlayerEffects(doc).root;
5567
5613
  root = materialiseOffsetPathsInTree(root);
5568
5614
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5569
5615
  root = materialiseInternalLoopsInTree(root, duration);
5570
- if (engine === PxAnimatorEngine.waapi) {
5616
+ if (engine === PxTimelineEngine.native) {
5571
5617
  root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
5572
5618
  root = materialiseAnimatedUseInstances(root);
5573
5619
  root = pruneUnreferencedDefs(root);
@@ -5604,7 +5650,7 @@ var PixodeskAnimator = (() => {
5604
5650
  return root;
5605
5651
  }
5606
5652
 
5607
- // ../svg-animator-core/src/PxFrameLoop.ts
5653
+ // ../svg-animator-core/src/playback/PxFrameLoop.ts
5608
5654
  function requestFrame(cb) {
5609
5655
  const g = globalThis;
5610
5656
  if (typeof g.requestAnimationFrame === "function") return g.requestAnimationFrame(cb);
@@ -5621,7 +5667,7 @@ var PixodeskAnimator = (() => {
5621
5667
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5622
5668
  var _a;
5623
5669
  const config = getAnimatorConfig(doc) || {};
5624
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
5670
+ const bindings = getNormalisedBindings(doc, PxTimelineEngine.js);
5625
5671
  const _iterations = config.iterations;
5626
5672
  let iterations = 1;
5627
5673
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -5882,7 +5928,194 @@ var PixodeskAnimator = (() => {
5882
5928
  return api;
5883
5929
  }
5884
5930
 
5885
- // src/PxAnimatorTriggers.ts
5931
+ // ../svg-animator-core/src/playback/PxAnimatorConfigPatch.ts
5932
+ var FLAT_ONLY_KEYS = [
5933
+ "timelineSource",
5934
+ "scroll",
5935
+ "trigger",
5936
+ "delay",
5937
+ "iterations",
5938
+ "direction",
5939
+ "fill",
5940
+ "resetOnFinish",
5941
+ "duration",
5942
+ "mode",
5943
+ "frameRate"
5944
+ ];
5945
+ var CONTENT_KEYS = ["definitions", "animateById"];
5946
+ var isPlainObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
5947
+ var timelineTypeOf = (t) => isPlainObject(t) && typeof t.type === "string" ? t.type : "time";
5948
+ var isScrollish = (type) => type === "scroll" || type === "view";
5949
+ function mergePlain(base, patch) {
5950
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
5951
+ for (const key of Object.keys(patch)) {
5952
+ const value = patch[key];
5953
+ if (value === null) {
5954
+ delete out[key];
5955
+ continue;
5956
+ }
5957
+ if (isPlainObject(value)) {
5958
+ out[key] = mergePlain(out[key], value);
5959
+ continue;
5960
+ }
5961
+ out[key] = value;
5962
+ }
5963
+ return out;
5964
+ }
5965
+ function mergeTimeline(base, patch, warn) {
5966
+ const baseType = timelineTypeOf(base);
5967
+ const patchNamesType = isPlainObject(patch) && typeof patch.type === "string";
5968
+ const patchType = patchNamesType ? String(patch.type) : baseType;
5969
+ let merged;
5970
+ if (patchType !== baseType) {
5971
+ const carried = {};
5972
+ if (isPlainObject(base)) {
5973
+ for (const k of PX_TIMELINE_SHARED_KEYS) {
5974
+ if (base[k] !== void 0) carried[k] = base[k];
5975
+ }
5976
+ }
5977
+ merged = mergePlain(carried, patch);
5978
+ } else {
5979
+ merged = mergePlain(base, patch);
5980
+ }
5981
+ if (isScrollish(patchType)) {
5982
+ for (const k of PX_TIME_ONLY_TIMELINE_KEYS) {
5983
+ if (merged[k] === void 0) continue;
5984
+ warn("animator.timeline." + k + ": no slot on a '" + patchType + "' timeline \u2014 dropped");
5985
+ delete merged[k];
5986
+ }
5987
+ if (merged.iterations === "infinite") {
5988
+ warn("animator.timeline.iterations: 'infinite' cannot map onto a scroll range \u2014 dropped");
5989
+ delete merged.iterations;
5990
+ }
5991
+ }
5992
+ return merged;
5993
+ }
5994
+ function foldAnimatorConfigShortcuts(config, shortcuts) {
5995
+ let base;
5996
+ if (typeof config === "string") {
5997
+ try {
5998
+ base = JSON.parse(config);
5999
+ } catch (e) {
6000
+ console.warn("animator config: not valid JSON \u2014 ignored", e);
6001
+ base = void 0;
6002
+ }
6003
+ } else {
6004
+ base = config != null ? config : void 0;
6005
+ }
6006
+ const { duration, delay, iterations, startOn } = shortcuts;
6007
+ if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6008
+ return base;
6009
+ }
6010
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6011
+ const timeline = __spreadValues({}, out.timeline);
6012
+ if (duration !== void 0) timeline.duration = duration;
6013
+ if (delay !== void 0) timeline.delay = delay;
6014
+ if (iterations !== void 0) timeline.iterations = iterations;
6015
+ if (startOn !== void 0) {
6016
+ timeline.trigger = __spreadProps(__spreadValues({}, timeline.trigger), { startOn });
6017
+ }
6018
+ out.timeline = timeline;
6019
+ return out;
6020
+ }
6021
+ function mergeAnimatorConfig(base, patch) {
6022
+ const warnings = [];
6023
+ const warn = (m) => warnings.push(m);
6024
+ if (patch === null) return { config: void 0, warnings };
6025
+ if (!isPlainObject(patch) || Object.keys(patch).length === 0) {
6026
+ return { config: base, warnings };
6027
+ }
6028
+ const flatInBase = isPlainObject(base) ? FLAT_ONLY_KEYS.filter((k) => base[k] !== void 0) : [];
6029
+ if (flatInBase.length) {
6030
+ warn("animator: the base carries the flat runtime spelling (" + flatInBase.join(", ") + "); the patch merges the wire spelling only");
6031
+ }
6032
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6033
+ for (const key of Object.keys(patch)) {
6034
+ const value = patch[key];
6035
+ if (value === null) {
6036
+ delete out[key];
6037
+ continue;
6038
+ }
6039
+ if (key === "timeline") {
6040
+ out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
6041
+ continue;
6042
+ }
6043
+ if (isPlainObject(value)) {
6044
+ out[key] = mergePlain(out[key], value);
6045
+ continue;
6046
+ }
6047
+ out[key] = value;
6048
+ }
6049
+ return { config: out, warnings };
6050
+ }
6051
+ function applyAnimatorConfig(doc, patch, opts) {
6052
+ var _a, _b;
6053
+ const reset = !!(opts == null ? void 0 : opts.resetDefaults);
6054
+ if (!doc || (patch === void 0 || !reset && (patch === null || !isPlainObject(patch) || !Object.keys(patch).length))) {
6055
+ return { doc, warnings: [] };
6056
+ }
6057
+ const anyDoc = doc;
6058
+ const atRoot = isPlainObject(anyDoc.animator);
6059
+ const atMeta = !atRoot && isPlainObject((_a = anyDoc.meta) == null ? void 0 : _a.animator);
6060
+ const current = atRoot ? anyDoc.animator : atMeta ? anyDoc.meta.animator : void 0;
6061
+ const warnings = [];
6062
+ if (atRoot && isPlainObject((_b = anyDoc.meta) == null ? void 0 : _b.animator)) {
6063
+ warnings.push("animator: doc.meta.animator is shadowed by doc.animator and was not patched");
6064
+ }
6065
+ let base = current;
6066
+ if (reset) {
6067
+ const kept = {};
6068
+ for (const k of CONTENT_KEYS) {
6069
+ if (isPlainObject(current) && current[k] !== void 0) kept[k] = current[k];
6070
+ }
6071
+ base = kept;
6072
+ }
6073
+ const merged = mergeAnimatorConfig(base, patch != null ? patch : {});
6074
+ warnings.push(...merged.warnings);
6075
+ if (merged.config === current) return { doc, warnings };
6076
+ if (atMeta) {
6077
+ return {
6078
+ doc: __spreadProps(__spreadValues({}, anyDoc), { meta: __spreadProps(__spreadValues({}, anyDoc.meta), { animator: merged.config }) }),
6079
+ warnings
6080
+ };
6081
+ }
6082
+ return { doc: __spreadProps(__spreadValues({}, anyDoc), { animator: merged.config }), warnings };
6083
+ }
6084
+
6085
+ // ../svg-animator-core/src/format/PxDocumentDiagnostic.ts
6086
+ var MAX_REPORTED = 6;
6087
+ var LEGACY_FLAT_KEYS = [
6088
+ ...PX_TIMELINE_SHARED_KEYS,
6089
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
6090
+ "fill",
6091
+ "resetOnFinish",
6092
+ "timelineSource",
6093
+ "scroll"
6094
+ ];
6095
+ var isLegacyFlatAnimatorKey = (w) => LEGACY_FLAT_KEYS.some((k) => w.indexOf("animator." + k + ":") >= 0);
6096
+ function diagnoseDocument(doc) {
6097
+ let all;
6098
+ try {
6099
+ all = validateDocument(doc);
6100
+ } catch (e) {
6101
+ return { problems: [], legacy: [] };
6102
+ }
6103
+ const problems = [];
6104
+ const legacy = [];
6105
+ for (const w of all) (isLegacyFlatAnimatorKey(w) ? legacy : problems).push(w);
6106
+ return { problems, legacy };
6107
+ }
6108
+ function reportDocumentDiagnostics(doc, where) {
6109
+ const { problems } = diagnoseDocument(doc);
6110
+ if (!problems.length) return;
6111
+ const shown = problems.slice(0, MAX_REPORTED);
6112
+ const more = problems.length - shown.length;
6113
+ console.warn(
6114
+ where + ": this document does not match the animation schema in " + problems.length + " place" + (problems.length === 1 ? "" : "s") + ".\n" + shown.map((p) => " - " + p).join("\n") + (more > 0 ? "\n \u2026 and " + more + " more" : "") + "\n\nIf you did not author these keys, the usual cause is a build that MANGLES PROPERTY NAMES. An animation document is data loaded at runtime, so renaming the property reads inside the player stops them matching the keys in the JSON, and the animation silently does nothing. Feed the published reserved-name list to your minifier \u2014 @pixodesk/svg-animator-web/mangle-reserved.json \u2014 see docs/library/minification.md."
6115
+ );
6116
+ }
6117
+
6118
+ // src/triggers/PxAnimatorTriggers.ts
5886
6119
  function setupAnimationTriggers(api, config) {
5887
6120
  const { startOn, outAction = "continue", scrollIntoViewThreshold = 0 } = config;
5888
6121
  const root = api.getRootElement();
@@ -5987,7 +6220,7 @@ var PixodeskAnimator = (() => {
5987
6220
  return api;
5988
6221
  }
5989
6222
 
5990
- // src/PxAnimatorFrameLoop.ts
6223
+ // src/engines/PxAnimatorFrameLoop.ts
5991
6224
  function getSelector(id) {
5992
6225
  return "#" + id;
5993
6226
  }
@@ -6047,11 +6280,10 @@ var PixodeskAnimator = (() => {
6047
6280
  return adapter;
6048
6281
  }
6049
6282
 
6050
- // src/PxAnimatorWebApi.ts
6283
+ // src/engines/PxAnimatorWebApi.ts
6051
6284
  function createCssKf(kf, t, propName, unsupportedSet) {
6052
- var _a, _b;
6053
- let value = (_a = kf.v) != null ? _a : kf.value;
6054
- const e = (_b = kf.e) != null ? _b : kf.easing;
6285
+ let value = kfValue(kf);
6286
+ const e = kfEasing(kf);
6055
6287
  const cssKf = {
6056
6288
  offset: t,
6057
6289
  easing: e && Array.isArray(e) ? "cubic-bezier(" + e.join(",") + ")" : void 0
@@ -6156,7 +6388,7 @@ var PixodeskAnimator = (() => {
6156
6388
  console.warn("createFrameLoopAnimator: No root element provided");
6157
6389
  }
6158
6390
  }
6159
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.waapi);
6391
+ const bindings = getNormalisedBindings(doc, PxTimelineEngine.native);
6160
6392
  const animations = [];
6161
6393
  const _iterations = config.iterations;
6162
6394
  let iterations;
@@ -6314,7 +6546,7 @@ var PixodeskAnimator = (() => {
6314
6546
  return api;
6315
6547
  }
6316
6548
 
6317
- // src/PxScrollDriver.ts
6549
+ // src/scroll/PxScrollDriver.ts
6318
6550
  function nativeRangeOffset(point, defaultFraction, view) {
6319
6551
  var _a, _b, _c;
6320
6552
  const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
@@ -6328,7 +6560,7 @@ var PixodeskAnimator = (() => {
6328
6560
  const scroll = config.scroll || {};
6329
6561
  const kind = (_a = scroll.kind) != null ? _a : "view";
6330
6562
  if (scroll.smoothing) {
6331
- console.warn('scroll timeline: `smoothing` needs the built-in driver \u2014 ignoring `driver: "native"`');
6563
+ console.warn("scroll timeline: `smoothing` needs the built-in driver \u2014 using the built-in driver instead of the browser timeline");
6332
6564
  return null;
6333
6565
  }
6334
6566
  const g = globalThis;
@@ -6345,7 +6577,7 @@ var PixodeskAnimator = (() => {
6345
6577
  timeline = new Ctor({ source, axis });
6346
6578
  }
6347
6579
  } catch (e) {
6348
- console.warn("scroll timeline: native timeline construction failed \u2014 falling back to the custom driver", e);
6580
+ console.warn("scroll timeline: native timeline construction failed \u2014 falling back to the player measuring progress itself", e);
6349
6581
  return null;
6350
6582
  }
6351
6583
  return {
@@ -6564,7 +6796,7 @@ var PixodeskAnimator = (() => {
6564
6796
  };
6565
6797
  }
6566
6798
 
6567
- // src/PxAnimatorBind.ts
6799
+ // src/engines/PxAnimatorBind.ts
6568
6800
  function finaliseAnimator(animatorConfig, callbacks, make) {
6569
6801
  let apiRef;
6570
6802
  let effectiveCallbacks = callbacks;
@@ -6579,8 +6811,8 @@ var PixodeskAnimator = (() => {
6579
6811
  }
6580
6812
  const res = make(effectiveCallbacks);
6581
6813
  apiRef = res;
6582
- if (animatorConfig.debugInstName) {
6583
- window[animatorConfig.debugInstName] = res;
6814
+ if (animatorConfig.debugGlobalName) {
6815
+ window[animatorConfig.debugGlobalName] = res;
6584
6816
  }
6585
6817
  return res;
6586
6818
  }
@@ -6588,10 +6820,10 @@ var PixodeskAnimator = (() => {
6588
6820
  const animatorConfig = getAnimatorConfig(doc) || {};
6589
6821
  if (isScrollTimeline(animatorConfig)) {
6590
6822
  return finaliseAnimator(animatorConfig, callbacks, (cb) => {
6591
- var _a, _b;
6823
+ var _a;
6592
6824
  let unpin = () => {
6593
6825
  };
6594
- if (animatorConfig.mode !== PxAnimatorMode.frames && ((_a = animatorConfig.scroll) == null ? void 0 : _a.driver) === "native" && rootElement) {
6826
+ if (mayUseNativeScrollTimeline(animatorConfig.engine) && rootElement) {
6595
6827
  unpin = applyScrollPin(rootElement, animatorConfig.scroll);
6596
6828
  const native = createNativeScrollTimeline(rootElement, animatorConfig);
6597
6829
  if (native) {
@@ -6599,7 +6831,7 @@ var PixodeskAnimator = (() => {
6599
6831
  doc,
6600
6832
  cb,
6601
6833
  rootElement,
6602
- animatorConfig.mode === PxAnimatorMode.waapi,
6834
+ isNativeForced(animatorConfig.engine),
6603
6835
  native
6604
6836
  );
6605
6837
  if (api2) {
@@ -6615,8 +6847,8 @@ var PixodeskAnimator = (() => {
6615
6847
  unpin = () => {
6616
6848
  };
6617
6849
  }
6618
- const api = (animatorConfig.mode !== PxAnimatorMode.frames ? createWebApiAnimator(doc, cb, rootElement, animatorConfig.mode === PxAnimatorMode.waapi) : null) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
6619
- const subject = ((_b = api.getRootElement) == null ? void 0 : _b.call(api)) || rootElement;
6850
+ const api = (animatorConfig.engine !== PxTimelineEngineExtra.js ? createWebApiAnimator(doc, cb, rootElement, isNativeForced(animatorConfig.engine)) : null) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
6851
+ const subject = ((_a = api.getRootElement) == null ? void 0 : _a.call(api)) || rootElement;
6620
6852
  if (subject) {
6621
6853
  unpin = applyScrollPin(subject, animatorConfig.scroll);
6622
6854
  const totalMs = scrollTotalDurationMs(animatorConfig);
@@ -6640,20 +6872,19 @@ var PixodeskAnimator = (() => {
6640
6872
  });
6641
6873
  }
6642
6874
  return finaliseAnimator(animatorConfig, callbacks, (cb) => {
6643
- if (animatorConfig.mode === PxAnimatorMode.frames) {
6875
+ if (animatorConfig.engine === PxTimelineEngineExtra.js) {
6644
6876
  return createFrameLoopAnimator(doc, adapter, cb, rootElement);
6645
6877
  }
6646
6878
  return createWebApiAnimator(
6647
6879
  doc,
6648
6880
  cb,
6649
6881
  rootElement,
6650
- animatorConfig.mode === PxAnimatorMode.waapi
6651
- // forcing waapi
6882
+ isNativeForced(animatorConfig.engine)
6652
6883
  ) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
6653
6884
  });
6654
6885
  }
6655
6886
 
6656
- // src/PxAnimatorDOM.ts
6887
+ // src/dom/PxAnimatorDOM.ts
6657
6888
  var SVG_NS = "http://www.w3.org/2000/svg";
6658
6889
  function createElement(tagName, normalisedProps, style, children, textContent) {
6659
6890
  if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
@@ -6711,18 +6942,24 @@ var PixodeskAnimator = (() => {
6711
6942
  return element;
6712
6943
  }
6713
6944
 
6714
- // src/PxAnimatorKeys.ts
6945
+ // src/shared/PxAnimatorKeys.ts
6715
6946
  var PX_ANIMATOR_DATA_KEY = "data";
6716
6947
 
6717
- // src/PxAnimator.ts
6948
+ // src/animator/PxAnimator.ts
6718
6949
  function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
6719
6950
  return bindWithEngineChoice(doc, adapter, callbacks, rootElement);
6720
6951
  }
6721
- function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
6952
+ function createAnimatorImpl(doc, adapter, callbacks, containerElement, config, resetDocDefaults) {
6722
6953
  const effectsWarnings = validateNodeEffects(doc);
6723
6954
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
6955
+ reportDocumentDiagnostics(doc, "[PxAnimator] createAnimator");
6956
+ if (config !== void 0 || resetDocDefaults) {
6957
+ const patched = applyAnimatorConfig(doc, config != null ? config : {}, { resetDefaults: !!resetDocDefaults });
6958
+ for (const w of patched.warnings) console.warn("[PxAnimator] config override:", w);
6959
+ doc = patched.doc;
6960
+ }
6724
6961
  const animatorConfig = getAnimatorConfig(doc) || {};
6725
- const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi;
6962
+ const engine = resolveTimelineEngine(animatorConfig.engine);
6726
6963
  doc = materialiseAllInTree(doc, engine);
6727
6964
  let rootElement = null;
6728
6965
  if (containerElement) {
@@ -6746,8 +6983,13 @@ var PixodeskAnimator = (() => {
6746
6983
  }
6747
6984
  return api;
6748
6985
  }
6986
+ function resolveAnimatorConfigOption(options) {
6987
+ const { config, duration, delay, iterations, startOn } = options;
6988
+ return foldAnimatorConfigShortcuts(config, { duration, delay, iterations, startOn });
6989
+ }
6749
6990
  function createAnimator(options) {
6750
- const { src, data, adapter, callbacks, container } = options;
6991
+ const { src, data, adapter, callbacks, container, resetDocDefaults } = options;
6992
+ const config = resolveAnimatorConfigOption(options);
6751
6993
  if (data !== void 0 && src !== void 0) {
6752
6994
  throw new Error("createAnimator: provide either `src` or `data`, not both");
6753
6995
  }
@@ -6755,7 +6997,7 @@ var PixodeskAnimator = (() => {
6755
6997
  throw new Error("createAnimator: either `src` or `data` is required");
6756
6998
  }
6757
6999
  if (data !== void 0) {
6758
- return createAnimatorImpl(data, adapter, callbacks, container);
7000
+ return createAnimatorImpl(data, adapter, callbacks, container, config, resetDocDefaults);
6759
7001
  }
6760
7002
  let animator = null;
6761
7003
  let pending = [];
@@ -6770,7 +7012,7 @@ var PixodeskAnimator = (() => {
6770
7012
  fetch(src).then((res) => res.json()).then((json) => {
6771
7013
  if (destroyed) return;
6772
7014
  if (isPxElementFileFormat(json)) {
6773
- animator = createAnimatorImpl(json, adapter, callbacks, container);
7015
+ animator = createAnimatorImpl(json, adapter, callbacks, container, config, resetDocDefaults);
6774
7016
  const queued = pending;
6775
7017
  pending = null;
6776
7018
  queued == null ? void 0 : queued.forEach((call) => call(animator));