@pixodesk/svg-animator-core 1.0.39 → 1.0.41

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.
@@ -0,0 +1,4595 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __pow = Math.pow;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ var __objRest = (source, exclude) => {
22
+ var target = {};
23
+ for (var prop in source)
24
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
25
+ target[prop] = source[prop];
26
+ if (source != null && __getOwnPropSymbols)
27
+ for (var prop of __getOwnPropSymbols(source)) {
28
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
29
+ target[prop] = source[prop];
30
+ }
31
+ return target;
32
+ };
33
+
34
+ // src/schema/PxSchema.ts
35
+ var PX_UNKNOWN_KEY_ERROR = "unexpected extra key";
36
+ function pathStr(path) {
37
+ if (!path.length) return ".";
38
+ let result = "";
39
+ for (const seg of path) {
40
+ if (seg.startsWith("[")) result += seg;
41
+ else result += (result ? "." : "") + seg;
42
+ }
43
+ return result;
44
+ }
45
+ var Base = class {
46
+ _canSanitize(raw) {
47
+ return this.isValid(raw);
48
+ }
49
+ optional() {
50
+ return new Optional(this);
51
+ }
52
+ };
53
+ var Optional = class extends Base {
54
+ constructor(inner) {
55
+ super();
56
+ this.inner = inner;
57
+ this._default = void 0;
58
+ }
59
+ sanitize(raw) {
60
+ if (raw === void 0 || raw === null) return void 0;
61
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
62
+ }
63
+ isValid(raw, ctx, path) {
64
+ if (raw === void 0 || raw === null) return true;
65
+ return this.inner.isValid(raw, ctx, path);
66
+ }
67
+ _canSanitize(raw) {
68
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
69
+ }
70
+ };
71
+ var Str = class extends Base {
72
+ constructor(_default = "") {
73
+ super();
74
+ this._default = _default;
75
+ }
76
+ sanitize(raw) {
77
+ return typeof raw === "string" ? raw : this._default;
78
+ }
79
+ isValid(raw, ctx, path) {
80
+ if (typeof raw === "string") return true;
81
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
82
+ return false;
83
+ }
84
+ };
85
+ var Num = class extends Base {
86
+ constructor(_default = 0) {
87
+ super();
88
+ this._default = _default;
89
+ }
90
+ sanitize(raw) {
91
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
92
+ }
93
+ isValid(raw, ctx, path) {
94
+ if (typeof raw === "number" && isFinite(raw)) return true;
95
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
96
+ return false;
97
+ }
98
+ };
99
+ var Bool = class extends Base {
100
+ constructor(_default = false) {
101
+ super();
102
+ this._default = _default;
103
+ }
104
+ sanitize(raw) {
105
+ return typeof raw === "boolean" ? raw : this._default;
106
+ }
107
+ isValid(raw, ctx, path) {
108
+ if (typeof raw === "boolean") return true;
109
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
110
+ return false;
111
+ }
112
+ };
113
+ var Literal = class extends Base {
114
+ constructor(value) {
115
+ super();
116
+ this.value = value;
117
+ this._default = value;
118
+ }
119
+ sanitize(raw) {
120
+ return raw === this.value ? this.value : this._default;
121
+ }
122
+ isValid(raw, ctx, path) {
123
+ if (raw === this.value) return true;
124
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
125
+ return false;
126
+ }
127
+ };
128
+ var Enum = class extends Base {
129
+ constructor(values, defaultVal) {
130
+ super();
131
+ this.values = values;
132
+ this._default = defaultVal != null ? defaultVal : values[0];
133
+ }
134
+ sanitize(raw) {
135
+ return this.values.includes(raw) ? raw : this._default;
136
+ }
137
+ isValid(raw, ctx, path) {
138
+ if (this.values.includes(raw)) return true;
139
+ 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));
140
+ return false;
141
+ }
142
+ };
143
+ var UNION_MEMBER_ERROR_LIMIT = 4;
144
+ var Union = class extends Base {
145
+ constructor(schemas, defaultVal) {
146
+ super();
147
+ this.schemas = schemas;
148
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Union from Tuple. */
149
+ this._kind = "union";
150
+ this._default = defaultVal != null ? defaultVal : schemas[0]._default;
151
+ }
152
+ sanitize(raw) {
153
+ for (const s of this.schemas) {
154
+ if (s.isValid(raw)) return s.sanitize(raw);
155
+ }
156
+ return this._default;
157
+ }
158
+ isValid(raw, ctx, path) {
159
+ var _a2;
160
+ const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
161
+ if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
162
+ if (!ctx) return false;
163
+ const base = pathStr(path != null ? path : []);
164
+ ctx.errors.push(base + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
165
+ let best;
166
+ let bestDepth = -1;
167
+ const leafExpectations = [];
168
+ for (const member of this.schemas) {
169
+ const sink = { errors: [], warnings: [], strict: ctx.strict };
170
+ member.isValid(raw, sink, path ? [...path] : void 0);
171
+ if (!sink.errors.length) continue;
172
+ const depth = Math.max(...sink.errors.map((e) => e.slice(0, e.indexOf(":")).length));
173
+ if (depth > bestDepth || depth === bestDepth && best && sink.errors.length < best.length) {
174
+ bestDepth = depth;
175
+ best = sink.errors;
176
+ }
177
+ if (depth <= base.length) {
178
+ for (const e of sink.errors) {
179
+ const m = /: expected (.+?), got /.exec(e);
180
+ if (m && !leafExpectations.includes(m[1])) leafExpectations.push(m[1]);
181
+ }
182
+ }
183
+ }
184
+ if (best && bestDepth > base.length) {
185
+ for (const e of best.slice(0, UNION_MEMBER_ERROR_LIMIT)) {
186
+ if (!ctx.errors.includes(e)) ctx.errors.push(e);
187
+ }
188
+ } else if (leafExpectations.length) {
189
+ ctx.errors.push(base + ": expected " + leafExpectations.join(" | "));
190
+ }
191
+ return false;
192
+ }
193
+ _canSanitize(raw) {
194
+ return this.schemas.some((s) => s._canSanitize(raw));
195
+ }
196
+ };
197
+ var DiscriminatedUnion = class extends Base {
198
+ constructor(_key, _schemas, defaultVal) {
199
+ var _a2;
200
+ super();
201
+ this._key = _key;
202
+ this._schemas = _schemas;
203
+ /** Structural tag read by {@link describeSchema}. */
204
+ this._kind = "discriminatedUnion";
205
+ this._default = defaultVal != null ? defaultVal : _schemas[0]._default;
206
+ this._map = /* @__PURE__ */ new Map();
207
+ for (const s of _schemas) {
208
+ const keySchema = s._shape[_key];
209
+ if (!keySchema) continue;
210
+ const literal = (_a2 = keySchema.inner) != null ? _a2 : keySchema;
211
+ this._map.set(literal._default, s);
212
+ if (keySchema.inner) this._absentMember = s;
213
+ }
214
+ }
215
+ _findSchema(raw) {
216
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
217
+ const val = raw[this._key];
218
+ if (val === void 0 || val === null) return this._absentMember;
219
+ return this._map.get(val);
220
+ }
221
+ sanitize(raw) {
222
+ var _a2;
223
+ return ((_a2 = this._findSchema(raw)) != null ? _a2 : this._schemas[0]).sanitize(raw);
224
+ }
225
+ isValid(raw, ctx, path) {
226
+ const schema = this._findSchema(raw);
227
+ if (!schema) {
228
+ const val = raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw[this._key] : void 0;
229
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no discriminated union member matched " + this._key + "=" + JSON.stringify(val));
230
+ return false;
231
+ }
232
+ return schema.isValid(raw, ctx, path);
233
+ }
234
+ _canSanitize(raw) {
235
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return false;
236
+ const schema = this._findSchema(raw);
237
+ return schema ? schema._canSanitize(raw) : this._schemas[0]._canSanitize(raw);
238
+ }
239
+ };
240
+ var Obj = class extends Base {
241
+ constructor(_shape) {
242
+ super();
243
+ this._shape = _shape;
244
+ const d = {};
245
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
246
+ this._default = d;
247
+ }
248
+ sanitize(raw) {
249
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
250
+ const out = {};
251
+ for (const key of Object.keys(this._shape)) {
252
+ const v = this._shape[key].sanitize(src[key]);
253
+ if (v !== void 0) out[key] = v;
254
+ }
255
+ return out;
256
+ }
257
+ isValid(raw, ctx, path) {
258
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
259
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
260
+ return false;
261
+ }
262
+ const obj = raw;
263
+ const p = path != null ? path : [];
264
+ let ok = true;
265
+ for (const key of Object.keys(this._shape)) {
266
+ p.push(key);
267
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
268
+ p.pop();
269
+ }
270
+ if (ctx == null ? void 0 : ctx.strict) {
271
+ for (const key of Object.keys(obj)) {
272
+ if (key in this._shape) continue;
273
+ if (obj[key] === void 0) continue;
274
+ p.push(key);
275
+ ctx.errors.push(pathStr(p) + ": " + PX_UNKNOWN_KEY_ERROR);
276
+ p.pop();
277
+ ok = false;
278
+ }
279
+ }
280
+ return ok;
281
+ }
282
+ _canSanitize(raw) {
283
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
284
+ }
285
+ };
286
+ var OpenObj = class extends Base {
287
+ constructor(_shape, _openSchema) {
288
+ super();
289
+ this._shape = _shape;
290
+ this._openSchema = _openSchema;
291
+ const d = {};
292
+ for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
293
+ this._default = d;
294
+ }
295
+ sanitize(raw) {
296
+ const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
297
+ const out = __spreadValues({}, src);
298
+ for (const key of Object.keys(this._shape)) {
299
+ const v = this._shape[key].sanitize(src[key]);
300
+ if (v !== void 0) out[key] = v;
301
+ }
302
+ if (this._openSchema) {
303
+ for (const key of Object.keys(src)) {
304
+ if (!(key in this._shape)) out[key] = this._openSchema.sanitize(src[key]);
305
+ }
306
+ }
307
+ return out;
308
+ }
309
+ isValid(raw, ctx, path) {
310
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
311
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object, got " + (Array.isArray(raw) ? "array" : typeof raw));
312
+ return false;
313
+ }
314
+ const obj = raw;
315
+ const p = path != null ? path : [];
316
+ let ok = true;
317
+ for (const key of Object.keys(this._shape)) {
318
+ p.push(key);
319
+ if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;
320
+ p.pop();
321
+ }
322
+ if (this._openSchema) {
323
+ for (const key of Object.keys(obj)) {
324
+ if (key in this._shape) continue;
325
+ p.push(key);
326
+ if (!this._openSchema.isValid(obj[key], ctx, p)) ok = false;
327
+ p.pop();
328
+ }
329
+ }
330
+ return ok;
331
+ }
332
+ _canSanitize(raw) {
333
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
334
+ }
335
+ };
336
+ var Arr = class extends Base {
337
+ constructor(item) {
338
+ super();
339
+ this.item = item;
340
+ this._default = [];
341
+ }
342
+ sanitize(raw) {
343
+ if (!Array.isArray(raw)) return [];
344
+ const out = [];
345
+ for (const el of raw) {
346
+ if (this.item._canSanitize(el)) out.push(this.item.sanitize(el));
347
+ }
348
+ return out;
349
+ }
350
+ isValid(raw, ctx, path) {
351
+ if (!Array.isArray(raw)) {
352
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected array, got " + typeof raw);
353
+ return false;
354
+ }
355
+ const p = path != null ? path : [];
356
+ let ok = true;
357
+ for (let i = 0; i < raw.length; i++) {
358
+ p.push("[" + i + "]");
359
+ if (!this.item.isValid(raw[i], ctx, p)) ok = false;
360
+ p.pop();
361
+ }
362
+ return ok;
363
+ }
364
+ _canSanitize(raw) {
365
+ return Array.isArray(raw);
366
+ }
367
+ };
368
+ var Rec = class extends Base {
369
+ constructor(value) {
370
+ super();
371
+ this.value = value;
372
+ /** Structural tag read by {@link describeSchema}. */
373
+ this._kind = "record";
374
+ this._default = {};
375
+ }
376
+ sanitize(raw) {
377
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
378
+ const out = {};
379
+ for (const [k, v] of Object.entries(raw)) {
380
+ if (this.value._canSanitize(v)) out[k] = this.value.sanitize(v);
381
+ }
382
+ return out;
383
+ }
384
+ isValid(raw, ctx, path) {
385
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
386
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected object/record, got " + (Array.isArray(raw) ? "array" : typeof raw));
387
+ return false;
388
+ }
389
+ const p = path != null ? path : [];
390
+ let ok = true;
391
+ for (const [k, v] of Object.entries(raw)) {
392
+ p.push(k);
393
+ if (!this.value.isValid(v, ctx, p)) ok = false;
394
+ p.pop();
395
+ }
396
+ return ok;
397
+ }
398
+ _canSanitize(raw) {
399
+ return !!raw && typeof raw === "object" && !Array.isArray(raw);
400
+ }
401
+ };
402
+ var Any = class extends Base {
403
+ constructor() {
404
+ super(...arguments);
405
+ this._default = void 0;
406
+ }
407
+ sanitize(raw) {
408
+ return raw;
409
+ }
410
+ isValid(_raw, _ctx, _path) {
411
+ return true;
412
+ }
413
+ _canSanitize(_raw) {
414
+ return true;
415
+ }
416
+ };
417
+ var Defined = class extends Base {
418
+ constructor() {
419
+ super(...arguments);
420
+ this._default = void 0;
421
+ }
422
+ sanitize(raw) {
423
+ return raw;
424
+ }
425
+ isValid(raw, ctx, path) {
426
+ if (raw !== void 0) return true;
427
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": required value is missing");
428
+ return false;
429
+ }
430
+ _canSanitize(raw) {
431
+ return raw !== void 0;
432
+ }
433
+ };
434
+ var Lazy = class extends Base {
435
+ constructor(fn, _default) {
436
+ super();
437
+ this.fn = fn;
438
+ this._default = _default;
439
+ this.resolved = null;
440
+ }
441
+ get schema() {
442
+ var _a2;
443
+ return (_a2 = this.resolved) != null ? _a2 : this.resolved = this.fn();
444
+ }
445
+ sanitize(raw) {
446
+ return this.schema.sanitize(raw);
447
+ }
448
+ isValid(raw, ctx, path) {
449
+ return this.schema.isValid(raw, ctx, path);
450
+ }
451
+ _canSanitize(raw) {
452
+ return this.schema._canSanitize(raw);
453
+ }
454
+ };
455
+ var Tuple = class extends Base {
456
+ constructor(schemas) {
457
+ super();
458
+ this.schemas = schemas;
459
+ /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Tuple from Union. */
460
+ this._kind = "tuple";
461
+ this._default = schemas.map((s) => s._default);
462
+ }
463
+ sanitize(raw) {
464
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) return this._default;
465
+ return this.schemas.map((s, i) => s.sanitize(raw[i]));
466
+ }
467
+ isValid(raw, ctx, path) {
468
+ if (!Array.isArray(raw) || raw.length !== this.schemas.length) {
469
+ 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));
470
+ return false;
471
+ }
472
+ const p = path != null ? path : [];
473
+ let ok = true;
474
+ for (let i = 0; i < this.schemas.length; i++) {
475
+ p.push("[" + i + "]");
476
+ if (!this.schemas[i].isValid(raw[i], ctx, p)) ok = false;
477
+ p.pop();
478
+ }
479
+ return ok;
480
+ }
481
+ // Require exact length so wrong-length arrays are dropped rather than repaired to default.
482
+ _canSanitize(raw) {
483
+ return Array.isArray(raw) && raw.length === this.schemas.length;
484
+ }
485
+ };
486
+ function implementsInterface() {
487
+ return (schema) => schema;
488
+ }
489
+ function schemaKeys(schema) {
490
+ return Object.fromEntries(
491
+ Object.keys(schema["_shape"]).map((k) => [k, k])
492
+ );
493
+ }
494
+ function describeSchema(schema) {
495
+ var _a2;
496
+ const s = schema;
497
+ switch (s._kind) {
498
+ case "union":
499
+ return { kind: "union", members: s.schemas };
500
+ case "discriminatedUnion":
501
+ return { kind: "discriminatedUnion", key: s._key, members: s._schemas };
502
+ case "record":
503
+ return { kind: "record", value: s.value };
504
+ case "tuple":
505
+ return { kind: "tuple", items: s.schemas };
506
+ }
507
+ if ("_shape" in s) return { kind: "shape", shape: s._shape, openValue: s._openSchema };
508
+ if ("item" in s) return { kind: "array", item: s.item };
509
+ if ("inner" in s) return { kind: "optional", inner: s.inner };
510
+ if ("fn" in s) return { kind: "lazy", resolved: (_a2 = s.resolved) != null ? _a2 : s.resolved = s.fn() };
511
+ return { kind: "leaf" };
512
+ }
513
+ var px = {
514
+ /** Matches a string. Default: '' or provided value. */
515
+ string: (defaultVal = "") => new Str(defaultVal),
516
+ /** Matches a finite number. Default: 0 or provided value. */
517
+ number: (defaultVal = 0) => new Num(defaultVal),
518
+ /** Matches a boolean. Default: false or provided value. */
519
+ boolean: (defaultVal = false) => new Bool(defaultVal),
520
+ /** Matches one exact primitive value; its default is the value itself. */
521
+ literal: (value) => new Literal(value),
522
+ /** Matches one of a fixed set of string/number values. Default: first value. */
523
+ enum: (values, defaultVal) => new Enum(values, defaultVal),
524
+ /**
525
+ * Returns the first schema whose isValid passes.
526
+ * TypeScript infers the union of all member types automatically.
527
+ */
528
+ union: (schemas, defaultVal) => new Union(schemas, defaultVal),
529
+ /**
530
+ * Discriminated union — reads `raw[key]`, finds the member schema whose
531
+ * literal at `key` matches, then delegates sanitize/isValid to that member.
532
+ * Each member must be an object schema with a `px.literal(...)` at `key`.
533
+ * TypeScript infers the union of all member types automatically.
534
+ */
535
+ discriminatedUnion: (key, schemas) => new DiscriminatedUnion(key, schemas),
536
+ /** Typed object — unknown keys are stripped. Required fields fall back to their default. */
537
+ object: (shape) => new Obj(shape),
538
+ /**
539
+ * Open object — validates known keys; passes unknown keys through as-is,
540
+ * or validates/sanitizes them against `openSchema` when provided.
541
+ */
542
+ openObject: (shape, openSchema) => new OpenObj(shape, openSchema),
543
+ /**
544
+ * Creates a new closed object schema by merging a base schema's shape with additional fields.
545
+ * The base can be the result of px.object() or px.openObject() — anything with a _shape property.
546
+ *
547
+ * @example
548
+ * const PxSvgNodeSchema = px.extendedObject(PxNodeBaseSchema, { width: px.number().optional() });
549
+ */
550
+ extendedObject: (base, extra) => new Obj(__spreadValues(__spreadValues({}, base._shape), extra)),
551
+ /** Array whose unrecoverable items are filtered out. Default: []. */
552
+ array: (item) => new Arr(item),
553
+ /** String-keyed record whose unrecoverable values are dropped. Default: {}. */
554
+ record: (value) => new Rec(value),
555
+ /** Passes anything through unchanged — always valid. */
556
+ any: () => new Any(),
557
+ /** Anything EXCEPT `undefined` — an open type whose presence is required (V6). */
558
+ defined: () => new Defined(),
559
+ /** Fixed-length tuple — validates element count and each position individually. */
560
+ tuple: (schemas) => new Tuple(schemas),
561
+ /** Defers schema creation — required for recursive types. Must supply a default value. */
562
+ lazy: (fn, defaultVal) => new Lazy(fn, defaultVal)
563
+ };
564
+
565
+ // src/version/PxSchemaVersion.ts
566
+ var PX_WIRE_SCHEMA_VERSION = "1.1";
567
+
568
+ // src/version/PxWireVersion.ts
569
+ var PX_WIRE_VERSION_KEY = "version";
570
+ var ANIMATOR_KEY = "animator";
571
+ var META_KEY = "meta";
572
+ var PxWireVersionRelation = /* @__PURE__ */ ((PxWireVersionRelation2) => {
573
+ PxWireVersionRelation2["unstamped"] = "unstamped";
574
+ PxWireVersionRelation2["same"] = "same";
575
+ PxWireVersionRelation2["older"] = "older";
576
+ PxWireVersionRelation2["newer"] = "newer";
577
+ PxWireVersionRelation2["otherGeneration"] = "otherGeneration";
578
+ return PxWireVersionRelation2;
579
+ })(PxWireVersionRelation || {});
580
+ var VERSION_RE = /^(\d+)\.(\d+)(?:\.(\d+))?$/;
581
+ function parseWireVersion(raw) {
582
+ if (typeof raw !== "string") return void 0;
583
+ const m = VERSION_RE.exec(raw.trim());
584
+ if (!m) return void 0;
585
+ return { a: Number(m[1]), b: Number(m[2]), c: m[3] === void 0 ? 0 : Number(m[3]) };
586
+ }
587
+ function formatWireVersion(v) {
588
+ return v.a + "." + v.b + "." + v.c;
589
+ }
590
+ var _a;
591
+ var PX_WIRE_VERSION = (_a = parseWireVersion(PX_WIRE_SCHEMA_VERSION)) != null ? _a : { a: 1, b: 1, c: 0 };
592
+ function getAnimatorBlock(doc) {
593
+ if (!doc || typeof doc !== "object") return void 0;
594
+ const atRoot = readObjectProp(doc, ANIMATOR_KEY);
595
+ if (atRoot) return atRoot;
596
+ const meta = readObjectProp(doc, META_KEY);
597
+ return meta ? readObjectProp(meta, ANIMATOR_KEY) : void 0;
598
+ }
599
+ function readObjectProp(obj, key) {
600
+ const value = obj[key];
601
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
602
+ }
603
+ function readWireVersion(doc) {
604
+ const animator = getAnimatorBlock(doc);
605
+ return animator ? parseWireVersion(animator[PX_WIRE_VERSION_KEY]) : void 0;
606
+ }
607
+ function compareWireVersion(file, mine, readerReadsEditorPart) {
608
+ if (!file) return "unstamped" /* unstamped */;
609
+ if (file.a !== mine.a) return "otherGeneration" /* otherGeneration */;
610
+ if (file.b !== mine.b) return file.b > mine.b ? "newer" /* newer */ : "older" /* older */;
611
+ if (!readerReadsEditorPart || file.c === mine.c) return "same" /* same */;
612
+ return file.c > mine.c ? "newer" /* newer */ : "older" /* older */;
613
+ }
614
+ function wireVersionAdvice(relation, file, mine, isPlayer) {
615
+ if (!file) return void 0;
616
+ const target = isPlayer ? "player" : "editor";
617
+ const gap = "written for schema " + formatWireVersion(file) + ", this " + target + " reads " + formatWireVersion(mine);
618
+ switch (relation) {
619
+ case "newer" /* newer */:
620
+ return "This file is " + gap + ". Update the " + target + " to open it fully.";
621
+ case "older" /* older */:
622
+ return "This file is " + gap + ". Saving it from this " + target + " rewrites it in the current format.";
623
+ case "otherGeneration" /* otherGeneration */:
624
+ return "This file is " + gap + " \u2014 a different format generation, which no conversion bridges. Open it in a " + target + " of that generation, or accept this document without the parts named above.";
625
+ default:
626
+ return void 0;
627
+ }
628
+ }
629
+ var PxWireStepKind = /* @__PURE__ */ ((PxWireStepKind2) => {
630
+ PxWireStepKind2["additive"] = "additive";
631
+ PxWireStepKind2["converted"] = "converted";
632
+ return PxWireStepKind2;
633
+ })(PxWireStepKind || {});
634
+ var PX_WIRE_BASELINE_VERSION = "1.1";
635
+ var PX_WIRE_STEPS = [];
636
+ function applyWireSteps(doc, cfg) {
637
+ const from = readWireVersion(doc);
638
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
639
+ if (!from || relation !== "older" /* older */) {
640
+ return {
641
+ doc,
642
+ from,
643
+ relation,
644
+ applied: [],
645
+ advice: wireVersionAdvice(relation, from, cfg.target, !cfg.readerReadsEditorPart)
646
+ };
647
+ }
648
+ const due = [];
649
+ for (const step of cfg.steps) {
650
+ const stepTo = parseWireVersion(step.to);
651
+ if (!stepTo) continue;
652
+ if (compareWireVersion(from, stepTo, cfg.readerReadsEditorPart) !== "older" /* older */) continue;
653
+ if (!step.up) continue;
654
+ due.push(step);
655
+ }
656
+ if (!due.length || !doc || typeof doc !== "object") return { doc, from, relation, applied: [] };
657
+ const target = clonePlain(doc);
658
+ const applied = [];
659
+ for (const step of due) {
660
+ try {
661
+ step.up(target);
662
+ applied.push(step);
663
+ } catch (e) {
664
+ break;
665
+ }
666
+ }
667
+ if (!applied.length) return { doc, from, relation, applied: [] };
668
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
669
+ return { doc: target, from, relation, applied };
670
+ }
671
+ function convertWireDocument(doc) {
672
+ return applyWireSteps(doc, {
673
+ steps: PX_WIRE_STEPS,
674
+ target: PX_WIRE_VERSION,
675
+ readerReadsEditorPart: false
676
+ });
677
+ }
678
+ function clonePlain(value) {
679
+ const structured = globalThis.structuredClone;
680
+ return structured ? structured(value) : JSON.parse(JSON.stringify(value));
681
+ }
682
+ function stampVersion(doc, target, readerReadsEditorPart) {
683
+ const animator = getAnimatorBlock(doc);
684
+ if (!animator) return;
685
+ const previous = parseWireVersion(animator[PX_WIRE_VERSION_KEY]);
686
+ animator[PX_WIRE_VERSION_KEY] = formatWireVersion({
687
+ a: target.a,
688
+ b: target.b,
689
+ c: readerReadsEditorPart ? target.c : previous ? previous.c : 0
690
+ });
691
+ }
692
+ function applyWireStepsDown(doc, cfg) {
693
+ const from = readWireVersion(doc);
694
+ if (!from) {
695
+ return { ok: false, blocking: [], reason: "The document carries no version, so there is nothing to convert down from." };
696
+ }
697
+ const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);
698
+ if (relation === "otherGeneration" /* otherGeneration */) {
699
+ return {
700
+ ok: false,
701
+ blocking: [],
702
+ reason: "Schema " + formatWireVersion(from) + " and " + formatWireVersion(cfg.target) + " are different generations; no conversion bridges them."
703
+ };
704
+ }
705
+ if (relation !== "newer" /* newer */) return { ok: true, doc, applied: [] };
706
+ const toUndo = [];
707
+ for (const step of cfg.steps) {
708
+ const stepTo = parseWireVersion(step.to);
709
+ if (!stepTo) continue;
710
+ if (compareWireVersion(stepTo, cfg.target, cfg.readerReadsEditorPart) !== "newer" /* newer */) continue;
711
+ if (compareWireVersion(stepTo, from, cfg.readerReadsEditorPart) === "newer" /* newer */) continue;
712
+ toUndo.push(step);
713
+ }
714
+ toUndo.reverse();
715
+ const blocking = toUndo.filter((s) => s.kind === "converted" /* converted */ && !s.down);
716
+ if (blocking.length) {
717
+ return {
718
+ ok: false,
719
+ blocking,
720
+ reason: "Cannot convert down to " + formatWireVersion(cfg.target) + ": " + blocking.map((s) => s.from + " \u2192 " + s.to + " (" + s.reason + ")").join("; ") + " cannot be undone."
721
+ };
722
+ }
723
+ const target = clonePlain(doc);
724
+ const applied = [];
725
+ for (const step of toUndo) {
726
+ if (!step.down) continue;
727
+ try {
728
+ step.down(target);
729
+ applied.push(step);
730
+ } catch (e) {
731
+ return {
732
+ ok: false,
733
+ blocking: [step],
734
+ reason: "Undoing " + step.from + " \u2192 " + step.to + " failed: " + String(e)
735
+ };
736
+ }
737
+ }
738
+ stampVersion(target, cfg.target, cfg.readerReadsEditorPart);
739
+ return { ok: true, doc: target, applied };
740
+ }
741
+ function downgradeWireDocument(doc, target) {
742
+ return applyWireStepsDown(doc, { steps: PX_WIRE_STEPS, target, readerReadsEditorPart: false });
743
+ }
744
+
745
+ // src/format/PxAnimatorConstants.ts
746
+ var PxFillMode = {
747
+ forwards: "forwards",
748
+ backwards: "backwards",
749
+ both: "both",
750
+ none: "none"
751
+ };
752
+ var PxPlaybackDirection = {
753
+ normal: "normal",
754
+ reverse: "reverse",
755
+ alternate: "alternate",
756
+ alternateReverse: "alternate-reverse"
757
+ };
758
+ var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
759
+ var PX_ANIM_ATTR_NAME = "_px_animator";
760
+ var PxStartOn = {
761
+ load: "load",
762
+ mouseOver: "mouseOver",
763
+ click: "click",
764
+ scrollIntoView: "scrollIntoView",
765
+ programmatic: "programmatic"
766
+ };
767
+ var PxOutAction = {
768
+ continue: "continue",
769
+ pause: "pause",
770
+ reset: "reset",
771
+ reverse: "reverse"
772
+ };
773
+ var PxFinishAction = {
774
+ hold: "hold",
775
+ reset: "reset"
776
+ };
777
+ var PxScrollKind = {
778
+ view: "view",
779
+ scroll: "scroll"
780
+ };
781
+ var PxScrollAxis = {
782
+ block: "block",
783
+ inline: "inline",
784
+ x: "x",
785
+ y: "y"
786
+ };
787
+ var PxScrollSource = {
788
+ nearest: "nearest",
789
+ root: "root"
790
+ };
791
+ var PxPinAlign = {
792
+ top: "top",
793
+ center: "center",
794
+ bottom: "bottom"
795
+ };
796
+ var PxScrollPhase = {
797
+ cover: "cover",
798
+ contain: "contain",
799
+ entry: "entry",
800
+ exit: "exit",
801
+ entryCrossing: "entry-crossing",
802
+ exitCrossing: "exit-crossing"
803
+ };
804
+ var PxAlongPathMode = {
805
+ sampled: "sampled",
806
+ offsetPath: "offsetPath"
807
+ };
808
+ var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
809
+ var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
810
+ var PX_FLAT_RUNTIME_VIEW_KEYS = [
811
+ ...PX_TIMELINE_SHARED_KEYS,
812
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
813
+ "fill",
814
+ "resetOnFinish",
815
+ "timelineSource",
816
+ "scroll"
817
+ ];
818
+ var PxTimelineEngine = {
819
+ native: "native",
820
+ js: "js"
821
+ };
822
+ var PxTimelineEngineSetting = __spreadProps(__spreadValues({}, PxTimelineEngine), {
823
+ auto: "auto"
824
+ });
825
+ function resolveTimelineEngine(engine) {
826
+ return engine === PxTimelineEngineSetting.js ? PxTimelineEngine.js : PxTimelineEngine.native;
827
+ }
828
+ function isNativeForced(engine) {
829
+ return engine === PxTimelineEngineSetting.native;
830
+ }
831
+ function mayUseNativeScrollTimeline(engine) {
832
+ return engine !== PxTimelineEngineSetting.js;
833
+ }
834
+ var PX_TRIGGER_DEFAULTS = {
835
+ startOn: "load",
836
+ outAction: "continue",
837
+ scrollIntoViewThreshold: 0
838
+ };
839
+ var PxControlMode = {
840
+ /** No control props — the document's trigger decides, and nothing is taken over. */
841
+ static: "static",
842
+ /** `progress` / `time` — the host scrubs; the component seeks and stays paused. */
843
+ fixedTime: "fixedTime",
844
+ /** `play` / `pause` — the host drives playback with booleans. */
845
+ play: "play",
846
+ /** `autoplay` — the document's own trigger starts it. */
847
+ autoplay: "autoplay"
848
+ };
849
+ function resolveControlMode(props) {
850
+ const hasFixedTime = props.progress !== void 0 || props.time !== void 0;
851
+ const hasPlayPause = props.play !== void 0 || props.pause !== void 0;
852
+ const hasAutoplay = !!props.autoplay;
853
+ const warnings = [];
854
+ const named = (a, b, winner) => a + " and " + b + " were both set \u2014 " + winner + " wins, " + (winner === a ? b : a) + " is ignored.";
855
+ if (hasFixedTime) {
856
+ if (hasPlayPause) warnings.push(named("progress/time", "play/pause", "progress/time"));
857
+ if (hasAutoplay) warnings.push(named("progress/time", "autoplay", "progress/time"));
858
+ return { mode: PxControlMode.fixedTime, warnings };
859
+ }
860
+ if (hasPlayPause) {
861
+ if (hasAutoplay) warnings.push(named("play/pause", "autoplay", "play/pause"));
862
+ return { mode: PxControlMode.play, warnings };
863
+ }
864
+ if (hasAutoplay) return { mode: PxControlMode.autoplay, warnings };
865
+ return { mode: PxControlMode.static, warnings };
866
+ }
867
+ function controlModeTakesOverTrigger(mode) {
868
+ return mode !== PxControlMode.autoplay;
869
+ }
870
+ function resolveTrigger(trigger) {
871
+ var _a2, _b, _c;
872
+ return {
873
+ startOn: (_a2 = trigger == null ? void 0 : trigger.startOn) != null ? _a2 : PX_TRIGGER_DEFAULTS.startOn,
874
+ outAction: (_b = trigger == null ? void 0 : trigger.outAction) != null ? _b : PX_TRIGGER_DEFAULTS.outAction,
875
+ scrollIntoViewThreshold: (_c = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _c : PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold
876
+ };
877
+ }
878
+ var PxLoopRepeatAt = {
879
+ /** Segment from the START; the repetition runs BEFORE the first keyframe
880
+ * (intro loops that play until the main timeline begins). */
881
+ start: "start",
882
+ /** DEFAULT — segment from the END; the repetition runs AFTER the last keyframe
883
+ * (idle/outro loops that continue once the main timeline has finished). */
884
+ end: "end"
885
+ };
886
+ var PxLoopDirection = {
887
+ /** DEFAULT — cycle: every repetition replays the segment the same way round. */
888
+ normal: "normal",
889
+ /** Ping-pong: repetitions alternate forward / backward. */
890
+ alternate: "alternate"
891
+ };
892
+ var PxMaskType = {
893
+ luminance: "luminance",
894
+ alpha: "alpha"
895
+ };
896
+ var PxUnits = {
897
+ userSpaceOnUse: "userSpaceOnUse",
898
+ objectBoundingBox: "objectBoundingBox"
899
+ };
900
+ var PxCloneWithout = {
901
+ translate: "translate"
902
+ // transform: 'transform', // future: drop rotate/scale too (content only)
903
+ };
904
+ var PxPathOverflow = {
905
+ clip: "clip",
906
+ extend: "extend"
907
+ };
908
+ var PxLengthAdjust = {
909
+ spacing: "spacing",
910
+ spacingAndGlyphs: "spacingAndGlyphs"
911
+ };
912
+ var PxTextPathMethod = {
913
+ align: "align",
914
+ stretch: "stretch"
915
+ };
916
+ var PxTextPathSpacing = {
917
+ auto: "auto",
918
+ exact: "exact"
919
+ };
920
+ var PxStrokeTrimSubPaths = {
921
+ separate: "separate",
922
+ combined: "combined"
923
+ };
924
+ var PX_TEXT_CONTENT_ATTR = "textContent";
925
+ var CLASS_ATTR = "class";
926
+ var TRANSFORM_ATTR = "transform";
927
+ var OFFSET_DISTANCE_ATTR = "offsetDistance";
928
+ var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
929
+ "type",
930
+ "children",
931
+ "animator",
932
+ "meta",
933
+ "animate",
934
+ "effects",
935
+ PX_TEXT_CONTENT_ATTR
936
+ ]);
937
+ var TRANSFORM_PART = {
938
+ translate: "translate",
939
+ rotate: "rotate",
940
+ scale: "scale",
941
+ origin: "origin"
942
+ };
943
+ var PX_TRANSFORM_PART_KEYS = [
944
+ TRANSFORM_PART.translate,
945
+ TRANSFORM_PART.rotate,
946
+ TRANSFORM_PART.scale,
947
+ TRANSFORM_PART.origin
948
+ ];
949
+ var PxGradientSpreadMethod = {
950
+ pad: "pad",
951
+ reflect: "reflect",
952
+ repeat: "repeat"
953
+ };
954
+ var PxGradientType = {
955
+ linear: "linear",
956
+ radial: "radial"
957
+ };
958
+ function isPxDocument(doc) {
959
+ if (!(doc && typeof doc === "object" && !Array.isArray(doc))) {
960
+ return false;
961
+ }
962
+ return doc.type === "svg";
963
+ }
964
+ function getAnimatorConfig(doc) {
965
+ var _a2;
966
+ const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
967
+ if (!cfg) return void 0;
968
+ const memoised = wireViewMemo.get(cfg);
969
+ if (memoised) return memoised;
970
+ const wire = cfg;
971
+ const stray = PX_FLAT_RUNTIME_VIEW_KEYS.filter((k) => wire[k] !== void 0);
972
+ const source = stray.length ? __spreadValues({}, wire) : cfg;
973
+ for (const k of stray) delete source[k];
974
+ const view = flattenAnimatorTimeline(source);
975
+ wireViewMemo.set(cfg, view);
976
+ return view;
977
+ }
978
+ var wireViewMemo = /* @__PURE__ */ new WeakMap();
979
+ var flattenMemo = /* @__PURE__ */ new WeakMap();
980
+ function flattenAnimatorTimeline(cfg) {
981
+ const timeline = cfg.timeline;
982
+ if (timeline === void 0 || timeline === null || typeof timeline !== "object") return cfg;
983
+ const memoised = flattenMemo.get(cfg);
984
+ if (memoised) return memoised;
985
+ const _a2 = cfg, { timeline: _dropped } = _a2, flat = __objRest(_a2, ["timeline"]);
986
+ if (timeline.engine !== void 0) flat.engine = timeline.engine;
987
+ if (timeline.frameRate !== void 0) flat.frameRate = timeline.frameRate;
988
+ if (timeline.type === "scroll" || timeline.type === "view") {
989
+ flat.timelineSource = "scroll";
990
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
991
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
992
+ const scroll = __spreadValues({}, flat.scroll || {});
993
+ scroll.kind = timeline.type;
994
+ if (timeline.axis !== void 0) scroll.axis = timeline.axis;
995
+ if (timeline.source !== void 0) scroll.source = timeline.source;
996
+ if (timeline.subject !== void 0) scroll.subject = timeline.subject;
997
+ if (timeline.smoothing !== void 0) scroll.smoothing = timeline.smoothing;
998
+ if (timeline.range !== void 0) scroll.range = timeline.range;
999
+ const pin = timeline.pin;
1000
+ if (typeof pin === "boolean") scroll.pin = pin;
1001
+ else if (pin && typeof pin === "object") {
1002
+ scroll.pin = true;
1003
+ if (pin.align !== void 0) scroll.pinAlign = pin.align;
1004
+ if (pin.offset !== void 0) scroll.pinOffset = pin.offset;
1005
+ if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1006
+ }
1007
+ flat.scroll = scroll;
1008
+ } else {
1009
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
1010
+ if (timeline.trigger !== void 0) {
1011
+ const _b = timeline.trigger, { finishAction } = _b, restTrigger = __objRest(_b, ["finishAction"]);
1012
+ if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
1013
+ if (finishAction !== void 0) flat.resetOnFinish = finishAction === "reset";
1014
+ }
1015
+ if (timeline.delay !== void 0) flat.delay = timeline.delay;
1016
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1017
+ if (timeline.direction !== void 0) flat.direction = timeline.direction;
1018
+ if (timeline.fillMode !== void 0) flat.fill = timeline.fillMode;
1019
+ }
1020
+ flattenMemo.set(cfg, flat);
1021
+ return flat;
1022
+ }
1023
+ function scrollKindOrDefault(kind) {
1024
+ return kind === "scroll" ? "scroll" : "view";
1025
+ }
1026
+ function nestAnimatorTimeline(cfg) {
1027
+ if (!cfg || cfg.timeline !== void 0) return cfg;
1028
+ const _a2 = cfg, {
1029
+ timelineSource,
1030
+ scroll,
1031
+ trigger,
1032
+ delay,
1033
+ iterations,
1034
+ direction,
1035
+ fill,
1036
+ resetOnFinish,
1037
+ duration,
1038
+ engine,
1039
+ frameRate
1040
+ } = _a2, shared = __objRest(_a2, [
1041
+ "timelineSource",
1042
+ "scroll",
1043
+ "trigger",
1044
+ "delay",
1045
+ "iterations",
1046
+ "direction",
1047
+ "fill",
1048
+ "resetOnFinish",
1049
+ "duration",
1050
+ "engine",
1051
+ "frameRate"
1052
+ ]);
1053
+ if (timelineSource === "scroll") {
1054
+ const timeline2 = { type: scrollKindOrDefault(scroll == null ? void 0 : scroll.kind) };
1055
+ if (engine !== void 0) timeline2.engine = engine;
1056
+ if (frameRate !== void 0) timeline2.frameRate = frameRate;
1057
+ if (duration !== void 0) timeline2.duration = duration;
1058
+ if (typeof iterations === "number") timeline2.iterations = iterations;
1059
+ if (scroll) {
1060
+ if (scroll.axis !== void 0) timeline2.axis = scroll.axis;
1061
+ if (scroll.source !== void 0) timeline2.source = scroll.source;
1062
+ if (scroll.subject !== void 0) timeline2.subject = scroll.subject;
1063
+ if (scroll.smoothing !== void 0) timeline2.smoothing = scroll.smoothing;
1064
+ if (scroll.range !== void 0) timeline2.range = scroll.range;
1065
+ const hasPinParams = scroll.pinAlign !== void 0 || scroll.pinOffset !== void 0 || scroll.pinDistance !== void 0;
1066
+ if (hasPinParams) {
1067
+ timeline2.pin = __spreadValues(__spreadValues(__spreadValues({}, scroll.pinAlign !== void 0 ? { align: scroll.pinAlign } : {}), scroll.pinOffset !== void 0 ? { offset: scroll.pinOffset } : {}), scroll.pinDistance !== void 0 ? { distance: scroll.pinDistance } : {});
1068
+ } else if (scroll.pin !== void 0) {
1069
+ timeline2.pin = scroll.pin;
1070
+ }
1071
+ }
1072
+ return __spreadProps(__spreadValues({}, shared), { timeline: timeline2 });
1073
+ }
1074
+ const timeline = {};
1075
+ if (engine !== void 0) timeline.engine = engine;
1076
+ if (frameRate !== void 0) timeline.frameRate = frameRate;
1077
+ if (duration !== void 0) timeline.duration = duration;
1078
+ if (trigger !== void 0 || resetOnFinish) {
1079
+ const t = __spreadValues({}, trigger || {});
1080
+ if (resetOnFinish) t.finishAction = "reset";
1081
+ timeline.trigger = t;
1082
+ }
1083
+ if (delay !== void 0) timeline.delay = delay;
1084
+ if (iterations !== void 0) timeline.iterations = iterations;
1085
+ if (direction !== void 0) timeline.direction = direction;
1086
+ if (fill !== void 0) timeline.fillMode = fill;
1087
+ return Object.keys(timeline).length > 0 ? __spreadProps(__spreadValues({}, shared), { timeline }) : shared;
1088
+ }
1089
+ function getDefinitions(doc) {
1090
+ var _a2;
1091
+ if (!doc) return void 0;
1092
+ return (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
1093
+ }
1094
+ function getBindings(doc) {
1095
+ var _a2;
1096
+ if (!doc) return void 0;
1097
+ return (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.bindings;
1098
+ }
1099
+ function getChildren(doc) {
1100
+ return doc == null ? void 0 : doc.children;
1101
+ }
1102
+
1103
+ // src/format/PxAnimatorTypes.ts
1104
+ var PxEasingOrRefSchema = px.union([
1105
+ px.string(),
1106
+ px.tuple([px.number(), px.number(), px.number(), px.number()])
1107
+ ]);
1108
+ var PxKeyframeValueSchema = implementsInterface()(px.union([
1109
+ px.string(),
1110
+ // e.g. for colors
1111
+ px.number(),
1112
+ px.array(px.number()),
1113
+ // ORDER LAW: the key-discriminated object shape (`{pathData}`) comes BEFORE the
1114
+ // all-optional transform-parts record. In default (non-strict) mode that record accepts
1115
+ // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1116
+ // Union.sanitize route `{pathData}` values into it and strip them to `{}` —
1117
+ // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1118
+ // order-independent (`some()`); only sanitize routing depends on this order.
1119
+ px.object({ pathData: px.string() }),
1120
+ // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1121
+ px.lazy(() => px.array(PxGradientStopSchema), []),
1122
+ px.lazy(() => PxTransformPartsSchema, {})
1123
+ ]));
1124
+ var PxKeyframeSchema = implementsInterface()(px.object({
1125
+ time: px.number().optional(),
1126
+ value: PxKeyframeValueSchema.optional(),
1127
+ easing: PxEasingOrRefSchema.optional(),
1128
+ tangentOut: px.tuple([px.number(), px.number()]).optional(),
1129
+ tangentIn: px.tuple([px.number(), px.number()]).optional()
1130
+ // (`selected` — editor timeline-selection UI state — was REMOVED from the wire
1131
+ // (review §1.3): editor data lives under `meta`. The editor still carries it on
1132
+ // its internal COPY-PASTE payload, which never validates against this schema.)
1133
+ }));
1134
+ var anyKf = (kf) => kf;
1135
+ var keyframeTime = (kf) => {
1136
+ var _a2, _b;
1137
+ return (_b = (_a2 = anyKf(kf).time) != null ? _a2 : anyKf(kf).t) != null ? _b : 0;
1138
+ };
1139
+ var keyframeValue = (kf) => {
1140
+ var _a2;
1141
+ return (_a2 = anyKf(kf).value) != null ? _a2 : anyKf(kf).v;
1142
+ };
1143
+ var keyframeEasing = (kf) => {
1144
+ var _a2;
1145
+ return (_a2 = anyKf(kf).easing) != null ? _a2 : anyKf(kf).e;
1146
+ };
1147
+ var keyframeTangentIn = (kf) => anyKf(kf).tangentIn;
1148
+ var keyframeTangentOut = (kf) => anyKf(kf).tangentOut;
1149
+ var PxLoopSchema = implementsInterface()(px.object({
1150
+ segmentCount: px.number().optional(),
1151
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1152
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1153
+ }));
1154
+ var PxPropertyAnimationSchema = implementsInterface()(px.object({
1155
+ value: PxKeyframeValueSchema.optional(),
1156
+ keyframes: px.array(PxKeyframeSchema).optional(),
1157
+ loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1158
+ autoOrient: px.boolean().optional(),
1159
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
1160
+ }));
1161
+ var PxTransformPartsSchema = implementsInterface()(px.object({
1162
+ translate: px.tuple([px.number(), px.number()]).optional(),
1163
+ rotate: px.number().optional(),
1164
+ skew: px.number().optional(),
1165
+ scale: px.tuple([px.number(), px.number()]).optional(),
1166
+ origin: px.tuple([px.number(), px.number()]).optional()
1167
+ }));
1168
+ var PxTransformValueSchema = px.union([
1169
+ px.string(),
1170
+ PxTransformPartsSchema,
1171
+ px.object({ value: PxTransformPartsSchema }),
1172
+ PxPropertyAnimationSchema
1173
+ ]);
1174
+ var PxAnimationDefinitionSchema = implementsInterface()(
1175
+ px.record(PxPropertyAnimationSchema)
1176
+ );
1177
+ var PxElementAnimationSchema = implementsInterface()(px.union([
1178
+ px.string(),
1179
+ px.array(px.union([px.string(), PxAnimationDefinitionSchema])),
1180
+ PxAnimationDefinitionSchema
1181
+ ]));
1182
+ var PxTriggerSchema = implementsInterface()(px.object({
1183
+ startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic], PX_TRIGGER_DEFAULTS.startOn).optional(),
1184
+ outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse], PX_TRIGGER_DEFAULTS.outAction).optional(),
1185
+ // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1186
+ // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
1187
+ // happens when the trigger condition ends"); both end-of-life knobs now read alike.
1188
+ finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
1189
+ scrollIntoViewThreshold: px.number().optional()
1190
+ }));
1191
+ var PxGlyphSchema = implementsInterface()(px.object({
1192
+ width: px.number(),
1193
+ pathData: px.string()
1194
+ }));
1195
+ var PxGlyphFontSchema = implementsInterface()(px.object({
1196
+ fontFamily: px.string(),
1197
+ fontStyle: px.string(),
1198
+ ascent: px.number(),
1199
+ unitsPerEm: px.number(),
1200
+ glyphs: px.record(PxGlyphSchema)
1201
+ }));
1202
+ var PxDefinitionsSchema = implementsInterface()(px.object({
1203
+ easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1204
+ animations: px.record(PxAnimationDefinitionSchema).optional(),
1205
+ fonts: px.record(PxGlyphFontSchema).optional()
1206
+ }));
1207
+ var PxScrollRangePointSchema = implementsInterface()(px.object({
1208
+ phase: px.enum([
1209
+ PxScrollPhase.cover,
1210
+ PxScrollPhase.contain,
1211
+ PxScrollPhase.entry,
1212
+ PxScrollPhase.exit,
1213
+ PxScrollPhase.entryCrossing,
1214
+ PxScrollPhase.exitCrossing
1215
+ ]).optional(),
1216
+ fraction: px.number().optional()
1217
+ }));
1218
+ var PxScrollRangeSchema = px.object({
1219
+ start: PxScrollRangePointSchema.optional(),
1220
+ end: PxScrollRangePointSchema.optional()
1221
+ });
1222
+ var PxScrollSchema = implementsInterface()(px.object({
1223
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
1224
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1225
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1226
+ // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1227
+ subject: px.string().optional(),
1228
+ smoothing: px.number().optional(),
1229
+ pin: px.boolean().optional(),
1230
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1231
+ pinOffset: px.number().optional(),
1232
+ pinDistance: px.number().optional(),
1233
+ range: PxScrollRangeSchema.optional()
1234
+ }));
1235
+ var PxTimelinePinSchema = implementsInterface()(px.object({
1236
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1237
+ offset: px.number().optional(),
1238
+ distance: px.number().optional()
1239
+ }));
1240
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineSetting.auto, PxTimelineEngineSetting.native, PxTimelineEngineSetting.js]).optional();
1241
+ var PxTimeTimelineSchema = implementsInterface()(px.object({
1242
+ type: px.literal("time").optional(),
1243
+ engine: PxTimelineEngineSchema,
1244
+ frameRate: px.number().optional(),
1245
+ // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1246
+ duration: px.number().optional(),
1247
+ trigger: PxTriggerSchema.optional(),
1248
+ delay: px.number().optional(),
1249
+ iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1250
+ // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1251
+ // — never `fill`, which is paint everywhere else in the format.
1252
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
1253
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
1254
+ }));
1255
+ var scrollishTimelineShape = {
1256
+ // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1257
+ // span the scroll range maps onto.
1258
+ duration: px.number().optional(),
1259
+ // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1260
+ // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1261
+ iterations: px.number().optional(),
1262
+ engine: PxTimelineEngineSchema,
1263
+ frameRate: px.number().optional(),
1264
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1265
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1266
+ subject: px.string().optional(),
1267
+ // 'parent' | 'scroller' | any CSS selector
1268
+ smoothing: px.number().optional(),
1269
+ // ms
1270
+ pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1271
+ range: PxScrollRangeSchema.optional()
1272
+ };
1273
+ var PxScrollTimelineSchema = implementsInterface()(
1274
+ px.object(__spreadValues({ type: px.literal("scroll") }, scrollishTimelineShape))
1275
+ );
1276
+ var PxViewTimelineSchema = implementsInterface()(
1277
+ px.object(__spreadValues({ type: px.literal("view") }, scrollishTimelineShape))
1278
+ );
1279
+ var PxTimelineSchema = px.discriminatedUnion("type", [
1280
+ PxTimeTimelineSchema,
1281
+ // first = the member an absent `type` selects
1282
+ PxScrollTimelineSchema,
1283
+ PxViewTimelineSchema
1284
+ ]);
1285
+ var PxBindingSchema = implementsInterface()(px.object({
1286
+ target: px.string(),
1287
+ animateWith: px.array(px.string())
1288
+ }));
1289
+ var PxAnimatorConfigSchema = implementsInterface()(px.object({
1290
+ // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist
1291
+ // at this level only on the runtime view, like the rest of the playback dynamics.)
1292
+ // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1293
+ timeline: PxTimelineSchema.optional(),
1294
+ definitions: PxDefinitionsSchema.optional(),
1295
+ bindings: px.array(PxBindingSchema).optional(),
1296
+ debugGlobalName: px.string().optional(),
1297
+ // Declared HERE because this is a closed object: an undeclared key would be stripped by
1298
+ // `sanitize` and flagged by strict validation on our own files.
1299
+ version: px.string().optional()
1300
+ }));
1301
+ var PxAttrValueSchema = px.union([
1302
+ px.string(),
1303
+ px.number(),
1304
+ px.array(px.number()),
1305
+ // Structured static — `{value: …}` (read-accepted transitional spelling, S1).
1306
+ // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).
1307
+ px.object({ value: px.defined() }),
1308
+ // Bare transform parts record — the canonical static `transform` on the wire (T2).
1309
+ PxTransformPartsSchema
1310
+ ]);
1311
+ var PxAnimatableNumberSchema = px.union([
1312
+ px.number(),
1313
+ PxPropertyAnimationSchema,
1314
+ px.object({ value: px.number() })
1315
+ ]);
1316
+ var PxAnimatableVec2Schema = px.union([
1317
+ px.tuple([px.number(), px.number()]),
1318
+ PxPropertyAnimationSchema,
1319
+ px.object({ value: px.tuple([px.number(), px.number()]) })
1320
+ ]);
1321
+ var PxAnimatableStringSchema = px.union([
1322
+ px.string(),
1323
+ PxPropertyAnimationSchema,
1324
+ px.object({ value: px.string() })
1325
+ ]);
1326
+ var PxTransformByEffectSchema = implementsInterface()(px.object({
1327
+ translate: PxAnimatableVec2Schema.optional(),
1328
+ rotate: PxAnimatableNumberSchema.optional(),
1329
+ scale: PxAnimatableVec2Schema.optional(),
1330
+ skew: PxAnimatableNumberSchema.optional(),
1331
+ origin: PxAnimatableVec2Schema.optional()
1332
+ }));
1333
+ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1334
+ // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
1335
+ // once at expansion time and never sampled — plain number, no `keyframes`.
1336
+ copies: px.number().optional(),
1337
+ translate: PxAnimatableVec2Schema.optional(),
1338
+ rotate: PxAnimatableNumberSchema.optional(),
1339
+ skew: PxAnimatableNumberSchema.optional(),
1340
+ scale: PxAnimatableVec2Schema.optional(),
1341
+ origin: PxAnimatableVec2Schema.optional()
1342
+ }));
1343
+ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1344
+ source: px.string().optional(),
1345
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1346
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1347
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1348
+ x: px.number().optional(),
1349
+ y: px.number().optional(),
1350
+ width: px.number().optional(),
1351
+ height: px.number().optional()
1352
+ }));
1353
+ var PxClipPathEffectSchema = implementsInterface()(px.object({
1354
+ pathData: PxAnimatableStringSchema.optional()
1355
+ }));
1356
+ var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1357
+ offset: PxAnimatableNumberSchema.optional(),
1358
+ range: PxAnimatableVec2Schema.optional(),
1359
+ subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined]).optional()
1360
+ }));
1361
+ var PxRetimeEffectSchema = implementsInterface()(px.object({
1362
+ start: px.number().optional(),
1363
+ stretch: px.number().optional(),
1364
+ timeCrop: px.tuple([px.number(), px.number()]).optional()
1365
+ }));
1366
+ var PxCloneEffectSchema = implementsInterface()(px.object({
1367
+ // Subtractive on purpose: the `<use>` can only point at one wrapper layer of the
1368
+ // source, so the choices form a ladder — 'translate' now, maybe 'transform' later.
1369
+ without: px.enum([PxCloneWithout.translate]).optional(),
1370
+ source: px.string().optional(),
1371
+ retime: PxRetimeEffectSchema.optional()
1372
+ }));
1373
+ var PxGradientStopSchema = implementsInterface()(px.object({
1374
+ offset: px.number(),
1375
+ color: px.string()
1376
+ }));
1377
+ var PxAnimatableGradientStopsSchema = px.union([
1378
+ px.array(PxGradientStopSchema),
1379
+ px.object({ value: px.array(PxGradientStopSchema) }),
1380
+ PxPropertyAnimationSchema
1381
+ ]);
1382
+ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1383
+ // Contextual kind — the `type` convention, see `PxNodeBaseSchema.type`.
1384
+ type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1385
+ start: PxAnimatableVec2Schema.optional(),
1386
+ end: PxAnimatableVec2Schema.optional(),
1387
+ center: PxAnimatableVec2Schema.optional(),
1388
+ radius: PxAnimatableNumberSchema.optional(),
1389
+ focal: PxAnimatableVec2Schema.optional(),
1390
+ stops: PxAnimatableGradientStopsSchema.optional(),
1391
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1392
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1393
+ gradientTransform: px.string().optional()
1394
+ }));
1395
+ var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1396
+ var PxTextPathEffectSchema = implementsInterface()(px.object({
1397
+ pathData: px.string(),
1398
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1399
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1400
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
1401
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
1402
+ startOffset: PxAnimatableNumberSchema.optional(),
1403
+ textLength: PxAnimatableNumberSchema.optional()
1404
+ }));
1405
+ var PxTextEffectSchema = implementsInterface()(px.object({
1406
+ useGlyphs: px.boolean().optional()
1407
+ }));
1408
+ var PxEffectsSchema = implementsInterface()(px.object({
1409
+ transformBy: PxTransformByEffectSchema.optional(),
1410
+ repeater: PxRepeaterEffectSchema.optional(),
1411
+ maskedBy: PxMaskedByEffectSchema.optional(),
1412
+ clipPath: PxClipPathEffectSchema.optional(),
1413
+ strokeTrim: PxStrokeTrimEffectSchema.optional(),
1414
+ clone: PxCloneEffectSchema.optional(),
1415
+ fillGradient: PxFillGradientEffectSchema.optional(),
1416
+ strokeGradient: PxStrokeGradientEffectSchema.optional(),
1417
+ textPath: PxTextPathEffectSchema.optional(),
1418
+ text: PxTextEffectSchema.optional()
1419
+ }));
1420
+ function validateNodeEffects(root, options) {
1421
+ const warnings = [];
1422
+ const walk = (node, path) => {
1423
+ if (node && node.effects) {
1424
+ const ctx = { errors: [], warnings: [], strict: !!(options == null ? void 0 : options.strict) };
1425
+ const ok = PxEffectsSchema.isValid(node.effects, ctx, [path + ".effects"]);
1426
+ if (!ok) {
1427
+ for (const err of ctx.errors) warnings.push(err);
1428
+ }
1429
+ }
1430
+ if (node && Array.isArray(node.children)) {
1431
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]"));
1432
+ }
1433
+ };
1434
+ walk(root, "root");
1435
+ return warnings;
1436
+ }
1437
+ function validateGlyphFontRefs(root, fonts) {
1438
+ if (!fonts || !Object.keys(fonts).length) return [];
1439
+ const problems = [];
1440
+ const walk = (node, path, inherited, inGlyphText) => {
1441
+ var _a2, _b;
1442
+ if (!node) return;
1443
+ const own = typeof node.fontFamily === "string" ? node.fontFamily : void 0;
1444
+ const family = own != null ? own : inherited;
1445
+ const isGlyphText = inGlyphText || node.type === "text" && !!((_b = (_a2 = node.effects) == null ? void 0 : _a2.text) == null ? void 0 : _b.useGlyphs);
1446
+ if (isGlyphText && own && !Object.prototype.hasOwnProperty.call(fonts, own)) {
1447
+ const problem = path + ': glyph-mode text uses font-family "' + own + '", which has no entry in animator.definitions.fonts';
1448
+ if (!problems.includes(problem)) problems.push(problem);
1449
+ }
1450
+ if (Array.isArray(node.children)) {
1451
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]", family, isGlyphText));
1452
+ }
1453
+ };
1454
+ walk(root, "root", void 0, false);
1455
+ return problems;
1456
+ }
1457
+ function validateEasingRefs(root, easings) {
1458
+ const problems = [];
1459
+ const walk = (node, path) => {
1460
+ if (Array.isArray(node)) {
1461
+ node.forEach((item, i) => walk(item, path + "[" + i + "]"));
1462
+ return;
1463
+ }
1464
+ if (!node || typeof node !== "object") return;
1465
+ const easing = node.easing;
1466
+ if (typeof easing === "string" && !(easings && Object.prototype.hasOwnProperty.call(easings, easing))) {
1467
+ const problem = path + '.easing: "' + easing + '" names no entry in animator.definitions.easings \u2014 it will play linear';
1468
+ if (!problems.includes(problem)) problems.push(problem);
1469
+ }
1470
+ for (const [key, value] of Object.entries(node)) {
1471
+ if (key === "easing") continue;
1472
+ if (value && typeof value === "object") walk(value, path + "." + key);
1473
+ }
1474
+ };
1475
+ walk(root, "root");
1476
+ return problems;
1477
+ }
1478
+ function validateVersionStamp(doc) {
1479
+ var _a2;
1480
+ const version = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.version;
1481
+ if (version === void 0) return [];
1482
+ if (parseWireVersion(version) !== void 0) return [];
1483
+ return ["root.animator.version: " + JSON.stringify(version) + ' is not a version stamp ("a.b" or "a.b.c") \u2014 it reads as unstamped'];
1484
+ }
1485
+ function validateDocument(doc, options) {
1486
+ var _a2;
1487
+ const strict = (options == null ? void 0 : options.strict) !== false;
1488
+ const ctx = { errors: [], warnings: [], strict };
1489
+ const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
1490
+ if (doc && typeof doc === "object") {
1491
+ for (const w of validateNodeEffects(doc, { strict })) {
1492
+ if (!problems.includes(w)) problems.push(w);
1493
+ }
1494
+ const defs = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
1495
+ for (const w of validateGlyphFontRefs(doc, defs == null ? void 0 : defs.fonts)) {
1496
+ if (!problems.includes(w)) problems.push(w);
1497
+ }
1498
+ for (const w of validateEasingRefs(doc, defs == null ? void 0 : defs.easings)) {
1499
+ if (!problems.includes(w)) problems.push(w);
1500
+ }
1501
+ for (const w of validateVersionStamp(doc)) {
1502
+ if (!problems.includes(w)) problems.push(w);
1503
+ }
1504
+ }
1505
+ return problems;
1506
+ }
1507
+ var PxNodeBaseSchema = px.openObject({
1508
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
1509
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
1510
+ // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,
1511
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
1512
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
1513
+ // would add words that all mean "type" and still need the carrier to read.
1514
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
1515
+ // (issues V3), never of distinct key names.
1516
+ type: px.string(),
1517
+ // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence
1518
+ // type="fractalNoise">`, `<feFuncR type="table">`, `<feColorMatrix type="saturate">`.
1519
+ // `type` is taken by the tag name, so the attribute travels here and the renderer puts
1520
+ // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely
1521
+ // documented — because a wire key that is not in a schema is invisible to the
1522
+ // minifier's reserve list and gets renamed (dev-docs/plans/minification-boundary.md §1.1).
1523
+ domType: px.string().optional(),
1524
+ // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
1525
+ // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
1526
+ textContent: px.string().optional(),
1527
+ id: px.string().optional(),
1528
+ meta: px.any().optional(),
1529
+ // Player-effects bucket emitted by the Editor's lightweight design format.
1530
+ // Consumed and removed by `materializeNodeEffects` before any other normalization
1531
+ // (see `createAnimatorImpl`), so downstream code never sees it.
1532
+ effects: PxEffectsSchema.optional(),
1533
+ // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
1534
+ // string ref / array of refs / inline definition / mixed array; mirrors
1535
+ // `node.animate` values and what `processNode` resolves at runtime.
1536
+ animate: PxElementAnimationSchema.optional(),
1537
+ style: px.record(px.union([px.string(), px.number()])).optional()
1538
+ }, PxAttrValueSchema);
1539
+ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBaseSchema._shape), {
1540
+ children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1541
+ }), PxAttrValueSchema);
1542
+ var PxSvgNodeRootSchema = px.object({
1543
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
1544
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
1545
+ width: px.union([px.number(), px.string()]).optional(),
1546
+ height: px.union([px.number(), px.string()]).optional(),
1547
+ viewBox: px.string().optional(),
1548
+ animator: PxAnimatorConfigSchema.optional()
1549
+ });
1550
+ var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps(__spreadValues(__spreadValues({}, PxNodeBaseSchema._shape), PxSvgNodeRootSchema._shape), {
1551
+ type: px.literal("svg"),
1552
+ // override string → literal to require 'svg'
1553
+ children: px.array(PxNodeSchema).optional()
1554
+ }), PxAttrValueSchema);
1555
+ var PxBezierPathSchema = implementsInterface()(px.object({
1556
+ v: px.array(px.array(px.number())),
1557
+ i: px.array(px.array(px.number())).optional(),
1558
+ o: px.array(px.array(px.number())).optional(),
1559
+ c: px.boolean().optional()
1560
+ }));
1561
+ function isValidPxDocument(doc) {
1562
+ const errors = validateDocument(doc, { strict: false });
1563
+ return { valid: errors.length === 0, errors };
1564
+ }
1565
+
1566
+ // src/util/PxIdUtil.ts
1567
+ var _idCounter = 0;
1568
+ function generateUniqueId() {
1569
+ const timestamp = Date.now().toString(36);
1570
+ const counter = (++_idCounter).toString(36);
1571
+ const random = Math.random().toString(36).substring(2, 6);
1572
+ return "_px_" + timestamp + counter + random;
1573
+ }
1574
+ function deepClone(value) {
1575
+ if (value === null || typeof value !== "object") return value;
1576
+ if (Array.isArray(value)) return value.map((item) => deepClone(item));
1577
+ const obj = value;
1578
+ const cloned = {};
1579
+ for (const key of Object.keys(obj)) {
1580
+ cloned[key] = deepClone(obj[key]);
1581
+ }
1582
+ return cloned;
1583
+ }
1584
+ function generateNewIds(doc) {
1585
+ var _a2;
1586
+ const cloned = deepClone(doc);
1587
+ const idMap = /* @__PURE__ */ new Map();
1588
+ const hashRefAttrs = /* @__PURE__ */ new Set(["href", "xlink:href"]);
1589
+ const urlRefAttrs = /* @__PURE__ */ new Set([
1590
+ "fill",
1591
+ "stroke",
1592
+ "clip-path",
1593
+ "clipPath",
1594
+ "mask",
1595
+ "marker",
1596
+ "marker-start",
1597
+ "marker-mid",
1598
+ "marker-end",
1599
+ "filter",
1600
+ "flood-color",
1601
+ "lighting-color"
1602
+ ]);
1603
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["targetId", "boundElementId"]);
1604
+ const isEffectSourceRef = (key, parentKey) => key === "source" && (parentKey === "maskedBy" || parentKey === "clone");
1605
+ function collectIds(node) {
1606
+ if (!node || typeof node !== "object") return;
1607
+ if (node.id && typeof node.id === "string") {
1608
+ const oldId = node.id;
1609
+ const newId = generateUniqueId();
1610
+ idMap.set(oldId, newId);
1611
+ node.id = newId;
1612
+ } else if (node.animate) {
1613
+ node.id = generateUniqueId();
1614
+ }
1615
+ if (Array.isArray(node.children)) {
1616
+ for (const child of node.children) {
1617
+ collectIds(child);
1618
+ }
1619
+ }
1620
+ }
1621
+ function updateRefs(node, parentKey) {
1622
+ if (!node || typeof node !== "object") return;
1623
+ for (const [key, value] of Object.entries(node)) {
1624
+ if (key === "children") {
1625
+ if (Array.isArray(value)) {
1626
+ for (const child of value) {
1627
+ updateRefs(child);
1628
+ }
1629
+ }
1630
+ continue;
1631
+ }
1632
+ if (typeof value === "string") {
1633
+ if (hashRefAttrs.has(key) && value.startsWith("#")) {
1634
+ const oldId = value.slice(1);
1635
+ const newId = idMap.get(oldId);
1636
+ if (newId) {
1637
+ node[key] = "#" + newId;
1638
+ }
1639
+ } else if (urlRefAttrs.has(key)) {
1640
+ node[key] = replaceUrlRefs(value, idMap);
1641
+ } else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {
1642
+ const hasHash = value.startsWith("#");
1643
+ const newId = idMap.get(hasHash ? value.slice(1) : value);
1644
+ if (newId) {
1645
+ node[key] = hasHash ? "#" + newId : newId;
1646
+ }
1647
+ } else if (value.includes("url(#")) {
1648
+ node[key] = replaceUrlRefs(value, idMap);
1649
+ }
1650
+ } else if (key === "style" && typeof value === "object" && value !== null) {
1651
+ for (const [styleProp, styleValue] of Object.entries(value)) {
1652
+ if (typeof styleValue === "string") {
1653
+ value[styleProp] = replaceUrlRefs(styleValue, idMap);
1654
+ }
1655
+ }
1656
+ } else if (typeof value === "object" && value !== null) {
1657
+ updateRefs(value, key);
1658
+ }
1659
+ }
1660
+ }
1661
+ collectIds(cloned);
1662
+ updateRefs(cloned);
1663
+ const docBindings = (_a2 = cloned.animator) == null ? void 0 : _a2.bindings;
1664
+ if (Array.isArray(docBindings)) {
1665
+ const updatedBindings = docBindings.map((binding) => {
1666
+ var _a3;
1667
+ const hashed = binding.target.startsWith("#");
1668
+ const id = hashed ? binding.target.slice(1) : binding.target;
1669
+ const newId = (_a3 = idMap.get(id)) != null ? _a3 : id;
1670
+ return __spreadProps(__spreadValues({}, binding), { target: hashed ? "#" + newId : newId });
1671
+ });
1672
+ cloned.animator = __spreadProps(__spreadValues({}, cloned.animator), { bindings: updatedBindings });
1673
+ }
1674
+ return cloned;
1675
+ }
1676
+ function replaceUrlRefs(value, idMap) {
1677
+ return value.replace(/url\(#([^)]+)\)/g, (match, oldId) => {
1678
+ const newId = idMap.get(oldId);
1679
+ return newId ? "url(#" + newId + ")" : match;
1680
+ });
1681
+ }
1682
+
1683
+ // src/util/PxAnimatorUtil.ts
1684
+ function bezierToSvgPath(path, forceCurves = false) {
1685
+ var _a2, _b, _c, _d;
1686
+ const v = path.v;
1687
+ const i = path.i;
1688
+ const o = path.o;
1689
+ const c = path.c;
1690
+ if (!v.length) return "";
1691
+ const d = [];
1692
+ const len = v.length;
1693
+ d.push("M" + v[0][0] + "," + v[0][1]);
1694
+ for (let idx = 1; idx < len; idx++) {
1695
+ const prevV = v[idx - 1];
1696
+ const prevO = (_a2 = o == null ? void 0 : o[idx - 1]) != null ? _a2 : prevV;
1697
+ const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
1698
+ const currV = v[idx];
1699
+ const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
1700
+ if (isLine) {
1701
+ d.push("L" + currV[0] + "," + currV[1]);
1702
+ } else {
1703
+ d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
1704
+ }
1705
+ }
1706
+ if (c && len > 0) {
1707
+ const lastV = v[len - 1];
1708
+ const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
1709
+ const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
1710
+ const firstV = v[0];
1711
+ const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
1712
+ if (!isLine) {
1713
+ d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
1714
+ }
1715
+ d.push("z");
1716
+ }
1717
+ return d.join("");
1718
+ }
1719
+ function interpolateNum(a, b, t) {
1720
+ return a + (b - a) * t;
1721
+ }
1722
+ function interpolateVec(a, b, t) {
1723
+ const res = [];
1724
+ const count = Math.max(a.length, b.length);
1725
+ for (let i = 0; i < count; i++) {
1726
+ res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
1727
+ }
1728
+ return res;
1729
+ }
1730
+ function interpolateColor(a, b, t) {
1731
+ return [
1732
+ interpolateNum(a[0] || 0, b[0] || 0, t),
1733
+ interpolateNum(a[1] || 0, b[1] || 0, t),
1734
+ interpolateNum(a[2] || 0, b[2] || 0, t),
1735
+ interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
1736
+ ];
1737
+ }
1738
+ function interpolateBeziers(paths1, paths2, progress) {
1739
+ const count = Math.max(paths1.length, paths2.length);
1740
+ const res = [];
1741
+ for (let i = 0; i < count; i++) {
1742
+ res.push(interpolateBezier(paths1[i], paths2[i], progress));
1743
+ }
1744
+ return res;
1745
+ }
1746
+ function interpolateBezier(path1, path2, progress) {
1747
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
1748
+ if (!path1 || !path2) return path1 || path2 || { v: [] };
1749
+ const t = Math.min(Math.max(progress, 0), 1);
1750
+ const len = Math.min(path1.v.length, path2.v.length);
1751
+ const v = [];
1752
+ const i = [];
1753
+ const o = [];
1754
+ for (let idx = 0; idx < len; idx++) {
1755
+ const v1 = path1.v[idx];
1756
+ const v2 = path2.v[idx];
1757
+ v.push(interpolateVec(v1, v2, t));
1758
+ const i1 = (_b = (_a2 = path1.i) == null ? void 0 : _a2[idx]) != null ? _b : v1;
1759
+ const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
1760
+ i.push(interpolateVec(i1, i2, t));
1761
+ const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
1762
+ const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
1763
+ o.push(interpolateVec(o1, o2, t));
1764
+ }
1765
+ return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
1766
+ }
1767
+ function remap(value, inMin, inMax, outMin, outMax) {
1768
+ if (inMax === inMin) return outMin;
1769
+ const t = (value - inMin) / (inMax - inMin);
1770
+ return outMin + t * (outMax - outMin);
1771
+ }
1772
+ function solveCubicBezierX(p1x, p2x, x) {
1773
+ if (x <= 0) return 0;
1774
+ if (x >= 1) return 1;
1775
+ const cx = 3 * p1x;
1776
+ const bx = 3 * (p2x - p1x) - cx;
1777
+ const ax = 1 - cx - bx;
1778
+ function sampleX(t) {
1779
+ return ((ax * t + bx) * t + cx) * t;
1780
+ }
1781
+ function sampleDX(t) {
1782
+ return (3 * ax * t + 2 * bx) * t + cx;
1783
+ }
1784
+ let t2 = x;
1785
+ let t0 = 0;
1786
+ let t1 = 1;
1787
+ for (let i = 0; i < 8; i++) {
1788
+ const x2 = sampleX(t2) - x;
1789
+ if (Math.abs(x2) < 1e-6) return t2;
1790
+ const d2 = sampleDX(t2);
1791
+ if (Math.abs(d2) < 1e-6) break;
1792
+ t2 -= x2 / d2;
1793
+ }
1794
+ t2 = x;
1795
+ while (t0 < t1) {
1796
+ const x2 = sampleX(t2);
1797
+ if (Math.abs(x2 - x) < 1e-6) return t2;
1798
+ if (x > x2) t0 = t2;
1799
+ else t1 = t2;
1800
+ t2 = (t1 + t0) / 2;
1801
+ }
1802
+ return t2;
1803
+ }
1804
+ function cubicBezier(easing) {
1805
+ const [p1x, p1y, p2x, p2y] = easing;
1806
+ const cy = 3 * p1y;
1807
+ const by = 3 * (p2y - p1y) - cy;
1808
+ const ay = 1 - cy - by;
1809
+ function sampleCurveY(t) {
1810
+ return ((ay * t + by) * t + cy) * t;
1811
+ }
1812
+ return function(x) {
1813
+ return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
1814
+ };
1815
+ }
1816
+ function lerp2(a, b, t) {
1817
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
1818
+ }
1819
+ function subdivideCubicBezier(p0, p1, p2, p3, t) {
1820
+ const q0 = lerp2(p0, p1, t);
1821
+ const q1 = lerp2(p1, p2, t);
1822
+ const q2 = lerp2(p2, p3, t);
1823
+ const r0 = lerp2(q0, q1, t);
1824
+ const r1 = lerp2(q1, q2, t);
1825
+ const s = lerp2(r0, r1, t);
1826
+ return {
1827
+ left: [p0, q0, r0, s],
1828
+ right: [s, r1, q2, p3]
1829
+ };
1830
+ }
1831
+ function splitEasing(easing, xFraction) {
1832
+ if (!easing) return { left: void 0, right: void 0 };
1833
+ if (xFraction <= 0) return { left: void 0, right: easing };
1834
+ if (xFraction >= 1) return { left: easing, right: void 0 };
1835
+ const [x1, y1, x2, y2] = easing;
1836
+ const t = solveCubicBezierX(x1, x2, xFraction);
1837
+ const p0 = [0, 0];
1838
+ const p1 = [x1, y1];
1839
+ const p2 = [x2, y2];
1840
+ const p3 = [1, 1];
1841
+ const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
1842
+ const sx = left[3][0];
1843
+ const sy = left[3][1];
1844
+ let leftEasing;
1845
+ if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
1846
+ leftEasing = [
1847
+ left[1][0] / sx,
1848
+ left[1][1] / sy,
1849
+ left[2][0] / sx,
1850
+ left[2][1] / sy
1851
+ ];
1852
+ }
1853
+ let rightEasing;
1854
+ const rx = 1 - sx;
1855
+ const ry = 1 - sy;
1856
+ if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
1857
+ rightEasing = [
1858
+ (right[1][0] - sx) / rx,
1859
+ (right[1][1] - sy) / ry,
1860
+ (right[2][0] - sx) / rx,
1861
+ (right[2][1] - sy) / ry
1862
+ ];
1863
+ }
1864
+ return { left: leftEasing, right: rightEasing };
1865
+ }
1866
+ function reverseEasing(easing) {
1867
+ if (!easing) return void 0;
1868
+ return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
1869
+ }
1870
+ function toRGBA(color) {
1871
+ const r = Math.round(color[0] * 255);
1872
+ const g = Math.round(color[1] * 255);
1873
+ const b = Math.round(color[2] * 255);
1874
+ return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
1875
+ }
1876
+ function parseRgba(s) {
1877
+ var _a2;
1878
+ const inner = (_a2 = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a2[1];
1879
+ if (!inner) throw new Error("Invalid rgb/rgba format");
1880
+ const parts = inner.split(",").map((v) => +v.trim());
1881
+ return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
1882
+ }
1883
+ function parseHex(s) {
1884
+ const hex = s.slice(1);
1885
+ const isShort = hex.length <= 4;
1886
+ const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
1887
+ const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
1888
+ const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
1889
+ const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
1890
+ const result = [
1891
+ parseInt(r, 16) / 255,
1892
+ parseInt(g, 16) / 255,
1893
+ parseInt(b, 16) / 255
1894
+ ];
1895
+ if (a !== null) {
1896
+ result.push(parseInt(a, 16) / 255);
1897
+ }
1898
+ return result;
1899
+ }
1900
+ function parseColor(s) {
1901
+ if (!s) return void 0;
1902
+ if (Array.isArray(s)) return s;
1903
+ if (typeof s !== "string") return void 0;
1904
+ if (s.startsWith("#")) {
1905
+ return parseHex(s);
1906
+ } else if (s.startsWith("rgb")) {
1907
+ return parseRgba(s);
1908
+ } else {
1909
+ console.warn("Unsupported color format: " + s);
1910
+ }
1911
+ return void 0;
1912
+ }
1913
+ var PX_COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
1914
+ var PX_TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
1915
+ var PX_PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1916
+ function composeTransformParts(parts, opts) {
1917
+ var _a2;
1918
+ if (!parts) return "";
1919
+ const withUnits = (_a2 = opts == null ? void 0 : opts.withUnits) != null ? _a2 : true;
1920
+ const segs = [];
1921
+ const t = parts.translate;
1922
+ const o = parts.origin;
1923
+ const r = parts.rotate;
1924
+ const k = parts.skew;
1925
+ const s = parts.scale;
1926
+ const tu = withUnits ? "px" : "";
1927
+ const ru = withUnits ? "deg" : "";
1928
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
1929
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
1930
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
1931
+ if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
1932
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
1933
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
1934
+ return segs.join("");
1935
+ }
1936
+ function parseTransformParts(str2) {
1937
+ var _a2, _b;
1938
+ if (!str2 || typeof str2 !== "string") return void 0;
1939
+ const out = {};
1940
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
1941
+ const order = ["translate", "rotate", "skewX", "scale"];
1942
+ let lastIdx = -1;
1943
+ let m;
1944
+ while ((m = re.exec(str2)) !== null) {
1945
+ const fn = m[1];
1946
+ const idx = order.indexOf(fn);
1947
+ if (idx < 0 || idx <= lastIdx) return void 0;
1948
+ lastIdx = idx;
1949
+ const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
1950
+ if (nums.some((n) => Number.isNaN(n))) return void 0;
1951
+ if (fn === "translate") {
1952
+ if (nums.length < 1 || nums.length > 2) return void 0;
1953
+ out.translate = [nums[0], (_a2 = nums[1]) != null ? _a2 : 0];
1954
+ } else if (fn === "rotate") {
1955
+ if (nums.length !== 1) return void 0;
1956
+ out.rotate = nums[0];
1957
+ } else if (fn === "skewX") {
1958
+ if (nums.length !== 1) return void 0;
1959
+ out.skew = nums[0];
1960
+ } else {
1961
+ if (nums.length < 1 || nums.length > 2) return void 0;
1962
+ out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
1963
+ }
1964
+ }
1965
+ if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
1966
+ return Object.keys(out).length ? out : void 0;
1967
+ }
1968
+ var PX_STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1969
+ var PX_DEFAULT_DURATION_MS = 1e3;
1970
+ function kebabToCamelCaseWord(kebab) {
1971
+ return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
1972
+ }
1973
+ function isCamelCaseWord(word) {
1974
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
1975
+ }
1976
+ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
1977
+ // Transform/positioning
1978
+ "viewBox",
1979
+ "preserveAspectRatio",
1980
+ // Gradient
1981
+ "gradientUnits",
1982
+ "gradientTransform",
1983
+ "spreadMethod",
1984
+ // Pattern
1985
+ "patternUnits",
1986
+ "patternContentUnits",
1987
+ "patternTransform",
1988
+ // Clipping/masking
1989
+ "clipPathUnits",
1990
+ "maskUnits",
1991
+ "maskContentUnits",
1992
+ // Marker (SVG spec keeps these camelCase, like viewBox)
1993
+ "markerUnits",
1994
+ "markerWidth",
1995
+ "markerHeight",
1996
+ "refX",
1997
+ "refY",
1998
+ // Text
1999
+ "textLength",
2000
+ "lengthAdjust",
2001
+ "startOffset",
2002
+ // Filter
2003
+ "filterUnits",
2004
+ "primitiveUnits",
2005
+ "tableValues",
2006
+ // feFuncR/G/B/A transfer table (type="table")
2007
+ "stdDeviation",
2008
+ "baseFrequency",
2009
+ "numOctaves",
2010
+ "surfaceScale",
2011
+ "diffuseConstant",
2012
+ "specularConstant",
2013
+ "specularExponent",
2014
+ "kernelMatrix",
2015
+ "kernelUnitLength",
2016
+ "edgeMode",
2017
+ "preserveAlpha",
2018
+ "targetX",
2019
+ "targetY"
2020
+ // // Animation
2021
+ // 'attributeName',
2022
+ // 'attributeType',
2023
+ // 'calcMode',
2024
+ // 'keyTimes',
2025
+ // 'keySplines',
2026
+ // 'repeatCount',
2027
+ // 'repeatDur'
2028
+ ]);
2029
+ function camelCaseToKebabWordIfNeeded(camel) {
2030
+ return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
2031
+ }
2032
+ function clamp(value, min, max) {
2033
+ return Math.max(min, Math.min(value, max));
2034
+ }
2035
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
2036
+ if (t <= 0) return [P0[0], P0[1]];
2037
+ if (t >= 1) return [P3[0], P3[1]];
2038
+ const u = 1 - t;
2039
+ const u2 = u * u;
2040
+ const u3 = u2 * u;
2041
+ const t2 = t * t;
2042
+ const t3 = t2 * t;
2043
+ const w0 = u3;
2044
+ const w1 = 3 * t * u2;
2045
+ const w2 = 3 * t2 * u;
2046
+ const w3 = t3;
2047
+ return [
2048
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
2049
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
2050
+ ];
2051
+ }
2052
+ var BEZIER_T_NUDGE = 1e-4;
2053
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
2054
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
2055
+ if (result[0] === 0 && result[1] === 0) {
2056
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
2057
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
2058
+ }
2059
+ return result;
2060
+ }
2061
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
2062
+ const u = 1 - t;
2063
+ const a = 3 * u * u;
2064
+ const b = 6 * t * u;
2065
+ const c = 3 * t * t;
2066
+ return [
2067
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
2068
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
2069
+ ];
2070
+ }
2071
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
2072
+ const n = steps + 1;
2073
+ const ts = new Float64Array(n);
2074
+ const ds = new Float64Array(n);
2075
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
2076
+ ts[0] = 0;
2077
+ ds[0] = 0;
2078
+ let cum = 0;
2079
+ for (let i = 1; i < n; i++) {
2080
+ const t = i / steps;
2081
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
2082
+ const dx = cur[0] - prev[0];
2083
+ const dy = cur[1] - prev[1];
2084
+ cum += Math.sqrt(dx * dx + dy * dy);
2085
+ ts[i] = t;
2086
+ ds[i] = cum;
2087
+ prev = cur;
2088
+ }
2089
+ return { ts, ds };
2090
+ }
2091
+ function bezier2D_tForDistance(lut, distance) {
2092
+ const { ts, ds } = lut;
2093
+ const last = ds.length - 1;
2094
+ if (distance <= 0) return ts[0];
2095
+ if (distance >= ds[last]) return ts[last];
2096
+ let lo = 1;
2097
+ let hi = last;
2098
+ while (lo < hi) {
2099
+ const mid = lo + hi >>> 1;
2100
+ if (ds[mid] < distance) lo = mid + 1;
2101
+ else hi = mid;
2102
+ }
2103
+ const dPrev = ds[hi - 1];
2104
+ const dCur = ds[hi];
2105
+ const span = dCur - dPrev;
2106
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
2107
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
2108
+ }
2109
+ function bezier2D_arcAtT(lut, t) {
2110
+ const { ts, ds } = lut;
2111
+ const last = ts.length - 1;
2112
+ if (t <= ts[0]) return ds[0];
2113
+ if (t >= ts[last]) return ds[last];
2114
+ let lo = 1, hi = last;
2115
+ while (lo < hi) {
2116
+ const mid = lo + hi >>> 1;
2117
+ if (ts[mid] < t) lo = mid + 1;
2118
+ else hi = mid;
2119
+ }
2120
+ const tPrev = ts[hi - 1];
2121
+ const span = ts[hi] - tPrev;
2122
+ const frac = span > 0 ? (t - tPrev) / span : 0;
2123
+ return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
2124
+ }
2125
+ function invertEasing(easing) {
2126
+ if (!easing) return (y) => y;
2127
+ const flipped = [easing[1], easing[0], easing[3], easing[2]];
2128
+ return cubicBezier(flipped);
2129
+ }
2130
+
2131
+ // src/util/PxNodeProps.ts
2132
+ var PX_DISALLOWED_SVG_TAGS_LOWER = /* @__PURE__ */ new Set([
2133
+ "script",
2134
+ "foreignobject"
2135
+ ]);
2136
+ var URL_VALUE_ATTRS_LOWER = /* @__PURE__ */ new Set([
2137
+ "href",
2138
+ // <use>, <image>
2139
+ "xlink:href",
2140
+ // legacy <use>
2141
+ "src",
2142
+ // <image>
2143
+ "filter",
2144
+ // url(#filterId)
2145
+ "clippath",
2146
+ // clip-path="url(#…)"
2147
+ "mask",
2148
+ // url(#maskId)
2149
+ "markerstart",
2150
+ // marker-start="url(#…)"
2151
+ "markermid",
2152
+ // marker-mid="url(#…)"
2153
+ "markerend"
2154
+ // marker-end="url(#…)"
2155
+ ]);
2156
+ var IMAGE_REF_ATTRS_LOWER = /* @__PURE__ */ new Set(["href", "xlink:href", "src"]);
2157
+ var PX_CSS_ONLY_STYLE_PROPS = /* @__PURE__ */ new Set(["mixBlendMode", "isolation"]);
2158
+ var DATA_RASTER_IMAGE_RE = /^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/i;
2159
+ var DATA_SVG_IMAGE_RE = /^data:image\/svg\+xml(?:;[^,]*)?,/i;
2160
+ var DATA_IMAGE_BASE64_PAYLOAD_RE = /^data:image\/[^;,]*;base64,([A-Za-z0-9+/]{8})/i;
2161
+ var BASE64_RASTER_MAGICS = ["iVBORw0K", "/9j/", "R0lGOD", "UklGR", "Qk"];
2162
+ function isContentSniffedRasterImage(str2) {
2163
+ const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str2);
2164
+ return !!m && BASE64_RASTER_MAGICS.some((magic) => m[1].startsWith(magic));
2165
+ }
2166
+ function isDangerousAttrName(nameLower) {
2167
+ if (nameLower.startsWith("on")) return true;
2168
+ return false;
2169
+ }
2170
+ function sanitizeAttributeValue(name, value) {
2171
+ const nameLower = name.toLowerCase();
2172
+ if (isDangerousAttrName(nameLower)) {
2173
+ console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
2174
+ return void 0;
2175
+ }
2176
+ if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopcolor") {
2177
+ const str2 = String(value);
2178
+ if (str2.includes("url(") && !/^url\(#[^)]+\)$/.test(str2)) {
2179
+ console.warn('Attribute "' + nameLower + '" blocked: url() must be internal url(#id), got:', value);
2180
+ return void 0;
2181
+ }
2182
+ return value;
2183
+ }
2184
+ if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {
2185
+ const str2 = String(value);
2186
+ if (str2.startsWith("#")) return value;
2187
+ if (/^url\(#[^)]+\)$/.test(str2)) return value;
2188
+ if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str2) || DATA_SVG_IMAGE_RE.test(str2) || isContentSniffedRasterImage(str2))) return value;
2189
+ console.warn('Attribute "' + nameLower + '" blocked: must be #id, url(#id), or data:image/\u2026 URI, got:', value);
2190
+ return void 0;
2191
+ }
2192
+ return value;
2193
+ }
2194
+ function toDomProps(props) {
2195
+ const propsCopy = {};
2196
+ for (const rawKey of Object.keys(props)) {
2197
+ const key = kebabToCamelCaseWord(rawKey);
2198
+ if (INTERNAL_ATTRS.has(key)) continue;
2199
+ if (key === "style") continue;
2200
+ let value = props[rawKey];
2201
+ if (PX_COLOR_ATTR_NAMES.has(key) && Array.isArray(value)) {
2202
+ propsCopy[key] = toRGBA(value);
2203
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
2204
+ const parts = value.value && typeof value.value === "object" ? value.value : value;
2205
+ propsCopy[TRANSFORM_ATTR] = composeTransformParts(parts, { withUnits: false });
2206
+ } else if (PX_TRANSFORM_FN_NAMES.has(key)) {
2207
+ if (Array.isArray(value)) {
2208
+ if (key === "translate") value = value.map((v) => v + "px");
2209
+ value = value.join(",");
2210
+ }
2211
+ if (key === "rotate") value = value + "deg";
2212
+ propsCopy[TRANSFORM_ATTR] = key + "(" + value + ")";
2213
+ } else if (Array.isArray(value)) {
2214
+ propsCopy[key] = value.join(",");
2215
+ } else if (value !== void 0 && value !== null) {
2216
+ propsCopy[key] = String(value);
2217
+ }
2218
+ }
2219
+ return propsCopy;
2220
+ }
2221
+
2222
+ // src/materialize/PxMotionPath.ts
2223
+ function getKfTranslate(kf) {
2224
+ const v = keyframeValue(kf);
2225
+ if (!v) return void 0;
2226
+ if (Array.isArray(v) && v.length >= 2 && typeof v[0] === "number" && typeof v[1] === "number") {
2227
+ return [v[0], v[1]];
2228
+ }
2229
+ const tr = v.translate;
2230
+ if (Array.isArray(tr) && tr.length >= 2) return [tr[0], tr[1]];
2231
+ return void 0;
2232
+ }
2233
+ function getKfTime(kf) {
2234
+ return keyframeTime(kf);
2235
+ }
2236
+ function getKfEasing(kf) {
2237
+ return keyframeEasing(kf);
2238
+ }
2239
+ function propAnimIsMotionPath(anim) {
2240
+ const kfs = anim.keyframes;
2241
+ if (!Array.isArray(kfs)) return false;
2242
+ if (anim.autoOrient) return true;
2243
+ for (const kf of kfs) {
2244
+ if (keyframeTangentIn(kf) || keyframeTangentOut(kf)) return true;
2245
+ }
2246
+ return false;
2247
+ }
2248
+ var _segmentCache = /* @__PURE__ */ new WeakMap();
2249
+ function getSegmentCache(prevKf, nextKf, prevPos, nextPos) {
2250
+ let byNext = _segmentCache.get(prevKf);
2251
+ const existing = byNext == null ? void 0 : byNext.get(nextKf);
2252
+ if (existing) return existing;
2253
+ const to = keyframeTangentOut(prevKf);
2254
+ const ti = keyframeTangentIn(nextKf);
2255
+ const P1 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];
2256
+ const P2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];
2257
+ const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);
2258
+ const entry = {
2259
+ P0: prevPos,
2260
+ P1,
2261
+ P2,
2262
+ P3: nextPos,
2263
+ lut,
2264
+ totalArc: lut.ds[lut.ds.length - 1]
2265
+ };
2266
+ if (!byNext) {
2267
+ byNext = /* @__PURE__ */ new WeakMap();
2268
+ _segmentCache.set(prevKf, byNext);
2269
+ }
2270
+ byNext.set(nextKf, entry);
2271
+ return entry;
2272
+ }
2273
+ function evaluateMotionPathSegment(prevKf, nextKf, prevPos, nextPos, localProgress, autoOrient) {
2274
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2275
+ const t = seg.totalArc === 0 ? localProgress : tFromArcFraction(seg.lut, localProgress);
2276
+ const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2277
+ if (!autoOrient) return { translate: point };
2278
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2279
+ const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2280
+ return { translate: point, rotateDeg };
2281
+ }
2282
+ function tFromArcFraction(lut, arcFrac) {
2283
+ const total = lut.ds[lut.ds.length - 1];
2284
+ const target = arcFrac * total;
2285
+ const { ts, ds } = lut;
2286
+ const last = ds.length - 1;
2287
+ if (target <= 0) return ts[0];
2288
+ if (target >= ds[last]) return ts[last];
2289
+ let lo = 1, hi = last;
2290
+ while (lo < hi) {
2291
+ const mid = lo + hi >>> 1;
2292
+ if (ds[mid] < target) lo = mid + 1;
2293
+ else hi = mid;
2294
+ }
2295
+ const dPrev = ds[hi - 1];
2296
+ const span = ds[hi] - dPrev;
2297
+ const frac = span > 0 ? (target - dPrev) / span : 0;
2298
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
2299
+ }
2300
+ var DEFAULT_FLATNESS_TOL = 0.5;
2301
+ var DEFAULT_ROTATION_TOL = 5;
2302
+ var DEFAULT_MAX_SAMPLES = 32;
2303
+ function materializeMotionPathInPropAnim(anim, opts) {
2304
+ var _a2, _b, _c;
2305
+ if (!propAnimIsMotionPath(anim)) return anim;
2306
+ const kfs = anim.keyframes;
2307
+ if (!Array.isArray(kfs) || kfs.length < 2) return anim;
2308
+ const autoOrient = !!anim.autoOrient;
2309
+ const flatnessTol = (_a2 = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a2 : DEFAULT_FLATNESS_TOL;
2310
+ const rotationTol = (_b = opts == null ? void 0 : opts.rotationTolerance) != null ? _b : DEFAULT_ROTATION_TOL;
2311
+ const maxSamples = (_c = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _c : DEFAULT_MAX_SAMPLES;
2312
+ const out = [];
2313
+ const firstPos = getKfTranslate(kfs[0]);
2314
+ if (!firstPos) return anim;
2315
+ const firstRotate = autoOrient ? derivAngleForFirstKf(kfs[0], kfs[1]) : void 0;
2316
+ out.push(makeOutKf(
2317
+ getKfTime(kfs[0]),
2318
+ buildOutKfValue(getKfValueParts(kfs[0]), getKfValueParts(kfs[0]), 0, firstPos, firstRotate, autoOrient)
2319
+ ));
2320
+ for (let i = 0; i < kfs.length - 1; i++) {
2321
+ const prevKf = kfs[i];
2322
+ const nextKf = kfs[i + 1];
2323
+ const prevPos = getKfTranslate(prevKf);
2324
+ const nextPos = getKfTranslate(nextKf);
2325
+ if (!prevPos || !nextPos) {
2326
+ out.push(makeOutKf(
2327
+ getKfTime(nextKf),
2328
+ buildOutKfValue(getKfValueParts(nextKf), getKfValueParts(nextKf), 1, nextPos != null ? nextPos : [0, 0], void 0, autoOrient)
2329
+ ));
2330
+ continue;
2331
+ }
2332
+ if (autoOrient && i > 0) {
2333
+ insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
2334
+ }
2335
+ materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
2336
+ }
2337
+ const lastInE = getKfEasing(kfs[kfs.length - 1]);
2338
+ if (lastInE) out[out.length - 1].e = lastInE;
2339
+ if (autoOrient) unwrapAutoOrientRotations(out);
2340
+ const result = { keyframes: out };
2341
+ if (anim.loop !== void 0) result.loop = anim.loop;
2342
+ return result;
2343
+ }
2344
+ function unwrapAutoOrientRotations(kfs) {
2345
+ let prev;
2346
+ for (const kf of kfs) {
2347
+ const v = keyframeValue(kf);
2348
+ if (!v || typeof v.rotate !== "number") continue;
2349
+ if (prev === void 0) {
2350
+ prev = v.rotate;
2351
+ continue;
2352
+ }
2353
+ let r = v.rotate;
2354
+ while (r - prev > 180) r -= 360;
2355
+ while (r - prev < -180) r += 360;
2356
+ v.rotate = r;
2357
+ prev = r;
2358
+ }
2359
+ }
2360
+ function makeOutKf(time, value) {
2361
+ return { t: time, v: value };
2362
+ }
2363
+ function getKfValueParts(kf) {
2364
+ const v = keyframeValue(kf);
2365
+ if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
2366
+ return v;
2367
+ }
2368
+ function interpolatePart(prev, next, p) {
2369
+ if (prev === void 0) return next;
2370
+ if (next === void 0) return prev;
2371
+ if (typeof prev === "number" && typeof next === "number") {
2372
+ return prev + (next - prev) * p;
2373
+ }
2374
+ if (Array.isArray(prev) && Array.isArray(next) && prev.length === next.length) {
2375
+ const out = new Array(prev.length);
2376
+ for (let i = 0; i < prev.length; i++) {
2377
+ const a = typeof prev[i] === "number" ? prev[i] : 0;
2378
+ const b = typeof next[i] === "number" ? next[i] : 0;
2379
+ out[i] = a + (b - a) * p;
2380
+ }
2381
+ return out;
2382
+ }
2383
+ return p < 0.5 ? prev : next;
2384
+ }
2385
+ function buildOutKfValue(prevV, nextV, p, translate, rotateDegFromAutoOrient, autoOrient) {
2386
+ const value = { translate };
2387
+ const keys = /* @__PURE__ */ new Set();
2388
+ if (prevV) for (const k of Object.keys(prevV)) keys.add(k);
2389
+ if (nextV) for (const k of Object.keys(nextV)) keys.add(k);
2390
+ for (const k of keys) {
2391
+ if (k === "translate") continue;
2392
+ if (k === "rotate" && autoOrient) continue;
2393
+ const pv = prevV == null ? void 0 : prevV[k];
2394
+ const nv = nextV == null ? void 0 : nextV[k];
2395
+ if (pv === void 0 && nv === void 0) continue;
2396
+ value[k] = interpolatePart(pv, nv, p);
2397
+ }
2398
+ if (rotateDegFromAutoOrient !== void 0) {
2399
+ value.rotate = rotateDegFromAutoOrient + explicitRotateAt(prevV, nextV, p);
2400
+ }
2401
+ return value;
2402
+ }
2403
+ function explicitRotateAt(prevV, nextV, p) {
2404
+ const pv = typeof (prevV == null ? void 0 : prevV.rotate) === "number" ? prevV.rotate : void 0;
2405
+ const nv = typeof (nextV == null ? void 0 : nextV.rotate) === "number" ? nextV.rotate : void 0;
2406
+ if (pv === void 0 && nv === void 0) return 0;
2407
+ const r = interpolatePart(pv, nv, p);
2408
+ return typeof r === "number" ? r : 0;
2409
+ }
2410
+ function derivAngleForFirstKf(kf0, kf1) {
2411
+ const p0 = getKfTranslate(kf0);
2412
+ const p1 = getKfTranslate(kf1);
2413
+ if (!p0 || !p1) return 0;
2414
+ const seg = getSegmentCache(kf0, kf1, p0, p1);
2415
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
2416
+ return Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2417
+ }
2418
+ function wrappedAngleDelta(a, b) {
2419
+ let d = a - b;
2420
+ while (d > 180) d -= 360;
2421
+ while (d < -180) d += 360;
2422
+ return d;
2423
+ }
2424
+ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol) {
2425
+ const lastKf = out[out.length - 1];
2426
+ const lastV = keyframeValue(lastKf);
2427
+ const prevExit = lastV == null ? void 0 : lastV.rotate;
2428
+ if (typeof prevExit !== "number") return;
2429
+ const boundaryV = getKfValueParts(prevKf);
2430
+ const prevExitTangent = prevExit - explicitRotateAt(boundaryV, boundaryV, 0);
2431
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2432
+ const tanAtStart = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
2433
+ const nextEntry = Math.atan2(tanAtStart[1], tanAtStart[0]) * 180 / Math.PI;
2434
+ const delta = wrappedAngleDelta(nextEntry, prevExitTangent);
2435
+ if (Math.abs(delta) <= rotationTol) return;
2436
+ const prevTime = getKfTime(prevKf);
2437
+ const stepTime = Math.min(prevTime + CORNER_STEP_AFTER_BOUNDARY_MS, (prevTime + getKfTime(nextKf)) / 2);
2438
+ const dupValue = buildOutKfValue(
2439
+ getKfValueParts(prevKf),
2440
+ getKfValueParts(prevKf),
2441
+ 0,
2442
+ prevPos,
2443
+ nextEntry,
2444
+ true
2445
+ );
2446
+ out.push(makeOutKf(stepTime, dupValue));
2447
+ }
2448
+ var CORNER_STEP_AFTER_BOUNDARY_MS = 0.05;
2449
+ function materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
2450
+ const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
2451
+ const prevTime = getKfTime(prevKf);
2452
+ const nextTime = getKfTime(nextKf);
2453
+ const prevEasing = getKfEasing(prevKf);
2454
+ const invertFn = invertEasing(prevEasing);
2455
+ const prevV = getKfValueParts(prevKf);
2456
+ const nextV = getKfValueParts(nextKf);
2457
+ const interiorTs = computeSampleTs(seg, autoOrient, flatnessTol, rotationTol, maxSamples);
2458
+ const samples = [];
2459
+ for (const t of interiorTs) {
2460
+ const arc = bezier2D_arcAtT(seg.lut, t);
2461
+ const p = clamp(seg.totalArc > 0 ? arc / seg.totalArc : t, 0, 1);
2462
+ const u = clamp(invertFn(p), 0, 1);
2463
+ const pos = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2464
+ const sample = { u, p, pos };
2465
+ if (autoOrient) {
2466
+ const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2467
+ sample.rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
2468
+ }
2469
+ samples.push(sample);
2470
+ }
2471
+ let remaining = prevEasing;
2472
+ let prevU = 0;
2473
+ const startIdx = out.length - 1;
2474
+ for (let i = 0; i < samples.length; i++) {
2475
+ const s = samples[i];
2476
+ const xFrac = prevU < 1 ? clamp((s.u - prevU) / (1 - prevU), 0, 1) : 1;
2477
+ const { left, right } = splitEasing(remaining, xFrac);
2478
+ const ownerIdx = i === 0 ? startIdx : out.length - 1;
2479
+ if (left) out[ownerIdx].e = left;
2480
+ else delete out[ownerIdx].e;
2481
+ const tGlobal = prevTime + s.u * (nextTime - prevTime);
2482
+ const value = buildOutKfValue(prevV, nextV, s.p, s.pos, s.rotateDeg, autoOrient);
2483
+ out.push(makeOutKf(tGlobal, value));
2484
+ remaining = right;
2485
+ prevU = s.u;
2486
+ }
2487
+ }
2488
+ function computeSampleTs(seg, autoOrient, flatnessTol, rotationTol, maxSamples) {
2489
+ const extremes = [];
2490
+ addAxisExtremes(seg.P0[0], seg.P1[0], seg.P2[0], seg.P3[0], extremes);
2491
+ addAxisExtremes(seg.P0[1], seg.P1[1], seg.P2[1], seg.P3[1], extremes);
2492
+ extremes.sort((a, b) => a - b);
2493
+ const critical = [0];
2494
+ for (const t of extremes) {
2495
+ if (t > critical[critical.length - 1] + 1e-6 && t < 1 - 1e-6) {
2496
+ critical.push(t);
2497
+ }
2498
+ }
2499
+ critical.push(1);
2500
+ const out = [];
2501
+ const budget = { remaining: maxSamples - critical.length };
2502
+ for (let i = 0; i < critical.length - 1; i++) {
2503
+ bisect(critical[i], critical[i + 1], out, seg, autoOrient, flatnessTol, rotationTol, budget);
2504
+ }
2505
+ return out;
2506
+ }
2507
+ function addAxisExtremes(p0, p1, p2, p3, out) {
2508
+ const a = p1 - p0;
2509
+ const b = p2 - p1;
2510
+ const c = p3 - p2;
2511
+ const A = a - 2 * b + c;
2512
+ const B = 2 * (b - a);
2513
+ const C = a;
2514
+ if (Math.abs(A) < 1e-10) {
2515
+ if (Math.abs(B) > 1e-10) {
2516
+ const t = -C / B;
2517
+ if (t > 1e-6 && t < 1 - 1e-6) out.push(t);
2518
+ }
2519
+ return;
2520
+ }
2521
+ const disc = B * B - 4 * A * C;
2522
+ if (disc < 0) return;
2523
+ const sq = Math.sqrt(disc);
2524
+ const t1 = (-B - sq) / (2 * A);
2525
+ const t2 = (-B + sq) / (2 * A);
2526
+ if (t1 > 1e-6 && t1 < 1 - 1e-6) out.push(t1);
2527
+ if (t2 > 1e-6 && t2 < 1 - 1e-6) out.push(t2);
2528
+ }
2529
+ function bisect(tA, tB, out, seg, autoOrient, flatnessTol, rotationTol, budget) {
2530
+ const tMid = (tA + tB) / 2;
2531
+ const pA = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);
2532
+ const pB = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);
2533
+ const span = tB - tA;
2534
+ const p25 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.25);
2535
+ const p50 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tMid);
2536
+ const p75 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.75);
2537
+ const dev = Math.max(
2538
+ perpDist(p25, pA, pB),
2539
+ perpDist(p50, pA, pB),
2540
+ perpDist(p75, pA, pB)
2541
+ );
2542
+ let rotOk = true;
2543
+ if (autoOrient) {
2544
+ const tanA = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);
2545
+ const tanB = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);
2546
+ const angA = Math.atan2(tanA[1], tanA[0]) * 180 / Math.PI;
2547
+ const angB = Math.atan2(tanB[1], tanB[0]) * 180 / Math.PI;
2548
+ let delta = Math.abs(angA - angB);
2549
+ if (delta > 180) delta = 360 - delta;
2550
+ if (delta > rotationTol) rotOk = false;
2551
+ }
2552
+ if (dev <= flatnessTol && rotOk || budget.remaining <= 0 || span < 1e-6) {
2553
+ out.push(tB);
2554
+ return;
2555
+ }
2556
+ budget.remaining -= 1;
2557
+ bisect(tA, tMid, out, seg, autoOrient, flatnessTol, rotationTol, budget);
2558
+ bisect(tMid, tB, out, seg, autoOrient, flatnessTol, rotationTol, budget);
2559
+ }
2560
+ function perpDist(q, pA, pB) {
2561
+ const dx = pB[0] - pA[0];
2562
+ const dy = pB[1] - pA[1];
2563
+ const len2 = dx * dx + dy * dy;
2564
+ if (len2 < 1e-20) {
2565
+ const qdx = q[0] - pA[0];
2566
+ const qdy = q[1] - pA[1];
2567
+ return Math.sqrt(qdx * qdx + qdy * qdy);
2568
+ }
2569
+ const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
2570
+ return Math.abs(cross) / Math.sqrt(len2);
2571
+ }
2572
+ function materializeMotionPathsInTree(root, opts) {
2573
+ const out = walkAndMaterialize(root, opts);
2574
+ return out != null ? out : root;
2575
+ }
2576
+ function walkAndMaterialize(node, opts) {
2577
+ let newChildren;
2578
+ if (node.children) {
2579
+ for (let i = 0; i < node.children.length; i++) {
2580
+ const ch = node.children[i];
2581
+ const ret = walkAndMaterialize(ch, opts);
2582
+ if (ret !== null) {
2583
+ if (!newChildren) newChildren = node.children.slice();
2584
+ newChildren[i] = ret;
2585
+ }
2586
+ }
2587
+ }
2588
+ let newAnimate;
2589
+ const animBucket = node.animate;
2590
+ if (animBucket && typeof animBucket === "object" && !Array.isArray(animBucket)) {
2591
+ const animDef = animBucket;
2592
+ const transformAnim = animDef.transform;
2593
+ if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
2594
+ const materialized = materializeMotionPathInPropAnim(transformAnim, opts);
2595
+ if (materialized !== transformAnim) {
2596
+ newAnimate = __spreadProps(__spreadValues({}, animDef), { transform: materialized });
2597
+ }
2598
+ }
2599
+ }
2600
+ if (!newChildren && !newAnimate) return null;
2601
+ const cloned = __spreadValues({}, node);
2602
+ if (newChildren) cloned.children = newChildren;
2603
+ if (newAnimate) cloned.animate = newAnimate;
2604
+ return cloned;
2605
+ }
2606
+
2607
+ // src/animation/PxDefinitions.ts
2608
+ var PX_LOOP_JUMP_SHIFT_MS = 1;
2609
+ function deepEqualValue(a, b) {
2610
+ if (a === b) return true;
2611
+ if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
2612
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
2613
+ const ka = Object.keys(a);
2614
+ const kb = Object.keys(b);
2615
+ if (ka.length !== kb.length) return false;
2616
+ return ka.every((k) => deepEqualValue(a[k], b[k]));
2617
+ }
2618
+ function parsePathCommands(d) {
2619
+ const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
2620
+ const commands = [];
2621
+ let currentCommand = null;
2622
+ for (const token of tokens) {
2623
+ if (/[MLCZmlcz]/.test(token)) {
2624
+ currentCommand = { type: token, values: [] };
2625
+ commands.push(currentCommand);
2626
+ } else if (currentCommand) {
2627
+ const value = +token;
2628
+ currentCommand.values.push(Number.isNaN(value) ? 0 : value);
2629
+ }
2630
+ }
2631
+ return commands;
2632
+ }
2633
+ function parseSvgPathToBezier(d) {
2634
+ const res = [];
2635
+ let currentPath;
2636
+ const commands = parsePathCommands(d);
2637
+ for (const command of commands) {
2638
+ const type = command.type;
2639
+ const values = command.values;
2640
+ if (type === "M" || type === "m") {
2641
+ const x = values[0] || 0;
2642
+ const y = values[1] || 0;
2643
+ currentPath = {
2644
+ v: [[x, y]],
2645
+ i: [[x, y]],
2646
+ o: [[x, y]],
2647
+ c: false
2648
+ };
2649
+ res.push(currentPath);
2650
+ continue;
2651
+ }
2652
+ if (!currentPath) {
2653
+ currentPath = {
2654
+ v: [[0, 0]],
2655
+ i: [[0, 0]],
2656
+ o: [[0, 0]],
2657
+ c: false
2658
+ };
2659
+ res.push(currentPath);
2660
+ }
2661
+ if (type === "L") {
2662
+ const x = values[0] || 0;
2663
+ const y = values[1] || 0;
2664
+ currentPath.v.push([x, y]);
2665
+ currentPath.i.push([x, y]);
2666
+ currentPath.o.push([x, y]);
2667
+ } else if (type === "C") {
2668
+ const outX = values[0] || 0;
2669
+ const outY = values[1] || 0;
2670
+ const inX2 = values[2] || 0;
2671
+ const inY2 = values[3] || 0;
2672
+ const x2 = values[4] || 0;
2673
+ const y2 = values[5] || 0;
2674
+ currentPath.o[currentPath.o.length - 1] = [outX, outY];
2675
+ currentPath.v.push([x2, y2]);
2676
+ currentPath.i.push([inX2, inY2]);
2677
+ currentPath.o.push([x2, y2]);
2678
+ } else if (type === "Z" || type === "z") {
2679
+ currentPath.c = true;
2680
+ } else {
2681
+ console.warn('Unsupported path command "' + type + '"');
2682
+ }
2683
+ }
2684
+ return res;
2685
+ }
2686
+ function extractPathData(str2) {
2687
+ if (str2.startsWith("path(") && str2.endsWith(")")) {
2688
+ return str2.slice(5, -1);
2689
+ }
2690
+ if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str2)) {
2691
+ return str2;
2692
+ }
2693
+ return void 0;
2694
+ }
2695
+ function isPathString(value) {
2696
+ return typeof value === "string" && extractPathData(value) !== void 0;
2697
+ }
2698
+ function normalizePathValue(value) {
2699
+ if (value && typeof value === "object" && typeof value.pathData === "string") {
2700
+ const d = extractPathData(value.pathData);
2701
+ return d ? { paths: parseSvgPathToBezier(d) } : value;
2702
+ }
2703
+ if (value && typeof value === "object" && "paths" in value) {
2704
+ const pathsArray = value.paths;
2705
+ if (Array.isArray(pathsArray) && pathsArray.length > 0) {
2706
+ if (isPathString(pathsArray[0])) {
2707
+ const paths = [];
2708
+ for (const pathStr2 of pathsArray) {
2709
+ const d = extractPathData(pathStr2);
2710
+ if (d) {
2711
+ paths.push(...parseSvgPathToBezier(d));
2712
+ }
2713
+ }
2714
+ return { paths };
2715
+ }
2716
+ }
2717
+ return value;
2718
+ }
2719
+ if (Array.isArray(value)) {
2720
+ if (value.length > 0 && isPathString(value[0])) {
2721
+ const paths = [];
2722
+ for (const pathStr2 of value) {
2723
+ const d = extractPathData(pathStr2);
2724
+ if (d) {
2725
+ paths.push(...parseSvgPathToBezier(d));
2726
+ }
2727
+ }
2728
+ return { paths };
2729
+ }
2730
+ return { paths: value };
2731
+ }
2732
+ if (isPathString(value)) {
2733
+ const d = extractPathData(value);
2734
+ return { paths: parseSvgPathToBezier(d) };
2735
+ }
2736
+ return value;
2737
+ }
2738
+ function resolveEasing(easing, defs) {
2739
+ var _a2;
2740
+ if (!easing) return void 0;
2741
+ if (Array.isArray(easing)) {
2742
+ return easing;
2743
+ }
2744
+ if ((_a2 = defs == null ? void 0 : defs.easings) == null ? void 0 : _a2[easing]) {
2745
+ return defs.easings[easing];
2746
+ }
2747
+ console.warn("Unknown easing name: " + easing);
2748
+ return void 0;
2749
+ }
2750
+ function resolveAnimation(animRef, defs) {
2751
+ var _a2;
2752
+ if (typeof animRef === "string") {
2753
+ const resolved = (_a2 = defs == null ? void 0 : defs.animations) == null ? void 0 : _a2[animRef];
2754
+ if (!resolved) {
2755
+ console.warn("Unknown animation name: " + animRef);
2756
+ }
2757
+ return resolved;
2758
+ }
2759
+ return animRef;
2760
+ }
2761
+ function resolveElementAnimation(animate, defs) {
2762
+ if (!animate) return [];
2763
+ const results = [];
2764
+ if (typeof animate === "string") {
2765
+ const resolved = resolveAnimation(animate, defs);
2766
+ if (resolved) results.push(resolved);
2767
+ } else if (Array.isArray(animate)) {
2768
+ for (const item of animate) {
2769
+ const resolved = resolveAnimation(item, defs);
2770
+ if (resolved) results.push(resolved);
2771
+ }
2772
+ } else {
2773
+ results.push(animate);
2774
+ }
2775
+ return results;
2776
+ }
2777
+ function interpolateValue(propName, a, b, t) {
2778
+ var _a2, _b;
2779
+ if (propName === "d") {
2780
+ const aPaths = (_a2 = a == null ? void 0 : a.paths) != null ? _a2 : Array.isArray(a) ? a : [];
2781
+ const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
2782
+ return { paths: interpolateBeziers(aPaths, bPaths, t) };
2783
+ }
2784
+ if (PX_COLOR_ATTR_NAMES.has(propName)) {
2785
+ return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
2786
+ }
2787
+ if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
2788
+ return interpolateTransformParts(a, b, t);
2789
+ }
2790
+ if (propName === "rotate" && typeof a === "number" && typeof b === "number") {
2791
+ return interpolateNum(a, b, t);
2792
+ }
2793
+ if (PX_TRANSFORM_FN_NAMES.has(propName) || propName === "stroke-dasharray" || propName === "strokeDasharray") {
2794
+ return interpolateVec(a || [], b || [], t);
2795
+ }
2796
+ return interpolateNum(+(a || 0), +(b || 0), t);
2797
+ }
2798
+ function interpolateTransformParts(a, b, t) {
2799
+ const keys = /* @__PURE__ */ new Set([...Object.keys(a != null ? a : {}), ...Object.keys(b != null ? b : {})]);
2800
+ const out = {};
2801
+ for (const k of keys) {
2802
+ const av = a == null ? void 0 : a[k];
2803
+ const bv = b == null ? void 0 : b[k];
2804
+ if (k === "rotate" || k === "skew") {
2805
+ out[k] = interpolateNum(+(av != null ? av : 0), +(bv != null ? bv : 0), t);
2806
+ } else if (k === "translate" || k === "scale" || k === "origin") {
2807
+ const fallback = k === "scale" ? [1, 1] : [0, 0];
2808
+ out[k] = interpolateVec(av || fallback, bv || fallback, t);
2809
+ } else {
2810
+ out[k] = bv != null ? bv : av;
2811
+ }
2812
+ }
2813
+ return out;
2814
+ }
2815
+ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2816
+ var _a2, _b, _c, _d, _e;
2817
+ const totalIntervals = keyframes.length - 1;
2818
+ const segCount = clamp((_a2 = loop.segmentCount) != null ? _a2 : totalIntervals, 1, totalIntervals);
2819
+ let segKfs;
2820
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2821
+ segKfs = keyframes.slice(0, segCount + 1);
2822
+ } else {
2823
+ segKfs = keyframes.slice(totalIntervals - segCount);
2824
+ }
2825
+ const firstT = (_b = keyframes[0].t) != null ? _b : 0;
2826
+ const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
2827
+ let fillStart, fillEnd;
2828
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2829
+ fillStart = 0;
2830
+ fillEnd = firstT;
2831
+ } else {
2832
+ fillStart = lastT;
2833
+ fillEnd = duration;
2834
+ }
2835
+ const fillDuration = fillEnd - fillStart;
2836
+ if (fillDuration <= 0) return keyframes;
2837
+ const segStartT = (_d = segKfs[0].t) != null ? _d : 0;
2838
+ const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
2839
+ const segDuration = segEndT - segStartT;
2840
+ if (segDuration <= 0) return keyframes;
2841
+ const template = segKfs.map((kf) => ({
2842
+ relT: (kf.t - segStartT) / segDuration,
2843
+ v: kf.v,
2844
+ e: kf.e,
2845
+ tangentIn: keyframeTangentIn(kf),
2846
+ tangentOut: keyframeTangentOut(kf)
2847
+ }));
2848
+ const fullReps = Math.floor(fillDuration / segDuration);
2849
+ const remainder = fillDuration - fullReps * segDuration;
2850
+ const partialFraction = remainder / segDuration;
2851
+ const looped = [];
2852
+ const separateBoundary = loop.repeatAt !== PxLoopRepeatAt.start;
2853
+ const originalTerminalKf = keyframes[keyframes.length - 1];
2854
+ let terminalEasingOverride;
2855
+ let hasTerminalEasingOverride = false;
2856
+ function appendRep(repStart, isReversed, partial) {
2857
+ var _a3;
2858
+ let entries;
2859
+ if (isReversed) {
2860
+ entries = [];
2861
+ for (let i = template.length - 1; i >= 0; i--) {
2862
+ entries.push({
2863
+ relT: 1 - template[i].relT,
2864
+ v: template[i].v,
2865
+ // Easing for reversed transition: use reversed easing from the forward "from" keyframe
2866
+ e: i > 0 ? reverseEasing(template[i - 1].e) : void 0,
2867
+ // Reversed traversal swaps each vertex's in/out spatial tangents
2868
+ // (geometry is identical, walked backwards), so curvature and
2869
+ // auto-orientation survive the reversed rep.
2870
+ tangentIn: template[i].tangentOut,
2871
+ tangentOut: template[i].tangentIn
2872
+ });
2873
+ }
2874
+ } else {
2875
+ entries = template;
2876
+ }
2877
+ const cutRelT = partial !== void 0 ? partial : 1;
2878
+ for (let i = 0; i < entries.length; i++) {
2879
+ const entry = entries[i];
2880
+ if (entry.relT > cutRelT + 1e-9) {
2881
+ const prev = entries[i - 1];
2882
+ const intervalSpan = entry.relT - prev.relT;
2883
+ const localFrac = (cutRelT - prev.relT) / intervalSpan;
2884
+ const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
2885
+ const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
2886
+ const { left: leftEasing } = splitEasing(prev.e, localFrac);
2887
+ if (looped.length > 0 && prev.relT <= cutRelT) {
2888
+ looped[looped.length - 1].e = leftEasing;
2889
+ }
2890
+ looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
2891
+ return;
2892
+ }
2893
+ const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2894
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a3 = prevKf.t) != null ? _a3 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2895
+ if (isBoundary) {
2896
+ if (deepEqualValue(prevKf.v, entry.v)) {
2897
+ if (looped.length > 0) {
2898
+ prevKf.e = entry.e;
2899
+ prevKf.tangentOut = entry.tangentOut;
2900
+ } else {
2901
+ terminalEasingOverride = entry.e;
2902
+ hasTerminalEasingOverride = true;
2903
+ }
2904
+ continue;
2905
+ }
2906
+ if (looped.length > 0) {
2907
+ delete prevKf.tangentIn;
2908
+ delete prevKf.tangentOut;
2909
+ }
2910
+ }
2911
+ const pushed = {
2912
+ t: repStart + entry.relT * segDuration + (isBoundary ? PX_LOOP_JUMP_SHIFT_MS : 0),
2913
+ v: entry.v,
2914
+ e: i < entries.length - 1 ? entry.e : void 0
2915
+ };
2916
+ if (entry.tangentIn) pushed.tangentIn = entry.tangentIn;
2917
+ if (entry.tangentOut) pushed.tangentOut = entry.tangentOut;
2918
+ looped.push(pushed);
2919
+ }
2920
+ }
2921
+ function appendRepTail(repStart, isReversed, tailFraction) {
2922
+ let entries;
2923
+ if (isReversed) {
2924
+ entries = [];
2925
+ for (let i = template.length - 1; i >= 0; i--) {
2926
+ entries.push({
2927
+ relT: 1 - template[i].relT,
2928
+ v: template[i].v,
2929
+ e: i > 0 ? reverseEasing(template[i - 1].e) : void 0,
2930
+ tangentIn: template[i].tangentOut,
2931
+ tangentOut: template[i].tangentIn
2932
+ });
2933
+ }
2934
+ } else {
2935
+ entries = template;
2936
+ }
2937
+ const startRelT = 1 - tailFraction;
2938
+ for (let i = 0; i < entries.length; i++) {
2939
+ const entry = entries[i];
2940
+ if (entry.relT < startRelT - 1e-9) continue;
2941
+ const prev = entries[i - 1];
2942
+ if (prev && prev.relT < startRelT - 1e-9 && entry.relT > startRelT + 1e-9) {
2943
+ const intervalSpan = entry.relT - prev.relT;
2944
+ const localFrac = (startRelT - prev.relT) / intervalSpan;
2945
+ const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
2946
+ const startValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
2947
+ const { right: rightEasing } = splitEasing(prev.e, localFrac);
2948
+ looped.push({ t: repStart, v: startValue, e: rightEasing });
2949
+ }
2950
+ const pushed = {
2951
+ t: repStart + (entry.relT - startRelT) * segDuration,
2952
+ v: entry.v,
2953
+ e: i < entries.length - 1 ? entry.e : void 0
2954
+ };
2955
+ if (entry.tangentIn) pushed.tangentIn = entry.tangentIn;
2956
+ if (entry.tangentOut) pushed.tangentOut = entry.tangentOut;
2957
+ looped.push(pushed);
2958
+ }
2959
+ }
2960
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2961
+ if (partialFraction > 1e-9) {
2962
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2963
+ appendRepTail(fillStart, isReversed, partialFraction);
2964
+ }
2965
+ for (let rep = 0; rep < fullReps; rep++) {
2966
+ const distFromBoundary = fullReps - 1 - rep;
2967
+ const isReversed = loop.direction === PxLoopDirection.alternate && distFromBoundary % 2 === 0;
2968
+ const repStart = fillStart + remainder + rep * segDuration;
2969
+ appendRep(repStart, isReversed);
2970
+ }
2971
+ } else {
2972
+ for (let rep = 0; rep < fullReps; rep++) {
2973
+ const isReversed = loop.direction === PxLoopDirection.alternate && rep % 2 === 0;
2974
+ const repStart = fillStart + rep * segDuration;
2975
+ appendRep(repStart, isReversed);
2976
+ }
2977
+ if (partialFraction > 1e-9) {
2978
+ const isReversed = loop.direction === PxLoopDirection.alternate && fullReps % 2 === 0;
2979
+ const repStart = fillStart + fullReps * segDuration;
2980
+ appendRep(repStart, isReversed, partialFraction);
2981
+ }
2982
+ }
2983
+ if (loop.repeatAt === PxLoopRepeatAt.start) {
2984
+ return [...looped, ...keyframes];
2985
+ } else {
2986
+ if (hasTerminalEasingOverride && keyframes.length > 0) {
2987
+ const head = keyframes.slice(0, -1);
2988
+ const tail = __spreadProps(__spreadValues({}, keyframes[keyframes.length - 1]), { e: terminalEasingOverride });
2989
+ return [...head, tail, ...looped];
2990
+ }
2991
+ return [...keyframes, ...looped];
2992
+ }
2993
+ }
2994
+ function normalizeKeyframes(propName, propAnim, duration, defs) {
2995
+ var _a2;
2996
+ const keyframes = propAnim.keyframes || [];
2997
+ const normalized = [];
2998
+ for (const kf of keyframes) {
2999
+ const timePct = keyframeTime(kf);
3000
+ let value = keyframeValue(kf);
3001
+ const easing = keyframeEasing(kf);
3002
+ if (propName === "d") {
3003
+ value = normalizePathValue(value);
3004
+ }
3005
+ const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3006
+ if (PX_COLOR_ATTR_NAMES.has(propNameKebab)) {
3007
+ value = (_a2 = parseColor(value)) != null ? _a2 : value;
3008
+ }
3009
+ const normKf = {
3010
+ t: timePct,
3011
+ v: value,
3012
+ e: resolveEasing(easing, defs)
3013
+ };
3014
+ const tIn = keyframeTangentIn(kf);
3015
+ const tOut = keyframeTangentOut(kf);
3016
+ if (tIn) normKf.tangentIn = tIn;
3017
+ if (tOut) normKf.tangentOut = tOut;
3018
+ normalized.push(normKf);
3019
+ }
3020
+ normalized.sort((a, b) => {
3021
+ var _a3, _b;
3022
+ return ((_a3 = a.t) != null ? _a3 : 0) - ((_b = b.t) != null ? _b : 0);
3023
+ });
3024
+ const loopRaw = propAnim.loop;
3025
+ const loop = loopRaw === true ? {} : loopRaw || void 0;
3026
+ if (loop && normalized.length >= 2) {
3027
+ return expandLoopKeyframes(propName, normalized, loop, duration);
3028
+ }
3029
+ return normalized;
3030
+ }
3031
+ function mergeAnimationDefinitions(animations) {
3032
+ const merged = {};
3033
+ for (const anim of animations) {
3034
+ for (const [prop, propAnim] of Object.entries(anim)) {
3035
+ merged[prop] = propAnim;
3036
+ }
3037
+ }
3038
+ return merged;
3039
+ }
3040
+ function materializeInternalLoopsInPropAnim(propName, propAnim, duration) {
3041
+ const loopRaw = propAnim.loop;
3042
+ if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
3043
+ const loop = loopRaw === true ? {} : loopRaw;
3044
+ const rawKfs = propAnim.keyframes;
3045
+ if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
3046
+ const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3047
+ const isColor = PX_COLOR_ATTR_NAMES.has(propNameKebab);
3048
+ const kfs = rawKfs.map((kf) => {
3049
+ var _a2;
3050
+ const t = keyframeTime(kf);
3051
+ let v = keyframeValue(kf);
3052
+ if (propName === "d") v = normalizePathValue(v);
3053
+ if (isColor) v = (_a2 = parseColor(v)) != null ? _a2 : v;
3054
+ const e = keyframeEasing(kf);
3055
+ const out2 = { t, v, e };
3056
+ const tIn = keyframeTangentIn(kf);
3057
+ const tOut = keyframeTangentOut(kf);
3058
+ if (tIn) out2.tangentIn = tIn;
3059
+ if (tOut) out2.tangentOut = tOut;
3060
+ return out2;
3061
+ });
3062
+ const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
3063
+ const out = { keyframes: expanded };
3064
+ if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3065
+ return out;
3066
+ }
3067
+ function materializeInternalLoopsInTree(root, duration) {
3068
+ const ret = walkAndMaterializeLoops(root, duration);
3069
+ return ret != null ? ret : root;
3070
+ }
3071
+ function walkAndMaterializeLoops(node, duration) {
3072
+ let newChildren;
3073
+ if (node.children) {
3074
+ for (let i = 0; i < node.children.length; i++) {
3075
+ const ret = walkAndMaterializeLoops(node.children[i], duration);
3076
+ if (ret !== null) {
3077
+ if (!newChildren) newChildren = node.children.slice();
3078
+ newChildren[i] = ret;
3079
+ }
3080
+ }
3081
+ }
3082
+ let newAnimate;
3083
+ const animBucket = node.animate;
3084
+ if (animBucket && typeof animBucket === "object" && !Array.isArray(animBucket)) {
3085
+ const animDef = animBucket;
3086
+ for (const propName of Object.keys(animDef)) {
3087
+ const propAnim = animDef[propName];
3088
+ const materialized = materializeInternalLoopsInPropAnim(propName, propAnim, duration);
3089
+ if (materialized !== propAnim) {
3090
+ if (!newAnimate) newAnimate = __spreadValues({}, animDef);
3091
+ newAnimate[propName] = materialized;
3092
+ }
3093
+ }
3094
+ }
3095
+ if (!newChildren && !newAnimate) return null;
3096
+ const cloned = __spreadValues({}, node);
3097
+ if (newChildren) cloned.children = newChildren;
3098
+ if (newAnimate) cloned.animate = newAnimate;
3099
+ return cloned;
3100
+ }
3101
+ var _elementIdCounter = 0;
3102
+ function generateElementId() {
3103
+ return "_px_el_" + ++_elementIdCounter;
3104
+ }
3105
+ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
3106
+ if (!animDef) return animDef;
3107
+ const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
3108
+ if (!staticParts || !Object.keys(staticParts).length) return animDef;
3109
+ const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
3110
+ const transformAnim = animDef[TRANSFORM_ATTR];
3111
+ if (transformAnim && typeof transformAnim === "object") {
3112
+ const anim = transformAnim;
3113
+ if (Array.isArray(anim.keyframes)) {
3114
+ const out = __spreadProps(__spreadValues({}, anim), {
3115
+ keyframes: anim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: mergeKfValue(kf.value) }))
3116
+ });
3117
+ if (out.value !== void 0) out.value = mergeKfValue(out.value);
3118
+ return __spreadProps(__spreadValues({}, animDef), { transform: out });
3119
+ }
3120
+ return animDef;
3121
+ }
3122
+ const channels = Object.keys(animDef).filter((k) => PX_TRANSFORM_FN_NAMES.has(k));
3123
+ if (channels.length !== 1) return animDef;
3124
+ const ch = channels[0];
3125
+ const chAnim = animDef[ch];
3126
+ if (!chAnim || typeof chAnim !== "object" || !Array.isArray(chAnim.keyframes)) return animDef;
3127
+ const lifted = __spreadProps(__spreadValues({}, chAnim), {
3128
+ keyframes: chAnim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: __spreadProps(__spreadValues({}, staticParts), { [ch]: kf.value }) }))
3129
+ });
3130
+ if (lifted.value !== void 0) lifted.value = __spreadProps(__spreadValues({}, staticParts), { [ch]: lifted.value });
3131
+ const rest = __spreadValues({}, animDef);
3132
+ delete rest[ch];
3133
+ return __spreadProps(__spreadValues({}, rest), { transform: lifted });
3134
+ }
3135
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimelineEngine.native) {
3136
+ const normalized = {};
3137
+ for (const [propName, propAnim] of Object.entries(animDef)) {
3138
+ if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
3139
+ continue;
3140
+ }
3141
+ const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
3142
+ if (normalizedKfs.length > 0) {
3143
+ const out = { keyframes: normalizedKfs };
3144
+ if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
3145
+ if (propAnim.loop !== void 0) out.loop = propAnim.loop;
3146
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materializeMotionPathInPropAnim(out) : out;
3147
+ }
3148
+ }
3149
+ return normalized;
3150
+ }
3151
+ function normalizeBindings(doc, engine = PxTimelineEngine.native) {
3152
+ const animatorConfig = getAnimatorConfig(doc) || {};
3153
+ const defs = getDefinitions(doc);
3154
+ const duration = animatorConfig.duration || 1e3;
3155
+ const bindings = [];
3156
+ const processAnimation = (id, animDefs, staticTransform) => {
3157
+ if (animDefs.length === 0) return null;
3158
+ const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);
3159
+ const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
3160
+ if (Object.keys(normalizedAnim).length === 0) return null;
3161
+ return {
3162
+ id,
3163
+ animate: normalizedAnim
3164
+ };
3165
+ };
3166
+ const docBindings = getBindings(doc);
3167
+ if (docBindings) {
3168
+ for (const binding of docBindings) {
3169
+ const id = binding.target.startsWith("#") ? binding.target.slice(1) : binding.target;
3170
+ const animDefs = binding.animateWith.map((name) => resolveAnimation(name, defs)).filter((d) => !!d);
3171
+ const normalized = processAnimation(id, animDefs);
3172
+ if (normalized) bindings.push(normalized);
3173
+ }
3174
+ }
3175
+ const processNode = (node) => {
3176
+ const inlineAnim = node.animate;
3177
+ if (inlineAnim && Object.keys(inlineAnim).length > 0) {
3178
+ const nodeId = node.id || generateElementId();
3179
+ node.id = nodeId;
3180
+ const normalized = processAnimation(nodeId, resolveElementAnimation(inlineAnim, defs), node.transform);
3181
+ if (normalized) bindings.push(normalized);
3182
+ }
3183
+ if (node.children) {
3184
+ for (let i = 0; i < node.children.length; i++) {
3185
+ processNode(node.children[i]);
3186
+ }
3187
+ }
3188
+ };
3189
+ if (doc.children) {
3190
+ for (let i = 0; i < doc.children.length; i++) {
3191
+ processNode(doc.children[i]);
3192
+ }
3193
+ }
3194
+ return bindings;
3195
+ }
3196
+ function getKeyframesPair(keyframes, progress) {
3197
+ var _a2, _b;
3198
+ const last = keyframes.length - 1;
3199
+ let prevKf = keyframes[0];
3200
+ let nextKf = keyframes[last > 0 ? 1 : 0];
3201
+ for (let j = 0; j < last; j++) {
3202
+ const aOff = (_a2 = keyframes[j].t) != null ? _a2 : 0;
3203
+ const bOff = (_b = keyframes[j + 1].t) != null ? _b : 0;
3204
+ if (aOff <= progress && progress <= bOff) {
3205
+ prevKf = keyframes[j];
3206
+ nextKf = keyframes[j + 1];
3207
+ break;
3208
+ }
3209
+ if (progress > bOff && j === last - 1) {
3210
+ prevKf = keyframes[last > 0 ? last - 1 : 0];
3211
+ nextKf = keyframes[last];
3212
+ }
3213
+ }
3214
+ return { prevKf, nextKf };
3215
+ }
3216
+ function calcPropertyValue(propName, propAnim, progress) {
3217
+ var _a2, _b, _c, _d;
3218
+ const keyframes = propAnim.keyframes || [];
3219
+ if (keyframes.length === 0) return null;
3220
+ const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
3221
+ let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a2 = prevKf.t) != null ? _a2 : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
3222
+ localProgress = clamp(localProgress, 0, 1);
3223
+ const easing = keyframeEasing(prevKf);
3224
+ if (easing && Array.isArray(easing)) {
3225
+ try {
3226
+ localProgress = cubicBezier(easing)(localProgress);
3227
+ } catch (e) {
3228
+ }
3229
+ }
3230
+ let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
3231
+ let cssValue = null;
3232
+ const prevV = prevKf == null ? void 0 : prevKf.v;
3233
+ const nextV = nextKf == null ? void 0 : nextKf.v;
3234
+ if (cssAttrName === "d") {
3235
+ const prevPaths = (_c = prevV == null ? void 0 : prevV.paths) != null ? _c : Array.isArray(prevV) ? prevV : [];
3236
+ const nextPaths = (_d = nextV == null ? void 0 : nextV.paths) != null ? _d : Array.isArray(nextV) ? nextV : [];
3237
+ cssValue = interpolateBeziers(
3238
+ prevPaths,
3239
+ nextPaths,
3240
+ localProgress
3241
+ ).map((bz) => bezierToSvgPath(bz)).join("");
3242
+ } else if (PX_COLOR_ATTR_NAMES.has(cssAttrName)) {
3243
+ cssValue = toRGBA(interpolateColor(
3244
+ prevV || [0, 0, 0, 1],
3245
+ nextV || [0, 0, 0, 1],
3246
+ localProgress
3247
+ ));
3248
+ cssAttrName = propName;
3249
+ } else if (cssAttrName === "stroke-dasharray") {
3250
+ cssValue = interpolateVec(
3251
+ prevV || [],
3252
+ nextV || [],
3253
+ localProgress
3254
+ ).join(" ");
3255
+ cssAttrName = propName;
3256
+ } else if (cssAttrName === "transform" && prevV !== null && typeof prevV === "object" && !Array.isArray(prevV)) {
3257
+ const partKeys = /* @__PURE__ */ new Set([
3258
+ ...prevV ? Object.keys(prevV) : [],
3259
+ ...nextV ? Object.keys(nextV) : []
3260
+ ]);
3261
+ const partsResult = {};
3262
+ for (const partKey of partKeys) {
3263
+ const prevPart = prevV == null ? void 0 : prevV[partKey];
3264
+ const nextPart = nextV == null ? void 0 : nextV[partKey];
3265
+ if (partKey === "rotate" || partKey === "skew") {
3266
+ partsResult[partKey] = interpolateNum(+(prevPart != null ? prevPart : 0), +(nextPart != null ? nextPart : 0), localProgress);
3267
+ } else if (partKey === "translate" || partKey === "scale" || partKey === "origin") {
3268
+ const fallback = partKey === "scale" ? [1, 1] : [0, 0];
3269
+ const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);
3270
+ partsResult[partKey] = interp;
3271
+ }
3272
+ }
3273
+ if (propAnimIsMotionPath(propAnim)) {
3274
+ const prevTr = prevV.translate;
3275
+ const nextTr = nextV.translate;
3276
+ if (Array.isArray(prevTr) && Array.isArray(nextTr)) {
3277
+ const sample = evaluateMotionPathSegment(
3278
+ prevKf,
3279
+ nextKf,
3280
+ [+prevTr[0], +prevTr[1]],
3281
+ [+nextTr[0], +nextTr[1]],
3282
+ localProgress,
3283
+ !!propAnim.autoOrient
3284
+ );
3285
+ partsResult.translate = [sample.translate[0], sample.translate[1]];
3286
+ if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
3287
+ }
3288
+ }
3289
+ cssValue = composeTransformParts(partsResult, { withUnits: false });
3290
+ cssAttrName = "transform";
3291
+ } else if (cssAttrName === "translate") {
3292
+ const v = interpolateVec(
3293
+ prevV || [0, 0],
3294
+ nextV || [0, 0],
3295
+ localProgress
3296
+ );
3297
+ cssValue = "translate(" + v.join(",") + ")";
3298
+ cssAttrName = "transform";
3299
+ } else if (cssAttrName === "rotate") {
3300
+ const v = interpolateNum(
3301
+ +(prevV || 0),
3302
+ +(nextV || 0),
3303
+ localProgress
3304
+ );
3305
+ cssValue = "rotate(" + v + ")";
3306
+ cssAttrName = "transform";
3307
+ } else if (cssAttrName === "scale") {
3308
+ const v = interpolateVec(
3309
+ prevV || [1, 1],
3310
+ nextV || [1, 1],
3311
+ localProgress
3312
+ );
3313
+ cssValue = "scale(" + v.join(",") + ")";
3314
+ cssAttrName = "transform";
3315
+ } else {
3316
+ const num = interpolateNum(
3317
+ +(prevV || 0),
3318
+ +(nextV || 0),
3319
+ localProgress
3320
+ );
3321
+ cssValue = num;
3322
+ }
3323
+ if (PX_PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === "number") {
3324
+ cssValue = cssValue * 100 + "%";
3325
+ }
3326
+ return { k: cssAttrName, v: cssValue === null ? "" : "" + cssValue };
3327
+ }
3328
+ function calcAnimationValues(animDef, progress) {
3329
+ const result = {};
3330
+ for (const [propName, propAnim] of Object.entries(animDef)) {
3331
+ const computed = calcPropertyValue(propName, propAnim, progress);
3332
+ if (computed) {
3333
+ result[computed.k] = computed.v;
3334
+ }
3335
+ }
3336
+ return result;
3337
+ }
3338
+
3339
+ // src/effects/text/pathSampler.ts
3340
+ var LUT_STEPS = 48;
3341
+ var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
3342
+ function tokenize(d) {
3343
+ const tokens = [];
3344
+ const re = /([MmLlHhVvCcSsQqTtAaZz])|(-?\d*\.?\d+(?:[eE][-+]?\d+)?)/g;
3345
+ let m;
3346
+ while ((m = re.exec(d)) !== null) tokens.push(m[0]);
3347
+ return tokens;
3348
+ }
3349
+ function quadToCubic(P0, Qc, P3) {
3350
+ return {
3351
+ P1: [P0[0] + 2 / 3 * (Qc[0] - P0[0]), P0[1] + 2 / 3 * (Qc[1] - P0[1])],
3352
+ P2: [P3[0] + 2 / 3 * (Qc[0] - P3[0]), P3[1] + 2 / 3 * (Qc[1] - P3[1])]
3353
+ };
3354
+ }
3355
+ function parseCubics(d) {
3356
+ const tokens = tokenize(d);
3357
+ const segs = [];
3358
+ let i = 0;
3359
+ let cx = 0, cy = 0;
3360
+ let sx = 0, sy = 0;
3361
+ let pcx = 0, pcy = 0;
3362
+ let pqx = 0, pqy = 0;
3363
+ let prevCmd = "";
3364
+ const num = () => parseFloat(tokens[i++]);
3365
+ const push = (P1, P2, P3) => {
3366
+ const P0 = [cx, cy];
3367
+ const lut = bezier2D_arcLengthLUT(P0, P1, P2, P3, LUT_STEPS);
3368
+ segs.push({ P0, P1, P2, P3, lut, len: lut.ds[lut.ds.length - 1] });
3369
+ cx = P3[0];
3370
+ cy = P3[1];
3371
+ };
3372
+ const pushLine = (x, y) => {
3373
+ push(
3374
+ [cx + (x - cx) / 3, cy + (y - cy) / 3],
3375
+ [cx + 2 * (x - cx) / 3, cy + 2 * (y - cy) / 3],
3376
+ [x, y]
3377
+ );
3378
+ };
3379
+ while (i < tokens.length) {
3380
+ let cmd = tokens[i];
3381
+ if (CMD_RE.test(cmd)) i++;
3382
+ else cmd = prevCmd === "M" ? "L" : prevCmd === "m" ? "l" : prevCmd;
3383
+ const rel = cmd >= "a";
3384
+ const U = cmd.toUpperCase();
3385
+ if (U === "Z") {
3386
+ pushLine(sx, sy);
3387
+ cx = sx;
3388
+ cy = sy;
3389
+ prevCmd = cmd;
3390
+ continue;
3391
+ }
3392
+ if (U === "M") {
3393
+ const x = num() + (rel ? cx : 0), y = num() + (rel ? cy : 0);
3394
+ cx = x;
3395
+ cy = y;
3396
+ sx = x;
3397
+ sy = y;
3398
+ prevCmd = cmd;
3399
+ continue;
3400
+ }
3401
+ if (U === "L") {
3402
+ pushLine(num() + (rel ? cx : 0), num() + (rel ? cy : 0));
3403
+ } else if (U === "H") {
3404
+ pushLine(num() + (rel ? cx : 0), cy);
3405
+ } else if (U === "V") {
3406
+ pushLine(cx, num() + (rel ? cy : 0));
3407
+ } else if (U === "C") {
3408
+ const p1 = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3409
+ const p2 = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3410
+ const p3 = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3411
+ pcx = p2[0];
3412
+ pcy = p2[1];
3413
+ push(p1, p2, p3);
3414
+ } else if (U === "S") {
3415
+ const smooth = prevCmd.toUpperCase() === "C" || prevCmd.toUpperCase() === "S";
3416
+ const p1 = smooth ? [2 * cx - pcx, 2 * cy - pcy] : [cx, cy];
3417
+ const p2 = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3418
+ const p3 = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3419
+ pcx = p2[0];
3420
+ pcy = p2[1];
3421
+ push(p1, p2, p3);
3422
+ } else if (U === "Q") {
3423
+ const qc = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3424
+ const p3 = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3425
+ pqx = qc[0];
3426
+ pqy = qc[1];
3427
+ const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
3428
+ push(P1, P2, p3);
3429
+ } else if (U === "T") {
3430
+ const smooth = prevCmd.toUpperCase() === "Q" || prevCmd.toUpperCase() === "T";
3431
+ const qc = smooth ? [2 * cx - pqx, 2 * cy - pqy] : [cx, cy];
3432
+ const p3 = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];
3433
+ pqx = qc[0];
3434
+ pqy = qc[1];
3435
+ const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
3436
+ push(P1, P2, p3);
3437
+ } else if (U === "A") {
3438
+ i += 5;
3439
+ pushLine(num() + (rel ? cx : 0), num() + (rel ? cy : 0));
3440
+ } else {
3441
+ i++;
3442
+ continue;
3443
+ }
3444
+ prevCmd = cmd;
3445
+ }
3446
+ return segs.length ? segs : null;
3447
+ }
3448
+ function clamp2(v, lo, hi) {
3449
+ return v < lo ? lo : v > hi ? hi : v;
3450
+ }
3451
+ function createPathSampler(d) {
3452
+ const segs = parseCubics(d);
3453
+ if (!segs) return null;
3454
+ const cum = new Float64Array(segs.length + 1);
3455
+ for (let k = 0; k < segs.length; k++) cum[k + 1] = cum[k] + segs[k].len;
3456
+ const totalLength = cum[segs.length];
3457
+ const start = segs[0].P0, end = segs[segs.length - 1].P3;
3458
+ const closed = Math.hypot(end[0] - start[0], end[1] - start[1]) < 1e-3;
3459
+ const sampleOn = (dist) => {
3460
+ let k = 0;
3461
+ while (k < segs.length - 1 && dist > cum[k + 1]) k++;
3462
+ const seg = segs[k];
3463
+ const local = dist - cum[k];
3464
+ const t = seg.len > 0 ? bezier2D_tForDistance(seg.lut, local) : 0;
3465
+ const [x, y] = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
3466
+ const [dx, dy] = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
3467
+ return { x, y, angle: Math.atan2(dy, dx) };
3468
+ };
3469
+ return {
3470
+ totalLength,
3471
+ closed,
3472
+ sampleAtDistance(dist) {
3473
+ if (closed && totalLength > 0 && (dist < 0 || dist > totalLength)) {
3474
+ return sampleOn((dist % totalLength + totalLength) % totalLength);
3475
+ }
3476
+ if (!closed && (dist < 0 || dist > totalLength)) {
3477
+ const edge = dist < 0 ? 0 : totalLength;
3478
+ const p = sampleOn(edge);
3479
+ const over = dist - edge;
3480
+ return { x: p.x + Math.cos(p.angle) * over, y: p.y + Math.sin(p.angle) * over, angle: p.angle };
3481
+ }
3482
+ return sampleOn(clamp2(dist, 0, totalLength));
3483
+ }
3484
+ };
3485
+ }
3486
+
3487
+ // src/effects/shared/transformParts.ts
3488
+ function partsRecord(part, value, origin) {
3489
+ const rec = {};
3490
+ if (part === "translate" /* Translate */) rec.translate = value;
3491
+ else if (part === "rotate" /* Rotate */) rec.rotate = value;
3492
+ else if (part === "skew" /* Skew */) rec.skew = value;
3493
+ else rec.scale = value;
3494
+ if (origin && part !== "translate" /* Translate */) rec.origin = origin;
3495
+ return rec;
3496
+ }
3497
+ function readAnimatable(raw) {
3498
+ var _a2, _b;
3499
+ if (raw === void 0) return { kind: "absent" /* Absent */ };
3500
+ if (Array.isArray(raw)) return { kind: "static" /* Static */, value: raw };
3501
+ if (typeof raw === "object") {
3502
+ const obj = raw;
3503
+ const kfs = obj.keyframes;
3504
+ if (kfs) {
3505
+ const out = { kind: "animated" /* Animated */, keyframes: kfs.map(normalizeKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
3506
+ const base = (_a2 = obj.value) != null ? _a2 : obj.v;
3507
+ if (base !== void 0 && out.kind === "animated" /* Animated */) out.base = base;
3508
+ return out;
3509
+ }
3510
+ const staticValue = (_b = obj.value) != null ? _b : obj.v;
3511
+ if (staticValue !== void 0) return { kind: "static" /* Static */, value: staticValue };
3512
+ }
3513
+ return { kind: "static" /* Static */, value: raw };
3514
+ }
3515
+ function writeAnimatableChannel(node, attrName, read, opts) {
3516
+ var _a2, _b, _c, _d;
3517
+ const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
3518
+ if (read.kind === "absent" /* Absent */) return;
3519
+ if (read.kind === "static" /* Static */) {
3520
+ node[attrName] = toOut(read.value);
3521
+ return;
3522
+ }
3523
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
3524
+ const animate = __spreadValues({}, prevAnimate || {});
3525
+ const block = { keyframes: read.keyframes };
3526
+ if (read.loop !== void 0) block.loop = read.loop;
3527
+ if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
3528
+ animate[attrName] = block;
3529
+ node.animate = animate;
3530
+ const baseline = (_d = (_b = read.base) != null ? _b : (_a2 = read.keyframes[0]) == null ? void 0 : _a2.value) != null ? _d : (_c = read.keyframes[0]) == null ? void 0 : _c.v;
3531
+ if (baseline !== void 0) node[attrName] = toOut(baseline);
3532
+ }
3533
+ function normalizeKeyframe(kf) {
3534
+ if (!kf || typeof kf !== "object") return kf;
3535
+ const k = kf;
3536
+ if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
3537
+ return kf;
3538
+ }
3539
+ const out = __spreadValues({}, k);
3540
+ if (out.time === void 0 && k.t !== void 0) out.time = k.t;
3541
+ if (out.value === void 0 && k.v !== void 0) out.value = k.v;
3542
+ if (out.easing === void 0 && k.e !== void 0) out.easing = k.e;
3543
+ if (out.tangentOut === void 0 && k.to !== void 0) out.tangentOut = k.to;
3544
+ if (out.tangentIn === void 0 && k.ti !== void 0) out.tangentIn = k.ti;
3545
+ return out;
3546
+ }
3547
+ function readStaticOrigin(raw, ctx) {
3548
+ var _a2;
3549
+ const o = readAnimatable(raw);
3550
+ if (o.kind === "absent" /* Absent */) return void 0;
3551
+ if (o.kind === "static" /* Static */) return o.value;
3552
+ ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
3553
+ return (_a2 = o.keyframes[0]) == null ? void 0 : _a2.value;
3554
+ }
3555
+ function keyframeWith(kf, value) {
3556
+ const out = { value };
3557
+ if (kf.time !== void 0) out.time = kf.time;
3558
+ if (kf.easing !== void 0) out.easing = kf.easing;
3559
+ if (kf.tangentOut !== void 0) out.tangentOut = kf.tangentOut;
3560
+ if (kf.tangentIn !== void 0) out.tangentIn = kf.tangentIn;
3561
+ return out;
3562
+ }
3563
+
3564
+ // src/util/PxNodeCloneUtil.ts
3565
+ function deepClonePxNode(value) {
3566
+ if (value === null || typeof value !== "object") return value;
3567
+ if (Array.isArray(value)) return value.map(deepClonePxNode);
3568
+ const out = {};
3569
+ for (const k of Object.keys(value)) out[k] = deepClonePxNode(value[k]);
3570
+ return out;
3571
+ }
3572
+ function regenerateIdsAndRewriteRefs(root, genId2) {
3573
+ const oldToNew = /* @__PURE__ */ new Map();
3574
+ const walkAssign = (n) => {
3575
+ var _a2;
3576
+ if (typeof n.id === "string") {
3577
+ const newId = genId2();
3578
+ oldToNew.set(n.id, newId);
3579
+ n.id = newId;
3580
+ }
3581
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkAssign);
3582
+ };
3583
+ walkAssign(root);
3584
+ const rewriteUrl = (s) => s.replace(/url\(#([^)]+)\)/g, (m, oldId) => {
3585
+ const newId = oldToNew.get(oldId);
3586
+ return newId ? "url(#" + newId + ")" : m;
3587
+ });
3588
+ const walkRewrite = (n) => {
3589
+ var _a2;
3590
+ if (typeof n.href === "string" && n.href.startsWith("#")) {
3591
+ const newId = oldToNew.get(n.href.slice(1));
3592
+ if (newId) n.href = "#" + newId;
3593
+ }
3594
+ for (const k of Object.keys(n)) {
3595
+ if (k === "children" || k === "effects" || k === "meta" || k === "animate" || k === "href" || k === "id") continue;
3596
+ const v = n[k];
3597
+ if (typeof v === "string" && v.indexOf("url(#") !== -1) {
3598
+ n[k] = rewriteUrl(v);
3599
+ }
3600
+ }
3601
+ (_a2 = n.children) == null ? void 0 : _a2.forEach(walkRewrite);
3602
+ };
3603
+ walkRewrite(root);
3604
+ return oldToNew;
3605
+ }
3606
+ function toFiniteNum(v) {
3607
+ const n = typeof v === "number" ? v : typeof v === "string" ? parseFloat(v) : NaN;
3608
+ return Number.isFinite(n) ? n : 0;
3609
+ }
3610
+ function applyUseOffsetToG(gNode) {
3611
+ var _a2;
3612
+ const x = toFiniteNum(gNode.x);
3613
+ const y = toFiniteNum(gNode.y);
3614
+ delete gNode.x;
3615
+ delete gNode.y;
3616
+ if (!x && !y) return gNode;
3617
+ const offset = "translate(" + x + "," + y + ")";
3618
+ const carriesTransform = gNode.transform !== void 0 || gNode.animate !== void 0;
3619
+ if (carriesTransform) {
3620
+ const inner = { type: "g", transform: offset, children: (_a2 = gNode.children) != null ? _a2 : [] };
3621
+ gNode.children = [inner];
3622
+ } else {
3623
+ gNode.transform = offset;
3624
+ }
3625
+ return gNode;
3626
+ }
3627
+
3628
+ // src/effects/shared/util.ts
3629
+ function genId(ctx, prefix) {
3630
+ return "_lw_" + prefix + "_" + ctx.nextId++;
3631
+ }
3632
+ function stripHash(href) {
3633
+ return typeof href === "string" ? href.replace(/^#/, "") : void 0;
3634
+ }
3635
+ function indexById(node, map) {
3636
+ var _a2;
3637
+ if (typeof node.id === "string") map.set(node.id, node);
3638
+ (_a2 = node.children) == null ? void 0 : _a2.forEach((child) => indexById(child, map));
3639
+ }
3640
+ function spliceDefs(root, defs) {
3641
+ if (!defs.length) return;
3642
+ const existing = root.children || (root.children = []);
3643
+ existing.unshift({ type: "defs", children: defs });
3644
+ }
3645
+ var clone = deepClonePxNode;
3646
+ function regenerateIdsInClone(root, ctx) {
3647
+ return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
3648
+ }
3649
+
3650
+ // src/effects/text/textPathEffect.ts
3651
+ var EXTEND_MARGIN_FRAC = 0.15;
3652
+ function numRange(v) {
3653
+ const read = readAnimatable(v);
3654
+ if (read.kind === "static" /* Static */ && typeof read.value === "number") return { min: read.value, max: read.value };
3655
+ if (read.kind === "animated" /* Animated */ && read.keyframes.length) {
3656
+ const vals = read.keyframes.map((k) => Number(k.value) || 0);
3657
+ return { min: Math.min(...vals), max: Math.max(...vals) };
3658
+ }
3659
+ return { min: 0, max: 0 };
3660
+ }
3661
+ function estimateTextAdvance(node) {
3662
+ let chars = 0, maxFont = 16;
3663
+ const walk = (el) => {
3664
+ var _a2;
3665
+ const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
3666
+ if (fs) maxFont = Math.max(maxFont, fs);
3667
+ const t = el.textContent;
3668
+ if (typeof t === "string") chars += t.length;
3669
+ if (el.children) for (const c of el.children) walk(c);
3670
+ };
3671
+ walk(node);
3672
+ return chars * maxFont;
3673
+ }
3674
+ var r3 = (n) => Math.round(n * 1e3) / 1e3;
3675
+ function shiftAnimatable(v, by) {
3676
+ if (!by || v === void 0 || v === null) return v;
3677
+ const read = readAnimatable(v);
3678
+ if (read.kind === "absent" /* Absent */) return v;
3679
+ if (read.kind === "static" /* Static */) return typeof v === "number" ? read.value + by : { value: read.value + by };
3680
+ const out = {
3681
+ keyframes: read.keyframes.map((k) => __spreadProps(__spreadValues({}, k), { value: (Number(k.value) || 0) + by }))
3682
+ };
3683
+ if (read.loop !== void 0) out.loop = read.loop;
3684
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
3685
+ if (read.base !== void 0) out.value = read.base + by;
3686
+ return out;
3687
+ }
3688
+ function extendedPathForBrowser(pathD, opts) {
3689
+ var _a2;
3690
+ if (opts.pathOverflow === "clip") return { d: pathD, startShift: 0 };
3691
+ const sampler = createPathSampler(pathD);
3692
+ if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };
3693
+ const L = sampler.totalLength;
3694
+ const margin = EXTEND_MARGIN_FRAC * L;
3695
+ const so = numRange(opts.startOffset);
3696
+ const runWidth = numRange(opts.textLength).max || ((_a2 = opts.advance) != null ? _a2 : 0);
3697
+ const startOverflow = Math.max(0, -so.min);
3698
+ const endOverflow = Math.max(0, so.max + runWidth - L);
3699
+ const startExt = startOverflow > 0 ? startOverflow + margin : 0;
3700
+ const endExt = endOverflow > 0 ? endOverflow + margin : 0;
3701
+ if (endExt <= 0 && startExt <= 0) return { d: pathD, startShift: 0 };
3702
+ const s = sampler.sampleAtDistance(0);
3703
+ const e = sampler.sampleAtDistance(L);
3704
+ let d = pathD;
3705
+ if (startExt > 0) {
3706
+ const sx = s.x - Math.cos(s.angle) * startExt, sy = s.y - Math.sin(s.angle) * startExt;
3707
+ const rest = pathD.replace(/^\s*[Mm]\s*-?[\d.]+[\s,]+-?[\d.]+/, "");
3708
+ d = "M" + r3(sx) + "," + r3(sy) + "L" + r3(s.x) + "," + r3(s.y) + rest;
3709
+ }
3710
+ if (endExt > 0) {
3711
+ const ex = e.x + Math.cos(e.angle) * endExt, ey = e.y + Math.sin(e.angle) * endExt;
3712
+ d += "L" + r3(ex) + "," + r3(ey);
3713
+ }
3714
+ return { d, startShift: startExt };
3715
+ }
3716
+ function applyTextPathEffect(node, fx, ctx) {
3717
+ var _a2;
3718
+ if (!fx || typeof fx.pathData !== "string" || !fx.pathData) return node;
3719
+ const pathId = genId(ctx, "tpath");
3720
+ const { d, startShift } = extendedPathForBrowser(fx.pathData, {
3721
+ pathOverflow: fx.pathOverflow,
3722
+ startOffset: fx.startOffset,
3723
+ textLength: fx.textLength,
3724
+ advance: estimateTextAdvance(node)
3725
+ });
3726
+ ctx.defs.push({ type: "path", id: pathId, d });
3727
+ const textPath = {
3728
+ type: "textPath",
3729
+ href: "#" + pathId,
3730
+ children: (_a2 = node.children) != null ? _a2 : []
3731
+ };
3732
+ if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
3733
+ if (fx.method !== void 0) textPath.method = fx.method;
3734
+ if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
3735
+ applyAnimatableNumber(textPath, "startOffset", shiftAnimatable(fx.startOffset, startShift));
3736
+ applyAnimatableNumber(textPath, "textLength", fx.textLength);
3737
+ node.children = [textPath];
3738
+ return node;
3739
+ }
3740
+ function applyAnimatableNumber(node, attrName, raw) {
3741
+ if (raw === void 0 || raw === null) return;
3742
+ writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
3743
+ }
3744
+
3745
+ // src/effects/text/elementFactory.ts
3746
+ var jsonElementFactory = (type, props, children) => {
3747
+ const node = { type };
3748
+ for (const k in props) if (props[k] !== void 0) node[k] = props[k];
3749
+ const arr = Array.isArray(children) ? children.filter((c) => c != null) : children != null ? [children] : [];
3750
+ if (arr.length) node.children = arr;
3751
+ return node;
3752
+ };
3753
+
3754
+ // src/effects/text/glyphPathBake.ts
3755
+ function fmt(v, decimals) {
3756
+ return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
3757
+ }
3758
+ function pack(nums, decimals) {
3759
+ let s = "";
3760
+ for (let i = 0; i < nums.length; i++) {
3761
+ const str2 = fmt(nums[i], decimals);
3762
+ if (i > 0 && str2.charCodeAt(0) !== 45) s += " ";
3763
+ s += str2;
3764
+ }
3765
+ return s;
3766
+ }
3767
+ function apply(m, x, y) {
3768
+ return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
3769
+ }
3770
+ var TOKEN_RE = /([MLCQZ])|(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi;
3771
+ function transformPathData(d, m, decimals = 2) {
3772
+ const tokens = [];
3773
+ let match;
3774
+ TOKEN_RE.lastIndex = 0;
3775
+ while ((match = TOKEN_RE.exec(d)) !== null) tokens.push(match[0]);
3776
+ let out = "";
3777
+ let i = 0;
3778
+ const num = () => parseFloat(tokens[i++]);
3779
+ while (i < tokens.length) {
3780
+ const cmd = tokens[i++];
3781
+ if (cmd === "M" || cmd === "L") {
3782
+ const [x, y] = apply(m, num(), num());
3783
+ out += cmd + pack([x, y], decimals);
3784
+ } else if (cmd === "C") {
3785
+ const [x1, y1] = apply(m, num(), num());
3786
+ const [x2, y2] = apply(m, num(), num());
3787
+ const [x, y] = apply(m, num(), num());
3788
+ out += "C" + pack([x1, y1, x2, y2, x, y], decimals);
3789
+ } else if (cmd === "Q") {
3790
+ const [x1, y1] = apply(m, num(), num());
3791
+ const [x, y] = apply(m, num(), num());
3792
+ out += "Q" + pack([x1, y1, x, y], decimals);
3793
+ } else if (cmd === "Z" || cmd === "z") {
3794
+ out += "Z";
3795
+ }
3796
+ }
3797
+ return out;
3798
+ }
3799
+
3800
+ // src/effects/text/textGlyphsEffect.ts
3801
+ var DEFAULT_FONT_SIZE = 16;
3802
+ var TEXT_ATTR_KEYS = [
3803
+ "fontFamily",
3804
+ "fontSize",
3805
+ "fontWeight",
3806
+ "fontStyle",
3807
+ "textAnchor",
3808
+ "letterSpacing",
3809
+ "wordSpacing",
3810
+ "textDecoration",
3811
+ "textTransform",
3812
+ "whiteSpace",
3813
+ "x",
3814
+ "y",
3815
+ "dx",
3816
+ "dy",
3817
+ "lengthAdjust",
3818
+ "fill",
3819
+ "stroke",
3820
+ "strokeWidth",
3821
+ "effects",
3822
+ PX_TEXT_CONTENT_ATTR,
3823
+ "xml:space"
3824
+ ];
3825
+ var PAINT_STATIC_KEYS = [
3826
+ "fillOpacity",
3827
+ "fillRule",
3828
+ "strokeOpacity",
3829
+ "strokeDasharray",
3830
+ "strokeDashoffset",
3831
+ "strokeLinecap",
3832
+ "strokeLinejoin",
3833
+ "strokeMiterlimit",
3834
+ "mixBlendMode",
3835
+ "filter"
3836
+ ];
3837
+ var PAINT_ANIMATE_KEYS = ["fill", "stroke", "strokeWidth", "opacity", "fillOpacity", "strokeOpacity", "strokeDasharray", "strokeDashoffset"];
3838
+ function parseLen(v) {
3839
+ if (typeof v === "number") return v;
3840
+ if (typeof v === "string") {
3841
+ const n = parseFloat(v);
3842
+ return isNaN(n) ? void 0 : n;
3843
+ }
3844
+ return void 0;
3845
+ }
3846
+ function str(v) {
3847
+ return typeof v === "string" ? v : void 0;
3848
+ }
3849
+ function paintAnimateOf(node) {
3850
+ const bag = node.animate;
3851
+ if (!bag || typeof bag !== "object") return void 0;
3852
+ let out;
3853
+ for (const k of PAINT_ANIMATE_KEYS) {
3854
+ if (bag[k] !== void 0) (out != null ? out : out = {})[k] = bag[k];
3855
+ }
3856
+ return out;
3857
+ }
3858
+ function resolveStyle(node, parent) {
3859
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3860
+ const isTextRoot = node.type === "text";
3861
+ const nodeStyle = node.style;
3862
+ const own = (key) => {
3863
+ var _a3;
3864
+ return isTextRoot ? void 0 : (_a3 = node[key]) != null ? _a3 : nodeStyle == null ? void 0 : nodeStyle[key];
3865
+ };
3866
+ const res = {
3867
+ fontFamily: (_a2 = str(node.fontFamily)) != null ? _a2 : parent.fontFamily,
3868
+ fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
3869
+ fill: (_c = node.fill) != null ? _c : parent.fill,
3870
+ stroke: (_d = node.stroke) != null ? _d : parent.stroke,
3871
+ strokeWidth: (_e = node.strokeWidth) != null ? _e : parent.strokeWidth,
3872
+ letterSpacing: (_f = parseLen(node.letterSpacing)) != null ? _f : parent.letterSpacing,
3873
+ wordSpacing: (_g = parseLen(node.wordSpacing)) != null ? _g : parent.wordSpacing,
3874
+ opacity: (_h = parseLen(own("opacity"))) != null ? _h : parent.opacity,
3875
+ animate: (_i = isTextRoot ? void 0 : paintAnimateOf(node)) != null ? _i : parent.animate
3876
+ };
3877
+ for (const key of PAINT_STATIC_KEYS) {
3878
+ const v = (_j = own(key)) != null ? _j : parent[key];
3879
+ if (v !== void 0) res[key] = v;
3880
+ }
3881
+ return res;
3882
+ }
3883
+ function rootStyleOf(node) {
3884
+ var _a2, _b, _c;
3885
+ return {
3886
+ fontFamily: str(node.fontFamily),
3887
+ fontSize: (_a2 = parseLen(node.fontSize)) != null ? _a2 : DEFAULT_FONT_SIZE,
3888
+ fill: node.fill,
3889
+ stroke: node.stroke,
3890
+ strokeWidth: node.strokeWidth,
3891
+ letterSpacing: (_b = parseLen(node.letterSpacing)) != null ? _b : 0,
3892
+ wordSpacing: (_c = parseLen(node.wordSpacing)) != null ? _c : 0
3893
+ };
3894
+ }
3895
+ function paintOf(s) {
3896
+ const p = {};
3897
+ if (s.fill !== void 0) p.fill = s.fill;
3898
+ if (s.stroke !== void 0) p.stroke = s.stroke;
3899
+ if (s.strokeWidth !== void 0) p.strokeWidth = s.strokeWidth;
3900
+ if (s.opacity !== void 0 && s.opacity !== 1) p.opacity = s.opacity;
3901
+ for (const key of PAINT_STATIC_KEYS) {
3902
+ if (s[key] !== void 0) p[key] = s[key];
3903
+ }
3904
+ if (s.animate !== void 0) p.animate = s.animate;
3905
+ return p;
3906
+ }
3907
+ function glyphFontFor(s, glyphs, soleFont, warnings) {
3908
+ var _a2;
3909
+ const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;
3910
+ if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a2 = s.fontFamily) != null ? _a2 : "") + '"');
3911
+ return gf;
3912
+ }
3913
+ function soleFontOf(glyphs) {
3914
+ const names = Object.keys(glyphs);
3915
+ return names.length === 1 ? glyphs[names[0]] : void 0;
3916
+ }
3917
+ var MISSING_GLYPH_ADVANCE_EM = 0.6;
3918
+ var MISSING_GLYPH_CLASS_NAME = "px-missing-glyph";
3919
+ function missingGlyphBoxEm(advanceEm, ascentEm) {
3920
+ if (advanceEm <= 0 || ascentEm <= 0) return "";
3921
+ const inset = 0.08;
3922
+ const x0 = advanceEm * inset, x1 = advanceEm * (1 - inset);
3923
+ const y1 = -ascentEm * (1 - inset);
3924
+ const bw = x1 - x0, bh = -y1;
3925
+ const t = Math.max(1, Math.min(bw, bh) * 0.12);
3926
+ const outer = "M" + x0 + " 0L" + x1 + " 0L" + x1 + " " + y1 + "L" + x0 + " " + y1 + "Z";
3927
+ if (bw <= 2 * t || bh <= 2 * t) return outer;
3928
+ const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
3929
+ return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
3930
+ }
3931
+ function materializeGlyphTextHorizontal(node, opts) {
3932
+ var _a2, _b, _c;
3933
+ const { glyphs, create = jsonElementFactory, warnings } = opts;
3934
+ const soleFont = soleFontOf(glyphs);
3935
+ const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
3936
+ const placements = [];
3937
+ const lines = [{ start: pen.x, end: pen.x }];
3938
+ let line = 0;
3939
+ const renderChars = (content, s) => {
3940
+ var _a3;
3941
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
3942
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
3943
+ const scale = s.fontSize / upm;
3944
+ const ascentEm = (_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm;
3945
+ const paint = paintOf(s);
3946
+ for (let i = 0; i < content.length; i++) {
3947
+ const ch = content.charAt(i);
3948
+ const g = gf == null ? void 0 : gf.glyphs[ch];
3949
+ if (g && g.pathData) {
3950
+ placements.push({ glyphD: g.pathData, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
3951
+ pen.x += g.width * scale;
3952
+ } else if (/\S/.test(ch)) {
3953
+ const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
3954
+ placements.push({ glyphD: missingGlyphBoxEm(advEm, ascentEm), m: [scale, 0, 0, scale, pen.x, pen.y], paint, isMissing: true, line, x: pen.x, y: pen.y, scale });
3955
+ pen.x += advEm * scale;
3956
+ } else {
3957
+ pen.x += (g ? g.width : 0) * scale;
3958
+ }
3959
+ pen.x += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
3960
+ lines[line].end = pen.x;
3961
+ }
3962
+ };
3963
+ const walk = (el, parentStyle) => {
3964
+ var _a3, _b2, _c2;
3965
+ const s = resolveStyle(el, parentStyle);
3966
+ const x = parseLen(el.x);
3967
+ const y = parseLen(el.y);
3968
+ if (x !== void 0) {
3969
+ pen.x = x;
3970
+ line = lines.length;
3971
+ lines.push({ start: pen.x, end: pen.x });
3972
+ }
3973
+ if (y !== void 0) pen.y = y;
3974
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
3975
+ pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
3976
+ const content = str(el[PX_TEXT_CONTENT_ATTR]);
3977
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
3978
+ if (el.children) for (const ch of el.children) walk(ch, s);
3979
+ };
3980
+ const rootStyle = rootStyleOf(node);
3981
+ if (node.children) for (const ch of node.children) walk(ch, rootStyle);
3982
+ const rootContent = str(node[PX_TEXT_CONTENT_ATTR]);
3983
+ if (rootContent && !((_c = node.children) == null ? void 0 : _c.length)) renderChars(rootContent, rootStyle);
3984
+ const anchor = str(node.textAnchor);
3985
+ if (anchor === "middle" || anchor === "end") {
3986
+ for (const p of placements) {
3987
+ const w = lines[p.line].end - lines[p.line].start;
3988
+ const shift = anchor === "middle" ? -w / 2 : -w;
3989
+ p.m = [p.scale, 0, 0, p.scale, p.x + shift, p.y];
3990
+ }
3991
+ }
3992
+ return toGroup(node, buildPaths(placements, create, warnings), create);
3993
+ }
3994
+ function layoutGlyphTextChars(node, opts) {
3995
+ var _a2, _b, _c, _d, _e;
3996
+ if ((_a2 = opts.alongPath) == null ? void 0 : _a2.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
3997
+ const { glyphs, warnings } = opts;
3998
+ const soleFont = soleFontOf(glyphs);
3999
+ const pen = { x: (_b = parseLen(node.x)) != null ? _b : 0, y: (_c = parseLen(node.y)) != null ? _c : 0 };
4000
+ const boxes = [];
4001
+ const lines = [{ start: pen.x, end: pen.x }];
4002
+ let line = 0;
4003
+ const renderChars = (content, s) => {
4004
+ var _a3;
4005
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4006
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4007
+ const scale = s.fontSize / upm;
4008
+ const ascent = ((_a3 = gf == null ? void 0 : gf.ascent) != null ? _a3 : 0.9 * upm) * scale;
4009
+ for (let i = 0; i < content.length; i++) {
4010
+ const ch = content.charAt(i);
4011
+ const g = gf == null ? void 0 : gf.glyphs[ch];
4012
+ const advance = (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
4013
+ boxes.push({ x: pen.x, y: pen.y, width: advance, ascent, fontSize: s.fontSize, line });
4014
+ pen.x += advance;
4015
+ lines[line].end = pen.x;
4016
+ }
4017
+ };
4018
+ const walk = (el, parentStyle) => {
4019
+ var _a3, _b2, _c2;
4020
+ const s = resolveStyle(el, parentStyle);
4021
+ const x = parseLen(el.x);
4022
+ const y = parseLen(el.y);
4023
+ if (x !== void 0) {
4024
+ pen.x = x;
4025
+ line = lines.length;
4026
+ lines.push({ start: pen.x, end: pen.x });
4027
+ }
4028
+ if (y !== void 0) pen.y = y;
4029
+ pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
4030
+ pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
4031
+ const content = str(el[PX_TEXT_CONTENT_ATTR]);
4032
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
4033
+ if (el.children) for (const ch of el.children) walk(ch, s);
4034
+ };
4035
+ const rootStyle = rootStyleOf(node);
4036
+ if (node.children) for (const ch of node.children) {
4037
+ const before = boxes.length;
4038
+ walk(ch, rootStyle);
4039
+ if (boxes.length === before) {
4040
+ const s = resolveStyle(ch, rootStyle);
4041
+ const gf = glyphFontFor(s, glyphs, soleFont);
4042
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4043
+ boxes.push({ x: pen.x, y: pen.y, width: 0, ascent: ((_d = gf == null ? void 0 : gf.ascent) != null ? _d : 0.9 * upm) * (s.fontSize / upm), fontSize: s.fontSize, line });
4044
+ }
4045
+ }
4046
+ const rootContent = str(node[PX_TEXT_CONTENT_ATTR]);
4047
+ if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
4048
+ const anchor = str(node.textAnchor);
4049
+ if (anchor === "middle" || anchor === "end") {
4050
+ for (const b of boxes) {
4051
+ const w = lines[b.line].end - lines[b.line].start;
4052
+ b.x += anchor === "middle" ? -w / 2 : -w;
4053
+ }
4054
+ }
4055
+ return boxes.map((_f) => {
4056
+ var _g = _f, { line: _l } = _g, b = __objRest(_g, ["line"]);
4057
+ return b;
4058
+ });
4059
+ }
4060
+ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
4061
+ var _a2, _b;
4062
+ const { glyphs, warnings, alongPath } = opts;
4063
+ const sampler = createPathSampler(pathD);
4064
+ if (!sampler) {
4065
+ warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry (caret)");
4066
+ return [];
4067
+ }
4068
+ const soleFont = soleFontOf(glyphs);
4069
+ const chars = [];
4070
+ let adv = 0;
4071
+ const walk = (el, parentStyle) => {
4072
+ var _a3, _b2;
4073
+ const s = resolveStyle(el, parentStyle);
4074
+ const content = str(el[PX_TEXT_CONTENT_ATTR]);
4075
+ if (content && !((_a3 = el.children) == null ? void 0 : _a3.length)) {
4076
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4077
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
4078
+ const scale = s.fontSize / upm;
4079
+ const ascent = ((_b2 = gf == null ? void 0 : gf.ascent) != null ? _b2 : 0.9 * upm) * scale;
4080
+ for (let i = 0; i < content.length; i++) {
4081
+ const ch = content.charAt(i);
4082
+ const g = gf == null ? void 0 : gf.glyphs[ch];
4083
+ const glyphW = (g ? g.width : 0) * scale;
4084
+ const advance = glyphW + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
4085
+ chars.push({ advStart: adv, advEnd: adv + advance, glyphW, ascent, fontSize: s.fontSize });
4086
+ adv += advance;
4087
+ }
4088
+ }
4089
+ if (el.children) for (const ch of el.children) walk(ch, s);
4090
+ };
4091
+ walk(node, rootStyleOf(node));
4092
+ const width = adv;
4093
+ const tlr = readAnimatable(alongPath == null ? void 0 : alongPath.textLength);
4094
+ const tlv = tlr.kind === "animated" /* Animated */ ? Number((_a2 = tlr.keyframes[0]) == null ? void 0 : _a2.value) || 0 : tlr.kind === "static" /* Static */ ? Number(tlr.value) || 0 : 0;
4095
+ const k = tlv > 0 && width > 0 ? tlv / width : 1;
4096
+ const so = readAnimatable(alongPath == null ? void 0 : alongPath.startOffset);
4097
+ const { along: alongOffset, perp } = alongPathNodeOffsets(node);
4098
+ const base = alongOffset + (so.kind === "animated" /* Animated */ ? Number((_b = so.keyframes[0]) == null ? void 0 : _b.value) || 0 : so.kind === "static" /* Static */ ? Number(so.value) || 0 : 0);
4099
+ const withPerp = (p) => ({
4100
+ x: p.x - perp * Math.sin(p.angle),
4101
+ y: p.y + perp * Math.cos(p.angle),
4102
+ angle: p.angle
4103
+ });
4104
+ return chars.map((c) => {
4105
+ const dStart = base + c.advStart * k;
4106
+ const dEnd = base + c.advEnd * k;
4107
+ const p0 = withPerp(sampler.sampleAtDistance(dStart));
4108
+ const p1 = withPerp(sampler.sampleAtDistance(dEnd));
4109
+ const glyphMid = sampler.sampleAtDistance(base + (c.advStart + c.glyphW / 2) * k);
4110
+ return {
4111
+ x: p0.x,
4112
+ y: p0.y,
4113
+ width: c.advEnd - c.advStart,
4114
+ ascent: c.ascent,
4115
+ fontSize: c.fontSize,
4116
+ endX: p1.x,
4117
+ endY: p1.y,
4118
+ rotation: glyphMid.angle * 180 / Math.PI
4119
+ };
4120
+ });
4121
+ }
4122
+ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4123
+ const cells = [];
4124
+ let adv = 0;
4125
+ const walk = (el, parentStyle) => {
4126
+ var _a2, _b;
4127
+ const s = resolveStyle(el, parentStyle);
4128
+ const content = str(el[PX_TEXT_CONTENT_ATTR]);
4129
+ if (content && !((_a2 = el.children) == null ? void 0 : _a2.length)) {
4130
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
4131
+ if (gf) {
4132
+ const scale = s.fontSize / gf.unitsPerEm;
4133
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
4134
+ const paint = paintOf(s);
4135
+ for (let i = 0; i < content.length; i++) {
4136
+ const ch = content.charAt(i);
4137
+ const g = gf.glyphs[ch];
4138
+ if (g && g.pathData) {
4139
+ const glyphAdv = g.width * scale;
4140
+ cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
4141
+ adv += glyphAdv;
4142
+ } else if (/\S/.test(ch)) {
4143
+ const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
4144
+ const boxAdv = wEm * scale;
4145
+ cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, isMissing: true, midBase: adv + boxAdv / 2 });
4146
+ adv += boxAdv;
4147
+ } else {
4148
+ adv += (g ? g.width : 0) * scale;
4149
+ }
4150
+ adv += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
4151
+ }
4152
+ }
4153
+ }
4154
+ if (el.children) for (const ch of el.children) walk(ch, s);
4155
+ };
4156
+ walk(node, rootStyleOf(node));
4157
+ return { cells, width: adv };
4158
+ }
4159
+ function alongAffine(sampler, dist, scale, widthEm, perp = 0) {
4160
+ const { x, y, angle } = sampler.sampleAtDistance(dist);
4161
+ const cos = Math.cos(angle), sin = Math.sin(angle), hw = widthEm / 2;
4162
+ return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];
4163
+ }
4164
+ function alongPathNodeOffsets(node) {
4165
+ var _a2, _b, _c;
4166
+ return {
4167
+ along: ((_a2 = parseLen(node.x)) != null ? _a2 : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
4168
+ perp: (_c = parseLen(node.dy)) != null ? _c : 0
4169
+ };
4170
+ }
4171
+ function materializeGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
4172
+ const { glyphs, create = jsonElementFactory, warnings } = opts;
4173
+ const sampler = pathD ? createPathSampler(pathD) : null;
4174
+ if (!sampler) {
4175
+ warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry");
4176
+ return null;
4177
+ }
4178
+ const soleFont = soleFontOf(glyphs);
4179
+ const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
4180
+ if (!cells.length) return toGroup(node, [], create);
4181
+ const { along: alongOffset, perp } = alongPathNodeOffsets(node);
4182
+ const soTrack = numTrackOf(startOffset);
4183
+ const tlTrack = numTrackOf(textLength);
4184
+ const kOf = (tl) => tl > 0 && width > 0 ? tl / width : 1;
4185
+ const isClip = pathOverflow === "clip" && !sampler.closed;
4186
+ if (soTrack.animated || tlTrack.animated) {
4187
+ const times = mergeTrackTimes(soTrack.times, tlTrack.times);
4188
+ const distOf = (c, t) => alongOffset + soTrack.at(t) + kOf(tlTrack.at(t)) * c.midBase;
4189
+ const loop = soTrack.animated ? soTrack.loop : tlTrack.loop;
4190
+ return toGroup(node, buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isClip, perp), create);
4191
+ }
4192
+ const k = kOf(tlTrack.at(0));
4193
+ const base = alongOffset + soTrack.at(0);
4194
+ const placeCells = isClip ? cells.filter((c) => {
4195
+ const d = base + c.midBase * k;
4196
+ return d >= 0 && d <= sampler.totalLength;
4197
+ }) : cells;
4198
+ const placements = placeCells.map((c) => ({
4199
+ glyphD: c.glyphD,
4200
+ paint: c.paint,
4201
+ isMissing: c.isMissing,
4202
+ m: alongAffine(sampler, base + c.midBase * k, c.scale, c.widthEm, perp)
4203
+ }));
4204
+ return toGroup(node, buildPaths(placements, create, warnings), create);
4205
+ }
4206
+ function numTrackOf(raw) {
4207
+ var _a2;
4208
+ const r = readAnimatable(raw);
4209
+ if (r.kind === "animated" /* Animated */ && r.keyframes.length >= 2) {
4210
+ const kfs = [...r.keyframes].sort((k1, k2) => (Number(k1.time) || 0) - (Number(k2.time) || 0));
4211
+ const times = kfs.map((kf) => Number(kf.time) || 0);
4212
+ const vals = kfs.map((kf) => Number(kf.value) || 0);
4213
+ return {
4214
+ animated: true,
4215
+ times,
4216
+ loop: r.loop,
4217
+ at(t) {
4218
+ if (t <= times[0]) return vals[0];
4219
+ for (let i = 1; i < times.length; i++) {
4220
+ if (t <= times[i]) {
4221
+ const span = times[i] - times[i - 1];
4222
+ const f = span > 0 ? (t - times[i - 1]) / span : 1;
4223
+ return vals[i - 1] + f * (vals[i] - vals[i - 1]);
4224
+ }
4225
+ }
4226
+ return vals[vals.length - 1];
4227
+ }
4228
+ };
4229
+ }
4230
+ const v = r.kind === "animated" /* Animated */ ? Number((_a2 = r.keyframes[0]) == null ? void 0 : _a2.value) || 0 : r.kind === "static" /* Static */ ? Number(r.value) || 0 : 0;
4231
+ return { animated: false, times: [], at: () => v };
4232
+ }
4233
+ function mergeTrackTimes(a, b) {
4234
+ const all = [...a, ...b].sort((t1, t2) => t1 - t2);
4235
+ const out = [];
4236
+ for (const t of all) if (!out.length || t !== out[out.length - 1]) out.push(t);
4237
+ return out;
4238
+ }
4239
+ var ALONG_PATH_MAX_STEPS = 48;
4240
+ var ALONG_PATH_MAX_STEPS_PER_SEGMENT = 64;
4241
+ function roundN(v, n) {
4242
+ const f = __pow(10, n);
4243
+ return Math.round(v * f) / f;
4244
+ }
4245
+ function buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isClip, perp = 0) {
4246
+ const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
4247
+ const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
4248
+ const out = [];
4249
+ for (const c of cells) {
4250
+ const centered = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
4251
+ const d = transformPathData(c.glyphD, centered);
4252
+ const sampleKf = (dist, time) => {
4253
+ const { x, y, angle } = sampler.sampleAtDistance(dist);
4254
+ const cos = Math.cos(angle), sin = Math.sin(angle);
4255
+ return {
4256
+ time,
4257
+ value: {
4258
+ ["translate" /* Translate */]: [roundN(x - perp * sin, 3), roundN(y + perp * cos, 3)],
4259
+ ["rotate" /* Rotate */]: roundN(angle * 180 / Math.PI, 3)
4260
+ }
4261
+ };
4262
+ };
4263
+ const kfs = [];
4264
+ const opKfs = [];
4265
+ const pushKf = (dist, time) => {
4266
+ kfs.push(sampleKf(dist, time));
4267
+ if (isClip) opKfs.push({ time, value: onPath(dist) ? 1 : 0 });
4268
+ };
4269
+ pushKf(distOf(c, times[0]), times[0]);
4270
+ for (let k = 1; k < times.length; k++) {
4271
+ const t0 = times[k - 1], t1 = times[k];
4272
+ const d0 = distOf(c, t0), d1 = distOf(c, t1);
4273
+ const n = Math.min(ALONG_PATH_MAX_STEPS_PER_SEGMENT, Math.max(1, Math.ceil(Math.abs(d1 - d0) / step)));
4274
+ for (let s = 1; s <= n; s++) {
4275
+ const f = s / n;
4276
+ const t = t0 + f * (t1 - t0);
4277
+ pushKf(distOf(c, t), t);
4278
+ }
4279
+ }
4280
+ unwrapAutoOrientRotations(kfs);
4281
+ const transform = { keyframes: kfs };
4282
+ if (loop !== void 0) transform.loop = loop;
4283
+ const animate = { transform };
4284
+ if (c.paint.animate) Object.assign(animate, c.paint.animate);
4285
+ if (isClip && opKfs.some((k) => k.value === 0)) {
4286
+ const op = { keyframes: opKfs };
4287
+ if (loop !== void 0) op.loop = loop;
4288
+ animate.opacity = op;
4289
+ }
4290
+ out.push(create("path", __spreadProps(__spreadValues(__spreadValues({ d }, paintProps(c.paint)), missingGlyphProps(c.isMissing)), { animate }), []));
4291
+ }
4292
+ return out;
4293
+ }
4294
+ function paintProps(paint) {
4295
+ const p = {};
4296
+ if (paint.fill !== void 0) p.fill = paint.fill;
4297
+ if (paint.stroke !== void 0) p.stroke = paint.stroke;
4298
+ if (paint.strokeWidth !== void 0) p.strokeWidth = paint.strokeWidth;
4299
+ if (paint.opacity !== void 0) p.opacity = paint.opacity;
4300
+ for (const key of PAINT_STATIC_KEYS) {
4301
+ if (paint[key] !== void 0) p[key] = paint[key];
4302
+ }
4303
+ return p;
4304
+ }
4305
+ function missingGlyphProps(isMissing) {
4306
+ return isMissing ? { [CLASS_ATTR]: MISSING_GLYPH_CLASS_NAME } : {};
4307
+ }
4308
+ function buildPaths(placements, create, warnings) {
4309
+ if (!placements.length) {
4310
+ warnings == null ? void 0 : warnings.push("textGlyphs: nothing to render");
4311
+ return [];
4312
+ }
4313
+ const byPaint = /* @__PURE__ */ new Map();
4314
+ for (const p of placements) {
4315
+ const key = JSON.stringify([p.paint, !!p.isMissing]);
4316
+ const baked = transformPathData(p.glyphD, p.m);
4317
+ const entry = byPaint.get(key);
4318
+ if (entry) entry.d += baked;
4319
+ else byPaint.set(key, { paint: p.paint, d: baked, isMissing: p.isMissing });
4320
+ }
4321
+ const out = [];
4322
+ for (const { paint, d, isMissing } of byPaint.values()) {
4323
+ out.push(create("path", __spreadValues(__spreadValues(__spreadValues({
4324
+ d
4325
+ }, paintProps(paint)), missingGlyphProps(isMissing)), paint.animate !== void 0 ? { animate: __spreadValues({}, paint.animate) } : {}), []));
4326
+ }
4327
+ return out;
4328
+ }
4329
+ function toGroup(node, children, create) {
4330
+ const gProps = {};
4331
+ for (const k of Object.keys(node)) {
4332
+ if (k === "type" || k === "children" || TEXT_ATTR_KEYS.indexOf(k) !== -1) continue;
4333
+ gProps[k] = node[k];
4334
+ }
4335
+ if (gProps.style && typeof gProps.style === "object") {
4336
+ const style = __spreadValues({}, gProps.style);
4337
+ delete style["white-space"];
4338
+ if (Object.keys(style).length) gProps.style = style;
4339
+ else delete gProps.style;
4340
+ }
4341
+ return create("g", gProps, children);
4342
+ }
4343
+ function materializeGlyphText(node, opts) {
4344
+ if (opts.alongPath) return materializeGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
4345
+ return materializeGlyphTextHorizontal(node, opts);
4346
+ }
4347
+ function applyTextGlyphsEffect(node, fx, ctx) {
4348
+ if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
4349
+ if (!ctx.glyphs) {
4350
+ ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
4351
+ return node;
4352
+ }
4353
+ return materializeGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
4354
+ }
4355
+ function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
4356
+ if (!ctx.glyphs) {
4357
+ ctx.warnings.push("textGlyphs: no definitions.fonts");
4358
+ return null;
4359
+ }
4360
+ return materializeGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
4361
+ }
4362
+
4363
+ // src/playback/PxDiagnostics.ts
4364
+ var PxDiagnosticKind = {
4365
+ /** The document is wrong — regenerate or repair the file. */
4366
+ document: "document",
4367
+ /** The page or app cannot provide what the document asks for — fix the mount. */
4368
+ host: "host",
4369
+ /** The platform cannot do it and the player degraded — usually nothing to fix. */
4370
+ platform: "platform",
4371
+ /** The call is wrong or self-contradictory — fix the options or props you passed. */
4372
+ usage: "usage",
4373
+ /** The player failed where it did not expect to — report it to us. */
4374
+ internal: "internal"
4375
+ };
4376
+ function asError(error) {
4377
+ return typeof error === "string" ? new Error(error) : error;
4378
+ }
4379
+ function createDiagnostics(config, prefix) {
4380
+ const tag = prefix ? prefix + " " : "";
4381
+ return {
4382
+ warn: (kind, message, detail) => {
4383
+ if (config == null ? void 0 : config.onWarn) {
4384
+ config.onWarn({ kind, message, detail });
4385
+ return;
4386
+ }
4387
+ if (config == null ? void 0 : config.muteWarn) return;
4388
+ const line = tag + kind + ": " + message;
4389
+ if (detail === void 0) console.warn(line);
4390
+ else console.warn(line, detail);
4391
+ },
4392
+ error: (kind, error, detail) => {
4393
+ const err = asError(error);
4394
+ if (config == null ? void 0 : config.onError) {
4395
+ config.onError({ kind, message: err.message, error: err, detail });
4396
+ return;
4397
+ }
4398
+ if (config == null ? void 0 : config.muteError) return;
4399
+ const line = tag + kind + ": " + err.message;
4400
+ if (detail === void 0) console.error(line);
4401
+ else console.error(line, detail);
4402
+ }
4403
+ };
4404
+ }
4405
+
4406
+ // src/format/PxDocumentDiagnostic.ts
4407
+ var MAX_REPORTED = 6;
4408
+ function diagnoseDocument(doc) {
4409
+ try {
4410
+ return { problems: validateDocument(doc) };
4411
+ } catch (e) {
4412
+ return { problems: [] };
4413
+ }
4414
+ }
4415
+ function reportDocumentDiagnostics(doc, where) {
4416
+ const { problems } = diagnoseDocument(doc);
4417
+ if (!problems.length) return;
4418
+ const shown = problems.slice(0, MAX_REPORTED);
4419
+ const more = problems.length - shown.length;
4420
+ console.warn(
4421
+ where + ": this document does not match the animation schema in " + problems.length + " place" + (problems.length === 1 ? "" : "s") + ".\n" + shown.map((p) => " - " + p).join("\n") + (more > 0 ? "\n \u2026 and " + more + " more" : "") + "\n\nIf you did not author these keys, the usual cause is a build that MANGLES PROPERTY NAMES. An animation document is data loaded at runtime, so renaming the property reads inside the player stops them matching the keys in the JSON, and the animation silently does nothing. Feed the published reserved-name list to your minifier \u2014 @pixodesk/svg-animator-web/mangle-reserved.json \u2014 see docs/library/minification.md."
4422
+ );
4423
+ }
4424
+
4425
+ export {
4426
+ __spreadValues,
4427
+ __spreadProps,
4428
+ PX_UNKNOWN_KEY_ERROR,
4429
+ schemaKeys,
4430
+ describeSchema,
4431
+ px,
4432
+ PX_WIRE_SCHEMA_VERSION,
4433
+ PX_WIRE_VERSION_KEY,
4434
+ PxWireVersionRelation,
4435
+ parseWireVersion,
4436
+ formatWireVersion,
4437
+ PX_WIRE_VERSION,
4438
+ readWireVersion,
4439
+ compareWireVersion,
4440
+ wireVersionAdvice,
4441
+ PxWireStepKind,
4442
+ PX_WIRE_BASELINE_VERSION,
4443
+ PX_WIRE_STEPS,
4444
+ applyWireSteps,
4445
+ convertWireDocument,
4446
+ downgradeWireDocument,
4447
+ PxFillMode,
4448
+ PxPlaybackDirection,
4449
+ PX_ANIM_SRC_ATTR_NAME,
4450
+ PX_ANIM_ATTR_NAME,
4451
+ PxStartOn,
4452
+ PxOutAction,
4453
+ PxFinishAction,
4454
+ PxScrollKind,
4455
+ PxScrollAxis,
4456
+ PxScrollSource,
4457
+ PxPinAlign,
4458
+ PxScrollPhase,
4459
+ PxAlongPathMode,
4460
+ PX_TIMELINE_SHARED_KEYS,
4461
+ PX_TIME_ONLY_TIMELINE_KEYS,
4462
+ PxTimelineEngine,
4463
+ PxTimelineEngineSetting,
4464
+ resolveTimelineEngine,
4465
+ isNativeForced,
4466
+ mayUseNativeScrollTimeline,
4467
+ PX_TRIGGER_DEFAULTS,
4468
+ PxControlMode,
4469
+ resolveControlMode,
4470
+ controlModeTakesOverTrigger,
4471
+ resolveTrigger,
4472
+ PxLoopRepeatAt,
4473
+ PxLoopDirection,
4474
+ PxMaskType,
4475
+ PxUnits,
4476
+ PxCloneWithout,
4477
+ PxPathOverflow,
4478
+ PxLengthAdjust,
4479
+ PxTextPathMethod,
4480
+ PxTextPathSpacing,
4481
+ PxStrokeTrimSubPaths,
4482
+ PX_TEXT_CONTENT_ATTR,
4483
+ TRANSFORM_ATTR,
4484
+ OFFSET_DISTANCE_ATTR,
4485
+ TRANSFORM_PART,
4486
+ PX_TRANSFORM_PART_KEYS,
4487
+ PxGradientSpreadMethod,
4488
+ PxGradientType,
4489
+ isPxDocument,
4490
+ getAnimatorConfig,
4491
+ flattenAnimatorTimeline,
4492
+ nestAnimatorTimeline,
4493
+ getDefinitions,
4494
+ getBindings,
4495
+ getChildren,
4496
+ PxKeyframeValueSchema,
4497
+ PxKeyframeSchema,
4498
+ keyframeTime,
4499
+ keyframeValue,
4500
+ keyframeEasing,
4501
+ keyframeTangentIn,
4502
+ keyframeTangentOut,
4503
+ PxLoopSchema,
4504
+ PxPropertyAnimationSchema,
4505
+ PxTransformPartsSchema,
4506
+ PxTransformValueSchema,
4507
+ PxElementAnimationSchema,
4508
+ PxTriggerSchema,
4509
+ PxDefinitionsSchema,
4510
+ PxScrollRangePointSchema,
4511
+ PxScrollRangeSchema,
4512
+ PxScrollSchema,
4513
+ PxTimelineSchema,
4514
+ PxAnimatorConfigSchema,
4515
+ PxAttrValueSchema,
4516
+ PxTransformByEffectSchema,
4517
+ PxRepeaterEffectSchema,
4518
+ PxMaskedByEffectSchema,
4519
+ PxClipPathEffectSchema,
4520
+ PxStrokeTrimEffectSchema,
4521
+ PxRetimeEffectSchema,
4522
+ PxCloneEffectSchema,
4523
+ PxGradientStopSchema,
4524
+ PxFillGradientEffectSchema,
4525
+ PxTextPathEffectSchema,
4526
+ PxTextEffectSchema,
4527
+ PxEffectsSchema,
4528
+ validateNodeEffects,
4529
+ validateDocument,
4530
+ PxNodeBaseSchema,
4531
+ PxNodeSchema,
4532
+ PxSvgNodeRootSchema,
4533
+ PxAnimatedSvgDocumentSchema,
4534
+ PxBezierPathSchema,
4535
+ isValidPxDocument,
4536
+ generateUniqueId,
4537
+ deepClone,
4538
+ generateNewIds,
4539
+ bezierToSvgPath,
4540
+ cubicBezier,
4541
+ subdivideCubicBezier,
4542
+ splitEasing,
4543
+ reverseEasing,
4544
+ toRGBA,
4545
+ PX_COLOR_ATTR_NAMES,
4546
+ PX_TRANSFORM_FN_NAMES,
4547
+ PX_PCT_BASED_ATTR_NAMES,
4548
+ composeTransformParts,
4549
+ PX_STYLE_ATTR_NAMES,
4550
+ PX_DEFAULT_DURATION_MS,
4551
+ kebabToCamelCaseWord,
4552
+ camelCaseToKebabWordIfNeeded,
4553
+ clamp,
4554
+ bezier2D_arcLengthLUT,
4555
+ PX_DISALLOWED_SVG_TAGS_LOWER,
4556
+ PX_CSS_ONLY_STYLE_PROPS,
4557
+ sanitizeAttributeValue,
4558
+ toDomProps,
4559
+ materializeMotionPathInPropAnim,
4560
+ materializeMotionPathsInTree,
4561
+ PX_LOOP_JUMP_SHIFT_MS,
4562
+ parseSvgPathToBezier,
4563
+ interpolateValue,
4564
+ materializeInternalLoopsInTree,
4565
+ mergeStaticTransformIntoAnimDef,
4566
+ normalizeBindings,
4567
+ calcAnimationValues,
4568
+ partsRecord,
4569
+ readAnimatable,
4570
+ writeAnimatableChannel,
4571
+ readStaticOrigin,
4572
+ keyframeWith,
4573
+ deepClonePxNode,
4574
+ regenerateIdsAndRewriteRefs,
4575
+ applyUseOffsetToG,
4576
+ genId,
4577
+ stripHash,
4578
+ indexById,
4579
+ spliceDefs,
4580
+ clone,
4581
+ regenerateIdsInClone,
4582
+ createPathSampler,
4583
+ extendedPathForBrowser,
4584
+ applyTextPathEffect,
4585
+ layoutGlyphTextChars,
4586
+ materializeGlyphTextAlongPath,
4587
+ materializeGlyphText,
4588
+ applyTextGlyphsEffect,
4589
+ applyTextGlyphsAlongPath,
4590
+ PxDiagnosticKind,
4591
+ createDiagnostics,
4592
+ diagnoseDocument,
4593
+ reportDocumentDiagnostics
4594
+ };
4595
+ //# sourceMappingURL=chunk-L6GJ6Y2M.js.map