@pixodesk/svg-animator-web 1.0.10 → 1.0.15

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.js CHANGED
@@ -4,6 +4,7 @@ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
6
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __pow = Math.pow;
7
8
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
9
  var __spreadValues = (a, b) => {
9
10
  for (var prop in b || (b = {}))
@@ -30,281 +31,1283 @@ var __objRest = (source, exclude) => {
30
31
  return target;
31
32
  };
32
33
 
33
- // src/PxAnimatorTypes.ts
34
- var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
35
- var PX_ANIM_ATTR_NAME = "_px_animator";
36
- var ANIMATE_ATTR = "animate";
37
- var TEXT_ATTR = "text";
38
- var TEXT_CONTENT_ATTR = "textContent";
39
- var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
40
- "type",
41
- "children",
42
- ANIMATE_ATTR,
43
- "animator",
44
- "meta",
45
- "defs",
46
- "bindings",
47
- TEXT_ATTR,
48
- TEXT_CONTENT_ATTR
49
- ]);
50
- function isPxElementFileFormat(fileJson) {
51
- if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
52
- return false;
34
+ // src/effects/transformParts.ts
35
+ function partsRecord(part, value, origin) {
36
+ const rec = {};
37
+ if (part === "translate") rec.translate = value;
38
+ else if (part === "rotate") rec.rotate = value;
39
+ else rec.scale = value;
40
+ if (origin && part !== "translate") rec.origin = origin;
41
+ return rec;
42
+ }
43
+ function readAnimatable(raw) {
44
+ if (raw === void 0) return { kind: "absent" };
45
+ if (Array.isArray(raw)) return { kind: "static", value: raw };
46
+ if (typeof raw === "object") {
47
+ const obj = raw;
48
+ if (obj.keyframes) {
49
+ return { kind: "animated", keyframes: obj.keyframes, autoOrient: obj.autoOrient };
50
+ }
51
+ if (obj.value !== void 0) return { kind: "static", value: obj.value };
52
+ }
53
+ return { kind: "static", value: raw };
54
+ }
55
+ function readStaticOrigin(raw, ctx) {
56
+ var _a;
57
+ const o = readAnimatable(raw);
58
+ if (o.kind === "absent") return void 0;
59
+ if (o.kind === "static") return o.value;
60
+ ctx.warnings.push("transformation.origin: animated origin approximated by its first keyframe");
61
+ return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
62
+ }
63
+ function keyframeWith(kf, value) {
64
+ const out = { value };
65
+ if (kf.time !== void 0) out.time = kf.time;
66
+ if (kf.easing !== void 0) out.easing = kf.easing;
67
+ if (kf.tangentOut !== void 0) out.tangentOut = kf.tangentOut;
68
+ if (kf.tangentIn !== void 0) out.tangentIn = kf.tangentIn;
69
+ return out;
70
+ }
71
+
72
+ // src/effects/transformationEffect.ts
73
+ function applyTransformationEffect(node, fx, ctx) {
74
+ if (!fx) return node;
75
+ delete node.transform;
76
+ let n = node;
77
+ n = wrapTransformPart(n, "skew", fx.skew, ctx);
78
+ n = wrapOrigin(
79
+ n,
80
+ fx.origin,
81
+ /*invert=*/
82
+ true
83
+ );
84
+ n = wrapTransformPart(n, "scale", normalizeScale(fx.scale), ctx);
85
+ n = wrapTransformPart(n, "rotate", fx.rotate, ctx);
86
+ n = wrapOrigin(
87
+ n,
88
+ fx.origin,
89
+ /*invert=*/
90
+ false
91
+ );
92
+ if (translateHasAutoOrient(fx.translate)) {
93
+ n = wrapOrigin(
94
+ n,
95
+ fx.origin,
96
+ /*invert=*/
97
+ true
98
+ );
99
+ n = wrapTransformPart(n, "translate", fx.translate, ctx);
100
+ n = wrapOrigin(
101
+ n,
102
+ fx.origin,
103
+ /*invert=*/
104
+ false
105
+ );
106
+ } else {
107
+ n = wrapTransformPart(n, "translate", fx.translate, ctx);
108
+ }
109
+ return n;
110
+ }
111
+ function translateHasAutoOrient(translate) {
112
+ if (!translate || typeof translate !== "object") return false;
113
+ const obj = translate;
114
+ if (obj.autoOrient) return true;
115
+ return Array.isArray(obj.keyframes) && obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
116
+ }
117
+ function normalizeScale(raw) {
118
+ if (raw === void 0) return void 0;
119
+ if (Array.isArray(raw)) return [raw[0] / 100, raw[1] / 100];
120
+ return raw;
121
+ }
122
+ function wrapTransformPart(inner, part, raw, ctx) {
123
+ if (raw === void 0) return inner;
124
+ if (part === "skew") {
125
+ const skew = readAnimatable(raw);
126
+ if (skew.kind !== "static") {
127
+ ctx.warnings.push("transformation.skew: only static skew is supported");
128
+ return inner;
129
+ }
130
+ return { type: "g", transform: "skewX(" + skew.value[0] + ")skewY(" + skew.value[1] + ")", children: [inner] };
131
+ }
132
+ const v = readAnimatable(raw);
133
+ if (v.kind === "static") {
134
+ return { type: "g", transform: { value: partsRecord(part, v.value, void 0) }, children: [inner] };
135
+ }
136
+ if (v.kind === "animated") {
137
+ const animTr = { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, kf.value, void 0))) };
138
+ if (v.autoOrient) animTr.autoOrient = true;
139
+ return {
140
+ type: "g",
141
+ animate: { transform: animTr },
142
+ children: [inner]
143
+ };
53
144
  }
54
- return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
145
+ return inner;
55
146
  }
56
- function isObject(v) {
57
- return v && typeof v === "object" && !Array.isArray(v);
147
+ function wrapOrigin(inner, raw, invert) {
148
+ if (raw === void 0) return inner;
149
+ const v = readAnimatable(raw);
150
+ const sign = (value) => invert ? [-value[0], -value[1]] : value;
151
+ if (v.kind === "absent") return inner;
152
+ if (v.kind === "static") {
153
+ if (v.value[0] === 0 && v.value[1] === 0) return inner;
154
+ return { type: "g", transform: { value: { translate: sign(v.value) } }, children: [inner] };
155
+ }
156
+ if (v.kind === "animated") {
157
+ return {
158
+ type: "g",
159
+ animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, { translate: sign(kf.value) })) } },
160
+ children: [inner]
161
+ };
162
+ }
163
+ return inner;
58
164
  }
59
- function validateFillMode(v, path, errors) {
60
- if (v === "forwards" || v === "backwards" || v === "both" || v === "none") return true;
61
- errors.push(path + ': invalid FillMode "' + v + `", expected 'forwards'|'backwards'|'both'|'none'`);
62
- return false;
165
+
166
+ // src/effects/contentRefSplit.ts
167
+ function identifyContentRefTargets(node, ctx, allocator) {
168
+ var _a, _b, _c;
169
+ if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.ref) == null ? void 0 : _b.type) === "content") {
170
+ const baseId = node.effects.ref.baseId;
171
+ if (typeof baseId === "string" && baseId && !ctx.contentRefInnerIds.has(baseId)) {
172
+ ctx.contentRefInnerIds.set(baseId, allocator(baseId));
173
+ }
174
+ }
175
+ (_c = node.children) == null ? void 0 : _c.forEach((c) => identifyContentRefTargets(c, ctx, allocator));
176
+ }
177
+ function splitForContentRef(node, transformation, originalId, innerId, ctx) {
178
+ const outerBody = liftBodyTranslate(node, transformation);
179
+ if (typeof node.id === "string") delete node.id;
180
+ const { outer: outerTr, inner: innerTr } = splitTransformationEffect(transformation);
181
+ let innerNode = node;
182
+ innerNode = applyTransformationEffect(innerNode, innerTr, ctx);
183
+ const innerWrapper = { type: "g", id: innerId, children: [innerNode] };
184
+ let outerWrapper = { type: "g", id: originalId, children: [innerWrapper] };
185
+ if (outerBody.transform !== void 0) outerWrapper.transform = outerBody.transform;
186
+ if (outerBody.animate !== void 0) outerWrapper.animate = outerBody.animate;
187
+ if (outerTr) {
188
+ delete outerWrapper.id;
189
+ outerWrapper = applyTransformationEffect(outerWrapper, outerTr, ctx);
190
+ outerWrapper.id = originalId;
191
+ }
192
+ return outerWrapper;
193
+ }
194
+ function liftBodyTranslate(node, transformation) {
195
+ var _a;
196
+ const out = {};
197
+ let didLiftAnimate = false;
198
+ const animTr = (_a = node.animate) == null ? void 0 : _a.transform;
199
+ if (animTr && typeof animTr === "object" && Array.isArray(animTr.keyframes)) {
200
+ const kfs = animTr.keyframes;
201
+ const hasTranslate = kfs.some((kf) => kf.value && kf.value.translate);
202
+ if (hasTranslate) {
203
+ const outerHasOrigin = needsOriginOnOuter(animTr);
204
+ const outerKfs = kfs.map((kf) => {
205
+ const v = kf.value || {};
206
+ const newValue = {};
207
+ if (v.translate !== void 0) newValue.translate = v.translate;
208
+ if (outerHasOrigin && v.origin !== void 0) newValue.origin = v.origin;
209
+ const outerKf = { value: newValue };
210
+ if (kf.time !== void 0) outerKf.time = kf.time;
211
+ if (kf.easing !== void 0) outerKf.easing = kf.easing;
212
+ if (kf.tangentOut !== void 0) outerKf.tangentOut = kf.tangentOut;
213
+ if (kf.tangentIn !== void 0) outerKf.tangentIn = kf.tangentIn;
214
+ return outerKf;
215
+ });
216
+ const outerAnimTr = { keyframes: outerKfs };
217
+ if (animTr.autoOrient) outerAnimTr.autoOrient = true;
218
+ out.animate = { transform: outerAnimTr };
219
+ const innerHasPivotedPart = kfs.some((kf) => {
220
+ const v = kf.value || {};
221
+ return v.rotate !== void 0 || v.scale !== void 0;
222
+ });
223
+ const innerKfs = kfs.map((kf) => {
224
+ const v = kf.value || {};
225
+ const newValue = {};
226
+ if (v.rotate !== void 0) newValue.rotate = v.rotate;
227
+ if (v.scale !== void 0) newValue.scale = v.scale;
228
+ if (v.origin !== void 0 && (!outerHasOrigin || innerHasPivotedPart)) newValue.origin = v.origin;
229
+ const innerKf = { value: newValue };
230
+ if (kf.time !== void 0) innerKf.time = kf.time;
231
+ if (kf.easing !== void 0) innerKf.easing = kf.easing;
232
+ return innerKf;
233
+ });
234
+ const allInnerEmpty = innerKfs.every((kf) => Object.keys(kf.value).length === 0);
235
+ if (allInnerEmpty) {
236
+ delete node.animate.transform;
237
+ if (node.animate && Object.keys(node.animate).length === 0) delete node.animate;
238
+ } else {
239
+ node.animate.transform = { keyframes: innerKfs };
240
+ }
241
+ didLiftAnimate = true;
242
+ }
243
+ }
244
+ const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
245
+ const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
246
+ if (typeof node.transform === "string") {
247
+ const split = splitTransformString(node.transform);
248
+ if (stripBodyTranslateOnly) {
249
+ if (split.translate !== void 0) {
250
+ if (split.rest) node.transform = split.rest;
251
+ else delete node.transform;
252
+ } else if (isPureTranslateBody(node.transform)) {
253
+ delete node.transform;
254
+ }
255
+ } else if (split.translate) {
256
+ out.transform = split.translate;
257
+ if (split.rest) node.transform = split.rest;
258
+ else delete node.transform;
259
+ }
260
+ }
261
+ return out;
262
+ }
263
+ function isPureTranslateBody(s) {
264
+ const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
265
+ const ops = [];
266
+ let m;
267
+ while (m = re.exec(s)) ops.push({ name: m[1], full: m[0] });
268
+ if (ops.length !== 1) return false;
269
+ if (ops[0].name === "translate") return true;
270
+ if (ops[0].name !== "matrix") return false;
271
+ const args = /matrix\(([^)]*)\)/.exec(ops[0].full);
272
+ if (!args) return false;
273
+ const nums = args[1].split(/[\s,]+/).filter(Boolean).map(Number);
274
+ return nums.length >= 4 && nums[0] === 1 && nums[1] === 0 && nums[2] === 0 && nums[3] === 1;
275
+ }
276
+ function splitTransformString(s) {
277
+ const ops = [];
278
+ const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
279
+ let m;
280
+ while (m = re.exec(s)) ops.push({ name: m[1], full: m[0] });
281
+ if (!ops.length) return { rest: s || void 0 };
282
+ if (ops.every((o) => o.name === "translate")) {
283
+ return { translate: ops.map((o) => o.full).join("") };
284
+ }
285
+ const leading = ops[0];
286
+ const trailing = ops[ops.length - 1];
287
+ if (trailing.name === "translate" && leading.name === "translate") {
288
+ const trailingVec = parseTranslateArgs(trailing.full);
289
+ const leadingVec = parseTranslateArgs(leading.full);
290
+ const ox = -trailingVec[0];
291
+ const oy = -trailingVec[1];
292
+ const userTx = leadingVec[0] - ox;
293
+ const userTy = leadingVec[1] - oy;
294
+ if (userTx === 0 && userTy === 0) return { rest: s };
295
+ const middleAndTrailing = "translate(" + ox + "," + oy + ")" + ops.slice(1).map((o) => o.full).join("");
296
+ return { translate: "translate(" + userTx + "," + userTy + ")", rest: middleAndTrailing };
297
+ }
298
+ if (trailing.name === "translate") return { rest: s };
299
+ const lifted = [];
300
+ let i = 0;
301
+ while (i < ops.length && ops[i].name === "translate") {
302
+ lifted.push(ops[i].full);
303
+ i++;
304
+ }
305
+ if (!lifted.length) return { rest: s };
306
+ const rest = ops.slice(i).map((o) => o.full).join("");
307
+ return {
308
+ translate: lifted.join(""),
309
+ rest: rest || void 0
310
+ };
63
311
  }
