@pixodesk/svg-animator-core 1.0.35 → 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
@@ -51,68 +51,81 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
51
51
  var index_exports = {};
52
52
  __export(index_exports, {
53
53
  BASELINE_PLAYER_VERSION: () => BASELINE_PLAYER_VERSION,
54
- COLOUR_ATTR_NAMES: () => COLOUR_ATTR_NAMES,
54
+ COLOR_ATTR_NAMES: () => COLOR_ATTR_NAMES,
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,
64
62
  PX_ANIM_ATTR_NAME: () => PX_ANIM_ATTR_NAME,
65
63
  PX_ANIM_SRC_ATTR_NAME: () => PX_ANIM_SRC_ATTR_NAME,
66
64
  PX_PLAYER_SCHEMA_VERSION: () => PX_PLAYER_SCHEMA_VERSION,
65
+ PX_RATE_REJECTED: () => PX_RATE_REJECTED,
67
66
  PX_TRANSFORM_PART_KEYS: () => PX_TRANSFORM_PART_KEYS,
67
+ PX_TRIGGER_DEFAULTS: () => PX_TRIGGER_DEFAULTS,
68
68
  PX_UNKNOWN_KEY_ERROR: () => PX_UNKNOWN_KEY_ERROR,
69
+ PxAlongPathMode: () => PxAlongPathMode,
69
70
  PxAnimatedSvgDocumentSchema: () => PxAnimatedSvgDocumentSchema,
70
- PxAnimationDefinitionSchema: () => PxAnimationDefinitionSchema,
71
71
  PxAnimatorConfigSchema: () => PxAnimatorConfigSchema,
72
72
  PxAttrValueSchema: () => PxAttrValueSchema,
73
73
  PxBezierPathSchema: () => PxBezierPathSchema,
74
- PxBindingSchema: () => PxBindingSchema,
74
+ PxClipPathEffectSchema: () => PxClipPathEffectSchema,
75
75
  PxCloneEffectSchema: () => PxCloneEffectSchema,
76
76
  PxCloneWithout: () => PxCloneWithout,
77
+ PxControlMode: () => PxControlMode,
77
78
  PxDefsSchema: () => PxDefsSchema,
78
- PxEasingOrRefSchema: () => PxEasingOrRefSchema,
79
+ PxDiagnosticKind: () => PxDiagnosticKind,
79
80
  PxEffectsSchema: () => PxEffectsSchema,
80
81
  PxElementAnimationSchema: () => PxElementAnimationSchema,
81
82
  PxFillGradientEffectSchema: () => PxFillGradientEffectSchema,
83
+ PxFillMode: () => PxFillMode,
84
+ PxFinishAction: () => PxFinishAction,
82
85
  PxGradientSpreadMethod: () => PxGradientSpreadMethod,
83
86
  PxGradientStopSchema: () => PxGradientStopSchema,
84
87
  PxGradientType: () => PxGradientType,
85
- PxGradientUnits: () => PxGradientUnits,
86
88
  PxKeyframeSchema: () => PxKeyframeSchema,
87
89
  PxKeyframeValueSchema: () => PxKeyframeValueSchema,
90
+ PxLengthAdjust: () => PxLengthAdjust,
88
91
  PxLoopDirection: () => PxLoopDirection,
89
92
  PxLoopRepeatAt: () => PxLoopRepeatAt,
90
93
  PxLoopSchema: () => PxLoopSchema,
94
+ PxMaskType: () => PxMaskType,
91
95
  PxMaskedByEffectSchema: () => PxMaskedByEffectSchema,
92
96
  PxNodeBase: () => PxNodeBase,
93
97
  PxNodeSchema: () => PxNodeSchema,
98
+ PxOutAction: () => PxOutAction,
99
+ PxPathOverflow: () => PxPathOverflow,
100
+ PxPinAlign: () => PxPinAlign,
101
+ PxPlaybackDirection: () => PxPlaybackDirection,
94
102
  PxPropertyAnimationSchema: () => PxPropertyAnimationSchema,
95
103
  PxRepeaterEffectSchema: () => PxRepeaterEffectSchema,
96
104
  PxRetimeEffectSchema: () => PxRetimeEffectSchema,
105
+ PxScrollAxis: () => PxScrollAxis,
106
+ PxScrollKind: () => PxScrollKind,
107
+ PxScrollPhase: () => PxScrollPhase,
97
108
  PxScrollRangePointSchema: () => PxScrollRangePointSchema,
98
109
  PxScrollRangeSchema: () => PxScrollRangeSchema,
99
110
  PxScrollSchema: () => PxScrollSchema,
100
- PxStrokeGradientEffectSchema: () => PxStrokeGradientEffectSchema,
111
+ PxScrollSource: () => PxScrollSource,
112
+ PxStartOn: () => PxStartOn,
101
113
  PxStrokeTrimEffectSchema: () => PxStrokeTrimEffectSchema,
102
114
  PxStrokeTrimSubPaths: () => PxStrokeTrimSubPaths,
103
115
  PxSvgNodeExtra: () => PxSvgNodeExtra,
104
116
  PxTextEffectSchema: () => PxTextEffectSchema,
105
117
  PxTextPathEffectSchema: () => PxTextPathEffectSchema,
118
+ PxTextPathMethod: () => PxTextPathMethod,
119
+ PxTextPathSpacing: () => PxTextPathSpacing,
106
120
  PxTimelineEngine: () => PxTimelineEngine,
107
121
  PxTimelineEngineExtra: () => PxTimelineEngineExtra,
108
- PxTimelinePinSchema: () => PxTimelinePinSchema,
109
122
  PxTimelineSchema: () => PxTimelineSchema,
110
123
  PxTransformByEffectSchema: () => PxTransformByEffectSchema,
111
124
  PxTransformPartsSchema: () => PxTransformPartsSchema,
112
125
  PxTransformValueSchema: () => PxTransformValueSchema,
113
126
  PxTriggerSchema: () => PxTriggerSchema,
127
+ PxUnits: () => PxUnits,
114
128
  STYLE_ATTR_NAMES: () => STYLE_ATTR_NAMES,
115
- TEXT_ATTR: () => TEXT_ATTR,
116
129
  TEXT_CONTENT_ATTR: () => TEXT_CONTENT_ATTR,
117
130
  TRANSFORM_FN_NAMES: () => TRANSFORM_FN_NAMES,
118
131
  WIRE_VERSION_KEY: () => WIRE_VERSION_KEY,
@@ -121,17 +134,19 @@ __export(index_exports, {
121
134
  applyAnimatorConfig: () => applyAnimatorConfig,
122
135
  applyPlayerEffects: () => applyPlayerEffects,
123
136
  applyWireSteps: () => applyWireSteps,
124
- applyWireStepsDown: () => applyWireStepsDown,
125
137
  bezierToSvgPath: () => bezierToSvgPath,
126
138
  calcAnimationValues: () => calcAnimationValues,
127
139
  camelCaseToKebabWordIfNeeded: () => camelCaseToKebabWordIfNeeded,
128
140
  clamp: () => clamp,
129
- collectSampleTimes: () => collectSampleTimes,
141
+ clampSeekMs: () => clampSeekMs,
130
142
  compareWireVersion: () => compareWireVersion,
131
143
  composeTransformParts: () => composeTransformParts,
144
+ controlModeTakesOverTrigger: () => controlModeTakesOverTrigger,
132
145
  convertPlayerDocument: () => convertPlayerDocument,
133
146
  createBasicFrameLoopAnimator: () => createBasicFrameLoopAnimator,
147
+ createDiagnostics: () => createDiagnostics,
134
148
  createPathSampler: () => createPathSampler,
149
+ createRunClock: () => createRunClock,
135
150
  cubicBezier: () => cubicBezier,
136
151
  deepClone: () => deepClone,
137
152
  describeSchema: () => describeSchema,
@@ -139,10 +154,9 @@ __export(index_exports, {
139
154
  diffFieldUniverse: () => diffFieldUniverse,
140
155
  diffInEffect: () => diffInEffect,
141
156
  downgradePlayerDocument: () => downgradePlayerDocument,
142
- evaluateMotionPathSegment: () => evaluateMotionPathSegment,
143
157
  extendedPathForBrowser: () => extendedPathForBrowser,
144
158
  flattenAnimatorTimeline: () => flattenAnimatorTimeline,
145
- foldAnimatorConfigShortcuts: () => foldAnimatorConfigShortcuts,
159
+ foldTimelineOverride: () => foldTimelineOverride,
146
160
  formatWireVersion: () => formatWireVersion,
147
161
  generateNewIds: () => generateNewIds,
148
162
  generateUniqueId: () => generateUniqueId,
@@ -150,47 +164,39 @@ __export(index_exports, {
150
164
  getBindings: () => getBindings,
151
165
  getChildren: () => getChildren,
152
166
  getDefs: () => getDefs,
153
- getNormalisedBindings: () => getNormalisedBindings,
167
+ getNormalizedBindings: () => getNormalizedBindings,
154
168
  getNormalizedProps: () => getNormalizedProps,
155
- interpolateBeziers: () => interpolateBeziers,
156
169
  interpolateValue: () => interpolateValue,
157
170
  isNativeForced: () => isNativeForced,
158
171
  isPxElementFileFormat: () => isPxElementFileFormat,
159
172
  isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
160
173
  isScrollTimeline: () => isScrollTimeline,
161
- jsonElementFactory: () => jsonElementFactory,
174
+ isValidPlaybackRate: () => isValidPlaybackRate,
162
175
  kebabToCamelCaseWord: () => kebabToCamelCaseWord,
163
176
  kfEasing: () => kfEasing,
164
- kfTangentIn: () => kfTangentIn,
165
- kfTangentOut: () => kfTangentOut,
166
- kfTime: () => kfTime,
167
177
  kfValue: () => kfValue,
168
178
  layoutGlyphTextChars: () => layoutGlyphTextChars,
169
- materialiseAllInTree: () => materialiseAllInTree,
170
- materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
171
- materialiseGlyphText: () => materialiseGlyphText,
172
- materialiseGlyphTextAlongPath: () => materialiseGlyphTextAlongPath,
173
- materialiseGlyphTextHorizontal: () => materialiseGlyphTextHorizontal,
174
- materialiseInternalLoopsInPropAnim: () => materialiseInternalLoopsInPropAnim,
175
- materialiseInternalLoopsInTree: () => materialiseInternalLoopsInTree,
176
- materialiseMotionPathInPropAnim: () => materialiseMotionPathInPropAnim,
177
- materialiseMotionPathsInTree: () => materialiseMotionPathsInTree,
179
+ materializeAllInTree: () => materializeAllInTree,
180
+ materializeGlyphText: () => materializeGlyphText,
181
+ materializeGlyphTextAlongPath: () => materializeGlyphTextAlongPath,
182
+ materializeMotionPathInPropAnim: () => materializeMotionPathInPropAnim,
178
183
  mayUseNativeScrollTimeline: () => mayUseNativeScrollTimeline,
179
184
  mergeAnimatorConfig: () => mergeAnimatorConfig,
180
185
  mergeStaticTransformIntoAnimDef: () => mergeStaticTransformIntoAnimDef,
181
186
  nestAnimatorTimeline: () => nestAnimatorTimeline,
182
- parseTransformParts: () => parseTransformParts,
183
187
  parseWireVersion: () => parseWireVersion,
184
188
  planSchemaRelease: () => planSchemaRelease,
185
- propAnimIsMotionPath: () => propAnimIsMotionPath,
189
+ progressSpanMs: () => progressSpanMs,
190
+ progressToTimeMs: () => progressToTimeMs,
186
191
  px: () => px,
187
192
  readWireVersion: () => readWireVersion,
188
193
  releaseLogProblems: () => releaseLogProblems,
189
194
  reportDocumentDiagnostics: () => reportDocumentDiagnostics,
190
- resolveStyle: () => resolveStyle,
195
+ resolveControlMode: () => resolveControlMode,
191
196
  resolveTimelineEngine: () => resolveTimelineEngine,
197
+ resolveTrigger: () => resolveTrigger,
192
198
  reverseEasing: () => reverseEasing,
193
- sanitiseAttributeValue: () => sanitiseAttributeValue,
199
+ sanitizeAttributeValue: () => sanitizeAttributeValue,
194
200
  schemaFieldUniverse: () => schemaFieldUniverse,
195
201
  schemaKeys: () => schemaKeys,
196
202
  scrollOffsetProgress: () => scrollOffsetProgress,
@@ -198,608 +204,104 @@ __export(index_exports, {
198
204
  scrollResolveAxis: () => scrollResolveAxis,
199
205
  scrollTotalDurationMs: () => scrollTotalDurationMs,
200
206
  scrollViewProgress: () => scrollViewProgress,
201
- shiftAnimatable: () => shiftAnimatable,
207
+ seekCeilingMs: () => seekCeilingMs,
202
208
  splitEasing: () => splitEasing,
203
209
  subdivideCubicBezier: () => subdivideCubicBezier,
210
+ timeToProgress: () => timeToProgress,
204
211
  toRGBA: () => toRGBA,
205
212
  validateDocument: () => validateDocument,
206
213
  validateNodeEffects: () => validateNodeEffects,
207
- versionAdvice: () => versionAdvice,
208
- visualModelAt: () => visualModelAt
214
+ versionAdvice: () => versionAdvice
209
215
  });
210
216
  module.exports = __toCommonJS(index_exports);
211
217
 
212
- // src/util/PxAnimatorUtil.ts
213
- function bezierToSvgPath(path, forceCurves = false) {
214
- var _a2, _b, _c, _d;
215
- const v = path.v;
216
- const i = path.i;
217
- const o = path.o;
218
- const c = path.c;
219
- if (!v.length) return "";
220
- const d = [];
221
- const len = v.length;
222
- d.push("M" + v[0][0] + "," + v[0][1]);
223
- for (let idx = 1; idx < len; idx++) {
224
- const prevV = v[idx - 1];
225
- const prevO = (_a2 = o == null ? void 0 : o[idx - 1]) != null ? _a2 : prevV;
226
- const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
227
- const currV = v[idx];
228
- const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
229
- if (isLine) {
230
- d.push("L" + currV[0] + "," + currV[1]);
231
- } else {
232
- d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
233
- }
234
- }
235
- if (c && len > 0) {
236
- const lastV = v[len - 1];
237
- const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
238
- const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
239
- const firstV = v[0];
240
- const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
241
- if (!isLine) {
242
- d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
243
- }
244
- 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;
245
226
  }
246
- return d.join("");
247
- }
248
- function interpolateNum(a, b, t) {
249
- return a + (b - a) * t;
227
+ return result;
250
228
  }
251
- function interpolateVec(a, b, t) {
252
- const res = [];
253
- const count = Math.max(a.length, b.length);
254
- for (let i = 0; i < count; i++) {
255
- res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
229
+ var Base = class {
230
+ _canSanitize(raw) {
231
+ return this.isValid(raw);
256
232
  }
257
- return res;
258
- }
259
- function interpolateColor(a, b, t) {
260
- return [
261
- interpolateNum(a[0] || 0, b[0] || 0, t),
262
- interpolateNum(a[1] || 0, b[1] || 0, t),
263
- interpolateNum(a[2] || 0, b[2] || 0, t),
264
- interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
265
- ];
266
- }
267
- function interpolateBeziers(paths1, paths2, progress) {
268
- const count = Math.max(paths1.length, paths2.length);
269
- const res = [];
270
- for (let i = 0; i < count; i++) {
271
- res.push(interpolateBezier(paths1[i], paths2[i], progress));
233
+ optional() {
234
+ return new Optional(this);
272
235
  }
273
- return res;
274
- }
275
- function interpolateBezier(path1, path2, progress) {
276
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
277
- if (!path1 || !path2) return path1 || path2 || { v: [] };
278
- const t = Math.min(Math.max(progress, 0), 1);
279
- const len = Math.min(path1.v.length, path2.v.length);
280
- const v = [];
281
- const i = [];
282
- const o = [];
283
- for (let idx = 0; idx < len; idx++) {
284
- const v1 = path1.v[idx];
285
- const v2 = path2.v[idx];
286
- v.push(interpolateVec(v1, v2, t));
287
- const i1 = (_b = (_a2 = path1.i) == null ? void 0 : _a2[idx]) != null ? _b : v1;
288
- const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
289
- i.push(interpolateVec(i1, i2, t));
290
- const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
291
- const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
292
- 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;
293
242
  }
294
- return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
295
- }
296
- function remap(value, inMin, inMax, outMin, outMax) {
297
- if (inMax === inMin) return outMin;
298
- const t = (value - inMin) / (inMax - inMin);
299
- return outMin + t * (outMax - outMin);
300
- }
301
- function solveCubicBezierX(p1x, p2x, x) {
302
- if (x <= 0) return 0;
303
- if (x >= 1) return 1;
304
- const cx = 3 * p1x;
305
- const bx = 3 * (p2x - p1x) - cx;
306
- const ax = 1 - cx - bx;
307
- function sampleX(t) {
308
- 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;
309
246
  }
310
- function sampleDX(t) {
311
- 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);
312
250
  }
313
- let t2 = x;
314
- let t0 = 0;
315
- let t1 = 1;
316
- for (let i = 0; i < 8; i++) {
317
- const x2 = sampleX(t2) - x;
318
- if (Math.abs(x2) < 1e-6) return t2;
319
- const d2 = sampleDX(t2);
320
- if (Math.abs(d2) < 1e-6) break;
321
- t2 -= x2 / d2;
251
+ _canSanitize(raw) {
252
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
322
253
  }
323
- t2 = x;
324
- while (t0 < t1) {
325
- const x2 = sampleX(t2);
326
- if (Math.abs(x2 - x) < 1e-6) return t2;
327
- if (x > x2) t0 = t2;
328
- else t1 = t2;
329
- t2 = (t1 + t0) / 2;
254
+ };
255
+ var Str = class extends Base {
256
+ constructor(_default = "") {
257
+ super();
258
+ this._default = _default;
330
259
  }
331
- return t2;
332
- }
333
- function cubicBezier(easing) {
334
- const [p1x, p1y, p2x, p2y] = easing;
335
- const cy = 3 * p1y;
336
- const by = 3 * (p2y - p1y) - cy;
337
- const ay = 1 - cy - by;
338
- function sampleCurveY(t) {
339
- return ((ay * t + by) * t + cy) * t;
260
+ sanitize(raw) {
261
+ return typeof raw === "string" ? raw : this._default;
340
262
  }
341
- return function(x) {
342
- return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
343
- };
344
- }
345
- function lerp2(a, b, t) {
346
- return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
347
- }
348
- function subdivideCubicBezier(p0, p1, p2, p3, t) {
349
- const q0 = lerp2(p0, p1, t);
350
- const q1 = lerp2(p1, p2, t);
351
- const q2 = lerp2(p2, p3, t);
352
- const r0 = lerp2(q0, q1, t);
353
- const r1 = lerp2(q1, q2, t);
354
- const s = lerp2(r0, r1, t);
355
- return {
356
- left: [p0, q0, r0, s],
357
- right: [s, r1, q2, p3]
358
- };
359
- }
360
- function splitEasing(easing, xFraction) {
361
- if (!easing) return { left: void 0, right: void 0 };
362
- if (xFraction <= 0) return { left: void 0, right: easing };
363
- if (xFraction >= 1) return { left: easing, right: void 0 };
364
- const [x1, y1, x2, y2] = easing;
365
- const t = solveCubicBezierX(x1, x2, xFraction);
366
- const p0 = [0, 0];
367
- const p1 = [x1, y1];
368
- const p2 = [x2, y2];
369
- const p3 = [1, 1];
370
- const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
371
- const sx = left[3][0];
372
- const sy = left[3][1];
373
- let leftEasing;
374
- if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
375
- leftEasing = [
376
- left[1][0] / sx,
377
- left[1][1] / sy,
378
- left[2][0] / sx,
379
- left[2][1] / sy
380
- ];
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;
381
267
  }
382
- let rightEasing;
383
- const rx = 1 - sx;
384
- const ry = 1 - sy;
385
- if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
386
- rightEasing = [
387
- (right[1][0] - sx) / rx,
388
- (right[1][1] - sy) / ry,
389
- (right[2][0] - sx) / rx,
390
- (right[2][1] - sy) / ry
391
- ];
268
+ };
269
+ var Num = class extends Base {
270
+ constructor(_default = 0) {
271
+ super();
272
+ this._default = _default;
392
273
  }
393
- return { left: leftEasing, right: rightEasing };
394
- }
395
- function reverseEasing(easing) {
396
- if (!easing) return void 0;
397
- return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
398
- }
399
- function toRGBA(color) {
400
- const r = Math.round(color[0] * 255);
401
- const g = Math.round(color[1] * 255);
402
- const b = Math.round(color[2] * 255);
403
- return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
404
- }
405
- function parseRgba(s) {
406
- var _a2;
407
- const inner = (_a2 = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a2[1];
408
- if (!inner) throw new Error("Invalid rgb/rgba format");
409
- const parts = inner.split(",").map((v) => +v.trim());
410
- return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
411
- }
412
- function parseHex(s) {
413
- const hex = s.slice(1);
414
- const isShort = hex.length <= 4;
415
- const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
416
- const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
417
- const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
418
- const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
419
- const result = [
420
- parseInt(r, 16) / 255,
421
- parseInt(g, 16) / 255,
422
- parseInt(b, 16) / 255
423
- ];
424
- if (a !== null) {
425
- result.push(parseInt(a, 16) / 255);
274
+ sanitize(raw) {
275
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
426
276
  }
427
- return result;
428
- }
429
- function parseColor(s) {
430
- if (!s) return void 0;
431
- if (Array.isArray(s)) return s;
432
- if (typeof s !== "string") return void 0;
433
- if (s.startsWith("#")) {
434
- return parseHex(s);
435
- } else if (s.startsWith("rgb")) {
436
- return parseRgba(s);
437
- } else {
438
- 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;
439
281
  }
440
- return void 0;
441
- }
442
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
443
- var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
444
- var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
445
- function composeTransformParts(parts, opts) {
446
- var _a2;
447
- if (!parts) return "";
448
- const withUnits = (_a2 = opts == null ? void 0 : opts.withUnits) != null ? _a2 : true;
449
- const segs = [];
450
- const t = parts.translate;
451
- const o = parts.origin;
452
- const r = parts.rotate;
453
- const k = parts.skew;
454
- const s = parts.scale;
455
- const tu = withUnits ? "px" : "";
456
- const ru = withUnits ? "deg" : "";
457
- if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
458
- if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
459
- if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
460
- if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
461
- if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
462
- if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
463
- return segs.join("");
464
- }
465
- function parseTransformParts(str2) {
466
- var _a2, _b;
467
- if (!str2 || typeof str2 !== "string") return void 0;
468
- const out = {};
469
- const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
470
- const order = ["translate", "rotate", "skewX", "scale"];
471
- let lastIdx = -1;
472
- let m;
473
- while ((m = re.exec(str2)) !== null) {
474
- const fn = m[1];
475
- const idx = order.indexOf(fn);
476
- if (idx < 0 || idx <= lastIdx) return void 0;
477
- lastIdx = idx;
478
- const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
479
- if (nums.some((n) => Number.isNaN(n))) return void 0;
480
- if (fn === "translate") {
481
- if (nums.length < 1 || nums.length > 2) return void 0;
482
- out.translate = [nums[0], (_a2 = nums[1]) != null ? _a2 : 0];
483
- } else if (fn === "rotate") {
484
- if (nums.length !== 1) return void 0;
485
- out.rotate = nums[0];
486
- } else if (fn === "skewX") {
487
- if (nums.length !== 1) return void 0;
488
- out.skew = nums[0];
489
- } else {
490
- if (nums.length < 1 || nums.length > 2) return void 0;
491
- out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
492
- }
282
+ };
283
+ var Bool = class extends Base {
284
+ constructor(_default = false) {
285
+ super();
286
+ this._default = _default;
493
287
  }
494
- if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
495
- return Object.keys(out).length ? out : void 0;
496
- }
497
- var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
498
- var DEFAULT_DURATION_MS = 1e3;
499
- function kebabToCamelCaseWord(kebab) {
500
- return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
501
- }
502
- function isCamelCaseWord(word) {
503
- return !word.includes("-") && /[a-z][A-Z]/.test(word);
504
- }
505
- var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
506
- // Transform/positioning
507
- "viewBox",
508
- "preserveAspectRatio",
509
- // Gradient
510
- "gradientUnits",
511
- "gradientTransform",
512
- "spreadMethod",
513
- // Pattern
514
- "patternUnits",
515
- "patternContentUnits",
516
- "patternTransform",
517
- // Clipping/masking
518
- "clipPathUnits",
519
- "maskUnits",
520
- "maskContentUnits",
521
- // Marker (SVG spec keeps these camelCase, like viewBox)
522
- "markerUnits",
523
- "markerWidth",
524
- "markerHeight",
525
- "refX",
526
- "refY",
527
- // Text
528
- "textLength",
529
- "lengthAdjust",
530
- "startOffset",
531
- // Filter
532
- "filterUnits",
533
- "primitiveUnits",
534
- "tableValues",
535
- // feFuncR/G/B/A transfer table (type="table")
536
- "stdDeviation",
537
- "baseFrequency",
538
- "numOctaves",
539
- "surfaceScale",
540
- "diffuseConstant",
541
- "specularConstant",
542
- "specularExponent",
543
- "kernelMatrix",
544
- "kernelUnitLength",
545
- "edgeMode",
546
- "preserveAlpha",
547
- "targetX",
548
- "targetY"
549
- // // Animation
550
- // 'attributeName',
551
- // 'attributeType',
552
- // 'calcMode',
553
- // 'keyTimes',
554
- // 'keySplines',
555
- // 'repeatCount',
556
- // 'repeatDur'
557
- ]);
558
- function camelCaseToKebabWordIfNeeded(camel) {
559
- return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
560
- }
561
- function clamp(value, min, max) {
562
- return Math.max(min, Math.min(value, max));
563
- }
564
- function bezier2D_pointAt(P0, P1, P2, P3, t) {
565
- if (t <= 0) return [P0[0], P0[1]];
566
- if (t >= 1) return [P3[0], P3[1]];
567
- const u = 1 - t;
568
- const u2 = u * u;
569
- const u3 = u2 * u;
570
- const t2 = t * t;
571
- const t3 = t2 * t;
572
- const w0 = u3;
573
- const w1 = 3 * t * u2;
574
- const w2 = 3 * t2 * u;
575
- const w3 = t3;
576
- return [
577
- w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
578
- w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
579
- ];
580
- }
581
- var BEZIER_T_NUDGE = 1e-4;
582
- function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
583
- const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
584
- if (result[0] === 0 && result[1] === 0) {
585
- const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
586
- return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
288
+ sanitize(raw) {
289
+ return typeof raw === "boolean" ? raw : this._default;
587
290
  }
588
- return result;
589
- }
590
- function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
591
- const u = 1 - t;
592
- const a = 3 * u * u;
593
- const b = 6 * t * u;
594
- const c = 3 * t * t;
595
- return [
596
- a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
597
- a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
598
- ];
599
- }
600
- function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
601
- const n = steps + 1;
602
- const ts = new Float64Array(n);
603
- const ds = new Float64Array(n);
604
- let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
605
- ts[0] = 0;
606
- ds[0] = 0;
607
- let cum = 0;
608
- for (let i = 1; i < n; i++) {
609
- const t = i / steps;
610
- const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
611
- const dx = cur[0] - prev[0];
612
- const dy = cur[1] - prev[1];
613
- cum += Math.sqrt(dx * dx + dy * dy);
614
- ts[i] = t;
615
- ds[i] = cum;
616
- 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;
617
295
  }
618
- return { ts, ds };
619
- }
620
- function bezier2D_tForDistance(lut, distance) {
621
- const { ts, ds } = lut;
622
- const last = ds.length - 1;
623
- if (distance <= 0) return ts[0];
624
- if (distance >= ds[last]) return ts[last];
625
- let lo = 1;
626
- let hi = last;
627
- while (lo < hi) {
628
- const mid = lo + hi >>> 1;
629
- if (ds[mid] < distance) lo = mid + 1;
630
- else hi = mid;
296
+ };
297
+ var Literal = class extends Base {
298
+ constructor(value) {
299
+ super();
300
+ this.value = value;
301
+ this._default = value;
631
302
  }
632
- const dPrev = ds[hi - 1];
633
- const dCur = ds[hi];
634
- const span = dCur - dPrev;
635
- const frac = span > 0 ? (distance - dPrev) / span : 0;
636
- return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
637
- }
638
- function bezier2D_arcAtT(lut, t) {
639
- const { ts, ds } = lut;
640
- const last = ts.length - 1;
641
- if (t <= ts[0]) return ds[0];
642
- if (t >= ts[last]) return ds[last];
643
- let lo = 1, hi = last;
644
- while (lo < hi) {
645
- const mid = lo + hi >>> 1;
646
- if (ts[mid] < t) lo = mid + 1;
647
- else hi = mid;
648
- }
649
- const tPrev = ts[hi - 1];
650
- const span = ts[hi] - tPrev;
651
- const frac = span > 0 ? (t - tPrev) / span : 0;
652
- return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
653
- }
654
- function invertEasing(easing) {
655
- if (!easing) return (y) => y;
656
- const flipped = [easing[1], easing[0], easing[3], easing[2]];
657
- return cubicBezier(flipped);
658
- }
659
-
660
- // src/playback/PxScrollMath.ts
661
- function isScrollTimeline(config) {
662
- return (config == null ? void 0 : config.timelineSource) === "scroll";
663
- }
664
- function scrollTotalDurationMs(config) {
665
- const duration = typeof (config == null ? void 0 : config.duration) === "number" && config.duration > 0 ? config.duration : DEFAULT_DURATION_MS;
666
- const iterations = typeof (config == null ? void 0 : config.iterations) === "number" && config.iterations > 0 ? config.iterations : 1;
667
- return duration * iterations;
668
- }
669
- function scrollPhaseInterval(phase, subjectSize, scrollportSize) {
670
- const s = subjectSize, vp = scrollportSize;
671
- switch (phase) {
672
- case "cover":
673
- return [0, s + vp];
674
- case "entry":
675
- return [0, Math.min(s, vp)];
676
- case "contain":
677
- return [Math.min(s, vp), Math.max(s, vp)];
678
- case "exit":
679
- return [Math.max(s, vp), s + vp];
680
- case "entry-crossing":
681
- return [0, s];
682
- case "exit-crossing":
683
- return [vp, s + vp];
684
- }
685
- }
686
- var DEFAULT_PHASE = "cover";
687
- function resolveRangePointU(point, defaultFraction, subjectSize, scrollportSize) {
688
- var _a2;
689
- const [u0, u1] = scrollPhaseInterval((_a2 = point == null ? void 0 : point.phase) != null ? _a2 : DEFAULT_PHASE, subjectSize, scrollportSize);
690
- const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
691
- return u0 + fraction * (u1 - u0);
692
- }
693
- function scrollViewProgress(subjectStart, subjectSize, scrollportSize, range) {
694
- const u = scrollportSize - subjectStart;
695
- const uStart = resolveRangePointU(range == null ? void 0 : range.start, 0, subjectSize, scrollportSize);
696
- const uEnd = resolveRangePointU(range == null ? void 0 : range.end, 1, subjectSize, scrollportSize);
697
- if (uEnd <= uStart) return u >= uEnd ? 1 : 0;
698
- return clamp((u - uStart) / (uEnd - uStart), 0, 1);
699
- }
700
- function scrollOffsetProgress(offset, maxOffset, range) {
701
- var _a2, _b;
702
- const raw = maxOffset > 0 ? clamp(offset / maxOffset, 0, 1) : 1;
703
- const start = typeof ((_a2 = range == null ? void 0 : range.start) == null ? void 0 : _a2.fraction) === "number" ? range.start.fraction : 0;
704
- const end = typeof ((_b = range == null ? void 0 : range.end) == null ? void 0 : _b.fraction) === "number" ? range.end.fraction : 1;
705
- if (end <= start) return raw >= end ? 1 : 0;
706
- return clamp((raw - start) / (end - start), 0, 1);
707
- }
708
- function scrollResolveAxis(axis, writingMode) {
709
- const a = axis != null ? axis : "block";
710
- if (a === "x" || a === "y") return a;
711
- const vertical = !!writingMode && writingMode.startsWith("vertical");
712
- if (a === "inline") return vertical ? "y" : "x";
713
- return vertical ? "x" : "y";
714
- }
715
-
716
- // src/schema/PxSchema.ts
717
- var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
718
- function pathStr(path) {
719
- if (!path.length) return ".";
720
- let result = "";
721
- for (const seg of path) {
722
- if (seg.startsWith("[")) result += seg;
723
- else result += (result ? "." : "") + seg;
724
- }
725
- return result;
726
- }
727
- var Base = class {
728
- _canSanitize(raw) {
729
- return this.isValid(raw);
730
- }
731
- optional() {
732
- return new Optional(this);
733
- }
734
- };
735
- var Optional = class extends Base {
736
- constructor(inner) {
737
- super();
738
- this.inner = inner;
739
- this._default = void 0;
740
- }
741
- sanitize(raw) {
742
- if (raw === void 0 || raw === null) return void 0;
743
- return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
744
- }
745
- isValid(raw, ctx, path) {
746
- if (raw === void 0 || raw === null) return true;
747
- return this.inner.isValid(raw, ctx, path);
748
- }
749
- _canSanitize(raw) {
750
- return raw === void 0 || raw === null || this.inner._canSanitize(raw);
751
- }
752
- };
753
- var Str = class extends Base {
754
- constructor(_default = "") {
755
- super();
756
- this._default = _default;
757
- }
758
- sanitize(raw) {
759
- return typeof raw === "string" ? raw : this._default;
760
- }
761
- isValid(raw, ctx, path) {
762
- if (typeof raw === "string") return true;
763
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
764
- return false;
765
- }
766
- };
767
- var Num = class extends Base {
768
- constructor(_default = 0) {
769
- super();
770
- this._default = _default;
771
- }
772
- sanitize(raw) {
773
- return typeof raw === "number" && isFinite(raw) ? raw : this._default;
774
- }
775
- isValid(raw, ctx, path) {
776
- if (typeof raw === "number" && isFinite(raw)) return true;
777
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
778
- return false;
779
- }
780
- };
781
- var Bool = class extends Base {
782
- constructor(_default = false) {
783
- super();
784
- this._default = _default;
785
- }
786
- sanitize(raw) {
787
- return typeof raw === "boolean" ? raw : this._default;
788
- }
789
- isValid(raw, ctx, path) {
790
- if (typeof raw === "boolean") return true;
791
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
792
- return false;
793
- }
794
- };
795
- var Literal = class extends Base {
796
- constructor(value) {
797
- super();
798
- this.value = value;
799
- this._default = value;
800
- }
801
- sanitize(raw) {
802
- return raw === this.value ? this.value : this._default;
303
+ sanitize(raw) {
304
+ return raw === this.value ? this.value : this._default;
803
305
  }
804
306
  isValid(raw, ctx, path) {
805
307
  if (raw === this.value) return true;
@@ -822,6 +324,7 @@ var Enum = class extends Base {
822
324
  return false;
823
325
  }
824
326
  };
327
+ var UNION_MEMBER_ERROR_LIMIT = 4;
825
328
  var Union = class extends Base {
826
329
  constructor(schemas, defaultVal) {
827
330
  super();
@@ -840,7 +343,35 @@ var Union = class extends Base {
840
343
  var _a2;
841
344
  const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
842
345
  if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
843
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
346
+ if (!ctx) return false;
347
+ const base = pathStr(path != null ? path : []);
348
+ ctx.errors.push(base + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
349
+ let best;
350
+ let bestDepth = -1;
351
+ const leafExpectations = [];
352
+ for (const member of this.schemas) {
353
+ const sink = { errors: [], warnings: [], strict: ctx.strict };
354
+ member.isValid(raw, sink, path ? [...path] : void 0);
355
+ if (!sink.errors.length) continue;
356
+ const depth = Math.max(...sink.errors.map((e) => e.slice(0, e.indexOf(":")).length));
357
+ if (depth > bestDepth || depth === bestDepth && best && sink.errors.length < best.length) {
358
+ bestDepth = depth;
359
+ best = sink.errors;
360
+ }
361
+ if (depth <= base.length) {
362
+ for (const e of sink.errors) {
363
+ const m = /: expected (.+?), got /.exec(e);
364
+ if (m && !leafExpectations.includes(m[1])) leafExpectations.push(m[1]);
365
+ }
366
+ }
367
+ }
368
+ if (best && bestDepth > base.length) {
369
+ for (const e of best.slice(0, UNION_MEMBER_ERROR_LIMIT)) {
370
+ if (!ctx.errors.includes(e)) ctx.errors.push(e);
371
+ }
372
+ } else if (leafExpectations.length) {
373
+ ctx.errors.push(base + ": expected " + leafExpectations.join(" | "));
374
+ }
844
375
  return false;
845
376
  }
846
377
  _canSanitize(raw) {
@@ -1395,150 +926,139 @@ function downgradePlayerDocument(doc, target) {
1395
926
  return applyWireStepsDown(doc, { steps: PLAYER_WIRE_STEPS, target, readerReadsEditorPart: false });
1396
927
  }
1397
928
 
1398
- // src/version/PxSchemaFieldUniverse.ts
1399
- function schemaFieldUniverse(root) {
1400
- const fields = /* @__PURE__ */ new Set();
1401
- const enumerated = /* @__PURE__ */ new Set();
1402
- const queue = [{ schema: root, path: "" }];
1403
- while (queue.length) {
1404
- const { schema, path } = queue.shift();
1405
- const d = describeSchema(schema);
1406
- switch (d.kind) {
1407
- case "shape": {
1408
- if (enumerated.has(schema)) break;
1409
- enumerated.add(schema);
1410
- for (const key of Object.keys(d.shape)) {
1411
- const id = path ? path + "." + key : key;
1412
- fields.add(id);
1413
- queue.push({ schema: d.shape[key], path: id });
1414
- }
1415
- if (d.openValue) queue.push({ schema: d.openValue, path: path + "{*}" });
1416
- break;
1417
- }
1418
- case "optional":
1419
- queue.push({ schema: d.inner, path });
1420
- break;
1421
- case "array":
1422
- queue.push({ schema: d.item, path: path + "[]" });
1423
- break;
1424
- case "lazy":
1425
- queue.push({ schema: d.resolved, path });
1426
- break;
1427
- case "record":
1428
- queue.push({ schema: d.value, path: path + "{*}" });
1429
- break;
1430
- case "union":
1431
- d.members.forEach((member, i) => queue.push({ schema: member, path: path + "|" + i }));
1432
- break;
1433
- case "discriminatedUnion":
1434
- for (const member of d.members) queue.push({ schema: member, path: path + "|" + discriminantOf(member, d.key) });
1435
- break;
1436
- default:
1437
- break;
1438
- }
929
+ // src/format/PxAnimatorConstants.ts
930
+ var PxFillMode = {
931
+ forwards: "forwards",
932
+ backwards: "backwards",
933
+ both: "both",
934
+ none: "none"
935
+ };
936
+ var PxPlaybackDirection = {
937
+ normal: "normal",
938
+ reverse: "reverse",
939
+ alternate: "alternate",
940
+ alternateReverse: "alternate-reverse"
941
+ };
942
+ var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
943
+ var PX_ANIM_ATTR_NAME = "_px_animator";
944
+ var PxStartOn = {
945
+ load: "load",
946
+ mouseOver: "mouseOver",
947
+ click: "click",
948
+ scrollIntoView: "scrollIntoView",
949
+ programmatic: "programmatic"
950
+ };
951
+ var PxOutAction = {
952
+ continue: "continue",
953
+ pause: "pause",
954
+ reset: "reset",
955
+ reverse: "reverse"
956
+ };
957
+ var PxFinishAction = {
958
+ hold: "hold",
959
+ reset: "reset"
960
+ };
961
+ var PxScrollKind = {
962
+ view: "view",
963
+ scroll: "scroll"
964
+ };
965
+ var PxScrollAxis = {
966
+ block: "block",
967
+ inline: "inline",
968
+ x: "x",
969
+ y: "y"
970
+ };
971
+ var PxScrollSource = {
972
+ nearest: "nearest",
973
+ root: "root"
974
+ };
975
+ var PxPinAlign = {
976
+ top: "top",
977
+ center: "center",
978
+ bottom: "bottom"
979
+ };
980
+ var PxScrollPhase = {
981
+ cover: "cover",
982
+ contain: "contain",
983
+ entry: "entry",
984
+ exit: "exit",
985
+ entryCrossing: "entry-crossing",
986
+ exitCrossing: "exit-crossing"
987
+ };
988
+ var PxAlongPathMode = {
989
+ sampled: "sampled",
990
+ offsetPath: "offsetPath"
991
+ };
992
+ var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
993
+ var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
994
+ var PX_FLAT_RUNTIME_VIEW_KEYS = [
995
+ ...PX_TIMELINE_SHARED_KEYS,
996
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
997
+ "fill",
998
+ "resetOnFinish",
999
+ "timelineSource",
1000
+ "scroll"
1001
+ ];
1002
+ var PxTimelineEngine = {
1003
+ native: "native",
1004
+ js: "js"
1005
+ };
1006
+ var PxTimelineEngineExtra = __spreadProps(__spreadValues({}, PxTimelineEngine), {
1007
+ auto: "auto"
1008
+ });
1009
+ function resolveTimelineEngine(engine) {
1010
+ return engine === PxTimelineEngineExtra.js ? PxTimelineEngine.js : PxTimelineEngine.native;
1011
+ }
1012
+ function isNativeForced(engine) {
1013
+ return engine === PxTimelineEngineExtra.native;
1014
+ }
1015
+ function mayUseNativeScrollTimeline(engine) {
1016
+ return engine !== PxTimelineEngineExtra.js;
1017
+ }
1018
+ var PX_TRIGGER_DEFAULTS = {
1019
+ startOn: "load",
1020
+ outAction: "continue",
1021
+ scrollIntoViewThreshold: 0
1022
+ };
1023
+ var PxControlMode = {
1024
+ /** No control props — the document's trigger decides, and nothing is taken over. */
1025
+ static: "static",
1026
+ /** `progress` / `time` — the host scrubs; the component seeks and stays paused. */
1027
+ fixedTime: "fixedTime",
1028
+ /** `play` / `pause` — the host drives playback with booleans. */
1029
+ play: "play",
1030
+ /** `autoplay` — the document's own trigger starts it. */
1031
+ autoplay: "autoplay"
1032
+ };
1033
+ function resolveControlMode(props) {
1034
+ const hasFixedTime = props.progress !== void 0 || props.time !== void 0;
1035
+ const hasPlayPause = props.play !== void 0 || props.pause !== void 0;
1036
+ const hasAutoplay = !!props.autoplay;
1037
+ const warnings = [];
1038
+ const named = (a, b, winner) => a + " and " + b + " were both set \u2014 " + winner + " wins, " + (winner === a ? b : a) + " is ignored.";
1039
+ if (hasFixedTime) {
1040
+ if (hasPlayPause) warnings.push(named("progress/time", "play/pause", "progress/time"));
1041
+ if (hasAutoplay) warnings.push(named("progress/time", "autoplay", "progress/time"));
1042
+ return { mode: PxControlMode.fixedTime, warnings };
1439
1043
  }
1440
- return [...fields].sort();
1044
+ if (hasPlayPause) {
1045
+ if (hasAutoplay) warnings.push(named("play/pause", "autoplay", "play/pause"));
1046
+ return { mode: PxControlMode.play, warnings };
1047
+ }
1048
+ if (hasAutoplay) return { mode: PxControlMode.autoplay, warnings };
1049
+ return { mode: PxControlMode.static, warnings };
1441
1050
  }
1442
- function discriminantOf(member, key) {
1443
- const d = describeSchema(member);
1444
- if (d.kind !== "shape") return "?";
1445
- const keySchema = d.shape[key];
1446
- if (keySchema === void 0) return "?";
1447
- const kd = describeSchema(keySchema);
1448
- return String((kd.kind === "optional" ? kd.inner : keySchema)._default);
1051
+ function controlModeTakesOverTrigger(mode) {
1052
+ return mode !== PxControlMode.autoplay;
1449
1053
  }
1450
-
1451
- // src/version/PxSchemaRelease.ts
1452
- function diffFieldUniverse(previous, current) {
1453
- const prev = new Set(previous);
1454
- const cur = new Set(current);
1054
+ function resolveTrigger(trigger) {
1055
+ var _a2, _b, _c;
1455
1056
  return {
1456
- added: current.filter((k) => !prev.has(k)).sort(),
1457
- removed: previous.filter((k) => !cur.has(k)).sort()
1057
+ startOn: (_a2 = trigger == null ? void 0 : trigger.startOn) != null ? _a2 : PX_TRIGGER_DEFAULTS.startOn,
1058
+ outAction: (_b = trigger == null ? void 0 : trigger.outAction) != null ? _b : PX_TRIGGER_DEFAULTS.outAction,
1059
+ scrollIntoViewThreshold: (_c = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _c : PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold
1458
1060
  };
1459
1061
  }
1460
- function planSchemaRelease(p) {
1461
- const changed = p.added.length > 0 || p.removed.length > 0;
1462
- const last = parseWireVersion(p.lastReleased);
1463
- const declared = parseWireVersion(p.declared);
1464
- if (!last || !declared) return { changed, refuse: "Unparseable version: " + p.lastReleased + " / " + p.declared + "." };
1465
- const requiredVersion = last.a + "." + (last.b + 1);
1466
- if (!changed) {
1467
- if (declared.b === last.b && declared.a === last.a) return { changed };
1468
- const step2 = p.steps.find((s) => s.to === p.declared);
1469
- return step2 ? { changed, requiredVersion: p.declared } : { changed, refuse: "The version moved to " + p.declared + " with no key change and no step explaining it." };
1470
- }
1471
- const requiredKind = p.removed.length ? "converted" /* converted */ : "additive" /* additive */;
1472
- const summary = p.added.length + " key(s) added, " + p.removed.length + " removed";
1473
- if (declared.a !== last.a || declared.b !== last.b + 1) {
1474
- return {
1475
- changed,
1476
- requiredKind,
1477
- requiredVersion,
1478
- 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."
1479
- };
1480
- }
1481
- const step = p.steps.find((s) => s.to === p.declared);
1482
- if (!step) {
1483
- return { changed, requiredKind, requiredVersion, refuse: "No PLAYER_WIRE_STEPS entry reaches " + p.declared + "." };
1484
- }
1485
- if (requiredKind === "converted" /* converted */ && step.kind !== "converted" /* converted */) {
1486
- return {
1487
- changed,
1488
- requiredKind,
1489
- requiredVersion,
1490
- refuse: "Keys were REMOVED (" + p.removed.join(", ") + "), which is never additive \u2014 the " + p.declared + " step must be `converted`, with an up()."
1491
- };
1492
- }
1493
- return { changed, requiredKind, requiredVersion };
1494
- }
1495
- function releaseLogProblems(releases, steps, declared, baseline) {
1496
- const problems = [];
1497
- if (!releases.length) return ["The release log is empty."];
1498
- if (!releases[0].baseline || releases[0].version !== baseline) {
1499
- problems.push("The first release must be the baseline " + baseline + ".");
1500
- }
1501
- for (let i = 1; i < releases.length; i++) {
1502
- const prev = parseWireVersion(releases[i - 1].version);
1503
- const cur = parseWireVersion(releases[i].version);
1504
- if (!prev || !cur || cur.a !== prev.a || cur.b !== prev.b + 1) {
1505
- problems.push("Release " + releases[i].version + " does not follow " + releases[i - 1].version + " by one `b` step.");
1506
- }
1507
- if (releases[i].date < releases[i - 1].date) problems.push("Release " + releases[i].version + " is dated before its predecessor.");
1508
- const step = steps.find((s) => s.to === releases[i].version);
1509
- if (!step) problems.push("Release " + releases[i].version + " has no PLAYER_WIRE_STEPS entry.");
1510
- else if (releases[i].removed.length && step.kind !== "converted" /* converted */) {
1511
- problems.push("Release " + releases[i].version + " removed keys, but its step is not `converted`.");
1512
- }
1513
- }
1514
- const latest = releases[releases.length - 1].version;
1515
- if (latest !== declared) {
1516
- 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).");
1517
- }
1518
- return problems;
1519
- }
1520
-
1521
- // src/format/PxAnimatorConstants.ts
1522
- var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1523
- var PX_ANIM_ATTR_NAME = "_px_animator";
1524
- var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
1525
- var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
1526
- var PxTimelineEngine = {
1527
- native: "native",
1528
- js: "js"
1529
- };
1530
- var PxTimelineEngineExtra = __spreadProps(__spreadValues({}, PxTimelineEngine), {
1531
- auto: "auto"
1532
- });
1533
- function resolveTimelineEngine(engine) {
1534
- return engine === PxTimelineEngineExtra.js ? PxTimelineEngine.js : PxTimelineEngine.native;
1535
- }
1536
- function isNativeForced(engine) {
1537
- return engine === PxTimelineEngineExtra.native;
1538
- }
1539
- function mayUseNativeScrollTimeline(engine) {
1540
- return engine !== PxTimelineEngineExtra.js;
1541
- }
1542
1062
  var PxLoopRepeatAt = {
1543
1063
  /** Segment from the START; the repetition runs BEFORE the first keyframe
1544
1064
  * (intro loops that play until the main timeline begins). */
@@ -1585,7 +1105,6 @@ var PxStrokeTrimSubPaths = {
1585
1105
  separate: "separate",
1586
1106
  combined: "combined"
1587
1107
  };
1588
- var TEXT_ATTR = "text";
1589
1108
  var TEXT_CONTENT_ATTR = "textContent";
1590
1109
  var CLASS_ATTR = "class";
1591
1110
  var TRANSFORM_ATTR = "transform";
@@ -1597,7 +1116,6 @@ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1597
1116
  "meta",
1598
1117
  "animate",
1599
1118
  "effects",
1600
- TEXT_ATTR,
1601
1119
  TEXT_CONTENT_ATTR
1602
1120
  ]);
1603
1121
  var TRANSFORM_PART = {
@@ -1612,10 +1130,6 @@ var PX_TRANSFORM_PART_KEYS = [
1612
1130
  TRANSFORM_PART.scale,
1613
1131
  TRANSFORM_PART.origin
1614
1132
  ];
1615
- var PxGradientUnits = {
1616
- userSpaceOnUse: "userSpaceOnUse",
1617
- objectBoundingBox: "objectBoundingBox"
1618
- };
1619
1133
  var PxGradientSpreadMethod = {
1620
1134
  pad: "pad",
1621
1135
  reflect: "reflect",
@@ -1634,8 +1148,18 @@ function isPxElementFileFormat(fileJson) {
1634
1148
  function getAnimatorConfig(doc) {
1635
1149
  var _a2;
1636
1150
  const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
1637
- return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1638
- }
1151
+ if (!cfg) return void 0;
1152
+ const memoised = wireViewMemo.get(cfg);
1153
+ if (memoised) return memoised;
1154
+ const wire = cfg;
1155
+ const stray = PX_FLAT_RUNTIME_VIEW_KEYS.filter((k) => wire[k] !== void 0);
1156
+ const source = stray.length ? __spreadValues({}, wire) : cfg;
1157
+ for (const k of stray) delete source[k];
1158
+ const view = flattenAnimatorTimeline(source);
1159
+ wireViewMemo.set(cfg, view);
1160
+ return view;
1161
+ }
1162
+ var wireViewMemo = /* @__PURE__ */ new WeakMap();
1639
1163
  var flattenMemo = /* @__PURE__ */ new WeakMap();
1640
1164
  function flattenAnimatorTimeline(cfg) {
1641
1165
  const timeline = cfg.timeline;
@@ -1661,7 +1185,7 @@ function flattenAnimatorTimeline(cfg) {
1661
1185
  else if (pin && typeof pin === "object") {
1662
1186
  scroll.pin = true;
1663
1187
  if (pin.align !== void 0) scroll.pinAlign = pin.align;
1664
- if (pin.top !== void 0) scroll.pinTop = pin.top;
1188
+ if (pin.offset !== void 0) scroll.pinOffset = pin.offset;
1665
1189
  if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1666
1190
  }
1667
1191
  flat.scroll = scroll;
@@ -1722,9 +1246,9 @@ function nestAnimatorTimeline(cfg) {
1722
1246
  if (scroll.subject !== void 0) timeline2.subject = scroll.subject;
1723
1247
  if (scroll.smoothing !== void 0) timeline2.smoothing = scroll.smoothing;
1724
1248
  if (scroll.range !== void 0) timeline2.range = scroll.range;
1725
- const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinTop !== void 0 || scroll.pinDistance !== void 0;
1249
+ const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinOffset !== void 0 || scroll.pinDistance !== void 0;
1726
1250
  if (hasPinParams) {
1727
- timeline2.pin = __spreadValues(__spreadValues(__spreadValues({}, scroll.pinAlign !== void 0 ? { align: scroll.pinAlign } : {}), scroll.pinTop !== void 0 ? { top: scroll.pinTop } : {}), scroll.pinDistance !== void 0 ? { distance: scroll.pinDistance } : {});
1251
+ timeline2.pin = __spreadValues(__spreadValues(__spreadValues({}, scroll.pinAlign !== void 0 ? { align: scroll.pinAlign } : {}), scroll.pinOffset !== void 0 ? { offset: scroll.pinOffset } : {}), scroll.pinDistance !== void 0 ? { distance: scroll.pinDistance } : {});
1728
1252
  } else if (scroll.pin !== void 0) {
1729
1253
  timeline2.pin = scroll.pin;
1730
1254
  }
@@ -1754,9 +1278,7 @@ function getDefs(doc) {
1754
1278
  function getBindings(doc) {
1755
1279
  var _a2;
1756
1280
  if (!doc) return void 0;
1757
- const animateById = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.animateById;
1758
- if (!animateById) return void 0;
1759
- 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;
1760
1282
  }
1761
1283
  function getChildren(doc) {
1762
1284
  return doc == null ? void 0 : doc.children;
@@ -1772,14 +1294,13 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
1772
1294
  // e.g. for colors
1773
1295
  px.number(),
1774
1296
  px.array(px.number()),
1775
- // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1297
+ // ORDER LAW: the key-discriminated object shape (`{pathData}`) comes BEFORE the
1776
1298
  // all-optional transform-parts record. In default (non-strict) mode that record accepts
1777
1299
  // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1778
- // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1300
+ // Union.sanitize route `{pathData}` values into it and strip them to `{}` —
1779
1301
  // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1780
1302
  // order-independent (`some()`); only sanitize routing depends on this order.
1781
- px.object({ path: px.string() }),
1782
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1303
+ px.object({ pathData: px.string() }),
1783
1304
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1784
1305
  px.lazy(() => px.array(PxGradientStopSchema), []),
1785
1306
  px.lazy(() => PxTransformPartsSchema, {})
@@ -1819,7 +1340,7 @@ var PxPropertyAnimationSchema = implementsInterface()(px.object({
1819
1340
  keyframes: px.array(PxKeyframeSchema).optional(),
1820
1341
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1821
1342
  autoOrient: px.boolean().optional(),
1822
- alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
1343
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
1823
1344
  }));
1824
1345
  var PxTransformPartsSchema = implementsInterface()(px.object({
1825
1346
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1843,17 +1364,17 @@ var PxElementAnimationSchema = implementsInterface()(px.union([
1843
1364
  PxAnimationDefinitionSchema
1844
1365
  ]));
1845
1366
  var PxTriggerSchema = implementsInterface()(px.object({
1846
- startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1847
- outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1367
+ startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic], PX_TRIGGER_DEFAULTS.startOn).optional(),
1368
+ outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse], PX_TRIGGER_DEFAULTS.outAction).optional(),
1848
1369
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1849
1370
  // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1850
1371
  // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1851
- finishAction: px.enum(["hold", "reset"]).optional(),
1372
+ finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
1852
1373
  scrollIntoViewThreshold: px.number().optional()
1853
1374
  }));
1854
1375
  var PxGlyphSchema = implementsInterface()(px.object({
1855
1376
  width: px.number(),
1856
- d: px.string()
1377
+ pathData: px.string()
1857
1378
  }));
1858
1379
  var PxGlyphFontSchema = implementsInterface()(px.object({
1859
1380
  fontFamily: px.string(),
@@ -1865,14 +1386,17 @@ var PxGlyphFontSchema = implementsInterface()(px.object({
1865
1386
  var PxDefsSchema = implementsInterface()(px.object({
1866
1387
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1867
1388
  animations: px.record(PxAnimationDefinitionSchema).optional(),
1868
- // Review §2.6: the schema now matches the declared type — a style preset is a flat
1869
- // record of string|number attribute values, nothing nested.
1870
- styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1871
1389
  fonts: px.record(PxGlyphFontSchema).optional()
1872
1390
  }));
1873
- var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1874
1391
  var PxScrollRangePointSchema = implementsInterface()(px.object({
1875
- phase: px.enum(PX_SCROLL_PHASES).optional(),
1392
+ phase: px.enum([
1393
+ PxScrollPhase.cover,
1394
+ PxScrollPhase.contain,
1395
+ PxScrollPhase.entry,
1396
+ PxScrollPhase.exit,
1397
+ PxScrollPhase.entryCrossing,
1398
+ PxScrollPhase.exitCrossing
1399
+ ]).optional(),
1876
1400
  fraction: px.number().optional()
1877
1401
  }));
1878
1402
  var PxScrollRangeSchema = px.object({
@@ -1880,21 +1404,21 @@ var PxScrollRangeSchema = px.object({
1880
1404
  end: PxScrollRangePointSchema.optional()
1881
1405
  });
1882
1406
  var PxScrollSchema = implementsInterface()(px.object({
1883
- kind: px.enum(["view", "scroll"]).optional(),
1884
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1885
- source: px.enum(["nearest", "root"]).optional(),
1407
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
1408
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1409
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1886
1410
  // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1887
1411
  subject: px.string().optional(),
1888
1412
  smoothing: px.number().optional(),
1889
1413
  pin: px.boolean().optional(),
1890
- pinAlign: px.enum(["top", "center", "bottom"]).optional(),
1891
- pinTop: px.number().optional(),
1414
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1415
+ pinOffset: px.number().optional(),
1892
1416
  pinDistance: px.number().optional(),
1893
1417
  range: PxScrollRangeSchema.optional()
1894
1418
  }));
1895
1419
  var PxTimelinePinSchema = implementsInterface()(px.object({
1896
- align: px.enum(["top", "center", "bottom"]).optional(),
1897
- top: px.number().optional(),
1420
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1421
+ offset: px.number().optional(),
1898
1422
  distance: px.number().optional()
1899
1423
  }));
1900
1424
  var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
@@ -1909,8 +1433,8 @@ var PxTimeTimelineSchema = implementsInterface()(px.object({
1909
1433
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1910
1434
  // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1911
1435
  // — never `fill`, which is paint everywhere else in the format.
1912
- fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1913
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1436
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
1437
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
1914
1438
  }));
1915
1439
  var scrollishTimelineShape = {
1916
1440
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
@@ -1921,8 +1445,8 @@ var scrollishTimelineShape = {
1921
1445
  iterations: px.number().optional(),
1922
1446
  engine: PxTimelineEngineSchema,
1923
1447
  frameRate: px.number().optional(),
1924
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
1925
- source: px.enum(["nearest", "root"]).optional(),
1448
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1449
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1926
1450
  subject: px.string().optional(),
1927
1451
  // 'parent' | 'scroller' | any CSS selector
1928
1452
  smoothing: px.number().optional(),
@@ -1942,22 +1466,22 @@ var PxTimelineSchema = px.discriminatedUnion("type", [
1942
1466
  PxScrollTimelineSchema,
1943
1467
  PxViewTimelineSchema
1944
1468
  ]);
1469
+ var PxBindingSchema = implementsInterface()(px.object({
1470
+ target: px.string(),
1471
+ animateWith: px.array(px.string())
1472
+ }));
1945
1473
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
1946
1474
  // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1947
1475
  // at this level only on the runtime view, like the rest of the playback dynamics.)
1948
1476
  // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1949
1477
  timeline: PxTimelineSchema.optional(),
1950
1478
  definitions: PxDefsSchema.optional(),
1951
- animateById: px.record(PxElementAnimationSchema).optional(),
1479
+ bindings: px.array(PxBindingSchema).optional(),
1952
1480
  debugGlobalName: px.string().optional(),
1953
1481
  // Declared HERE because this is a closed object: an undeclared key would be stripped by
1954
1482
  // `sanitize` and flagged by strict validation on our own files.
1955
1483
  version: px.string().optional()
1956
1484
  }));
1957
- var PxBindingSchema = implementsInterface()(px.object({
1958
- id: px.string(),
1959
- animate: PxElementAnimationSchema
1960
- }));
1961
1485
  var PxAttrValueSchema = px.union([
1962
1486
  px.string(),
1963
1487
  px.number(),
@@ -2011,7 +1535,7 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
2011
1535
  height: px.number().optional()
2012
1536
  }));
2013
1537
  var PxClipPathEffectSchema = implementsInterface()(px.object({
2014
- d: PxAnimatableStringSchema.optional()
1538
+ pathData: PxAnimatableStringSchema.optional()
2015
1539
  }));
2016
1540
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
2017
1541
  offset: PxAnimatableNumberSchema.optional(),
@@ -2048,7 +1572,7 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
2048
1572
  radius: PxAnimatableNumberSchema.optional(),
2049
1573
  focal: PxAnimatableVec2Schema.optional(),
2050
1574
  stops: PxAnimatableGradientStopsSchema.optional(),
2051
- gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
1575
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
2052
1576
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
2053
1577
  gradientTransform: px.string().optional()
2054
1578
  }));
@@ -2094,187 +1618,698 @@ function validateNodeEffects(root, opts) {
2094
1618
  walk(root, "root");
2095
1619
  return warnings;
2096
1620
  }
2097
- function validateDocument(doc) {
2098
- const ctx = { errors: [], warnings: [], strict: true };
1621
+ function validateGlyphFontRefs(root, fonts) {
1622
+ if (!fonts || !Object.keys(fonts).length) return [];
1623
+ const problems = [];
1624
+ const walk = (node, path, inherited, inGlyphText) => {
1625
+ var _a2, _b;
1626
+ if (!node) return;
1627
+ const own = typeof node.fontFamily === "string" ? node.fontFamily : void 0;
1628
+ const family = own != null ? own : inherited;
1629
+ const isGlyphText = inGlyphText || node.type === "text" && !!((_b = (_a2 = node.effects) == null ? void 0 : _a2.text) == null ? void 0 : _b.useGlyphs);
1630
+ if (isGlyphText && own && !Object.prototype.hasOwnProperty.call(fonts, own)) {
1631
+ const problem = path + ': glyph-mode text uses font-family "' + own + '", which has no entry in animator.definitions.fonts';
1632
+ if (!problems.includes(problem)) problems.push(problem);
1633
+ }
1634
+ if (Array.isArray(node.children)) {
1635
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]", family, isGlyphText));
1636
+ }
1637
+ };
1638
+ walk(root, "root", void 0, false);
1639
+ return problems;
1640
+ }
1641
+ function validateEasingRefs(root, easings) {
1642
+ const problems = [];
1643
+ const walk = (node, path) => {
1644
+ if (Array.isArray(node)) {
1645
+ node.forEach((item, i) => walk(item, path + "[" + i + "]"));
1646
+ return;
1647
+ }
1648
+ if (!node || typeof node !== "object") return;
1649
+ const easing = node.easing;
1650
+ if (typeof easing === "string" && !(easings && Object.prototype.hasOwnProperty.call(easings, easing))) {
1651
+ const problem = path + '.easing: "' + easing + '" names no entry in animator.definitions.easings \u2014 it will play linear';
1652
+ if (!problems.includes(problem)) problems.push(problem);
1653
+ }
1654
+ for (const [key, value] of Object.entries(node)) {
1655
+ if (key === "easing") continue;
1656
+ if (value && typeof value === "object") walk(value, path + "." + key);
1657
+ }
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 };
2099
1673
  const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
2100
1674
  if (doc && typeof doc === "object") {
2101
- for (const w of validateNodeEffects(doc, { strict: true })) {
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)) {
2102
1680
  if (!problems.includes(w)) problems.push(w);
2103
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
+ }
2104
2148
  }
2105
- return problems;
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;
2106
2151
  }
2107
- var PxNodeBase = px.openObject({
2108
- // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
2109
- // kind of thing is this", discriminated by its CARRIER — here the node TAG
2110
- // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
2111
- // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
2112
- // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
2113
- // would add words that all mean "type" and still need the carrier to read.
2114
- // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
2115
- // (issues V3), never of distinct key names.
2116
- type: px.string(),
2117
- // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
2118
- // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
2119
- // `type` is taken by the tag name, so the attribute travels here and the renderer puts
2120
- // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
2121
- // documented — because a wire key that is not in a schema is invisible to the
2122
- // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
2123
- domType: px.string().optional(),
2124
- id: px.string().optional(),
2125
- meta: px.any().optional(),
2126
- // Player-effects bucket emitted by the Editor's lightweight design format.
2127
- // Consumed and removed by `applyPlayerEffects` before any other normalisation
2128
- // (see `createAnimatorImpl`), so downstream code never sees it.
2129
- effects: PxEffectsSchema.optional(),
2130
- // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
2131
- // string ref / array of refs / inline definition / mixed array; mirrors
2132
- // `animator.animateById` map values and what `processNode` resolves at runtime.
2133
- animate: PxElementAnimationSchema.optional(),
2134
- style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
2135
- }, PxAttrValueSchema);
2136
- var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
2137
- children: px.lazy(() => px.array(PxNodeSchema), []).optional()
2138
- }), PxAttrValueSchema);
2139
- var PxSvgNodeExtra = px.object({
2140
- // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
2141
- // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
2142
- width: px.union([px.number(), px.string()]).optional(),
2143
- height: px.union([px.number(), px.string()]).optional(),
2144
- viewBox: px.string().optional(),
2145
- animator: PxAnimatorConfigSchema.optional()
2146
- });
2147
- var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
2148
- type: px.literal("svg"),
2149
- // override string → literal to require 'svg'
2150
- children: px.array(PxNodeSchema).optional()
2151
- }), PxAttrValueSchema);
2152
- var PxBezierPathSchema = implementsInterface()(px.object({
2153
- v: px.array(px.array(px.number())),
2154
- i: px.array(px.array(px.number())).optional(),
2155
- o: px.array(px.array(px.number())).optional(),
2156
- c: px.boolean().optional()
2157
- }));
2158
- function isPxElementFileFormatDeep(fileJson) {
2159
- const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
2160
- return { valid, errors: valid ? [] : ["Document failed schema validation"] };
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;
2161
2156
  }
2162
-
2163
- // src/util/PxIdUtil.ts
2164
- var _idCounter = 0;
2165
- function generateUniqueId() {
2166
- const timestamp = Date.now().toString(36);
2167
- const counter = (++_idCounter).toString(36);
2168
- const random = Math.random().toString(36).substring(2, 6);
2169
- return "_px_" + timestamp + counter + random;
2157
+ function isCamelCaseWord(word) {
2158
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
2170
2159
  }
2171
- function deepClone(value) {
2172
- if (value === null || typeof value !== "object") return value;
2173
- if (Array.isArray(value)) return value.map((item) => deepClone(item));
2174
- const obj = value;
2175
- const cloned = {};
2176
- for (const key of Object.keys(obj)) {
2177
- cloned[key] = deepClone(obj[key]);
2178
- }
2179
- return cloned;
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();
2180
2215
  }
2181
- function generateNewIds(doc) {
2182
- var _a2, _b;
2183
- const cloned = deepClone(doc);
2184
- const idMap = /* @__PURE__ */ new Map();
2185
- const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
2186
- const urlRefAttrs = /* @__PURE__ */ new Set([
2187
- "fill",
2188
- "stroke",
2189
- "clip-path",
2190
- "clipPath",
2191
- "mask",
2192
- "marker",
2193
- "marker-start",
2194
- "marker-mid",
2195
- "marker-end",
2196
- "filter",
2197
- "flood-color",
2198
- "lighting-color"
2199
- ]);
2200
- const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
2201
- const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
2202
- function collectIds(node) {
2203
- if (!node || typeof node !== "object") return;
2204
- if (node.id && typeof node.id === "string") {
2205
- const oldId = node.id;
2206
- const newId = generateUniqueId();
2207
- idMap.set(oldId, newId);
2208
- node.id = newId;
2209
- } else if (node.animate) {
2210
- node.id = generateUniqueId();
2211
- }
2212
- if (Array.isArray(node.children)) {
2213
- for (const child of node.children) {
2214
- collectIds(child);
2215
- }
2216
- }
2216
+ function clamp(value, min, max) {
2217
+ return Math.max(min, Math.min(value, max));
2218
+ }
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);
2217
2242
  }
2218
- function updateRefs(node, parentKey) {
2219
- if (!node || typeof node !== "object") return;
2220
- for (const [key, value] of Object.entries(node)) {
2221
- if (key === "children") {
2222
- if (Array.isArray(value)) {
2223
- for (const child of value) {
2224
- updateRefs(child);
2225
- }
2226
- }
2227
- continue;
2228
- }
2229
- if (typeof value === "string") {
2230
- if (hashRefAttrs.has(key) && value.startsWith("#")) {
2231
- const oldId = value.slice(1);
2232
- const newId = idMap.get(oldId);
2233
- if (newId) {
2234
- node[key] = "#" + newId;
2235
- }
2236
- } else if (urlRefAttrs.has(key)) {
2237
- node[key] = replaceUrlRefs(value, idMap);
2238
- } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
2239
- const hasHash = value.startsWith("#");
2240
- const newId = idMap.get(hasHash ? value.slice(1) : value);
2241
- if (newId) {
2242
- node[key] = hasHash ? "#" + newId : newId;
2243
- }
2244
- } else if (value.includes("url(#")) {
2245
- node[key] = replaceUrlRefs(value, idMap);
2246
- }
2247
- } else if (key === "style" && typeof value === "object" && value !== null) {
2248
- for (const [styleProp, styleValue] of Object.entries(value)) {
2249
- if (typeof styleValue === "string") {
2250
- value[styleProp] = replaceUrlRefs(styleValue, idMap);
2251
- }
2252
- }
2253
- } else if (typeof value === "object" && value !== null) {
2254
- updateRefs(value, key);
2255
- }
2256
- }
2243
+ return result;
2244
+ }
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;
2257
2272
  }
2258
- collectIds(cloned);
2259
- updateRefs(cloned);
2260
- const docAnimate = (_a2 = cloned.animator) == null ? void 0 : _a2.animateById;
2261
- if (docAnimate && typeof docAnimate === "object") {
2262
- const updatedAnimate = {};
2263
- for (const [key, anim] of Object.entries(docAnimate)) {
2264
- const hashed = key.startsWith("#");
2265
- const id = hashed ? key.slice(1) : key;
2266
- const newId = (_b = idMap.get(id)) != null ? _b : id;
2267
- updatedAnimate[hashed ? "#" + newId : newId] = anim;
2268
- }
2269
- cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animateById: updatedAnimate });
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;
2270
2286
  }
2271
- return cloned;
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]);
2272
2292
  }
2273
- function replaceUrlRefs(value, idMap) {
2274
- return value.replace(/url\(#([^)]+)\)/g, (match, oldId) => {
2275
- const newId = idMap.get(oldId);
2276
- return newId ? "url(#" + newId + ")" : match;
2277
- });
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;
2303
+ }
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]);
2308
+ }
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);
2278
2313
  }
2279
2314
 
2280
2315
  // src/util/PxNodeProps.ts
@@ -2316,7 +2351,7 @@ function isDangerousAttrName(nameLower) {
2316
2351
  if (nameLower.startsWith("on")) return true;
2317
2352
  return false;
2318
2353
  }
2319
- function sanitiseAttributeValue(name, value) {
2354
+ function sanitizeAttributeValue(name, value) {
2320
2355
  const nameLower = name.toLowerCase();
2321
2356
  if (isDangerousAttrName(nameLower)) {
2322
2357
  console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
@@ -2340,14 +2375,6 @@ function sanitiseAttributeValue(name, value) {
2340
2375
  }
2341
2376
  return value;
2342
2377
  }
2343
- function resolveStyle(style, defs) {
2344
- var _a2;
2345
- if (!style) return void 0;
2346
- if (typeof style === "string") {
2347
- return (_a2 = defs == null ? void 0 : defs.styles) == null ? void 0 : _a2[style];
2348
- }
2349
- return style;
2350
- }
2351
2378
  function getNormalizedProps(props) {
2352
2379
  const propsCopy = {};
2353
2380
  for (const rawKey of Object.keys(props)) {
@@ -2355,7 +2382,7 @@ function getNormalizedProps(props) {
2355
2382
  if (INTERNAL_ATTRS.has(key)) continue;
2356
2383
  if (key === "style") continue;
2357
2384
  let value = props[rawKey];
2358
- if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2385
+ if (COLOR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2359
2386
  propsCopy[key] = toRGBA(value);
2360
2387
  } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
2361
2388
  const parts = value.value && typeof value.value === "object" ? value.value : value;
@@ -2376,7 +2403,7 @@ function getNormalizedProps(props) {
2376
2403
  return propsCopy;
2377
2404
  }
2378
2405
 
2379
- // src/materialise/PxMotionPath.ts
2406
+ // src/materialize/PxMotionPath.ts
2380
2407
  function getKfTranslate(kf) {
2381
2408
  const v = kfValue(kf);
2382
2409
  if (!v) return void 0;
@@ -2457,7 +2484,7 @@ function tFromArcFraction(lut, arcFrac) {
2457
2484
  var DEFAULT_FLATNESS_TOL = 0.5;
2458
2485
  var DEFAULT_ROTATION_TOL = 5;
2459
2486
  var DEFAULT_MAX_SAMPLES = 32;
2460
- function materialiseMotionPathInPropAnim(anim, opts) {
2487
+ function materializeMotionPathInPropAnim(anim, opts) {
2461
2488
  var _a2, _b, _c;
2462
2489
  if (!propAnimIsMotionPath(anim)) return anim;
2463
2490
  const kfs = anim.keyframes;
@@ -2489,7 +2516,7 @@ function materialiseMotionPathInPropAnim(anim, opts) {
2489
2516
  if (autoOrient && i > 0) {
2490
2517
  insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
2491
2518
  }
2492
- materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2519
+ materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2493
2520
  }
2494
2521
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
2495
2522
  if (lastInE) out[out.length - 1].e = lastInE;
@@ -2603,7 +2630,7 @@ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos,
2603
2630
  out.push(makeOutKf(stepTime, dupValue));
2604
2631
  }
2605
2632
  var CORNER_STEP_AFTER_BOUNDARY_MS = 0.05;
2606
- function materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2633
+ function materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2607
2634
  const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2608
2635
  const prevTime = getKfTime(prevKf);
2609
2636
  const nextTime = getKfTime(nextKf);
@@ -2726,16 +2753,16 @@ function perpDist(q, pA, pB) {
2726
2753
  const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
2727
2754
  return Math.abs(cross) / Math.sqrt(len2);
2728
2755
  }
2729
- function materialiseMotionPathsInTree(root, opts) {
2730
- const out = walkAndMaterialise(root, opts);
2756
+ function materializeMotionPathsInTree(root, opts) {
2757
+ const out = walkAndMaterialize(root, opts);
2731
2758
  return out != null ? out : root;
2732
2759
  }
2733
- function walkAndMaterialise(node, opts) {
2760
+ function walkAndMaterialize(node, opts) {
2734
2761
  let newChildren;
2735
2762
  if (node.children) {
2736
2763
  for (let i = 0; i < node.children.length; i++) {
2737
2764
  const ch = node.children[i];
2738
- const ret = walkAndMaterialise(ch, opts);
2765
+ const ret = walkAndMaterialize(ch, opts);
2739
2766
  if (ret !== null) {
2740
2767
  if (!newChildren) newChildren = node.children.slice();
2741
2768
  newChildren[i] = ret;
@@ -2748,9 +2775,9 @@ function walkAndMaterialise(node, opts) {
2748
2775
  const animDef = animBucket;
2749
2776
  const transformAnim = animDef.transform;
2750
2777
  if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
2751
- const materialised = materialiseMotionPathInPropAnim(transformAnim, opts);
2752
- if (materialised !== transformAnim) {
2753
- newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialised });
2778
+ const materialized = materializeMotionPathInPropAnim(transformAnim, opts);
2779
+ if (materialized !== transformAnim) {
2780
+ newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialized });
2754
2781
  }
2755
2782
  }
2756
2783
  }
@@ -2853,8 +2880,8 @@ function isPathString(value) {
2853
2880
  return typeof value === "string" && extractPathData(value) !== void 0;
2854
2881
  }
2855
2882
  function normalizePathValue(value) {
2856
- if (value && typeof value === "object" && typeof value.path === "string") {
2857
- const d = extractPathData(value.path);
2883
+ if (value && typeof value === "object" && typeof value.pathData === "string") {
2884
+ const d = extractPathData(value.pathData);
2858
2885
  return d ? { paths: parseSvgPathToBezier(d) } : value;
2859
2886
  }
2860
2887
  if (value && typeof value === "object" && "paths" in value) {
@@ -2938,7 +2965,7 @@ function interpolateValue(propName, a, b, t) {
2938
2965
  const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2939
2966
  return { paths: interpolateBeziers(aPaths, bPaths, t) };
2940
2967
  }
2941
- if (COLOUR_ATTR_NAMES.has(propName)) {
2968
+ if (COLOR_ATTR_NAMES.has(propName)) {
2942
2969
  return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
2943
2970
  }
2944
2971
  if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
@@ -3160,7 +3187,7 @@ function normalizeKeyframes(propName, propAnim, duration, defs) {
3160
3187
  value = normalizePathValue(value);
3161
3188
  }
3162
3189
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3163
- if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
3190
+ if (COLOR_ATTR_NAMES.has(propNameKebab)) {
3164
3191
  value = (_a2 = parseColor(value)) != null ? _a2 : value;
3165
3192
  }
3166
3193
  const normKf = {
@@ -3194,20 +3221,20 @@ function mergeAnimationDefinitions(animations) {
3194
3221
  }
3195
3222
  return merged;
3196
3223
  }
3197
- function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
3224
+ function materializeInternalLoopsInPropAnim(propName, propAnim, duration) {
3198
3225
  const loopRaw = propAnim.loop;
3199
3226
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
3200
3227
  const loop = loopRaw === true ? {} : loopRaw;
3201
3228
  const rawKfs = propAnim.keyframes;
3202
3229
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
3203
3230
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3204
- const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
3231
+ const isColor = COLOR_ATTR_NAMES.has(propNameKebab);
3205
3232
  const kfs = rawKfs.map((kf) => {
3206
3233
  var _a2;
3207
3234
  const t = kfTime(kf);
3208
3235
  let v = kfValue(kf);
3209
3236
  if (propName === "d") v = normalizePathValue(v);
3210
- if (isColour) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3237
+ if (isColor) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3211
3238
  const e = kfEasing(kf);
3212
3239
  const out2 = { t, v, e };
3213
3240
  const tIn = kfTangentIn(kf);
@@ -3221,15 +3248,15 @@ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
3221
3248
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3222
3249
  return out;
3223
3250
  }
3224
- function materialiseInternalLoopsInTree(root, duration) {
3225
- const ret = walkAndMaterialiseLoops(root, duration);
3251
+ function materializeInternalLoopsInTree(root, duration) {
3252
+ const ret = walkAndMaterializeLoops(root, duration);
3226
3253
  return ret != null ? ret : root;
3227
3254
  }
3228
- function walkAndMaterialiseLoops(node, duration) {
3255
+ function walkAndMaterializeLoops(node, duration) {
3229
3256
  let newChildren;
3230
3257
  if (node.children) {
3231
3258
  for (let i = 0; i < node.children.length; i++) {
3232
- const ret = walkAndMaterialiseLoops(node.children[i], duration);
3259
+ const ret = walkAndMaterializeLoops(node.children[i], duration);
3233
3260
  if (ret !== null) {
3234
3261
  if (!newChildren) newChildren = node.children.slice();
3235
3262
  newChildren[i] = ret;
@@ -3242,10 +3269,10 @@ function walkAndMaterialiseLoops(node, duration) {
3242
3269
  const animDef = animBucket;
3243
3270
  for (const propName of Object.keys(animDef)) {
3244
3271
  const propAnim = animDef[propName];
3245
- const materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);
3246
- if (materialised !== propAnim) {
3272
+ const materialized = materializeInternalLoopsInPropAnim(propName, propAnim, duration);
3273
+ if (materialized !== propAnim) {
3247
3274
  if (!newAnimate) newAnimate = __spreadValues({}, animDef);
3248
- newAnimate[propName] = materialised;
3275
+ newAnimate[propName] = materialized;
3249
3276
  }
3250
3277
  }
3251
3278
  }
@@ -3300,19 +3327,17 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimeli
3300
3327
  const out = { keyframes: normalizedKfs };
3301
3328
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3302
3329
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
3303
- normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
3330
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materializeMotionPathInPropAnim(out) : out;
3304
3331
  }
3305
3332
  }
3306
3333
  return normalized;
3307
3334
  }
3308
- function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
3335
+ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
3309
3336
  const animatorConfig = getAnimatorConfig(doc) || {};
3310
3337
  const defs = getDefs(doc);
3311
3338
  const duration = animatorConfig.duration || 1e3;
3312
3339
  const bindings = [];
3313
- const processAnimation = (id, animate, staticTransform) => {
3314
- if (!animate) return null;
3315
- const animDefs = resolveElementAnimation(animate, defs);
3340
+ const processAnimation = (id, animDefs, staticTransform) => {
3316
3341
  if (animDefs.length === 0) return null;
3317
3342
  const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);
3318
3343
  const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
@@ -3325,7 +3350,9 @@ function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
3325
3350
  const docBindings = getBindings(doc);
3326
3351
  if (docBindings) {
3327
3352
  for (const binding of docBindings) {
3328
- 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);
3329
3356
  if (normalized) bindings.push(normalized);
3330
3357
  }
3331
3358
  }
@@ -3334,7 +3361,7 @@ function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
3334
3361
  if (inlineAnim && Object.keys(inlineAnim).length > 0) {
3335
3362
  const nodeId = node.id || generateElementId();
3336
3363
  node.id = nodeId;
3337
- const normalized = processAnimation(nodeId, inlineAnim, node.transform);
3364
+ const normalized = processAnimation(nodeId, resolveElementAnimation(inlineAnim, defs), node.transform);
3338
3365
  if (normalized) bindings.push(normalized);
3339
3366
  }
3340
3367
  if (node.children) {
@@ -3396,7 +3423,7 @@ function calcPropertyValue(propName, propAnim, progress) {
3396
3423
  nextPaths,
3397
3424
  localProgress
3398
3425
  ).map((bz) => bezierToSvgPath(bz)).join("");
3399
- } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
3426
+ } else if (COLOR_ATTR_NAMES.has(cssAttrName)) {
3400
3427
  cssValue = toRGBA(interpolateColor(
3401
3428
  prevV || [0, 0, 0, 1],
3402
3429
  nextV || [0, 0, 0, 1],
@@ -3441,268 +3468,56 @@ function calcPropertyValue(propName, propAnim, progress) {
3441
3468
  );
3442
3469
  partsResult.translate = [sample.translate[0], sample.translate[1]];
3443
3470
  if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
3444
- }
3445
- }
3446
- cssValue = composeTransformParts(partsResult, { withUnits: false });
3447
- cssAttrName = "transform";
3448
- } else if (cssAttrName === "translate") {
3449
- const v = interpolateVec(
3450
- prevV || [0, 0],
3451
- nextV || [0, 0],
3452
- localProgress
3453
- );
3454
- cssValue = "translate(" + v.join(",") + ")";
3455
- cssAttrName = "transform";
3456
- } else if (cssAttrName === "rotate") {
3457
- const v = interpolateNum(
3458
- +(prevV || 0),
3459
- +(nextV || 0),
3460
- localProgress
3461
- );
3462
- cssValue = "rotate(" + v + ")";
3463
- cssAttrName = "transform";
3464
- } else if (cssAttrName === "scale") {
3465
- const v = interpolateVec(
3466
- prevV || [1, 1],
3467
- nextV || [1, 1],
3468
- localProgress
3469
- );
3470
- cssValue = "scale(" + v.join(",") + ")";
3471
- cssAttrName = "transform";
3472
- } else {
3473
- const num2 = interpolateNum(
3474
- +(prevV || 0),
3475
- +(nextV || 0),
3476
- localProgress
3477
- );
3478
- cssValue = num2;
3479
- }
3480
- if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
3481
- cssValue = cssValue * 100 + "%";
3482
- }
3483
- return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
3484
- }
3485
- function calcAnimationValues(animDef, progress) {
3486
- const result = {};
3487
- for (const [propName, propAnim] of Object.entries(animDef)) {
3488
- const computed = calcPropertyValue(propName, propAnim, progress);
3489
- if (computed) {
3490
- result[computed.k] = computed.v;
3491
- }
3492
- }
3493
- return result;
3494
- }
3495
-
3496
- // src/util/PxNodeCloneUtil.ts
3497
- function deepClonePxNode(value) {
3498
- if (value === null || typeof value !== "object") return value;
3499
- if (Array.isArray(value)) return value.map(deepClonePxNode);
3500
- const out = {};
3501
- for (const k of Object.keys(value)) out[k] = deepClonePxNode(value[k]);
3502
- return out;
3503
- }
3504
- function regenerateIdsAndRewriteRefs(root, genId3) {
3505
- const oldToNew = /* @__PURE__ */ new Map();
3506
- const walkAssign = (n) => {
3507
- var _a2;
3508
- if (typeof n.id === "string") {
3509
- const newId = genId3();
3510
- oldToNew.set(n.id, newId);
3511
- n.id = newId;
3512
- }
3513
- (_a2 = n.children) == null ? void 0 : _a2.forEach(walkAssign);
3514
- };
3515
- walkAssign(root);
3516
- const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
3517
- const newId = oldToNew.get(oldId);
3518
- return newId ? "url(#" + newId + ")" : m;
3519
- });
3520
- const walkRewrite = (n) => {
3521
- var _a2;
3522
- if (typeof n.href === "string" && n.href.startsWith("#")) {
3523
- const newId = oldToNew.get(n.href.slice(1));
3524
- if (newId) n.href = "#" + newId;
3525
- }
3526
- for (const k of Object.keys(n)) {
3527
- if (k === "children" || k === "effects" || k === "meta" || k === "animate" || k === "href" || k === "id") continue;
3528
- const v = n[k];
3529
- if (typeof v === "string" && v.indexOf("url(#") !== -1) {
3530
- n[k] = rewriteUrl(v);
3531
- }
3532
- }
3533
- (_a2 = n.children) == null ? void 0 : _a2.forEach(walkRewrite);
3534
- };
3535
- walkRewrite(root);
3536
- return oldToNew;
3537
- }
3538
- function toFiniteNum(v) {
3539
- const n = typeof v === "number" ? v : typeof v === "string" ? parseFloat(v) : NaN;
3540
- return Number.isFinite(n) ? n : 0;
3541
- }
3542
- function applyUseOffsetToG(gNode) {
3543
- var _a2;
3544
- const x = toFiniteNum(gNode.x);
3545
- const y = toFiniteNum(gNode.y);
3546
- delete gNode.x;
3547
- delete gNode.y;
3548
- if (!x && !y) return gNode;
3549
- const offset = "translate(" + x + "," + y + ")";
3550
- const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
3551
- if (carriesTransform) {
3552
- const inner = { type: "g", transform: offset, children: (_a2 = gNode.children) != null ? _a2 : [] };
3553
- gNode.children = [inner];
3554
- } else {
3555
- gNode.transform = offset;
3556
- }
3557
- return gNode;
3558
- }
3559
-
3560
- // src/materialise/PxAnimatorUseMaterialiser.ts
3561
- function materialiseAnimatedUseInstances(root) {
3562
- var _a2;
3563
- const idMap = buildIdMap(root);
3564
- const animatedIds = computeAnimatedSubtreeIds(root, idMap);
3565
- if (animatedIds.size === 0) return root;
3566
- let idCounter = 0;
3567
- const genId3 = () => "_lw_use_mat_" + ++idCounter;
3568
- const rootViewport = readRootViewport(root);
3569
- const defsCollector = [];
3570
- const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
3571
- if (defsCollector.length === 0) return walked;
3572
- const defsNode = { type: "defs", children: defsCollector };
3573
- const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
3574
- return __spreadProps(__spreadValues({}, walked), { children: newChildren });
3575
- }
3576
- function readRootViewport(root) {
3577
- const vb = parseViewBox(root.viewBox);
3578
- if (vb) return [vb[2], vb[3]];
3579
- const w = numericAttr(root.width);
3580
- const h = numericAttr(root.height);
3581
- if (w !== void 0 && h !== void 0) return [w, h];
3582
- return [1, 1];
3583
- }
3584
- function numericAttr(v) {
3585
- if (typeof v === "number") return v;
3586
- if (typeof v === "string") {
3587
- const n = parseFloat(v);
3588
- return Number.isFinite(n) ? n : void 0;
3589
- }
3590
- return void 0;
3591
- }
3592
- function buildIdMap(root) {
3593
- const map = /* @__PURE__ */ new Map();
3594
- const visit = (n) => {
3595
- var _a2;
3596
- if (typeof n.id === "string") map.set(n.id, n);
3597
- (_a2 = n.children) == null ? void 0 : _a2.forEach(visit);
3598
- };
3599
- visit(root);
3600
- return map;
3601
- }
3602
- function computeAnimatedSubtreeIds(root, idMap) {
3603
- const cache = /* @__PURE__ */ new WeakMap();
3604
- const result = /* @__PURE__ */ new Set();
3605
- const hasAnim = (n, visiting) => {
3606
- const cached = cache.get(n);
3607
- if (cached !== void 0) return cached;
3608
- if (visiting.has(n)) return false;
3609
- visiting.add(n);
3610
- let r = false;
3611
- if (n.animate && typeof n.animate === "object" && !Array.isArray(n.animate)) {
3612
- for (const _ in n.animate) {
3613
- r = true;
3614
- break;
3615
- }
3616
- }
3617
- if (!r && n.children) {
3618
- for (const ch of n.children) {
3619
- if (hasAnim(ch, visiting)) {
3620
- r = true;
3621
- break;
3622
- }
3623
- }
3624
- }
3625
- if (!r && n.type === "use" && typeof n.href === "string") {
3626
- const targetId = stripHash(n.href);
3627
- const target = targetId ? idMap.get(targetId) : void 0;
3628
- if (target) r = hasAnim(target, visiting);
3629
- }
3630
- visiting.delete(n);
3631
- cache.set(n, r);
3632
- return r;
3633
- };
3634
- for (const [id, node] of idMap) {
3635
- if (hasAnim(node, /* @__PURE__ */ new Set())) result.add(id);
3471
+ }
3472
+ }
3473
+ cssValue = composeTransformParts(partsResult, { withUnits: false });
3474
+ cssAttrName = "transform";
3475
+ } else if (cssAttrName === "translate") {
3476
+ const v = interpolateVec(
3477
+ prevV || [0, 0],
3478
+ nextV || [0, 0],
3479
+ localProgress
3480
+ );
3481
+ cssValue = "translate(" + v.join(",") + ")";
3482
+ cssAttrName = "transform";
3483
+ } else if (cssAttrName === "rotate") {
3484
+ const v = interpolateNum(
3485
+ +(prevV || 0),
3486
+ +(nextV || 0),
3487
+ localProgress
3488
+ );
3489
+ cssValue = "rotate(" + v + ")";
3490
+ cssAttrName = "transform";
3491
+ } else if (cssAttrName === "scale") {
3492
+ const v = interpolateVec(
3493
+ prevV || [1, 1],
3494
+ nextV || [1, 1],
3495
+ localProgress
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;
3636
3506
  }
3637
- return result;
3638
- }
3639
- function stripHash(href) {
3640
- if (typeof href !== "string") return void 0;
3641
- return href.startsWith("#") ? href.slice(1) : href;
3642
- }
3643
- function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3644
- var _a2, _b, _c, _d;
3645
- const clone2 = deepClonePxNode(target);
3646
- regenerateIdsAndRewriteRefs(clone2, genId3);
3647
- const symbolViewBox = clone2.type === "symbol" ? parseViewBox(clone2.viewBox) : void 0;
3648
- const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
3649
- const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
3650
- const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
3651
- const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
3652
- const newNode = __spreadProps(__spreadValues({}, useNode), { type: "g", children: [materialisedClone] });
3653
- delete newNode.href;
3654
- delete newNode.width;
3655
- delete newNode.height;
3656
- return applyUseOffsetToG(newNode);
3657
- }
3658
- function rewriteSymbolRootToGroup(symbolNode, genId3, defsCollector, useW, useH) {
3659
- const viewBox = parseViewBox(symbolNode.viewBox);
3660
- const g = __spreadProps(__spreadValues({}, symbolNode), { type: "g" });
3661
- delete g.viewBox;
3662
- delete g.preserveAspectRatio;
3663
- delete g.width;
3664
- delete g.height;
3665
- if (!viewBox) return g;
3666
- const [vbX, vbY, vbW, vbH] = viewBox;
3667
- const scale = vbW > 0 && vbH > 0 ? Math.min(useW / vbW, useH / vbH) : 1;
3668
- const xOff = (useW - vbW * scale) / 2;
3669
- const yOff = (useH - vbH * scale) / 2;
3670
- const parts = [];
3671
- if (xOff !== 0 || yOff !== 0) parts.push("translate(" + xOff + "," + yOff + ")");
3672
- if (scale !== 1) parts.push("scale(" + scale + ")");
3673
- if (vbX !== 0 || vbY !== 0) parts.push("translate(" + -vbX + "," + -vbY + ")");
3674
- if (parts.length) g.transform = parts.join("");
3675
- const clipId = genId3();
3676
- defsCollector.push({
3677
- type: "clipPath",
3678
- id: clipId,
3679
- children: [{ type: "rect", x: vbX, y: vbY, width: vbW, height: vbH }]
3680
- });
3681
- g.clipPath = "url(#" + clipId + ")";
3682
- return g;
3683
- }
3684
- function parseViewBox(v) {
3685
- if (typeof v !== "string") return void 0;
3686
- const parts = v.trim().split(/[\s,]+/).map(Number);
3687
- if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
3688
- 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 };
3689
3511
  }
3690
- function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
3691
- if (node.type === "use" && typeof node.href === "string") {
3692
- const targetId = stripHash(node.href);
3693
- if (targetId && animatedIds.has(targetId)) {
3694
- const target = idMap.get(targetId);
3695
- if (target) return materialiseOneUse(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;
3696
3518
  }
3697
3519
  }
3698
- if (!node.children) return node;
3699
- let changed = false;
3700
- const newChildren = node.children.map((ch) => {
3701
- const m = walkAndMaterialise2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
3702
- if (m !== ch) changed = true;
3703
- return m;
3704
- });
3705
- return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
3520
+ return result;
3706
3521
  }
3707
3522
 
3708
3523
  // src/effects/shared/transformParts.ts
@@ -3723,7 +3538,7 @@ function readAnimatable(raw) {
3723
3538
  const obj = raw;
3724
3539
  const kfs = obj.keyframes;
3725
3540
  if (kfs) {
3726
- const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3541
+ const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normalizeKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3727
3542
  const base = (_a2 = obj.value) != null ? _a2 : obj.v;
3728
3543
  if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
3729
3544
  return out;
@@ -3751,7 +3566,7 @@ function writeAnimatableChannel(node, attrName, read, opts) {
3751
3566
  const baseline = (_d = (_b = read.base) != null ? _b : (_a2 = read.keyframes[0]) == null ? void 0 : _a2.value) != null ? _d : (_c = read.keyframes[0]) == null ? void 0 : _c.v;
3752
3567
  if (baseline !== void 0) node[attrName] = toOut(baseline);
3753
3568
  }
3754
- function normaliseKeyframe(kf) {
3569
+ function normalizeKeyframe(kf) {
3755
3570
  if (!kf || typeof kf !== "object") return kf;
3756
3571
  const k = kf;
3757
3572
  if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
@@ -3873,11 +3688,75 @@ function wrapOrigin(inner, raw, invert) {
3873
3688
  return inner;
3874
3689
  }
3875
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
+
3876
3755
  // src/effects/shared/util.ts
3877
3756
  function genId(ctx, prefix) {
3878
3757
  return "_lw_" + prefix + "_" + ctx.nextId++;
3879
3758
  }
3880
- function stripHash2(href) {
3759
+ function stripHash(href) {
3881
3760
  return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3882
3761
  }
3883
3762
  function indexById(node, map) {
@@ -3899,7 +3778,7 @@ function regenerateIdsInClone(root, ctx) {
3899
3778
  function identifyContentRefTargets(node, ctx, allocator) {
3900
3779
  var _a2, _b, _c;
3901
3780
  if (node.type === "use" && ((_b = (_a2 = node.effects) == null ? void 0 : _a2.clone) == null ? void 0 : _b.without) === "translate") {
3902
- const sourceId = stripHash2(node.effects.clone.source);
3781
+ const sourceId = stripHash(node.effects.clone.source);
3903
3782
  if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
3904
3783
  ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
3905
3784
  }
@@ -4263,10 +4142,10 @@ function formatOffset(o) {
4263
4142
 
4264
4143
  // src/effects/clipping/clipPathEffect.ts
4265
4144
  function applyClipPathEffect(node, fx, ctx) {
4266
- if (!(fx == null ? void 0 : fx.d)) return node;
4145
+ if (!(fx == null ? void 0 : fx.pathData)) return node;
4267
4146
  const clipId = genId(ctx, "clip");
4268
4147
  const pathChild = { type: "path" };
4269
- const read = readAnimatable(fx.d);
4148
+ const read = readAnimatable(fx.pathData);
4270
4149
  if (read.kind !== "absent" /* Absent */) {
4271
4150
  if (read.kind === "static" /* Static */) {
4272
4151
  pathChild.d = pathString(read.value);
@@ -4281,14 +4160,14 @@ function applyClipPathEffect(node, fx, ctx) {
4281
4160
  }
4282
4161
  function pathString(v) {
4283
4162
  if (typeof v === "string") return v;
4284
- if (v && typeof v === "object" && typeof v.path === "string") return v.path;
4163
+ if (v && typeof v === "object" && typeof v.pathData === "string") return v.pathData;
4285
4164
  return void 0;
4286
4165
  }
4287
4166
 
4288
4167
  // src/effects/clipping/maskedByEffect.ts
4289
4168
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
4290
4169
  if (!fx) return node;
4291
- const sourceId = stripHash2(fx.source);
4170
+ const sourceId = stripHash(fx.source);
4292
4171
  if (!sourceId) {
4293
4172
  ctx.errors.push("maskedBy.source missing \u2014 cannot build mask");
4294
4173
  return node;
@@ -4328,8 +4207,8 @@ function wrapInverseTransform(inner, fx, ctx) {
4328
4207
  }
4329
4208
  function wrapInversePart(inner, part, raw, origin, ctx) {
4330
4209
  if (raw === void 0) return inner;
4331
- const normalisedRaw = part === "scale" /* Scale */ && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
4332
- const v = readAnimatable(normalisedRaw);
4210
+ const normalizedRaw = part === "scale" /* Scale */ && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
4211
+ const v = readAnimatable(normalizedRaw);
4333
4212
  if (v.kind === "static" /* Static */) {
4334
4213
  return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
4335
4214
  }
@@ -4565,7 +4444,7 @@ function collectMaskAncestorChains(root, ctx) {
4565
4444
  const interestingNodes = /* @__PURE__ */ new Set();
4566
4445
  const collectInterestingNodes = (n) => {
4567
4446
  var _a2, _b;
4568
- 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);
4569
4448
  if (typeof maskSourceId === "string") {
4570
4449
  interestingNodes.add(n);
4571
4450
  const sourceNode = ctx.idMap.get(maskSourceId);
@@ -4645,7 +4524,7 @@ function parseTranslateOnlyFromString(s, ctx) {
4645
4524
  // src/effects/reference/refEffect.ts
4646
4525
  function applyRefHref(node, clone2, ctx) {
4647
4526
  if (!clone2) return;
4648
- const sourceId = stripHash2(clone2.source);
4527
+ const sourceId = stripHash(clone2.source);
4649
4528
  if (!sourceId) {
4650
4529
  if (clone2.without === PxCloneWithout.translate) ctx.errors.push("clone: content ref missing `source`");
4651
4530
  return;
@@ -4730,7 +4609,7 @@ function synthesiseScale(raw, i) {
4730
4609
  }
4731
4610
 
4732
4611
  // src/effects/reference/retimeEffect.ts
4733
- var RETIME_MATERIALISATION_MODE_INLINE_G = false;
4612
+ var RETIME_MATERIALIZATION_MODE_INLINE_G = false;
4734
4613
  function asRetime(r) {
4735
4614
  var _a2, _b;
4736
4615
  return { start: (_a2 = r.start) != null ? _a2 : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
@@ -4791,7 +4670,7 @@ function applyAllRetimeEffects(root, ctx) {
4791
4670
  if (!n) return;
4792
4671
  if (n !== site && readCloneRetime(n)) count++;
4793
4672
  if (n.type === "use" && n.href) {
4794
- const id = stripHash2(n.href);
4673
+ const id = stripHash(n.href);
4795
4674
  if (id && !visited.has(id)) {
4796
4675
  visited.add(id);
4797
4676
  walk(ctx.idMap.get(id));
@@ -4799,7 +4678,7 @@ function applyAllRetimeEffects(root, ctx) {
4799
4678
  }
4800
4679
  (_a2 = n.children) == null ? void 0 : _a2.forEach(walk);
4801
4680
  };
4802
- const rootId = stripHash2(site.href);
4681
+ const rootId = stripHash(site.href);
4803
4682
  if (rootId) {
4804
4683
  visited.add(rootId);
4805
4684
  walk(ctx.idMap.get(rootId));
@@ -4815,19 +4694,19 @@ function applyAllRetimeEffects(root, ctx) {
4815
4694
  if (!retime) continue;
4816
4695
  const crop = retime.timeCrop;
4817
4696
  clearCloneRetime(useNode);
4818
- materialiseRetime(useNode, asRetime(retime), ctx);
4697
+ materializeRetime(useNode, asRetime(retime), ctx);
4819
4698
  if (crop) applyTimeCrop(useNode, crop, ctx);
4820
4699
  }
4821
4700
  }
4822
- function materialiseRetime(useNode, retime, ctx) {
4823
- const targetId = stripHash2(useNode.href);
4701
+ function materializeRetime(useNode, retime, ctx) {
4702
+ const targetId = stripHash(useNode.href);
4824
4703
  if (!targetId) {
4825
4704
  ctx.errors.push("retime: <use> has no href to follow");
4826
4705
  return;
4827
4706
  }
4828
4707
  const chainRootId = buildChainClone(targetId, retime, ctx, /* @__PURE__ */ new Set());
4829
4708
  if (!chainRootId) return;
4830
- if (RETIME_MATERIALISATION_MODE_INLINE_G) {
4709
+ if (RETIME_MATERIALIZATION_MODE_INLINE_G) {
4831
4710
  const cloneNode = ctx.idMap.get(chainRootId);
4832
4711
  useNode.type = "g";
4833
4712
  delete useNode.href;
@@ -4857,7 +4736,7 @@ function buildChainClone(targetId, accum, ctx, chain) {
4857
4736
  }
4858
4737
  clearCloneRetime(cloneNode);
4859
4738
  if (target.type === "use" && target.href) {
4860
- const subId = stripHash2(target.href);
4739
+ const subId = stripHash(target.href);
4861
4740
  if (subId) {
4862
4741
  const innerRetime = readCloneRetime(target);
4863
4742
  const subAccum = innerRetime ? concatRetime(asRetime(innerRetime), accum) : accum;
@@ -4867,18 +4746,18 @@ function buildChainClone(targetId, accum, ctx, chain) {
4867
4746
  if (subId2) cloneNode.href = "#" + subId2;
4868
4747
  }
4869
4748
  } else {
4870
- materialiseNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4749
+ materializeNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
4871
4750
  }
4872
4751
  ctx.defs.push(cloneNode);
4873
4752
  if (typeof cloneNode.id === "string") ctx.idMap.set(cloneNode.id, cloneNode);
4874
4753
  return typeof cloneNode.id === "string" ? cloneNode.id : void 0;
4875
4754
  }
4876
- function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4755
+ function materializeNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
4877
4756
  const visit = (n) => {
4878
4757
  var _a2;
4879
4758
  const retime = readCloneRetime(n);
4880
4759
  if (n.type === "use" && retime && n.href) {
4881
- const subId = stripHash2(n.href);
4760
+ const subId = stripHash(n.href);
4882
4761
  if (subId) {
4883
4762
  const subAccum = concatRetime(asRetime(retime), accum);
4884
4763
  const subChain = new Set(chain);
@@ -5074,10 +4953,10 @@ function numRange(v) {
5074
4953
  function estimateTextAdvance(node) {
5075
4954
  let chars = 0, maxFont = 16;
5076
4955
  const walk = (el) => {
5077
- var _a2, _b;
4956
+ var _a2;
5078
4957
  const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
5079
4958
  if (fs) maxFont = Math.max(maxFont, fs);
5080
- const t = (_b = el.text) != null ? _b : el.textContent;
4959
+ const t = el.textContent;
5081
4960
  if (typeof t === "string") chars += t.length;
5082
4961
  if (el.children) for (const c of el.children) walk(c);
5083
4962
  };
@@ -5232,7 +5111,6 @@ var TEXT_ATTR_KEYS = [
5232
5111
  "stroke",
5233
5112
  "strokeWidth",
5234
5113
  "effects",
5235
- TEXT_ATTR,
5236
5114
  TEXT_CONTENT_ATTR,
5237
5115
  "xml:space"
5238
5116
  ];
@@ -5269,7 +5147,7 @@ function paintAnimateOf(node) {
5269
5147
  }
5270
5148
  return out;
5271
5149
  }
5272
- function resolveStyle2(node, parent) {
5150
+ function resolveStyle(node, parent) {
5273
5151
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5274
5152
  const isTextRoot = node.type === "text";
5275
5153
  const nodeStyle = node.style;
@@ -5342,8 +5220,8 @@ function missingGlyphBoxEm(advanceEm, ascentEm) {
5342
5220
  const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
5343
5221
  return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
5344
5222
  }
5345
- function materialiseGlyphTextHorizontal(node, opts) {
5346
- var _a2, _b, _c, _d;
5223
+ function materializeGlyphTextHorizontal(node, opts) {
5224
+ var _a2, _b, _c;
5347
5225
  const { glyphs, create = jsonElementFactory, warnings } = opts;
5348
5226
  const soleFont = soleFontOf(glyphs);
5349
5227
  const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
@@ -5360,8 +5238,8 @@ function materialiseGlyphTextHorizontal(node, opts) {
5360
5238
  for (let i = 0; i < content.length; i++) {
5361
5239
  const ch = content.charAt(i);
5362
5240
  const g = gf == null ? void 0 : gf.glyphs[ch];
5363
- if (g && g.d) {
5364
- placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
5241
+ if (g && g.pathData) {
5242
+ placements.push({ glyphD: g.pathData, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
5365
5243
  pen.x += g.width * scale;
5366
5244
  } else if (/\S/.test(ch)) {
5367
5245
  const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
@@ -5375,8 +5253,8 @@ function materialiseGlyphTextHorizontal(node, opts) {
5375
5253
  }
5376
5254
  };
5377
5255
  const walk = (el, parentStyle) => {
5378
- var _a3, _b2, _c2, _d2;
5379
- const s = resolveStyle2(el, parentStyle);
5256
+ var _a3, _b2, _c2;
5257
+ const s = resolveStyle(el, parentStyle);
5380
5258
  const x = parseLen(el.x);
5381
5259
  const y = parseLen(el.y);
5382
5260
  if (x !== void 0) {
@@ -5387,14 +5265,14 @@ function materialiseGlyphTextHorizontal(node, opts) {
5387
5265
  if (y !== void 0) pen.y = y;
5388
5266
  pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
5389
5267
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
5390
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
5391
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5268
+ const content = str(el[TEXT_CONTENT_ATTR]);
5269
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
5392
5270
  if (el.children) for (const ch of el.children) walk(ch, s);
5393
5271
  };
5394
5272
  const rootStyle = rootStyleOf(node);
5395
5273
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
5396
- const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
5397
- if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
5274
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5275
+ if (rootContent && !((_c = node.children) == null ? void 0 : _c.length)) renderChars(rootContent, rootStyle);
5398
5276
  const anchor = str(node.textAnchor);
5399
5277
  if (anchor === "middle" || anchor === "end") {
5400
5278
  for (const p of placements) {
@@ -5406,7 +5284,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
5406
5284
  return toGroup(node, buildPaths(placements, create, warnings), create);
5407
5285
  }
5408
5286
  function layoutGlyphTextChars(node, opts) {
5409
- var _a2, _b, _c, _d, _e, _f;
5287
+ var _a2, _b, _c, _d, _e;
5410
5288
  if ((_a2 = opts.alongPath) == null ? void 0 : _a2.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
5411
5289
  const { glyphs, warnings } = opts;
5412
5290
  const soleFont = soleFontOf(glyphs);
@@ -5430,8 +5308,8 @@ function layoutGlyphTextChars(node, opts) {
5430
5308
  }
5431
5309
  };
5432
5310
  const walk = (el, parentStyle) => {
5433
- var _a3, _b2, _c2, _d2;
5434
- const s = resolveStyle2(el, parentStyle);
5311
+ var _a3, _b2, _c2;
5312
+ const s = resolveStyle(el, parentStyle);
5435
5313
  const x = parseLen(el.x);
5436
5314
  const y = parseLen(el.y);
5437
5315
  if (x !== void 0) {
@@ -5442,8 +5320,8 @@ function layoutGlyphTextChars(node, opts) {
5442
5320
  if (y !== void 0) pen.y = y;
5443
5321
  pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
5444
5322
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
5445
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
5446
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5323
+ const content = str(el[TEXT_CONTENT_ATTR]);
5324
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
5447
5325
  if (el.children) for (const ch of el.children) walk(ch, s);
5448
5326
  };
5449
5327
  const rootStyle = rootStyleOf(node);
@@ -5451,14 +5329,14 @@ function layoutGlyphTextChars(node, opts) {
5451
5329
  const before = boxes.length;
5452
5330
  walk(ch, rootStyle);
5453
5331
  if (boxes.length === before) {
5454
- const s = resolveStyle2(ch, rootStyle);
5332
+ const s = resolveStyle(ch, rootStyle);
5455
5333
  const gf = glyphFontFor(s, glyphs, soleFont);
5456
5334
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
5457
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 });
5458
5336
  }
5459
5337
  }
5460
- const rootContent = (_e = str(node[TEXT_CONTENT_ATTR])) != null ? _e : str(node[TEXT_ATTR]);
5461
- if (rootContent && !((_f = node.children) == null ? void 0 : _f.length)) renderChars(rootContent, rootStyle);
5338
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
5339
+ if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
5462
5340
  const anchor = str(node.textAnchor);
5463
5341
  if (anchor === "middle" || anchor === "end") {
5464
5342
  for (const b of boxes) {
@@ -5466,8 +5344,8 @@ function layoutGlyphTextChars(node, opts) {
5466
5344
  b.x += anchor === "middle" ? -w / 2 : -w;
5467
5345
  }
5468
5346
  }
5469
- return boxes.map((_g) => {
5470
- var _h = _g, { line: _l } = _h, b = __objRest(_h, ["line"]);
5347
+ return boxes.map((_f) => {
5348
+ var _g = _f, { line: _l } = _g, b = __objRest(_g, ["line"]);
5471
5349
  return b;
5472
5350
  });
5473
5351
  }
@@ -5483,14 +5361,14 @@ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
5483
5361
  const chars = [];
5484
5362
  let adv = 0;
5485
5363
  const walk = (el, parentStyle) => {
5486
- var _a3, _b2, _c;
5487
- const s = resolveStyle2(el, parentStyle);
5488
- const content = (_a3 = str(el[TEXT_CONTENT_ATTR])) != null ? _a3 : str(el[TEXT_ATTR]);
5489
- if (content && !((_b2 = el.children) == null ? void 0 : _b2.length)) {
5364
+ var _a3, _b2;
5365
+ const s = resolveStyle(el, parentStyle);
5366
+ const content = str(el[TEXT_CONTENT_ATTR]);
5367
+ if (content && !((_a3 = el.children) == null ? void 0 : _a3.length)) {
5490
5368
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
5491
5369
  const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
5492
5370
  const scale = s.fontSize / upm;
5493
- const ascent = ((_c = gf == null ? void 0 : gf.ascent) != null ? _c : 0.9 * upm) * scale;
5371
+ const ascent = ((_b2 = gf == null ? void 0 : gf.ascent) != null ? _b2 : 0.9 * upm) * scale;
5494
5372
  for (let i = 0; i < content.length; i++) {
5495
5373
  const ch = content.charAt(i);
5496
5374
  const g = gf == null ? void 0 : gf.glyphs[ch];
@@ -5537,21 +5415,21 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
5537
5415
  const cells = [];
5538
5416
  let adv = 0;
5539
5417
  const walk = (el, parentStyle) => {
5540
- var _a2, _b, _c;
5541
- const s = resolveStyle2(el, parentStyle);
5542
- const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
5543
- if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
5418
+ var _a2, _b;
5419
+ const s = resolveStyle(el, parentStyle);
5420
+ const content = str(el[TEXT_CONTENT_ATTR]);
5421
+ if (content && !((_a2 = el.children) == null ? void 0 : _a2.length)) {
5544
5422
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
5545
5423
  if (gf) {
5546
5424
  const scale = s.fontSize / gf.unitsPerEm;
5547
- const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
5425
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
5548
5426
  const paint = paintOf(s);
5549
5427
  for (let i = 0; i < content.length; i++) {
5550
5428
  const ch = content.charAt(i);
5551
5429
  const g = gf.glyphs[ch];
5552
- if (g && g.d) {
5430
+ if (g && g.pathData) {
5553
5431
  const glyphAdv = g.width * scale;
5554
- cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
5432
+ cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
5555
5433
  adv += glyphAdv;
5556
5434
  } else if (/\S/.test(ch)) {
5557
5435
  const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
@@ -5582,7 +5460,7 @@ function alongPathNodeOffsets(node) {
5582
5460
  perp: (_c = parseLen(node.dy)) != null ? _c : 0
5583
5461
  };
5584
5462
  }
5585
- function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5463
+ function materializeGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
5586
5464
  const { glyphs, create = jsonElementFactory, warnings } = opts;
5587
5465
  const sampler = pathD ? createPathSampler(pathD) : null;
5588
5466
  if (!sampler) {
@@ -5661,8 +5539,8 @@ function buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isC
5661
5539
  const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
5662
5540
  const out = [];
5663
5541
  for (const c of cells) {
5664
- const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5665
- const d = transformPathData(c.glyphD, centred);
5542
+ const centered = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
5543
+ const d = transformPathData(c.glyphD, centered);
5666
5544
  const sampleKf = (dist, time) => {
5667
5545
  const { x, y, angle } = sampler.sampleAtDistance(dist);
5668
5546
  const cos = Math.cos(angle), sin = Math.sin(angle);
@@ -5754,9 +5632,9 @@ function toGroup(node, children, create) {
5754
5632
  }
5755
5633
  return create("g", gProps, children);
5756
5634
  }
5757
- function materialiseGlyphText(node, opts) {
5758
- if (opts.alongPath) return materialiseGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5759
- return materialiseGlyphTextHorizontal(node, opts);
5635
+ function materializeGlyphText(node, opts) {
5636
+ if (opts.alongPath) return materializeGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
5637
+ return materializeGlyphTextHorizontal(node, opts);
5760
5638
  }
5761
5639
  function applyTextGlyphsEffect(node, fx, ctx) {
5762
5640
  if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
@@ -5764,14 +5642,14 @@ function applyTextGlyphsEffect(node, fx, ctx) {
5764
5642
  ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
5765
5643
  return node;
5766
5644
  }
5767
- return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5645
+ return materializeGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
5768
5646
  }
5769
5647
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
5770
5648
  if (!ctx.glyphs) {
5771
5649
  ctx.warnings.push("textGlyphs: no definitions.fonts");
5772
5650
  return null;
5773
5651
  }
5774
- return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5652
+ return materializeGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
5775
5653
  }
5776
5654
 
5777
5655
  // src/effects/stroke/strokeTrimEffect.ts
@@ -6173,7 +6051,7 @@ function applyPlayerEffects_retime(node, ctx) {
6173
6051
  return node;
6174
6052
  }
6175
6053
 
6176
- // src/materialise/PxOffsetPathMaterialiser.ts
6054
+ // src/materialize/PxOffsetPathMaterializer.ts
6177
6055
  function cubicAt(p0, c1, c2, p1, t) {
6178
6056
  const u = 1 - t;
6179
6057
  const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
@@ -6239,7 +6117,7 @@ function buildOffsetPath(propAnim) {
6239
6117
  }
6240
6118
  return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
6241
6119
  }
6242
- function materialiseOffsetPathsInTree(root) {
6120
+ function materializeOffsetPathsInTree(root) {
6243
6121
  const walk = (node) => {
6244
6122
  var _a2;
6245
6123
  let out = node;
@@ -6261,38 +6139,186 @@ function materialiseOffsetPathsInTree(root) {
6261
6139
  delete t[TRANSFORM_PART.origin];
6262
6140
  newTransform = Object.keys(t).length ? t : void 0;
6263
6141
  }
6264
- out = __spreadProps(__spreadValues({}, node), {
6265
- animate: newAnimate,
6266
- style: __spreadProps(__spreadValues({}, node.style), {
6267
- offsetPath: "path('" + built.pathStr + "')",
6268
- offsetAnchor: fmt2(built.anchor[0]) + "px " + fmt2(built.anchor[1]) + "px",
6269
- offsetRotate: built.autoOrient ? "auto" : "0deg",
6270
- offsetDistance: "0%"
6271
- })
6272
- });
6273
- if (newTransform !== void 0) out.transform = newTransform;
6274
- else delete out.transform;
6142
+ out = __spreadProps(__spreadValues({}, node), {
6143
+ animate: newAnimate,
6144
+ style: __spreadProps(__spreadValues({}, node.style), {
6145
+ offsetPath: "path('" + built.pathStr + "')",
6146
+ offsetAnchor: fmt2(built.anchor[0]) + "px " + fmt2(built.anchor[1]) + "px",
6147
+ offsetRotate: built.autoOrient ? "auto" : "0deg",
6148
+ offsetDistance: "0%"
6149
+ })
6150
+ });
6151
+ if (newTransform !== void 0) out.transform = newTransform;
6152
+ else delete out.transform;
6153
+ }
6154
+ }
6155
+ if ((_a2 = out.children) == null ? void 0 : _a2.length) {
6156
+ const children = out.children.map(walk);
6157
+ if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
6158
+ }
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
+ }
6275
6227
  }
6276
6228
  }
6277
- if ((_a2 = out.children) == null ? void 0 : _a2.length) {
6278
- const children = out.children.map(walk);
6279
- if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
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);
6280
6233
  }
6281
- return out;
6234
+ visiting.delete(n);
6235
+ cache.set(n, r);
6236
+ return r;
6282
6237
  };
6283
- return walk(root);
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;
6284
6310
  }
6285
6311
 
6286
- // src/materialise/PxAnimatorMaterialiseAll.ts
6287
- function materialiseAllInTree(doc, engine, opts) {
6312
+ // src/materialize/PxAnimatorMaterializeAll.ts
6313
+ function materializeAllInTree(doc, engine, opts) {
6288
6314
  var _a2, _b;
6289
6315
  let root = applyPlayerEffects(doc).root;
6290
- root = materialiseOffsetPathsInTree(root);
6316
+ root = materializeOffsetPathsInTree(root);
6291
6317
  const duration = (_b = (_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.duration) != null ? _b : DEFAULT_DURATION_MS;
6292
- root = materialiseInternalLoopsInTree(root, duration);
6318
+ root = materializeInternalLoopsInTree(root, duration);
6293
6319
  if (engine === PxTimelineEngine.native) {
6294
- root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
6295
- root = materialiseAnimatedUseInstances(root);
6320
+ root = materializeMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
6321
+ root = materializeAnimatedUseInstances(root);
6296
6322
  root = pruneUnreferencedDefs(root);
6297
6323
  }
6298
6324
  return root;
@@ -6327,6 +6353,66 @@ function pruneUnreferencedDefs(root) {
6327
6353
  return root;
6328
6354
  }
6329
6355
 
6356
+ // src/playback/PxPlaybackTime.ts
6357
+ var PX_RATE_REJECTED = "setPlaybackRate: rate must be finite and non-zero";
6358
+ function isValidPlaybackRate(rate) {
6359
+ return Number.isFinite(rate) && rate !== 0;
6360
+ }
6361
+ function seekCeilingMs(durationMs, iterations) {
6362
+ if (!(durationMs > 0)) return 0;
6363
+ if (iterations === Infinity) return Infinity;
6364
+ return durationMs * (iterations > 0 ? iterations : 1);
6365
+ }
6366
+ function progressSpanMs(durationMs, iterations) {
6367
+ if (!(durationMs > 0)) return 0;
6368
+ if (iterations === Infinity) return durationMs;
6369
+ return durationMs * (iterations > 0 ? iterations : 1);
6370
+ }
6371
+ function clampSeekMs(timeMs, ceilingMs) {
6372
+ if (Number.isNaN(timeMs) || timeMs < 0) return 0;
6373
+ if (Number.isFinite(ceilingMs)) return timeMs > ceilingMs ? ceilingMs : timeMs;
6374
+ return Number.isFinite(timeMs) ? timeMs : 0;
6375
+ }
6376
+ function timeToProgress(timeMs, durationMs, iterations) {
6377
+ const span = progressSpanMs(durationMs, iterations);
6378
+ if (!(span > 0) || !Number.isFinite(timeMs)) return 0;
6379
+ if (timeMs <= 0) return 0;
6380
+ if (iterations === Infinity) return timeMs % span / span;
6381
+ return timeMs >= span ? 1 : timeMs / span;
6382
+ }
6383
+ function progressToTimeMs(progress, durationMs, iterations) {
6384
+ const span = progressSpanMs(durationMs, iterations);
6385
+ if (!(span > 0) || !Number.isFinite(progress)) return 0;
6386
+ if (progress <= 0) return 0;
6387
+ return progress >= 1 ? span : progress * span;
6388
+ }
6389
+ function createRunClock(ceilingMs, nowFn = Date.now) {
6390
+ let baseMs = 0;
6391
+ let startedAt = 0;
6392
+ let running = false;
6393
+ let rate = 1;
6394
+ const value = () => running ? clampSeekMs(baseMs + (nowFn() - startedAt) * rate, ceilingMs) : clampSeekMs(baseMs, ceilingMs);
6395
+ return {
6396
+ now: value,
6397
+ isRunning: () => running,
6398
+ start: (r, atMs) => {
6399
+ baseMs = clampSeekMs(atMs != null ? atMs : value(), ceilingMs);
6400
+ rate = isValidPlaybackRate(r) ? r : 1;
6401
+ startedAt = nowFn();
6402
+ running = true;
6403
+ },
6404
+ stop: () => {
6405
+ baseMs = value();
6406
+ startedAt = 0;
6407
+ running = false;
6408
+ },
6409
+ seek: (ms) => {
6410
+ baseMs = clampSeekMs(ms, ceilingMs);
6411
+ if (running) startedAt = nowFn();
6412
+ }
6413
+ };
6414
+ }
6415
+
6330
6416
  // src/playback/PxFrameLoop.ts
6331
6417
  function requestFrame(cb) {
6332
6418
  const g = globalThis;
@@ -6344,7 +6430,7 @@ function cancelFrame(handle) {
6344
6430
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6345
6431
  var _a2;
6346
6432
  const config = getAnimatorConfig(doc) || {};
6347
- const bindings = getNormalisedBindings(doc, PxTimelineEngine.js);
6433
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.js);
6348
6434
  const _iterations = config.iterations;
6349
6435
  let iterations = 1;
6350
6436
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -6521,88 +6607,305 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
6521
6607
  } else if (fillsBackwards) {
6522
6608
  renderFrame(0);
6523
6609
  }
6524
- };
6525
- const cancelAnim = () => {
6526
- var _a3;
6527
- pauseAnim();
6528
- timeBeforeLastStartMs = 0;
6529
- lastStartedTs = 0;
6530
- playing = false;
6531
- finishCalled = false;
6532
- renderFrame(timeBeforeLastStartMs);
6533
- (_a3 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a3.call(callbacks);
6534
- };
6535
- const finishAnim = (callOnFinish = true) => {
6536
- var _a3;
6537
- if (Number.isFinite(totalDuration)) {
6538
- timeBeforeLastStartMs = totalDuration;
6539
- } else {
6540
- timeBeforeLastStartMs = getAnimCurrentTime();
6610
+ };
6611
+ const cancelAnim = () => {
6612
+ var _a3;
6613
+ pauseAnim();
6614
+ timeBeforeLastStartMs = 0;
6615
+ lastStartedTs = 0;
6616
+ playing = false;
6617
+ finishCalled = false;
6618
+ renderFrame(timeBeforeLastStartMs);
6619
+ (_a3 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a3.call(callbacks);
6620
+ };
6621
+ const finishAnim = (callOnFinish = true) => {
6622
+ var _a3;
6623
+ if (Number.isFinite(totalDuration)) {
6624
+ timeBeforeLastStartMs = totalDuration;
6625
+ } else {
6626
+ timeBeforeLastStartMs = getAnimCurrentTime();
6627
+ }
6628
+ lastStartedTs = 0;
6629
+ playing = false;
6630
+ if (timerId !== null) {
6631
+ cancelFrame(timerId);
6632
+ timerId = null;
6633
+ }
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;
6541
6845
  }
6542
- lastStartedTs = 0;
6543
- playing = false;
6544
- if (timerId !== null) {
6545
- cancelFrame(timerId);
6546
- timerId = null;
6846
+ if (key === "timeline") {
6847
+ out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
6848
+ continue;
6547
6849
  }
6548
- renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
6549
- if (callOnFinish && !finishCalled) {
6550
- finishCalled = true;
6551
- (_a3 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a3.call(callbacks);
6850
+ if (isPlainObject(value)) {
6851
+ out[key] = mergePlain(out[key], value);
6852
+ continue;
6552
6853
  }
6553
- };
6554
- const api = {
6555
- "isReady": () => true,
6556
- "getRootElement": () => null,
6557
- "isPlaying": () => {
6558
- return _isPlaying();
6559
- },
6560
- "play": () => {
6561
- var _a3;
6562
- startAnim();
6563
- (_a3 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a3.call(callbacks);
6564
- },
6565
- "pause": () => {
6566
- var _a3;
6567
- pauseAnim();
6568
- (_a3 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a3.call(callbacks);
6569
- },
6570
- "cancel": () => {
6571
- cancelAnim();
6572
- },
6573
- "finish": () => {
6574
- finishAnim(true);
6575
- },
6576
- "setPlaybackRate": (rate) => {
6577
- if (!isFinite(rate) || rate === 0) {
6578
- console.warn("setPlaybackRate: rate must be finite and non-zero");
6579
- return;
6580
- }
6581
- let current = getRawAnimTime();
6582
- if (Number.isFinite(totalDuration) && current > totalDuration) current = totalDuration;
6583
- if (rate < 0 !== playbackRate < 0) finishCalled = false;
6584
- playbackRate = rate;
6585
- timeBeforeLastStartMs = current;
6586
- if (playing) lastStartedTs = Date.now();
6587
- },
6588
- "getCurrentTime": () => {
6589
- return getAnimCurrentTime();
6590
- },
6591
- "setCurrentTime": (newTime) => {
6592
- if (newTime < 0) newTime = 0;
6593
- if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
6594
- timeBeforeLastStartMs = newTime;
6595
- if (playing) lastStartedTs = Date.now();
6596
- if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
6597
- renderFrame(getAnimCurrentTime());
6598
- },
6599
- "destroy": () => {
6600
- var _a3;
6601
- api.cancel();
6602
- (_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];
6603
6877
  }
6604
- };
6605
- 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 };
6890
+ }
6891
+
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
+ }
6900
+ }
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
+ );
6606
6909
  }
6607
6910
 
6608
6911
  // src/effects/PlayerEffectsUtil.visualModel.ts
@@ -6795,276 +7098,281 @@ function diffInEffect(a, b) {
6795
7098
  const diffs = [];
6796
7099
  for (const t of Array.from(times).sort((x, y) => x - y)) {
6797
7100
  const ma = visualModelAt(a, t);
6798
- const mb = visualModelAt(b, t);
6799
- const onlyInA = subtractMultiset(ma, mb);
6800
- const onlyInB = subtractMultiset(mb, ma);
6801
- if (onlyInA.length || onlyInB.length) diffs.push({ time: t, onlyInA, onlyInB });
6802
- }
6803
- return diffs;
6804
- }
6805
- function subtractMultiset(a, b) {
6806
- const counts = /* @__PURE__ */ new Map();
6807
- for (const x of b) counts.set(x, (counts.get(x) || 0) + 1);
6808
- const extra = [];
6809
- for (const x of a) {
6810
- const c = counts.get(x) || 0;
6811
- if (c > 0) counts.set(x, c - 1);
6812
- else extra.push(x);
6813
- }
6814
- return extra;
6815
- }
6816
-
6817
- // src/playback/PxAnimatorConfigPatch.ts
6818
- var FLAT_ONLY_KEYS = [
6819
- "timelineSource",
6820
- "scroll",
6821
- "trigger",
6822
- "delay",
6823
- "iterations",
6824
- "direction",
6825
- "fill",
6826
- "resetOnFinish",
6827
- "duration",
6828
- "mode",
6829
- "frameRate"
6830
- ];
6831
- var CONTENT_KEYS = ["definitions", "animateById"];
6832
- var isPlainObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
6833
- var timelineTypeOf = (t) => isPlainObject(t) && typeof t.type === "string" ? t.type : "time";
6834
- var isScrollish = (type) => type === "scroll" || type === "view";
6835
- function mergePlain(base, patch) {
6836
- const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6837
- for (const key of Object.keys(patch)) {
6838
- const value = patch[key];
6839
- if (value === null) {
6840
- delete out[key];
6841
- continue;
6842
- }
6843
- if (isPlainObject(value)) {
6844
- out[key] = mergePlain(out[key], value);
6845
- continue;
6846
- }
6847
- out[key] = value;
6848
- }
6849
- return out;
6850
- }
6851
- function mergeTimeline(base, patch, warn) {
6852
- const baseType = timelineTypeOf(base);
6853
- const patchNamesType = isPlainObject(patch) && typeof patch.type === "string";
6854
- const patchType = patchNamesType ? String(patch.type) : baseType;
6855
- let merged;
6856
- if (patchType !== baseType) {
6857
- const carried = {};
6858
- if (isPlainObject(base)) {
6859
- for (const k of PX_TIMELINE_SHARED_KEYS) {
6860
- if (base[k] !== void 0) carried[k] = base[k];
6861
- }
6862
- }
6863
- merged = mergePlain(carried, patch);
6864
- } else {
6865
- merged = mergePlain(base, patch);
6866
- }
6867
- if (isScrollish(patchType)) {
6868
- for (const k of PX_TIME_ONLY_TIMELINE_KEYS) {
6869
- if (merged[k] === void 0) continue;
6870
- warn("animator.timeline." + k + ": no slot on a '" + patchType + "' timeline \u2014 dropped");
6871
- delete merged[k];
6872
- }
6873
- if (merged.iterations === "infinite") {
6874
- warn("animator.timeline.iterations: 'infinite' cannot map onto a scroll range \u2014 dropped");
6875
- delete merged.iterations;
6876
- }
6877
- }
6878
- return merged;
6879
- }
6880
- function foldAnimatorConfigShortcuts(config, shortcuts) {
6881
- let base;
6882
- if (typeof config === "string") {
6883
- try {
6884
- base = JSON.parse(config);
6885
- } catch (e) {
6886
- console.warn("animator config: not valid JSON \u2014 ignored", e);
6887
- base = void 0;
6888
- }
6889
- } else {
6890
- base = config != null ? config : void 0;
6891
- }
6892
- const { duration, delay, iterations, startOn } = shortcuts;
6893
- if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6894
- return base;
6895
- }
6896
- const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6897
- const timeline = __spreadValues({}, out.timeline);
6898
- if (duration !== void 0) timeline.duration = duration;
6899
- if (delay !== void 0) timeline.delay = delay;
6900
- if (iterations !== void 0) timeline.iterations = iterations;
6901
- if (startOn !== void 0) {
6902
- timeline.trigger = __spreadProps(__spreadValues({}, timeline.trigger), { startOn });
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 });
6903
7105
  }
6904
- out.timeline = timeline;
6905
- return out;
7106
+ return diffs;
6906
7107
  }
6907
- function mergeAnimatorConfig(base, patch) {
6908
- const warnings = [];
6909
- const warn = (m) => warnings.push(m);
6910
- if (patch === null) return { config: void 0, warnings };
6911
- if (!isPlainObject(patch) || Object.keys(patch).length === 0) {
6912
- 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);
6913
7116
  }
6914
- const flatInBase = isPlainObject(base) ? FLAT_ONLY_KEYS.filter((k) => base[k] !== void 0) : [];
6915
- if (flatInBase.length) {
6916
- 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];
6917
7144
  }
6918
- const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6919
- for (const key of Object.keys(patch)) {
6920
- const value = patch[key];
6921
- if (value === null) {
6922
- delete out[key];
6923
- continue;
6924
- }
6925
- if (key === "timeline") {
6926
- out.timeline = isPlainObject(value) ? mergeTimeline(out.timeline, value, warn) : value;
6927
- continue;
6928
- }
6929
- if (isPlainObject(value)) {
6930
- out[key] = mergePlain(out[key], value);
6931
- 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;
6932
7216
  }
6933
- out[key] = value;
6934
7217
  }
6935
- return { config: out, warnings };
7218
+ return [...fields].sort();
6936
7219
  }
6937
- function applyAnimatorConfig(doc, patch, opts) {
6938
- var _a2, _b;
6939
- const reset = !!(opts == null ? void 0 : opts.resetDefaults);
6940
- if (!doc || (patch === void 0 || !reset && (patch === null || !isPlainObject(patch) || !Object.keys(patch).length))) {
6941
- 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." };
6942
7248
  }
6943
- const anyDoc = doc;
6944
- const atRoot = isPlainObject(anyDoc.animator);
6945
- const atMeta = !atRoot && isPlainObject((_a2 = anyDoc.meta) == null ? void 0 : _a2.animator);
6946
- const current = atRoot ? anyDoc.animator : atMeta ? anyDoc.meta.animator : void 0;
6947
- const warnings = [];
6948
- if (atRoot && isPlainObject((_b = anyDoc.meta) == null ? void 0 : _b.animator)) {
6949
- 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
+ };
6950
7258
  }
6951
- let base = current;
6952
- if (reset) {
6953
- const kept = {};
6954
- for (const k of CONTENT_KEYS) {
6955
- if (isPlainObject(current) && current[k] !== void 0) kept[k] = current[k];
6956
- }
6957
- 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 + "." };
6958
7262
  }
6959
- const merged = mergeAnimatorConfig(base, patch != null ? patch : {});
6960
- warnings.push(...merged.warnings);
6961
- if (merged.config === current) return { doc, warnings };
6962
- if (atMeta) {
7263
+ if (requiredKind === "converted" /* converted */ && step.kind !== "converted" /* converted */) {
6963
7264
  return {
6964
- doc: __spreadProps(__spreadValues({}, anyDoc), { meta: __spreadProps(__spreadValues({}, anyDoc.meta), { animator: merged.config }) }),
6965
- 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()."
6966
7269
  };
6967
7270
  }
6968
- return { doc: __spreadProps(__spreadValues({}, anyDoc), { animator: merged.config }), warnings };
7271
+ return { changed, requiredKind, requiredVersion };
6969
7272
  }
6970
-
6971
- // src/format/PxDocumentDiagnostic.ts
6972
- var MAX_REPORTED = 6;
6973
- var LEGACY_FLAT_KEYS = [
6974
- ...PX_TIMELINE_SHARED_KEYS,
6975
- ...PX_TIME_ONLY_TIMELINE_KEYS,
6976
- "fill",
6977
- "resetOnFinish",
6978
- "timelineSource",
6979
- "scroll"
6980
- ];
6981
- var isLegacyFlatAnimatorKey = (w) => LEGACY_FLAT_KEYS.some((k) => w.indexOf("animator." + k + ":") >= 0);
6982
- function diagnoseDocument(doc) {
6983
- let all;
6984
- try {
6985
- all = validateDocument(doc);
6986
- } catch (e) {
6987
- return { problems: [], legacy: [] };
6988
- }
7273
+ function releaseLogProblems(releases, steps, declared, baseline) {
6989
7274
  const problems = [];
6990
- const legacy = [];
6991
- for (const w of all) (isLegacyFlatAnimatorKey(w) ? legacy : problems).push(w);
6992
- return { problems, legacy };
6993
- }
6994
- function reportDocumentDiagnostics(doc, where) {
6995
- const { problems } = diagnoseDocument(doc);
6996
- if (!problems.length) return;
6997
- const shown = problems.slice(0, MAX_REPORTED);
6998
- const more = problems.length - shown.length;
6999
- console.warn(
7000
- 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."
7001
- );
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 + ".");
7278
+ }
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;
7002
7297
  }
7003
7298
  // Annotate the CommonJS export names for ESM import in node:
7004
7299
  0 && (module.exports = {
7005
7300
  BASELINE_PLAYER_VERSION,
7006
- COLOUR_ATTR_NAMES,
7301
+ COLOR_ATTR_NAMES,
7007
7302
  CSS_ONLY_STYLE_PROPS,
7008
7303
  DEFAULT_DURATION_MS,
7009
7304
  DISALLOWED_SVG_TAGS_LOWER,
7010
- INTERNAL_ATTRS,
7011
7305
  LOOP_JUMP_SHIFT_MS,
7012
- MISSING_GLYPH_CLASS_NAME,
7013
7306
  PCT_BASED_ATTR_NAMES,
7014
7307
  PLAYER_WIRE_STEPS,
7015
7308
  PLAYER_WIRE_VERSION,
7016
7309
  PX_ANIM_ATTR_NAME,
7017
7310
  PX_ANIM_SRC_ATTR_NAME,
7018
7311
  PX_PLAYER_SCHEMA_VERSION,
7312
+ PX_RATE_REJECTED,
7019
7313
  PX_TRANSFORM_PART_KEYS,
7314
+ PX_TRIGGER_DEFAULTS,
7020
7315
  PX_UNKNOWN_KEY_ERROR,
7316
+ PxAlongPathMode,
7021
7317
  PxAnimatedSvgDocumentSchema,
7022
- PxAnimationDefinitionSchema,
7023
7318
  PxAnimatorConfigSchema,
7024
7319
  PxAttrValueSchema,
7025
7320
  PxBezierPathSchema,
7026
- PxBindingSchema,
7321
+ PxClipPathEffectSchema,
7027
7322
  PxCloneEffectSchema,
7028
7323
  PxCloneWithout,
7324
+ PxControlMode,
7029
7325
  PxDefsSchema,
7030
- PxEasingOrRefSchema,
7326
+ PxDiagnosticKind,
7031
7327
  PxEffectsSchema,
7032
7328
  PxElementAnimationSchema,
7033
7329
  PxFillGradientEffectSchema,
7330
+ PxFillMode,
7331
+ PxFinishAction,
7034
7332
  PxGradientSpreadMethod,
7035
7333
  PxGradientStopSchema,
7036
7334
  PxGradientType,
7037
- PxGradientUnits,
7038
7335
  PxKeyframeSchema,
7039
7336
  PxKeyframeValueSchema,
7337
+ PxLengthAdjust,
7040
7338
  PxLoopDirection,
7041
7339
  PxLoopRepeatAt,
7042
7340
  PxLoopSchema,
7341
+ PxMaskType,
7043
7342
  PxMaskedByEffectSchema,
7044
7343
  PxNodeBase,
7045
7344
  PxNodeSchema,
7345
+ PxOutAction,
7346
+ PxPathOverflow,
7347
+ PxPinAlign,
7348
+ PxPlaybackDirection,
7046
7349
  PxPropertyAnimationSchema,
7047
7350
  PxRepeaterEffectSchema,
7048
7351
  PxRetimeEffectSchema,
7352
+ PxScrollAxis,
7353
+ PxScrollKind,
7354
+ PxScrollPhase,
7049
7355
  PxScrollRangePointSchema,
7050
7356
  PxScrollRangeSchema,
7051
7357
  PxScrollSchema,
7052
- PxStrokeGradientEffectSchema,
7358
+ PxScrollSource,
7359
+ PxStartOn,
7053
7360
  PxStrokeTrimEffectSchema,
7054
7361
  PxStrokeTrimSubPaths,
7055
7362
  PxSvgNodeExtra,
7056
7363
  PxTextEffectSchema,
7057
7364
  PxTextPathEffectSchema,
7365
+ PxTextPathMethod,
7366
+ PxTextPathSpacing,
7058
7367
  PxTimelineEngine,
7059
7368
  PxTimelineEngineExtra,
7060
- PxTimelinePinSchema,
7061
7369
  PxTimelineSchema,
7062
7370
  PxTransformByEffectSchema,
7063
7371
  PxTransformPartsSchema,
7064
7372
  PxTransformValueSchema,
7065
7373
  PxTriggerSchema,
7374
+ PxUnits,
7066
7375
  STYLE_ATTR_NAMES,
7067
- TEXT_ATTR,
7068
7376
  TEXT_CONTENT_ATTR,
7069
7377
  TRANSFORM_FN_NAMES,
7070
7378
  WIRE_VERSION_KEY,
@@ -7073,17 +7381,19 @@ function reportDocumentDiagnostics(doc, where) {
7073
7381
  applyAnimatorConfig,
7074
7382
  applyPlayerEffects,
7075
7383
  applyWireSteps,
7076
- applyWireStepsDown,
7077
7384
  bezierToSvgPath,
7078
7385
  calcAnimationValues,
7079
7386
  camelCaseToKebabWordIfNeeded,
7080
7387
  clamp,
7081
- collectSampleTimes,
7388
+ clampSeekMs,
7082
7389
  compareWireVersion,
7083
7390
  composeTransformParts,
7391
+ controlModeTakesOverTrigger,
7084
7392
  convertPlayerDocument,
7085
7393
  createBasicFrameLoopAnimator,
7394
+ createDiagnostics,
7086
7395
  createPathSampler,
7396
+ createRunClock,
7087
7397
  cubicBezier,
7088
7398
  deepClone,
7089
7399
  describeSchema,
@@ -7091,10 +7401,9 @@ function reportDocumentDiagnostics(doc, where) {
7091
7401
  diffFieldUniverse,
7092
7402
  diffInEffect,
7093
7403
  downgradePlayerDocument,
7094
- evaluateMotionPathSegment,
7095
7404
  extendedPathForBrowser,
7096
7405
  flattenAnimatorTimeline,
7097
- foldAnimatorConfigShortcuts,
7406
+ foldTimelineOverride,
7098
7407
  formatWireVersion,
7099
7408
  generateNewIds,
7100
7409
  generateUniqueId,
@@ -7102,47 +7411,39 @@ function reportDocumentDiagnostics(doc, where) {
7102
7411
  getBindings,
7103
7412
  getChildren,
7104
7413
  getDefs,
7105
- getNormalisedBindings,
7414
+ getNormalizedBindings,
7106
7415
  getNormalizedProps,
7107
- interpolateBeziers,
7108
7416
  interpolateValue,
7109
7417
  isNativeForced,
7110
7418
  isPxElementFileFormat,
7111
7419
  isPxElementFileFormatDeep,
7112
7420
  isScrollTimeline,
7113
- jsonElementFactory,
7421
+ isValidPlaybackRate,
7114
7422
  kebabToCamelCaseWord,
7115
7423
  kfEasing,
7116
- kfTangentIn,
7117
- kfTangentOut,
7118
- kfTime,
7119
7424
  kfValue,
7120
7425
  layoutGlyphTextChars,
7121
- materialiseAllInTree,
7122
- materialiseAnimatedUseInstances,
7123
- materialiseGlyphText,
7124
- materialiseGlyphTextAlongPath,
7125
- materialiseGlyphTextHorizontal,
7126
- materialiseInternalLoopsInPropAnim,
7127
- materialiseInternalLoopsInTree,
7128
- materialiseMotionPathInPropAnim,
7129
- materialiseMotionPathsInTree,
7426
+ materializeAllInTree,
7427
+ materializeGlyphText,
7428
+ materializeGlyphTextAlongPath,
7429
+ materializeMotionPathInPropAnim,
7130
7430
  mayUseNativeScrollTimeline,
7131
7431
  mergeAnimatorConfig,
7132
7432
  mergeStaticTransformIntoAnimDef,
7133
7433
  nestAnimatorTimeline,
7134
- parseTransformParts,
7135
7434
  parseWireVersion,
7136
7435
  planSchemaRelease,
7137
- propAnimIsMotionPath,
7436
+ progressSpanMs,
7437
+ progressToTimeMs,
7138
7438
  px,
7139
7439
  readWireVersion,
7140
7440
  releaseLogProblems,
7141
7441
  reportDocumentDiagnostics,
7142
- resolveStyle,
7442
+ resolveControlMode,
7143
7443
  resolveTimelineEngine,
7444
+ resolveTrigger,
7144
7445
  reverseEasing,
7145
- sanitiseAttributeValue,
7446
+ sanitizeAttributeValue,
7146
7447
  schemaFieldUniverse,
7147
7448
  schemaKeys,
7148
7449
  scrollOffsetProgress,
@@ -7150,13 +7451,13 @@ function reportDocumentDiagnostics(doc, where) {
7150
7451
  scrollResolveAxis,
7151
7452
  scrollTotalDurationMs,
7152
7453
  scrollViewProgress,
7153
- shiftAnimatable,
7454
+ seekCeilingMs,
7154
7455
  splitEasing,
7155
7456
  subdivideCubicBezier,
7457
+ timeToProgress,
7156
7458
  toRGBA,
7157
7459
  validateDocument,
7158
7460
  validateNodeEffects,
7159
- versionAdvice,
7160
- visualModelAt
7461
+ versionAdvice
7161
7462
  });
7162
7463
  //# sourceMappingURL=index.cjs.map