@pixodesk/svg-animator-core 1.0.24 → 1.0.26

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.d.cts CHANGED
@@ -17368,8 +17368,8 @@ interface PxNode extends PxInfer<typeof PxNodeBase> {
17368
17368
  * `{ width?:number, height?:number, viewBox?:string, animator?:AnimatorConfig }`
17369
17369
  */
17370
17370
  declare const PxSvgNodeExtra: PxSchema<{} & {
17371
- width?: number | undefined;
17372
- height?: number | undefined;
17371
+ width?: string | number | undefined;
17372
+ height?: string | number | undefined;
17373
17373
  viewBox?: string | undefined;
17374
17374
  animator?: ({} & {
17375
17375
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -17658,8 +17658,8 @@ declare const PxSvgNodeExtra: PxSchema<{} & {
17658
17658
  }) | undefined;
17659
17659
  }, false> & {
17660
17660
  readonly _shape: {
17661
- width: PxSchema<number | undefined, true>;
17662
- height: PxSchema<number | undefined, true>;
17661
+ width: PxSchema<string | number | undefined, true>;
17662
+ height: PxSchema<string | number | undefined, true>;
17663
17663
  viewBox: PxSchema<string | undefined, true>;
17664
17664
  animator: PxSchema<({} & {
17665
17665
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -17967,8 +17967,8 @@ declare const PxAnimatedSvgDocumentSchema: PxSchema<{
17967
17967
  type: "svg";
17968
17968
  } & {
17969
17969
  children?: any[] | undefined;
17970
- width?: number | undefined;
17971
- height?: number | undefined;
17970
+ width?: string | number | undefined;
17971
+ height?: string | number | undefined;
17972
17972
  viewBox?: string | undefined;
17973
17973
  animator?: ({} & {
17974
17974
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -20936,8 +20936,8 @@ declare const PxAnimatedSvgDocumentSchema: PxSchema<{
20936
20936
  readonly _shape: {
20937
20937
  type: PxSchema<"svg", false>;
20938
20938
  children: PxSchema<any[] | undefined, true>;
20939
- width: PxSchema<number | undefined, true>;
20940
- height: PxSchema<number | undefined, true>;
20939
+ width: PxSchema<string | number | undefined, true>;
20940
+ height: PxSchema<string | number | undefined, true>;
20941
20941
  viewBox: PxSchema<string | undefined, true>;
20942
20942
  animator: PxSchema<({} & {
20943
20943
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -24038,6 +24038,7 @@ declare function reverseEasing(easing: Easing | undefined): Easing | undefined;
24038
24038
  declare function toRGBA(color: Array<number>): string;
24039
24039
  declare const COLOUR_ATTR_NAMES: Set<string>;
24040
24040
  declare const TRANSFORM_FN_NAMES: Set<string>;
24041
+ declare const PCT_BASED_ATTR_NAMES: Set<string>;
24041
24042
  /**
24042
24043
  * Compose a `PxTransformParts` record into a single SVG/CSS transform string in
24043
24044
  * the canonical order:
@@ -24138,6 +24139,23 @@ declare function sanitiseAttributeValue(name: string, value: any): any | undefin
24138
24139
  declare function resolveStyle(style: string | Record<string, string | number> | undefined, defs?: PxDefs): Record<string, string | number> | undefined;
24139
24140
  declare function getNormalizedProps(props: Record<string, any>): Record<string, any>;
24140
24141
 
24142
+ /**
24143
+ * Time separation between a cycle's snap-back keyframe and the previous repetition's
24144
+ * end, in ms.
24145
+ *
24146
+ * SINGLE SOURCE OF TRUTH — the editor imports this and converts to its own frame unit
24147
+ * (`TLoop.smallFrameShift = LOOP_JUMP_SHIFT_MS / FRAME_DURATION_MS`), so the two sides
24148
+ * cannot drift apart and materialise different keyframes (B7).
24149
+ *
24150
+ * 1ms, not one 10ms editor frame: a 10ms snap-back is long enough to read as a visible
24151
+ * jump in a looping animation (confirmed visually). The gap only has to be non-zero — it
24152
+ * exists so the snap-back is a discontinuity rather than an interpolated tween.
24153
+ *
24154
+ * ⚠️ The editor works in FRAMES (`FRAME_DURATION_MS = 10`), so this is a sub-frame shift
24155
+ * there. `TKeyframeGroup` rounds keyframe times to integer frames in some paths; the
24156
+ * editor side keeps the fractional value and must not be re-clamped to a whole frame.
24157
+ */
24158
+ declare const LOOP_JUMP_SHIFT_MS = 1;
24141
24159
  /**
24142
24160
  * Interpolates between two keyframe values based on property type.
24143
24161
  * Returns the raw interpolated value (not a CSS string).
@@ -24468,4 +24486,4 @@ interface EffectDiff {
24468
24486
  */
24469
24487
  declare function diffInEffect(a: VmNode, b: VmNode): Array<EffectDiff>;
24470
24488
 
24471
- export { type ApplyResult, COLOUR_ATTR_NAMES, CSS_ONLY_STYLE_PROPS, DEFAULT_DURATION_MS, DISALLOWED_SVG_TAGS_LOWER, type ExtendPathOpts, type ExtendedPath, type FillMode, type GlyphCharBox, type GlyphCharBoxAlongPath, type GlyphMaterialiseOpts, INTERNAL_ATTRS, type JsMode, type KeysMatch, type MaterialiseAllOptions, type MotionPathMaterialisationOptions, type MotionPathSample, type OutAction, PX_ANIM_ATTR_NAME, PX_ANIM_SRC_ATTR_NAME, PX_TRANSFORM_PART_KEYS, type PathPoint, type PathSampler, type PlaybackDirection, type PxAnimatable, type PxAnimatedSvgDocument, PxAnimatedSvgDocumentSchema, type PxAnimationDefinition, PxAnimationDefinitionSchema, type PxAnimatorAPI, type PxAnimatorCallbacksConfig, type PxAnimatorConfig, PxAnimatorConfigSchema, PxAnimatorEngine, PxAnimatorMode, type PxAttrValue, PxAttrValueSchema, type PxBasicAnimatorAPI, type PxBezierPath, PxBezierPathSchema, type PxBinding, PxBindingSchema, type PxCloneEffect, PxCloneEffectSchema, type PxCreateElement, type PxDefs, PxDefsSchema, PxEasingOrRefSchema, type PxEffects, PxEffectsSchema, type PxElementAnimation, PxElementAnimationSchema, type PxFillGradientEffect, PxFillGradientEffectSchema, type PxGlyph, type PxGlyphFont, PxGradientSpreadMethod, type PxGradientStop, PxGradientStopSchema, PxGradientType, PxGradientUnits, type PxInfer, type PxKeyframe, PxKeyframeSchema, PxKeyframeValueSchema, type PxLoop, PxLoopExtend, PxLoopSchema, type PxMaskedByEffect, PxMaskedByEffectSchema, type PxNode, PxNodeBase, PxNodeSchema, type PxPlatformAdapter, type PxPropertyAnimation, PxPropertyAnimationSchema, type PxRepeaterEffect, PxRepeaterEffectSchema, type PxRetimeEffect, PxRetimeEffectSchema, type PxSchema, type PxSchemaDesc, type PxStrokeGradientEffect, PxStrokeGradientEffectSchema, type PxSvgNode, PxSvgNodeExtra, PxTextEffectSchema, type PxTextPathEffect, PxTextPathEffectSchema, type PxTransformByEffect, PxTransformByEffectSchema, type PxTransformPartKey, type PxTransformParts, PxTransformPartsSchema, type PxTransformValue, PxTransformValueSchema, type PxTrigger, PxTriggerSchema, type PxTrimPathEffect, PxTrimPathEffectSchema, PxTrimSubPaths, type PxValidationContext, type PxValidationResult, type RemoveIndex, STYLE_ATTR_NAMES, type StartOn, TEXT_ATTR, TEXT_CONTENT_ATTR, TRANSFORM_FN_NAMES, type Vec2, applyPlayerEffects, bezierToSvgPath, calcAnimationValues, camelCaseToKebabWordIfNeeded, clamp, collectSampleTimes, composeTransformParts, createBasicFrameLoopAnimator, createPathSampler, cubicBezier, deepClone, describeSchema, diffInEffect, evaluateMotionPathSegment, extendedPathForBrowser, generateNewIds, generateUniqueId, getAnimatorConfig, getBindings, getChildren, getDefs, getNormalisedBindings, getNormalizedProps, interpolateBeziers, interpolateValue, isPxElementFileFormat, isPxElementFileFormatDeep, jsonElementFactory, kebabToCamelCaseWord, layoutGlyphTextChars, materialiseAllInTree, materialiseAnimatedUseInstances, materialiseGlyphText, materialiseGlyphTextAlongPath, materialiseGlyphTextHorizontal, materialiseInternalLoopsInPropAnim, materialiseInternalLoopsInTree, materialiseMotionPathInPropAnim, materialiseMotionPathsInTree, propAnimIsMotionPath, px, resolveStyle, reverseEasing, sanitiseAttributeValue, schemaKeys, shiftAnimatable, splitEasing, subdivideCubicBezier, toRGBA, validateNodeEffects, visualModelAt };
24489
+ export { type ApplyResult, COLOUR_ATTR_NAMES, CSS_ONLY_STYLE_PROPS, DEFAULT_DURATION_MS, DISALLOWED_SVG_TAGS_LOWER, type ExtendPathOpts, type ExtendedPath, type FillMode, type GlyphCharBox, type GlyphCharBoxAlongPath, type GlyphMaterialiseOpts, INTERNAL_ATTRS, type JsMode, type KeysMatch, LOOP_JUMP_SHIFT_MS, type MaterialiseAllOptions, type MotionPathMaterialisationOptions, type MotionPathSample, type OutAction, PCT_BASED_ATTR_NAMES, PX_ANIM_ATTR_NAME, PX_ANIM_SRC_ATTR_NAME, PX_TRANSFORM_PART_KEYS, type PathPoint, type PathSampler, type PlaybackDirection, type PxAnimatable, type PxAnimatedSvgDocument, PxAnimatedSvgDocumentSchema, type PxAnimationDefinition, PxAnimationDefinitionSchema, type PxAnimatorAPI, type PxAnimatorCallbacksConfig, type PxAnimatorConfig, PxAnimatorConfigSchema, PxAnimatorEngine, PxAnimatorMode, type PxAttrValue, PxAttrValueSchema, type PxBasicAnimatorAPI, type PxBezierPath, PxBezierPathSchema, type PxBinding, PxBindingSchema, type PxCloneEffect, PxCloneEffectSchema, type PxCreateElement, type PxDefs, PxDefsSchema, PxEasingOrRefSchema, type PxEffects, PxEffectsSchema, type PxElementAnimation, PxElementAnimationSchema, type PxFillGradientEffect, PxFillGradientEffectSchema, type PxGlyph, type PxGlyphFont, PxGradientSpreadMethod, type PxGradientStop, PxGradientStopSchema, PxGradientType, PxGradientUnits, type PxInfer, type PxKeyframe, PxKeyframeSchema, PxKeyframeValueSchema, type PxLoop, PxLoopExtend, PxLoopSchema, type PxMaskedByEffect, PxMaskedByEffectSchema, type PxNode, PxNodeBase, PxNodeSchema, type PxPlatformAdapter, type PxPropertyAnimation, PxPropertyAnimationSchema, type PxRepeaterEffect, PxRepeaterEffectSchema, type PxRetimeEffect, PxRetimeEffectSchema, type PxSchema, type PxSchemaDesc, type PxStrokeGradientEffect, PxStrokeGradientEffectSchema, type PxSvgNode, PxSvgNodeExtra, PxTextEffectSchema, type PxTextPathEffect, PxTextPathEffectSchema, type PxTransformByEffect, PxTransformByEffectSchema, type PxTransformPartKey, type PxTransformParts, PxTransformPartsSchema, type PxTransformValue, PxTransformValueSchema, type PxTrigger, PxTriggerSchema, type PxTrimPathEffect, PxTrimPathEffectSchema, PxTrimSubPaths, type PxValidationContext, type PxValidationResult, type RemoveIndex, STYLE_ATTR_NAMES, type StartOn, TEXT_ATTR, TEXT_CONTENT_ATTR, TRANSFORM_FN_NAMES, type Vec2, applyPlayerEffects, bezierToSvgPath, calcAnimationValues, camelCaseToKebabWordIfNeeded, clamp, collectSampleTimes, composeTransformParts, createBasicFrameLoopAnimator, createPathSampler, cubicBezier, deepClone, describeSchema, diffInEffect, evaluateMotionPathSegment, extendedPathForBrowser, generateNewIds, generateUniqueId, getAnimatorConfig, getBindings, getChildren, getDefs, getNormalisedBindings, getNormalizedProps, interpolateBeziers, interpolateValue, isPxElementFileFormat, isPxElementFileFormatDeep, jsonElementFactory, kebabToCamelCaseWord, layoutGlyphTextChars, materialiseAllInTree, materialiseAnimatedUseInstances, materialiseGlyphText, materialiseGlyphTextAlongPath, materialiseGlyphTextHorizontal, materialiseInternalLoopsInPropAnim, materialiseInternalLoopsInTree, materialiseMotionPathInPropAnim, materialiseMotionPathsInTree, propAnimIsMotionPath, px, resolveStyle, reverseEasing, sanitiseAttributeValue, schemaKeys, shiftAnimatable, splitEasing, subdivideCubicBezier, toRGBA, validateNodeEffects, visualModelAt };
package/dist/index.d.ts CHANGED
@@ -17368,8 +17368,8 @@ interface PxNode extends PxInfer<typeof PxNodeBase> {
17368
17368
  * `{ width?:number, height?:number, viewBox?:string, animator?:AnimatorConfig }`
17369
17369
  */
17370
17370
  declare const PxSvgNodeExtra: PxSchema<{} & {
17371
- width?: number | undefined;
17372
- height?: number | undefined;
17371
+ width?: string | number | undefined;
17372
+ height?: string | number | undefined;
17373
17373
  viewBox?: string | undefined;
17374
17374
  animator?: ({} & {
17375
17375
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -17658,8 +17658,8 @@ declare const PxSvgNodeExtra: PxSchema<{} & {
17658
17658
  }) | undefined;
17659
17659
  }, false> & {
17660
17660
  readonly _shape: {
17661
- width: PxSchema<number | undefined, true>;
17662
- height: PxSchema<number | undefined, true>;
17661
+ width: PxSchema<string | number | undefined, true>;
17662
+ height: PxSchema<string | number | undefined, true>;
17663
17663
  viewBox: PxSchema<string | undefined, true>;
17664
17664
  animator: PxSchema<({} & {
17665
17665
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -17967,8 +17967,8 @@ declare const PxAnimatedSvgDocumentSchema: PxSchema<{
17967
17967
  type: "svg";
17968
17968
  } & {
17969
17969
  children?: any[] | undefined;
17970
- width?: number | undefined;
17971
- height?: number | undefined;
17970
+ width?: string | number | undefined;
17971
+ height?: string | number | undefined;
17972
17972
  viewBox?: string | undefined;
17973
17973
  animator?: ({} & {
17974
17974
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -20936,8 +20936,8 @@ declare const PxAnimatedSvgDocumentSchema: PxSchema<{
20936
20936
  readonly _shape: {
20937
20937
  type: PxSchema<"svg", false>;
20938
20938
  children: PxSchema<any[] | undefined, true>;
20939
- width: PxSchema<number | undefined, true>;
20940
- height: PxSchema<number | undefined, true>;
20939
+ width: PxSchema<string | number | undefined, true>;
20940
+ height: PxSchema<string | number | undefined, true>;
20941
20941
  viewBox: PxSchema<string | undefined, true>;
20942
20942
  animator: PxSchema<({} & {
20943
20943
  mode?: "auto" | "waapi" | "frames" | undefined;
@@ -24038,6 +24038,7 @@ declare function reverseEasing(easing: Easing | undefined): Easing | undefined;
24038
24038
  declare function toRGBA(color: Array<number>): string;
24039
24039
  declare const COLOUR_ATTR_NAMES: Set<string>;
24040
24040
  declare const TRANSFORM_FN_NAMES: Set<string>;
24041
+ declare const PCT_BASED_ATTR_NAMES: Set<string>;
24041
24042
  /**
24042
24043
  * Compose a `PxTransformParts` record into a single SVG/CSS transform string in
24043
24044
  * the canonical order:
@@ -24138,6 +24139,23 @@ declare function sanitiseAttributeValue(name: string, value: any): any | undefin
24138
24139
  declare function resolveStyle(style: string | Record<string, string | number> | undefined, defs?: PxDefs): Record<string, string | number> | undefined;
24139
24140
  declare function getNormalizedProps(props: Record<string, any>): Record<string, any>;
24140
24141
 
24142
+ /**
24143
+ * Time separation between a cycle's snap-back keyframe and the previous repetition's
24144
+ * end, in ms.
24145
+ *
24146
+ * SINGLE SOURCE OF TRUTH — the editor imports this and converts to its own frame unit
24147
+ * (`TLoop.smallFrameShift = LOOP_JUMP_SHIFT_MS / FRAME_DURATION_MS`), so the two sides
24148
+ * cannot drift apart and materialise different keyframes (B7).
24149
+ *
24150
+ * 1ms, not one 10ms editor frame: a 10ms snap-back is long enough to read as a visible
24151
+ * jump in a looping animation (confirmed visually). The gap only has to be non-zero — it
24152
+ * exists so the snap-back is a discontinuity rather than an interpolated tween.
24153
+ *
24154
+ * ⚠️ The editor works in FRAMES (`FRAME_DURATION_MS = 10`), so this is a sub-frame shift
24155
+ * there. `TKeyframeGroup` rounds keyframe times to integer frames in some paths; the
24156
+ * editor side keeps the fractional value and must not be re-clamped to a whole frame.
24157
+ */
24158
+ declare const LOOP_JUMP_SHIFT_MS = 1;
24141
24159
  /**
24142
24160
  * Interpolates between two keyframe values based on property type.
24143
24161
  * Returns the raw interpolated value (not a CSS string).
@@ -24468,4 +24486,4 @@ interface EffectDiff {
24468
24486
  */
24469
24487
  declare function diffInEffect(a: VmNode, b: VmNode): Array<EffectDiff>;
24470
24488
 
24471
- export { type ApplyResult, COLOUR_ATTR_NAMES, CSS_ONLY_STYLE_PROPS, DEFAULT_DURATION_MS, DISALLOWED_SVG_TAGS_LOWER, type ExtendPathOpts, type ExtendedPath, type FillMode, type GlyphCharBox, type GlyphCharBoxAlongPath, type GlyphMaterialiseOpts, INTERNAL_ATTRS, type JsMode, type KeysMatch, type MaterialiseAllOptions, type MotionPathMaterialisationOptions, type MotionPathSample, type OutAction, PX_ANIM_ATTR_NAME, PX_ANIM_SRC_ATTR_NAME, PX_TRANSFORM_PART_KEYS, type PathPoint, type PathSampler, type PlaybackDirection, type PxAnimatable, type PxAnimatedSvgDocument, PxAnimatedSvgDocumentSchema, type PxAnimationDefinition, PxAnimationDefinitionSchema, type PxAnimatorAPI, type PxAnimatorCallbacksConfig, type PxAnimatorConfig, PxAnimatorConfigSchema, PxAnimatorEngine, PxAnimatorMode, type PxAttrValue, PxAttrValueSchema, type PxBasicAnimatorAPI, type PxBezierPath, PxBezierPathSchema, type PxBinding, PxBindingSchema, type PxCloneEffect, PxCloneEffectSchema, type PxCreateElement, type PxDefs, PxDefsSchema, PxEasingOrRefSchema, type PxEffects, PxEffectsSchema, type PxElementAnimation, PxElementAnimationSchema, type PxFillGradientEffect, PxFillGradientEffectSchema, type PxGlyph, type PxGlyphFont, PxGradientSpreadMethod, type PxGradientStop, PxGradientStopSchema, PxGradientType, PxGradientUnits, type PxInfer, type PxKeyframe, PxKeyframeSchema, PxKeyframeValueSchema, type PxLoop, PxLoopExtend, PxLoopSchema, type PxMaskedByEffect, PxMaskedByEffectSchema, type PxNode, PxNodeBase, PxNodeSchema, type PxPlatformAdapter, type PxPropertyAnimation, PxPropertyAnimationSchema, type PxRepeaterEffect, PxRepeaterEffectSchema, type PxRetimeEffect, PxRetimeEffectSchema, type PxSchema, type PxSchemaDesc, type PxStrokeGradientEffect, PxStrokeGradientEffectSchema, type PxSvgNode, PxSvgNodeExtra, PxTextEffectSchema, type PxTextPathEffect, PxTextPathEffectSchema, type PxTransformByEffect, PxTransformByEffectSchema, type PxTransformPartKey, type PxTransformParts, PxTransformPartsSchema, type PxTransformValue, PxTransformValueSchema, type PxTrigger, PxTriggerSchema, type PxTrimPathEffect, PxTrimPathEffectSchema, PxTrimSubPaths, type PxValidationContext, type PxValidationResult, type RemoveIndex, STYLE_ATTR_NAMES, type StartOn, TEXT_ATTR, TEXT_CONTENT_ATTR, TRANSFORM_FN_NAMES, type Vec2, applyPlayerEffects, bezierToSvgPath, calcAnimationValues, camelCaseToKebabWordIfNeeded, clamp, collectSampleTimes, composeTransformParts, createBasicFrameLoopAnimator, createPathSampler, cubicBezier, deepClone, describeSchema, diffInEffect, evaluateMotionPathSegment, extendedPathForBrowser, generateNewIds, generateUniqueId, getAnimatorConfig, getBindings, getChildren, getDefs, getNormalisedBindings, getNormalizedProps, interpolateBeziers, interpolateValue, isPxElementFileFormat, isPxElementFileFormatDeep, jsonElementFactory, kebabToCamelCaseWord, layoutGlyphTextChars, materialiseAllInTree, materialiseAnimatedUseInstances, materialiseGlyphText, materialiseGlyphTextAlongPath, materialiseGlyphTextHorizontal, materialiseInternalLoopsInPropAnim, materialiseInternalLoopsInTree, materialiseMotionPathInPropAnim, materialiseMotionPathsInTree, propAnimIsMotionPath, px, resolveStyle, reverseEasing, sanitiseAttributeValue, schemaKeys, shiftAnimatable, splitEasing, subdivideCubicBezier, toRGBA, validateNodeEffects, visualModelAt };
24489
+ export { type ApplyResult, COLOUR_ATTR_NAMES, CSS_ONLY_STYLE_PROPS, DEFAULT_DURATION_MS, DISALLOWED_SVG_TAGS_LOWER, type ExtendPathOpts, type ExtendedPath, type FillMode, type GlyphCharBox, type GlyphCharBoxAlongPath, type GlyphMaterialiseOpts, INTERNAL_ATTRS, type JsMode, type KeysMatch, LOOP_JUMP_SHIFT_MS, type MaterialiseAllOptions, type MotionPathMaterialisationOptions, type MotionPathSample, type OutAction, PCT_BASED_ATTR_NAMES, PX_ANIM_ATTR_NAME, PX_ANIM_SRC_ATTR_NAME, PX_TRANSFORM_PART_KEYS, type PathPoint, type PathSampler, type PlaybackDirection, type PxAnimatable, type PxAnimatedSvgDocument, PxAnimatedSvgDocumentSchema, type PxAnimationDefinition, PxAnimationDefinitionSchema, type PxAnimatorAPI, type PxAnimatorCallbacksConfig, type PxAnimatorConfig, PxAnimatorConfigSchema, PxAnimatorEngine, PxAnimatorMode, type PxAttrValue, PxAttrValueSchema, type PxBasicAnimatorAPI, type PxBezierPath, PxBezierPathSchema, type PxBinding, PxBindingSchema, type PxCloneEffect, PxCloneEffectSchema, type PxCreateElement, type PxDefs, PxDefsSchema, PxEasingOrRefSchema, type PxEffects, PxEffectsSchema, type PxElementAnimation, PxElementAnimationSchema, type PxFillGradientEffect, PxFillGradientEffectSchema, type PxGlyph, type PxGlyphFont, PxGradientSpreadMethod, type PxGradientStop, PxGradientStopSchema, PxGradientType, PxGradientUnits, type PxInfer, type PxKeyframe, PxKeyframeSchema, PxKeyframeValueSchema, type PxLoop, PxLoopExtend, PxLoopSchema, type PxMaskedByEffect, PxMaskedByEffectSchema, type PxNode, PxNodeBase, PxNodeSchema, type PxPlatformAdapter, type PxPropertyAnimation, PxPropertyAnimationSchema, type PxRepeaterEffect, PxRepeaterEffectSchema, type PxRetimeEffect, PxRetimeEffectSchema, type PxSchema, type PxSchemaDesc, type PxStrokeGradientEffect, PxStrokeGradientEffectSchema, type PxSvgNode, PxSvgNodeExtra, PxTextEffectSchema, type PxTextPathEffect, PxTextPathEffectSchema, type PxTransformByEffect, PxTransformByEffectSchema, type PxTransformPartKey, type PxTransformParts, PxTransformPartsSchema, type PxTransformValue, PxTransformValueSchema, type PxTrigger, PxTriggerSchema, type PxTrimPathEffect, PxTrimPathEffectSchema, PxTrimSubPaths, type PxValidationContext, type PxValidationResult, type RemoveIndex, STYLE_ATTR_NAMES, type StartOn, TEXT_ATTR, TEXT_CONTENT_ATTR, TRANSFORM_FN_NAMES, type Vec2, applyPlayerEffects, bezierToSvgPath, calcAnimationValues, camelCaseToKebabWordIfNeeded, clamp, collectSampleTimes, composeTransformParts, createBasicFrameLoopAnimator, createPathSampler, cubicBezier, deepClone, describeSchema, diffInEffect, evaluateMotionPathSegment, extendedPathForBrowser, generateNewIds, generateUniqueId, getAnimatorConfig, getBindings, getChildren, getDefs, getNormalisedBindings, getNormalizedProps, interpolateBeziers, interpolateValue, isPxElementFileFormat, isPxElementFileFormatDeep, jsonElementFactory, kebabToCamelCaseWord, layoutGlyphTextChars, materialiseAllInTree, materialiseAnimatedUseInstances, materialiseGlyphText, materialiseGlyphTextAlongPath, materialiseGlyphTextHorizontal, materialiseInternalLoopsInPropAnim, materialiseInternalLoopsInTree, materialiseMotionPathInPropAnim, materialiseMotionPathsInTree, propAnimIsMotionPath, px, resolveStyle, reverseEasing, sanitiseAttributeValue, schemaKeys, shiftAnimatable, splitEasing, subdivideCubicBezier, toRGBA, validateNodeEffects, visualModelAt };
package/dist/index.js CHANGED
@@ -882,8 +882,10 @@ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._sh
882
882
  children: px.lazy(() => px.array(PxNodeSchema), []).optional()
883
883
  }), PxAttrValueSchema);
884
884
  var PxSvgNodeExtra = px.object({
885
- width: px.number().optional(),
886
- height: px.number().optional(),
885
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
886
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
887
+ width: px.union([px.number(), px.string()]).optional(),
888
+ height: px.union([px.number(), px.string()]).optional(),
887
889
  viewBox: px.string().optional(),
888
890
  animator: PxAnimatorConfigSchema.optional()
889
891
  });
@@ -1926,7 +1928,7 @@ function walkAndMaterialise(node, opts) {
1926
1928
  }
1927
1929
 
1928
1930
  // src/PxDefinitions.ts
1929
- var LOOP_JUMP_SHIFT_MS = 10;
1931
+ var LOOP_JUMP_SHIFT_MS = 1;
1930
1932
  function deepEqualValue(a, b) {
1931
1933
  if (a === b) return true;
1932
1934
  if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
@@ -2175,6 +2177,8 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2175
2177
  const looped = [];
2176
2178
  const separateBoundary = loop.extend !== PxLoopExtend.before;
2177
2179
  const originalTerminalKf = keyframes[keyframes.length - 1];
2180
+ let terminalEasingOverride;
2181
+ let hasTerminalEasingOverride = false;
2178
2182
  function appendRep(repStart, isReversed, partial) {
2179
2183
  var _a2;
2180
2184
  let entries;
@@ -2215,7 +2219,16 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2215
2219
  const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2216
2220
  const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2217
2221
  if (isBoundary) {
2218
- if (deepEqualValue(prevKf.v, entry.v)) continue;
2222
+ if (deepEqualValue(prevKf.v, entry.v)) {
2223
+ if (looped.length > 0) {
2224
+ prevKf.e = entry.e;
2225
+ prevKf.tangentOut = entry.tangentOut;
2226
+ } else {
2227
+ terminalEasingOverride = entry.e;
2228
+ hasTerminalEasingOverride = true;
2229
+ }
2230
+ continue;
2231
+ }
2219
2232
  if (looped.length > 0) {
2220
2233
  delete prevKf.tangentIn;
2221
2234
  delete prevKf.tangentOut;
@@ -2296,6 +2309,11 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2296
2309
  if (loop.extend === PxLoopExtend.before) {
2297
2310
  return [...looped, ...keyframes];
2298
2311
  } else {
2312
+ if (hasTerminalEasingOverride && keyframes.length > 0) {
2313
+ const head = keyframes.slice(0, -1);
2314
+ const tail = __spreadProps(__spreadValues({}, keyframes[keyframes.length - 1]), { e: terminalEasingOverride });
2315
+ return [...head, tail, ...looped];
2316
+ }
2299
2317
  return [...keyframes, ...looped];
2300
2318
  }
2301
2319
  }
@@ -2412,6 +2430,9 @@ function generateElementId() {
2412
2430
  function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2413
2431
  const normalized = {};
2414
2432
  for (const [propName, propAnim] of Object.entries(animDef)) {
2433
+ if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
2434
+ continue;
2435
+ }
2415
2436
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2416
2437
  if (normalizedKfs.length > 0) {
2417
2438
  const out = { kfs: normalizedKfs };
@@ -5253,10 +5274,141 @@ function applyPlayerEffects_retime(node, ctx) {
5253
5274
  return node;
5254
5275
  }
5255
5276
 
5277
+ // src/PxOffsetPathMaterialiser.ts
5278
+ var kfTime = (kf) => {
5279
+ var _a, _b;
5280
+ return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
5281
+ };
5282
+ var kfValue = (kf) => {
5283
+ var _a;
5284
+ return (_a = kf.v) != null ? _a : kf.value;
5285
+ };
5286
+ var kfEasing = (kf) => {
5287
+ var _a;
5288
+ return (_a = kf.e) != null ? _a : kf.easing;
5289
+ };
5290
+ var kfTangentIn = (kf) => {
5291
+ var _a;
5292
+ return (_a = kf.tangentIn) != null ? _a : kf.ti;
5293
+ };
5294
+ var kfTangentOut = (kf) => {
5295
+ var _a;
5296
+ return (_a = kf.tangentOut) != null ? _a : kf.to;
5297
+ };
5298
+ function cubicAt(p0, c1, c2, p1, t) {
5299
+ const u = 1 - t;
5300
+ const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
5301
+ return [
5302
+ a * p0[0] + b * c1[0] + c * c2[0] + d * p1[0],
5303
+ a * p0[1] + b * c1[1] + c * c2[1] + d * p1[1]
5304
+ ];
5305
+ }
5306
+ function cubicLength(p0, c1, c2, p1, steps = 64) {
5307
+ let len = 0;
5308
+ let prev = p0;
5309
+ for (let i = 1; i <= steps; i++) {
5310
+ const pt = cubicAt(p0, c1, c2, p1, i / steps);
5311
+ len += Math.hypot(pt[0] - prev[0], pt[1] - prev[1]);
5312
+ prev = pt;
5313
+ }
5314
+ return len;
5315
+ }
5316
+ var fmt2 = (n) => {
5317
+ const r = Math.round(n * 1e4) / 1e4;
5318
+ return Object.is(r, -0) ? "0" : String(r);
5319
+ };
5320
+ function buildOffsetPath(propAnim) {
5321
+ var _a, _b, _c, _d;
5322
+ if (propAnim.alongPathMode !== "offsetPath") return void 0;
5323
+ const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
5324
+ if (!kfs || kfs.length < 2) return void 0;
5325
+ const first = kfValue(kfs[0]);
5326
+ const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
5327
+ const points = [];
5328
+ for (const kf of kfs) {
5329
+ const v = kfValue(kf);
5330
+ const tr = v == null ? void 0 : v.translate;
5331
+ if (!tr || tr.length < 2) return void 0;
5332
+ const parts = Object.keys(v);
5333
+ if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5334
+ const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
5335
+ if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5336
+ points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5337
+ }
5338
+ if (!kfs.some((kf) => kfTangentIn(kf) || kfTangentOut(kf))) return void 0;
5339
+ let d = "M" + fmt2(points[0][0]) + "," + fmt2(points[0][1]);
5340
+ const segLens = [];
5341
+ for (let i = 0; i < points.length - 1; i++) {
5342
+ const p0 = points[i], p1 = points[i + 1];
5343
+ const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
5344
+ const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
5345
+ const c1 = [p0[0] + to[0], p0[1] + to[1]];
5346
+ const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
5347
+ d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
5348
+ segLens.push(cubicLength(p0, c1, c2, p1));
5349
+ }
5350
+ const total = segLens.reduce((a, b) => a + b, 0);
5351
+ if (!(total > 0)) return void 0;
5352
+ const distanceKfs = [];
5353
+ let cum = 0;
5354
+ for (let i = 0; i < kfs.length; i++) {
5355
+ if (i > 0) cum += segLens[i - 1];
5356
+ const out = { t: kfTime(kfs[i]), v: cum / total };
5357
+ const e = kfEasing(kfs[i]);
5358
+ if (e !== void 0) out.e = e;
5359
+ distanceKfs.push(out);
5360
+ }
5361
+ return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
5362
+ }
5363
+ function materialiseOffsetPathsInTree(root) {
5364
+ const walk = (node) => {
5365
+ var _a;
5366
+ let out = node;
5367
+ const anim = node.animate;
5368
+ const transform = anim == null ? void 0 : anim["transform"];
5369
+ if (transform) {
5370
+ const built = buildOffsetPath(transform);
5371
+ if (built) {
5372
+ const newAnimate = __spreadValues({}, anim);
5373
+ delete newAnimate["transform"];
5374
+ const distance = { keyframes: built.distanceKfs };
5375
+ if (transform.loop !== void 0) distance.loop = transform.loop;
5376
+ newAnimate["offsetDistance"] = distance;
5377
+ const staticTr = node.transform;
5378
+ let newTransform = staticTr;
5379
+ if (staticTr && typeof staticTr === "object") {
5380
+ const t = __spreadValues({}, staticTr);
5381
+ delete t["translate"];
5382
+ delete t["origin"];
5383
+ newTransform = Object.keys(t).length ? t : void 0;
5384
+ }
5385
+ out = __spreadProps(__spreadValues({}, node), {
5386
+ animate: newAnimate,
5387
+ style: __spreadProps(__spreadValues({}, node.style), {
5388
+ offsetPath: "path('" + built.pathStr + "')",
5389
+ offsetAnchor: fmt2(built.anchor[0]) + "px " + fmt2(built.anchor[1]) + "px",
5390
+ offsetRotate: built.autoOrient ? "auto" : "0deg",
5391
+ offsetDistance: "0%"
5392
+ })
5393
+ });
5394
+ if (newTransform !== void 0) out.transform = newTransform;
5395
+ else delete out.transform;
5396
+ }
5397
+ }
5398
+ if ((_a = out.children) == null ? void 0 : _a.length) {
5399
+ const children = out.children.map(walk);
5400
+ if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
5401
+ }
5402
+ return out;
5403
+ };
5404
+ return walk(root);
5405
+ }
5406
+
5256
5407
  // src/PxAnimatorMaterialiseAll.ts
5257
5408
  function materialiseAllInTree(doc, engine, opts) {
5258
5409
  var _a, _b;
5259
5410
  let root = applyPlayerEffects(doc).root;
5411
+ root = materialiseOffsetPathsInTree(root);
5260
5412
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5261
5413
  root = materialiseInternalLoopsInTree(root, duration);
5262
5414
  if (engine === PxAnimatorEngine.waapi) {
@@ -5788,6 +5940,8 @@ export {
5788
5940
  DEFAULT_DURATION_MS,
5789
5941
  DISALLOWED_SVG_TAGS_LOWER,
5790
5942
  INTERNAL_ATTRS,
5943
+ LOOP_JUMP_SHIFT_MS,
5944
+ PCT_BASED_ATTR_NAMES,
5791
5945
  PX_ANIM_ATTR_NAME,
5792
5946
  PX_ANIM_SRC_ATTR_NAME,
5793
5947
  PX_TRANSFORM_PART_KEYS,