@pixodesk/svg-animator-core 1.0.45 → 1.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -110,6 +110,7 @@ __export(index_exports, {
110
110
  PxTextPathEffectSchema: () => PxTextPathEffectSchema,
111
111
  PxTextPathMethod: () => PxTextPathMethod,
112
112
  PxTextPathSpacing: () => PxTextPathSpacing,
113
+ PxTimeTimelineSchema: () => PxTimeTimelineSchema,
113
114
  PxTimelineEngine: () => PxTimelineEngine,
114
115
  PxTimelineEngineSetting: () => PxTimelineEngineSetting,
115
116
  PxTimelineSchema: () => PxTimelineSchema,
@@ -181,19 +182,31 @@ function pathStr(path) {
181
182
  return result;
182
183
  }
183
184
  var Base = class {
185
+ /** Structural schemas (objects, arrays, unions of objects…) pass `false`: they state no scalar default. */
186
+ constructor(_statesDefault) {
187
+ this._statesDefault = _statesDefault;
188
+ }
184
189
  _canSanitize(raw) {
185
190
  return this.isValid(raw);
186
191
  }
192
+ /** A REQUIRED field is never absent; its default is the repair value. */
193
+ absentDefault() {
194
+ return this._default;
195
+ }
187
196
  optional() {
188
197
  return new Optional(this);
189
198
  }
190
199
  };
191
200
  var Optional = class extends Base {
192
201
  constructor(inner) {
193
- super();
202
+ super(inner._statesDefault);
194
203
  this.inner = inner;
195
204
  this._default = void 0;
196
205
  }
206
+ /** Absent means the inner schema's STATED default — or nothing at all when it states none. */
207
+ absentDefault() {
208
+ return this.inner._statesDefault ? this.inner._default : void 0;
209
+ }
197
210
  sanitize(raw) {
198
211
  if (raw === void 0 || raw === null) return void 0;
199
212
  return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
@@ -207,8 +220,8 @@ var Optional = class extends Base {
207
220
  }
208
221
  };
209
222
  var Str = class extends Base {
210
- constructor(_default = "") {
211
- super();
223
+ constructor(_default, statesDefault) {
224
+ super(statesDefault);
212
225
  this._default = _default;
213
226
  }
214
227
  sanitize(raw) {
@@ -221,8 +234,8 @@ var Str = class extends Base {
221
234
  }
222
235
  };
223
236
  var Num = class extends Base {
224
- constructor(_default = 0) {
225
- super();
237
+ constructor(_default, statesDefault) {
238
+ super(statesDefault);
226
239
  this._default = _default;
227
240
  }
228
241
  sanitize(raw) {
@@ -235,8 +248,8 @@ var Num = class extends Base {
235
248
  }
236
249
  };
237
250
  var Bool = class extends Base {
238
- constructor(_default = false) {
239
- super();
251
+ constructor(_default, statesDefault) {
252
+ super(statesDefault);
240
253
  this._default = _default;
241
254
  }
242
255
  sanitize(raw) {
@@ -249,8 +262,9 @@ var Bool = class extends Base {
249
262
  }
250
263
  };
251
264
  var Literal = class extends Base {
265
+ /** A literal IS its own value: absent means it. */
252
266
  constructor(value) {
253
- super();
267
+ super(true);
254
268
  this.value = value;
255
269
  this._default = value;
256
270
  }
@@ -264,8 +278,8 @@ var Literal = class extends Base {
264
278
  }
265
279
  };
266
280
  var Enum = class extends Base {
267
- constructor(values, defaultVal) {
268
- super();
281
+ constructor(values, defaultVal, statesDefault) {
282
+ super(statesDefault);
269
283
  this.values = values;
270
284
  this._default = defaultVal != null ? defaultVal : values[0];
271
285
  }
@@ -280,8 +294,8 @@ var Enum = class extends Base {
280
294
  };
281
295
  var UNION_MEMBER_ERROR_LIMIT = 4;
282
296
  var Union = class extends Base {
283
- constructor(schemas, defaultVal) {
284
- super();
297
+ constructor(schemas, defaultVal, statesDefault) {
298
+ super(statesDefault);
285
299
  this.schemas = schemas;
286
300
  /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Union from Tuple. */
287
301
  this._kind = "union";
@@ -335,7 +349,7 @@ var Union = class extends Base {
335
349
  var DiscriminatedUnion = class extends Base {
336
350
  constructor(_key, _schemas, defaultVal) {
337
351
  var _a2;
338
- super();
352
+ super(false);
339
353
  this._key = _key;
340
354
  this._schemas = _schemas;
341
355
  /** Structural tag read by {@link describeSchema}. */
@@ -375,13 +389,19 @@ var DiscriminatedUnion = class extends Base {
375
389
  return schema ? schema._canSanitize(raw) : this._schemas[0]._canSanitize(raw);
376
390
  }
377
391
  };
392
+ function statedDefaults(shape) {
393
+ const out = {};
394
+ for (const key of Object.keys(shape)) if (shape[key]._statesDefault) out[key] = shape[key].absentDefault();
395
+ return Object.freeze(out);
396
+ }
378
397
  var Obj = class extends Base {
379
398
  constructor(_shape) {
380
- super();
399
+ super(false);
381
400
  this._shape = _shape;
382
401
  const d = {};
383
402
  for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
384
403
  this._default = d;
404
+ this.defaults = statedDefaults(_shape);
385
405
  }
386
406
  sanitize(raw) {
387
407
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
@@ -423,12 +443,13 @@ var Obj = class extends Base {
423
443
  };
424
444
  var OpenObj = class extends Base {
425
445
  constructor(_shape, _openSchema) {
426
- super();
446
+ super(false);
427
447
  this._shape = _shape;
428
448
  this._openSchema = _openSchema;
429
449
  const d = {};
430
450
  for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
431
451
  this._default = d;
452
+ this.defaults = statedDefaults(_shape);
432
453
  }
433
454
  sanitize(raw) {
434
455
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
@@ -473,7 +494,7 @@ var OpenObj = class extends Base {
473
494
  };
474
495
  var Arr = class extends Base {
475
496
  constructor(item) {
476
- super();
497
+ super(false);
477
498
  this.item = item;
478
499
  this._default = [];
479
500
  }
@@ -505,7 +526,7 @@ var Arr = class extends Base {
505
526
  };
506
527
  var Rec = class extends Base {
507
528
  constructor(value) {
508
- super();
529
+ super(false);
509
530
  this.value = value;
510
531
  /** Structural tag read by {@link describeSchema}. */
511
532
  this._kind = "record";
@@ -539,7 +560,7 @@ var Rec = class extends Base {
539
560
  };
540
561
  var Any = class extends Base {
541
562
  constructor() {
542
- super(...arguments);
563
+ super(false);
543
564
  this._default = void 0;
544
565
  }
545
566
  sanitize(raw) {
@@ -554,7 +575,7 @@ var Any = class extends Base {
554
575
  };
555
576
  var Defined = class extends Base {
556
577
  constructor() {
557
- super(...arguments);
578
+ super(false);
558
579
  this._default = void 0;
559
580
  }
560
581
  sanitize(raw) {
@@ -571,7 +592,7 @@ var Defined = class extends Base {
571
592
  };
572
593
  var Lazy = class extends Base {
573
594
  constructor(fn, _default) {
574
- super();
595
+ super(false);
575
596
  this.fn = fn;
576
597
  this._default = _default;
577
598
  this.resolved = null;
@@ -592,7 +613,7 @@ var Lazy = class extends Base {
592
613
  };
593
614
  var Tuple = class extends Base {
594
615
  constructor(schemas) {
595
- super();
616
+ super(false);
596
617
  this.schemas = schemas;
597
618
  /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Tuple from Union. */
598
619
  this._kind = "tuple";
@@ -648,22 +669,29 @@ function describeSchema(schema) {
648
669
  if ("fn" in s) return { kind: "lazy", resolved: (_a2 = s.resolved) != null ? _a2 : s.resolved = s.fn() };
649
670
  return { kind: "leaf" };
650
671
  }
672
+ function string(defaultVal) {
673
+ return defaultVal === void 0 ? new Str("", false) : new Str(defaultVal, true);
674
+ }
675
+ function number(defaultVal) {
676
+ return defaultVal === void 0 ? new Num(0, false) : new Num(defaultVal, true);
677
+ }
678
+ function boolean(defaultVal) {
679
+ return defaultVal === void 0 ? new Bool(false, false) : new Bool(defaultVal, true);
680
+ }
681
+ function oneOf(values, defaultVal) {
682
+ return defaultVal === void 0 ? new Enum(values, void 0, false) : new Enum(values, defaultVal, true);
683
+ }
684
+ function unionOf(schemas, defaultVal) {
685
+ return defaultVal === void 0 ? new Union(schemas, void 0, false) : new Union(schemas, defaultVal, true);
686
+ }
651
687
  var px = {
652
- /** Matches a string. Default: '' or provided value. */
653
- string: (defaultVal = "") => new Str(defaultVal),
654
- /** Matches a finite number. Default: 0 or provided value. */
655
- number: (defaultVal = 0) => new Num(defaultVal),
656
- /** Matches a boolean. Default: false or provided value. */
657
- boolean: (defaultVal = false) => new Bool(defaultVal),
658
- /** Matches one exact primitive value; its default is the value itself. */
688
+ string,
689
+ number,
690
+ boolean,
691
+ /** Matches one exact primitive value; absent means the value itself. */
659
692
  literal: (value) => new Literal(value),
660
- /** Matches one of a fixed set of string/number values. Default: first value. */
661
- enum: (values, defaultVal) => new Enum(values, defaultVal),
662
- /**
663
- * Returns the first schema whose isValid passes.
664
- * TypeScript infers the union of all member types automatically.
665
- */
666
- union: (schemas, defaultVal) => new Union(schemas, defaultVal),
693
+ enum: oneOf,
694
+ union: unionOf,
667
695
  /**
668
696
  * Discriminated union — reads `raw[key]`, finds the member schema whose
669
697
  * literal at `key` matches, then delegates sanitize/isValid to that member.
@@ -671,7 +699,8 @@ var px = {
671
699
  * TypeScript infers the union of all member types automatically.
672
700
  */
673
701
  discriminatedUnion: (key, schemas) => new DiscriminatedUnion(key, schemas),
674
- /** Typed object — unknown keys are stripped. Required fields fall back to their default. */
702
+ /** Typed object — unknown keys are stripped. Required fields fall back to their default.
703
+ * Its `defaults` say what each stated field means when a document leaves it out. */
675
704
  object: (shape) => new Obj(shape),
676
705
  /**
677
706
  * Open object — validates known keys; passes unknown keys through as-is,
@@ -1015,8 +1044,11 @@ var PX_TRIGGER_DEFAULTS = {
1015
1044
  offScreen: "pause",
1016
1045
  mouseOut: "continue",
1017
1046
  visibilityThreshold: 0.5,
1018
- visibilityDebounce: 150
1047
+ visibilityDebounce: 150,
1048
+ finish: "hold"
1019
1049
  };
1050
+ var PX_DEFAULT_DURATION_MS = 1e3;
1051
+ var PX_DEFAULT_ITERATIONS = 1;
1020
1052
  var PxControlMode = {
1021
1053
  /** No control props — the document's trigger decides, and nothing is taken over. */
1022
1054
  static: "static",
@@ -1331,15 +1363,15 @@ var keyframeTangentIn = (kf) => anyKf(kf).tangentIn;
1331
1363
  var keyframeTangentOut = (kf) => anyKf(kf).tangentOut;
1332
1364
  var PxLoopSchema = implementsInterface()(px.object({
1333
1365
  segmentCount: px.number().optional(),
1334
- repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1335
- direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1366
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end], PxLoopRepeatAt.end).optional(),
1367
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate], PxLoopDirection.normal).optional()
1336
1368
  }));
1337
1369
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1338
1370
  value: PxKeyframeValueSchema.optional(),
1339
1371
  keyframes: px.array(PxKeyframeSchema).optional(),
1340
1372
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1341
1373
  autoOrient: px.boolean().optional(),
1342
- alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
1374
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath], PxAlongPathMode.sampled).optional()
1343
1375
  }));
1344
1376
  var PxTransformPartsSchema = implementsInterface()(px.object({
1345
1377
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1369,9 +1401,9 @@ var PxTriggerSchema = implementsInterface()(px.object({
1369
1401
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1370
1402
  // `fill`) or `'reset'` (snap back to the start state). One of four occasion keys
1371
1403
  // (`start`, `offScreen`, `mouseOut`, `finish`), all named the same way.
1372
- finish: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
1373
- visibilityThreshold: px.number().optional(),
1374
- visibilityDebounce: px.number().optional()
1404
+ finish: px.enum([PxFinishAction.hold, PxFinishAction.reset], PX_TRIGGER_DEFAULTS.finish).optional(),
1405
+ visibilityThreshold: px.number(PX_TRIGGER_DEFAULTS.visibilityThreshold).optional(),
1406
+ visibilityDebounce: px.number(PX_TRIGGER_DEFAULTS.visibilityDebounce).optional()
1375
1407
  }));
1376
1408
  var PxGlyphSchema = implementsInterface()(px.object({
1377
1409
  width: px.number(),
@@ -1397,7 +1429,7 @@ var PxScrollRangePointSchema = implementsInterface()(px.object({
1397
1429
  PxScrollPhase.exit,
1398
1430
  PxScrollPhase.entryCrossing,
1399
1431
  PxScrollPhase.exitCrossing
1400
- ]).optional(),
1432
+ ], PxScrollPhase.cover).optional(),
1401
1433
  fraction: px.number().optional()
1402
1434
  }));
1403
1435
  var PxScrollRangeSchema = px.object({
@@ -1405,37 +1437,37 @@ var PxScrollRangeSchema = px.object({
1405
1437
  end: PxScrollRangePointSchema.optional()
1406
1438
  });
1407
1439
  var PxScrollSchema = implementsInterface()(px.object({
1408
- kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
1409
- axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1410
- source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1440
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll], PxScrollKind.view).optional(),
1441
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y], PxScrollAxis.block).optional(),
1442
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root], PxScrollSource.nearest).optional(),
1411
1443
  // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1412
1444
  subject: px.string().optional(),
1413
1445
  smoothing: px.number().optional(),
1414
- pin: px.boolean().optional(),
1415
- pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1446
+ pin: px.boolean(false).optional(),
1447
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom], PxPinAlign.top).optional(),
1416
1448
  pinOffset: px.number().optional(),
1417
1449
  pinDistance: px.number().optional(),
1418
1450
  range: PxScrollRangeSchema.optional()
1419
1451
  }));
1420
1452
  var PxTimelinePinSchema = implementsInterface()(px.object({
1421
- align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1453
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom], PxPinAlign.top).optional(),
1422
1454
  offset: px.number().optional(),
1423
1455
  distance: px.number().optional()
1424
1456
  }));
1425
- var PxTimelineEngineSchema = px.enum([PxTimelineEngineSetting.auto, PxTimelineEngineSetting.native, PxTimelineEngineSetting.js]).optional();
1457
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineSetting.auto, PxTimelineEngineSetting.native, PxTimelineEngineSetting.js], PxTimelineEngineSetting.auto).optional();
1426
1458
  var PxTimeTimelineSchema = implementsInterface()(px.object({
1427
1459
  type: px.literal("time").optional(),
1428
1460
  engine: PxTimelineEngineSchema,
1429
1461
  frameRate: px.number().optional(),
1430
1462
  // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1431
- duration: px.number().optional(),
1463
+ duration: px.number(PX_DEFAULT_DURATION_MS).optional(),
1432
1464
  trigger: PxTriggerSchema.optional(),
1433
- delay: px.number().optional(),
1434
- iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1465
+ delay: px.number(0).optional(),
1466
+ iterations: px.union([px.number(PX_DEFAULT_ITERATIONS), px.literal("infinite")], PX_DEFAULT_ITERATIONS).optional(),
1435
1467
  // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1436
1468
  // — never `fill`, which is paint everywhere else in the format.
1437
- fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
1438
- direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
1469
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none], PxFillMode.forwards).optional(),
1470
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse], PxPlaybackDirection.normal).optional()
1439
1471
  }));
1440
1472
  var scrollishTimelineShape = {
1441
1473
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
@@ -1446,8 +1478,8 @@ var scrollishTimelineShape = {
1446
1478
  iterations: px.number().optional(),
1447
1479
  engine: PxTimelineEngineSchema,
1448
1480
  frameRate: px.number().optional(),
1449
- axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1450
- source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1481
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y], PxScrollAxis.block).optional(),
1482
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root], PxScrollSource.nearest).optional(),
1451
1483
  subject: px.string().optional(),
1452
1484
  // 'parent' | 'scroller' | any CSS selector
1453
1485
  smoothing: px.number().optional(),
@@ -1527,9 +1559,10 @@ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1527
1559
  }));
1528
1560
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
1529
1561
  source: px.string().optional(),
1530
- maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1531
- maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1532
- maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1562
+ // SVG's own initial values — what a <mask> does when the attribute is not there.
1563
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha], PxMaskType.luminance).optional(),
1564
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox], PxUnits.objectBoundingBox).optional(),
1565
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox], PxUnits.userSpaceOnUse).optional(),
1533
1566
  x: px.number().optional(),
