@pixodesk/svg-animator-core 1.0.39 → 1.0.40

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
@@ -55,9 +55,7 @@ __export(index_exports, {
55
55
  CSS_ONLY_STYLE_PROPS: () => CSS_ONLY_STYLE_PROPS,
56
56
  DEFAULT_DURATION_MS: () => DEFAULT_DURATION_MS,
57
57
  DISALLOWED_SVG_TAGS_LOWER: () => DISALLOWED_SVG_TAGS_LOWER,
58
- INTERNAL_ATTRS: () => INTERNAL_ATTRS,
59
58
  LOOP_JUMP_SHIFT_MS: () => LOOP_JUMP_SHIFT_MS,
60
- MISSING_GLYPH_CLASS_NAME: () => MISSING_GLYPH_CLASS_NAME,
61
59
  PCT_BASED_ATTR_NAMES: () => PCT_BASED_ATTR_NAMES,
62
60
  PLAYER_WIRE_STEPS: () => PLAYER_WIRE_STEPS,
63
61
  PLAYER_WIRE_VERSION: () => PLAYER_WIRE_VERSION,
@@ -70,18 +68,15 @@ __export(index_exports, {
70
68
  PX_UNKNOWN_KEY_ERROR: () => PX_UNKNOWN_KEY_ERROR,
71
69
  PxAlongPathMode: () => PxAlongPathMode,
72
70
  PxAnimatedSvgDocumentSchema: () => PxAnimatedSvgDocumentSchema,
73
- PxAnimationDefinitionSchema: () => PxAnimationDefinitionSchema,
74
71
  PxAnimatorConfigSchema: () => PxAnimatorConfigSchema,
75
72
  PxAttrValueSchema: () => PxAttrValueSchema,
76
73
  PxBezierPathSchema: () => PxBezierPathSchema,
77
- PxBindingSchema: () => PxBindingSchema,
78
74
  PxClipPathEffectSchema: () => PxClipPathEffectSchema,
79
75
  PxCloneEffectSchema: () => PxCloneEffectSchema,
80
76
  PxCloneWithout: () => PxCloneWithout,
81
77
  PxControlMode: () => PxControlMode,
82
78
  PxDefsSchema: () => PxDefsSchema,
83
79
  PxDiagnosticKind: () => PxDiagnosticKind,
84
- PxEasingOrRefSchema: () => PxEasingOrRefSchema,
85
80
  PxEffectsSchema: () => PxEffectsSchema,
86
81
  PxElementAnimationSchema: () => PxElementAnimationSchema,
87
82
  PxFillGradientEffectSchema: () => PxFillGradientEffectSchema,
@@ -115,7 +110,6 @@ __export(index_exports, {
115
110
  PxScrollSchema: () => PxScrollSchema,
116
111
  PxScrollSource: () => PxScrollSource,
117
112
  PxStartOn: () => PxStartOn,
118
- PxStrokeGradientEffectSchema: () => PxStrokeGradientEffectSchema,
119
113
  PxStrokeTrimEffectSchema: () => PxStrokeTrimEffectSchema,
120
114
  PxStrokeTrimSubPaths: () => PxStrokeTrimSubPaths,
121
115
  PxSvgNodeExtra: () => PxSvgNodeExtra,
@@ -125,7 +119,6 @@ __export(index_exports, {
125
119
  PxTextPathSpacing: () => PxTextPathSpacing,
126
120
  PxTimelineEngine: () => PxTimelineEngine,
127
121
  PxTimelineEngineExtra: () => PxTimelineEngineExtra,
128
- PxTimelinePinSchema: () => PxTimelinePinSchema,
129
122
  PxTimelineSchema: () => PxTimelineSchema,
130
123
  PxTransformByEffectSchema: () => PxTransformByEffectSchema,
131
124
  PxTransformPartsSchema: () => PxTransformPartsSchema,
@@ -141,13 +134,11 @@ __export(index_exports, {
141
134
  applyAnimatorConfig: () => applyAnimatorConfig,
142
135
  applyPlayerEffects: () => applyPlayerEffects,
143
136
  applyWireSteps: () => applyWireSteps,
144
- applyWireStepsDown: () => applyWireStepsDown,
145
137
  bezierToSvgPath: () => bezierToSvgPath,
146
138
  calcAnimationValues: () => calcAnimationValues,
147
139
  camelCaseToKebabWordIfNeeded: () => camelCaseToKebabWordIfNeeded,
148
140
  clamp: () => clamp,
149
141
  clampSeekMs: () => clampSeekMs,
150
- collectSampleTimes: () => collectSampleTimes,
151
142
  compareWireVersion: () => compareWireVersion,
152
143
  composeTransformParts: () => composeTransformParts,
153
144
  controlModeTakesOverTrigger: () => controlModeTakesOverTrigger,
@@ -163,7 +154,6 @@ __export(index_exports, {
163
154
  diffFieldUniverse: () => diffFieldUniverse,
164
155
  diffInEffect: () => diffInEffect,
165
156
  downgradePlayerDocument: () => downgradePlayerDocument,
166
- evaluateMotionPathSegment: () => evaluateMotionPathSegment,
167
157
  extendedPathForBrowser: () => extendedPathForBrowser,
168
158
  flattenAnimatorTimeline: () => flattenAnimatorTimeline,
169
159
  foldTimelineOverride: () => foldTimelineOverride,
@@ -176,46 +166,33 @@ __export(index_exports, {
176
166
  getDefs: () => getDefs,
177
167
  getNormalizedBindings: () => getNormalizedBindings,
178
168
  getNormalizedProps: () => getNormalizedProps,
179
- interpolateBeziers: () => interpolateBeziers,
180
169
  interpolateValue: () => interpolateValue,
181
170
  isNativeForced: () => isNativeForced,
182
171
  isPxElementFileFormat: () => isPxElementFileFormat,
183
172
  isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
184
173
  isScrollTimeline: () => isScrollTimeline,
185
174
  isValidPlaybackRate: () => isValidPlaybackRate,
186
- jsonElementFactory: () => jsonElementFactory,
187
175
  kebabToCamelCaseWord: () => kebabToCamelCaseWord,
188
176
  kfEasing: () => kfEasing,
189
- kfTangentIn: () => kfTangentIn,
190
- kfTangentOut: () => kfTangentOut,
191
- kfTime: () => kfTime,
192
177
  kfValue: () => kfValue,
193
178
  layoutGlyphTextChars: () => layoutGlyphTextChars,
194
179
  materializeAllInTree: () => materializeAllInTree,
195
- materializeAnimatedUseInstances: () => materializeAnimatedUseInstances,
196
180
  materializeGlyphText: () => materializeGlyphText,
197
181
  materializeGlyphTextAlongPath: () => materializeGlyphTextAlongPath,
198
- materializeGlyphTextHorizontal: () => materializeGlyphTextHorizontal,
199
- materializeInternalLoopsInPropAnim: () => materializeInternalLoopsInPropAnim,
200
- materializeInternalLoopsInTree: () => materializeInternalLoopsInTree,
201
182
  materializeMotionPathInPropAnim: () => materializeMotionPathInPropAnim,
202
- materializeMotionPathsInTree: () => materializeMotionPathsInTree,
203
183
  mayUseNativeScrollTimeline: () => mayUseNativeScrollTimeline,
204
184
  mergeAnimatorConfig: () => mergeAnimatorConfig,
205
185
  mergeStaticTransformIntoAnimDef: () => mergeStaticTransformIntoAnimDef,
206
186
  nestAnimatorTimeline: () => nestAnimatorTimeline,
207
- parseTransformParts: () => parseTransformParts,
208
187
  parseWireVersion: () => parseWireVersion,
209
188
  planSchemaRelease: () => planSchemaRelease,
210
189
  progressSpanMs: () => progressSpanMs,
211
190
  progressToTimeMs: () => progressToTimeMs,
212
- propAnimIsMotionPath: () => propAnimIsMotionPath,
213
191
  px: () => px,
214
192
  readWireVersion: () => readWireVersion,
215
193
  releaseLogProblems: () => releaseLogProblems,
216
194
  reportDocumentDiagnostics: () => reportDocumentDiagnostics,
217
195
  resolveControlMode: () => resolveControlMode,
218
- resolveStyle: () => resolveStyle,
219
196
  resolveTimelineEngine: () => resolveTimelineEngine,
220
197
  resolveTrigger: () => resolveTrigger,
221
198
  reverseEasing: () => reverseEasing,
@@ -228,609 +205,103 @@ __export(index_exports, {
228
205
  scrollTotalDurationMs: () => scrollTotalDurationMs,
229
206
  scrollViewProgress: () => scrollViewProgress,
230
207
  seekCeilingMs: () => seekCeilingMs,
231
- shiftAnimatable: () => shiftAnimatable,
232
208
  splitEasing: () => splitEasing,
233
209
  subdivideCubicBezier: () => subdivideCubicBezier,
234
210
  timeToProgress: () => timeToProgress,
235
211
  toRGBA: () => toRGBA,
236
212
  validateDocument: () => validateDocument,
237
213
  validateNodeEffects: () => validateNodeEffects,
238
- versionAdvice: () => versionAdvice,
239
- visualModelAt: () => visualModelAt
214
+ versionAdvice: () => versionAdvice
240
215
  });
241
216
  module.exports = __toCommonJS(index_exports);
242
217
 
243
- // src/util/PxAnimatorUtil.ts
244
- function bezierToSvgPath(path, forceCurves = false) {
245
- var _a2, _b, _c, _d;
246
- const v = path.v;
247
- const i = path.i;
248
- const o = path.o;
249
- const c = path.c;
250
- if (!v.length) return "";
251
- const d = [];
252
- const len = v.length;
253
- d.push("M" + v[0][0] + "," + v[0][1]);
254
- for (let idx = 1; idx < len; idx++) {
255
- const prevV = v[idx - 1];
256
- const prevO = (_a2 = o == null ? void 0 : o[idx - 1]) != null ? _a2 : prevV;
257
- const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
258
- const currV = v[idx];
259
- const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
260
- if (isLine) {
261
- d.push("L" + currV[0] + "," + currV[1]);
262
- } else {
263
- d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
264
- }
265
- }
266
- if (c && len > 0) {
267
- const lastV = v[len - 1];
268
- const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
269
- const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
270
- const firstV = v[0];
271
- const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
272
- if (!isLine) {
273
- d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
274
- }
275
- d.push("z");
218
+ // src/schema/PxSchema.ts
219
+ var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
220
+ function pathStr(path) {
221
+ if (!path.length) return ".";
222
+ let result = "";
223
+ for (const seg of path) {
224
+ if (seg.startsWith("[")) result += seg;
225
+ else result += (result ? "." : "") + seg;
276
226
  }
277
- return d.join("");
278
- }
279
- function interpolateNum(a, b, t) {
280
- return a + (b - a) * t;
227
+ return result;
281
228
  }
282
- function interpolateVec(a, b, t) {
283
- const res = [];
284
- const count = Math.max(a.length, b.length);
285
- for (let i = 0; i < count; i++) {
286
- res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
229
+ var Base = class {
230
+ _canSanitize(raw) {
231
+ return this.isValid(raw);
287
232
  }
288
- return res;
289
- }
290
- function interpolateColor(a, b, t) {
291
- return [
292
- interpolateNum(a[0] || 0, b[0] || 0, t),
293
- interpolateNum(a[1] || 0, b[1] || 0, t),
294
- interpolateNum(a[2] || 0, b[2] || 0, t),
295
- interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
296
- ];
297
- }
298
- function interpolateBeziers(paths1, paths2, progress) {
299
- const count = Math.max(paths1.length, paths2.length);
300
- const res = [];
301
- for (let i = 0; i < count; i++) {
302
- res.push(interpolateBezier(paths1[i], paths2[i], progress));
233
+ optional() {
234
+ return new Optional(this);
303
235
  }
304
- return res;
305
- }
306
- function interpolateBezier(path1, path2, progress) {
307
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
308
- if (!path1 || !path2) return path1 || path2 || { v: [] };
309
- const t = Math.min(Math.max(progress, 0), 1);
310
- const len = Math.min(path1.v.length, path2.v.length);
311
- const v = [];
312
- const i = [];
313
- const o = [];
314
- for (let idx = 0; idx < len; idx++) {
315
- const v1 = path1.v[idx];
316
- const v2 = path2.v[idx];
317
- v.push(interpolateVec(v1, v2, t));
318
- const i1 = (_b = (_a2 = path1.i) == null ? void 0 : _a2[idx]) != null ? _b : v1;
319
- const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
320
- i.push(interpolateVec(i1, i2, t));
321
- const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
322
- const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
323
- o.push(interpolateVec(o1, o2, t));
236
+ };
237
+ var Optional = class extends Base {
238
+ constructor(inner) {
239
+ super();
240
+ this.inner = inner;
241
+ this._default = void 0;
324
242
  }
325
- return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
326
- }
327
- function remap(value, inMin, inMax, outMin, outMax) {
328
- if (inMax === inMin) return outMin;
329
- const t = (value - inMin) / (inMax - inMin);
330
- return outMin + t * (outMax - outMin);
331
- }
332
- function solveCubicBezierX(p1x, p2x, x) {
333
- if (x <= 0) return 0;
334
- if (x >= 1) return 1;
335
- const cx = 3 * p1x;
336
- const bx = 3 * (p2x - p1x) - cx;
337
- const ax = 1 - cx - bx;
338
- function sampleX(t) {
339
- return ((ax * t + bx) * t + cx) * t;
243
+ sanitize(raw) {
244
+ if (raw === void 0 || raw === null) return void 0;
245
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
340
246
  }
341
- function sampleDX(t) {
342
- return (3 * ax * t + 2 * bx) * t + cx;
247
+ isValid(raw, ctx, path) {
248
+ if (raw === void 0 || raw === null) return true;
249
+ return this.inner.isValid(raw, ctx, path);
343
250
  }
344
- let t2 = x;
345
- let t0 = 0;
346
- let t1 = 1;
347
- for (let i = 0; i < 8; i++) {
348
- const x2 = sampleX(t2) - x;
349
- if (Math.abs(x2) < 1e-6) return t2;
350
- const d2 = sampleDX(t2);
351
- if (Math.abs(d2) < 1e-6) break;
352
- t2 -= x2 / d2;
251
+ _canSanitize(raw) {
252
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
353
253
  }
354
- t2 = x;
355
- while (t0 < t1) {
356
- const x2 = sampleX(t2);
357
- if (Math.abs(x2 - x) < 1e-6) return t2;
358
- if (x > x2) t0 = t2;
359
- else t1 = t2;
360
- t2 = (t1 + t0) / 2;
254
+ };
255
+ var Str = class extends Base {
256
+ constructor(_default = "") {
257
+ super();
258
+ this._default = _default;
361
259
  }
362
- return t2;
363
- }
364
- function cubicBezier(easing) {
365
- const [p1x, p1y, p2x, p2y] = easing;
366
- const cy = 3 * p1y;
367
- const by = 3 * (p2y - p1y) - cy;
368
- const ay = 1 - cy - by;
369
- function sampleCurveY(t) {
370
- return ((ay * t + by) * t + cy) * t;
260
+ sanitize(raw) {
261
+ return typeof raw === "string" ? raw : this._default;
371
262
  }
372
- return function(x) {
373
- return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
374
- };
375
- }
376
- function lerp2(a, b, t) {
377
- return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
378
- }
379
- function subdivideCubicBezier(p0, p1, p2, p3, t) {
380
- const q0 = lerp2(p0, p1, t);
381
- const q1 = lerp2(p1, p2, t);
382
- const q2 = lerp2(p2, p3, t);
383
- const r0 = lerp2(q0, q1, t);
384
- const r1 = lerp2(q1, q2, t);
385
- const s = lerp2(r0, r1, t);
386
- return {
387
- left: [p0, q0, r0, s],
388
- right: [s, r1, q2, p3]
389
- };
390
- }
391
- function splitEasing(easing, xFraction) {
392
- if (!easing) return { left: void 0, right: void 0 };
393
- if (xFraction <= 0) return { left: void 0, right: easing };
394
- if (xFraction >= 1) return { left: easing, right: void 0 };
395
- const [x1, y1, x2, y2] = easing;
396
- const t = solveCubicBezierX(x1, x2, xFraction);
397
- const p0 = [0, 0];
398
- const p1 = [x1, y1];
399
- const p2 = [x2, y2];
400
- const p3 = [1, 1];
401
- const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
402
- const sx = left[3][0];
403
- const sy = left[3][1];
404
- let leftEasing;
405
- if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
406
- leftEasing = [
407
- left[1][0] / sx,
408
- left[1][1] / sy,
409
- left[2][0] / sx,
410
- left[2][1] / sy
411
- ];
263
+ isValid(raw, ctx, path) {
264
+ if (typeof raw === "string") return true;
265
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
266
+ return false;
412
267
  }
413
- let rightEasing;
414
- const rx = 1 - sx;
415
- const ry = 1 - sy;
416
- if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
417
- rightEasing = [
418
- (right[1][0] - sx) / rx,
419
- (right[1][1] - sy) / ry,
420
- (right[2][0] - sx) / rx,
421
- (right[2][1] - sy) / ry
422
- ];
268
+ };
269
+ var Num = class extends Base {
270
+ constructor(_default = 0) {
271
+ super();
272
+ this._default = _default;
423
273
  }
424
- return { left: leftEasing, right: rightEasing };
425
- }
426
- function reverseEasing(easing) {
427
- if (!easing) return void 0;
428
- return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
429
- }
430
- function toRGBA(color) {
431
- const r = Math.round(color[0] * 255);
432
- const g = Math.round(color[1] * 255);
433
- const b = Math.round(color[2] * 255);
434
- return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
435
- }
436
- function parseRgba(s) {
437
- var _a2;
438
- const inner = (_a2 = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a2[1];
439
- if (!inner) throw new Error("Invalid rgb/rgba format");
440
- const parts = inner.split(",").map((v) => +v.trim());
441
- return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
442
- }
443
- function parseHex(s) {
444
- const hex = s.slice(1);
445
- const isShort = hex.length <= 4;
446
- const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
447
- const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
448
- const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
449
- const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
450
- const result = [
451
- parseInt(r, 16) / 255,
452
- parseInt(g, 16) / 255,
453
- parseInt(b, 16) / 255
454
- ];
455
- if (a !== null) {
456
- result.push(parseInt(a, 16) / 255);
274
+ sanitize(raw) {
275
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
457
276
  }
458
- return result;
459
- }
460
- function parseColor(s) {
461
- if (!s) return void 0;
462
- if (Array.isArray(s)) return s;
463
- if (typeof s !== "string") return void 0;
464
- if (s.startsWith("#")) {
465
- return parseHex(s);
466
- } else if (s.startsWith("rgb")) {
467
- return parseRgba(s);
468
- } else {
469
- console.warn("Unsupported color format: " + s);
277
+ isValid(raw, ctx, path) {
278
+ if (typeof raw === "number" && isFinite(raw)) return true;
279
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
280
+ return false;
470
281
  }
471
- return void 0;
472
- }
473
- var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
474
- var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
475
- var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
476
- function composeTransformParts(parts, opts) {
477
- var _a2;
478
- if (!parts) return "";
479
- const withUnits = (_a2 = opts == null ? void 0 : opts.withUnits) != null ? _a2 : true;
480
- const segs = [];
481
- const t = parts.translate;
482
- const o = parts.origin;
483
- const r = parts.rotate;
484
- const k = parts.skew;
485
- const s = parts.scale;
486
- const tu = withUnits ? "px" : "";
487
- const ru = withUnits ? "deg" : "";
488
- if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
489
- if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
490
- if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
491
- if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
492
- if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
493
- if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
494
- return segs.join("");
495
- }
496
- function parseTransformParts(str2) {
497
- var _a2, _b;
498
- if (!str2 || typeof str2 !== "string") return void 0;
499
- const out = {};
500
- const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
501
- const order = ["translate", "rotate", "skewX", "scale"];
502
- let lastIdx = -1;
503
- let m;
504
- while ((m = re.exec(str2)) !== null) {
505
- const fn = m[1];
506
- const idx = order.indexOf(fn);
507
- if (idx < 0 || idx <= lastIdx) return void 0;
508
- lastIdx = idx;
509
- const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
510
- if (nums.some((n) => Number.isNaN(n))) return void 0;
511
- if (fn === "translate") {
512
- if (nums.length < 1 || nums.length > 2) return void 0;
513
- out.translate = [nums[0], (_a2 = nums[1]) != null ? _a2 : 0];
514
- } else if (fn === "rotate") {
515
- if (nums.length !== 1) return void 0;
516
- out.rotate = nums[0];
517
- } else if (fn === "skewX") {
518
- if (nums.length !== 1) return void 0;
519
- out.skew = nums[0];
520
- } else {
521
- if (nums.length < 1 || nums.length > 2) return void 0;
522
- out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
523
- }
282
+ };
283
+ var Bool = class extends Base {
284
+ constructor(_default = false) {
285
+ super();
286
+ this._default = _default;
524
287
  }
525
- if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
526
- return Object.keys(out).length ? out : void 0;
527
- }
528
- var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
529
- var DEFAULT_DURATION_MS = 1e3;
530
- function kebabToCamelCaseWord(kebab) {
531
- return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
532
- }
533
- function isCamelCaseWord(word) {
534
- return !word.includes("-") && /[a-z][A-Z]/.test(word);
535
- }
536
- var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
537
- // Transform/positioning
538
- "viewBox",
539
- "preserveAspectRatio",
540
- // Gradient
541
- "gradientUnits",
542
- "gradientTransform",
543
- "spreadMethod",
544
- // Pattern
545
- "patternUnits",
546
- "patternContentUnits",
547
- "patternTransform",
548
- // Clipping/masking
549
- "clipPathUnits",
550
- "maskUnits",
551
- "maskContentUnits",
552
- // Marker (SVG spec keeps these camelCase, like viewBox)
553
- "markerUnits",
554
- "markerWidth",
555
- "markerHeight",
556
- "refX",
557
- "refY",
558
- // Text
559
- "textLength",
560
- "lengthAdjust",
561
- "startOffset",
562
- // Filter
563
- "filterUnits",
564
- "primitiveUnits",
565
- "tableValues",
566
- // feFuncR/G/B/A transfer table (type="table")
567
- "stdDeviation",
568
- "baseFrequency",
569
- "numOctaves",
570
- "surfaceScale",
571
- "diffuseConstant",
572
- "specularConstant",
573
- "specularExponent",
574
- "kernelMatrix",
575
- "kernelUnitLength",
576
- "edgeMode",
577
- "preserveAlpha",
578
- "targetX",
579
- "targetY"
580
- // // Animation
581
- // 'attributeName',
582
- // 'attributeType',
583
- // 'calcMode',
584
- // 'keyTimes',
585
- // 'keySplines',
586
- // 'repeatCount',
587
- // 'repeatDur'
588
- ]);
589
- function camelCaseToKebabWordIfNeeded(camel) {
590
- return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
591
- }
592
- function clamp(value, min, max) {
593
- return Math.max(min, Math.min(value, max));
594
- }
595
- function bezier2D_pointAt(P0, P1, P2, P3, t) {
596
- if (t <= 0) return [P0[0], P0[1]];
597
- if (t >= 1) return [P3[0], P3[1]];
598
- const u = 1 - t;
599
- const u2 = u * u;
600
- const u3 = u2 * u;
601
- const t2 = t * t;
602
- const t3 = t2 * t;
603
- const w0 = u3;
604
- const w1 = 3 * t * u2;
605
- const w2 = 3 * t2 * u;
606
- const w3 = t3;
607
- return [
608
- w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
609
- w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
610
- ];
611
- }
612
- var BEZIER_T_NUDGE = 1e-4;
613
- function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
614
- const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
615
- if (result[0] === 0 && result[1] === 0) {
616
- const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
617
- return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
288
+ sanitize(raw) {
289
+ return typeof raw === "boolean" ? raw : this._default;
618
290
  }
619
- return result;
620
- }
621
- function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
622
- const u = 1 - t;
623
- const a = 3 * u * u;
624
- const b = 6 * t * u;
625
- const c = 3 * t * t;
626
- return [
627
- a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
628
- a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
629
- ];
630
- }
631
- function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
632
- const n = steps + 1;
633
- const ts = new Float64Array(n);
634
- const ds = new Float64Array(n);
635
- let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
636
- ts[0] = 0;
637
- ds[0] = 0;
638
- let cum = 0;
639
- for (let i = 1; i < n; i++) {
640
- const t = i / steps;
641
- const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
642
- const dx = cur[0] - prev[0];
643
- const dy = cur[1] - prev[1];
644
- cum += Math.sqrt(dx * dx + dy * dy);
645
- ts[i] = t;
646
- ds[i] = cum;
647
- prev = cur;
291
+ isValid(raw, ctx, path) {
292
+ if (typeof raw === "boolean") return true;
293
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
294
+ return false;
648
295
  }
649
- return { ts, ds };
650
- }
651
- function bezier2D_tForDistance(lut, distance) {
652
- const { ts, ds } = lut;
653
- const last = ds.length - 1;
654
- if (distance <= 0) return ts[0];
655
- if (distance >= ds[last]) return ts[last];
656
- let lo = 1;
657
- let hi = last;
658
- while (lo < hi) {
659
- const mid = lo + hi >>> 1;
660
- if (ds[mid] < distance) lo = mid + 1;
661
- else hi = mid;
296
+ };
297
+ var Literal = class extends Base {
298
+ constructor(value) {
299
+ super();
300
+ this.value = value;
301
+ this._default = value;
662
302
  }
663
- const dPrev = ds[hi - 1];
664
- const dCur = ds[hi];
665
- const span = dCur - dPrev;
666
- const frac = span > 0 ? (distance - dPrev) / span : 0;
667
- return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
668
- }
669
- function bezier2D_arcAtT(lut, t) {
670
- const { ts, ds } = lut;
671
- const last = ts.length - 1;
672
- if (t <= ts[0]) return ds[0];
673
- if (t >= ts[last]) return ds[last];
674
- let lo = 1, hi = last;
675
- while (lo < hi) {
676
- const mid = lo + hi >>> 1;
677
- if (ts[mid] < t) lo = mid + 1;
678
- else hi = mid;
679
- }
680
- const tPrev = ts[hi - 1];
681
- const span = ts[hi] - tPrev;
682
- const frac = span > 0 ? (t - tPrev) / span : 0;
683
- return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
684
- }
685
- function invertEasing(easing) {
686
- if (!easing) return (y) => y;
687
- const flipped = [easing[1], easing[0], easing[3], easing[2]];
688
- return cubicBezier(flipped);
689
- }
690
-
691
- // src/playback/PxScrollMath.ts
692
- function isScrollTimeline(config) {
693
- return (config == null ? void 0 : config.timelineSource) === "scroll";
694
- }
695
- function scrollTotalDurationMs(config) {
696
- const duration = typeof (config == null ? void 0 : config.duration) === "number" && config.duration > 0 ? config.duration : DEFAULT_DURATION_MS;
697
- const iterations = typeof (config == null ? void 0 : config.iterations) === "number" && config.iterations > 0 ? config.iterations : 1;
698
- return duration * iterations;
699
- }
700
- function scrollPhaseInterval(phase, subjectSize, scrollportSize) {
701
- const s = subjectSize, vp = scrollportSize;
702
- switch (phase) {
703
- case "cover":
704
- return [0, s + vp];
705
- case "entry":
706
- return [0, Math.min(s, vp)];
707
- case "contain":
708
- return [Math.min(s, vp), Math.max(s, vp)];
709
- case "exit":
710
- return [Math.max(s, vp), s + vp];
711
- case "entry-crossing":
712
- return [0, s];
713
- case "exit-crossing":
714
- return [vp, s + vp];
715
- }
716
- }
717
- var DEFAULT_PHASE = "cover";
718
- function resolveRangePointU(point, defaultFraction, subjectSize, scrollportSize) {
719
- var _a2;
720
- const [u0, u1] = scrollPhaseInterval((_a2 = point == null ? void 0 : point.phase) != null ? _a2 : DEFAULT_PHASE, subjectSize, scrollportSize);
721
- const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
722
- return u0 + fraction * (u1 - u0);
723
- }
724
- function scrollViewProgress(subjectStart, subjectSize, scrollportSize, range) {
725
- const u = scrollportSize - subjectStart;
726
- const uStart = resolveRangePointU(range == null ? void 0 : range.start, 0, subjectSize, scrollportSize);
727
- const uEnd = resolveRangePointU(range == null ? void 0 : range.end, 1, subjectSize, scrollportSize);
728
- if (uEnd <= uStart) return u >= uEnd ? 1 : 0;
729
- return clamp((u - uStart) / (uEnd - uStart), 0, 1);
730
- }
731
- function scrollOffsetProgress(offset, maxOffset, range) {
732
- var _a2, _b;
733
- const raw = maxOffset > 0 ? clamp(offset / maxOffset, 0, 1) : 1;
734
- const start = typeof ((_a2 = range == null ? void 0 : range.start) == null ? void 0 : _a2.fraction) === "number" ? range.start.fraction : 0;
735
- const end = typeof ((_b = range == null ? void 0 : range.end) == null ? void 0 : _b.fraction) === "number" ? range.end.fraction : 1;
736
- if (end <= start) return raw >= end ? 1 : 0;
737
- return clamp((raw - start) / (end - start), 0, 1);
738
- }
739
- function scrollResolveAxis(axis, writingMode) {
740
- const a = axis != null ? axis : "block";
741
- if (a === "x" || a === "y") return a;
742
- const vertical = !!writingMode && writingMode.startsWith("vertical");
743
- if (a === "inline") return vertical ? "y" : "x";
744
- return vertical ? "x" : "y";
745
- }
746
-
747
- // src/schema/PxSchema.ts
748
- var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
749
- function pathStr(path) {
750
- if (!path.length) return ".";
751
- let result = "";
752
- for (const seg of path) {
753
- if (seg.startsWith("[")) result += seg;
754
- else result += (result ? "." : "") + seg;
755
- }
756
- return result;
757
- }
758
- var Base = class {
759
- _canSanitize(raw) {
760
- return this.isValid(raw);
761
- }
762
- optional() {
763
- return new Optional(this);
764
- }
765
- };
766
- var Optional = class extends Base {
767
- constructor(inner) {
768
- super();
769
- this.inner = inner;
770
- this._default = void 0;
771
- }
772
- sanitize(raw) {
773
- if (raw === void 0 || raw === null) return void 0;
774
- return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
775
- }
776
- isValid(raw, ctx, path) {
777
- if (raw === void 0 || raw === null) return true;
778
- return this.inner.isValid(raw, ctx, path);
779
- }
780
- _canSanitize(raw) {
781
- return raw === void 0 || raw === null || this.inner._canSanitize(raw);
782
- }
783
- };
784
- var Str = class extends Base {
785
- constructor(_default = "") {
786
- super();
787
- this._default = _default;
788
- }
789
- sanitize(raw) {
790
- return typeof raw === "string" ? raw : this._default;
791
- }
792
- isValid(raw, ctx, path) {
793
- if (typeof raw === "string") return true;
794
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
795
- return false;
796
- }
797
- };
798
- var Num = class extends Base {
799
- constructor(_default = 0) {
800
- super();
801
- this._default = _default;
802
- }
803
- sanitize(raw) {
804
- return typeof raw === "number" && isFinite(raw) ? raw : this._default;
805
- }
806
- isValid(raw, ctx, path) {
807
- if (typeof raw === "number" && isFinite(raw)) return true;
808
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
809
- return false;
810
- }
811
- };
812
- var Bool = class extends Base {
813
- constructor(_default = false) {
814
- super();
815
- this._default = _default;
816
- }
817
- sanitize(raw) {
818
- return typeof raw === "boolean" ? raw : this._default;
819
- }
820
- isValid(raw, ctx, path) {
821
- if (typeof raw === "boolean") return true;
822
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
823
- return false;
824
- }
825
- };
826
- var Literal = class extends Base {
827
- constructor(value) {
828
- super();
829
- this.value = value;
830
- this._default = value;
831
- }
832
- sanitize(raw) {
833
- return raw === this.value ? this.value : this._default;
303
+ sanitize(raw) {
304
+ return raw === this.value ? this.value : this._default;
834
305
  }
835
306
  isValid(raw, ctx, path) {
836
307
  if (raw === this.value) return true;
@@ -1455,129 +926,6 @@ function downgradePlayerDocument(doc, target) {
1455
926
  return applyWireStepsDown(doc, { steps: PLAYER_WIRE_STEPS, target, readerReadsEditorPart: false });
1456
927
  }
1457
928
 
1458
- // src/version/PxSchemaFieldUniverse.ts
1459
- function schemaFieldUniverse(root) {
1460
- const fields = /* @__PURE__ */ new Set();
1461
- const enumerated = /* @__PURE__ */ new Set();
1462
- const queue = [{ schema: root, path: "" }];
1463
- while (queue.length) {
1464
- const { schema, path } = queue.shift();
1465
- const d = describeSchema(schema);
1466
- switch (d.kind) {
1467
- case "shape": {
1468
- if (enumerated.has(schema)) break;
1469
- enumerated.add(schema);
1470
- for (const key of Object.keys(d.shape)) {
1471
- const id = path ? path + "." + key : key;
1472
- fields.add(id);
1473
- queue.push({ schema: d.shape[key], path: id });
1474
- }
1475
- if (d.openValue) queue.push({ schema: d.openValue, path: path + "{*}" });
1476
- break;
1477
- }
1478
- case "optional":
1479
- queue.push({ schema: d.inner, path });
1480
- break;
1481
- case "array":
1482
- queue.push({ schema: d.item, path: path + "[]" });
1483
- break;
1484
- case "lazy":
1485
- queue.push({ schema: d.resolved, path });
1486
- break;
1487
- case "record":
1488
- queue.push({ schema: d.value, path: path + "{*}" });
1489
- break;
1490
- case "union":
1491
- d.members.forEach((member, i) => queue.push({ schema: member, path: path + "|" + i }));
1492
- break;
1493
- case "discriminatedUnion":
1494
- for (const member of d.members) queue.push({ schema: member, path: path + "|" + discriminantOf(member, d.key) });
1495
- break;
1496
- default:
1497
- break;
1498
- }
1499
- }
1500
- return [...fields].sort();
1501
- }
1502
- function discriminantOf(member, key) {
1503
- const d = describeSchema(member);
1504
- if (d.kind !== "shape") return "?";
1505
- const keySchema = d.shape[key];
1506
- if (keySchema === void 0) return "?";
1507
- const kd = describeSchema(keySchema);
1508
- return String((kd.kind === "optional" ? kd.inner : keySchema)._default);
1509
- }
1510
-
1511
- // src/version/PxSchemaRelease.ts
1512
- function diffFieldUniverse(previous, current) {
1513
- const prev = new Set(previous);
1514
- const cur = new Set(current);
1515
- return {
1516
- added: current.filter((k) => !prev.has(k)).sort(),
1517
- removed: previous.filter((k) => !cur.has(k)).sort()
1518
- };
1519
- }
1520
- function planSchemaRelease(p) {
1521
- const changed = p.added.length > 0 || p.removed.length > 0;
1522
- const last = parseWireVersion(p.lastReleased);
1523
- const declared = parseWireVersion(p.declared);
1524
- if (!last || !declared) return { changed, refuse: "Unparseable version: " + p.lastReleased + " / " + p.declared + "." };
1525
- const requiredVersion = last.a + "." + (last.b + 1);
1526
- if (!changed) {
1527
- if (declared.b === last.b && declared.a === last.a) return { changed };
1528
- const step2 = p.steps.find((s) => s.to === p.declared);
1529
- return step2 ? { changed, requiredVersion: p.declared } : { changed, refuse: "The version moved to " + p.declared + " with no key change and no step explaining it." };
1530
- }
1531
- const requiredKind = p.removed.length ? "converted" /* converted */ : "additive" /* additive */;
1532
- const summary = p.added.length + " key(s) added, " + p.removed.length + " removed";
1533
- if (declared.a !== last.a || declared.b !== last.b + 1) {
1534
- return {
1535
- changed,
1536
- requiredKind,
1537
- requiredVersion,
1538
- refuse: "The player schema changed (" + summary + ") but PX_PLAYER_SCHEMA_VERSION is " + p.declared + ". Set it to " + requiredVersion + " and add the PLAYER_WIRE_STEPS entry."
1539
- };
1540
- }
1541
- const step = p.steps.find((s) => s.to === p.declared);
1542
- if (!step) {
1543
- return { changed, requiredKind, requiredVersion, refuse: "No PLAYER_WIRE_STEPS entry reaches " + p.declared + "." };
1544
- }
1545
- if (requiredKind === "converted" /* converted */ && step.kind !== "converted" /* converted */) {
1546
- return {
1547
- changed,
1548
- requiredKind,
1549
- requiredVersion,
1550
- refuse: "Keys were REMOVED (" + p.removed.join(", ") + "), which is never additive \u2014 the " + p.declared + " step must be `converted`, with an up()."
1551
- };
1552
- }
1553
- return { changed, requiredKind, requiredVersion };
1554
- }
1555
- function releaseLogProblems(releases, steps, declared, baseline) {
1556
- const problems = [];
1557
- if (!releases.length) return ["The release log is empty."];
1558
- if (!releases[0].baseline || releases[0].version !== baseline) {
1559
- problems.push("The first release must be the baseline " + baseline + ".");
1560
- }
1561
- for (let i = 1; i < releases.length; i++) {
1562
- const prev = parseWireVersion(releases[i - 1].version);
1563
- const cur = parseWireVersion(releases[i].version);
1564
- if (!prev || !cur || cur.a !== prev.a || cur.b !== prev.b + 1) {
1565
- problems.push("Release " + releases[i].version + " does not follow " + releases[i - 1].version + " by one `b` step.");
1566
- }
1567
- if (releases[i].date < releases[i - 1].date) problems.push("Release " + releases[i].version + " is dated before its predecessor.");
1568
- const step = steps.find((s) => s.to === releases[i].version);
1569
- if (!step) problems.push("Release " + releases[i].version + " has no PLAYER_WIRE_STEPS entry.");
1570
- else if (releases[i].removed.length && step.kind !== "converted" /* converted */) {
1571
- problems.push("Release " + releases[i].version + " removed keys, but its step is not `converted`.");
1572
- }
1573
- }
1574
- const latest = releases[releases.length - 1].version;
1575
- if (latest !== declared) {
1576
- problems.push("PX_PLAYER_SCHEMA_VERSION is " + declared + " but the last release record is " + latest + " \u2014 a bump needs its changelog entry (run scripts/schema-release.mjs --apply).");
1577
- }
1578
- return problems;
1579
- }
1580
-
1581
929
  // src/format/PxAnimatorConstants.ts
1582
930
  var PxFillMode = {
1583
931
  forwards: "forwards",
@@ -1930,9 +1278,7 @@ function getDefs(doc) {
1930
1278
  function getBindings(doc) {
1931
1279
  var _a2;
1932
1280
  if (!doc) return void 0;
1933
- const animateById = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.animateById;
1934
- if (!animateById) return void 0;
1935
- return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
1281
+ return (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.bindings;
1936
1282
  }
1937
1283
  function getChildren(doc) {
1938
1284
  return doc == null ? void 0 : doc.children;
@@ -2040,9 +1386,6 @@ var PxGlyphFontSchema = implementsInterface()(px.object({
2040
1386
  var PxDefsSchema = implementsInterface()(px.object({
2041
1387
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
2042
1388
  animations: px.record(PxAnimationDefinitionSchema).optional(),
2043
- // Review §2.6: the schema now matches the declared type — a style preset is a flat
2044
- // record of string|number attribute values, nothing nested.
2045
- styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
2046
1389
  fonts: px.record(PxGlyphFontSchema).optional()
2047
1390
  }));
2048
1391
  var PxScrollRangePointSchema = implementsInterface()(px.object({
@@ -2123,22 +1466,22 @@ var PxTimelineSchema = px.discriminatedUnion("type", [
2123
1466
  PxScrollTimelineSchema,
2124
1467
  PxViewTimelineSchema
2125
1468
  ]);
1469
+ var PxBindingSchema = implementsInterface()(px.object({
1470
+ target: px.string(),
1471
+ animateWith: px.array(px.string())
1472
+ }));
2126
1473
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
2127
1474
  // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
2128
1475
  // at this level only on the runtime view, like the rest of the playback dynamics.)
2129
1476
  // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
2130
1477
  timeline: PxTimelineSchema.optional(),
2131
1478
  definitions: PxDefsSchema.optional(),
2132
- animateById: px.record(PxElementAnimationSchema).optional(),
1479
+ bindings: px.array(PxBindingSchema).optional(),
2133
1480
  debugGlobalName: px.string().optional(),
2134
1481
  // Declared HERE because this is a closed object: an undeclared key would be stripped by
2135
1482
  // `sanitize` and flagged by strict validation on our own files.
2136
1483
  version: px.string().optional()
2137
1484
  }));
2138
- var PxBindingSchema = implementsInterface()(px.object({
2139
- id: px.string(),
2140
- animate: PxElementAnimationSchema
2141
- }));
2142
1485
  var PxAttrValueSchema = px.union([
2143
1486
  px.string(),
2144
1487
  px.number(),
@@ -2312,213 +1655,661 @@ function validateEasingRefs(root, easings) {
2312
1655
  if (key === "easing") continue;
2313
1656
  if (value && typeof value === "object") walk(value, path + "." + key);
2314
1657
  }
2315
- };
2316
- walk(root, "root");
2317
- return problems;
1658
+ };
1659
+ walk(root, "root");
1660
+ return problems;
1661
+ }
1662
+ function validateVersionStamp(doc) {
1663
+ var _a2;
1664
+ const version = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.version;
1665
+ if (version === void 0) return [];
1666
+ if (parseWireVersion(version) !== void 0) return [];
1667
+ return ["root.animator.version: " + JSON.stringify(version) + ' is not a version stamp ("a.b" or "a.b.c") \u2014 it reads as unstamped'];
1668
+ }
1669
+ function validateDocument(doc, opts) {
1670
+ var _a2;
1671
+ const strict = (opts == null ? void 0 : opts.strict) !== false;
1672
+ const ctx = { errors: [], warnings: [], strict };
1673
+ const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
1674
+ if (doc && typeof doc === "object") {
1675
+ for (const w of validateNodeEffects(doc, { strict })) {
1676
+ if (!problems.includes(w)) problems.push(w);
1677
+ }
1678
+ const defs = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
1679
+ for (const w of validateGlyphFontRefs(doc, defs == null ? void 0 : defs.fonts)) {
1680
+ if (!problems.includes(w)) problems.push(w);
1681
+ }
1682
+ for (const w of validateEasingRefs(doc, defs == null ? void 0 : defs.easings)) {
1683
+ if (!problems.includes(w)) problems.push(w);
1684
+ }
1685
+ for (const w of validateVersionStamp(doc)) {
1686
+ if (!problems.includes(w)) problems.push(w);
1687
+ }
1688
+ }
1689
+ return problems;
1690
+ }
1691
+ var PxNodeBase = px.openObject({
1692
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1693
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
1694
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1695
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1696
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1697
+ // would add words that all mean "type" and still need the carrier to read.
1698
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1699
+ // (issues V3), never of distinct key names.
1700
+ type: px.string(),
1701
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
1702
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
1703
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
1704
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
1705
+ // documented — because a wire key that is not in a schema is invisible to the
1706
+ // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1707
+ domType: px.string().optional(),
1708
+ // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
1709
+ // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
1710
+ textContent: px.string().optional(),
1711
+ id: px.string().optional(),
1712
+ meta: px.any().optional(),
1713
+ // Player-effects bucket emitted by the Editor's lightweight design format.
1714
+ // Consumed and removed by `applyPlayerEffects` before any other normalization
1715
+ // (see `createAnimatorImpl`), so downstream code never sees it.
1716
+ effects: PxEffectsSchema.optional(),
1717
+ // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
1718
+ // string ref / array of refs / inline definition / mixed array; mirrors
1719
+ // `node.animate` values and what `processNode` resolves at runtime.
1720
+ animate: PxElementAnimationSchema.optional(),
1721
+ style: px.record(px.union([px.string(), px.number()])).optional()
1722
+ }, PxAttrValueSchema);
1723
+ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
1724
+ children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1725
+ }), PxAttrValueSchema);
1726
+ var PxSvgNodeExtra = px.object({
1727
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
1728
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
1729
+ width: px.union([px.number(), px.string()]).optional(),
1730
+ height: px.union([px.number(), px.string()]).optional(),
1731
+ viewBox: px.string().optional(),
1732
+ animator: PxAnimatorConfigSchema.optional()
1733
+ });
1734
+ var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
1735
+ type: px.literal("svg"),
1736
+ // override string → literal to require 'svg'
1737
+ children: px.array(PxNodeSchema).optional()
1738
+ }), PxAttrValueSchema);
1739
+ var PxBezierPathSchema = implementsInterface()(px.object({
1740
+ v: px.array(px.array(px.number())),
1741
+ i: px.array(px.array(px.number())).optional(),
1742
+ o: px.array(px.array(px.number())).optional(),
1743
+ c: px.boolean().optional()
1744
+ }));
1745
+ function isPxElementFileFormatDeep(fileJson) {
1746
+ const errors = validateDocument(fileJson, { strict: false });
1747
+ return { valid: errors.length === 0, errors };
1748
+ }
1749
+
1750
+ // src/util/PxIdUtil.ts
1751
+ var _idCounter = 0;
1752
+ function generateUniqueId() {
1753
+ const timestamp = Date.now().toString(36);
1754
+ const counter = (++_idCounter).toString(36);
1755
+ const random = Math.random().toString(36).substring(2, 6);
1756
+ return "_px_" + timestamp + counter + random;
1757
+ }
1758
+ function deepClone(value) {
1759
+ if (value === null || typeof value !== "object") return value;
1760
+ if (Array.isArray(value)) return value.map((item) => deepClone(item));
1761
+ const obj = value;
1762
+ const cloned = {};
1763
+ for (const key of Object.keys(obj)) {
1764
+ cloned[key] = deepClone(obj[key]);
1765
+ }
1766
+ return cloned;
1767
+ }
1768
+ function generateNewIds(doc) {
1769
+ var _a2;
1770
+ const cloned = deepClone(doc);
1771
+ const idMap = /* @__PURE__ */ new Map();
1772
+ const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
1773
+ const urlRefAttrs = /* @__PURE__ */ new Set([
1774
+ "fill",
1775
+ "stroke",
1776
+ "clip-path",
1777
+ "clipPath",
1778
+ "mask",
1779
+ "marker",
1780
+ "marker-start",
1781
+ "marker-mid",
1782
+ "marker-end",
1783
+ "filter",
1784
+ "flood-color",
1785
+ "lighting-color"
1786
+ ]);
1787
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
1788
+ const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
1789
+ function collectIds(node) {
1790
+ if (!node || typeof node !== "object") return;
1791
+ if (node.id && typeof node.id === "string") {
1792
+ const oldId = node.id;
1793
+ const newId = generateUniqueId();
1794
+ idMap.set(oldId, newId);
1795
+ node.id = newId;
1796
+ } else if (node.animate) {
1797
+ node.id = generateUniqueId();
1798
+ }
1799
+ if (Array.isArray(node.children)) {
1800
+ for (const child of node.children) {
1801
+ collectIds(child);
1802
+ }
1803
+ }
1804
+ }
1805
+ function updateRefs(node, parentKey) {
1806
+ if (!node || typeof node !== "object") return;
1807
+ for (const [key, value] of Object.entries(node)) {
1808
+ if (key === "children") {
1809
+ if (Array.isArray(value)) {
1810
+ for (const child of value) {
1811
+ updateRefs(child);
1812
+ }
1813
+ }
1814
+ continue;
1815
+ }
1816
+ if (typeof value === "string") {
1817
+ if (hashRefAttrs.has(key) && value.startsWith("#")) {
1818
+ const oldId = value.slice(1);
1819
+ const newId = idMap.get(oldId);
1820
+ if (newId) {
1821
+ node[key] = "#" + newId;
1822
+ }
1823
+ } else if (urlRefAttrs.has(key)) {
1824
+ node[key] = replaceUrlRefs(value, idMap);
1825
+ } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
1826
+ const hasHash = value.startsWith("#");
1827
+ const newId = idMap.get(hasHash ? value.slice(1) : value);
1828
+ if (newId) {
1829
+ node[key] = hasHash ? "#" + newId : newId;
1830
+ }
1831
+ } else if (value.includes("url(#")) {
1832
+ node[key] = replaceUrlRefs(value, idMap);
1833
+ }
1834
+ } else if (key === "style" && typeof value === "object" && value !== null) {
1835
+ for (const [styleProp, styleValue] of Object.entries(value)) {
1836
+ if (typeof styleValue === "string") {
1837
+ value[styleProp] = replaceUrlRefs(styleValue, idMap);
1838
+ }
1839
+ }
1840
+ } else if (typeof value === "object" && value !== null) {
1841
+ updateRefs(value, key);
1842
+ }
1843
+ }
1844
+ }
1845
+ collectIds(cloned);
1846
+ updateRefs(cloned);
1847
+ const docBindings = (_a2 = cloned.animator) == null ? void 0 : _a2.bindings;
1848
+ if (Array.isArray(docBindings)) {
1849
+ const updatedBindings = docBindings.map((binding) => {
1850
+ var _a3;
1851
+ const hashed = binding.target.startsWith("#");
1852
+ const id = hashed ? binding.target.slice(1) : binding.target;
1853
+ const newId = (_a3 = idMap.get(id)) != null ? _a3 : id;
1854
+ return __spreadProps(__spreadValues({}, binding), { target: hashed ? "#" + newId : newId });
1855
+ });
1856
+ cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { bindings: updatedBindings });
1857
+ }
1858
+ return cloned;
1859
+ }
1860
+ function replaceUrlRefs(value, idMap) {
1861
+ return value.replace(/url\(#([^)]+)\)/g, (match, oldId) => {
1862
+ const newId = idMap.get(oldId);
1863
+ return newId ? "url(#" + newId + ")" : match;
1864
+ });
1865
+ }
1866
+
1867
+ // src/util/PxAnimatorUtil.ts
1868
+ function bezierToSvgPath(path, forceCurves = false) {
1869
+ var _a2, _b, _c, _d;
1870
+ const v = path.v;
1871
+ const i = path.i;
1872
+ const o = path.o;
1873
+ const c = path.c;
1874
+ if (!v.length) return "";
1875
+ const d = [];
1876
+ const len = v.length;
1877
+ d.push("M" + v[0][0] + "," + v[0][1]);
1878
+ for (let idx = 1; idx < len; idx++) {
1879
+ const prevV = v[idx - 1];
1880
+ const prevO = (_a2 = o == null ? void 0 : o[idx - 1]) != null ? _a2 : prevV;
1881
+ const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
1882
+ const currV = v[idx];
1883
+ const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
1884
+ if (isLine) {
1885
+ d.push("L" + currV[0] + "," + currV[1]);
1886
+ } else {
1887
+ d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
1888
+ }
1889
+ }
1890
+ if (c && len > 0) {
1891
+ const lastV = v[len - 1];
1892
+ const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
1893
+ const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
1894
+ const firstV = v[0];
1895
+ const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
1896
+ if (!isLine) {
1897
+ d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
1898
+ }
1899
+ d.push("z");
1900
+ }
1901
+ return d.join("");
1902
+ }
1903
+ function interpolateNum(a, b, t) {
1904
+ return a + (b - a) * t;
1905
+ }
1906
+ function interpolateVec(a, b, t) {
1907
+ const res = [];
1908
+ const count = Math.max(a.length, b.length);
1909
+ for (let i = 0; i < count; i++) {
1910
+ res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
1911
+ }
1912
+ return res;
1913
+ }
1914
+ function interpolateColor(a, b, t) {
1915
+ return [
1916
+ interpolateNum(a[0] || 0, b[0] || 0, t),
1917
+ interpolateNum(a[1] || 0, b[1] || 0, t),
1918
+ interpolateNum(a[2] || 0, b[2] || 0, t),
1919
+ interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
1920
+ ];
1921
+ }
1922
+ function interpolateBeziers(paths1, paths2, progress) {
1923
+ const count = Math.max(paths1.length, paths2.length);
1924
+ const res = [];
1925
+ for (let i = 0; i < count; i++) {
1926
+ res.push(interpolateBezier(paths1[i], paths2[i], progress));
1927
+ }
1928
+ return res;
1929
+ }
1930
+ function interpolateBezier(path1, path2, progress) {
1931
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
1932
+ if (!path1 || !path2) return path1 || path2 || { v: [] };
1933
+ const t = Math.min(Math.max(progress, 0), 1);
1934
+ const len = Math.min(path1.v.length, path2.v.length);
1935
+ const v = [];
1936
+ const i = [];
1937
+ const o = [];
1938
+ for (let idx = 0; idx < len; idx++) {
1939
+ const v1 = path1.v[idx];
1940
+ const v2 = path2.v[idx];
1941
+ v.push(interpolateVec(v1, v2, t));
1942
+ const i1 = (_b = (_a2 = path1.i) == null ? void 0 : _a2[idx]) != null ? _b : v1;
1943
+ const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
1944
+ i.push(interpolateVec(i1, i2, t));
1945
+ const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
1946
+ const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
1947
+ o.push(interpolateVec(o1, o2, t));
1948
+ }
1949
+ return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
1950
+ }
1951
+ function remap(value, inMin, inMax, outMin, outMax) {
1952
+ if (inMax === inMin) return outMin;
1953
+ const t = (value - inMin) / (inMax - inMin);
1954
+ return outMin + t * (outMax - outMin);
1955
+ }
1956
+ function solveCubicBezierX(p1x, p2x, x) {
1957
+ if (x <= 0) return 0;
1958
+ if (x >= 1) return 1;
1959
+ const cx = 3 * p1x;
1960
+ const bx = 3 * (p2x - p1x) - cx;
1961
+ const ax = 1 - cx - bx;
1962
+ function sampleX(t) {
1963
+ return ((ax * t + bx) * t + cx) * t;
1964
+ }
1965
+ function sampleDX(t) {
1966
+ return (3 * ax * t + 2 * bx) * t + cx;
1967
+ }
1968
+ let t2 = x;
1969
+ let t0 = 0;
1970
+ let t1 = 1;
1971
+ for (let i = 0; i < 8; i++) {
1972
+ const x2 = sampleX(t2) - x;
1973
+ if (Math.abs(x2) < 1e-6) return t2;
1974
+ const d2 = sampleDX(t2);
1975
+ if (Math.abs(d2) < 1e-6) break;
1976
+ t2 -= x2 / d2;
1977
+ }
1978
+ t2 = x;
1979
+ while (t0 < t1) {
1980
+ const x2 = sampleX(t2);
1981
+ if (Math.abs(x2 - x) < 1e-6) return t2;
1982
+ if (x > x2) t0 = t2;
1983
+ else t1 = t2;
1984
+ t2 = (t1 + t0) / 2;
1985
+ }
1986
+ return t2;
1987
+ }
1988
+ function cubicBezier(easing) {
1989
+ const [p1x, p1y, p2x, p2y] = easing;
1990
+ const cy = 3 * p1y;
1991
+ const by = 3 * (p2y - p1y) - cy;
1992
+ const ay = 1 - cy - by;
1993
+ function sampleCurveY(t) {
1994
+ return ((ay * t + by) * t + cy) * t;
1995
+ }
1996
+ return function(x) {
1997
+ return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
1998
+ };
1999
+ }
2000
+ function lerp2(a, b, t) {
2001
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
2002
+ }
2003
+ function subdivideCubicBezier(p0, p1, p2, p3, t) {
2004
+ const q0 = lerp2(p0, p1, t);
2005
+ const q1 = lerp2(p1, p2, t);
2006
+ const q2 = lerp2(p2, p3, t);
2007
+ const r0 = lerp2(q0, q1, t);
2008
+ const r1 = lerp2(q1, q2, t);
2009
+ const s = lerp2(r0, r1, t);
2010
+ return {
2011
+ left: [p0, q0, r0, s],
2012
+ right: [s, r1, q2, p3]
2013
+ };
2014
+ }
2015
+ function splitEasing(easing, xFraction) {
2016
+ if (!easing) return { left: void 0, right: void 0 };
2017
+ if (xFraction <= 0) return { left: void 0, right: easing };
2018
+ if (xFraction >= 1) return { left: easing, right: void 0 };
2019
+ const [x1, y1, x2, y2] = easing;
2020
+ const t = solveCubicBezierX(x1, x2, xFraction);
2021
+ const p0 = [0, 0];
2022
+ const p1 = [x1, y1];
2023
+ const p2 = [x2, y2];
2024
+ const p3 = [1, 1];
2025
+ const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
2026
+ const sx = left[3][0];
2027
+ const sy = left[3][1];
2028
+ let leftEasing;
2029
+ if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
2030
+ leftEasing = [
2031
+ left[1][0] / sx,
2032
+ left[1][1] / sy,
2033
+ left[2][0] / sx,
2034
+ left[2][1] / sy
2035
+ ];
2036
+ }
2037
+ let rightEasing;
2038
+ const rx = 1 - sx;
2039
+ const ry = 1 - sy;
2040
+ if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
2041
+ rightEasing = [
2042
+ (right[1][0] - sx) / rx,
2043
+ (right[1][1] - sy) / ry,
2044
+ (right[2][0] - sx) / rx,
2045
+ (right[2][1] - sy) / ry
2046
+ ];
2047
+ }
2048
+ return { left: leftEasing, right: rightEasing };
2049
+ }
2050
+ function reverseEasing(easing) {
2051
+ if (!easing) return void 0;
2052
+ return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
2053
+ }
2054
+ function toRGBA(color) {
2055
+ const r = Math.round(color[0] * 255);
2056
+ const g = Math.round(color[1] * 255);
2057
+ const b = Math.round(color[2] * 255);
2058
+ return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
2059
+ }
2060
+ function parseRgba(s) {
2061
+ var _a2;
2062
+ const inner = (_a2 = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a2[1];
2063
+ if (!inner) throw new Error("Invalid rgb/rgba format");
2064
+ const parts = inner.split(",").map((v) => +v.trim());
2065
+ return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
2066
+ }
2067
+ function parseHex(s) {
2068
+ const hex = s.slice(1);
2069
+ const isShort = hex.length <= 4;
2070
+ const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
2071
+ const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
2072
+ const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
2073
+ const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
2074
+ const result = [
2075
+ parseInt(r, 16) / 255,
2076
+ parseInt(g, 16) / 255,
2077
+ parseInt(b, 16) / 255
2078
+ ];
2079
+ if (a !== null) {
2080
+ result.push(parseInt(a, 16) / 255);
2081
+ }
2082
+ return result;
2083
+ }
2084
+ function parseColor(s) {
2085
+ if (!s) return void 0;
2086
+ if (Array.isArray(s)) return s;
2087
+ if (typeof s !== "string") return void 0;
2088
+ if (s.startsWith("#")) {
2089
+ return parseHex(s);
2090
+ } else if (s.startsWith("rgb")) {
2091
+ return parseRgba(s);
2092
+ } else {
2093
+ console.warn("Unsupported color format: " + s);
2094
+ }
2095
+ return void 0;
2096
+ }
2097
+ var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
2098
+ var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
2099
+ var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
2100
+ function composeTransformParts(parts, opts) {
2101
+ var _a2;
2102
+ if (!parts) return "";
2103
+ const withUnits = (_a2 = opts == null ? void 0 : opts.withUnits) != null ? _a2 : true;
2104
+ const segs = [];
2105
+ const t = parts.translate;
2106
+ const o = parts.origin;
2107
+ const r = parts.rotate;
2108
+ const k = parts.skew;
2109
+ const s = parts.scale;
2110
+ const tu = withUnits ? "px" : "";
2111
+ const ru = withUnits ? "deg" : "";
2112
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
2113
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
2114
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
2115
+ if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
2116
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
2117
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
2118
+ return segs.join("");
2119
+ }
2120
+ function parseTransformParts(str2) {
2121
+ var _a2, _b;
2122
+ if (!str2 || typeof str2 !== "string") return void 0;
2123
+ const out = {};
2124
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
2125
+ const order = ["translate", "rotate", "skewX", "scale"];
2126
+ let lastIdx = -1;
2127
+ let m;
2128
+ while ((m = re.exec(str2)) !== null) {
2129
+ const fn = m[1];
2130
+ const idx = order.indexOf(fn);
2131
+ if (idx < 0 || idx <= lastIdx) return void 0;
2132
+ lastIdx = idx;
2133
+ const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
2134
+ if (nums.some((n) => Number.isNaN(n))) return void 0;
2135
+ if (fn === "translate") {
2136
+ if (nums.length < 1 || nums.length > 2) return void 0;
2137
+ out.translate = [nums[0], (_a2 = nums[1]) != null ? _a2 : 0];
2138
+ } else if (fn === "rotate") {
2139
+ if (nums.length !== 1) return void 0;
2140
+ out.rotate = nums[0];
2141
+ } else if (fn === "skewX") {
2142
+ if (nums.length !== 1) return void 0;
2143
+ out.skew = nums[0];
2144
+ } else {
2145
+ if (nums.length < 1 || nums.length > 2) return void 0;
2146
+ out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
2147
+ }
2148
+ }
2149
+ if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
2150
+ return Object.keys(out).length ? out : void 0;
2318
2151
  }
2319
- function validateVersionStamp(doc) {
2320
- var _a2;
2321
- const version = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.version;
2322
- if (version === void 0) return [];
2323
- if (parseWireVersion(version) !== void 0) return [];
2324
- return ["root.animator.version: " + JSON.stringify(version) + ' is not a version stamp ("a.b" or "a.b.c") \u2014 it reads as unstamped'];
2152
+ var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
2153
+ var DEFAULT_DURATION_MS = 1e3;
2154
+ function kebabToCamelCaseWord(kebab) {
2155
+ return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
2325
2156
  }
2326
- function validateDocument(doc, opts) {
2327
- var _a2;
2328
- const strict = (opts == null ? void 0 : opts.strict) !== false;
2329
- const ctx = { errors: [], warnings: [], strict };
2330
- const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
2331
- if (doc && typeof doc === "object") {
2332
- for (const w of validateNodeEffects(doc, { strict })) {
2333
- if (!problems.includes(w)) problems.push(w);
2334
- }
2335
- const defs = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
2336
- for (const w of validateGlyphFontRefs(doc, defs == null ? void 0 : defs.fonts)) {
2337
- if (!problems.includes(w)) problems.push(w);
2338
- }
2339
- for (const w of validateEasingRefs(doc, defs == null ? void 0 : defs.easings)) {
2340
- if (!problems.includes(w)) problems.push(w);
2341
- }
2342
- for (const w of validateVersionStamp(doc)) {
2343
- if (!problems.includes(w)) problems.push(w);
2344
- }
2345
- }
2346
- return problems;
2157
+ function isCamelCaseWord(word) {
2158
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
2347
2159
  }
2348
- var PxNodeBase = px.openObject({
2349
- // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
2350
- // kind of thing is this", discriminated by its CARRIER — here the node TAG
2351
- // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
2352
- // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
2353
- // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
2354
- // would add words that all mean "type" and still need the carrier to read.
2355
- // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
2356
- // (issues V3), never of distinct key names.
2357
- type: px.string(),
2358
- // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
2359
- // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
2360
- // `type` is taken by the tag name, so the attribute travels here and the renderer puts
2361
- // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
2362
- // documented — because a wire key that is not in a schema is invisible to the
2363
- // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
2364
- domType: px.string().optional(),
2365
- // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
2366
- // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
2367
- textContent: px.string().optional(),
2368
- id: px.string().optional(),
2369
- meta: px.any().optional(),
2370
- // Player-effects bucket emitted by the Editor's lightweight design format.
2371
- // Consumed and removed by `applyPlayerEffects` before any other normalization
2372
- // (see `createAnimatorImpl`), so downstream code never sees it.
2373
- effects: PxEffectsSchema.optional(),
2374
- // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
2375
- // string ref / array of refs / inline definition / mixed array; mirrors
2376
- // `animator.animateById` map values and what `processNode` resolves at runtime.
2377
- animate: PxElementAnimationSchema.optional(),
2378
- style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
2379
- }, PxAttrValueSchema);
2380
- var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
2381
- children: px.lazy(() => px.array(PxNodeSchema), []).optional()
2382
- }), PxAttrValueSchema);
2383
- var PxSvgNodeExtra = px.object({
2384
- // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
2385
- // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
2386
- width: px.union([px.number(), px.string()]).optional(),
2387
- height: px.union([px.number(), px.string()]).optional(),
2388
- viewBox: px.string().optional(),
2389
- animator: PxAnimatorConfigSchema.optional()
2390
- });
2391
- var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
2392
- type: px.literal("svg"),
2393
- // override string → literal to require 'svg'
2394
- children: px.array(PxNodeSchema).optional()
2395
- }), PxAttrValueSchema);
2396
- var PxBezierPathSchema = implementsInterface()(px.object({
2397
- v: px.array(px.array(px.number())),
2398
- i: px.array(px.array(px.number())).optional(),
2399
- o: px.array(px.array(px.number())).optional(),
2400
- c: px.boolean().optional()
2401
- }));
2402
- function isPxElementFileFormatDeep(fileJson) {
2403
- const errors = validateDocument(fileJson, { strict: false });
2404
- return { valid: errors.length === 0, errors };
2160
+ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
2161
+ // Transform/positioning
2162
+ "viewBox",
2163
+ "preserveAspectRatio",
2164
+ // Gradient
2165
+ "gradientUnits",
2166
+ "gradientTransform",
2167
+ "spreadMethod",
2168
+ // Pattern
2169
+ "patternUnits",
2170
+ "patternContentUnits",
2171
+ "patternTransform",
2172
+ // Clipping/masking
2173
+ "clipPathUnits",
2174
+ "maskUnits",
2175
+ "maskContentUnits",
2176
+ // Marker (SVG spec keeps these camelCase, like viewBox)
2177
+ "markerUnits",
2178
+ "markerWidth",
2179
+ "markerHeight",
2180
+ "refX",
2181
+ "refY",
2182
+ // Text
2183
+ "textLength",
2184
+ "lengthAdjust",
2185
+ "startOffset",
2186
+ // Filter
2187
+ "filterUnits",
2188
+ "primitiveUnits",
2189
+ "tableValues",
2190
+ // feFuncR/G/B/A transfer table (type="table")
2191
+ "stdDeviation",
2192
+ "baseFrequency",
2193
+ "numOctaves",
2194
+ "surfaceScale",
2195
+ "diffuseConstant",
2196
+ "specularConstant",
2197
+ "specularExponent",
2198
+ "kernelMatrix",
2199
+ "kernelUnitLength",
2200
+ "edgeMode",
2201
+ "preserveAlpha",
2202
+ "targetX",
2203
+ "targetY"
2204
+ // // Animation
2205
+ // 'attributeName',
2206
+ // 'attributeType',
2207
+ // 'calcMode',
2208
+ // 'keyTimes',
2209
+ // 'keySplines',
2210
+ // 'repeatCount',
2211
+ // 'repeatDur'
2212
+ ]);
2213
+ function camelCaseToKebabWordIfNeeded(camel) {
2214
+ return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
2405
2215
  }
2406
-
2407
- // src/util/PxIdUtil.ts
2408
- var _idCounter = 0;
2409
- function generateUniqueId() {
2410
- const timestamp = Date.now().toString(36);
2411
- const counter = (++_idCounter).toString(36);
2412
- const random = Math.random().toString(36).substring(2, 6);
2413
- return "_px_" + timestamp + counter + random;
2216
+ function clamp(value, min, max) {
2217
+ return Math.max(min, Math.min(value, max));
2414
2218
  }
2415
- function deepClone(value) {
2416
- if (value === null || typeof value !== "object") return value;
2417
- if (Array.isArray(value)) return value.map((item) => deepClone(item));
2418
- const obj = value;
2419
- const cloned = {};
2420
- for (const key of Object.keys(obj)) {
2421
- cloned[key] = deepClone(obj[key]);
2219
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
2220
+ if (t <= 0) return [P0[0], P0[1]];
2221
+ if (t >= 1) return [P3[0], P3[1]];
2222
+ const u = 1 - t;
2223
+ const u2 = u * u;
2224
+ const u3 = u2 * u;
2225
+ const t2 = t * t;
2226
+ const t3 = t2 * t;
2227
+ const w0 = u3;
2228
+ const w1 = 3 * t * u2;
2229
+ const w2 = 3 * t2 * u;
2230
+ const w3 = t3;
2231
+ return [
2232
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
2233
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
2234
+ ];
2235
+ }
2236
+ var BEZIER_T_NUDGE = 1e-4;
2237
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
2238
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
2239
+ if (result[0] === 0 && result[1] === 0) {
2240
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
2241
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
2422
2242
  }
2423
- return cloned;
2243
+ return result;
2424
2244
  }
2425
- function generateNewIds(doc) {
2426
- var _a2, _b;
2427
- const cloned = deepClone(doc);
2428
- const idMap = /* @__PURE__ */ new Map();
2429
- const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
2430
- const urlRefAttrs = /* @__PURE__ */ new Set([
2431
- "fill",
2432
- "stroke",
2433
- "clip-path",
2434
- "clipPath",
2435
- "mask",
2436
- "marker",
2437
- "marker-start",
2438
- "marker-mid",
2439
- "marker-end",
2440
- "filter",
2441
- "flood-color",
2442
- "lighting-color"
2443
- ]);
2444
- const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
2445
- const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
2446
- function collectIds(node) {
2447
- if (!node || typeof node !== "object") return;
2448
- if (node.id && typeof node.id === "string") {
2449
- const oldId = node.id;
2450
- const newId = generateUniqueId();
2451
- idMap.set(oldId, newId);
2452
- node.id = newId;
2453
- } else if (node.animate) {
2454
- node.id = generateUniqueId();
2455
- }
2456
- if (Array.isArray(node.children)) {
2457
- for (const child of node.children) {
2458
- collectIds(child);
2459
- }
2460
- }
2245
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
2246
+ const u = 1 - t;
2247
+ const a = 3 * u * u;
2248
+ const b = 6 * t * u;
2249
+ const c = 3 * t * t;
2250
+ return [
2251
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
2252
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
2253
+ ];
2254
+ }
2255
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
2256
+ const n = steps + 1;
2257
+ const ts = new Float64Array(n);
2258
+ const ds = new Float64Array(n);
2259
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
2260
+ ts[0] = 0;
2261
+ ds[0] = 0;
2262
+ let cum = 0;
2263
+ for (let i = 1; i < n; i++) {
2264
+ const t = i / steps;
2265
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
2266
+ const dx = cur[0] - prev[0];
2267
+ const dy = cur[1] - prev[1];
2268
+ cum += Math.sqrt(dx * dx + dy * dy);
2269
+ ts[i] = t;
2270
+ ds[i] = cum;
2271
+ prev = cur;
2461
2272
  }
2462
- function updateRefs(node, parentKey) {
2463
- if (!node || typeof node !== "object") return;
2464
- for (const [key, value] of Object.entries(node)) {
2465
- if (key === "children") {
2466
- if (Array.isArray(value)) {
2467
- for (const child of value) {
2468
- updateRefs(child);
2469
- }
2470
- }
2471
- continue;
2472
- }
2473
- if (typeof value === "string") {
2474
- if (hashRefAttrs.has(key) && value.startsWith("#")) {
2475
- const oldId = value.slice(1);
2476
- const newId = idMap.get(oldId);
2477
- if (newId) {
2478
- node[key] = "#" + newId;
2479
- }
2480
- } else if (urlRefAttrs.has(key)) {
2481
- node[key] = replaceUrlRefs(value, idMap);
2482
- } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
2483
- const hasHash = value.startsWith("#");
2484
- const newId = idMap.get(hasHash ? value.slice(1) : value);
2485
- if (newId) {
2486
- node[key] = hasHash ? "#" + newId : newId;
2487
- }
2488
- } else if (value.includes("url(#")) {
2489
- node[key] = replaceUrlRefs(value, idMap);
2490
- }
2491
- } else if (key === "style" && typeof value === "object" && value !== null) {
2492
- for (const [styleProp, styleValue] of Object.entries(value)) {
2493
- if (typeof styleValue === "string") {
2494
- value[styleProp] = replaceUrlRefs(styleValue, idMap);
2495
- }
2496
- }
2497
- } else if (typeof value === "object" && value !== null) {
2498
- updateRefs(value, key);
2499
- }
2500
- }
2273
+ return { ts, ds };
2274
+ }
2275
+ function bezier2D_tForDistance(lut, distance) {
2276
+ const { ts, ds } = lut;
2277
+ const last = ds.length - 1;
2278
+ if (distance <= 0) return ts[0];
2279
+ if (distance >= ds[last]) return ts[last];
2280
+ let lo = 1;
2281
+ let hi = last;
2282
+ while (lo < hi) {
2283
+ const mid = lo + hi >>> 1;
2284
+ if (ds[mid] < distance) lo = mid + 1;
2285
+ else hi = mid;
2501
2286
  }
2502
- collectIds(cloned);
2503
- updateRefs(cloned);
2504
- const docAnimate = (_a2 = cloned.animator) == null ? void 0 : _a2.animateById;
2505
- if (docAnimate && typeof docAnimate === "object") {
2506
- const updatedAnimate = {};
2507
- for (const [key, anim] of Object.entries(docAnimate)) {
2508
- const hashed = key.startsWith("#");
2509
- const id = hashed ? key.slice(1) : key;
2510
- const newId = (_b = idMap.get(id)) != null ? _b : id;
2511
- updatedAnimate[hashed ? "#" + newId : newId] = anim;
2512
- }
2513
- cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animateById: updatedAnimate });
2287
+ const dPrev = ds[hi - 1];
2288
+ const dCur = ds[hi];
2289
+ const span = dCur - dPrev;
2290
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
2291
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
2292
+ }
2293
+ function bezier2D_arcAtT(lut, t) {
2294
+ const { ts, ds } = lut;
2295
+ const last = ts.length - 1;
2296
+ if (t <= ts[0]) return ds[0];
2297
+ if (t >= ts[last]) return ds[last];
2298
+ let lo = 1, hi = last;
2299
+ while (lo < hi) {
2300
+ const mid = lo + hi >>> 1;
2301
+ if (ts[mid] < t) lo = mid + 1;
2302
+ else hi = mid;
2514
2303
  }
2515
- return cloned;
2304
+ const tPrev = ts[hi - 1];
2305
+ const span = ts[hi] - tPrev;
2306
+ const frac = span > 0 ? (t - tPrev) / span : 0;
2307
+ return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
2516
2308
  }
2517
- function replaceUrlRefs(value, idMap) {
2518
- return value.replace(/url\(#([^)]+)\)/g, (match, oldId) => {
2519
- const newId = idMap.get(oldId);
2520
- return newId ? "url(#" + newId + ")" : match;
2521
- });
2309
+ function invertEasing(easing) {
2310
+ if (!easing) return (y) => y;
2311
+ const flipped = [easing[1], easing[0], easing[3], easing[2]];
2312
+ return cubicBezier(flipped);
2522
2313
  }
2523
2314
 
2524
2315
  // src/util/PxNodeProps.ts
@@ -2584,14 +2375,6 @@ function sanitizeAttributeValue(name, value) {
2584
2375
  }
2585
2376
  return value;
2586
2377
  }
2587
- function resolveStyle(style, defs) {
2588
- var _a2;
2589
- if (!style) return void 0;
2590
- if (typeof style === "string") {
2591
- return (_a2 = defs == null ? void 0 : defs.styles) == null ? void 0 : _a2[style];
2592
- }
2593
- return style;
2594
- }
2595
2378
  function getNormalizedProps(props) {
2596
2379
  const propsCopy = {};
2597
2380
  for (const rawKey of Object.keys(props)) {
@@ -3554,9 +3337,7 @@ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
3554
3337
  const defs = getDefs(doc);
3555
3338
  const duration = animatorConfig.duration || 1e3;
3556
3339
  const bindings = [];
3557
- const processAnimation = (id, animate, staticTransform) => {
3558
- if (!animate) return null;
3559
- const animDefs = resolveElementAnimation(animate, defs);
3340
+ const processAnimation = (id, animDefs, staticTransform) => {
3560
3341
  if (animDefs.length === 0) return null;
3561
3342
  const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);
3562
3343
  const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
@@ -3569,7 +3350,9 @@ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
3569
3350
  const docBindings = getBindings(doc);
3570
3351
  if (docBindings) {
3571
3352
  for (const binding of docBindings) {
3572
- const normalized = processAnimation(binding.id, binding.animate);
3353
+ const id = binding.target.startsWith("#") ? binding.target.slice(1) : binding.target;
3354
+ const animDefs = binding.animateWith.map((name) => resolveAnimation(name, defs)).filter((d) => !!d);
3355
+ const normalized = processAnimation(id, animDefs);
3573
3356
  if (normalized) bindings.push(normalized);
3574
3357
  }
3575
3358
  }
@@ -3578,7 +3361,7 @@ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
3578
3361
  if (inlineAnim && Object.keys(inlineAnim).length > 0) {
3579
3362
  const nodeId = node.id || generateElementId();
3580
3363
  node.id = nodeId;
3581
- const normalized = processAnimation(nodeId, inlineAnim, node.transform);
3364
+ const normalized = processAnimation(nodeId, resolveElementAnimation(inlineAnim, defs), node.transform);
3582
3365
  if (normalized) bindings.push(normalized);
3583
3366
  }
3584
3367
  if (node.children) {
@@ -3710,243 +3493,31 @@ function calcPropertyValue(propName, propAnim, progress) {
3710
3493
  prevV || [1, 1],
3711
3494
  nextV || [1, 1],
3712
3495
  localProgress
3713
- );
3714
- cssValue = "scale(" + v.join(",") + ")";
3715
- cssAttrName = "transform";
3716
- } else {
3717
- const num2 = interpolateNum(
3718
- +(prevV || 0),
3719
- +(nextV || 0),
3720
- localProgress
3721
- );
3722
- cssValue = num2;
3723
- }
3724
- if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
3725
- cssValue = cssValue * 100 + "%";
3726
- }
3727
- return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
3728
- }
3729
- function calcAnimationValues(animDef, progress) {
3730
- const result = {};
3731
- for (const [propName, propAnim] of Object.entries(animDef)) {
3732
- const computed = calcPropertyValue(propName, propAnim, progress);
3733
- if (computed) {
3734
- result[computed.k] = computed.v;
3735
- }
3736
- }
3737
- return result;
3738
- }
3739
-
3740
- // src/util/PxNodeCloneUtil.ts
3741
- function deepClonePxNode(value) {
3742
- if (value === null || typeof value !== "object") return value;
3743
- if (Array.isArray(value)) return value.map(deepClonePxNode);
3744
- const out = {};
3745
- for (const k of Object.keys(value)) out[k] = deepClonePxNode(value[k]);
3746
- return out;
3747
- }
3748
- function regenerateIdsAndRewriteRefs(root, genId3) {
3749
- const oldToNew = /* @__PURE__ */ new Map();
3750
- const walkAssign = (n) => {
3751
- var _a2;
3752
- if (typeof n.id === "string") {
3753
- const newId = genId3();
3754
- oldToNew.set(n.id, newId);
3755
- n.id = newId;
3756
- }
3757
- (_a2 = n.children) == null ? void 0 : _a2.forEach(walkAssign);
3758
- };
3759
- walkAssign(root);
3760
- const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
3761
- const newId = oldToNew.get(oldId);
3762
- return newId ? "url(#" + newId + ")" : m;
3763
- });
3764
- const walkRewrite = (n) => {
3765
- var _a2;
3766
- if (typeof n.href === "string" && n.href.startsWith("#")) {
3767
- const newId = oldToNew.get(n.href.slice(1));
3768
- if (newId) n.href = "#" + newId;
3769
- }
3770
- for (const k of Object.keys(n)) {
3771
- if (k === "children" || k === "effects" || k === "meta" || k === "animate" || k === "href" || k === "id") continue;
3772
- const v = n[k];
3773
- if (typeof v === "string" && v.indexOf("url(#") !== -1) {
3774
- n[k] = rewriteUrl(v);
3775
- }
3776
- }
3777
- (_a2 = n.children) == null ? void 0 : _a2.forEach(walkRewrite);
3778
- };
3779
- walkRewrite(root);
3780
- return oldToNew;
3781
- }
3782
- function toFiniteNum(v) {
3783
- const n = typeof v === "number" ? v : typeof v === "string" ? parseFloat(v) : NaN;
3784
- return Number.isFinite(n) ? n : 0;
3785
- }
3786
- function applyUseOffsetToG(gNode) {
3787
- var _a2;
3788
- const x = toFiniteNum(gNode.x);
3789
- const y = toFiniteNum(gNode.y);
3790
- delete gNode.x;
3791
- delete gNode.y;
3792
- if (!x && !y) return gNode;
3793
- const offset = "translate(" + x + "," + y + ")";
3794
- const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
3795
- if (carriesTransform) {
3796
- const inner = { type: "g", transform: offset, children: (_a2 = gNode.children) != null ? _a2 : [] };
3797
- gNode.children = [inner];
3798
- } else {
3799
- gNode.transform = offset;
3800
- }
3801
- return gNode;
3802
- }
3803
-
3804
- // src/materialize/PxAnimatorUseMaterializer.ts
3805
- function materializeAnimatedUseInstances(root) {
3806
- var _a2;
3807
- const idMap = buildIdMap(root);
3808
- const animatedIds = computeAnimatedSubtreeIds(root, idMap);
3809
- if (animatedIds.size === 0) return root;
3810
- let idCounter = 0;
3811
- const genId3 = () => "_lw_use_mat_" + ++idCounter;
3812
- const rootViewport = readRootViewport(root);
3813
- const defsCollector = [];
3814
- const walked = walkAndMaterialize2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3815
- if (defsCollector.length === 0) return walked;
3816
- const defsNode = { type: "defs", children: defsCollector };
3817
- const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
3818
- return __spreadProps(__spreadValues({}, walked), { children: newChildren });
3819
- }
3820
- function readRootViewport(root) {
3821
- const vb = parseViewBox(root.viewBox);
3822
- if (vb) return [vb[2], vb[3]];
3823
- const w = numericAttr(root.width);
3824
- const h = numericAttr(root.height);
3825
- if (w !== void 0 && h !== void 0) return [w, h];
3826
- return [1, 1];
3827
- }
3828
- function numericAttr(v) {
3829
- if (typeof v === "number") return v;
3830
- if (typeof v === "string") {
3831
- const n = parseFloat(v);
3832
- return Number.isFinite(n) ? n : void 0;
3833
- }
3834
- return void 0;
3835
- }
3836
- function buildIdMap(root) {
3837
- const map = /* @__PURE__ */ new Map();
3838
- const visit = (n) => {
3839
- var _a2;
3840
- if (typeof n.id === "string") map.set(n.id, n);
3841
- (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
3842
- };
3843
- visit(root);
3844
- return map;
3845
- }
3846
- function computeAnimatedSubtreeIds(root, idMap) {
3847
- const cache = /* @__PURE__ */ new WeakMap();
3848
- const result = /* @__PURE__ */ new Set();
3849
- const hasAnim = (n, visiting) => {
3850
- const cached = cache.get(n);
3851
- if (cached !== void 0) return cached;
3852
- if (visiting.has(n)) return false;
3853
- visiting.add(n);
3854
- let r = false;
3855
- if (n.animate && typeof n.animate === "object" && !Array.isArray(n.animate)) {
3856
- for (const _ in n.animate) {
3857
- r = true;
3858
- break;
3859
- }
3860
- }
3861
- if (!r && n.children) {
3862
- for (const ch of n.children) {
3863
- if (hasAnim(ch, visiting)) {
3864
- r = true;
3865
- break;
3866
- }
3867
- }
3868
- }
3869
- if (!r && n.type === "use" && typeof n.href === "string") {
3870
- const targetId = stripHash(n.href);
3871
- const target = targetId ? idMap.get(targetId) : void 0;
3872
- if (target) r = hasAnim(target, visiting);
3873
- }
3874
- visiting.delete(n);
3875
- cache.set(n, r);
3876
- return r;
3877
- };
3878
- for (const [id, node] of idMap) {
3879
- if (hasAnim(node, /* @__PURE__ */ new Set())) result.add(id);
3496
+ );
3497
+ cssValue = "scale(" + v.join(",") + ")";
3498
+ cssAttrName = "transform";
3499
+ } else {
3500
+ const num2 = interpolateNum(
3501
+ +(prevV || 0),
3502
+ +(nextV || 0),
3503
+ localProgress
3504
+ );
3505
+ cssValue = num2;
3880
3506
  }
3881
- return result;
3882
- }
3883
- function stripHash(href) {
3884
- if (typeof href !== "string") return void 0;
3885
- return href.startsWith("#") ? href.slice(1) : href;
3886
- }
3887
- function materializeOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3888
- var _a2, _b, _c, _d;
3889
- const clone2 = deepClonePxNode(target);
3890
- regenerateIdsAndRewriteRefs(clone2, genId3);
3891
- const symbolViewBox = clone2.type === "symbol" ? parseViewBox(clone2.viewBox) : void 0;
3892
- const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3893
- const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
3894
- const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
3895
- const materializedClone = walkAndMaterialize2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3896
- const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materializedClone] });
3897
- delete newNode.href;
3898
- delete newNode.width;
3899
- delete newNode.height;
3900
- return applyUseOffsetToG(newNode);
3901
- }
3902
- function rewriteSymbolRootToGroup(symbolNode, genId3, defsCollector, useW, useH) {
3903
- const viewBox = parseViewBox(symbolNode.viewBox);
3904
- const g = __spreadProps(__spreadValues({}, symbolNode), { type: "g" });
3905
- delete g.viewBox;
3906
- delete g.preserveAspectRatio;
3907
- delete g.width;
3908
- delete g.height;
3909
- if (!viewBox) return g;
3910
- const [vbX, vbY, vbW, vbH] = viewBox;
3911
- const scale = vbW > 0 && vbH > 0 ? Math.min(useW / vbW, useH / vbH) : 1;
3912
- const xOff = (useW - vbW * scale) / 2;
3913
- const yOff = (useH - vbH * scale) / 2;
3914
- const parts = [];
3915
- if (xOff !== 0 || yOff !== 0) parts.push("translate(" + xOff + "," + yOff + ")");
3916
- if (scale !== 1) parts.push("scale(" + scale + ")");
3917
- if (vbX !== 0 || vbY !== 0) parts.push("translate(" + -vbX + "," + -vbY + ")");
3918
- if (parts.length) g.transform = parts.join("");
3919
- const clipId = genId3();
3920
- defsCollector.push({
3921
- type: "clipPath",
3922
- id: clipId,
3923
- children: [{ type: "rect", x: vbX, y: vbY, width: vbW, height: vbH }]
3924
- });
3925
- g.clipPath = "url(#" + clipId + ")";
3926
- return g;
3927
- }
3928
- function parseViewBox(v) {
3929
- if (typeof v !== "string") return void 0;
3930
- const parts = v.trim().split(/[\s,]+/).map(Number);
3931
- if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
3932
- return [parts[0], parts[1], parts[2], parts[3]];
3507
+ if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
3508
+ cssValue = cssValue * 100 + "%";
3509
+ }
3510
+ return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
3933
3511
  }
3934
- function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3935
- if (node.type === "use" && typeof node.href === "string") {
3936
- const targetId = stripHash(node.href);
3937
- if (targetId && animatedIds.has(targetId)) {
3938
- const target = idMap.get(targetId);
3939
- if (target) return materializeOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
3512
+ function calcAnimationValues(animDef, progress) {
3513
+ const result = {};
3514
+ for (const [propName, propAnim] of Object.entries(animDef)) {
3515
+ const computed = calcPropertyValue(propName, propAnim, progress);
3516
+ if (computed) {
3517
+ result[computed.k] = computed.v;
3940
3518
  }
3941
3519
  }
3942
- if (!node.children) return node;
3943
- let changed = false;
3944
- const newChildren = node.children.map((ch) => {
3945
- const m = walkAndMaterialize2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3946
- if (m !== ch) changed = true;
3947
- return m;
3948
- });
3949
- return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
3520
+ return result;
3950
3521
  }
3951
3522
 
3952
3523
  // src/effects/shared/transformParts.ts
@@ -4117,11 +3688,75 @@ function wrapOrigin(inner, raw, invert) {
4117
3688
  return inner;
4118
3689
  }
4119
3690
 
3691
+ // src/util/PxNodeCloneUtil.ts
3692
+ function deepClonePxNode(value) {
3693
+ if (value === null || typeof value !== "object") return value;
3694
+ if (Array.isArray(value)) return value.map(deepClonePxNode);
3695
+ const out = {};
3696
+ for (const k of Object.keys(value)) out[k] = deepClonePxNode(value[k]);
3697
+ return out;
3698
+ }
3699
+ function regenerateIdsAndRewriteRefs(root, genId3) {
3700
+ const oldToNew = /* @__PURE__ */ new Map();
3701
+ const walkAssign = (n) => {
3702
+ var _a2;
3703
+ if (typeof n.id === "string") {
3704
+ const newId = genId3();
3705
+ oldToNew.set(n.id, newId);
3706
+ n.id = newId;
3707
+ }
3708
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkAssign);
3709
+ };
3710
+ walkAssign(root);
3711
+ const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
3712
+ const newId = oldToNew.get(oldId);
3713
+ return newId ? "url(#" + newId + ")" : m;
3714
+ });
3715
+ const walkRewrite = (n) => {
3716
+ var _a2;
3717
+ if (typeof n.href === "string" && n.href.startsWith("#")) {
3718
+ const newId = oldToNew.get(n.href.slice(1));
3719
+ if (newId) n.href = "#" + newId;
3720
+ }
3721
+ for (const k of Object.keys(n)) {
3722
+ if (k === "children" || k === "effects" || k === "meta" || k === "animate" || k === "href" || k === "id") continue;
3723
+ const v = n[k];
3724
+ if (typeof v === "string" && v.indexOf("url(#") !== -1) {
3725
+ n[k] = rewriteUrl(v);
3726
+ }
3727
+ }
3728
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkRewrite);
3729
+ };
3730
+ walkRewrite(root);
3731
+ return oldToNew;
3732
+ }
3733
+ function toFiniteNum(v) {
3734
+ const n = typeof v === "number" ? v : typeof v === "string" ? parseFloat(v) : NaN;
3735
+ return Number.isFinite(n) ? n : 0;
3736
+ }
3737
+ function applyUseOffsetToG(gNode) {
3738
+ var _a2;
3739
+ const x = toFiniteNum(gNode.x);
3740
+ const y = toFiniteNum(gNode.y);
3741
+ delete gNode.x;
3742
+ delete gNode.y;
3743
+ if (!x && !y) return gNode;
3744
+ const offset = "translate(" + x + "," + y + ")";
3745
+ const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
3746
+ if (carriesTransform) {
3747
+ const inner = { type: "g", transform: offset, children: (_a2 = gNode.children) != null ? _a2 : [] };
3748
+ gNode.children = [inner];
3749
+ } else {
3750
+ gNode.transform = offset;
3751
+ }
3752
+ return gNode;
3753
+ }
3754
+
4120
3755
  // src/effects/shared/util.ts
4121
3756
  function genId(ctx, prefix) {
4122
3757
  return "_lw_" + prefix + "_" + ctx.nextId++;
4123
3758
  }
4124
- function stripHash2(href) {
3759
+ function stripHash(href) {
4125
3760
  return typeof href === "string" ? href.replace(/^#/, "") : void 0;
4126
3761
  }
4127
3762
  function indexById(node, map) {
@@ -4143,7 +3778,7 @@ function regenerateIdsInClone(root, ctx) {
4143
3778
  function identifyContentRefTargets(node, ctx, allocator) {
4144
3779
  var _a2, _b, _c;
4145
3780
  if (node.type === "use" && ((_b = (_a2 = node.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.without) === "translate") {
4146
- const sourceId = stripHash2(node.effects.clone.source);
3781
+ const sourceId = stripHash(node.effects.clone.source);
4147
3782
  if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
4148
3783
  ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
4149
3784
  }
@@ -4532,7 +4167,7 @@ function pathString(v) {
4532
4167
  // src/effects/clipping/maskedByEffect.ts
4533
4168
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
4534
4169
  if (!fx) return node;
4535
- const sourceId = stripHash2(fx.source);
4170
+ const sourceId = stripHash(fx.source);
4536
4171
  if (!sourceId) {
4537
4172
  ctx.errors.push("maskedBy.source missing \u2014 cannot build mask");
4538
4173
  return node;
@@ -4809,7 +4444,7 @@ function collectMaskAncestorChains(root, ctx) {
4809
4444
  const interestingNodes = /* @__PURE__ */ new Set();
4810
4445
  const collectInterestingNodes = (n) => {
4811
4446
  var _a2, _b;
4812
- const maskSourceId = stripHash2((_b = (_a2 = n.effects) == null ? void 0 : _a2.maskedBy) == null ? void 0 : _b.source);
4447
+ const maskSourceId = stripHash((_b = (_a2 = n.effects) == null ? void 0 : _a2.maskedBy) == null ? void 0 : _b.source);
4813
4448
  if (typeof maskSourceId === "string") {
4814
4449
  interestingNodes.add(n);
4815
4450
  const sourceNode = ctx.idMap.get(maskSourceId);
@@ -4889,7 +4524,7 @@ function parseTranslateOnlyFromString(s, ctx) {
4889
4524
  // src/effects/reference/refEffect.ts
4890
4525
  function applyRefHref(node, clone2, ctx) {
4891
4526
  if (!clone2) return;
4892
- const sourceId = stripHash2(clone2.source);
4527
+ const sourceId = stripHash(clone2.source);
4893
4528
  if (!sourceId) {
4894
4529
  if (clone2.without === PxCloneWithout.translate) ctx.errors.push("clone: content ref missing `source`");
4895
4530
  return;
@@ -5035,7 +4670,7 @@ function applyAllRetimeEffects(root, ctx) {
5035
4670
  if (!n) return;
5036
4671
  if (n !== site && readCloneRetime(n)) count++;
5037
4672
  if (n.type === "use" && n.href) {
5038
- const id = stripHash2(n.href);
4673
+ const id = stripHash(n.href);
5039
4674
  if (id && !visited.has(id)) {
5040
4675
  visited.add(id);
5041
4676
  walk(ctx.idMap.get(id));
@@ -5043,7 +4678,7 @@ function applyAllRetimeEffects(root, ctx) {
5043
4678
  }
5044
4679
  (_a2 = n.children) == null ? void 0 : _a2.forEach(walk);
5045
4680
  };
5046
- const rootId = stripHash2(site.href);
4681
+ const rootId = stripHash(site.href);
5047
4682
  if (rootId) {
5048
4683
  visited.add(rootId);
5049
4684
  walk(ctx.idMap.get(rootId));
@@ -5064,7 +4699,7 @@ function applyAllRetimeEffects(root, ctx) {
5064
4699
  }
5065
4700
  }
5066
4701
  function materializeRetime(useNode, retime, ctx) {
5067
- const targetId = stripHash2(useNode.href);
4702
+ const targetId = stripHash(useNode.href);
5068
4703
  if (!targetId) {
5069
4704
  ctx.errors.push("retime: <use> has no href to follow");
5070
4705
  return;
@@ -5101,7 +4736,7 @@ function buildChainClone(targetId, accum, ctx, chain) {
5101
4736
  }
5102
4737
  clearCloneRetime(cloneNode);
5103
4738
  if (target.type === "use" && target.href) {
5104
- const subId = stripHash2(target.href);
4739
+ const subId = stripHash(target.href);
5105
4740
  if (subId) {
5106
4741
  const innerRetime = readCloneRetime(target);
5107
4742
  const subAccum = innerRetime ? concatRetime(asRetime(innerRetime), accum) : accum;
@@ -5122,7 +4757,7 @@ function materializeNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
5122
4757
  var _a2;
5123
4758
  const retime = readCloneRetime(n);
5124
4759
  if (n.type === "use" && retime && n.href) {
5125
- const subId = stripHash2(n.href);
4760
+ const subId = stripHash(n.href);
5126
4761
  if (subId) {
5127
4762
  const subAccum = concatRetime(asRetime(retime), accum);
5128
4763
  const subChain = new Set(chain);
@@ -5512,7 +5147,7 @@ function paintAnimateOf(node) {
5512
5147
  }
5513
5148
  return out;
5514
5149
  }
5515
- function resolveStyle2(node, parent) {
5150
+ function resolveStyle(node, parent) {
5516
5151
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5517
5152
  const isTextRoot = node.type === "text";
5518
5153
  const nodeStyle = node.style;
@@ -5619,7 +5254,7 @@ function materializeGlyphTextHorizontal(node, opts) {
5619
5254
  };
5620
5255
  const walk = (el, parentStyle) => {
5621
5256
  var _a3, _b2, _c2;
5622
- const s = resolveStyle2(el, parentStyle);
5257
+ const s = resolveStyle(el, parentStyle);
5623
5258
  const x = parseLen(el.x);
5624
5259
  const y = parseLen(el.y);
5625
5260
  if (x !== void 0) {
@@ -5674,7 +5309,7 @@ function layoutGlyphTextChars(node, opts) {
5674
5309
  };
5675
5310
  const walk = (el, parentStyle) => {
5676
5311
  var _a3, _b2, _c2;
5677
- const s = resolveStyle2(el, parentStyle);
5312
+ const s = resolveStyle(el, parentStyle);
5678
5313
  const x = parseLen(el.x);
5679
5314
  const y = parseLen(el.y);
5680
5315
  if (x !== void 0) {
@@ -5694,7 +5329,7 @@ function layoutGlyphTextChars(node, opts) {
5694
5329
  const before = boxes.length;
5695
5330
  walk(ch, rootStyle);
5696
5331
  if (boxes.length === before) {
5697
- const s = resolveStyle2(ch, rootStyle);
5332
+ const s = resolveStyle(ch, rootStyle);
5698
5333
  const gf = glyphFontFor(s, glyphs, soleFont);
5699
5334
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
5700
5335
  boxes.push({ x: pen.x, y: pen.y, width: 0, ascent: ((_d = gf == null ? void 0 : gf.ascent) != null ? _d : 0.9 * upm) * (s.fontSize / upm), fontSize: s.fontSize, line });
@@ -5727,7 +5362,7 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
5727
5362
  let adv = 0;
5728
5363
  const walk = (el, parentStyle) => {
5729
5364
  var _a3, _b2;
5730
- const s = resolveStyle2(el, parentStyle);
5365
+ const s = resolveStyle(el, parentStyle);
5731
5366
  const content = str(el[TEXT_CONTENT_ATTR]);
5732
5367
  if (content && !((_a3 = el.children) == null ? void 0 : _a3.length)) {
5733
5368
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
@@ -5781,7 +5416,7 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
5781
5416
  let adv = 0;
5782
5417
  const walk = (el, parentStyle) => {
5783
5418
  var _a2, _b;
5784
- const s = resolveStyle2(el, parentStyle);
5419
+ const s = resolveStyle(el, parentStyle);
5785
5420
  const content = str(el[TEXT_CONTENT_ATTR]);
5786
5421
  if (content && !((_a2 = el.children) == null ? void 0 : _a2.length)) {
5787
5422
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
@@ -6521,9 +6156,157 @@ function materializeOffsetPathsInTree(root) {
6521
6156
  const children = out.children.map(walk);
6522
6157
  if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
6523
6158
  }
6524
- return out;
6525
- };
6526
- return walk(root);
6159
+ return out;
6160
+ };
6161
+ return walk(root);
6162
+ }
6163
+
6164
+ // src/materialize/PxAnimatorUseMaterializer.ts
6165
+ function materializeAnimatedUseInstances(root) {
6166
+ var _a2;
6167
+ const idMap = buildIdMap(root);
6168
+ const animatedIds = computeAnimatedSubtreeIds(root, idMap);
6169
+ if (animatedIds.size === 0) return root;
6170
+ let idCounter = 0;
6171
+ const genId3 = () => "_lw_use_mat_" + ++idCounter;
6172
+ const rootViewport = readRootViewport(root);
6173
+ const defsCollector = [];
6174
+ const walked = walkAndMaterialize2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
6175
+ if (defsCollector.length === 0) return walked;
6176
+ const defsNode = { type: "defs", children: defsCollector };
6177
+ const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
6178
+ return __spreadProps(__spreadValues({}, walked), { children: newChildren });
6179
+ }
6180
+ function readRootViewport(root) {
6181
+ const vb = parseViewBox(root.viewBox);
6182
+ if (vb) return [vb[2], vb[3]];
6183
+ const w = numericAttr(root.width);
6184
+ const h = numericAttr(root.height);
6185
+ if (w !== void 0 && h !== void 0) return [w, h];
6186
+ return [1, 1];
6187
+ }
6188
+ function numericAttr(v) {
6189
+ if (typeof v === "number") return v;
6190
+ if (typeof v === "string") {
6191
+ const n = parseFloat(v);
6192
+ return Number.isFinite(n) ? n : void 0;
6193
+ }
6194
+ return void 0;
6195
+ }
6196
+ function buildIdMap(root) {
6197
+ const map = /* @__PURE__ */ new Map();
6198
+ const visit = (n) => {
6199
+ var _a2;
6200
+ if (typeof n.id === "string") map.set(n.id, n);
6201
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
6202
+ };
6203
+ visit(root);
6204
+ return map;
6205
+ }
6206
+ function computeAnimatedSubtreeIds(root, idMap) {
6207
+ const cache = /* @__PURE__ */ new WeakMap();
6208
+ const result = /* @__PURE__ */ new Set();
6209
+ const hasAnim = (n, visiting) => {
6210
+ const cached = cache.get(n);
6211
+ if (cached !== void 0) return cached;
6212
+ if (visiting.has(n)) return false;
6213
+ visiting.add(n);
6214
+ let r = false;
6215
+ if (n.animate && typeof n.animate === "object" && !Array.isArray(n.animate)) {
6216
+ for (const _ in n.animate) {
6217
+ r = true;
6218
+ break;
6219
+ }
6220
+ }
6221
+ if (!r && n.children) {
6222
+ for (const ch of n.children) {
6223
+ if (hasAnim(ch, visiting)) {
6224
+ r = true;
6225
+ break;
6226
+ }
6227
+ }
6228
+ }
6229
+ if (!r && n.type === "use" && typeof n.href === "string") {
6230
+ const targetId = stripHash2(n.href);
6231
+ const target = targetId ? idMap.get(targetId) : void 0;
6232
+ if (target) r = hasAnim(target, visiting);
6233
+ }
6234
+ visiting.delete(n);
6235
+ cache.set(n, r);
6236
+ return r;
6237
+ };
6238
+ for (const [id, node] of idMap) {
6239
+ if (hasAnim(node, /* @__PURE__ */ new Set())) result.add(id);
6240
+ }
6241
+ return result;
6242
+ }
6243
+ function stripHash2(href) {
6244
+ if (typeof href !== "string") return void 0;
6245
+ return href.startsWith("#") ? href.slice(1) : href;
6246
+ }
6247
+ function materializeOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
6248
+ var _a2, _b, _c, _d;
6249
+ const clone2 = deepClonePxNode(target);
6250
+ regenerateIdsAndRewriteRefs(clone2, genId3);
6251
+ const symbolViewBox = clone2.type === "symbol" ? parseViewBox(clone2.viewBox) : void 0;
6252
+ const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
6253
+ const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
6254
+ const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
6255
+ const materializedClone = walkAndMaterialize2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
6256
+ const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materializedClone] });
6257
+ delete newNode.href;
6258
+ delete newNode.width;
6259
+ delete newNode.height;
6260
+ return applyUseOffsetToG(newNode);
6261
+ }
6262
+ function rewriteSymbolRootToGroup(symbolNode, genId3, defsCollector, useW, useH) {
6263
+ const viewBox = parseViewBox(symbolNode.viewBox);
6264
+ const g = __spreadProps(__spreadValues({}, symbolNode), { type: "g" });
6265
+ delete g.viewBox;
6266
+ delete g.preserveAspectRatio;
6267
+ delete g.width;
6268
+ delete g.height;
6269
+ if (!viewBox) return g;
6270
+ const [vbX, vbY, vbW, vbH] = viewBox;
6271
+ const scale = vbW > 0 && vbH > 0 ? Math.min(useW / vbW, useH / vbH) : 1;
6272
+ const xOff = (useW - vbW * scale) / 2;
6273
+ const yOff = (useH - vbH * scale) / 2;
6274
+ const parts = [];
6275
+ if (xOff !== 0 || yOff !== 0) parts.push("translate(" + xOff + "," + yOff + ")");
6276
+ if (scale !== 1) parts.push("scale(" + scale + ")");
6277
+ if (vbX !== 0 || vbY !== 0) parts.push("translate(" + -vbX + "," + -vbY + ")");
6278
+ if (parts.length) g.transform = parts.join("");
6279
+ const clipId = genId3();
6280
+ defsCollector.push({
6281
+ type: "clipPath",
6282
+ id: clipId,
6283
+ children: [{ type: "rect", x: vbX, y: vbY, width: vbW, height: vbH }]
6284
+ });
6285
+ g.clipPath = "url(#" + clipId + ")";
6286
+ return g;
6287
+ }
6288
+ function parseViewBox(v) {
6289
+ if (typeof v !== "string") return void 0;
6290
+ const parts = v.trim().split(/[\s,]+/).map(Number);
6291
+ if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
6292
+ return [parts[0], parts[1], parts[2], parts[3]];
6293
+ }
6294
+ function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
6295
+ if (node.type === "use" && typeof node.href === "string") {
6296
+ const targetId = stripHash2(node.href);
6297
+ if (targetId && animatedIds.has(targetId)) {
6298
+ const target = idMap.get(targetId);
6299
+ if (target) return materializeOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
6300
+ }
6301
+ }
6302
+ if (!node.children) return node;
6303
+ let changed = false;
6304
+ const newChildren = node.children.map((ch) => {
6305
+ const m = walkAndMaterialize2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
6306
+ if (m !== ch) changed = true;
6307
+ return m;
6308
+ });
6309
+ return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
6527
6310
  }
6528
6311
 
6529
6312
  // src/materialize/PxAnimatorMaterializeAll.ts
@@ -6848,112 +6631,281 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6848
6631
  cancelFrame(timerId);
6849
6632
  timerId = null;
6850
6633
  }
6851
- renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
6852
- if (callOnFinish && !finishCalled) {
6853
- finishCalled = true;
6854
- (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
6634
+ renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
6635
+ if (callOnFinish && !finishCalled) {
6636
+ finishCalled = true;
6637
+ (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
6638
+ }
6639
+ };
6640
+ const api = {
6641
+ "isReady": () => true,
6642
+ "getRootElement": () => null,
6643
+ "isPlaying": () => {
6644
+ return _isPlaying();
6645
+ },
6646
+ "play": () => {
6647
+ var _a3;
6648
+ startAnim();
6649
+ (_a3 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a3.call(callbacks);
6650
+ },
6651
+ "pause": () => {
6652
+ var _a3;
6653
+ pauseAnim();
6654
+ (_a3 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a3.call(callbacks);
6655
+ },
6656
+ "cancel": () => {
6657
+ cancelAnim();
6658
+ },
6659
+ "finish": () => {
6660
+ finishAnim(true);
6661
+ },
6662
+ "setPlaybackRate": (rate) => {
6663
+ if (!isValidPlaybackRate(rate)) {
6664
+ console.warn(PX_RATE_REJECTED);
6665
+ return;
6666
+ }
6667
+ let current = getRawAnimTime();
6668
+ if (Number.isFinite(totalDuration) && current > totalDuration) current = totalDuration;
6669
+ if (rate < 0 !== playbackRate < 0) finishCalled = false;
6670
+ playbackRate = rate;
6671
+ timeBeforeLastStartMs = current;
6672
+ if (playing) lastStartedTs = Date.now();
6673
+ },
6674
+ "getCurrentTime": () => {
6675
+ return getAnimCurrentTime();
6676
+ },
6677
+ "setCurrentTime": (newTime) => {
6678
+ newTime = clampSeekMs(newTime, totalDuration);
6679
+ timeBeforeLastStartMs = newTime;
6680
+ if (playing) lastStartedTs = Date.now();
6681
+ if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
6682
+ renderFrame(getAnimCurrentTime());
6683
+ },
6684
+ "getCurrentProgress": () => timeToProgress(getAnimCurrentTime(), duration, iterations),
6685
+ "setCurrentProgress": (progress) => {
6686
+ api.setCurrentTime(progressToTimeMs(progress, duration, iterations));
6687
+ },
6688
+ "destroy": () => {
6689
+ var _a3;
6690
+ api.cancel();
6691
+ (_a3 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a3.call(callbacks);
6692
+ }
6693
+ };
6694
+ return api;
6695
+ }
6696
+
6697
+ // src/playback/PxDiagnostics.ts
6698
+ var PxDiagnosticKind = {
6699
+ /** The document is wrong — regenerate or repair the file. */
6700
+ document: "document",
6701
+ /** The page or app cannot provide what the document asks for — fix the mount. */
6702
+ host: "host",
6703
+ /** The platform cannot do it and the player degraded — usually nothing to fix. */
6704
+ platform: "platform",
6705
+ /** The call is wrong or self-contradictory — fix the options or props you passed. */
6706
+ usage: "usage",
6707
+ /** The player failed where it did not expect to — report it to us. */
6708
+ internal: "internal"
6709
+ };
6710
+ function asError(error) {
6711
+ return typeof error === "string" ? new Error(error) : error;
6712
+ }
6713
+ function createDiagnostics(config, prefix) {
6714
+ const tag = prefix ? prefix + " " : "";
6715
+ return {
6716
+ warn: (kind, message, detail) => {
6717
+ if (config == null ? void 0 : config.onWarn) {
6718
+ config.onWarn({ kind, message, detail });
6719
+ return;
6720
+ }
6721
+ if (config == null ? void 0 : config.muteWarn) return;
6722
+ const line = tag + kind + ": " + message;
6723
+ if (detail === void 0) console.warn(line);
6724
+ else console.warn(line, detail);
6725
+ },
6726
+ error: (kind, error, detail) => {
6727
+ const err = asError(error);
6728
+ if (config == null ? void 0 : config.onError) {
6729
+ config.onError({ kind, message: err.message, error: err, detail });
6730
+ return;
6731
+ }
6732
+ if (config == null ? void 0 : config.muteError) return;
6733
+ const line = tag + kind + ": " + err.message;
6734
+ if (detail === void 0) console.error(line);
6735
+ else console.error(line, detail);
6736
+ }
6737
+ };
6738
+ }
6739
+
6740
+ // src/playback/PxAnimatorConfigPatch.ts
6741
+ var FLAT_ONLY_KEYS = [
6742
+ "timelineSource",
6743
+ "scroll",
6744
+ "trigger",
6745
+ "delay",
6746
+ "iterations",
6747
+ "direction",
6748
+ "fill",
6749
+ "resetOnFinish",
6750
+ "duration",
6751
+ "mode",
6752
+ "frameRate"
6753
+ ];
6754
+ var CONTENT_KEYS = ["definitions", "bindings"];
6755
+ var isPlainObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
6756
+ var timelineTypeOf = (t) => isPlainObject(t) && typeof t.type === "string" ? t.type : "time";
6757
+ var isScrollish = (type) => type === "scroll" || type === "view";
6758
+ function mergePlain(base, patch) {
6759
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6760
+ for (const key of Object.keys(patch)) {
6761
+ const value = patch[key];
6762
+ if (value === null) {
6763
+ delete out[key];
6764
+ continue;
6765
+ }
6766
+ if (isPlainObject(value)) {
6767
+ out[key] = mergePlain(out[key], value);
6768
+ continue;
6769
+ }
6770
+ out[key] = value;
6771
+ }
6772
+ return out;
6773
+ }
6774
+ function mergeTimeline(base, patch, warn) {
6775
+ const baseType = timelineTypeOf(base);
6776
+ const patchNamesType = isPlainObject(patch) && typeof patch.type === "string";
6777
+ const patchType = patchNamesType ? String(patch.type) : baseType;
6778
+ let merged;
6779
+ if (patchType !== baseType) {
6780
+ const carried = {};
6781
+ if (isPlainObject(base)) {
6782
+ for (const k of PX_TIMELINE_SHARED_KEYS) {
6783
+ if (base[k] !== void 0) carried[k] = base[k];
6784
+ }
6785
+ }
6786
+ merged = mergePlain(carried, patch);
6787
+ } else {
6788
+ merged = mergePlain(base, patch);
6789
+ }
6790
+ if (isScrollish(patchType)) {
6791
+ for (const k of PX_TIME_ONLY_TIMELINE_KEYS) {
6792
+ if (merged[k] === void 0) continue;
6793
+ warn("animator.timeline." + k + ": no slot on a '" + patchType + "' timeline \u2014 dropped");
6794
+ delete merged[k];
6795
+ }
6796
+ if (merged.iterations === "infinite") {
6797
+ warn("animator.timeline.iterations: 'infinite' cannot map onto a scroll range \u2014 dropped");
6798
+ delete merged.iterations;
6799
+ }
6800
+ }
6801
+ return merged;
6802
+ }
6803
+ function foldTimelineOverride(timeline, shortcuts) {
6804
+ let base;
6805
+ if (typeof timeline === "string") {
6806
+ try {
6807
+ base = JSON.parse(timeline);
6808
+ } catch (e) {
6809
+ console.warn("timeline override: not valid JSON \u2014 ignored", e);
6810
+ base = void 0;
6811
+ }
6812
+ } else {
6813
+ base = timeline != null ? timeline : void 0;
6814
+ }
6815
+ const { duration, delay, iterations, startOn } = shortcuts;
6816
+ if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6817
+ return base === void 0 ? void 0 : { timeline: base };
6818
+ }
6819
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6820
+ if (duration !== void 0) out.duration = duration;
6821
+ if (delay !== void 0) out.delay = delay;
6822
+ if (iterations !== void 0) out.iterations = iterations;
6823
+ if (startOn !== void 0) {
6824
+ out.trigger = __spreadProps(__spreadValues({}, out.trigger), { startOn });
6825
+ }
6826
+ return { timeline: out };
6827
+ }
6828
+ function mergeAnimatorConfig(base, patch) {
6829
+ const warnings = [];
6830
+ const warn = (m) => warnings.push(m);
6831
+ if (patch === null) return { config: void 0, warnings };
6832
+ if (!isPlainObject(patch) || Object.keys(patch).length === 0) {
6833
+ return { config: base, warnings };
6834
+ }
6835
+ const flatInBase = isPlainObject(base) ? FLAT_ONLY_KEYS.filter((k) => base[k] !== void 0) : [];
6836
+ if (flatInBase.length) {
6837
+ warn("animator: the base carries the flat runtime spelling (" + flatInBase.join(", ") + "); the patch merges the wire spelling only");
6838
+ }
6839
+ const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6840
+ for (const key of Object.keys(patch)) {
6841
+ const value = patch[key];
6842
+ if (value === null) {
6843
+ delete out[key];
6844
+ continue;
6845
+ }
6846
+ if (key === "timeline") {
6847
+ out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
6848
+ continue;
6849
+ }
6850
+ if (isPlainObject(value)) {
6851
+ out[key] = mergePlain(out[key], value);
6852
+ continue;
6855
6853
  }
6856
- };
6857
- const api = {
6858
- "isReady": () => true,
6859
- "getRootElement": () => null,
6860
- "isPlaying": () => {
6861
- return _isPlaying();
6862
- },
6863
- "play": () => {
6864
- var _a3;
6865
- startAnim();
6866
- (_a3 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a3.call(callbacks);
6867
- },
6868
- "pause": () => {
6869
- var _a3;
6870
- pauseAnim();
6871
- (_a3 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a3.call(callbacks);
6872
- },
6873
- "cancel": () => {
6874
- cancelAnim();
6875
- },
6876
- "finish": () => {
6877
- finishAnim(true);
6878
- },
6879
- "setPlaybackRate": (rate) => {
6880
- if (!isValidPlaybackRate(rate)) {
6881
- console.warn(PX_RATE_REJECTED);
6882
- return;
6883
- }
6884
- let current = getRawAnimTime();
6885
- if (Number.isFinite(totalDuration) && current > totalDuration) current = totalDuration;
6886
- if (rate < 0 !== playbackRate < 0) finishCalled = false;
6887
- playbackRate = rate;
6888
- timeBeforeLastStartMs = current;
6889
- if (playing) lastStartedTs = Date.now();
6890
- },
6891
- "getCurrentTime": () => {
6892
- return getAnimCurrentTime();
6893
- },
6894
- "setCurrentTime": (newTime) => {
6895
- newTime = clampSeekMs(newTime, totalDuration);
6896
- timeBeforeLastStartMs = newTime;
6897
- if (playing) lastStartedTs = Date.now();
6898
- if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
6899
- renderFrame(getAnimCurrentTime());
6900
- },
6901
- "getCurrentProgress": () => timeToProgress(getAnimCurrentTime(), duration, iterations),
6902
- "setCurrentProgress": (progress) => {
6903
- api.setCurrentTime(progressToTimeMs(progress, duration, iterations));
6904
- },
6905
- "destroy": () => {
6906
- var _a3;
6907
- api.cancel();
6908
- (_a3 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a3.call(callbacks);
6854
+ out[key] = value;
6855
+ }
6856
+ return { config: out, warnings };
6857
+ }
6858
+ function applyAnimatorConfig(doc, patch, opts) {
6859
+ var _a2, _b;
6860
+ const reset = !!(opts == null ? void 0 : opts.resetDefaults);
6861
+ if (!doc || (patch === void 0 || !reset && (patch === null || !isPlainObject(patch) || !Object.keys(patch).length))) {
6862
+ return { doc, warnings: [] };
6863
+ }
6864
+ const anyDoc = doc;
6865
+ const atRoot = isPlainObject(anyDoc.animator);
6866
+ const atMeta = !atRoot && isPlainObject((_a2 = anyDoc.meta) == null ? void 0 : _a2.animator);
6867
+ const current = atRoot ? anyDoc.animator : atMeta ? anyDoc.meta.animator : void 0;
6868
+ const warnings = [];
6869
+ if (atRoot && isPlainObject((_b = anyDoc.meta) == null ? void 0 : _b.animator)) {
6870
+ warnings.push("animator: doc.meta.animator is shadowed by doc.animator and was not patched");
6871
+ }
6872
+ let base = current;
6873
+ if (reset) {
6874
+ const kept = {};
6875
+ for (const k of CONTENT_KEYS) {
6876
+ if (isPlainObject(current) && current[k] !== void 0) kept[k] = current[k];
6909
6877
  }
6910
- };
6911
- return api;
6878
+ base = kept;
6879
+ }
6880
+ const merged = mergeAnimatorConfig(base, patch != null ? patch : {});
6881
+ warnings.push(...merged.warnings);
6882
+ if (merged.config === current) return { doc, warnings };
6883
+ if (atMeta) {
6884
+ return {
6885
+ doc: __spreadProps(__spreadValues({}, anyDoc), { meta: __spreadProps(__spreadValues({}, anyDoc.meta), { animator: merged.config }) }),
6886
+ warnings
6887
+ };
6888
+ }
6889
+ return { doc: __spreadProps(__spreadValues({}, anyDoc), { animator: merged.config }), warnings };
6912
6890
  }
6913
6891
 
6914
- // src/playback/PxDiagnostics.ts
6915
- var PxDiagnosticKind = {
6916
- /** The document is wrong — regenerate or repair the file. */
6917
- document: "document",
6918
- /** The page or app cannot provide what the document asks for — fix the mount. */
6919
- host: "host",
6920
- /** The platform cannot do it and the player degraded — usually nothing to fix. */
6921
- platform: "platform",
6922
- /** The call is wrong or self-contradictory — fix the options or props you passed. */
6923
- usage: "usage",
6924
- /** The player failed where it did not expect to — report it to us. */
6925
- internal: "internal"
6926
- };
6927
- function asError(error) {
6928
- return typeof error === "string" ? new Error(error) : error;
6929
- }
6930
- function isSilenced(silent, kind) {
6931
- if (!silent) return false;
6932
- return silent === true || silent.includes(kind);
6892
+ // src/format/PxDocumentDiagnostic.ts
6893
+ var MAX_REPORTED = 6;
6894
+ function diagnoseDocument(doc) {
6895
+ try {
6896
+ return { problems: validateDocument(doc) };
6897
+ } catch (e) {
6898
+ return { problems: [] };
6899
+ }
6933
6900
  }
6934
- function createDiagnostics(config, prefix) {
6935
- const tag = prefix ? prefix + " " : "";
6936
- return {
6937
- warn: (kind, message, detail) => {
6938
- if (config == null ? void 0 : config.onWarn) {
6939
- config.onWarn({ kind, message, detail });
6940
- return;
6941
- }
6942
- if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6943
- const line = tag + kind + ": " + message;
6944
- if (detail === void 0) console.warn(line);
6945
- else console.warn(line, detail);
6946
- },
6947
- error: (kind, error) => {
6948
- const err = asError(error);
6949
- if (config == null ? void 0 : config.onError) {
6950
- config.onError({ kind, message: err.message, error: err });
6951
- return;
6952
- }
6953
- if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
6954
- console.error(tag + kind + ": " + err.message);
6955
- }
6956
- };
6901
+ function reportDocumentDiagnostics(doc, where) {
6902
+ const { problems } = diagnoseDocument(doc);
6903
+ if (!problems.length) return;
6904
+ const shown = problems.slice(0, MAX_REPORTED);
6905
+ const more = problems.length - shown.length;
6906
+ console.warn(
6907
+ 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."
6908
+ );
6957
6909
  }
6958
6910
 
6959
6911
  // src/effects/PlayerEffectsUtil.visualModel.ts
@@ -7140,200 +7092,208 @@ function visualModelAt(root, t) {
7140
7092
  return out.sort();
7141
7093
  }
7142
7094
  function diffInEffect(a, b) {
7143
- const times = /* @__PURE__ */ new Set();
7144
- collectSampleTimes(a, times);
7145
- collectSampleTimes(b, times);
7146
- const diffs = [];
7147
- for (const t of Array.from(times).sort((x, y) => x - y)) {
7148
- const ma = visualModelAt(a, t);
7149
- const mb = visualModelAt(b, t);
7150
- const onlyInA = subtractMultiset(ma, mb);
7151
- const onlyInB = subtractMultiset(mb, ma);
7152
- if (onlyInA.length || onlyInB.length) diffs.push({ time: t, onlyInA, onlyInB });
7153
- }
7154
- return diffs;
7155
- }
7156
- function subtractMultiset(a, b) {
7157
- const counts = /* @__PURE__ */ new Map();
7158
- for (const x of b) counts.set(x, (counts.get(x) || 0) + 1);
7159
- const extra = [];
7160
- for (const x of a) {
7161
- const c = counts.get(x) || 0;
7162
- if (c > 0) counts.set(x, c - 1);
7163
- else extra.push(x);
7164
- }
7165
- return extra;
7166
- }
7167
-
7168
- // src/playback/PxAnimatorConfigPatch.ts
7169
- var FLAT_ONLY_KEYS = [
7170
- "timelineSource",
7171
- "scroll",
7172
- "trigger",
7173
- "delay",
7174
- "iterations",
7175
- "direction",
7176
- "fill",
7177
- "resetOnFinish",
7178
- "duration",
7179
- "mode",
7180
- "frameRate"
7181
- ];
7182
- var CONTENT_KEYS = ["definitions", "animateById"];
7183
- var isPlainObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
7184
- var timelineTypeOf = (t) => isPlainObject(t) && typeof t.type === "string" ? t.type : "time";
7185
- var isScrollish = (type) => type === "scroll" || type === "view";
7186
- function mergePlain(base, patch) {
7187
- const out = isPlainObject(base) ? __spreadValues({}, base) : {};
7188
- for (const key of Object.keys(patch)) {
7189
- const value = patch[key];
7190
- if (value === null) {
7191
- delete out[key];
7192
- continue;
7193
- }
7194
- if (isPlainObject(value)) {
7195
- out[key] = mergePlain(out[key], value);
7196
- continue;
7197
- }
7198
- out[key] = value;
7199
- }
7200
- return out;
7201
- }
7202
- function mergeTimeline(base, patch, warn) {
7203
- const baseType = timelineTypeOf(base);
7204
- const patchNamesType = isPlainObject(patch) && typeof patch.type === "string";
7205
- const patchType = patchNamesType ? String(patch.type) : baseType;
7206
- let merged;
7207
- if (patchType !== baseType) {
7208
- const carried = {};
7209
- if (isPlainObject(base)) {
7210
- for (const k of PX_TIMELINE_SHARED_KEYS) {
7211
- if (base[k] !== void 0) carried[k] = base[k];
7212
- }
7213
- }
7214
- merged = mergePlain(carried, patch);
7215
- } else {
7216
- merged = mergePlain(base, patch);
7217
- }
7218
- if (isScrollish(patchType)) {
7219
- for (const k of PX_TIME_ONLY_TIMELINE_KEYS) {
7220
- if (merged[k] === void 0) continue;
7221
- warn("animator.timeline." + k + ": no slot on a '" + patchType + "' timeline \u2014 dropped");
7222
- delete merged[k];
7223
- }
7224
- if (merged.iterations === "infinite") {
7225
- warn("animator.timeline.iterations: 'infinite' cannot map onto a scroll range \u2014 dropped");
7226
- delete merged.iterations;
7227
- }
7228
- }
7229
- return merged;
7230
- }
7231
- function foldTimelineOverride(timeline, shortcuts) {
7232
- let base;
7233
- if (typeof timeline === "string") {
7234
- try {
7235
- base = JSON.parse(timeline);
7236
- } catch (e) {
7237
- console.warn("timeline override: not valid JSON \u2014 ignored", e);
7238
- base = void 0;
7239
- }
7240
- } else {
7241
- base = timeline != null ? timeline : void 0;
7242
- }
7243
- const { duration, delay, iterations, startOn } = shortcuts;
7244
- if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
7245
- return base === void 0 ? void 0 : { timeline: base };
7246
- }
7247
- const out = isPlainObject(base) ? __spreadValues({}, base) : {};
7248
- if (duration !== void 0) out.duration = duration;
7249
- if (delay !== void 0) out.delay = delay;
7250
- if (iterations !== void 0) out.iterations = iterations;
7251
- if (startOn !== void 0) {
7252
- out.trigger = __spreadProps(__spreadValues({}, out.trigger), { startOn });
7095
+ const times = /* @__PURE__ */ new Set();
7096
+ collectSampleTimes(a, times);
7097
+ collectSampleTimes(b, times);
7098
+ const diffs = [];
7099
+ for (const t of Array.from(times).sort((x, y) => x - y)) {
7100
+ const ma = visualModelAt(a, t);
7101
+ const mb = visualModelAt(b, t);
7102
+ const onlyInA = subtractMultiset(ma, mb);
7103
+ const onlyInB = subtractMultiset(mb, ma);
7104
+ if (onlyInA.length || onlyInB.length) diffs.push({ time: t, onlyInA, onlyInB });
7253
7105
  }
7254
- return { timeline: out };
7106
+ return diffs;
7255
7107
  }
7256
- function mergeAnimatorConfig(base, patch) {
7257
- const warnings = [];
7258
- const warn = (m) => warnings.push(m);
7259
- if (patch === null) return { config: void 0, warnings };
7260
- if (!isPlainObject(patch) || Object.keys(patch).length === 0) {
7261
- return { config: base, warnings };
7108
+ function subtractMultiset(a, b) {
7109
+ const counts = /* @__PURE__ */ new Map();
7110
+ for (const x of b) counts.set(x, (counts.get(x) || 0) + 1);
7111
+ const extra = [];
7112
+ for (const x of a) {
7113
+ const c = counts.get(x) || 0;
7114
+ if (c > 0) counts.set(x, c - 1);
7115
+ else extra.push(x);
7262
7116
  }
7263
- const flatInBase = isPlainObject(base) ? FLAT_ONLY_KEYS.filter((k) => base[k] !== void 0) : [];
7264
- if (flatInBase.length) {
7265
- warn("animator: the base carries the flat runtime spelling (" + flatInBase.join(", ") + "); the patch merges the wire spelling only");
7117
+ return extra;
7118
+ }
7119
+
7120
+ // src/playback/PxScrollMath.ts
7121
+ function isScrollTimeline(config) {
7122
+ return (config == null ? void 0 : config.timelineSource) === "scroll";
7123
+ }
7124
+ function scrollTotalDurationMs(config) {
7125
+ const duration = typeof (config == null ? void 0 : config.duration) === "number" && config.duration > 0 ? config.duration : DEFAULT_DURATION_MS;
7126
+ const iterations = typeof (config == null ? void 0 : config.iterations) === "number" && config.iterations > 0 ? config.iterations : 1;
7127
+ return duration * iterations;
7128
+ }
7129
+ function scrollPhaseInterval(phase, subjectSize, scrollportSize) {
7130
+ const s = subjectSize, vp = scrollportSize;
7131
+ switch (phase) {
7132
+ case "cover":
7133
+ return [0, s + vp];
7134
+ case "entry":
7135
+ return [0, Math.min(s, vp)];
7136
+ case "contain":
7137
+ return [Math.min(s, vp), Math.max(s, vp)];
7138
+ case "exit":
7139
+ return [Math.max(s, vp), s + vp];
7140
+ case "entry-crossing":
7141
+ return [0, s];
7142
+ case "exit-crossing":
7143
+ return [vp, s + vp];
7266
7144
  }
7267
- const out = isPlainObject(base) ? __spreadValues({}, base) : {};
7268
- for (const key of Object.keys(patch)) {
7269
- const value = patch[key];
7270
- if (value === null) {
7271
- delete out[key];
7272
- continue;
7273
- }
7274
- if (key === "timeline") {
7275
- out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
7276
- continue;
7277
- }
7278
- if (isPlainObject(value)) {
7279
- out[key] = mergePlain(out[key], value);
7280
- continue;
7145
+ }
7146
+ var DEFAULT_PHASE = "cover";
7147
+ function resolveRangePointU(point, defaultFraction, subjectSize, scrollportSize) {
7148
+ var _a2;
7149
+ const [u0, u1] = scrollPhaseInterval((_a2 = point == null ? void 0 : point.phase) != null ? _a2 : DEFAULT_PHASE, subjectSize, scrollportSize);
7150
+ const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
7151
+ return u0 + fraction * (u1 - u0);
7152
+ }
7153
+ function scrollViewProgress(subjectStart, subjectSize, scrollportSize, range) {
7154
+ const u = scrollportSize - subjectStart;
7155
+ const uStart = resolveRangePointU(range == null ? void 0 : range.start, 0, subjectSize, scrollportSize);
7156
+ const uEnd = resolveRangePointU(range == null ? void 0 : range.end, 1, subjectSize, scrollportSize);
7157
+ if (uEnd <= uStart) return u >= uEnd ? 1 : 0;
7158
+ return clamp((u - uStart) / (uEnd - uStart), 0, 1);
7159
+ }
7160
+ function scrollOffsetProgress(offset, maxOffset, range) {
7161
+ var _a2, _b;
7162
+ const raw = maxOffset > 0 ? clamp(offset / maxOffset, 0, 1) : 1;
7163
+ const start = typeof ((_a2 = range == null ? void 0 : range.start) == null ? void 0 : _a2.fraction) === "number" ? range.start.fraction : 0;
7164
+ const end = typeof ((_b = range == null ? void 0 : range.end) == null ? void 0 : _b.fraction) === "number" ? range.end.fraction : 1;
7165
+ if (end <= start) return raw >= end ? 1 : 0;
7166
+ return clamp((raw - start) / (end - start), 0, 1);
7167
+ }
7168
+ function scrollResolveAxis(axis, writingMode) {
7169
+ const a = axis != null ? axis : "block";
7170
+ if (a === "x" || a === "y") return a;
7171
+ const vertical = !!writingMode && writingMode.startsWith("vertical");
7172
+ if (a === "inline") return vertical ? "y" : "x";
7173
+ return vertical ? "x" : "y";
7174
+ }
7175
+
7176
+ // src/version/PxSchemaFieldUniverse.ts
7177
+ function schemaFieldUniverse(root) {
7178
+ const fields = /* @__PURE__ */ new Set();
7179
+ const enumerated = /* @__PURE__ */ new Set();
7180
+ const queue = [{ schema: root, path: "" }];
7181
+ while (queue.length) {
7182
+ const { schema, path } = queue.shift();
7183
+ const d = describeSchema(schema);
7184
+ switch (d.kind) {
7185
+ case "shape": {
7186
+ if (enumerated.has(schema)) break;
7187
+ enumerated.add(schema);
7188
+ for (const key of Object.keys(d.shape)) {
7189
+ const id = path ? path + "." + key : key;
7190
+ fields.add(id);
7191
+ queue.push({ schema: d.shape[key], path: id });
7192
+ }
7193
+ if (d.openValue) queue.push({ schema: d.openValue, path: path + "{*}" });
7194
+ break;
7195
+ }
7196
+ case "optional":
7197
+ queue.push({ schema: d.inner, path });
7198
+ break;
7199
+ case "array":
7200
+ queue.push({ schema: d.item, path: path + "[]" });
7201
+ break;
7202
+ case "lazy":
7203
+ queue.push({ schema: d.resolved, path });
7204
+ break;
7205
+ case "record":
7206
+ queue.push({ schema: d.value, path: path + "{*}" });
7207
+ break;
7208
+ case "union":
7209
+ d.members.forEach((member, i) => queue.push({ schema: member, path: path + "|" + i }));
7210
+ break;
7211
+ case "discriminatedUnion":
7212
+ for (const member of d.members) queue.push({ schema: member, path: path + "|" + discriminantOf(member, d.key) });
7213
+ break;
7214
+ default:
7215
+ break;
7281
7216
  }
7282
- out[key] = value;
7283
7217
  }
7284
- return { config: out, warnings };
7218
+ return [...fields].sort();
7285
7219
  }
7286
- function applyAnimatorConfig(doc, patch, opts) {
7287
- var _a2, _b;
7288
- const reset = !!(opts == null ? void 0 : opts.resetDefaults);
7289
- if (!doc || (patch === void 0 || !reset && (patch === null || !isPlainObject(patch) || !Object.keys(patch).length))) {
7290
- return { doc, warnings: [] };
7220
+ function discriminantOf(member, key) {
7221
+ const d = describeSchema(member);
7222
+ if (d.kind !== "shape") return "?";
7223
+ const keySchema = d.shape[key];
7224
+ if (keySchema === void 0) return "?";
7225
+ const kd = describeSchema(keySchema);
7226
+ return String((kd.kind === "optional" ? kd.inner : keySchema)._default);
7227
+ }
7228
+
7229
+ // src/version/PxSchemaRelease.ts
7230
+ function diffFieldUniverse(previous, current) {
7231
+ const prev = new Set(previous);
7232
+ const cur = new Set(current);
7233
+ return {
7234
+ added: current.filter((k) => !prev.has(k)).sort(),
7235
+ removed: previous.filter((k) => !cur.has(k)).sort()
7236
+ };
7237
+ }
7238
+ function planSchemaRelease(p) {
7239
+ const changed = p.added.length > 0 || p.removed.length > 0;
7240
+ const last = parseWireVersion(p.lastReleased);
7241
+ const declared = parseWireVersion(p.declared);
7242
+ if (!last || !declared) return { changed, refuse: "Unparseable version: " + p.lastReleased + " / " + p.declared + "." };
7243
+ const requiredVersion = last.a + "." + (last.b + 1);
7244
+ if (!changed) {
7245
+ if (declared.b === last.b && declared.a === last.a) return { changed };
7246
+ const step2 = p.steps.find((s) => s.to === p.declared);
7247
+ return step2 ? { changed, requiredVersion: p.declared } : { changed, refuse: "The version moved to " + p.declared + " with no key change and no step explaining it." };
7291
7248
  }
7292
- const anyDoc = doc;
7293
- const atRoot = isPlainObject(anyDoc.animator);
7294
- const atMeta = !atRoot && isPlainObject((_a2 = anyDoc.meta) == null ? void 0 : _a2.animator);
7295
- const current = atRoot ? anyDoc.animator : atMeta ? anyDoc.meta.animator : void 0;
7296
- const warnings = [];
7297
- if (atRoot && isPlainObject((_b = anyDoc.meta) == null ? void 0 : _b.animator)) {
7298
- warnings.push("animator: doc.meta.animator is shadowed by doc.animator and was not patched");
7249
+ const requiredKind = p.removed.length ? "converted" /* converted */ : "additive" /* additive */;
7250
+ const summary = p.added.length + " key(s) added, " + p.removed.length + " removed";
7251
+ if (declared.a !== last.a || declared.b !== last.b + 1) {
7252
+ return {
7253
+ changed,
7254
+ requiredKind,
7255
+ requiredVersion,
7256
+ refuse: "The player schema changed (" + summary + ") but PX_PLAYER_SCHEMA_VERSION is " + p.declared + ". Set it to " + requiredVersion + " and add the PLAYER_WIRE_STEPS entry."
7257
+ };
7299
7258
  }
7300
- let base = current;
7301
- if (reset) {
7302
- const kept = {};
7303
- for (const k of CONTENT_KEYS) {
7304
- if (isPlainObject(current) && current[k] !== void 0) kept[k] = current[k];
7305
- }
7306
- base = kept;
7259
+ const step = p.steps.find((s) => s.to === p.declared);
7260
+ if (!step) {
7261
+ return { changed, requiredKind, requiredVersion, refuse: "No PLAYER_WIRE_STEPS entry reaches " + p.declared + "." };
7307
7262
  }
7308
- const merged = mergeAnimatorConfig(base, patch != null ? patch : {});
7309
- warnings.push(...merged.warnings);
7310
- if (merged.config === current) return { doc, warnings };
7311
- if (atMeta) {
7263
+ if (requiredKind === "converted" /* converted */ && step.kind !== "converted" /* converted */) {
7312
7264
  return {
7313
- doc: __spreadProps(__spreadValues({}, anyDoc), { meta: __spreadProps(__spreadValues({}, anyDoc.meta), { animator: merged.config }) }),
7314
- warnings
7265
+ changed,
7266
+ requiredKind,
7267
+ requiredVersion,
7268
+ refuse: "Keys were REMOVED (" + p.removed.join(", ") + "), which is never additive \u2014 the " + p.declared + " step must be `converted`, with an up()."
7315
7269
  };
7316
7270
  }
7317
- return { doc: __spreadProps(__spreadValues({}, anyDoc), { animator: merged.config }), warnings };
7271
+ return { changed, requiredKind, requiredVersion };
7318
7272
  }
7319
-
7320
- // src/format/PxDocumentDiagnostic.ts
7321
- var MAX_REPORTED = 6;
7322
- function diagnoseDocument(doc) {
7323
- try {
7324
- return { problems: validateDocument(doc) };
7325
- } catch (e) {
7326
- return { problems: [] };
7273
+ function releaseLogProblems(releases, steps, declared, baseline) {
7274
+ const problems = [];
7275
+ if (!releases.length) return ["The release log is empty."];
7276
+ if (!releases[0].baseline || releases[0].version !== baseline) {
7277
+ problems.push("The first release must be the baseline " + baseline + ".");
7327
7278
  }
7328
- }
7329
- function reportDocumentDiagnostics(doc, where) {
7330
- const { problems } = diagnoseDocument(doc);
7331
- if (!problems.length) return;
7332
- const shown = problems.slice(0, MAX_REPORTED);
7333
- const more = problems.length - shown.length;
7334
- console.warn(
7335
- 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."
7336
- );
7279
+ for (let i = 1; i < releases.length; i++) {
7280
+ const prev = parseWireVersion(releases[i - 1].version);
7281
+ const cur = parseWireVersion(releases[i].version);
7282
+ if (!prev || !cur || cur.a !== prev.a || cur.b !== prev.b + 1) {
7283
+ problems.push("Release " + releases[i].version + " does not follow " + releases[i - 1].version + " by one `b` step.");
7284
+ }
7285
+ if (releases[i].date < releases[i - 1].date) problems.push("Release " + releases[i].version + " is dated before its predecessor.");
7286
+ const step = steps.find((s) => s.to === releases[i].version);
7287
+ if (!step) problems.push("Release " + releases[i].version + " has no PLAYER_WIRE_STEPS entry.");
7288
+ else if (releases[i].removed.length && step.kind !== "converted" /* converted */) {
7289
+ problems.push("Release " + releases[i].version + " removed keys, but its step is not `converted`.");
7290
+ }
7291
+ }
7292
+ const latest = releases[releases.length - 1].version;
7293
+ if (latest !== declared) {
7294
+ problems.push("PX_PLAYER_SCHEMA_VERSION is " + declared + " but the last release record is " + latest + " \u2014 a bump needs its changelog entry (run scripts/schema-release.mjs --apply).");
7295
+ }
7296
+ return problems;
7337
7297
  }
7338
7298
  // Annotate the CommonJS export names for ESM import in node:
7339
7299
  0 && (module.exports = {
@@ -7342,9 +7302,7 @@ function reportDocumentDiagnostics(doc, where) {
7342
7302
  CSS_ONLY_STYLE_PROPS,
7343
7303
  DEFAULT_DURATION_MS,
7344
7304
  DISALLOWED_SVG_TAGS_LOWER,
7345
- INTERNAL_ATTRS,
7346
7305
  LOOP_JUMP_SHIFT_MS,
7347
- MISSING_GLYPH_CLASS_NAME,
7348
7306
  PCT_BASED_ATTR_NAMES,
7349
7307
  PLAYER_WIRE_STEPS,
7350
7308
  PLAYER_WIRE_VERSION,
@@ -7357,18 +7315,15 @@ function reportDocumentDiagnostics(doc, where) {
7357
7315
  PX_UNKNOWN_KEY_ERROR,
7358
7316
  PxAlongPathMode,
7359
7317
  PxAnimatedSvgDocumentSchema,
7360
- PxAnimationDefinitionSchema,
7361
7318
  PxAnimatorConfigSchema,
7362
7319
  PxAttrValueSchema,
7363
7320
  PxBezierPathSchema,
7364
- PxBindingSchema,
7365
7321
  PxClipPathEffectSchema,
7366
7322
  PxCloneEffectSchema,
7367
7323
  PxCloneWithout,
7368
7324
  PxControlMode,
7369
7325
  PxDefsSchema,
7370
7326
  PxDiagnosticKind,
7371
- PxEasingOrRefSchema,
7372
7327
  PxEffectsSchema,
7373
7328
  PxElementAnimationSchema,
7374
7329
  PxFillGradientEffectSchema,
@@ -7402,7 +7357,6 @@ function reportDocumentDiagnostics(doc, where) {
7402
7357
  PxScrollSchema,
7403
7358
  PxScrollSource,
7404
7359
  PxStartOn,
7405
- PxStrokeGradientEffectSchema,
7406
7360
  PxStrokeTrimEffectSchema,
7407
7361
  PxStrokeTrimSubPaths,
7408
7362
  PxSvgNodeExtra,
@@ -7412,7 +7366,6 @@ function reportDocumentDiagnostics(doc, where) {
7412
7366
  PxTextPathSpacing,
7413
7367
  PxTimelineEngine,
7414
7368
  PxTimelineEngineExtra,
7415
- PxTimelinePinSchema,
7416
7369
  PxTimelineSchema,
7417
7370
  PxTransformByEffectSchema,
7418
7371
  PxTransformPartsSchema,
@@ -7428,13 +7381,11 @@ function reportDocumentDiagnostics(doc, where) {
7428
7381
  applyAnimatorConfig,
7429
7382
  applyPlayerEffects,
7430
7383
  applyWireSteps,
7431
- applyWireStepsDown,
7432
7384
  bezierToSvgPath,
7433
7385
  calcAnimationValues,
7434
7386
  camelCaseToKebabWordIfNeeded,
7435
7387
  clamp,
7436
7388
  clampSeekMs,
7437
- collectSampleTimes,
7438
7389
  compareWireVersion,
7439
7390
  composeTransformParts,
7440
7391
  controlModeTakesOverTrigger,
@@ -7450,7 +7401,6 @@ function reportDocumentDiagnostics(doc, where) {
7450
7401
  diffFieldUniverse,
7451
7402
  diffInEffect,
7452
7403
  downgradePlayerDocument,
7453
- evaluateMotionPathSegment,
7454
7404
  extendedPathForBrowser,
7455
7405
  flattenAnimatorTimeline,
7456
7406
  foldTimelineOverride,
@@ -7463,46 +7413,33 @@ function reportDocumentDiagnostics(doc, where) {
7463
7413
  getDefs,
7464
7414
  getNormalizedBindings,
7465
7415
  getNormalizedProps,
7466
- interpolateBeziers,
7467
7416
  interpolateValue,
7468
7417
  isNativeForced,
7469
7418
  isPxElementFileFormat,
7470
7419
  isPxElementFileFormatDeep,
7471
7420
  isScrollTimeline,
7472
7421
  isValidPlaybackRate,
7473
- jsonElementFactory,
7474
7422
  kebabToCamelCaseWord,
7475
7423
  kfEasing,
7476
- kfTangentIn,
7477
- kfTangentOut,
7478
- kfTime,
7479
7424
  kfValue,
7480
7425
  layoutGlyphTextChars,
7481
7426
  materializeAllInTree,
7482
- materializeAnimatedUseInstances,
7483
7427
  materializeGlyphText,
7484
7428
  materializeGlyphTextAlongPath,
7485
- materializeGlyphTextHorizontal,
7486
- materializeInternalLoopsInPropAnim,
7487
- materializeInternalLoopsInTree,
7488
7429
  materializeMotionPathInPropAnim,
7489
- materializeMotionPathsInTree,
7490
7430
  mayUseNativeScrollTimeline,
7491
7431
  mergeAnimatorConfig,
7492
7432
  mergeStaticTransformIntoAnimDef,
7493
7433
  nestAnimatorTimeline,
7494
- parseTransformParts,
7495
7434
  parseWireVersion,
7496
7435
  planSchemaRelease,
7497
7436
  progressSpanMs,
7498
7437
  progressToTimeMs,
7499
- propAnimIsMotionPath,
7500
7438
  px,
7501
7439
  readWireVersion,
7502
7440
  releaseLogProblems,
7503
7441
  reportDocumentDiagnostics,
7504
7442
  resolveControlMode,
7505
- resolveStyle,
7506
7443
  resolveTimelineEngine,
7507
7444
  resolveTrigger,
7508
7445
  reverseEasing,
@@ -7515,14 +7452,12 @@ function reportDocumentDiagnostics(doc, where) {
7515
7452
  scrollTotalDurationMs,
7516
7453
  scrollViewProgress,
7517
7454
  seekCeilingMs,
7518
- shiftAnimatable,
7519
7455
  splitEasing,
7520
7456
  subdivideCubicBezier,
7521
7457
  timeToProgress,
7522
7458
  toRGBA,
7523
7459
  validateDocument,
7524
7460
  validateNodeEffects,
7525
- versionAdvice,
7526
- visualModelAt
7461
+ versionAdvice
7527
7462
  });
7528
7463
  //# sourceMappingURL=index.cjs.map