@pixodesk/svg-animator-web 1.0.39 → 1.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,525 +55,102 @@ var PixodeskAnimator = (() => {
55
55
  setupAnimationTriggers: () => setupAnimationTriggers
56
56
  });
57
57
 
58
- // ../svg-animator-core/src/util/PxAnimatorUtil.ts
59
- function bezierToSvgPath(path, forceCurves = false) {
60
- var _a, _b, _c, _d;
61
- const v = path.v;
62
- const i = path.i;
63
- const o = path.o;
64
- const c = path.c;
65
- if (!v.length) return "";
66
- const d = [];
67
- const len = v.length;
68
- d.push("M" + v[0][0] + "," + v[0][1]);
69
- for (let idx = 1; idx < len; idx++) {
70
- const prevV = v[idx - 1];
71
- const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
72
- const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
73
- const currV = v[idx];
74
- const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
75
- if (isLine) {
76
- d.push("L" + currV[0] + "," + currV[1]);
77
- } else {
78
- d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
79
- }
80
- }
81
- if (c && len > 0) {
82
- const lastV = v[len - 1];
83
- const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
84
- const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
85
- const firstV = v[0];
86
- const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
87
- if (!isLine) {
88
- d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
89
- }
90
- d.push("z");
91
- }
92
- return d.join("");
93
- }
94
- function interpolateNum(a, b, t) {
95
- return a + (b - a) * t;
96
- }
97
- function interpolateVec(a, b, t) {
98
- const res = [];
99
- const count = Math.max(a.length, b.length);
100
- for (let i = 0; i < count; i++) {
101
- res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
58
+ // ../svg-animator-core/src/schema/PxSchema.ts
59
+ var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
60
+ function pathStr(path) {
61
+ if (!path.length) return ".";
62
+ let result = "";
63
+ for (const seg of path) {
64
+ if (seg.startsWith("[")) result += seg;
65
+ else result += (result ? "." : "") + seg;
102
66
  }
103
- return res;
104
- }
105
- function interpolateColor(a, b, t) {
106
- return [
107
- interpolateNum(a[0] || 0, b[0] || 0, t),
108
- interpolateNum(a[1] || 0, b[1] || 0, t),
109
- interpolateNum(a[2] || 0, b[2] || 0, t),
110
- interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
111
- ];
67
+ return result;
112
68
  }
113
- function interpolateBeziers(paths1, paths2, progress) {
114
- const count = Math.max(paths1.length, paths2.length);
115
- const res = [];
116
- for (let i = 0; i < count; i++) {
117
- res.push(interpolateBezier(paths1[i], paths2[i], progress));
69
+ var Base = class {
70
+ _canSanitize(raw) {
71
+ return this.isValid(raw);
118
72
  }
119
- return res;
120
- }
121
- function interpolateBezier(path1, path2, progress) {
122
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
123
- if (!path1 || !path2) return path1 || path2 || { v: [] };
124
- const t = Math.min(Math.max(progress, 0), 1);
125
- const len = Math.min(path1.v.length, path2.v.length);
126
- const v = [];
127
- const i = [];
128
- const o = [];
129
- for (let idx = 0; idx < len; idx++) {
130
- const v1 = path1.v[idx];
131
- const v2 = path2.v[idx];
132
- v.push(interpolateVec(v1, v2, t));
133
- const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
134
- const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
135
- i.push(interpolateVec(i1, i2, t));
136
- const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
137
- const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
138
- o.push(interpolateVec(o1, o2, t));
73
+ optional() {
74
+ return new Optional(this);
139
75
  }
140
- return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
141
- }
142
- function solveCubicBezierX(p1x, p2x, x) {
143
- if (x <= 0) return 0;
144
- if (x >= 1) return 1;
145
- const cx = 3 * p1x;
146
- const bx = 3 * (p2x - p1x) - cx;
147
- const ax = 1 - cx - bx;
148
- function sampleX(t) {
149
- return ((ax * t + bx) * t + cx) * t;
76
+ };
77
+ var Optional = class extends Base {
78
+ constructor(inner) {
79
+ super();
80
+ this.inner = inner;
81
+ this._default = void 0;
150
82
  }
151
- function sampleDX(t) {
152
- return (3 * ax * t + 2 * bx) * t + cx;
83
+ sanitize(raw) {
84
+ if (raw === void 0 || raw === null) return void 0;
85
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
153
86
  }
154
- let t2 = x;
155
- let t0 = 0;
156
- let t1 = 1;
157
- for (let i = 0; i < 8; i++) {
158
- const x2 = sampleX(t2) - x;
159
- if (Math.abs(x2) < 1e-6) return t2;
160
- const d2 = sampleDX(t2);
161
- if (Math.abs(d2) < 1e-6) break;
162
- t2 -= x2 / d2;
87
+ isValid(raw, ctx, path) {
88
+ if (raw === void 0 || raw === null) return true;
89
+ return this.inner.isValid(raw, ctx, path);
163
90
  }
164
- t2 = x;
165
- while (t0 < t1) {
166
- const x2 = sampleX(t2);
167
- if (Math.abs(x2 - x) < 1e-6) return t2;
168
- if (x > x2) t0 = t2;
169
- else t1 = t2;
170
- t2 = (t1 + t0) / 2;
91
+ _canSanitize(raw) {
92
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
171
93
  }
172
- return t2;
173
- }
174
- function cubicBezier(easing) {
175
- const [p1x, p1y, p2x, p2y] = easing;
176
- const cy = 3 * p1y;
177
- const by = 3 * (p2y - p1y) - cy;
178
- const ay = 1 - cy - by;
179
- function sampleCurveY(t) {
180
- return ((ay * t + by) * t + cy) * t;
94
+ };
95
+ var Str = class extends Base {
96
+ constructor(_default = "") {
97
+ super();
98
+ this._default = _default;
181
99
  }
182
- return function(x) {
183
- return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
184
- };
185
- }
186
- function lerp2(a, b, t) {
187
- return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
188
- }
189
- function subdivideCubicBezier(p0, p1, p2, p3, t) {
190
- const q0 = lerp2(p0, p1, t);
191
- const q1 = lerp2(p1, p2, t);
192
- const q2 = lerp2(p2, p3, t);
193
- const r0 = lerp2(q0, q1, t);
194
- const r1 = lerp2(q1, q2, t);
195
- const s = lerp2(r0, r1, t);
196
- return {
197
- left: [p0, q0, r0, s],
198
- right: [s, r1, q2, p3]
199
- };
200
- }
201
- function splitEasing(easing, xFraction) {
202
- if (!easing) return { left: void 0, right: void 0 };
203
- if (xFraction <= 0) return { left: void 0, right: easing };
204
- if (xFraction >= 1) return { left: easing, right: void 0 };
205
- const [x1, y1, x2, y2] = easing;
206
- const t = solveCubicBezierX(x1, x2, xFraction);
207
- const p0 = [0, 0];
208
- const p1 = [x1, y1];
209
- const p2 = [x2, y2];
210
- const p3 = [1, 1];
211
- const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
212
- const sx = left[3][0];
213
- const sy = left[3][1];
214
- let leftEasing;
215
- if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
216
- leftEasing = [
217
- left[1][0] / sx,
218
- left[1][1] / sy,
219
- left[2][0] / sx,
220
- left[2][1] / sy
221
- ];
100
+ sanitize(raw) {
101
+ return typeof raw === "string" ? raw : this._default;
222
102
  }
223
- let rightEasing;
224
- const rx = 1 - sx;
225
- const ry = 1 - sy;
226
- if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
227
- rightEasing = [
228
- (right[1][0] - sx) / rx,
229
- (right[1][1] - sy) / ry,
230
- (right[2][0] - sx) / rx,
231
- (right[2][1] - sy) / ry
232
- ];
103
+ isValid(raw, ctx, path) {
104
+ if (typeof raw === "string") return true;
105
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
106
+ return false;
233
107
  }
234
- return { left: leftEasing, right: rightEasing };
235
- }
236
- function reverseEasing(easing) {
237
- if (!easing) return void 0;
238
- return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
239
- }
240
- function toRGBA(color) {
241
- const r = Math.round(color[0] * 255);
242
- const g = Math.round(color[1] * 255);
243
- const b = Math.round(color[2] * 255);
244
- return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
245
- }
246
- function parseRgba(s) {
247
- var _a;
248
- const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
249
- if (!inner) throw new Error("Invalid rgb/rgba format");
250
- const parts = inner.split(",").map((v) => +v.trim());
251
- return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
252
- }
253
- function parseHex(s) {
254
- const hex = s.slice(1);
255
- const isShort = hex.length <= 4;
256
- const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
257
- const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
258
- const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
259
- const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
260
- const result = [
261
- parseInt(r, 16) / 255,
262
- parseInt(g, 16) / 255,
263
- parseInt(b, 16) / 255
264
- ];
265
- if (a !== null) {
266
- result.push(parseInt(a, 16) / 255);
108
+ };
109
+ var Num = class extends Base {
110
+ constructor(_default = 0) {
111
+ super();
112
+ this._default = _default;
267
113
  }
268
- return result;
269
- }
270
- function parseColor(s) {
271
- if (!s) return void 0;
272
- if (Array.isArray(s)) return s;
273
- if (typeof s !== "string") return void 0;
274
- if (s.startsWith("#")) {
275
- return parseHex(s);
276
- } else if (s.startsWith("rgb")) {
277
- return parseRgba(s);
278
- } else {
279
- console.warn("Unsupported color format: " + s);
114
+ sanitize(raw) {
115
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
280
116
  }
281
- return void 0;
282
- }
283
- var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
284
- var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
285
- var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
286
- function composeTransformParts(parts, opts) {
287
- var _a;
288
- if (!parts) return "";
289
- const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
290
- const segs = [];
291
- const t = parts.translate;
292
- const o = parts.origin;
293
- const r = parts.rotate;
294
- const k = parts.skew;
295
- const s = parts.scale;
296
- const tu = withUnits ? "px" : "";
297
- const ru = withUnits ? "deg" : "";
298
- if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
299
- if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
300
- if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
301
- if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
302
- if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
303
- if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
304
- return segs.join("");
305
- }
306
- function parseTransformParts(str) {
307
- var _a, _b;
308
- if (!str || typeof str !== "string") return void 0;
309
- const out = {};
310
- const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
311
- const order = ["translate", "rotate", "skewX", "scale"];
312
- let lastIdx = -1;
313
- let m;
314
- while ((m = re.exec(str)) !== null) {
315
- const fn = m[1];
316
- const idx = order.indexOf(fn);
317
- if (idx < 0 || idx <= lastIdx) return void 0;
318
- lastIdx = idx;
319
- const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
320
- if (nums.some((n) => Number.isNaN(n))) return void 0;
321
- if (fn === "translate") {
322
- if (nums.length < 1 || nums.length > 2) return void 0;
323
- out.translate = [nums[0], (_a = nums[1]) != null ? _a : 0];
324
- } else if (fn === "rotate") {
325
- if (nums.length !== 1) return void 0;
326
- out.rotate = nums[0];
327
- } else if (fn === "skewX") {
328
- if (nums.length !== 1) return void 0;
329
- out.skew = nums[0];
330
- } else {
331
- if (nums.length < 1 || nums.length > 2) return void 0;
332
- out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
333
- }
334
- }
335
- if (str.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
336
- return Object.keys(out).length ? out : void 0;
337
- }
338
- function kebabToCamelCaseWord(kebab) {
339
- return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
340
- }
341
- function isCamelCaseWord(word) {
342
- return !word.includes("-") && /[a-z][A-Z]/.test(word);
343
- }
344
- var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
345
- // Transform/positioning
346
- "viewBox",
347
- "preserveAspectRatio",
348
- // Gradient
349
- "gradientUnits",
350
- "gradientTransform",
351
- "spreadMethod",
352
- // Pattern
353
- "patternUnits",
354
- "patternContentUnits",
355
- "patternTransform",
356
- // Clipping/masking
357
- "clipPathUnits",
358
- "maskUnits",
359
- "maskContentUnits",
360
- // Marker (SVG spec keeps these camelCase, like viewBox)
361
- "markerUnits",
362
- "markerWidth",
363
- "markerHeight",
364
- "refX",
365
- "refY",
366
- // Text
367
- "textLength",
368
- "lengthAdjust",
369
- "startOffset",
370
- // Filter
371
- "filterUnits",
372
- "primitiveUnits",
373
- "tableValues",
374
- // feFuncR/G/B/A transfer table (type="table")
375
- "stdDeviation",
376
- "baseFrequency",
377
- "numOctaves",
378
- "surfaceScale",
379
- "diffuseConstant",
380
- "specularConstant",
381
- "specularExponent",
382
- "kernelMatrix",
383
- "kernelUnitLength",
384
- "edgeMode",
385
- "preserveAlpha",
386
- "targetX",
387
- "targetY"
388
- // // Animation
389
- // 'attributeName',
390
- // 'attributeType',
391
- // 'calcMode',
392
- // 'keyTimes',
393
- // 'keySplines',
394
- // 'repeatCount',
395
- // 'repeatDur'
396
- ]);
397
- function camelCaseToKebabWordIfNeeded(camel) {
398
- return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
399
- }
400
- function clamp(value, min, max) {
401
- return Math.max(min, Math.min(value, max));
402
- }
403
- function bezier2D_pointAt(P0, P1, P2, P3, t) {
404
- if (t <= 0) return [P0[0], P0[1]];
405
- if (t >= 1) return [P3[0], P3[1]];
406
- const u = 1 - t;
407
- const u2 = u * u;
408
- const u3 = u2 * u;
409
- const t2 = t * t;
410
- const t3 = t2 * t;
411
- const w0 = u3;
412
- const w1 = 3 * t * u2;
413
- const w2 = 3 * t2 * u;
414
- const w3 = t3;
415
- return [
416
- w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
417
- w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
418
- ];
419
- }
420
- var BEZIER_T_NUDGE = 1e-4;
421
- function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
422
- const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
423
- if (result[0] === 0 && result[1] === 0) {
424
- const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
425
- return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
426
- }
427
- return result;
428
- }
429
- function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
430
- const u = 1 - t;
431
- const a = 3 * u * u;
432
- const b = 6 * t * u;
433
- const c = 3 * t * t;
434
- return [
435
- a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
436
- a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
437
- ];
438
- }
439
- function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
440
- const n = steps + 1;
441
- const ts = new Float64Array(n);
442
- const ds = new Float64Array(n);
443
- let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
444
- ts[0] = 0;
445
- ds[0] = 0;
446
- let cum = 0;
447
- for (let i = 1; i < n; i++) {
448
- const t = i / steps;
449
- const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
450
- const dx = cur[0] - prev[0];
451
- const dy = cur[1] - prev[1];
452
- cum += Math.sqrt(dx * dx + dy * dy);
453
- ts[i] = t;
454
- ds[i] = cum;
455
- prev = cur;
456
- }
457
- return { ts, ds };
458
- }
459
- function bezier2D_arcAtT(lut, t) {
460
- const { ts, ds } = lut;
461
- const last = ts.length - 1;
462
- if (t <= ts[0]) return ds[0];
463
- if (t >= ts[last]) return ds[last];
464
- let lo = 1, hi = last;
465
- while (lo < hi) {
466
- const mid = lo + hi >>> 1;
467
- if (ts[mid] < t) lo = mid + 1;
468
- else hi = mid;
469
- }
470
- const tPrev = ts[hi - 1];
471
- const span = ts[hi] - tPrev;
472
- const frac = span > 0 ? (t - tPrev) / span : 0;
473
- return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
474
- }
475
- function invertEasing(easing) {
476
- if (!easing) return (y) => y;
477
- const flipped = [easing[1], easing[0], easing[3], easing[2]];
478
- return cubicBezier(flipped);
479
- }
480
-
481
- // ../svg-animator-core/src/schema/PxSchema.ts
482
- var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
483
- function pathStr(path) {
484
- if (!path.length) return ".";
485
- let result = "";
486
- for (const seg of path) {
487
- if (seg.startsWith("[")) result += seg;
488
- else result += (result ? "." : "") + seg;
489
- }
490
- return result;
491
- }
492
- var Base = class {
493
- _canSanitize(raw) {
494
- return this.isValid(raw);
495
- }
496
- optional() {
497
- return new Optional(this);
117
+ isValid(raw, ctx, path) {
118
+ if (typeof raw === "number" && isFinite(raw)) return true;
119
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
120
+ return false;
498
121
  }
499
122
  };
500
- var Optional = class extends Base {
501
- constructor(inner) {
123
+ var Bool = class extends Base {
124
+ constructor(_default = false) {
502
125
  super();
503
- this.inner = inner;
504
- this._default = void 0;
126
+ this._default = _default;
505
127
  }
506
128
  sanitize(raw) {
507
- if (raw === void 0 || raw === null) return void 0;
508
- return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
129
+ return typeof raw === "boolean" ? raw : this._default;
509
130
  }
510
131
  isValid(raw, ctx, path) {
511
- if (raw === void 0 || raw === null) return true;
512
- return this.inner.isValid(raw, ctx, path);
513
- }
514
- _canSanitize(raw) {
515
- return raw === void 0 || raw === null || this.inner._canSanitize(raw);
132
+ if (typeof raw === "boolean") return true;
133
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
134
+ return false;
516
135
  }
517
136
  };
518
- var Str = class extends Base {
519
- constructor(_default = "") {
137
+ var Literal = class extends Base {
138
+ constructor(value) {
520
139
  super();
521
- this._default = _default;
140
+ this.value = value;
141
+ this._default = value;
522
142
  }
523
143
  sanitize(raw) {
524
- return typeof raw === "string" ? raw : this._default;
144
+ return raw === this.value ? this.value : this._default;
525
145
  }
526
146
  isValid(raw, ctx, path) {
527
- if (typeof raw === "string") return true;
528
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
147
+ if (raw === this.value) return true;
148
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
529
149
  return false;
530
150
  }
531
151
  };
532
- var Num = class extends Base {
533
- constructor(_default = 0) {
534
- super();
535
- this._default = _default;
536
- }
537
- sanitize(raw) {
538
- return typeof raw === "number" && isFinite(raw) ? raw : this._default;
539
- }
540
- isValid(raw, ctx, path) {
541
- if (typeof raw === "number" && isFinite(raw)) return true;
542
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
543
- return false;
544
- }
545
- };
546
- var Bool = class extends Base {
547
- constructor(_default = false) {
548
- super();
549
- this._default = _default;
550
- }
551
- sanitize(raw) {
552
- return typeof raw === "boolean" ? raw : this._default;
553
- }
554
- isValid(raw, ctx, path) {
555
- if (typeof raw === "boolean") return true;
556
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
557
- return false;
558
- }
559
- };
560
- var Literal = class extends Base {
561
- constructor(value) {
562
- super();
563
- this.value = value;
564
- this._default = value;
565
- }
566
- sanitize(raw) {
567
- return raw === this.value ? this.value : this._default;
568
- }
569
- isValid(raw, ctx, path) {
570
- if (raw === this.value) return true;
571
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
572
- return false;
573
- }
574
- };
575
- var Enum = class extends Base {
576
- constructor(values, defaultVal) {
152
+ var Enum = class extends Base {
153
+ constructor(values, defaultVal) {
577
154
  super();
578
155
  this.values = values;
579
156
  this._default = defaultVal != null ? defaultVal : values[0];
@@ -1211,9 +788,7 @@ var PixodeskAnimator = (() => {
1211
788
  function getBindings(doc) {
1212
789
  var _a;
1213
790
  if (!doc) return void 0;
1214
- const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
1215
- if (!animateById) return void 0;
1216
- return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
791
+ return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.bindings;
1217
792
  }
1218
793
 
1219
794
  // ../svg-animator-core/src/format/PxAnimatorTypes.ts
@@ -1318,9 +893,6 @@ var PixodeskAnimator = (() => {
1318
893
  var PxDefsSchema = implementsInterface()(px.object({
1319
894
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1320
895
  animations: px.record(PxAnimationDefinitionSchema).optional(),
1321
- // Review §2.6: the schema now matches the declared type — a style preset is a flat
1322
- // record of string|number attribute values, nothing nested.
1323
- styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1324
896
  fonts: px.record(PxGlyphFontSchema).optional()
1325
897
  }));
1326
898
  var PxScrollRangePointSchema = implementsInterface()(px.object({
@@ -1401,22 +973,22 @@ var PixodeskAnimator = (() => {
1401
973
  PxScrollTimelineSchema,
1402
974
  PxViewTimelineSchema
1403
975
  ]);
976
+ var PxBindingSchema = implementsInterface()(px.object({
977
+ target: px.string(),
978
+ animateWith: px.array(px.string())
979
+ }));
1404
980
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
1405
981
  // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1406
982
  // at this level only on the runtime view, like the rest of the playback dynamics.)
1407
983
  // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1408
984
  timeline: PxTimelineSchema.optional(),
1409
985
  definitions: PxDefsSchema.optional(),
1410
- animateById: px.record(PxElementAnimationSchema).optional(),
986
+ bindings: px.array(PxBindingSchema).optional(),
1411
987
  debugGlobalName: px.string().optional(),
1412
988
  // Declared HERE because this is a closed object: an undeclared key would be stripped by
1413
989
  // `sanitize` and flagged by strict validation on our own files.
1414
990
  version: px.string().optional()
1415
991
  }));
1416
- var PxBindingSchema = implementsInterface()(px.object({
1417
- id: px.string(),
1418
- animate: PxElementAnimationSchema
1419
- }));
1420
992
  var PxAttrValueSchema = px.union([
1421
993
  px.string(),
1422
994
  px.number(),
@@ -1498,98 +1070,521 @@ var PixodeskAnimator = (() => {
1498
1070
  px.object({ value: px.array(PxGradientStopSchema) }),
1499
1071
  PxPropertyAnimationSchema
1500
1072
  ]);
1501
- var PxFillGradientEffectSchema = implementsInterface()(px.object({
1502
- // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1503
- type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1504
- start: PxAnimatableVec2Schema.optional(),
1505
- end: PxAnimatableVec2Schema.optional(),
1506
- center: PxAnimatableVec2Schema.optional(),
1507
- radius: PxAnimatableNumberSchema.optional(),
1508
- focal: PxAnimatableVec2Schema.optional(),
1509
- stops: PxAnimatableGradientStopsSchema.optional(),
1510
- gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1511
- spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1512
- gradientTransform: px.string().optional()
1513
- }));
1514
- var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1515
- var PxTextPathEffectSchema = implementsInterface()(px.object({
1516
- pathData: px.string(),
1517
- pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1518
- lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1519
- method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
1520
- spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
1521
- startOffset: PxAnimatableNumberSchema.optional(),
1522
- textLength: PxAnimatableNumberSchema.optional()
1523
- }));
1524
- var PxTextEffectSchema = implementsInterface()(px.object({
1525
- useGlyphs: px.boolean().optional()
1526
- }));
1527
- var PxEffectsSchema = implementsInterface()(px.object({
1528
- transformBy: PxTransformByEffectSchema.optional(),
1529
- repeater: PxRepeaterEffectSchema.optional(),
1530
- maskedBy: PxMaskedByEffectSchema.optional(),
1531
- clipPath: PxClipPathEffectSchema.optional(),
1532
- strokeTrim: PxStrokeTrimEffectSchema.optional(),
1533
- clone: PxCloneEffectSchema.optional(),
1534
- fillGradient: PxFillGradientEffectSchema.optional(),
1535
- strokeGradient: PxStrokeGradientEffectSchema.optional(),
1536
- textPath: PxTextPathEffectSchema.optional(),
1537
- text: PxTextEffectSchema.optional()
1538
- }));
1539
- var PxNodeBase = px.openObject({
1540
- // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1541
- // kind of thing is this", discriminated by its CARRIER — here the node TAG
1542
- // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1543
- // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1544
- // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1545
- // would add words that all mean "type" and still need the carrier to read.
1546
- // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1547
- // (issues V3), never of distinct key names.
1548
- type: px.string(),
1549
- // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
1550
- // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
1551
- // `type` is taken by the tag name, so the attribute travels here and the renderer puts
1552
- // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
1553
- // documented — because a wire key that is not in a schema is invisible to the
1554
- // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1555
- domType: px.string().optional(),
1556
- // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
1557
- // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
1558
- textContent: px.string().optional(),
1559
- id: px.string().optional(),
1560
- meta: px.any().optional(),
1561
- // Player-effects bucket emitted by the Editor's lightweight design format.
1562
- // Consumed and removed by `applyPlayerEffects` before any other normalization
1563
- // (see `createAnimatorImpl`), so downstream code never sees it.
1564
- effects: PxEffectsSchema.optional(),
1565
- // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
1566
- // string ref / array of refs / inline definition / mixed array; mirrors
1567
- // `animator.animateById` map values and what `processNode` resolves at runtime.
1568
- animate: PxElementAnimationSchema.optional(),
1569
- style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
1570
- }, PxAttrValueSchema);
1571
- var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
1572
- children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1573
- }), PxAttrValueSchema);
1574
- var PxSvgNodeExtra = px.object({
1575
- // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
1576
- // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
1577
- width: px.union([px.number(), px.string()]).optional(),
1578
- height: px.union([px.number(), px.string()]).optional(),
1579
- viewBox: px.string().optional(),
1580
- animator: PxAnimatorConfigSchema.optional()
1581
- });
1582
- var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
1583
- type: px.literal("svg"),
1584
- // override string → literal to require 'svg'
1585
- children: px.array(PxNodeSchema).optional()
1586
- }), PxAttrValueSchema);
1587
- var PxBezierPathSchema = implementsInterface()(px.object({
1588
- v: px.array(px.array(px.number())),
1589
- i: px.array(px.array(px.number())).optional(),
1590
- o: px.array(px.array(px.number())).optional(),
1591
- c: px.boolean().optional()
1592
- }));
1073
+ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1074
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1075
+ type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1076
+ start: PxAnimatableVec2Schema.optional(),
1077
+ end: PxAnimatableVec2Schema.optional(),
1078
+ center: PxAnimatableVec2Schema.optional(),
1079
+ radius: PxAnimatableNumberSchema.optional(),
1080
+ focal: PxAnimatableVec2Schema.optional(),
1081
+ stops: PxAnimatableGradientStopsSchema.optional(),
1082
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1083
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1084
+ gradientTransform: px.string().optional()
1085
+ }));
1086
+ var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1087
+ var PxTextPathEffectSchema = implementsInterface()(px.object({
1088
+ pathData: px.string(),
1089
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1090
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1091
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
1092
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
1093
+ startOffset: PxAnimatableNumberSchema.optional(),
1094
+ textLength: PxAnimatableNumberSchema.optional()
1095
+ }));
1096
+ var PxTextEffectSchema = implementsInterface()(px.object({
1097
+ useGlyphs: px.boolean().optional()
1098
+ }));
1099
+ var PxEffectsSchema = implementsInterface()(px.object({
1100
+ transformBy: PxTransformByEffectSchema.optional(),
1101
+ repeater: PxRepeaterEffectSchema.optional(),
1102
+ maskedBy: PxMaskedByEffectSchema.optional(),
1103
+ clipPath: PxClipPathEffectSchema.optional(),
1104
+ strokeTrim: PxStrokeTrimEffectSchema.optional(),
1105
+ clone: PxCloneEffectSchema.optional(),
1106
+ fillGradient: PxFillGradientEffectSchema.optional(),
1107
+ strokeGradient: PxStrokeGradientEffectSchema.optional(),
1108
+ textPath: PxTextPathEffectSchema.optional(),
1109
+ text: PxTextEffectSchema.optional()
1110
+ }));
1111
+ var PxNodeBase = px.openObject({
1112
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1113
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
1114
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1115
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1116
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1117
+ // would add words that all mean "type" and still need the carrier to read.
1118
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1119
+ // (issues V3), never of distinct key names.
1120
+ type: px.string(),
1121
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
1122
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
1123
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
1124
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
1125
+ // documented — because a wire key that is not in a schema is invisible to the
1126
+ // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
1127
+ domType: px.string().optional(),
1128
+ // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
1129
+ // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
1130
+ textContent: px.string().optional(),
1131
+ id: px.string().optional(),
1132
+ meta: px.any().optional(),
1133
+ // Player-effects bucket emitted by the Editor's lightweight design format.
1134
+ // Consumed and removed by `applyPlayerEffects` before any other normalization
1135
+ // (see `createAnimatorImpl`), so downstream code never sees it.
1136
+ effects: PxEffectsSchema.optional(),
1137
+ // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
1138
+ // string ref / array of refs / inline definition / mixed array; mirrors
1139
+ // `node.animate` values and what `processNode` resolves at runtime.
1140
+ animate: PxElementAnimationSchema.optional(),
1141
+ style: px.record(px.union([px.string(), px.number()])).optional()
1142
+ }, PxAttrValueSchema);
1143
+ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
1144
+ children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1145
+ }), PxAttrValueSchema);
1146
+ var PxSvgNodeExtra = px.object({
1147
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
1148
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
1149
+ width: px.union([px.number(), px.string()]).optional(),
1150
+ height: px.union([px.number(), px.string()]).optional(),
1151
+ viewBox: px.string().optional(),
1152
+ animator: PxAnimatorConfigSchema.optional()
1153
+ });
1154
+ var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
1155
+ type: px.literal("svg"),
1156
+ // override string → literal to require 'svg'
1157
+ children: px.array(PxNodeSchema).optional()
1158
+ }), PxAttrValueSchema);
1159
+ var PxBezierPathSchema = implementsInterface()(px.object({
1160
+ v: px.array(px.array(px.number())),
1161
+ i: px.array(px.array(px.number())).optional(),
1162
+ o: px.array(px.array(px.number())).optional(),
1163
+ c: px.boolean().optional()
1164
+ }));
1165
+
1166
+ // ../svg-animator-core/src/util/PxAnimatorUtil.ts
1167
+ function bezierToSvgPath(path, forceCurves = false) {
1168
+ var _a, _b, _c, _d;
1169
+ const v = path.v;
1170
+ const i = path.i;
1171
+ const o = path.o;
1172
+ const c = path.c;
1173
+ if (!v.length) return "";
1174
+ const d = [];
1175
+ const len = v.length;
1176
+ d.push("M" + v[0][0] + "," + v[0][1]);
1177
+ for (let idx = 1; idx < len; idx++) {
1178
+ const prevV = v[idx - 1];
1179
+ const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
1180
+ const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
1181
+ const currV = v[idx];
1182
+ const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
1183
+ if (isLine) {
1184
+ d.push("L" + currV[0] + "," + currV[1]);
1185
+ } else {
1186
+ d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
1187
+ }
1188
+ }
1189
+ if (c && len > 0) {
1190
+ const lastV = v[len - 1];
1191
+ const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
1192
+ const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
1193
+ const firstV = v[0];
1194
+ const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
1195
+ if (!isLine) {
1196
+ d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
1197
+ }
1198
+ d.push("z");
1199
+ }
1200
+ return d.join("");
1201
+ }
1202
+ function interpolateNum(a, b, t) {
1203
+ return a + (b - a) * t;
1204
+ }
1205
+ function interpolateVec(a, b, t) {
1206
+ const res = [];
1207
+ const count = Math.max(a.length, b.length);
1208
+ for (let i = 0; i < count; i++) {
1209
+ res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
1210
+ }
1211
+ return res;
1212
+ }
1213
+ function interpolateColor(a, b, t) {
1214
+ return [
1215
+ interpolateNum(a[0] || 0, b[0] || 0, t),
1216
+ interpolateNum(a[1] || 0, b[1] || 0, t),
1217
+ interpolateNum(a[2] || 0, b[2] || 0, t),
1218
+ interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
1219
+ ];
1220
+ }
1221
+ function interpolateBeziers(paths1, paths2, progress) {
1222
+ const count = Math.max(paths1.length, paths2.length);
1223
+ const res = [];
1224
+ for (let i = 0; i < count; i++) {
1225
+ res.push(interpolateBezier(paths1[i], paths2[i], progress));
1226
+ }
1227
+ return res;
1228
+ }
1229
+ function interpolateBezier(path1, path2, progress) {
1230
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1231
+ if (!path1 || !path2) return path1 || path2 || { v: [] };
1232
+ const t = Math.min(Math.max(progress, 0), 1);
1233
+ const len = Math.min(path1.v.length, path2.v.length);
1234
+ const v = [];
1235
+ const i = [];
1236
+ const o = [];
1237
+ for (let idx = 0; idx < len; idx++) {
1238
+ const v1 = path1.v[idx];
1239
+ const v2 = path2.v[idx];
1240
+ v.push(interpolateVec(v1, v2, t));
1241
+ const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
1242
+ const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
1243
+ i.push(interpolateVec(i1, i2, t));
1244
+ const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
1245
+ const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
1246
+ o.push(interpolateVec(o1, o2, t));
1247
+ }
1248
+ return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
1249
+ }
1250
+ function solveCubicBezierX(p1x, p2x, x) {
1251
+ if (x <= 0) return 0;
1252
+ if (x >= 1) return 1;
1253
+ const cx = 3 * p1x;
1254
+ const bx = 3 * (p2x - p1x) - cx;
1255
+ const ax = 1 - cx - bx;
1256
+ function sampleX(t) {
1257
+ return ((ax * t + bx) * t + cx) * t;
1258
+ }
1259
+ function sampleDX(t) {
1260
+ return (3 * ax * t + 2 * bx) * t + cx;
1261
+ }
1262
+ let t2 = x;
1263
+ let t0 = 0;
1264
+ let t1 = 1;
1265
+ for (let i = 0; i < 8; i++) {
1266
+ const x2 = sampleX(t2) - x;
1267
+ if (Math.abs(x2) < 1e-6) return t2;
1268
+ const d2 = sampleDX(t2);
1269
+ if (Math.abs(d2) < 1e-6) break;
1270
+ t2 -= x2 / d2;
1271
+ }
1272
+ t2 = x;
1273
+ while (t0 < t1) {
1274
+ const x2 = sampleX(t2);
1275
+ if (Math.abs(x2 - x) < 1e-6) return t2;
1276
+ if (x > x2) t0 = t2;
1277
+ else t1 = t2;
1278
+ t2 = (t1 + t0) / 2;
1279
+ }
1280
+ return t2;
1281
+ }
1282
+ function cubicBezier(easing) {
1283
+ const [p1x, p1y, p2x, p2y] = easing;
1284
+ const cy = 3 * p1y;
1285
+ const by = 3 * (p2y - p1y) - cy;
1286
+ const ay = 1 - cy - by;
1287
+ function sampleCurveY(t) {
1288
+ return ((ay * t + by) * t + cy) * t;
1289
+ }
1290
+ return function(x) {
1291
+ return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
1292
+ };
1293
+ }
1294
+ function lerp2(a, b, t) {
1295
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
1296
+ }
1297
+ function subdivideCubicBezier(p0, p1, p2, p3, t) {
1298
+ const q0 = lerp2(p0, p1, t);
1299
+ const q1 = lerp2(p1, p2, t);
1300
+ const q2 = lerp2(p2, p3, t);
1301
+ const r0 = lerp2(q0, q1, t);
1302
+ const r1 = lerp2(q1, q2, t);
1303
+ const s = lerp2(r0, r1, t);
1304
+ return {
1305
+ left: [p0, q0, r0, s],
1306
+ right: [s, r1, q2, p3]
1307
+ };
1308
+ }
1309
+ function splitEasing(easing, xFraction) {
1310
+ if (!easing) return { left: void 0, right: void 0 };
1311
+ if (xFraction <= 0) return { left: void 0, right: easing };
1312
+ if (xFraction >= 1) return { left: easing, right: void 0 };
1313
+ const [x1, y1, x2, y2] = easing;
1314
+ const t = solveCubicBezierX(x1, x2, xFraction);
1315
+ const p0 = [0, 0];
1316
+ const p1 = [x1, y1];
1317
+ const p2 = [x2, y2];
1318
+ const p3 = [1, 1];
1319
+ const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
1320
+ const sx = left[3][0];
1321
+ const sy = left[3][1];
1322
+ let leftEasing;
1323
+ if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
1324
+ leftEasing = [
1325
+ left[1][0] / sx,
1326
+ left[1][1] / sy,
1327
+ left[2][0] / sx,
1328
+ left[2][1] / sy
1329
+ ];
1330
+ }
1331
+ let rightEasing;
1332
+ const rx = 1 - sx;
1333
+ const ry = 1 - sy;
1334
+ if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
1335
+ rightEasing = [
1336
+ (right[1][0] - sx) / rx,
1337
+ (right[1][1] - sy) / ry,
1338
+ (right[2][0] - sx) / rx,
1339
+ (right[2][1] - sy) / ry
1340
+ ];
1341
+ }
1342
+ return { left: leftEasing, right: rightEasing };
1343
+ }
1344
+ function reverseEasing(easing) {
1345
+ if (!easing) return void 0;
1346
+ return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
1347
+ }
1348
+ function toRGBA(color) {
1349
+ const r = Math.round(color[0] * 255);
1350
+ const g = Math.round(color[1] * 255);
1351
+ const b = Math.round(color[2] * 255);
1352
+ return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
1353
+ }
1354
+ function parseRgba(s) {
1355
+ var _a;
1356
+ const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
1357
+ if (!inner) throw new Error("Invalid rgb/rgba format");
1358
+ const parts = inner.split(",").map((v) => +v.trim());
1359
+ return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
1360
+ }
1361
+ function parseHex(s) {
1362
+ const hex = s.slice(1);
1363
+ const isShort = hex.length <= 4;
1364
+ const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
1365
+ const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
1366
+ const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
1367
+ const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
1368
+ const result = [
1369
+ parseInt(r, 16) / 255,
1370
+ parseInt(g, 16) / 255,
1371
+ parseInt(b, 16) / 255
1372
+ ];
1373
+ if (a !== null) {
1374
+ result.push(parseInt(a, 16) / 255);
1375
+ }
1376
+ return result;
1377
+ }
1378
+ function parseColor(s) {
1379
+ if (!s) return void 0;
1380
+ if (Array.isArray(s)) return s;
1381
+ if (typeof s !== "string") return void 0;
1382
+ if (s.startsWith("#")) {
1383
+ return parseHex(s);
1384
+ } else if (s.startsWith("rgb")) {
1385
+ return parseRgba(s);
1386
+ } else {
1387
+ console.warn("Unsupported color format: " + s);
1388
+ }
1389
+ return void 0;
1390
+ }
1391
+ var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
1392
+ var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
1393
+ var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1394
+ function composeTransformParts(parts, opts) {
1395
+ var _a;
1396
+ if (!parts) return "";
1397
+ const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
1398
+ const segs = [];
1399
+ const t = parts.translate;
1400
+ const o = parts.origin;
1401
+ const r = parts.rotate;
1402
+ const k = parts.skew;
1403
+ const s = parts.scale;
1404
+ const tu = withUnits ? "px" : "";
1405
+ const ru = withUnits ? "deg" : "";
1406
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
1407
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
1408
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
1409
+ if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
1410
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
1411
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
1412
+ return segs.join("");
1413
+ }
1414
+ function parseTransformParts(str) {
1415
+ var _a, _b;
1416
+ if (!str || typeof str !== "string") return void 0;
1417
+ const out = {};
1418
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
1419
+ const order = ["translate", "rotate", "skewX", "scale"];
1420
+ let lastIdx = -1;
1421
+ let m;
1422
+ while ((m = re.exec(str)) !== null) {
1423
+ const fn = m[1];
1424
+ const idx = order.indexOf(fn);
1425
+ if (idx < 0 || idx <= lastIdx) return void 0;
1426
+ lastIdx = idx;
1427
+ const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
1428
+ if (nums.some((n) => Number.isNaN(n))) return void 0;
1429
+ if (fn === "translate") {
1430
+ if (nums.length < 1 || nums.length > 2) return void 0;
1431
+ out.translate = [nums[0], (_a = nums[1]) != null ? _a : 0];
1432
+ } else if (fn === "rotate") {
1433
+ if (nums.length !== 1) return void 0;
1434
+ out.rotate = nums[0];
1435
+ } else if (fn === "skewX") {
1436
+ if (nums.length !== 1) return void 0;
1437
+ out.skew = nums[0];
1438
+ } else {
1439
+ if (nums.length < 1 || nums.length > 2) return void 0;
1440
+ out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
1441
+ }
1442
+ }
1443
+ if (str.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
1444
+ return Object.keys(out).length ? out : void 0;
1445
+ }
1446
+ function kebabToCamelCaseWord(kebab) {
1447
+ return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
1448
+ }
1449
+ function isCamelCaseWord(word) {
1450
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
1451
+ }
1452
+ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
1453
+ // Transform/positioning
1454
+ "viewBox",
1455
+ "preserveAspectRatio",
1456
+ // Gradient
1457
+ "gradientUnits",
1458
+ "gradientTransform",
1459
+ "spreadMethod",
1460
+ // Pattern
1461
+ "patternUnits",
1462
+ "patternContentUnits",
1463
+ "patternTransform",
1464
+ // Clipping/masking
1465
+ "clipPathUnits",
1466
+ "maskUnits",
1467
+ "maskContentUnits",
1468
+ // Marker (SVG spec keeps these camelCase, like viewBox)
1469
+ "markerUnits",
1470
+ "markerWidth",
1471
+ "markerHeight",
1472
+ "refX",
1473
+ "refY",
1474
+ // Text
1475
+ "textLength",
1476
+ "lengthAdjust",
1477
+ "startOffset",
1478
+ // Filter
1479
+ "filterUnits",
1480
+ "primitiveUnits",
1481
+ "tableValues",
1482
+ // feFuncR/G/B/A transfer table (type="table")
1483
+ "stdDeviation",
1484
+ "baseFrequency",
1485
+ "numOctaves",
1486
+ "surfaceScale",
1487
+ "diffuseConstant",
1488
+ "specularConstant",
1489
+ "specularExponent",
1490
+ "kernelMatrix",
1491
+ "kernelUnitLength",
1492
+ "edgeMode",
1493
+ "preserveAlpha",
1494
+ "targetX",
1495
+ "targetY"
1496
+ // // Animation
1497
+ // 'attributeName',
1498
+ // 'attributeType',
1499
+ // 'calcMode',
1500
+ // 'keyTimes',
1501
+ // 'keySplines',
1502
+ // 'repeatCount',
1503
+ // 'repeatDur'
1504
+ ]);
1505
+ function camelCaseToKebabWordIfNeeded(camel) {
1506
+ return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
1507
+ }
1508
+ function clamp(value, min, max) {
1509
+ return Math.max(min, Math.min(value, max));
1510
+ }
1511
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
1512
+ if (t <= 0) return [P0[0], P0[1]];
1513
+ if (t >= 1) return [P3[0], P3[1]];
1514
+ const u = 1 - t;
1515
+ const u2 = u * u;
1516
+ const u3 = u2 * u;
1517
+ const t2 = t * t;
1518
+ const t3 = t2 * t;
1519
+ const w0 = u3;
1520
+ const w1 = 3 * t * u2;
1521
+ const w2 = 3 * t2 * u;
1522
+ const w3 = t3;
1523
+ return [
1524
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
1525
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
1526
+ ];
1527
+ }
1528
+ var BEZIER_T_NUDGE = 1e-4;
1529
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
1530
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
1531
+ if (result[0] === 0 && result[1] === 0) {
1532
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
1533
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
1534
+ }
1535
+ return result;
1536
+ }
1537
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
1538
+ const u = 1 - t;
1539
+ const a = 3 * u * u;
1540
+ const b = 6 * t * u;
1541
+ const c = 3 * t * t;
1542
+ return [
1543
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
1544
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
1545
+ ];
1546
+ }
1547
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
1548
+ const n = steps + 1;
1549
+ const ts = new Float64Array(n);
1550
+ const ds = new Float64Array(n);
1551
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
1552
+ ts[0] = 0;
1553
+ ds[0] = 0;
1554
+ let cum = 0;
1555
+ for (let i = 1; i < n; i++) {
1556
+ const t = i / steps;
1557
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
1558
+ const dx = cur[0] - prev[0];
1559
+ const dy = cur[1] - prev[1];
1560
+ cum += Math.sqrt(dx * dx + dy * dy);
1561
+ ts[i] = t;
1562
+ ds[i] = cum;
1563
+ prev = cur;
1564
+ }
1565
+ return { ts, ds };
1566
+ }
1567
+ function bezier2D_arcAtT(lut, t) {
1568
+ const { ts, ds } = lut;
1569
+ const last = ts.length - 1;
1570
+ if (t <= ts[0]) return ds[0];
1571
+ if (t >= ts[last]) return ds[last];
1572
+ let lo = 1, hi = last;
1573
+ while (lo < hi) {
1574
+ const mid = lo + hi >>> 1;
1575
+ if (ts[mid] < t) lo = mid + 1;
1576
+ else hi = mid;
1577
+ }
1578
+ const tPrev = ts[hi - 1];
1579
+ const span = ts[hi] - tPrev;
1580
+ const frac = span > 0 ? (t - tPrev) / span : 0;
1581
+ return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
1582
+ }
1583
+ function invertEasing(easing) {
1584
+ if (!easing) return (y) => y;
1585
+ const flipped = [easing[1], easing[0], easing[3], easing[2]];
1586
+ return cubicBezier(flipped);
1587
+ }
1593
1588
 
1594
1589
  // ../svg-animator-core/src/materialize/PxMotionPath.ts
1595
1590
  function getKfTranslate(kf) {
@@ -2403,9 +2398,7 @@ var PixodeskAnimator = (() => {
2403
2398
  const defs = getDefs(doc);
2404
2399
  const duration = animatorConfig.duration || 1e3;
2405
2400
  const bindings = [];
2406
- const processAnimation = (id, animate, staticTransform) => {
2407
- if (!animate) return null;
2408
- const animDefs = resolveElementAnimation(animate, defs);
2401
+ const processAnimation = (id, animDefs, staticTransform) => {
2409
2402
  if (animDefs.length === 0) return null;
2410
2403
  const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);
2411
2404
  const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
@@ -2418,7 +2411,9 @@ var PixodeskAnimator = (() => {
2418
2411
  const docBindings = getBindings(doc);
2419
2412
  if (docBindings) {
2420
2413
  for (const binding of docBindings) {
2421
- const normalized = processAnimation(binding.id, binding.animate);
2414
+ const id = binding.target.startsWith("#") ? binding.target.slice(1) : binding.target;
2415
+ const animDefs = binding.animateWith.map((name) => resolveAnimation(name, defs)).filter((d) => !!d);
2416
+ const normalized = processAnimation(id, animDefs);
2422
2417
  if (normalized) bindings.push(normalized);
2423
2418
  }
2424
2419
  }
@@ -2427,7 +2422,7 @@ var PixodeskAnimator = (() => {
2427
2422
  if (inlineAnim && Object.keys(inlineAnim).length > 0) {
2428
2423
  const nodeId = node.id || generateElementId();
2429
2424
  node.id = nodeId;
2430
- const normalized = processAnimation(nodeId, inlineAnim, node.transform);
2425
+ const normalized = processAnimation(nodeId, resolveElementAnimation(inlineAnim, defs), node.transform);
2431
2426
  if (normalized) bindings.push(normalized);
2432
2427
  }
2433
2428
  if (node.children) {
@@ -2494,10 +2489,6 @@ var PixodeskAnimator = (() => {
2494
2489
  function asError(error) {
2495
2490
  return typeof error === "string" ? new Error(error) : error;
2496
2491
  }
2497
- function isSilenced(silent, kind) {
2498
- if (!silent) return false;
2499
- return silent === true || silent.includes(kind);
2500
- }
2501
2492
  function createDiagnostics(config, prefix) {
2502
2493
  const tag = prefix ? prefix + " " : "";
2503
2494
  return {
@@ -2506,26 +2497,28 @@ var PixodeskAnimator = (() => {
2506
2497
  config.onWarn({ kind, message, detail });
2507
2498
  return;
2508
2499
  }
2509
- if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
2500
+ if (config == null ? void 0 : config.muteWarn) return;
2510
2501
  const line = tag + kind + ": " + message;
2511
2502
  if (detail === void 0) console.warn(line);
2512
2503
  else console.warn(line, detail);
2513
2504
  },
2514
- error: (kind, error) => {
2505
+ error: (kind, error, detail) => {
2515
2506
  const err = asError(error);
2516
2507
  if (config == null ? void 0 : config.onError) {
2517
- config.onError({ kind, message: err.message, error: err });
2508
+ config.onError({ kind, message: err.message, error: err, detail });
2518
2509
  return;
2519
2510
  }
2520
- if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
2521
- console.error(tag + kind + ": " + err.message);
2511
+ if (config == null ? void 0 : config.muteError) return;
2512
+ const line = tag + kind + ": " + err.message;
2513
+ if (detail === void 0) console.error(line);
2514
+ else console.error(line, detail);
2522
2515
  }
2523
2516
  };
2524
2517
  }
2525
2518
 
2526
2519
  // src/shared/PxAnimatorCallbacks.ts
2527
2520
  function toEngineCallbacks(inline) {
2528
- const { onPlay, onPause, onCancel, onFinish, onRemove, onStop, onWarn, onError, silent } = inline != null ? inline : {};
2521
+ const { onPlay, onPause, onCancel, onFinish, onRemove, onStop, onWarn, onError, muteWarn, muteError } = inline != null ? inline : {};
2529
2522
  const withStop = (own) => own || onStop ? () => {
2530
2523
  own == null ? void 0 : own();
2531
2524
  onStop == null ? void 0 : onStop();
@@ -2538,9 +2531,38 @@ var PixodeskAnimator = (() => {
2538
2531
  onRemove: withStop(onRemove),
2539
2532
  onWarn,
2540
2533
  onError,
2541
- silent
2534
+ muteWarn,
2535
+ muteError
2536
+ };
2537
+ }
2538
+ function createInertAnimator() {
2539
+ return {
2540
+ isReady: () => false,
2541
+ getRootElement: () => null,
2542
+ isPlaying: () => false,
2543
+ play: () => {
2544
+ },
2545
+ pause: () => {
2546
+ },
2547
+ cancel: () => {
2548
+ },
2549
+ finish: () => {
2550
+ },
2551
+ setPlaybackRate: () => {
2552
+ },
2553
+ getCurrentTime: () => null,
2554
+ setCurrentTime: () => {
2555
+ },
2556
+ getCurrentProgress: () => null,
2557
+ setCurrentProgress: () => {
2558
+ },
2559
+ destroy: () => {
2560
+ }
2542
2561
  };
2543
2562
  }
2563
+ function asThrownError(e) {
2564
+ return e instanceof Error ? e : new Error(String(e));
2565
+ }
2544
2566
 
2545
2567
  // src/triggers/PxAnimatorTriggers.ts
2546
2568
  function setupAnimationTriggers(api, config, diag) {
@@ -2974,14 +2996,25 @@ var PixodeskAnimator = (() => {
2974
2996
  if (!(options == null ? void 0 : options.doc)) throw new Error("createAnimator: `doc` is required");
2975
2997
  return options.doc;
2976
2998
  }
2999
+ function buildOrReport(options, build) {
3000
+ try {
3001
+ return build();
3002
+ } catch (e) {
3003
+ const err = asThrownError(e);
3004
+ createDiagnostics(options, "[PxAnimator]").error(PxDiagnosticKind.internal, "createAnimator: could not build the player \u2014 " + err.message, err);
3005
+ return createInertAnimator();
3006
+ }
3007
+ }
2977
3008
  function createPrerenderedWaapiAnimator(options) {
2978
3009
  const doc = requireDoc(options);
2979
- const animatorConfig = getAnimatorConfig(doc) || {};
2980
- return finaliseAnimator(
2981
- animatorConfig,
2982
- toEngineCallbacks(options),
2983
- (cb) => createWebApiAnimator(doc, cb, null, true)
2984
- );
3010
+ return buildOrReport(options, () => {
3011
+ const animatorConfig = getAnimatorConfig(doc) || {};
3012
+ return finaliseAnimator(
3013
+ animatorConfig,
3014
+ toEngineCallbacks(options),
3015
+ (cb) => createWebApiAnimator(doc, cb, null, true)
3016
+ );
3017
+ });
2985
3018
  }
2986
3019
 
2987
3020
  // src/shared/PxAnimatorKeys.ts