64
- function validatePlaybackDirection(v, path, errors) {
65
- if (v === "normal" || v === "reverse" || v === "alternate" || v === "alternate-reverse") return true;
66
- errors.push(path + ': invalid PlaybackDirection "' + v + `", expected 'normal'|'reverse'|'alternate'|'alternate-reverse'`);
67
- return false;
312
+ function parseTranslateArgs(translateOp) {
313
+ const m = /translate\(([^)]*)\)/.exec(translateOp);
314
+ if (!m) return [0, 0];
315
+ const nums = m[1].split(/[\s,]+/).filter(Boolean).map(Number);
316
+ return [nums[0] || 0, nums[1] || 0];
317
+ }
318
+ function splitTransformationEffect(fx) {
319
+ if (!fx) return {};
320
+ const originOnOuter = needsOriginOnOuter(fx.translate);
321
+ const innerHasPivotedPart = fx.rotate !== void 0 || fx.scale !== void 0;
322
+ const outer = {};
323
+ const inner = {};
324
+ if (fx.translate !== void 0) outer.translate = fx.translate;
325
+ if (originOnOuter && fx.origin !== void 0) outer.origin = fx.origin;
326
+ if (fx.rotate !== void 0) inner.rotate = fx.rotate;
327
+ if (fx.scale !== void 0) inner.scale = fx.scale;
328
+ if (fx.skew !== void 0) inner.skew = fx.skew;
329
+ if (fx.origin !== void 0 && (!originOnOuter || innerHasPivotedPart)) inner.origin = fx.origin;
330
+ return {
331
+ outer: Object.keys(outer).length ? outer : void 0,
332
+ inner: Object.keys(inner).length ? inner : void 0
333
+ };
68
334
  }