1534
1567
  y: px.number().optional(),
1535
1568
  width: px.number().optional(),
@@ -1541,7 +1574,7 @@ var PxClipPathEffectSchema = implementsInterface()(px.object({
1541
1574
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1542
1575
  offset: PxAnimatableNumberSchema.optional(),
1543
1576
  range: PxAnimatableVec2Schema.optional(),
1544
- subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined]).optional()
1577
+ subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined], PxStrokeTrimSubPaths.separate).optional()
1545
1578
  }));
1546
1579
  var PxRetimeEffectSchema = implementsInterface()(px.object({
1547
1580
  start: px.number().optional(),
@@ -1573,17 +1606,20 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1573
1606
  radius: PxAnimatableNumberSchema.optional(),
1574
1607
  focal: PxAnimatableVec2Schema.optional(),
1575
1608
  stops: PxAnimatableGradientStopsSchema.optional(),
1576
- gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1577
- spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1609
+ // SVG's own initial values — what a gradient does when the attribute is not there.
1610
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox], PxUnits.objectBoundingBox).optional(),
1611
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat], PxGradientSpreadMethod.pad).optional(),
1578
1612
  gradientTransform: px.string().optional()
1579
1613
  }));
1580
1614
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1581
1615
  var PxTextPathEffectSchema = implementsInterface()(px.object({
1582
1616
  pathData: px.string(),
1583
- pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1584
- lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1585
- method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
1586
- spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
1617
+ // `extend` is what an omitted pathOverflow means (glyphs continue along the tangent); the
1618
+ // other three are SVG's own initial values for the native <textPath> attributes.
1619
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend], PxPathOverflow.extend).optional(),
1620
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs], PxLengthAdjust.spacing).optional(),
1621
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch], PxTextPathMethod.align).optional(),
1622
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact], PxTextPathSpacing.exact).optional(),
1587
1623
  startOffset: PxAnimatableNumberSchema.optional(),
1588
1624
  textLength: PxAnimatableNumberSchema.optional()
1589
1625
  }));
@@ -2150,7 +2186,6 @@ function parseTransformParts(str2) {
2150
2186
  if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
2151
2187
  return Object.keys(out).length ? out : void 0;
2152
2188
  }
2153
- var PX_DEFAULT_DURATION_MS = 1e3;
2154
2189
  function kebabToCamelCaseWord(kebab) {
2155
2190
  return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
2156
2191
  }
@@ -6126,9 +6161,10 @@ function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, ro
6126
6161
  // src/materialize/PxRestPose.ts
6127
6162
  var TRANSFORM_CHANNEL = "transform";
6128
6163
  var REVERSED_DIRECTIONS = /* @__PURE__ */ new Set(["reverse", "alternate-reverse"]);
6164
+ var VERIFY_SAMPLE_FRACTIONS = [0, 0.25, 0.5, 0.75, 1];
6129
6165
  var SCRATCH_ID_PREFIX = "__px_rest_";
6130
6166
  function materializeRestPosesInTree(root, engine) {
6131
- var _a2;
6167
+ var _a2, _b;
6132
6168
  const out = deepClone(root);
6133
6169
  const config = getAnimatorConfig(out) || {};
6134
6170
  const duration = +(config.duration || PX_DEFAULT_DURATION_MS);
@@ -6140,18 +6176,27 @@ function materializeRestPosesInTree(root, engine) {
6140
6176
  for (const [key, animate] of before) {
6141
6177
  const node = nodes.get(key);
6142
6178
  if (!node) continue;
6143
- for (const channel of Object.keys(animate)) {
6179
+ const channels = Object.keys(animate);
6180
+ for (const channel of channels) {
6181
+ if (PX_TRANSFORM_FN_NAMES.has(channel)) continue;
6144
6182
  if (!mayCarryRestPose(node, channel)) continue;
6145
6183
  const value = firstFrameValue(animate, channel, firstFrameTime);
6146
6184
  if (value === void 0) continue;
6147
6185
  node[channel] = value;
6148
6186
  added.set(key, [...(_a2 = added.get(key)) != null ? _a2 : [], channel]);
6149
6187
  }
6188
+ if (channels.some((channel) => PX_TRANSFORM_FN_NAMES.has(channel)) && mayCarryTransformRestPose(node)) {
6189
+ const parts = firstFrameTransformParts(animate, firstFrameTime);
6190
+ if (parts) {
6191
+ node[TRANSFORM_CHANNEL] = parts;
6192
+ added.set(key, [...(_b = added.get(key)) != null ? _b : [], TRANSFORM_CHANNEL]);
6193
+ }
6194
+ }
6150
6195
  }
6151
6196
  if (added.size) {
6152
6197
  const after = bindingsOf(out, engine);
6153
6198
  for (const [key, channels] of added) {
6154
- if (JSON.stringify(after.get(key)) === JSON.stringify(before.get(key))) continue;
6199
+ if (writesTheSameFrames(before.get(key), after.get(key), duration)) continue;
6155
6200
  const node = nodes.get(key);
6156
6201
  if (node) for (const channel of channels) delete node[channel];
6157
6202
  }
@@ -6160,16 +6205,31 @@ function materializeRestPosesInTree(root, engine) {
6160
6205
  }
6161
6206
  function mayCarryRestPose(node, channel) {
6162
6207
  if (node[channel] !== void 0) return false;
6163
- if (PX_TRANSFORM_FN_NAMES.has(channel)) return false;
6164
- if (channel === TRANSFORM_CHANNEL) {
6165
- for (const part of PX_TRANSFORM_FN_NAMES) if (node[part] !== void 0) return false;
6166
- }
6208
+ if (channel === TRANSFORM_CHANNEL) return mayCarryTransformRestPose(node);
6209
+ return true;
6210
+ }
6211
+ function mayCarryTransformRestPose(node) {
6212
+ if (node[TRANSFORM_CHANNEL] !== void 0) return false;
6213
+ for (const part of PX_TRANSFORM_FN_NAMES) if (node[part] !== void 0) return false;
6167
6214
  return true;
6168
6215
  }
6169
6216
  function firstFrameValue(animate, channel, timeMs) {
6170
6217
  const values = Object.values(calcAnimationValues({ [channel]: animate[channel] }, timeMs));
6171
6218
  return values.length === 1 && values[0] !== "" ? values[0] : void 0;
6172
6219
  }
6220
+ function firstFrameTransformParts(animate, timeMs) {
6221
+ const family = {};
6222
+ for (const channel of Object.keys(animate)) if (PX_TRANSFORM_FN_NAMES.has(channel)) family[channel] = animate[channel];
6223
+ const written = calcAnimationValues(family, timeMs)[TRANSFORM_CHANNEL];
6224
+ if (!written) return void 0;
6225
+ const parts = parseTransformParts(written.replace(/(px|deg)\b/g, ""));
6226
+ return parts && Object.keys(parts).length ? parts : void 0;
6227
+ }
6228
+ function writesTheSameFrames(a, b, durationMs) {
6229
+ if (!a || !b) return a === b;
6230
+ const frame = (animate, t) => JSON.stringify(calcAnimationValues(animate, t)).replace(/\s+/g, "");
6231
+ return VERIFY_SAMPLE_FRACTIONS.every((fraction) => frame(a, fraction * durationMs) === frame(b, fraction * durationMs));
6232
+ }
6173
6233
  function bindingsOf(tree, engine) {
6174
6234
  const scratch = deepClone(tree);
6175
6235
  const keyById = /* @__PURE__ */ new Map();
@@ -6320,13 +6380,13 @@ function createAdapterAnimator(doc, adapter, callbacks) {
6320
6380
  const bindings = normalizeBindings(doc, PxTimelineEngine.js);
6321
6381
  const _iterations = config.iterations;
6322
6382
  let iterations = 1;
6323
- if (typeof _iterations === "number") iterations = _iterations || 1;
6383
+ if (typeof _iterations === "number") iterations = _iterations || PX_DEFAULT_ITERATIONS;
6324
6384
  if (_iterations === "infinite") iterations = Infinity;
6325
6385
  if (iterations < 1) iterations = 1;
6326
6386
  const duration = +(config.duration || PX_DEFAULT_DURATION_MS);
6327
- const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
6328
- const direction = config.direction || "normal";
6329
- const fill = (_a2 = config.fill) != null ? _a2 : "forwards";
6387
+ const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : PX_DEFAULT_ITERATIONS) * duration : 0;
6388
+ const direction = config.direction || PxTimeTimelineSchema.defaults.direction;
6389
+ const fill = (_a2 = config.fill) != null ? _a2 : PxTimeTimelineSchema.defaults.fillMode;
6330
6390
  const fillsForwards = fill === "forwards" || fill === "both";
6331
6391
  const fillsBackwards = fill === "backwards" || fill === "both";
6332
6392
  let timerId = null;
@@ -6849,6 +6909,7 @@ function diagnoseDocument(doc) {
6849
6909
  PxTextPathEffectSchema,
6850
6910
  PxTextPathMethod,
6851
6911
  PxTextPathSpacing,
6912
+ PxTimeTimelineSchema,
6852
6913
  PxTimelineEngine,
6853
6914
  PxTimelineEngineSetting,
6854
6915
  PxTimelineSchema,