69
- function validatePxEasingOrRef(v, path, errors) {
70
- if (typeof v === "string") return true;
71
- if (Array.isArray(v) && v.length === 4 && v.every((n) => typeof n === "number")) return true;
72
- errors.push(path + ": invalid easing, expected string or [number, number, number, number]");
335
+ function needsOriginOnOuter(translateAnim) {
336
+ if (!translateAnim || typeof translateAnim !== "object") return false;
337
+ const obj = translateAnim;
338
+ if (obj.autoOrient) return true;
339
+ if (Array.isArray(obj.keyframes)) {
340
+ return obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
341
+ }
73
342
  return false;
74
343
  }
75
- function validatePxKeyframe(v, path, errors) {
76
- if (!isObject(v)) {
77
- errors.push(path + ": expected object");
78
- return false;
79
- }
80
- let valid = true;
81
- if (v.time !== void 0 && typeof v.time !== "number") {
82
- errors.push(path + ".time: expected number, got " + typeof v.time);
83
- valid = false;
84
- }
85
- if (v.t !== void 0 && typeof v.t !== "number") {
86
- errors.push(path + ".t: expected number, got " + typeof v.t);
87
- valid = false;
88
- }
89
- if (v.easing !== void 0 && !validatePxEasingOrRef(v.easing, path + ".easing", errors)) valid = false;
90
- if (v.e !== void 0 && !validatePxEasingOrRef(v.e, path + ".e", errors)) valid = false;
91
- return valid;
344
+
345
+ // src/effects/util.ts
346
+ function genId(ctx, prefix) {
347
+ return "_lw_" + prefix + "_" + ctx.nextId++;
92
348
  }
93
- function validatePxPropertyAnimation(v, path, errors) {
94
- if (!isObject(v)) {
95
- errors.push(path + ": expected object");
96
- return false;
97
- }
98
- let valid = true;
99
- if (v.keyframes !== void 0) {
100
- if (!Array.isArray(v.keyframes)) {
101
- errors.push(path + ".keyframes: expected array");
102
- valid = false;
103
- } else {
104
- v.keyframes.forEach((kf, i) => {
105
- if (!validatePxKeyframe(kf, path + ".keyframes[" + i + "]", errors)) valid = false;
106
- });
349
+ function indexById(node, map) {
350
+ var _a;
351
+ if (typeof node.id === "string") map.set(node.id, node);
352
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
353
+ }
354
+ function spliceDefs(root, defs) {
355
+ if (!defs.length) return;
356
+ const existing = root.children || (root.children = []);
357
+ existing.unshift({ type: "defs", children: defs });
358
+ }
359
+ function clone(value) {
360
+ if (value === null || typeof value !== "object") return value;
361
+ if (Array.isArray(value)) return value.map(clone);
362
+ const out = {};
363
+ for (const k of Object.keys(value)) out[k] = clone(value[k]);
364
+ return out;
365
+ }
366
+ function regenerateIdsInClone(root, ctx) {
367
+ const oldToNew = /* @__PURE__ */ new Map();
368
+ const walkAssign = (n) => {
369
+ var _a;
370
+ if (typeof n.id === "string") {
371
+ const newId = genId(ctx, "retimed");
372
+ oldToNew.set(n.id, newId);
373
+ n.id = newId;
374
+ }
375
+ (_a = n.children) == null ? void 0 : _a.forEach(walkAssign);
376
+ };
377
+ walkAssign(root);
378
+ const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
379
+ const newId = oldToNew.get(oldId);
380
+ return newId ? "url(#" + newId + ")" : m;
381
+ });
382
+ const walkRewrite = (n) => {
383
+ var _a;
384
+ if (typeof n.href === "string" && n.href.startsWith("#")) {
385
+ const newId = oldToNew.get(n.href.slice(1));
386
+ if (newId) n.href = "#" + newId;
387
+ }
388
+ for (const k of Object.keys(n)) {
389
+ if (k === "children" || k === "effects" || k === "meta" || k === "href" || k === "id") continue;
390
+ const v = n[k];
391
+ if (typeof v === "string" && v.indexOf("url(#") !== -1) n[k] = rewriteUrl(v);
107
392
  }
393
+ (_a = n.children) == null ? void 0 : _a.forEach(walkRewrite);
394
+ };
395
+ walkRewrite(root);
396
+ return oldToNew;
397
+ }
398
+
399
+ // src/effects/maskedByEffect.ts
400
+ function applyMaskedByEffect(node, fx, transformation, ctx) {
401
+ if (!fx) return node;
402
+ if (!fx.href) {
403
+ ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
404
+ return node;
405
+ }
406
+ const maskId = genId(ctx, "mask");
407
+ let content = { type: "use", href: "#" + fx.href };
408
+ content = wrapInverseTransform(content, transformation, ctx);
409
+ const mask = { type: "mask", id: maskId, children: [content] };
410
+ if (fx.maskType) mask.maskType = fx.maskType;
411
+ if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
412
+ if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
413
+ ctx.defs.push(mask);
414
+ node.mask = "url(#" + maskId + ")";
415
+ return node;
416
+ }
417
+ function wrapInverseTransform(inner, fx, ctx) {
418
+ if (!fx) return inner;
419
+ const origin = readStaticOrigin(fx.origin, ctx);
420
+ let n = inner;
421
+ n = wrapInversePart(n, "translate", fx.translate, void 0, ctx);
422
+ n = wrapInversePart(n, "rotate", fx.rotate, origin, ctx);
423
+ n = wrapInversePart(n, "scale", fx.scale, origin, ctx);
424
+ return n;
425
+ }
426
+ function wrapInversePart(inner, part, raw, origin, ctx) {
427
+ if (raw === void 0) return inner;
428
+ const v = readAnimatable(raw);
429
+ if (v.kind === "static") {
430
+ return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
431
+ }
432
+ if (v.kind === "animated") {
433
+ return {
434
+ type: "g",
435
+ animate: { transform: { keyframes: v.keyframes.map((kf) => keyframeWith(kf, partsRecord(part, invertPartValue(part, kf.value), origin))) } },
436
+ children: [inner]
437
+ };
108
438
  }
109
- if (v.kfs !== void 0) {
110
- if (!Array.isArray(v.kfs)) {
111
- errors.push(path + ".kfs: expected array");
112
- valid = false;
439
+ return inner;
440
+ }
441
+ function invertPartValue(part, value) {
442
+ if (part === "translate") return [-value[0], -value[1]];
443
+ if (part === "rotate") return -value;
444
+ return [1 / value[0], 1 / value[1]];
445
+ }
446
+
447
+ // src/effects/refEffect.ts
448
+ var CONTENT_SUBREF = "content";
449
+ function applyRefAndTransformationEffect(node, ref, transformation, ctx) {
450
+ if (ref) {
451
+ const baseId = ref.baseId;
452
+ if (!baseId) {
453
+ ctx.errors.push("ref: missing baseId");
113
454
  } else {
114
- v.kfs.forEach((kf, i) => {
115
- if (!validatePxKeyframe(kf, path + ".kfs[" + i + "]", errors)) valid = false;
116
- });
455
+ const targetId = ref.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
456
+ node.href = "#" + targetId;
117
457
  }
118
458
  }
119
- return valid;
459
+ return applyTransformationEffect(node, transformation, ctx);
120
460
  }
121
- function validatePxAnimationDefinition(v, path, errors) {
122
- if (!isObject(v)) {
123
- errors.push(path + ": expected object");
124
- return false;
461
+
462
+ // src/effects/repeaterEffect.ts
463
+ function applyRepeaterEffect(node, fx, ctx) {
464
+ var _a, _b;
465
+ if (!fx) return node;
466
+ const copies = (_a = fx.copies) != null ? _a : 1;
467
+ if (copies < 1) {
468
+ ctx.errors.push("repeater.copies invalid: " + fx.copies);
469
+ return node;
470
+ }
471
+ const sharedTransform = node.transform;
472
+ const sharedAnimTransform = (_b = node.animate) == null ? void 0 : _b.transform;
473
+ const base = clone(node);
474
+ delete base.transform;
475
+ if (base.animate) {
476
+ delete base.animate.transform;
477
+ if (Object.keys(base.animate).length === 0) delete base.animate;
478
+ }
479
+ const children = [base];
480
+ for (let i = 1; i < copies; i++) {
481
+ const copy = clone(base);
482
+ copy.transform = { value: perCopyParts(fx, i) };
483
+ children.push(copy);
484
+ }
485
+ const wrapper = { type: "g", children };
486
+ if (sharedTransform !== void 0) wrapper.transform = sharedTransform;
487
+ if (sharedAnimTransform !== void 0) wrapper.animate = { transform: sharedAnimTransform };
488
+ return wrapper;
489
+ }
490
+ function perCopyParts(fx, i) {
491
+ const parts = {};
492
+ if (fx.translate) parts.translate = [fx.translate[0] * i, fx.translate[1] * i];
493
+ if (fx.rotate !== void 0) parts.rotate = fx.rotate * i;
494
+ if (fx.scale) parts.scale = [__pow(fx.scale[0] / 100, i), __pow(fx.scale[1] / 100, i)];
495
+ if (fx.origin) parts.origin = [fx.origin[0] * i, fx.origin[1] * i];
496
+ return parts;
497
+ }
498
+
499
+ // src/effects/retimeEffect.ts
500
+ var RETIME_AS_SYMBOL = true;
501
+ function applyRetimeEffect(node, retime, ctx) {
502
+ var _a, _b, _c, _d;
503
+ if (!retime) return node;
504
+ const baseId = retime.baseId;
505
+ if (!baseId) {
506
+ ctx.errors.push("retime: missing baseId");
507
+ return node;
508
+ }
509
+ const target = ctx.idMap.get(baseId);
510
+ if (!target) {
511
+ ctx.warnings.push('retime: target "' + baseId + '" not found');
512
+ return node;
513
+ }
514
+ const start = (_a = retime.start) != null ? _a : 0;
515
+ const stretch = (_b = retime.stretch) != null ? _b : 1;
516
+ if (RETIME_AS_SYMBOL) {
517
+ const symbolClone = clone(target);
518
+ regenerateIdsInClone(symbolClone, ctx);
519
+ const cloneId = genId(ctx, "retime");
520
+ symbolClone.id = cloneId;
521
+ remapKeyframeTimes(symbolClone, start, stretch);
522
+ ctx.defs.push(symbolClone);
523
+ node.href = "#" + cloneId;
524
+ return node;
525
+ }
526
+ const sourceNodes = target.type === "symbol" ? target.children || [] : [target];
527
+ const content = sourceNodes.map((child) => {
528
+ const c = clone(child);
529
+ regenerateIdsInClone(c, ctx);
530
+ remapKeyframeTimes(c, start, stretch);
531
+ return c;
532
+ });
533
+ const g = __spreadProps(__spreadValues({}, node), { type: "g", children: content });
534
+ delete g.href;
535
+ const x = Number((_c = node.x) != null ? _c : 0), y = Number((_d = node.y) != null ? _d : 0);
536
+ if (x || y) {
537
+ const offset = "translate(" + x + "," + y + ")";
538
+ g.transform = typeof g.transform === "string" ? offset + g.transform : offset;
539
+ delete g.x;
540
+ delete g.y;
541
+ }
542
+ return g;
543
+ }
544
+ function remapKeyframeTimes(node, start, stretch) {
545
+ var _a;
546
+ const remap2 = (kfs) => {
547
+ for (const kf of kfs) if (typeof kf.time === "number") kf.time = start + kf.time * stretch;
548
+ };
549
+ if (node.transform && typeof node.transform === "object" && Array.isArray(node.transform.keyframes)) {
550
+ remap2(node.transform.keyframes);
125
551
  }
126
- let valid = true;
127
- for (const key of Object.keys(v)) {
128
- if (!validatePxPropertyAnimation(v[key], path + "." + key, errors)) valid = false;
552
+ if (node.animate && typeof node.animate === "object") {
553
+ for (const prop of Object.keys(node.animate)) {
554
+ const anim = node.animate[prop];
555
+ if (anim && Array.isArray(anim.keyframes)) remap2(anim.keyframes);
556
+ }
129
557
  }
130
- return valid;
558
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => remapKeyframeTimes(child, start, stretch));
131
559
  }
132
- function validatePxElementAnimation(v, path, errors) {
133
- if (typeof v === "string") return true;
134
- if (Array.isArray(v)) {
135
- let valid = true;
136
- v.forEach((item, i) => {
137
- if (typeof item !== "string" && !validatePxAnimationDefinition(item, path + "[" + i + "]", errors)) {
138
- valid = false;
139
- }
140
- });
141
- return valid;
560
+
561
+ // src/effects/trimPathEffect.ts
562
+ function applyTrimPathEffect(node, trimPath, isCombinedShape) {
563
+ var _a;
564
+ if (!trimPath && !isCombinedShape) return node;
565
+ const d = (_a = node.d) != null ? _a : rectToPathD(node);
566
+ if (d === void 0) return node;
567
+ const g = __spreadProps(__spreadValues({}, node), { type: "g" });
568
+ delete g.d;
569
+ const meta = g.meta = __spreadValues({}, g.meta || {});
570
+ const effects = meta.effects = __spreadValues({}, meta.effects || {});
571
+ if (trimPath) effects.trimPath = trimPath;
572
+ effects.isCombinedShape = true;
573
+ g.children = [{ type: "path", d }];
574
+ return g;
575
+ }
576
+ function rectToPathD(node) {
577
+ var _a, _b, _c, _d;
578
+ if (node.type !== "rect") return void 0;
579
+ const x = Number((_a = node.x) != null ? _a : 0), y = Number((_b = node.y) != null ? _b : 0);
580
+ const w = Number((_c = node.width) != null ? _c : 0), h = Number((_d = node.height) != null ? _d : 0);
581
+ return "M" + (x + w) + "," + y + "L" + (x + w) + "," + (y + h) + "L" + x + "," + (y + h) + "L" + x + "," + y + "L" + (x + w) + "," + y + "z";
582
+ }
583
+
584
+ // src/effects/PlayerEffectsUtil.ts
585
+ function applyPlayerEffects(root) {
586
+ const ctx = {
587
+ defs: [],
588
+ warnings: [],
589
+ errors: [],
590
+ idMap: /* @__PURE__ */ new Map(),
591
+ nextId: 0,
592
+ contentRefInnerIds: /* @__PURE__ */ new Map()
593
+ };
594
+ const working = clone(root);
595
+ indexById(working, ctx.idMap);
596
+ identifyContentRefTargets(working, ctx, () => genId(ctx, "inner"));
597
+ const afterPass1 = applyPlayerEffects_exceptRetime(working, ctx);
598
+ const out = applyPlayerEffects_retime(afterPass1, ctx);
599
+ spliceDefs(out, ctx.defs);
600
+ return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
601
+ }
602
+ function applyPlayerEffects_exceptRetime(node, ctx) {
603
+ if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
604
+ const fx = node.effects;
605
+ const originalId = typeof node.id === "string" ? node.id : void 0;
606
+ const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
607
+ if (!fx && !innerIdForContentRef) return node;
608
+ const { transformation, repeater, maskedBy, trimPath, retime, ref } = fx != null ? fx : {};
609
+ const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
610
+ if (fx) delete node.effects;
611
+ let n = node;
612
+ n = applyTrimPathEffect(n, trimPath, isCombinedShape);
613
+ n = applyRepeaterEffect(n, repeater, ctx);
614
+ n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
615
+ if (innerIdForContentRef) {
616
+ n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
617
+ } else {
618
+ n = applyRefAndTransformationEffect(n, ref, transformation, ctx);
142
619
  }
143
- if (isObject(v)) return validatePxAnimationDefinition(v, path, errors);
144
- errors.push(path + ": expected string, array, or PxAnimationDefinition object");
145
- return false;
620
+ if (retime) node.effects = { retime };
621
+ if (originalId) ctx.idMap.set(originalId, n);
622
+ return n;
146
623
  }
147
- function validatePxTrigger(v, path, errors) {
148
- if (!isObject(v)) {
149
- errors.push(path + ": expected object");
150
- return false;
624
+ function applyPlayerEffects_retime(node, ctx) {
625
+ var _a;
626
+ if (node.children) node.children = node.children.map((child) => applyPlayerEffects_retime(child, ctx));
627
+ const retime = (_a = node.effects) == null ? void 0 : _a.retime;
628
+ if (!retime) return node;
629
+ delete node.effects;
630
+ return applyRetimeEffect(node, retime, ctx);
631
+ }
632
+
633
+ // src/PxSchema.ts
634
+ function pathStr(path) {
635
+ if (!path.length) return ".";
636
+ let result = "";
637
+ for (const seg of path) {
638
+ if (seg.startsWith("[")) result += seg;
639
+ else result += (result ? "." : "") + seg;
151
640
  }
152
- let valid = true;
153
- const validStartOn = ["load", "mouseOver", "click", "scrollIntoView", "programmatic"];
154
- if (!validStartOn.includes(v.startOn)) {
155
- errors.push(path + '.startOn: invalid value "' + v.startOn + '", expected ' + validStartOn.join("|"));
156
- valid = false;
641
+ return result;
642
+ }
643
+ var Base = class {
644
+ _canSanitize(raw) {
645
+ return this.isValid(raw);
157
646
  }
158
- if (v.outAction !== void 0) {
159
- const validOutAction = ["continue", "pause", "reset", "reverse"];
160
- if (!validOutAction.includes(v.outAction)) {
161
- errors.push(path + '.outAction: invalid value "' + v.outAction + '", expected ' + validOutAction.join("|"));
162
- valid = false;
163
- }
647
+ optional() {
648
+ return new Optional(this);
649
+ }
650
+ };
651
+ var Optional = class extends Base {
652
+ constructor(inner) {
653
+ super();
654
+ this.inner = inner;
655
+ this._default = void 0;
164
656
  }
165
- if (v.scrollIntoViewThreshold !== void 0 && typeof v.scrollIntoViewThreshold !== "number") {
166
- errors.push(path + ".scrollIntoViewThreshold: expected number, got " + typeof v.scrollIntoViewThreshold);
167
- valid = false;
657
+ sanitize(raw) {
658
+ if (raw === void 0 || raw === null) return void 0;
659
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
168
660
  }
169
- return valid;
170
- }
171
- function validatePxAnimatorConfig(v, path, errors) {
172
- if (!isObject(v)) {
173
- errors.push(path + ": expected object");
661
+ isValid(raw, ctx, path) {
662
+ if (raw === void 0 || raw === null) return true;
663
+ return this.inner.isValid(raw, ctx, path);
664
+ }
665
+ _canSanitize(raw) {
666
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
667
+ }
668
+ };
669
+ var Str = class extends Base {
670
+ constructor(_default = "") {
671
+ super();
672
+ this._default = _default;
673
+ }
674
+ sanitize(raw) {
675
+ return typeof raw === "string" ? raw : this._default;
676
+ }
677
+ isValid(raw, ctx, path) {
678
+ if (typeof raw === "string") return true;
679
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
680
+ return false;
681
+ }
682
+ };
683
+ var Num = class extends Base {
684
+ constructor(_default = 0) {
685
+ super();
686
+ this._default = _default;
687
+ }
688
+ sanitize(raw) {
689
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
690
+ }
691
+ isValid(raw, ctx, path) {
692
+ if (typeof raw === "number" && isFinite(raw)) return true;
693
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
174
694
  return false;
175
695
  }
176
- let valid = true;
177
- if (v.mode !== void 0 && !["auto", "webapi", "frames"].includes(v.mode)) {
178
- errors.push(path + '.mode: invalid value "' + v.mode + `", expected 'auto'|'webapi'|'frames'`);
179
- valid = false;
696
+ };
697
+ var Bool = class extends Base {
698
+ constructor(_default = false) {
699
+ super();
700
+ this._default = _default;
180
701
  }
181
- if (v.duration !== void 0 && typeof v.duration !== "number") {
182
- errors.push(path + ".duration: expected number, got " + typeof v.duration);
183
- valid = false;
702
+ sanitize(raw) {
703
+ return typeof raw === "boolean" ? raw : this._default;
184
704
  }
185
- if (v.delay !== void 0 && typeof v.delay !== "number") {
186
- errors.push(path + ".delay: expected number, got " + typeof v.delay);
187
- valid = false;
705
+ isValid(raw, ctx, path) {
706
+ if (typeof raw === "boolean") return true;
707
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
708
+ return false;
188
709
  }
189
- if (v.iterations !== void 0 && typeof v.iterations !== "number" && v.iterations !== "infinite") {
190
- errors.push(path + ".iterations: expected number or 'infinite', got " + typeof v.iterations);
191
- valid = false;
710
+ };
711
+ var Literal = class extends Base {
712
+ constructor(value) {
713
+ super();
714
+ this.value = value;
715
+ this._default = value;
716
+ }
717
+ sanitize(raw) {
718
+ return raw === this.value ? this.value : this._default;
719
+ }
720
+ isValid(raw, ctx, path) {
721
+ if (raw === this.value) return true;
722
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
723
+ return false;
192
724
  }
193
- if (v.fill !== void 0 && !validateFillMode(v.fill, path + ".fill", errors)) valid = false;
194
- if (v.direction !== void 0 && !validatePlaybackDirection(v.direction, path + ".direction", errors)) valid = false;
195
- if (v.frameRate !== void 0 && typeof v.frameRate !== "number") {
196
- errors.push(path + ".frameRate: expected number, got " + typeof v.frameRate);
197
- valid = false;
725
+ };
726
+ var Enum = class extends Base {
727
+ constructor(values, defaultVal) {
728
+ super();
729
+ this.values = values;
730
+ this._default = defaultVal != null ? defaultVal : values[0];
731
+ }
732
+ sanitize(raw) {
733
+ return this.values.includes(raw) ? raw : this._default;
734
+ }
735
+ isValid(raw, ctx, path) {
736
+ if (this.values.includes(raw)) return true;
737
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected one of " + this.values.map((v) => JSON.stringify(v)).join(" | ") + ", got " + JSON.stringify(raw));
738
+ return false;
198
739
  }
199
- if (v.trigger !== void 0 && !validatePxTrigger(v.trigger, path + ".trigger", errors)) valid = false;
200
- return valid;
201
- }
202
- function validatePxDefs(v, path, errors) {
203
- if (!isObject(v)) {
204
- errors.push(path + ": expected object");
740
+ };
741
+ var Union = class extends Base {
742
+ constructor(schemas, defaultVal) {
743
+ super();
744
+ this.schemas = schemas;
745
+ this._default = defaultVal != null ? defaultVal : schemas[0]._default;
746
+ }
747
+ sanitize(raw) {
748
+ for (const s of this.schemas) {
749
+ if (s.isValid(raw)) return s.sanitize(raw);
750
+ }
751
+ return this._default;
752
+ }
753
+ isValid(raw, ctx, path) {
754
+ var _a;
755
+ if (this.schemas.some((s) => s.isValid(raw))) return true;
756
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a = JSON.stringify(raw)) != null ? _a : "").slice(0, 60));
205
757
  return false;
206
758
  }
207
- let valid = true;
208
- if (v.easings !== void 0) {
209
- if (!isObject(v.easings)) {
210
- errors.push(path + ".easings: expected object");
211
- valid = false;
212
- } else {
213
- for (const key of Object.keys(v.easings)) {
214
- if (!validatePxEasingOrRef(v.easings[key], path + ".easings." + key, errors)) valid = false;
215
- }
759
+ _canSanitize(raw) {
760
+ return this.schemas.some((s) => s._canSanitize(raw));
761
+ }
762
+ };
763
+ var DiscriminatedUnion = class extends Base {
764
+ constructor(_key, _schemas, defaultVal) {
765
+ super();
766
+ this._key = _key;
767
+ this._schemas = _schemas;
768
+ this._default = defaultVal != null ? defaultVal : _schemas[0]._default;
769
+ this._map = /* @__PURE__ */ new Map();
770
+ for (const s of _schemas) {
771
+ const keySchema = s._shape[_key];
772
+ if (keySchema) this._map.set(keySchema._default, s);
773
+ }
774
+ }
775
+ _findSchema(raw) {
776
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
777
+ const val = raw[this._key];
778
+ if (val === void 0 || val === null) return void 0;
779
+ return this._map.get(val);
780
+ }
781
+ sanitize(raw) {
782
+ var _a;
783
+ return ((_a = this._findSchema(raw)) != null ? _a : this._schemas[0]).sanitize(raw);
784
+ }
785
+ isValid(raw, ctx, path) {
786
+ const schema = this._findSchema(raw);
787
+ if (!schema) {
788
+ const val = raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw[this._key] : void 0;
789
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no discriminated union member matched " + this._key + "=" + JSON.stringify(val));
790
+ return false;
216
791
  }
792
+ return schema.isValid(raw, ctx, path);
217
793
  }
218
- if (v.animations !== void 0) {
219
- if (!isObject(v.animations)) {
220
- errors.push(path + ".animations: expected object");
221
- valid = false;
222
- } else {
223
- for (const key of Object.keys(v.animations)) {
224
- if (!validatePxAnimationDefinition(v.animations[key], path + ".animations." + key, errors)) valid = false;
794
+ _canSanitize(raw) {
795
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return false;
796
+ const schema = this._findSchema(raw);
797
+ return schema ? schema._canSanitize(raw) : this._schemas[0]._canSanitize(raw);
798
+ }
799
+ };
800
+ var Obj = class extends Base {
801
+ constructor(_shape) {
802
+ super();
803
+ this._shape = _shape;
804
+ const d = {};
805
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
806
+ this._default = d;
807
+ }
808
+ sanitize(raw) {
809
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
810
+ const out = {};
811
+ for (const key of Object.keys(this._shape)) {
812
+ out[key] = this._shape[key].sanitize(src[key]);
813
+ }
814
+ return out;
815
+ }
816
+ isValid(raw, ctx, path) {
817
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
818
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
819
+ return false;
820
+ }
821
+ const obj = raw;
822
+ const p = path != null ? path : [];
823
+ let ok = true;
824
+ for (const key of Object.keys(this._shape)) {
825
+ p.push(key);
826
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
827
+ p.pop();
828
+ }
829
+ if (ctx == null ? void 0 : ctx.strict) {
830
+ for (const key of Object.keys(obj)) {
831
+ if (key in this._shape) continue;
832
+ p.push(key);
833
+ ctx.errors.push(pathStr(p) + ": unexpected extra key");
834
+ p.pop();
835
+ ok = false;
225
836
  }
226
837
  }
838
+ return ok;
227
839
  }
228
- if (v.styles !== void 0 && !isObject(v.styles)) {
229
- errors.push(path + ".styles: expected object");
230
- valid = false;
840
+ _canSanitize(raw) {
841
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
231
842
  }
232
- return valid;
233
- }
234
- function validatePxBinding(v, path, errors) {
235
- if (!isObject(v)) {
236
- errors.push(path + ": expected object");
237
- return false;
843
+ };
844
+ var OpenObj = class extends Base {
845
+ constructor(_shape, _openSchema) {
846
+ super();
847
+ this._shape = _shape;
848
+ this._openSchema = _openSchema;
849
+ const d = {};
850
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
851
+ this._default = d;
852
+ }
853
+ sanitize(raw) {
854
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
855
+ const out = __spreadValues({}, src);
856
+ for (const key of Object.keys(this._shape)) {
857
+ out[key] = this._shape[key].sanitize(src[key]);
858
+ }
859
+ if (this._openSchema) {
860
+ for (const key of Object.keys(src)) {
861
+ if (!(key in this._shape)) out[key] = this._openSchema.sanitize(src[key]);
862
+ }
863
+ }
864
+ return out;
238
865
  }
239
- let valid = true;
240
- if (typeof v.id !== "string") {
241
- errors.push(path + ".id: expected string, got " + typeof v.id);
242
- valid = false;
866
+ isValid(raw, ctx, path) {
867
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
868
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
869
+ return false;
870
+ }
871
+ const obj = raw;
872
+ const p = path != null ? path : [];
873
+ let ok = true;
874
+ for (const key of Object.keys(this._shape)) {
875
+ p.push(key);
876
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
877
+ p.pop();
878
+ }
879
+ if (this._openSchema) {
880
+ for (const key of Object.keys(obj)) {
881
+ if (key in this._shape) continue;
882
+ p.push(key);
883
+ if (!this._openSchema.isValid(obj[key], ctx, p)) ok = false;
884
+ p.pop();
885
+ }
886
+ }
887
+ return ok;
243
888
  }
244
- if (!validatePxElementAnimation(v.animate, path + ".animate", errors)) valid = false;
245
- return valid;
246
- }
247
- function validatePxNode(v, path, errors) {
248
- if (!isObject(v)) {
249
- errors.push(path + ": expected object");
250
- return false;
889
+ _canSanitize(raw) {
890
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
891
+ }
892
+ };
893
+ var Arr = class extends Base {
894
+ constructor(item) {
895
+ super();
896
+ this.item = item;
897
+ this._default = [];
898
+ }
899
+ sanitize(raw) {
900
+ if (!Array.isArray(raw)) return [];
901
+ const out = [];
902
+ for (const el of raw) {
903
+ if (this.item._canSanitize(el)) out.push(this.item.sanitize(el));
904
+ }
905
+ return out;
906
+ }
907
+ isValid(raw, ctx, path) {
908
+ if (!Array.isArray(raw)) {
909
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected array, got " + typeof raw);
910
+ return false;
911
+ }
912
+ const p = path != null ? path : [];
913
+ let ok = true;
914
+ for (let i = 0; i < raw.length; i++) {
915
+ p.push("[" + i + "]");
916
+ if (!this.item.isValid(raw[i], ctx, p)) ok = false;
917
+ p.pop();
918
+ }
919
+ return ok;
251
920
  }
252
- let valid = true;
253
- if (typeof v.type !== "string") {
254
- errors.push(path + ".type: expected string, got " + typeof v.type);
255
- valid = false;
921
+ _canSanitize(raw) {
922
+ return Array.isArray(raw);
256
923
  }
257
- if (v.children !== void 0) {
258
- if (!Array.isArray(v.children)) {
259
- errors.push(path + ".children: expected array");
260
- valid = false;
261
- } else {
262
- v.children.forEach((child, i) => {
263
- if (!validatePxNode(child, path + ".children[" + i + "]", errors)) valid = false;
264
- });
924
+ };
925
+ var Rec = class extends Base {
926
+ constructor(value) {
927
+ super();
928
+ this.value = value;
929
+ this._default = {};
930
+ }
931
+ sanitize(raw) {
932
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
933
+ const out = {};
934
+ for (const [k, v] of Object.entries(raw)) {
935
+ if (this.value._canSanitize(v)) out[k] = this.value.sanitize(v);
936
+ }
937
+ return out;
938
+ }
939
+ isValid(raw, ctx, path) {
940
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
941
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object/record, got " + (Array.isArray(raw) ? "array" : typeof raw));
942
+ return false;
265
943
  }
944
+ const p = path != null ? path : [];
945
+ let ok = true;
946
+ for (const [k, v] of Object.entries(raw)) {
947
+ p.push(k);
948
+ if (!this.value.isValid(v, ctx, p)) ok = false;
949
+ p.pop();
950
+ }
951
+ return ok;
266
952
  }
267
- if (v.animate !== void 0 && !validatePxElementAnimation(v.animate, path + ".animate", errors)) valid = false;
268
- return valid;
269
- }
270
- function validatePxSvgNode(v, path, errors) {
271
- if (!validatePxNode(v, path, errors)) return false;
272
- let valid = true;
273
- if (v.type !== "svg") {
274
- errors.push(path + ".type: expected 'svg', got '" + v.type + "'");
275
- valid = false;
953
+ _canSanitize(raw) {
954
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
276
955
  }
277
- if (v.width !== void 0 && typeof v.width !== "number") {
278
- errors.push(path + ".width: expected number, got " + typeof v.width);
279
- valid = false;
956
+ };
957
+ var Any = class extends Base {
958
+ constructor() {
959
+ super(...arguments);
960
+ this._default = void 0;
280
961
  }
281
- if (v.height !== void 0 && typeof v.height !== "number") {
282
- errors.push(path + ".height: expected number, got " + typeof v.height);
283
- valid = false;
962
+ sanitize(raw) {
963
+ return raw;
284
964
  }
285
- if (v.viewBox !== void 0 && typeof v.viewBox !== "string") {
286
- errors.push(path + ".viewBox: expected string, got " + typeof v.viewBox);
287
- valid = false;
965
+ isValid(_raw, _ctx, _path) {
966
+ return true;
288
967
  }
289
- if (v.animator !== void 0 && !validatePxAnimatorConfig(v.animator, path + ".animator", errors)) valid = false;
290
- if (v.defs !== void 0 && !validatePxDefs(v.defs, path + ".defs", errors)) valid = false;
291
- if (v.bindings !== void 0) {
292
- if (!Array.isArray(v.bindings)) {
293
- errors.push(path + ".bindings: expected array");
294
- valid = false;
295
- } else {
296
- v.bindings.forEach((binding, i) => {
297
- if (!validatePxBinding(binding, path + ".bindings[" + i + "]", errors)) valid = false;
298
- });
968
+ _canSanitize(_raw) {
969
+ return true;
970
+ }
971
+ };
972
+ var Lazy = class extends Base {
973
+ constructor(fn, _default) {
974
+ super();
975
+ this.fn = fn;
976
+ this._default = _default;
977
+ this.resolved = null;
978
+ }
979
+ get schema() {
980
+ var _a;
981
+ return (_a = this.resolved) != null ? _a : this.resolved = this.fn();
982
+ }
983
+ sanitize(raw) {
984
+ return this.schema.sanitize(raw);
985
+ }
986
+ isValid(raw, ctx, path) {
987
+ return this.schema.isValid(raw, ctx, path);
988
+ }
989
+ _canSanitize(raw) {
990
+ return this.schema._canSanitize(raw);
991
+ }
992
+ };
993
+ var Tuple = class extends Base {
994
+ constructor(schemas) {
995
+ super();
996
+ this.schemas = schemas;
997
+ this._default = schemas.map((s) => s._default);
998
+ }
999
+ sanitize(raw) {
1000
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) return this._default;
1001
+ return this.schemas.map((s, i) => s.sanitize(raw[i]));
1002
+ }
1003
+ isValid(raw, ctx, path) {
1004
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) {
1005
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected tuple of length " + this.schemas.length + ", got " + (Array.isArray(raw) ? "array[" + raw.length + "]" : typeof raw));
1006
+ return false;
1007
+ }
1008
+ const p = path != null ? path : [];
1009
+ let ok = true;
1010
+ for (let i = 0; i < this.schemas.length; i++) {
1011
+ p.push("[" + i + "]");
1012
+ if (!this.schemas[i].isValid(raw[i], ctx, p)) ok = false;
1013
+ p.pop();
299
1014
  }
1015
+ return ok;
300
1016
  }
301
- if (v.design !== void 0 && !validatePxNode(v.design, path + ".design", errors)) valid = false;
302
- return valid;
1017
+ // Require exact length so wrong-length arrays are dropped rather than repaired to default.
1018
+ _canSanitize(raw) {
1019
+ return Array.isArray(raw) && raw.length === this.schemas.length;
1020
+ }
1021
+ };
1022
+ function implementsInterface() {
1023
+ return (schema) => schema;
1024
+ }
1025
+ function schemaKeys(schema) {
1026
+ return Object.fromEntries(
1027
+ Object.keys(schema["_shape"]).map((k) => [k, k])
1028
+ );
1029
+ }
1030
+ function describeSchema(schema) {
1031
+ var _a;
1032
+ const s = schema;
1033
+ if ("_shape" in s) return { kind: "shape", shape: s._shape };
1034
+ if ("item" in s) return { kind: "array", item: s.item };
1035
+ if ("inner" in s) return { kind: "optional", inner: s.inner };
1036
+ if ("fn" in s) return { kind: "lazy", resolved: (_a = s.resolved) != null ? _a : s.fn() };
1037
+ return { kind: "leaf" };
1038
+ }
1039
+ var px = {
1040
+ /** Matches a string. Default: '' or provided value. */
1041
+ string: (defaultVal = "") => new Str(defaultVal),
1042
+ /** Matches a finite number. Default: 0 or provided value. */
1043
+ number: (defaultVal = 0) => new Num(defaultVal),
1044
+ /** Matches a boolean. Default: false or provided value. */
1045
+ boolean: (defaultVal = false) => new Bool(defaultVal),
1046
+ /** Matches one exact primitive value; its default is the value itself. */
1047
+ literal: (value) => new Literal(value),
1048
+ /** Matches one of a fixed set of string/number values. Default: first value. */
1049
+ enum: (values, defaultVal) => new Enum(values, defaultVal),
1050
+ /**
1051
+ * Returns the first schema whose isValid passes.
1052
+ * TypeScript infers the union of all member types automatically.
1053
+ */
1054
+ union: (schemas, defaultVal) => new Union(schemas, defaultVal),
1055
+ /**
1056
+ * Discriminated union — reads `raw[key]`, finds the member schema whose
1057
+ * literal at `key` matches, then delegates sanitize/isValid to that member.
1058
+ * Each member must be an object schema with a `px.literal(...)` at `key`.
1059
+ * TypeScript infers the union of all member types automatically.
1060
+ */
1061
+ discriminatedUnion: (key, schemas) => new DiscriminatedUnion(key, schemas),
1062
+ /** Typed object — unknown keys are stripped. Required fields fall back to their default. */
1063
+ object: (shape) => new Obj(shape),
1064
+ /**
1065
+ * Open object — validates known keys; passes unknown keys through as-is,
1066
+ * or validates/sanitizes them against `openSchema` when provided.
1067
+ */
1068
+ openObject: (shape, openSchema) => new OpenObj(shape, openSchema),
1069
+ /**
1070
+ * Creates a new closed object schema by merging a base schema's shape with additional fields.
1071
+ * The base can be the result of px.object() or px.openObject() — anything with a _shape property.
1072
+ *
1073
+ * @example
1074
+ * const PxSvgNodeSchema = px.extendedObject(PxNodeBase, { width: px.number().optional() });
1075
+ */
1076
+ extendedObject: (base, extra) => new Obj(__spreadValues(__spreadValues({}, base._shape), extra)),
1077
+ /** Array whose unrecoverable items are filtered out. Default: []. */
1078
+ array: (item) => new Arr(item),
1079
+ /** String-keyed record whose unrecoverable values are dropped. Default: {}. */
1080
+ record: (value) => new Rec(value),
1081
+ /** Passes anything through unchanged — always valid. */
1082
+ any: () => new Any(),
1083
+ /** Fixed-length tuple — validates element count and each position individually. */
1084
+ tuple: (schemas) => new Tuple(schemas),
1085
+ /** Defers schema creation — required for recursive types. Must supply a default value. */
1086
+ lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
1087
+ };
1088
+
1089
+ // src/PxAnimatorTypes.ts
1090
+ var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
1091
+ var PX_ANIM_ATTR_NAME = "_px_animator";
1092
+ var TEXT_ATTR = "text";
1093
+ var TEXT_CONTENT_ATTR = "textContent";
1094
+ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
1095
+ "type",
1096
+ "children",
1097
+ "animator",
1098
+ "meta",
1099
+ "animate",
1100
+ TEXT_ATTR,
1101
+ TEXT_CONTENT_ATTR
1102
+ ]);
1103
+ var PxEasingOrRefSchema = px.union([
1104
+ px.string(),
1105
+ px.tuple([px.number(), px.number(), px.number(), px.number()])
1106
+ ]);
1107
+ var PxKeyframeValueSchema = implementsInterface()(px.union([
1108
+ px.string(),
1109
+ // e.g. for colors
1110
+ px.number(),
1111
+ px.array(px.number()),
1112
+ px.lazy(() => PxTransformPartsSchema, {}),
1113
+ px.object({ path: px.string() }),
1114
+ px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] })
1115
+ ]));
1116
+ var PxKeyframeSchema = implementsInterface()(px.object({
1117
+ time: px.number().optional(),
1118
+ t: px.number().optional(),
1119
+ value: px.any().optional(),
1120
+ v: px.any().optional(),
1121
+ easing: PxEasingOrRefSchema.optional(),
1122
+ e: PxEasingOrRefSchema.optional(),
1123
+ tangentOut: px.tuple([px.number(), px.number()]).optional(),
1124
+ to: px.tuple([px.number(), px.number()]).optional(),
1125
+ // short alias
1126
+ tangentIn: px.tuple([px.number(), px.number()]).optional(),
1127
+ ti: px.tuple([px.number(), px.number()]).optional(),
1128
+ // short alias
1129
+ selected: px.boolean().optional()
1130
+ // editor-side UI state (Player ignores it)
1131
+ }));
1132
+ var PxLoopSchema = implementsInterface()(px.object({
1133
+ segmentCount: px.number().optional(),
1134
+ before: px.boolean().optional(),
1135
+ alternate: px.boolean().optional()
1136
+ }));
1137
+ var PxPropertyAnimationSchema = implementsInterface()(px.object({
1138
+ keyframes: px.array(PxKeyframeSchema).optional(),
1139
+ kfs: px.array(PxKeyframeSchema).optional(),
1140
+ loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1141
+ autoOrient: px.boolean().optional()
1142
+ }));
1143
+ var PX_TRANSFORM_PART_KEYS = ["translate", "rotate", "scale", "origin"];
1144
+ var PxTransformPartsSchema = implementsInterface()(px.object({
1145
+ translate: px.tuple([px.number(), px.number()]).optional(),
1146
+ rotate: px.number().optional(),
1147
+ scale: px.tuple([px.number(), px.number()]).optional(),
1148
+ origin: px.tuple([px.number(), px.number()]).optional()
1149
+ }));
1150
+ var PxTransformValueSchema = px.union([
1151
+ px.string(),
1152
+ px.object({ value: PxTransformPartsSchema }),
1153
+ PxPropertyAnimationSchema
1154
+ ]);
1155
+ var PxAnimationDefinitionSchema = implementsInterface()(
1156
+ px.record(PxPropertyAnimationSchema)
1157
+ );
1158
+ var PxElementAnimationSchema = implementsInterface()(px.union([
1159
+ px.string(),
1160
+ px.array(px.union([px.string(), PxAnimationDefinitionSchema])),
1161
+ PxAnimationDefinitionSchema
1162
+ ]));
1163
+ var PxTriggerSchema = implementsInterface()(px.object({
1164
+ startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1165
+ outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1166
+ scrollIntoViewThreshold: px.number().optional()
1167
+ }));
1168
+ var PxDefsSchema = implementsInterface()(px.object({
1169
+ easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1170
+ animations: px.record(PxAnimationDefinitionSchema).optional(),
1171
+ styles: px.record(px.any()).optional()
1172
+ }));
1173
+ var PxAnimatorConfigSchema = implementsInterface()(px.object({
1174
+ mode: px.enum(["auto", "webapi", "frames"]).optional(),
1175
+ duration: px.number().optional(),
1176
+ delay: px.number().optional(),
1177
+ iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1178
+ fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1179
+ direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
1180
+ frameRate: px.number().optional(),
1181
+ trigger: PxTriggerSchema.optional(),
1182
+ definitions: PxDefsSchema.optional(),
1183
+ animate: px.record(PxElementAnimationSchema).optional(),
1184
+ debug: px.boolean().optional(),
1185
+ debugInstName: px.string().optional()
1186
+ }));
1187
+ var PxBindingSchema = implementsInterface()(px.object({
1188
+ id: px.string(),
1189
+ animate: PxElementAnimationSchema
1190
+ }));
1191
+ var PxAttrValueSchema = px.union([
1192
+ px.string(),
1193
+ px.number(),
1194
+ px.object({ value: px.any() }),
1195
+ PxPropertyAnimationSchema
1196
+ ]);
1197
+ var PxAnimatableNumberSchema = px.union([
1198
+ px.number(),
1199
+ px.object({ value: px.number() }),
1200
+ px.object({
1201
+ keyframes: px.array(PxKeyframeSchema),
1202
+ autoOrient: px.boolean().optional()
1203
+ })
1204
+ ]);
1205
+ var PxAnimatableVec2Schema = px.union([
1206
+ px.tuple([px.number(), px.number()]),
1207
+ px.object({ value: px.tuple([px.number(), px.number()]) }),
1208
+ px.object({
1209
+ keyframes: px.array(PxKeyframeSchema),
1210
+ autoOrient: px.boolean().optional()
1211
+ })
1212
+ ]);
1213
+ var PxTransformationEffectSchema = px.object({
1214
+ translate: PxAnimatableVec2Schema.optional(),
1215
+ rotate: PxAnimatableNumberSchema.optional(),
1216
+ scale: PxAnimatableVec2Schema.optional(),
1217
+ skew: PxAnimatableVec2Schema.optional(),
1218
+ origin: PxAnimatableVec2Schema.optional()
1219
+ });
1220
+ var PxRepeaterEffectSchema = px.object({
1221
+ copies: px.number().optional(),
1222
+ translate: px.tuple([px.number(), px.number()]).optional(),
1223
+ rotate: px.number().optional(),
1224
+ scale: px.tuple([px.number(), px.number()]).optional(),
1225
+ // per-copy scale, PERCENT (85 → 0.85)
1226
+ origin: px.tuple([px.number(), px.number()]).optional()
1227
+ });
1228
+ var PxMaskedByEffectSchema = px.object({
1229
+ href: px.string().optional(),
1230
+ maskType: px.string().optional(),
1231
+ maskUnits: px.string().optional(),
1232
+ maskContentUnits: px.string().optional()
1233
+ });
1234
+ var PxTrimPathEffectSchema = px.any();
1235
+ var PxRetimeEffectSchema = px.object({
1236
+ baseId: px.string().optional(),
1237
+ start: px.number().optional(),
1238
+ stretch: px.number().optional(),
1239
+ timeCrop: px.tuple([px.number(), px.number()]).optional()
1240
+ });
1241
+ var PxRefEffectSchema = px.object({
1242
+ baseId: px.string().optional(),
1243
+ type: px.string().optional()
1244
+ });
1245
+ var PxEffectsSchema = px.object({
1246
+ transformation: PxTransformationEffectSchema.optional(),
1247
+ repeater: PxRepeaterEffectSchema.optional(),
1248
+ maskedBy: PxMaskedByEffectSchema.optional(),
1249
+ trimPath: PxTrimPathEffectSchema.optional(),
1250
+ retime: PxRetimeEffectSchema.optional(),
1251
+ isCombinedShape: px.boolean().optional(),
1252
+ ref: PxRefEffectSchema.optional()
1253
+ });
1254
+ function validateNodeEffects(root, opts) {
1255
+ const warnings = [];
1256
+ const walk = (node, path) => {
1257
+ if (node && node.effects) {
1258
+ const ctx = { errors: [], warnings: [], strict: !!(opts == null ? void 0 : opts.strict) };
1259
+ const ok = PxEffectsSchema.isValid(node.effects, ctx, [path + ".effects"]);
1260
+ if (!ok) {
1261
+ for (const err of ctx.errors) warnings.push(err);
1262
+ }
1263
+ }
1264
+ if (node && Array.isArray(node.children)) {
1265
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]"));
1266
+ }
1267
+ };
1268
+ walk(root, "root");
1269
+ return warnings;
1270
+ }
1271
+ var PxNodeBase = px.openObject({
1272
+ type: px.string(),
1273
+ id: px.string().optional(),
1274
+ meta: px.any().optional(),
1275
+ // Player-effects bucket emitted by the Editor's lightweight design format.
1276
+ // Consumed and removed by `applyPlayerEffects` before any other normalisation
1277
+ // (see `createAnimatorImpl`), so downstream code never sees it.
1278
+ effects: PxEffectsSchema.optional(),
1279
+ animate: PxAnimationDefinitionSchema.optional(),
1280
+ style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
1281
+ }, PxAttrValueSchema);
1282
+ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._shape), {
1283
+ children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1284
+ }), PxAttrValueSchema);
1285
+ var PxSvgNodeExtra = px.object({
1286
+ width: px.number().optional(),
1287
+ height: px.number().optional(),
1288
+ viewBox: px.string().optional(),
1289
+ animator: PxAnimatorConfigSchema.optional()
1290
+ });
1291
+ var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
1292
+ type: px.literal("svg"),
1293
+ // override string → literal to require 'svg'
1294
+ children: px.array(PxNodeSchema).optional()
1295
+ }), PxAttrValueSchema);
1296
+ var PxBezierPathSchema = implementsInterface()(px.object({
1297
+ v: px.array(px.array(px.number())),
1298
+ i: px.array(px.array(px.number())).optional(),
1299
+ o: px.array(px.array(px.number())).optional(),
1300
+ c: px.boolean().optional()
1301
+ }));
1302
+ function isPxElementFileFormat(fileJson) {
1303
+ if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
1304
+ return false;
1305
+ }
1306
+ return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
303
1307
  }
304
1308
  function isPxElementFileFormatDeep(fileJson) {
305
- const errors = [];
306
- const valid = validatePxSvgNode(fileJson, "root", errors);
307
- return { valid, errors };
1309
+ const valid = PxAnimatedSvgDocumentSchema.isValid(fileJson);
1310
+ return { valid, errors: valid ? [] : ["Document failed schema validation"] };
308
1311
  }
309
1312
  function getAnimatorConfig(doc) {
310
1313
  var _a, _b;
@@ -313,12 +1316,14 @@ function getAnimatorConfig(doc) {
313
1316
  function getDefs(doc) {
314
1317
  var _a;
315
1318
  if (!doc) return void 0;
316
- return doc.defs || ((_a = doc.meta) == null ? void 0 : _a.defs);
1319
+ return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
317
1320
  }
318
1321
  function getBindings(doc) {
319
1322
  var _a;
320
1323
  if (!doc) return void 0;
321
- return doc.bindings || ((_a = doc.meta) == null ? void 0 : _a.bindings);
1324
+ const animate = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animate;
1325
+ if (!animate) return void 0;
1326
+ return Object.entries(animate).map(([id, anim]) => ({ id, animate: anim }));
322
1327
  }
323
1328
  function getChildren(doc) {
324
1329
  return doc == null ? void 0 : doc.children;
@@ -557,6 +1562,24 @@ function parseColor(s) {
557
1562
  var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
558
1563
  var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
559
1564
  var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1565
+ function composeTransformParts(parts, opts) {
1566
+ var _a;
1567
+ if (!parts) return "";
1568
+ const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
1569
+ const segs = [];
1570
+ const t = parts.translate;
1571
+ const o = parts.origin;
1572
+ const r = parts.rotate;
1573
+ const s = parts.scale;
1574
+ const tu = withUnits ? "px" : "";
1575
+ const ru = withUnits ? "deg" : "";
1576
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
1577
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
1578
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
1579
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
1580
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
1581
+ return segs.join("");
1582
+ }
560
1583
  var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
561
1584
  var DEFAULT_DURATION_MS = 1e3;
562
1585
  function kebabToCamelCaseWord(kebab) {
@@ -616,6 +1639,80 @@ function camelCaseToKebabWordIfNeeded(camel) {
616
1639
  function clamp(value, min, max) {
617
1640
  return Math.max(min, Math.min(value, max));
618
1641
  }
1642
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
1643
+ if (t <= 0) return [P0[0], P0[1]];
1644
+ if (t >= 1) return [P3[0], P3[1]];
1645
+ const u = 1 - t;
1646
+ const u2 = u * u;
1647
+ const u3 = u2 * u;
1648
+ const t2 = t * t;
1649
+ const t3 = t2 * t;
1650
+ const w0 = u3;
1651
+ const w1 = 3 * t * u2;
1652
+ const w2 = 3 * t2 * u;
1653
+ const w3 = t3;
1654
+ return [
1655
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
1656
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
1657
+ ];
1658
+ }
1659
+ var BEZIER_T_NUDGE = 1e-4;
1660
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
1661
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
1662
+ if (result[0] === 0 && result[1] === 0) {
1663
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
1664
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
1665
+ }
1666
+ return result;
1667
+ }
1668
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
1669
+ const u = 1 - t;
1670
+ const a = 3 * u * u;
1671
+ const b = 6 * t * u;
1672
+ const c = 3 * t * t;
1673
+ return [
1674
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
1675
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
1676
+ ];
1677
+ }
1678
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
1679
+ const n = steps + 1;
1680
+ const ts = new Float64Array(n);
1681
+ const ds = new Float64Array(n);
1682
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
1683
+ ts[0] = 0;
1684
+ ds[0] = 0;
1685
+ let cum = 0;
1686
+ for (let i = 1; i < n; i++) {
1687
+ const t = i / steps;
1688
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
1689
+ const dx = cur[0] - prev[0];
1690
+ const dy = cur[1] - prev[1];
1691
+ cum += Math.sqrt(dx * dx + dy * dy);
1692
+ ts[i] = t;
1693
+ ds[i] = cum;
1694
+ prev = cur;
1695
+ }
1696
+ return { ts, ds };
1697
+ }
1698
+ function bezier2D_tForDistance(lut, distance) {
1699
+ const { ts, ds } = lut;
1700
+ const last = ds.length - 1;
1701
+ if (distance <= 0) return ts[0];
1702
+ if (distance >= ds[last]) return ts[last];
1703
+ let lo = 1;
1704
+ let hi = last;
1705
+ while (lo < hi) {
1706
+ const mid = lo + hi >>> 1;
1707
+ if (ds[mid] < distance) lo = mid + 1;
1708
+ else hi = mid;
1709
+ }
1710
+ const dPrev = ds[hi - 1];
1711
+ const dCur = ds[hi];
1712
+ const span = dCur - dPrev;
1713
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
1714
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
1715
+ }
619
1716
 
620
1717
  // src/PxAnimatorDOM.ts
621
1718
  var SVG_NS = "http://www.w3.org/2000/svg";
@@ -631,6 +1728,7 @@ var ALLOWED_SVG_TAGS_LOWER_CASE = new Set([
631
1728
  "polygon",
632
1729
  "text",
633
1730
  "tspan",
1731
+ "textPath",
634
1732
  "defs",
635
1733
  "clipPath",
636
1734
  "mask",
@@ -671,13 +1769,21 @@ var ALLOWED_RESOURCE_ATTRIBUTES = [
671
1769
  // Don't allow 'cursor', can use external SVG, // url(cursor.svg)
672
1770
  ];
673
1771
  var ALLOWED_RESOURCE_ATTRIBUTES_SET = new Set(ALLOWED_RESOURCE_ATTRIBUTES);
674
- var ALLOWED_ATTRIBUTES_SET = /* @__PURE__ */ new Set([
1772
+ var ALLOWED_ATTRIBUTES = [
675
1773
  "href",
676
1774
  "src",
677
1775
  // Presentation
678
1776
  "fill",
1777
+ "fillOpacity",
1778
+ "fillRule",
679
1779
  "stroke",
680
1780
  "strokeWidth",
1781
+ "strokeOpacity",
1782
+ "strokeLinecap",
1783
+ "strokeLinejoin",
1784
+ "strokeMiterlimit",
1785
+ "strokeDasharray",
1786
+ "strokeDashoffset",
681
1787
  "opacity",
682
1788
  "transform",
683
1789
  // Geometry
@@ -696,10 +1802,27 @@ var ALLOWED_ATTRIBUTES_SET = /* @__PURE__ */ new Set([
696
1802
  "x2",
697
1803
  "y2",
698
1804
  "points",
699
- // Text
1805
+ "dx",
1806
+ "dy",
1807
+ // Font
700
1808
  "fontSize",
701
1809
  "fontFamily",
1810
+ "fontWeight",
1811
+ "fontStyle",
1812
+ // Text
702
1813
  "textAnchor",
1814
+ "letterSpacing",
1815
+ "wordSpacing",
1816
+ "space",
1817
+ "xml:space",
1818
+ "textDecoration",
1819
+ "textTransform",
1820
+ "whiteSpace",
1821
+ "white-space",
1822
+ "dominantBaseline",
1823
+ "alignmentBaseline",
1824
+ "rotate",
1825
+ // per-glyph rotation array, currently not supported
703
1826
  // Structure
704
1827
  "id",
705
1828
  "class",
@@ -713,6 +1836,16 @@ var ALLOWED_ATTRIBUTES_SET = /* @__PURE__ */ new Set([
713
1836
  // Clippath/Mask
714
1837
  "clipPath",
715
1838
  "mask",
1839
+ // Motion path
1840
+ "offsetPath",
1841
+ "offsetDistance",
1842
+ "offsetRotate",
1843
+ "offsetAnchor",
1844
+ "offsetPosition",
1845
+ // Text path
1846
+ "startOffset",
1847
+ "textLength",
1848
+ "lengthAdjust",
716
1849
  // Filter
717
1850
  "filter",
718
1851
  "stdDeviation",
@@ -721,10 +1854,11 @@ var ALLOWED_ATTRIBUTES_SET = /* @__PURE__ */ new Set([
721
1854
  "result",
722
1855
  "mode",
723
1856
  ...ALLOWED_RESOURCE_ATTRIBUTES
724
- ]);
1857
+ ];
1858
+ var ALLOWED_ATTRIBUTES_LOW_SET = new Set(ALLOWED_ATTRIBUTES.map((str) => str.toLowerCase()));
725
1859
  function sanitiseAttributeValue(name, value) {
726
1860
  const nameLower = name.toLowerCase();
727
- if (!ALLOWED_ATTRIBUTES_SET.has(nameLower)) {
1861
+ if (!ALLOWED_ATTRIBUTES_LOW_SET.has(nameLower)) {
728
1862
  console.warn("Attribute not in whitelist: ", nameLower);
729
1863
  return void 0;
730
1864
  }
@@ -749,7 +1883,10 @@ function sanitiseAttributeValue(name, value) {
749
1883
  return value;
750
1884
  }
751
1885
  function createElement(tagName, normalisedProps, style, children, textContent) {
752
- if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) return null;
1886
+ if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) {
1887
+ console.warn("Attribute not in whitelist: ", tagName);
1888
+ return null;
1889
+ }
753
1890
  const element = document.createElementNS(SVG_NS, tagName);
754
1891
  for (const propName in normalisedProps) {
755
1892
  element.setAttribute(
@@ -786,6 +1923,8 @@ function getNormalizedProps(props) {
786
1923
  let value = props[key];
787
1924
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
788
1925
  propsCopy[key] = toRGBA(value);
1926
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
1927
+ propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
789
1928
  } else if (TRANSFORM_FN_NAMES.has(key)) {
790
1929
  if (Array.isArray(value)) {
791
1930
  if (key === "translate") value = value.map((v) => v + "px");
@@ -801,8 +1940,8 @@ function getNormalizedProps(props) {
801
1940
  }
802
1941
  function renderNode(node, defs) {
803
1942
  if (!node) return null;
804
- const _a = node, { type, children, animate, style } = _a, props = __objRest(_a, ["type", "children", "animate", "style"]);
805
- const nodeDefs = node.defs || defs;
1943
+ const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
1944
+ const nodeDefs = getDefs(node) || defs;
806
1945
  const resolvedStyle = resolveStyle(style, nodeDefs);
807
1946
  let childElements;
808
1947
  if (children) {
@@ -900,6 +2039,47 @@ function setupAnimationTriggers(api, config) {
900
2039
  return api;
901
2040
  }
902
2041
 
2042
+ // src/PxMotionPath.ts
2043
+ function propAnimIsMotionPath(anim) {
2044
+ var _a;
2045
+ const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
2046
+ if (!Array.isArray(kfs)) return false;
2047
+ if (anim.autoOrient) return true;
2048
+ for (const kf of kfs) {
2049
+ if (kf.tangentIn || kf.tangentOut) return true;
2050
+ }
2051
+ return false;
2052
+ }
2053
+ var _segmentCache = /* @__PURE__ */ new WeakMap();
2054
+ function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
2055
+ const existing = _segmentCache.get(prevKf);
2056
+ if (existing) return existing;
2057
+ const to = prevKf.tangentOut;
2058
+ const ti = nextKf.tangentIn;
2059
+ const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
2060
+ const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
2061
+ const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
2062
+ const entry = {
2063
+ P0: prevPos,
2064
+ P1,
2065
+ P2,
2066
+ P3: nextPos,
2067
+ lut,
2068
+ totalArc: lut.ds[lut.ds.length - 1]
2069
+ };
2070
+ _segmentCache.set(prevKf, entry);
2071
+ return entry;
2072
+ }
2073
+ function evaluateMotionPathSegment(prevKf, nextKf, prevPos, nextPos, localProgress, autoOrient) {
2074
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2075
+ const t = seg.totalArc === 0 ? localProgress : bezier2D_tForDistance(seg.lut, localProgress * seg.totalArc);
2076
+ const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2077
+ if (!autoOrient) return { translate: point };
2078
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2079
+ const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2080
+ return { translate: point, rotateDeg };
2081
+ }
2082
+
903
2083
  // src/PxDefinitions.ts
904
2084
  function parsePathCommands(d) {
905
2085
  const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
@@ -963,6 +2143,8 @@ function parseSvgPathToBezier(d) {
963
2143
  currentPath.o.push([x2, y2]);
964
2144
  } else if (type === "Z" || type === "z") {
965
2145
  currentPath.c = true;
2146
+ } else {
2147
+ console.warn('Unsupported path command "' + type + '"');
966
2148
  }
967
2149
  }
968
2150
  return res;
@@ -980,13 +2162,17 @@ function isPathString(value) {
980
2162
  return typeof value === "string" && extractPathData(value) !== void 0;
981
2163
  }
982
2164
  function normalizePathValue(value) {
2165
+ if (value && typeof value === "object" && typeof value.path === "string") {
2166
+ const d = extractPathData(value.path);
2167
+ return d ? { paths: parseSvgPathToBezier(d) } : value;
2168
+ }
983
2169
  if (value && typeof value === "object" && "paths" in value) {
984
2170
  const pathsArray = value.paths;
985
2171
  if (Array.isArray(pathsArray) && pathsArray.length > 0) {
986
2172
  if (isPathString(pathsArray[0])) {
987
2173
  const paths = [];
988
- for (const pathStr of pathsArray) {
989
- const d = extractPathData(pathStr);
2174
+ for (const pathStr2 of pathsArray) {
2175
+ const d = extractPathData(pathStr2);
990
2176
  if (d) {
991
2177
  paths.push(...parseSvgPathToBezier(d));
992
2178
  }
@@ -999,8 +2185,8 @@ function normalizePathValue(value) {
999
2185
  if (Array.isArray(value)) {
1000
2186
  if (value.length > 0 && isPathString(value[0])) {
1001
2187
  const paths = [];
1002
- for (const pathStr of value) {
1003
- const d = extractPathData(pathStr);
2188
+ for (const pathStr2 of value) {
2189
+ const d = extractPathData(pathStr2);
1004
2190
  if (d) {
1005
2191
  paths.push(...parseSvgPathToBezier(d));
1006
2192
  }
@@ -1238,10 +2424,11 @@ function getNormalisedBindings(doc) {
1238
2424
  }
1239
2425
  }
1240
2426
  const processNode = (node) => {
1241
- if (node.animate) {
2427
+ const inlineAnim = node.animate;
2428
+ if (inlineAnim && Object.keys(inlineAnim).length > 0) {
1242
2429
  const nodeId = node.id || generateElementId();
1243
2430
  node.id = nodeId;
1244
- const normalized = processAnimation(nodeId, node.animate);
2431
+ const normalized = processAnimation(nodeId, inlineAnim);
1245
2432
  if (normalized) bindings.push(normalized);
1246
2433
  }
1247
2434
  if (node.children) {
@@ -1312,6 +2499,41 @@ function calcPropertyValue(propName, propAnim, progress) {
1312
2499
  localProgress
1313
2500
  ).join(" ");
1314
2501
  cssAttrName = propName;
2502
+ } else if (cssAttrName === "transform" && prevV !== null && typeof prevV === "object" && !Array.isArray(prevV)) {
2503
+ const partKeys = /* @__PURE__ */ new Set([
2504
+ ...prevV ? Object.keys(prevV) : [],
2505
+ ...nextV ? Object.keys(nextV) : []
2506
+ ]);
2507
+ const partsResult = {};
2508
+ for (const partKey of partKeys) {
2509
+ const prevPart = prevV == null ? void 0 : prevV[partKey];
2510
+ const nextPart = nextV == null ? void 0 : nextV[partKey];
2511
+ if (partKey === "rotate") {
2512
+ partsResult.rotate = interpolateNum(+(prevPart != null ? prevPart : 0), +(nextPart != null ? nextPart : 0), localProgress);
2513
+ } else if (partKey === "translate" || partKey === "scale" || partKey === "origin") {
2514
+ const fallback = partKey === "scale" ? [1, 1] : [0, 0];
2515
+ const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);
2516
+ partsResult[partKey] = interp;
2517
+ }
2518
+ }
2519
+ if (propAnimIsMotionPath(propAnim)) {
2520
+ const prevTr = prevV.translate;
2521
+ const nextTr = nextV.translate;
2522
+ if (Array.isArray(prevTr) && Array.isArray(nextTr)) {
2523
+ const sample = evaluateMotionPathSegment(
2524
+ prevKf,
2525
+ nextKf,
2526
+ [+prevTr[0], +prevTr[1]],
2527
+ [+nextTr[0], +nextTr[1]],
2528
+ localProgress,
2529
+ !!propAnim.autoOrient
2530
+ );
2531
+ partsResult.translate = [sample.translate[0], sample.translate[1]];
2532
+ if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
2533
+ }
2534
+ }
2535
+ cssValue = composeTransformParts(partsResult, { withUnits: false });
2536
+ cssAttrName = "transform";
1315
2537
  } else if (cssAttrName === "translate") {
1316
2538
  const v = interpolateVec(
1317
2539
  prevV || [0, 0],
@@ -1337,12 +2559,12 @@ function calcPropertyValue(propName, propAnim, progress) {
1337
2559
  cssValue = "scale(" + v.join(",") + ")";
1338
2560
  cssAttrName = "transform";
1339
2561
  } else {
1340
- const num = interpolateNum(
2562
+ const num2 = interpolateNum(
1341
2563
  +(prevV || 0),
1342
2564
  +(nextV || 0),
1343
2565
  localProgress
1344
2566
  );
1345
- cssValue = num;
2567
+ cssValue = num2;
1346
2568
  }
1347
2569
  if (PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
1348
2570
  cssValue = cssValue * 100 + "%";
@@ -1634,6 +2856,9 @@ function createCssKf(kf, t, propName, unsupportedSet) {
1634
2856
  let cssKey = propName;
1635
2857
  if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
1636
2858
  cssValue = toRGBA(value);
2859
+ } else if (propName === "transform" && value !== null && typeof value === "object" && !Array.isArray(value)) {
2860
+ cssValue = composeTransformParts(value, { withUnits: true });
2861
+ cssKey = "transform";
1637
2862
  } else if (TRANSFORM_FN_NAMES.has(propName)) {
1638
2863
  if (Array.isArray(value)) {
1639
2864
  if (propName === "translate") value = value.map((v) => v + "px");
@@ -1650,28 +2875,59 @@ function createCssKf(kf, t, propName, unsupportedSet) {
1650
2875
  cssKf[cssKey] = cssValue;
1651
2876
  return cssKf;
1652
2877
  }
2878
+ function clipKeyframesToDuration(propName, keyframes, duration) {
2879
+ var _a, _b, _c, _d, _e;
2880
+ const result = [];
2881
+ for (let i = 0; i < keyframes.length; i++) {
2882
+ const kf = keyframes[i];
2883
+ const t = (_a = kf.t) != null ? _a : 0;
2884
+ if (t < 0) {
2885
+ const next = keyframes[i + 1];
2886
+ if (next && ((_b = next.t) != null ? _b : 0) >= 0) {
2887
+ const nextT = (_c = next.t) != null ? _c : 0;
2888
+ const localFrac = (0 - t) / (nextT - t);
2889
+ const easedFrac = kf.e ? cubicBezier(kf.e)(localFrac) : localFrac;
2890
+ const { right: rightEasing } = splitEasing(kf.e, localFrac);
2891
+ result.push({ t: 0, v: interpolateValue(propName, kf.v, next.v, easedFrac), e: rightEasing });
2892
+ }
2893
+ continue;
2894
+ }
2895
+ if (t > duration) {
2896
+ const prev = keyframes[i - 1];
2897
+ if (prev && ((_d = prev.t) != null ? _d : 0) <= duration) {
2898
+ const prevT = (_e = prev.t) != null ? _e : 0;
2899
+ const localFrac = (duration - prevT) / (t - prevT);
2900
+ const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
2901
+ const { left: leftEasing } = splitEasing(prev.e, localFrac);
2902
+ if (result.length > 0) result[result.length - 1] = __spreadProps(__spreadValues({}, result[result.length - 1]), { e: leftEasing });
2903
+ result.push({ t: duration, v: interpolateValue(propName, prev.v, kf.v, easedFrac), e: void 0 });
2904
+ }
2905
+ break;
2906
+ }
2907
+ result.push(kf);
2908
+ }
2909
+ return result;
2910
+ }
1653
2911
  function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
1654
- var _a, _b;
2912
+ var _a;
1655
2913
  const result = /* @__PURE__ */ new Map();
1656
2914
  for (const [propName, propAnim] of Object.entries(animDef)) {
1657
- const keyframes = propAnim.kfs || propAnim.keyframes || [];
2915
+ const duration = config.duration || 1;
2916
+ const clippedKeyframes = clipKeyframesToDuration(propName, propAnim.kfs || propAnim.keyframes || [], duration);
1658
2917
  const cssKeyframes = [];
1659
- for (let i = 0; i < keyframes.length; i++) {
1660
- const kf = keyframes[i];
1661
- let t = (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
1662
- t = clamp(t / (config.duration || 1), 0, 1);
2918
+ for (let i = 0; i < clippedKeyframes.length; i++) {
2919
+ const kf = clippedKeyframes[i];
2920
+ const t = clamp(((_a = kf.t) != null ? _a : 0) / duration, 0, 1);
1663
2921
  const cssKf = createCssKf(kf, t, propName, unsupportedSet);
1664
2922
  if (i === 0 && (cssKf.offset || 0) > 0) {
1665
- cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
1666
- offset: 0
1667
- }));
2923
+ cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), { offset: 0 }));
1668
2924
  }
1669
2925
  cssKeyframes.push(cssKf);
1670
- if (i === keyframes.length - 1 && (cssKf.offset || 0) < 1) {
1671
- cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
1672
- offset: 1
1673
- }));
1674
- }
2926
+ }
2927
+ if (cssKeyframes.length > 0 && (cssKeyframes[cssKeyframes.length - 1].offset || 0) < 1) {
2928
+ cssKeyframes.push(__spreadProps(__spreadValues({}, cssKeyframes[cssKeyframes.length - 1]), {
2929
+ offset: 1
2930
+ }));
1675
2931
  }
1676
2932
  if (cssKeyframes.length > 0) {
1677
2933
  result.set(propName, cssKeyframes);
@@ -1680,6 +2936,7 @@ function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
1680
2936
  return result;
1681
2937
  }
1682
2938
  function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs) {
2939
+ var _a;
1683
2940
  const config = getAnimatorConfig(doc) || {};
1684
2941
  const bindings = getNormalisedBindings(doc);
1685
2942
  if (!rootElement) {
@@ -1717,7 +2974,11 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
1717
2974
  const effectOptions = {
1718
2975
  duration: config.duration,
1719
2976
  delay: positiveDelay,
1720
- fill: config.fill,
2977
+ // Default to 'forwards' so elements hold their final state after the
2978
+ // animation ends — consistent with Lottie and other animation runtimes.
2979
+ // Without this, seeking to the last frame reverts elements to their
2980
+ // pre-animation state (the Web Animations API "after" phase with fill:'none').
2981
+ fill: (_a = config.fill) != null ? _a : "forwards",
1721
2982
  direction: config.direction,
1722
2983
  iterations
1723
2984
  };
@@ -1729,12 +2990,12 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
1729
2990
  const effect = new KeyframeEffect(element, keyframes, effectOptions);
1730
2991
  const anim = new Animation(effect, document.timeline);
1731
2992
  if (callbacks == null ? void 0 : callbacks.onFinish) anim.onfinish = () => {
1732
- var _a;
1733
- return (_a = callbacks.onFinish) == null ? void 0 : _a.call(callbacks);
2993
+ var _a2;
2994
+ return (_a2 = callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
1734
2995
  };
1735
2996
  if (callbacks == null ? void 0 : callbacks.onRemove) anim.onremove = () => {
1736
- var _a;
1737
- return (_a = callbacks.onRemove) == null ? void 0 : _a.call(callbacks);
2997
+ var _a2;
2998
+ return (_a2 = callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
1738
2999
  };
1739
3000
  if (seekPosition) {
1740
3001
  anim.currentTime = seekPosition;
@@ -1755,29 +3016,29 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
1755
3016
  "isReady": () => true,
1756
3017
  "getRootElement": () => rootElement || null,
1757
3018
  "isPlaying": () => {
1758
- var _a;
1759
- return ((_a = animations[0]) == null ? void 0 : _a.playState) === "running";
3019
+ var _a2;
3020
+ return ((_a2 = animations[0]) == null ? void 0 : _a2.playState) === "running";
1760
3021
  },
1761
3022
  "play": () => {
1762
- var _a;
3023
+ var _a2;
1763
3024
  animations.forEach((a) => a.play());
1764
- (_a = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a.call(callbacks);
3025
+ (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
1765
3026
  },
1766
3027
  "pause": () => {
1767
- var _a;
3028
+ var _a2;
1768
3029
  animations.forEach((a) => a.pause());
1769
- (_a = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a.call(callbacks);
3030
+ (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
1770
3031
  },
1771
3032
  "cancel": () => {
1772
- var _a;
3033
+ var _a2;
1773
3034
  animations.forEach((a) => a.cancel());
1774
- (_a = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a.call(callbacks);
3035
+ (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
1775
3036
  },
1776
3037
  "finish": () => {
1777
- var _a;
3038
+ var _a2;
1778
3039
  for (const a of animations) {
1779
3040
  try {
1780
- if (((_a = a.effect) == null ? void 0 : _a.getTiming().iterations) === Infinity) {
3041
+ if (((_a2 = a.effect) == null ? void 0 : _a2.getTiming().iterations) === Infinity) {
1781
3042
  a.effect.updateTiming({ iterations: 1 });
1782
3043
  a.finish();
1783
3044
  a.effect.updateTiming({ iterations: Infinity });
@@ -1794,8 +3055,8 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
1794
3055
  return api;
1795
3056
  },
1796
3057
  "getCurrentTime": () => {
1797
- var _a, _b;
1798
- const res = (_b = (_a = animations[0]) == null ? void 0 : _a.currentTime) != null ? _b : null;
3058
+ var _a2, _b;
3059
+ const res = (_b = (_a2 = animations[0]) == null ? void 0 : _a2.currentTime) != null ? _b : null;
1799
3060
  return res !== null ? +res : null;
1800
3061
  },
1801
3062
  "setCurrentTime": (time) => {
@@ -1852,6 +3113,7 @@ function deepClone(value) {
1852
3113
  return cloned;
1853
3114
  }
1854
3115
  function generateNewIds(doc) {
3116
+ var _a, _b;
1855
3117
  const cloned = deepClone(doc);
1856
3118
  const idMap = /* @__PURE__ */ new Map();
1857
3119
  const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
@@ -1877,6 +3139,8 @@ function generateNewIds(doc) {
1877
3139
  const newId = generateUniqueId();
1878
3140
  idMap.set(oldId, newId);
1879
3141
  node.id = newId;
3142
+ } else if (node.animate) {
3143
+ node.id = generateUniqueId();
1880
3144
  }
1881
3145
  if (Array.isArray(node.children)) {
1882
3146
  for (const child of node.children) {
@@ -1918,23 +3182,21 @@ function generateNewIds(doc) {
1918
3182
  value[styleProp] = replaceUrlRefs(styleValue, idMap);
1919
3183
  }
1920
3184
  }
1921
- } else if (typeof value === "object" && value !== null && key !== ANIMATE_ATTR) {
3185
+ } else if (typeof value === "object" && value !== null) {
1922
3186
  updateRefs(value);
1923
3187
  }
1924
3188
  }
1925
3189
  }
1926
3190
  collectIds(cloned);
1927
3191
  updateRefs(cloned);
1928
- const docBindings = cloned.bindings;
1929
- if (Array.isArray(docBindings)) {
1930
- for (const binding of docBindings) {
1931
- if (binding.id) {
1932
- const newId = idMap.get(binding.id);
1933
- if (newId) {
1934
- binding.id = newId;
1935
- }
1936
- }
3192
+ const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animate;
3193
+ if (docAnimate && typeof docAnimate === "object") {
3194
+ const updatedAnimate = {};
3195
+ for (const [id, anim] of Object.entries(docAnimate)) {
3196
+ const newId = (_b = idMap.get(id)) != null ? _b : id;
3197
+ updatedAnimate[newId] = anim;
1937
3198
  }
3199
+ cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { animate: updatedAnimate });
1938
3200
  }
1939
3201
  return cloned;
1940
3202
  }
@@ -1945,6 +3207,9 @@ function replaceUrlRefs(value, idMap) {
1945
3207
  });
1946
3208
  }
1947
3209
  function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
3210
+ const effectsWarnings = validateNodeEffects(doc);
3211
+ for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
3212
+ doc = applyPlayerEffects(doc).root;
1948
3213
  const animatorConfig = getAnimatorConfig(doc) || {};
1949
3214
  animatorConfig.debug = true;
1950
3215
  let rootElement = null;
@@ -1960,14 +3225,22 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
1960
3225
  }
1961
3226
  return createAnimatorFromConfig(doc, adapter, callbacks, rootElement);
1962
3227
  }
1963
- function createAnimator(docOrUrl, adapter, callbacks, containerElement) {
1964
- if (typeof docOrUrl === "object") {
1965
- return createAnimatorImpl(docOrUrl, adapter, callbacks, containerElement);
3228
+ var PX_ANIMATOR_DATA_KEY = "data";
3229
+ function createAnimator(options) {
3230
+ const { src, data, adapter, callbacks, container } = options;
3231
+ if (data !== void 0 && src !== void 0) {
3232
+ throw new Error("createAnimator: provide either `src` or `data`, not both");
3233
+ }
3234
+ if (data === void 0 && src === void 0) {
3235
+ throw new Error("createAnimator: either `src` or `data` is required");
3236
+ }
3237
+ if (data !== void 0) {
3238
+ return createAnimatorImpl(data, adapter, callbacks, container);
1966
3239
  }
1967
3240
  let animator = null;
1968
- fetch(docOrUrl).then((res) => res.json()).then((json) => {
3241
+ fetch(src).then((res) => res.json()).then((json) => {
1969
3242
  if (isPxElementFileFormat(json)) {
1970
- animator = createAnimatorImpl(json, adapter, callbacks, containerElement);
3243
+ animator = createAnimatorImpl(json, adapter, callbacks, container);
1971
3244
  } else {
1972
3245
  console.error("Invalid animation document format");
1973
3246
  }
@@ -2007,7 +3280,7 @@ function loadTagAnimators() {
2007
3280
  if (!element[PX_ANIM_ATTR_NAME]) {
2008
3281
  const src = element.getAttribute(PX_ANIM_SRC_ATTR_NAME);
2009
3282
  if (src) {
2010
- element[PX_ANIM_ATTR_NAME] = createAnimator(src, void 0, void 0, element);
3283
+ element[PX_ANIM_ATTR_NAME] = createAnimator({ src, container: element });
2011
3284
  }
2012
3285
  }
2013
3286
  }
@@ -2017,19 +3290,258 @@ if (typeof window !== "undefined") {
2017
3290
  window["createAnimator"] = createAnimator;
2018
3291
  window["setupAnimationTriggers"] = setupAnimationTriggers;
2019
3292
  }
3293
+
3294
+ // src/effects/PlayerEffectsUtil.visualModel.ts
3295
+ var IDENTITY = [1, 0, 0, 1, 0, 0];
3296
+ function mul(m, n) {
3297
+ return [
3298
+ m[0] * n[0] + m[2] * n[1],
3299
+ m[1] * n[0] + m[3] * n[1],
3300
+ m[0] * n[2] + m[2] * n[3],
3301
+ m[1] * n[2] + m[3] * n[3],
3302
+ m[0] * n[4] + m[2] * n[5] + m[4],
3303
+ m[1] * n[4] + m[3] * n[5] + m[5]
3304
+ ];
3305
+ }
3306
+ var translateM = (x, y) => [1, 0, 0, 1, x, y];
3307
+ var scaleM = (sx, sy) => [sx, 0, 0, sy, 0, 0];
3308
+ function rotateM(deg) {
3309
+ const r = deg * Math.PI / 180;
3310
+ return [Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0];
3311
+ }
3312
+ var skewXM = (deg) => [1, 0, Math.tan(deg * Math.PI / 180), 1, 0, 0];
3313
+ var skewYM = (deg) => [1, Math.tan(deg * Math.PI / 180), 0, 1, 0, 0];
3314
+ function parseTransformString(s) {
3315
+ let m = IDENTITY;
3316
+ const re = /(translate|rotate|scale|matrix|skewX|skewY)\(([^)]*)\)/g;
3317
+ let hit;
3318
+ while (hit = re.exec(s)) {
3319
+ const fn = hit[1];
3320
+ const a = hit[2].split(/[\s,]+/).filter(Boolean).map(Number);
3321
+ if (fn === "translate") m = mul(m, translateM(a[0] || 0, a[1] || 0));
3322
+ else if (fn === "scale") m = mul(m, scaleM(a[0], a.length > 1 ? a[1] : a[0]));
3323
+ else if (fn === "rotate") m = mul(m, rotateM(a[0]));
3324
+ else if (fn === "skewX") m = mul(m, skewXM(a[0]));
3325
+ else if (fn === "skewY") m = mul(m, skewYM(a[0]));
3326
+ else if (fn === "matrix") m = mul(m, [a[0], a[1], a[2], a[3], a[4], a[5]]);
3327
+ }
3328
+ return m;
3329
+ }
3330
+ function partsToMatrix(p) {
3331
+ let m = IDENTITY;
3332
+ if (p.translate) m = mul(m, translateM(p.translate[0], p.translate[1]));
3333
+ const pivot = p.origin && (p.rotate !== void 0 || p.scale);
3334
+ if (pivot) m = mul(m, translateM(p.origin[0], p.origin[1]));
3335
+ if (p.rotate !== void 0) m = mul(m, rotateM(p.rotate));
3336
+ if (p.scale) m = mul(m, scaleM(p.scale[0], p.scale[1]));
3337
+ if (pivot) m = mul(m, translateM(-p.origin[0], -p.origin[1]));
3338
+ return m;
3339
+ }
3340
+ function lerp(a, b, f) {
3341
+ return a + (b - a) * f;
3342
+ }
3343
+ function interpParts(kfs, t) {
3344
+ var _a, _b, _c, _d, _e, _f, _g;
3345
+ if (!kfs.length) return {};
3346
+ if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value || {};
3347
+ if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value || {};
3348
+ let i = 0;
3349
+ while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
3350
+ const a = kfs[i], b = kfs[i + 1];
3351
+ const f = (t - ((_d = a.time) != null ? _d : 0)) / (((_e = b.time) != null ? _e : 0) - ((_f = a.time) != null ? _f : 0) || 1);
3352
+ const va = a.value || {}, vb = b.value || {};
3353
+ const out = {};
3354
+ if (va.translate && vb.translate) out.translate = [lerp(va.translate[0], vb.translate[0], f), lerp(va.translate[1], vb.translate[1], f)];
3355
+ else out.translate = va.translate || vb.translate;
3356
+ if (va.rotate !== void 0 && vb.rotate !== void 0) out.rotate = lerp(va.rotate, vb.rotate, f);
3357
+ else out.rotate = (_g = va.rotate) != null ? _g : vb.rotate;
3358
+ if (va.scale && vb.scale) out.scale = [lerp(va.scale[0], vb.scale[0], f), lerp(va.scale[1], vb.scale[1], f)];
3359
+ else out.scale = va.scale || vb.scale;
3360
+ out.origin = va.origin || vb.origin;
3361
+ return out;
3362
+ }
3363
+ function evalTransformValue(v, t) {
3364
+ if (v === void 0 || v === null) return IDENTITY;
3365
+ if (typeof v === "string") return parseTransformString(v);
3366
+ if (v.keyframes) return partsToMatrix(interpParts(v.keyframes, t));
3367
+ if (v.value) return partsToMatrix(v.value);
3368
+ return IDENTITY;
3369
+ }
3370
+ function nodeMatrix(node, t) {
3371
+ if (node.animate && node.animate.transform) return evalTransformValue(node.animate.transform, t);
3372
+ if (node.transform !== void 0) return evalTransformValue(node.transform, t);
3373
+ return IDENTITY;
3374
+ }
3375
+ function evalScalar(animated, staticVal, fallback, t) {
3376
+ var _a, _b, _c, _d, _e, _f;
3377
+ if (animated && animated.keyframes && animated.keyframes.length) {
3378
+ const kfs = animated.keyframes;
3379
+ if (t <= ((_a = kfs[0].time) != null ? _a : 0)) return kfs[0].value;
3380
+ if (t >= ((_b = kfs[kfs.length - 1].time) != null ? _b : 0)) return kfs[kfs.length - 1].value;
3381
+ let i = 0;
3382
+ while (i < kfs.length - 1 && ((_c = kfs[i + 1].time) != null ? _c : 0) < t) i++;
3383
+ const a = kfs[i], b = kfs[i + 1];
3384
+ const f = (t - ((_d = a.time) != null ? _d : 0)) / (((_e = b.time) != null ? _e : 0) - ((_f = a.time) != null ? _f : 0) || 1);
3385
+ return lerp(a.value, b.value, f);
3386
+ }
3387
+ return staticVal !== void 0 ? Number(staticVal) : fallback;
3388
+ }
3389
+ var CONTAINER_TYPES = /* @__PURE__ */ new Set(["svg", "g", "symbol"]);
3390
+ var SKIP_TYPES = /* @__PURE__ */ new Set(["defs", "mask", "clipPath", "title"]);
3391
+ function buildIdMap(node, map) {
3392
+ var _a;
3393
+ if (typeof node.id === "string") map.set(node.id, node);
3394
+ (_a = node.children) == null ? void 0 : _a.forEach((c) => buildIdMap(c, map));
3395
+ }
3396
+ function num(v) {
3397
+ return v === void 0 || v === null ? 0 : Number(v);
3398
+ }
3399
+ function round(n) {
3400
+ return Math.round(n * 100) / 100 + 0;
3401
+ }
3402
+ function geomKey(node) {
3403
+ var _a;
3404
+ switch (node.type) {
3405
+ case "rect":
3406
+ return num(node.width) + "," + num(node.height) + "," + num(node.x) + "," + num(node.y);
3407
+ case "ellipse":
3408
+ return num(node.rx) + "," + num(node.ry) + "," + num(node.cx) + "," + num(node.cy);
3409
+ case "circle":
3410
+ return num(node.r) + "," + num(node.cx) + "," + num(node.cy);
3411
+ case "path":
3412
+ return String((_a = node.d) != null ? _a : "");
3413
+ default:
3414
+ return "";
3415
+ }
3416
+ }
3417
+ function describePrimitive(node, m, t) {
3418
+ var _a, _b, _c, _d, _e;
3419
+ const fill = (_a = node.fill) != null ? _a : "";
3420
+ const stroke = (_b = node.stroke) != null ? _b : "";
3421
+ const sw = (_d = (_c = node["stroke-width"]) != null ? _c : node.strokeWidth) != null ? _d : "";
3422
+ const opacity = round(evalScalar((_e = node.animate) == null ? void 0 : _e.opacity, node.opacity, 1, t));
3423
+ const masked = node.mask ? 1 : 0;
3424
+ const mat = m.map(round).join(",");
3425
+ return node.type + "|" + geomKey(node) + "|[" + mat + "]|f:" + fill + "|s:" + stroke + "|sw:" + (num(sw) || "") + "|o:" + opacity + "|m:" + masked;
3426
+ }
3427
+ function flatten(node, parent, t, idMap, out) {
3428
+ var _a;
3429
+ const type = node.type || "";
3430
+ if (SKIP_TYPES.has(type)) return;
3431
+ const m = mul(parent, nodeMatrix(node, t));
3432
+ if (type === "use") {
3433
+ const targetId = typeof node.href === "string" ? node.href.replace(/^#/, "") : "";
3434
+ const target = idMap.get(targetId);
3435
+ const useM = mul(m, translateM(num(node.x), num(node.y)));
3436
+ if (target) flatten(target, useM, t, idMap, out);
3437
+ else out.push("UNRESOLVED_USE:#" + targetId);
3438
+ return;
3439
+ }
3440
+ if (CONTAINER_TYPES.has(type)) {
3441
+ (_a = node.children) == null ? void 0 : _a.forEach((c) => flatten(c, m, t, idMap, out));
3442
+ return;
3443
+ }
3444
+ out.push(describePrimitive(node, m, t));
3445
+ }
3446
+ function collectSampleTimes(node, into) {
3447
+ var _a;
3448
+ into.add(0);
3449
+ const scanAnim = (anim) => {
3450
+ var _a2;
3451
+ if (!anim || typeof anim !== "object") return;
3452
+ for (const key of Object.keys(anim)) {
3453
+ const kfs = (_a2 = anim[key]) == null ? void 0 : _a2.keyframes;
3454
+ if (Array.isArray(kfs)) kfs.forEach((kf) => {
3455
+ var _a3;
3456
+ return into.add((_a3 = kf.time) != null ? _a3 : 0);
3457
+ });
3458
+ }
3459
+ };
3460
+ scanAnim(node.animate);
3461
+ if (node.transform && typeof node.transform === "object" && node.transform.keyframes) {
3462
+ node.transform.keyframes.forEach((kf) => {
3463
+ var _a2;
3464
+ return into.add((_a2 = kf.time) != null ? _a2 : 0);
3465
+ });
3466
+ }
3467
+ (_a = node.children) == null ? void 0 : _a.forEach((c) => collectSampleTimes(c, into));
3468
+ }
3469
+ function visualModelAt(root, t) {
3470
+ const idMap = /* @__PURE__ */ new Map();
3471
+ buildIdMap(root, idMap);
3472
+ const out = [];
3473
+ flatten(root, IDENTITY, t, idMap, out);
3474
+ return out.sort();
3475
+ }
3476
+ function diffInEffect(a, b) {
3477
+ const times = /* @__PURE__ */ new Set();
3478
+ collectSampleTimes(a, times);
3479
+ collectSampleTimes(b, times);
3480
+ const diffs = [];
3481
+ for (const t of Array.from(times).sort((x, y) => x - y)) {
3482
+ const ma = visualModelAt(a, t);
3483
+ const mb = visualModelAt(b, t);
3484
+ const onlyInA = subtractMultiset(ma, mb);
3485
+ const onlyInB = subtractMultiset(mb, ma);
3486
+ if (onlyInA.length || onlyInB.length) diffs.push({ time: t, onlyInA, onlyInB });
3487
+ }
3488
+ return diffs;
3489
+ }
3490
+ function subtractMultiset(a, b) {
3491
+ const counts = /* @__PURE__ */ new Map();
3492
+ for (const x of b) counts.set(x, (counts.get(x) || 0) + 1);
3493
+ const extra = [];
3494
+ for (const x of a) {
3495
+ const c = counts.get(x) || 0;
3496
+ if (c > 0) counts.set(x, c - 1);
3497
+ else extra.push(x);
3498
+ }
3499
+ return extra;
3500
+ }
2020
3501
  export {
2021
3502
  COLOUR_ATTR_NAMES,
3503
+ PX_ANIMATOR_DATA_KEY,
2022
3504
  PX_ANIM_ATTR_NAME,
2023
3505
  PX_ANIM_SRC_ATTR_NAME,
3506
+ PX_TRANSFORM_PART_KEYS,
3507
+ PxAnimatedSvgDocumentSchema,
3508
+ PxAnimationDefinitionSchema,
3509
+ PxAnimatorConfigSchema,
3510
+ PxAttrValueSchema,
3511
+ PxBezierPathSchema,
3512
+ PxBindingSchema,
3513
+ PxDefsSchema,
3514
+ PxEasingOrRefSchema,
3515
+ PxEffectsSchema,
3516
+ PxElementAnimationSchema,
3517
+ PxKeyframeSchema,
3518
+ PxLoopSchema,
3519
+ PxMaskedByEffectSchema,
3520
+ PxNodeBase,
3521
+ PxNodeSchema,
3522
+ PxPropertyAnimationSchema,
3523
+ PxRefEffectSchema,
3524
+ PxRepeaterEffectSchema,
3525
+ PxRetimeEffectSchema,
3526
+ PxSvgNodeExtra,
3527
+ PxTransformPartsSchema,
3528
+ PxTransformValueSchema,
3529
+ PxTransformationEffectSchema,
3530
+ PxTriggerSchema,
3531
+ PxTrimPathEffectSchema,
2024
3532
  STYLE_ATTR_NAMES,
2025
3533
  TRANSFORM_FN_NAMES,
3534
+ applyPlayerEffects,
2026
3535
  calcAnimationValues,
2027
3536
  camelCaseToKebabWordIfNeeded,
3537
+ collectSampleTimes,
2028
3538
  createAnimator,
2029
3539
  createAnimatorImpl,
2030
3540
  createBasicFrameLoopAnimator,
2031
3541
  createFrameLoopAnimator,
2032
3542
  createWebApiAnimator,
3543
+ describeSchema,
3544
+ diffInEffect,
2033
3545
  generateNewIds,
2034
3546
  getAnimatorConfig,
2035
3547
  getBindings,
@@ -2040,8 +3552,12 @@ export {
2040
3552
  isPxElementFileFormatDeep,
2041
3553
  loadTagAnimators,
2042
3554
  getNormalisedBindings as normalizeDocument,
3555
+ px,
2043
3556
  renderNode,
3557
+ schemaKeys,
2044
3558
  setupAnimationTriggers,
2045
- toRGBA
3559
+ toRGBA,
3560
+ validateNodeEffects,
3561
+ visualModelAt
2046
3562
  };
2047
3563
  //# sourceMappingURL=index.js.map