@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.
- package/README.md +59 -14
- package/dist/PxDocumentDiagnostic-COGEjBbg.d.cts +10987 -0
- package/dist/PxDocumentDiagnostic-COGEjBbg.d.ts +10987 -0
- package/dist/chunk-7ZO7PQKZ.min.js +1 -0
- package/dist/chunk-L6GJ6Y2M.js +4595 -0
- package/dist/chunk-L6GJ6Y2M.js.map +1 -0
- package/dist/index.cjs +1193 -1978
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -12317
- package/dist/index.d.ts +40 -12317
- package/dist/index.js +469 -5230
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.js +1 -1
- package/dist/internal.cjs +3513 -0
- package/dist/internal.cjs.map +1 -0
- package/dist/internal.d.cts +378 -0
- package/dist/internal.d.ts +378 -0
- package/dist/internal.js +480 -0
- package/dist/internal.js.map +1 -0
- package/dist/internal.min.cjs +1 -0
- package/dist/internal.min.js +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema/PxSchema.ts","../src/version/PxSchemaVersion.ts","../src/version/PxWireVersion.ts","../src/format/PxAnimatorConstants.ts","../src/format/PxAnimatorTypes.ts","../src/util/PxIdUtil.ts","../src/util/PxAnimatorUtil.ts","../src/util/PxNodeProps.ts","../src/materialize/PxMotionPath.ts","../src/animation/PxDefinitions.ts","../src/effects/text/pathSampler.ts","../src/effects/shared/transformParts.ts","../src/util/PxNodeCloneUtil.ts","../src/effects/shared/util.ts","../src/effects/text/textPathEffect.ts","../src/effects/text/elementFactory.ts","../src/effects/text/glyphPathBake.ts","../src/effects/text/textGlyphsEffect.ts","../src/playback/PxDiagnostics.ts","../src/format/PxDocumentDiagnostic.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * Lightweight Zod-like schema system — type declaration + runtime sanitization.\n *\n * Two operations per schema:\n * isValid(raw) — true only when raw already conforms; no repair needed.\n * sanitize(raw) — always returns T; fixes or replaces invalid input with defaults.\n *\n * Field rules inside px.object():\n * required field → if absent/invalid, field's declared default is used.\n * optional field → if absent/invalid (or wrong JS type), field becomes undefined.\n *\n * Array: items that cannot even be attempted are filtered out.\n * Record: values that cannot even be attempted are dropped.\n *\n * The distinction between isValid and _canSanitize:\n * isValid — strict; ALL fields must be correct, no repairs accepted.\n * _canSanitize — permissive; \"is the JS type right enough to attempt repair?\"\n * For containers (object/array/record) this is a structural check\n * so that partially-valid nested objects are sanitized rather than dropped.\n * For primitives it equals isValid (a wrong primitive type is unrecoverable).\n *\n * Validation context (optional):\n * Pass a PxValidationContext as the second arg to isValid() to collect per-field\n * error and warning messages with their dot-paths.\n * e.g. schema.isValid(raw, ctx, []) where ctx = { errors: [], warnings: [] }\n * Path segments are pushed/popped during recursion; join with '.' only when reporting.\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * The reason text a STRICT closed object reports for an undeclared key — `\"<dot.path>: <this>\"`.\n *\n * Exported because it is the one validation finding that carries a MEANING beyond \"invalid\":\n * a key this build does not declare is a key some other build wrote, which is the signal a\n * reader turns into \"written for a newer schema — update your player/editor\". Callers match on\n * this constant rather than on a copy of the sentence.\n * @internal\n */\nexport const PX_UNKNOWN_KEY_ERROR = 'unexpected extra key';\n\n/** Collects structured validation feedback. Pass to isValid() as the second argument. @public @advanced */\nexport interface PxValidationContext {\n /** Per-field errors — each entry is \"<dot.path>: <reason>\". */\n errors: Array<string>;\n /** Per-field warnings — same format as errors but non-fatal. */\n warnings: Array<string>;\n /**\n * When true, closed objects (`px.object` / `px.extendedObject`) report any\n * extra (undeclared) keys as errors. Default `false` (or omitted) — extras\n * are ignored, matching `sanitize`'s strip-extras behavior, which is what\n * production app code wants (forward-compat with unknown future fields).\n * Tests that want to lock the wire shape down to its declared schema\n * should pass `strict: true`.\n *\n * Open objects (`px.openObject`) are unaffected by `strict` — they accept\n * extras by design (used for SVG element nodes that carry arbitrary attrs).\n */\n strict?: boolean;\n}\n\n/** @public @advanced */\nexport interface PxSchema<T, IsOptional extends boolean = false> {\n /** Phantom discriminator — `false` for required schemas, `true` for optional. Used by InferShape. */\n readonly _optional: IsOptional;\n sanitize(raw: unknown): T;\n /**\n * Returns true when raw already conforms to this schema.\n * Pass an optional PxValidationContext to collect per-field error messages.\n * Pass a mutable Array<string> as `path` — segments are pushed/popped during\n * recursion so only a single array allocation is needed per validation call.\n */\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean;\n /** True if raw has the right structure to attempt sanitization (may still need repair). */\n _canSanitize(raw: unknown): boolean;\n readonly _default: T;\n /** Returns a new schema that marks this field as optional (?: in object shapes). */\n optional(): PxSchema<T | undefined, true>;\n}\n\n/** Extract the TypeScript type from a schema. @public @advanced */\nexport type PxInfer<S> = S extends PxSchema<infer T, any> ? T : never;\n\n/**\n * Removes string/number index signatures from T, leaving only explicitly named properties.\n * Useful for strict property-access checking on types that have an open `[key: string]: any`.\n *\n * @example\n * type Strict = PxRemoveIndex<PxAnimatedSvgDocument>;\n * Strict['animator'] // PxAnimatorConfig | undefined ✓\n * Strict['anything'] // compile error ✓\n * @public @advanced\n */\nexport type PxRemoveIndex<T> = {\n [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]\n};\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal path helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n// Joins path segments into a dot-path string for error messages.\n// Segments starting with '[' are appended without a leading dot.\n// e.g. ['obj', 'key'] -> 'obj.key' ['arr', '[0]'] -> 'arr[0]' [] -> '.'\nfunction pathStr(path: Array<string>): string {\n if (!path.length) return '.';\n let result = '';\n for (const seg of path) {\n if (seg.startsWith('[')) result += seg;\n else result += (result ? '.' : '') + seg;\n }\n return result;\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Base — default _canSanitize = isValid (correct for primitives)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Shared base; overrides _canSanitize only when the structural check must differ from isValid. */\nabstract class Base<T, IsOptional extends boolean = false> implements PxSchema<T, IsOptional> {\n // `declare` emits no runtime code; purely satisfies the interface's phantom _optional property.\n declare readonly _optional: IsOptional;\n abstract sanitize(raw: unknown): T;\n abstract isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean;\n abstract readonly _default: T;\n\n _canSanitize(raw: unknown): boolean { return this.isValid(raw); }\n\n optional(): PxSchema<T | undefined, true> { return new Optional(this); }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Optional wrapper\n// Uses _canSanitize (not isValid) so that partially-valid nested objects are\n// repaired rather than dropped entirely.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Wraps any schema to make its value optional.\n * sanitize uses _canSanitize (not isValid) so partially-valid objects are repaired, not dropped.\n */\nclass Optional<T> extends Base<T | undefined, true> {\n readonly _default = undefined as T | undefined;\n constructor(private readonly inner: PxSchema<T, any>) { super(); }\n\n sanitize(raw: unknown): T | undefined {\n if (raw === undefined || raw === null) return undefined;\n return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : undefined;\n }\n\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (raw === undefined || raw === null) return true;\n return this.inner.isValid(raw, ctx, path);\n }\n\n override _canSanitize(raw: unknown): boolean {\n return raw === undefined || raw === null || this.inner._canSanitize(raw);\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Primitives — _canSanitize = isValid (a wrong primitive type is unrecoverable)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** String schema; wrong type is unrecoverable so _canSanitize = isValid (inherited default). */\nclass Str extends Base<string> {\n constructor(readonly _default: string = '') { super(); }\n sanitize(raw: unknown): string { return typeof raw === 'string' ? raw : this._default; }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (typeof raw === 'string') return true;\n ctx?.errors.push(pathStr(path ?? []) + ': expected string, got ' + typeof raw);\n return false;\n }\n}\n\n/** Finite-number schema; rejects NaN and ±Infinity as unrecoverable. */\nclass Num extends Base<number> {\n constructor(readonly _default: number = 0) { super(); }\n sanitize(raw: unknown): number {\n return typeof raw === 'number' && isFinite(raw) ? raw : this._default;\n }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (typeof raw === 'number' && isFinite(raw)) return true;\n ctx?.errors.push(pathStr(path ?? []) + ': expected finite number, got ' + JSON.stringify(raw));\n return false;\n }\n}\n\n/** Boolean schema. */\nclass Bool extends Base<boolean> {\n constructor(readonly _default: boolean = false) { super(); }\n sanitize(raw: unknown): boolean { return typeof raw === 'boolean' ? raw : this._default; }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (typeof raw === 'boolean') return true;\n ctx?.errors.push(pathStr(path ?? []) + ': expected boolean, got ' + typeof raw);\n return false;\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Literal — exact value match; default is the literal itself\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Matches one exact primitive value; its _default is the value itself. */\nclass Literal<T extends string | number | boolean> extends Base<T> {\n readonly _default: T;\n constructor(private readonly value: T) { super(); this._default = value; }\n sanitize(raw: unknown): T { return raw === this.value ? this.value : this._default; }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (raw === this.value) return true;\n ctx?.errors.push(pathStr(path ?? []) + ': expected ' + JSON.stringify(this.value) + ', got ' + JSON.stringify(raw));\n return false;\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Enum — union of string/number literals; default is first value\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Union of string/number literals; _default is the first value unless overridden. */\nclass Enum<T extends string | number> extends Base<T> {\n readonly _default: T;\n constructor(private readonly values: readonly T[], defaultVal?: T) {\n super();\n this._default = defaultVal ?? values[0];\n }\n sanitize(raw: unknown): T { return this.values.includes(raw as T) ? (raw as T) : this._default; }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (this.values.includes(raw as T)) return true;\n ctx?.errors.push(pathStr(path ?? []) + ': expected one of ' + this.values.map(v => JSON.stringify(v)).join(' | ') + ', got ' + JSON.stringify(raw));\n return false;\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Union — first matching schema wins\n// _canSanitize: true if any member can attempt sanitization\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** How many of the best-matching member's errors a failed union appends after its headline\n * (review §2.8). Enough to name the offending key and its neighbours, short of a wall. */\nconst UNION_MEMBER_ERROR_LIMIT = 4;\n\n/** Tries member schemas in order; first whose isValid passes wins. sanitize returns _default when none match. */\nclass Union<T> extends Base<T> {\n /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Union from Tuple. */\n readonly _kind = 'union' as const;\n readonly _default: T;\n constructor(private readonly schemas: ReadonlyArray<PxSchema<T>>, defaultVal?: T) {\n super();\n this._default = defaultVal ?? schemas[0]._default;\n }\n sanitize(raw: unknown): T {\n for (const s of this.schemas) {\n if (s.isValid(raw)) return s.sanitize(raw);\n }\n return this._default;\n }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n // Members see the MODE but NOT the caller's error sink (V6). Two separate\n // things were bundled in `ctx`: passing it whole made every non-matching\n // branch push errors even when a later branch matched; passing nothing at\n // all left `strict` inert inside every union. A scratch ctx carries the\n // flags and swallows the per-branch noise.\n const probe: PxValidationContext | undefined = ctx && { errors: [], warnings: [], strict: ctx.strict };\n if (this.schemas.some(s => s.isValid(raw, probe, path ? [...path] : undefined))) return true;\n if (!ctx) return false;\n\n const base = pathStr(path ?? []);\n ctx.errors.push(base + ': no union member matched for value ' + (JSON.stringify(raw) ?? '').slice(0, 240));\n\n // …then say WHY (review §2.8). The headline alone reads the same for a\n // `keyframes`/`keyframe` typo, for short `t`/`v` keys and for a plain type\n // mismatch, so an entry diagnostic — or an LLM repair loop — got no pointer to\n // the fix. Re-run each member into its OWN sink and report the one that got\n // FURTHEST into the value: the likeliest intended shape.\n //\n // Not every member's errors: the real unions run to 11 alternatives\n // (`PxKeyframeValueSchema`), so a typo inside one object member would arrive\n // buried under ten \"expected string, got object\" lines.\n let best: Array<string> | undefined;\n let bestDepth = -1;\n const leafExpectations: Array<string> = [];\n\n for (const member of this.schemas) {\n const sink: PxValidationContext = { errors: [], warnings: [], strict: ctx.strict };\n member.isValid(raw, sink, path ? [...path] : undefined);\n if (!sink.errors.length) continue; // cannot happen (it failed), but keeps this total\n\n // How far in did it get? Every message is \"<path>: <reason>\", and a member that\n // descended reports at a LONGER path than the union's own.\n const depth = Math.max(...sink.errors.map(e => e.slice(0, e.indexOf(':')).length));\n if (depth > bestDepth || (depth === bestDepth && best && sink.errors.length < best.length)) {\n bestDepth = depth;\n best = sink.errors;\n }\n // A member that stayed at the union's own path is a shape mismatch, not a\n // near-miss: collect just its expectation for the folded line below.\n if (depth <= base.length) {\n for (const e of sink.errors) {\n const m = /: expected (.+?), got /.exec(e);\n if (m && !leafExpectations.includes(m[1])) leafExpectations.push(m[1]);\n }\n }\n }\n\n if (best && bestDepth > base.length) {\n // One member reached inside the value — its errors ARE the diagnosis.\n for (const e of best.slice(0, UNION_MEMBER_ERROR_LIMIT)) {\n if (!ctx.errors.includes(e)) ctx.errors.push(e);\n }\n } else if (leafExpectations.length) {\n // Nothing descended: one line naming every shape this slot accepts.\n ctx.errors.push(base + ': expected ' + leafExpectations.join(' | '));\n }\n return false;\n }\n override _canSanitize(raw: unknown): boolean { return this.schemas.some(s => s._canSanitize(raw)); }\n}\n\n// Infers the union of all member types from a tuple of schemas.\n// Mapped-then-indexed, NOT `T extends ReadonlyArray<PxSchema<infer U>>`: the latter\n// gives TS one inference site for the whole array, so it collapses a heterogeneous\n// union to a single member (in practice the object branch) and the bare statics\n// vanish from the inferred type — `px.union([px.number(), px.object(…)])` typed as\n// the object alone. Per-position inference unions them properly (V6/Q1).\ntype UnionMembers<T extends ReadonlyArray<PxSchema<any, any>>> = {\n [K in keyof T]: T[K] extends PxSchema<infer U, any> ? U : never\n}[number];\n// NOTE: this only works because `px.union` / `px.discriminatedUnion` declare their\n// schema list as `const T` (Q1). Without the modifier TS infers the argument as a\n// plain ARRAY and unifies the element type to one `PxSchema<…>`, so `keyof T` has a\n// single member to map and the union collapses to whichever branch won unification —\n// in practice the last object branch, silently dropping every bare-static member\n// (`px.union([tuple, …, propAnim])` typed as propAnim alone). Source-level checks and\n// the emitted .d.ts both went wrong, so the dist types rejected legal wire values.\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DiscriminatedUnion — routes by a literal key field, not first-match order\n// ─────────────────────────────────────────────────────────────────────────────\n\n// `undefined` admitted: a member may declare its discriminant `.optional()` (see `_absentMember`).\ntype AnyDiscriminantShape<K extends string> = Record<K, PxSchema<string | number | boolean | undefined, any>>;\n\n/**\n * Reads `raw[key]`, finds the member schema whose literal matches that value,\n * then delegates sanitize/isValid to that member. Falls back to the first\n * member for sanitize when no match is found.\n */\nclass DiscriminatedUnion<T> extends Base<T> {\n /** Structural tag read by {@link describeSchema}. */\n readonly _kind = 'discriminatedUnion' as const;\n readonly _default: T;\n private readonly _map: Map<string | number | boolean, PxSchema<T>>;\n /** The member an ABSENT discriminant selects — the one whose discriminant slot is\n * `.optional()` (e.g. `timeline.type` omitted = the time-driven timeline). */\n private readonly _absentMember: PxSchema<T> | undefined;\n\n constructor(\n private readonly _key: string,\n private readonly _schemas: ReadonlyArray<PxSchema<T> & { readonly _shape: AnyDiscriminantShape<string> }>,\n defaultVal?: T\n ) {\n super();\n this._default = defaultVal ?? _schemas[0]._default;\n this._map = new Map();\n for (const s of _schemas) {\n const keySchema = s._shape[_key] as any;\n if (!keySchema) continue;\n // An optional discriminant wraps its literal: map the literal's value, and\n // remember this member as the one to use when the key is missing.\n const literal = keySchema.inner ?? keySchema;\n this._map.set(literal._default, s);\n if (keySchema.inner) this._absentMember = s;\n }\n }\n\n private _findSchema(raw: unknown): PxSchema<T> | undefined {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return undefined;\n const val = (raw as Record<string, unknown>)[this._key];\n if (val === undefined || val === null) return this._absentMember;\n return this._map.get(val as string | number | boolean);\n }\n\n sanitize(raw: unknown): T {\n return (this._findSchema(raw) ?? this._schemas[0]).sanitize(raw);\n }\n\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n const schema = this._findSchema(raw);\n if (!schema) {\n const val = (raw !== null && typeof raw === 'object' && !Array.isArray(raw))\n ? (raw as Record<string, unknown>)[this._key] : undefined;\n ctx?.errors.push(pathStr(path ?? []) + ': no discriminated union member matched '\n + this._key + '=' + JSON.stringify(val));\n return false;\n }\n return schema.isValid(raw, ctx, path);\n }\n\n override _canSanitize(raw: unknown): boolean {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return false;\n const schema = this._findSchema(raw);\n return schema ? schema._canSanitize(raw) : this._schemas[0]._canSanitize(raw);\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Object — strips unknown keys; required fields use default, optional → undefined\n// _canSanitize: true when raw is a plain (non-array) object\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AnyShape = Record<string, PxSchema<any, any>>;\n\n// Required keys: IsOptional=false → plain property.\n// Optional keys: IsOptional=true → ?:, with Exclude<T,undefined> (?: already adds undefined).\ntype InferShape<S extends AnyShape> =\n { [K in keyof S as S[K] extends PxSchema<any, true> ? never : K]: PxInfer<S[K]> } &\n { [K in keyof S as S[K] extends PxSchema<any, true> ? K : never]?: Exclude<PxInfer<S[K]>, undefined> };\n\n/**\n * Typed object schema; strips unknown keys, repairs required fields via their defaults.\n * _canSanitize checks structure only (non-array object) so partially-valid objects are repaired.\n */\nclass Obj<S extends AnyShape> extends Base<InferShape<S>> {\n readonly _default: InferShape<S>;\n\n constructor(readonly _shape: S) {\n super();\n const d: any = {};\n for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;\n this._default = d;\n }\n\n sanitize(raw: unknown): InferShape<S> {\n const src = (raw && typeof raw === 'object' && !Array.isArray(raw)) ? raw as any : {};\n const out: any = {};\n for (const key of Object.keys(this._shape)) {\n const v = this._shape[key].sanitize(src[key]);\n // An OPTIONAL key that was absent sanitizes to `undefined`. Writing it anyway\n // produced a \"phantom\" own key — invisible to JSON, but NOT to `Object.keys`,\n // and consumers branch on that: `PxOffsetPathMaterializer` bails when a transform\n // carries keys beyond translate/origin, so phantoms silently disabled the CSS\n // Motion Path path, and `contentRefSplit` emitted `transform=\"\"`. Measured across\n // 135 real documents: 16,367 phantoms, changing the render of 10 of them.\n if (v !== undefined) out[key] = v;\n }\n return out;\n }\n\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n ctx?.errors.push(pathStr(path ?? []) + ': expected object, got ' + (Array.isArray(raw) ? 'array' : typeof raw));\n return false;\n }\n const obj = raw as any;\n const p = path ?? [];\n let ok = true;\n for (const key of Object.keys(this._shape)) {\n p.push(key);\n if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;\n p.pop();\n }\n // Strict mode: closed objects reject extra (undeclared) keys.\n // Default mode silently ignores them (matching `sanitize`'s strip-extras).\n if (ctx?.strict) {\n for (const key of Object.keys(obj)) {\n if (key in this._shape) continue;\n // An undefined-valued key is indistinguishable from an absent one for\n // every consumer, and JSON.stringify drops it — strict judges the\n // DOCUMENT, not the in-memory object that produced it (V6). Without\n // this, validating a freshly-built (pre-serialization) object flags\n // phantom keys that cannot exist on the wire.\n if (obj[key] === undefined) continue;\n p.push(key);\n ctx.errors.push(pathStr(p) + ': ' + PX_UNKNOWN_KEY_ERROR);\n p.pop();\n ok = false;\n }\n }\n return ok;\n }\n\n override _canSanitize(raw: unknown): boolean {\n return !!raw && typeof raw === 'object' && !Array.isArray(raw);\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OpenObj — like Obj but passes unknown keys through unchanged (or validates/sanitizes\n// them against an optional open-value schema).\n// Known keys are validated/sanitized; unknown keys are passed through as-is when no\n// open schema is given, or validated/sanitized against the open schema when one is provided.\n// Inferred type: InferShape<S> & { [key: string]: V } where V defaults to any.\n// Note: TypeScript intersection semantics mean named-property access on the\n// derived type yields `any` rather than the specific declared type. For\n// type-precise access keep a hand-written interface alongside the schema.\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype InferOpenShape<S extends AnyShape, _V = any> = InferShape<S> & { [key: string]: any };\n\n/**\n * Open object schema; validates/repairs known keys, passes unknown keys through unchanged.\n * Use when the object may carry arbitrary extra properties (e.g. SVG element attributes).\n *\n * @param shape Known key schemas (validated and type-inferred).\n * @param openSchema Optional schema applied to every unknown key's value.\n * When omitted, unknown values are passed through as-is (`any`).\n */\nclass OpenObj<S extends AnyShape, V = any> extends Base<InferOpenShape<S, V>> {\n readonly _default: InferOpenShape<S, V>;\n\n constructor(readonly _shape: S, private readonly _openSchema?: PxSchema<V>) {\n super();\n const d: any = {};\n for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;\n this._default = d;\n }\n\n sanitize(raw: unknown): InferOpenShape<S, V> {\n const src: Record<string, unknown> = (raw && typeof raw === 'object' && !Array.isArray(raw))\n ? raw as Record<string, unknown>\n : {};\n const out: Record<string, unknown> = { ...src };\n for (const key of Object.keys(this._shape)) {\n const v = this._shape[key].sanitize(src[key]);\n if (v !== undefined) out[key] = v; // no phantom keys — see Obj.sanitize\n }\n if (this._openSchema) {\n for (const key of Object.keys(src)) {\n if (!(key in this._shape)) out[key] = this._openSchema.sanitize(src[key]);\n }\n }\n return out as InferOpenShape<S, V>;\n }\n\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n ctx?.errors.push(pathStr(path ?? []) + ': expected object, got ' + (Array.isArray(raw) ? 'array' : typeof raw));\n return false;\n }\n const obj = raw as any;\n const p = path ?? [];\n let ok = true;\n for (const key of Object.keys(this._shape)) {\n p.push(key);\n if (!this._shape[key].isValid(obj[key], ctx, p)) ok = false;\n p.pop();\n }\n if (this._openSchema) {\n for (const key of Object.keys(obj)) {\n if (key in this._shape) continue;\n p.push(key);\n if (!this._openSchema.isValid(obj[key], ctx, p)) ok = false;\n p.pop();\n }\n }\n return ok;\n }\n\n override _canSanitize(raw: unknown): boolean {\n return !!raw && typeof raw === 'object' && !Array.isArray(raw);\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Array — items that cannot be attempted are filtered out; default is []\n// Uses _canSanitize for filtering so partially-valid objects are repaired, not dropped.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Array schema; items failing _canSanitize are filtered out rather than blocking the whole array. */\nclass Arr<T> extends Base<Array<T>> {\n readonly _default: Array<T> = [];\n constructor(private readonly item: PxSchema<T>) { super(); }\n\n sanitize(raw: unknown): Array<T> {\n if (!Array.isArray(raw)) return [];\n const out: Array<T> = [];\n for (const el of raw) {\n if (this.item._canSanitize(el)) out.push(this.item.sanitize(el));\n }\n return out;\n }\n\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (!Array.isArray(raw)) {\n ctx?.errors.push(pathStr(path ?? []) + ': expected array, got ' + typeof raw);\n return false;\n }\n const p = path ?? [];\n let ok = true;\n for (let i = 0; i < raw.length; i++) {\n p.push('[' + i + ']');\n if (!this.item.isValid(raw[i], ctx, p)) ok = false;\n p.pop();\n }\n return ok;\n }\n\n override _canSanitize(raw: unknown): boolean { return Array.isArray(raw); }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Record — invalid values are dropped; default is {}\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** String-keyed record; values failing _canSanitize are dropped rather than blocking the whole record. */\nclass Rec<T> extends Base<Record<string, T>> {\n /** Structural tag read by {@link describeSchema}. */\n readonly _kind = 'record' as const;\n readonly _default: Record<string, T> = {};\n constructor(private readonly value: PxSchema<T>) { super(); }\n\n sanitize(raw: unknown): Record<string, T> {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};\n const out: Record<string, T> = {};\n for (const [k, v] of Object.entries(raw)) {\n if (this.value._canSanitize(v)) out[k] = this.value.sanitize(v);\n }\n return out;\n }\n\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n ctx?.errors.push(pathStr(path ?? []) + ': expected object/record, got ' + (Array.isArray(raw) ? 'array' : typeof raw));\n return false;\n }\n const p = path ?? [];\n let ok = true;\n for (const [k, v] of Object.entries(raw as object)) {\n p.push(k);\n if (!this.value.isValid(v, ctx, p)) ok = false;\n p.pop();\n }\n return ok;\n }\n\n override _canSanitize(raw: unknown): boolean {\n return !!raw && typeof raw === 'object' && !Array.isArray(raw);\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Any — passes raw through unchanged, always valid\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Passes any value through unchanged; always valid. Useful for opaque blobs with no schema. */\nclass Any extends Base<any> {\n readonly _default: any = undefined;\n sanitize(raw: unknown): any { return raw; }\n isValid(_raw: unknown, _ctx?: PxValidationContext, _path?: Array<string>): boolean { return true; }\n override _canSanitize(_raw: unknown): boolean { return true; }\n}\n\n\n/**\n * Like {@link Any} but REQUIRES the value to be present: anything except `undefined`.\n *\n * Use it for a key whose type is open but whose PRESENCE is what identifies the\n * shape — e.g. the structured-static branch `{value: …}` (V6). With `px.any()`\n * there, the branch matched EVERY object, because `any` accepts `undefined` and\n * an absent key is indistinguishable from one holding `undefined`.\n */\nclass Defined extends Base<any> {\n readonly _default: any = undefined;\n sanitize(raw: unknown): any { return raw; }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (raw !== undefined) return true;\n ctx?.errors.push(pathStr(path ?? []) + ': required value is missing');\n return false;\n }\n override _canSanitize(raw: unknown): boolean { return raw !== undefined; }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Lazy — resolves schema on first use, required for recursive types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Defers schema resolution to first use; required to break circular references in recursive types. */\nclass Lazy<T> extends Base<T> {\n private resolved: PxSchema<T> | null = null;\n constructor(private readonly fn: () => PxSchema<T>, readonly _default: T) { super(); }\n\n private get schema(): PxSchema<T> {\n return this.resolved ?? (this.resolved = this.fn());\n }\n\n sanitize(raw: unknown): T { return this.schema.sanitize(raw); }\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean { return this.schema.isValid(raw, ctx, path); }\n override _canSanitize(raw: unknown): boolean { return this.schema._canSanitize(raw); }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Tuple — fixed-length array with per-position schemas; default is defaults of each position\n// _canSanitize: true only when raw is an array of the exact expected length\n// ─────────────────────────────────────────────────────────────────────────────\n\n// Maps a tuple of schemas to a tuple of their inferred types.\ntype TupleItems<T extends ReadonlyArray<PxSchema<any, any>>> =\n { -readonly [K in keyof T]: T[K] extends PxSchema<infer U, any> ? U : never };\n\n/** Fixed-length array schema; validates element count and each position individually. */\nclass Tuple<T extends ReadonlyArray<PxSchema<any, any>>> extends Base<TupleItems<T>> {\n /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Tuple from Union. */\n readonly _kind = 'tuple' as const;\n readonly _default: TupleItems<T>;\n\n constructor(private readonly schemas: T) {\n super();\n this._default = schemas.map(s => s._default) as unknown as TupleItems<T>;\n }\n\n sanitize(raw: unknown): TupleItems<T> {\n if (!Array.isArray(raw) || raw.length !== this.schemas.length) return this._default;\n return this.schemas.map((s, i) => s.sanitize((raw as unknown[])[i])) as unknown as TupleItems<T>;\n }\n\n isValid(raw: unknown, ctx?: PxValidationContext, path?: Array<string>): boolean {\n if (!Array.isArray(raw) || raw.length !== this.schemas.length) {\n ctx?.errors.push(pathStr(path ?? []) + ': expected tuple of length ' + this.schemas.length + ', got ' + (Array.isArray(raw) ? 'array[' + (raw as unknown[]).length + ']' : typeof raw));\n return false;\n }\n const p = path ?? [];\n let ok = true;\n for (let i = 0; i < this.schemas.length; i++) {\n p.push('[' + i + ']');\n if (!(this.schemas as ReadonlyArray<PxSchema<any, any>>)[i].isValid((raw as unknown[])[i], ctx, p)) ok = false;\n p.pop();\n }\n return ok;\n }\n\n // Require exact length so wrong-length arrays are dropped rather than repaired to default.\n override _canSanitize(raw: unknown): boolean {\n return Array.isArray(raw) && raw.length === this.schemas.length;\n }\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// implementsInterface — compile-time lock between a schema and an interface\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Returns a pass-through wrapper that enforces at compile time that the schema's\n * inferred type is structurally assignable to `T`. Catches type mismatches on\n * required fields and value-type mismatches on optional fields.\n *\n * For key-level equality (catching optional field renames), pair with a\n * `KeysMatch` assertion after the inferred type alias:\n * ```ts\n * const _ck: KeysMatch<PxFoo, _PxFoo> = true;\n * ```\n *\n * @example\n * export const PxLoopSchema = implementsInterface<_PxLoop>()(px.object({ ... }));\n */\nexport function implementsInterface<T>() {\n return <S extends PxSchema<T>>(schema: S): S => schema;\n}\n\n/**\n * Evaluates to `true` when A and B have exactly the same set of keys; `false` otherwise.\n * Use with a `const` assertion to get a compile-time error on key renames:\n * ```ts\n * const _ck: KeysMatch<PxFoo, _PxFoo> = true;\n * ```\n * @public @advanced\n */\nexport type KeysMatch<A, B> =\n [Exclude<keyof A, keyof B>] extends [never]\n ? [Exclude<keyof B, keyof A>] extends [never] ? true : false\n : false;\n\n/**\n * Builds a `{ key: 'key', ... }` object from a schema's shape.\n * Each value is typed as the literal key name, so `schemaKeys(PxFooSchema).bar`\n * is typed as `'bar'` — use in @serializable calls to get a compile-time error\n * if the field is renamed in the schema.\n * @public @advanced\n */\nexport function schemaKeys<S extends { readonly _shape: Record<string, any> }>(schema: S) {\n return Object.fromEntries(\n Object.keys(schema['_shape']).map(k => [k, k])\n ) as { [K in keyof S['_shape']]: K };\n}\n\n/**\n * Describes the structural kind of a schema for traversal purposes.\n * Use with `getMissingCoveragePaths` or similar tree-walking utilities.\n *\n * Every composite kind is reported, so a walker can reach EVERY field a document\n * may legally carry — that is what makes schema-coverage checking possible\n * (see the app's `collectSchemaFieldUniverse`).\n *\n * - `shape` — object schema (Obj/OpenObj); `shape` maps key → sub-schema.\n * `openValue` is set for open objects: the schema unknown keys\n * are validated against (undefined ⇒ unknown keys pass through as-is)\n * - `array` — array schema; `item` is the element schema\n * - `optional` — optional wrapper; `inner` is the wrapped schema\n * - `lazy` — lazy/recursive schema; `resolved` is the resolved schema (cached)\n * - `union` — `px.union`; `members` are the alternatives, tried in order\n * - `discriminatedUnion`— `px.discriminatedUnion`; `key` is the discriminant field and\n * `members` the alternatives (each an object schema with a literal at `key`)\n * - `record` — `px.record`; `value` is the schema every entry's value must match\n * - `tuple` — `px.tuple`; `items` are the positional element schemas\n * - `leaf` — primitive, literal, enum, any — no traversable children\n * @public @advanced\n */\nexport type PxSchemaDesc =\n | { kind: 'shape'; shape: Record<string, PxSchema<any, any>>; openValue?: PxSchema<any, any> }\n | { kind: 'array'; item: PxSchema<any, any> }\n | { kind: 'optional'; inner: PxSchema<any, any> }\n | { kind: 'lazy'; resolved: PxSchema<any, any> }\n | { kind: 'union'; members: ReadonlyArray<PxSchema<any, any>> }\n | { kind: 'discriminatedUnion'; key: string; members: ReadonlyArray<PxSchema<any, any>> }\n | { kind: 'record'; value: PxSchema<any, any> }\n | { kind: 'tuple'; items: ReadonlyArray<PxSchema<any, any>> }\n | { kind: 'leaf' };\n\n/** @public @advanced */\nexport function describeSchema(schema: PxSchema<any, any>): PxSchemaDesc {\n const s = schema as any;\n // `_kind` is set only by the classes that are otherwise indistinguishable by\n // duck-typing (Union vs Tuple both carry `schemas`), so it is checked first.\n switch (s._kind) {\n case 'union': return { kind: 'union', members: s.schemas };\n case 'discriminatedUnion': return { kind: 'discriminatedUnion', key: s._key, members: s._schemas };\n case 'record': return { kind: 'record', value: s.value };\n case 'tuple': return { kind: 'tuple', items: s.schemas };\n }\n if ('_shape' in s) return { kind: 'shape', shape: s._shape, openValue: s._openSchema };\n if ('item' in s) return { kind: 'array', item: s.item };\n if ('inner' in s) return { kind: 'optional', inner: s.inner };\n // `??=` (not `??`): an unresolved lazy would otherwise build a FRESH schema on\n // every call, so two traversals could never agree on schema identity.\n if ('fn' in s) return { kind: 'lazy', resolved: (s.resolved ??= s.fn()) };\n return { kind: 'leaf' };\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public factory\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @public @advanced */\nexport const px = {\n /** Matches a string. Default: '' or provided value. */\n string: (defaultVal = ''): PxSchema<string> => new Str(defaultVal),\n\n /** Matches a finite number. Default: 0 or provided value. */\n number: (defaultVal = 0): PxSchema<number> => new Num(defaultVal),\n\n /** Matches a boolean. Default: false or provided value. */\n boolean: (defaultVal = false): PxSchema<boolean> => new Bool(defaultVal),\n\n /** Matches one exact primitive value; its default is the value itself. */\n literal: <T extends string | number | boolean>(value: T): PxSchema<T> =>\n new Literal(value),\n\n /** Matches one of a fixed set of string/number values. Default: first value. */\n enum: <T extends string | number>(values: readonly T[], defaultVal?: T): PxSchema<T> =>\n new Enum(values, defaultVal),\n\n /**\n * Returns the first schema whose isValid passes.\n * TypeScript infers the union of all member types automatically.\n */\n union: <const T extends ReadonlyArray<PxSchema<any, any>>>(\n schemas: T,\n defaultVal?: UnionMembers<T>\n ): PxSchema<UnionMembers<T>> =>\n new Union(schemas as any, defaultVal) as any,\n\n /**\n * Discriminated union — reads `raw[key]`, finds the member schema whose\n * literal at `key` matches, then delegates sanitize/isValid to that member.\n * Each member must be an object schema with a `px.literal(...)` at `key`.\n * TypeScript infers the union of all member types automatically.\n */\n discriminatedUnion: <\n K extends string,\n const T extends ReadonlyArray<PxSchema<any, any> & { readonly _shape: AnyDiscriminantShape<K> }>\n >(key: K, schemas: T): PxSchema<UnionMembers<T>> =>\n new DiscriminatedUnion(key, schemas as any) as any,\n\n /** Typed object — unknown keys are stripped. Required fields fall back to their default. */\n object: <S extends AnyShape>(shape: S): PxSchema<InferShape<S>> & { readonly _shape: S } =>\n new Obj(shape),\n\n /**\n * Open object — validates known keys; passes unknown keys through as-is,\n * or validates/sanitizes them against `openSchema` when provided.\n */\n openObject: <S extends AnyShape, V = any>(\n shape: S,\n openSchema?: PxSchema<V>\n ): PxSchema<InferOpenShape<S, V>> & { readonly _shape: S } =>\n new OpenObj(shape, openSchema) as any,\n\n /**\n * Creates a new closed object schema by merging a base schema's shape with additional fields.\n * The base can be the result of px.object() or px.openObject() — anything with a _shape property.\n *\n * @example\n * const PxSvgNodeSchema = px.extendedObject(PxNodeBaseSchema, { width: px.number().optional() });\n */\n extendedObject: <B extends AnyShape, E extends AnyShape>(\n base: { readonly _shape: B },\n extra: E\n ): PxSchema<InferShape<B & E>> & { readonly _shape: B & E } =>\n new Obj({ ...base._shape, ...extra } as B & E),\n\n /** Array whose unrecoverable items are filtered out. Default: []. */\n array: <T>(item: PxSchema<T>): PxSchema<Array<T>> =>\n new Arr(item),\n\n /** String-keyed record whose unrecoverable values are dropped. Default: {}. */\n record: <T>(value: PxSchema<T>): PxSchema<Record<string, T>> =>\n new Rec(value),\n\n /** Passes anything through unchanged — always valid. */\n any: (): PxSchema<any> => new Any(),\n\n /** Anything EXCEPT `undefined` — an open type whose presence is required (V6). */\n defined: (): PxSchema<any> => new Defined(),\n\n /** Fixed-length tuple — validates element count and each position individually. */\n tuple: <T extends ReadonlyArray<PxSchema<any, any>>>(schemas: T): PxSchema<TupleItems<T>> =>\n new Tuple(schemas),\n\n /** Defers schema creation — required for recursive types. Must supply a default value. */\n lazy: <T>(fn: () => PxSchema<T>, defaultVal: T): PxSchema<T> =>\n new Lazy(fn, defaultVal),\n} as const;\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n// The player's schema version, alone in its own file: a bump is a one-line diff that nothing\n// else rides along with. It must stay import-free (the pre-rendered builds load it).\n// How and when to bump it: dev-docs/versioning.md.\n\n/**\n * THE PLAYER'S WIRE SCHEMA VERSION — the `a.b` of `svgRoot.animator.version`.\n *\n * `a` a generation; no conversion bridges one to another.\n * `b` a revision within the generation. THIS player reads any file at `a.[b' <= b]`.\n *\n * A document may carry a third part (`a.b.c`) — the EDITOR's extension revision, covering\n * everything under `meta.*`. The player neither reads nor compares it.\n *\n * NOT the library's npm version, and never derived from it: the library ships far more often\n * than the format changes, so tying the two would make every release look like a format change\n * and every format change invisible between releases.\n * @public @advanced\n */\nexport const PX_WIRE_SCHEMA_VERSION = '1.1';\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n// ============================================================================\n// WIRE FORMAT VERSION + THE PLAYER'S CONVERSIONS — `svgRoot.animator.version`, `\"a.b[.c]\"`.\n//\n// a.b THE PLAYER SCHEMA. A reader at `a.b` reads any file at `a.[b' <= b]`, converting\n// it forward through the steps below. `a` is a generation nothing bridges.\n// c the EDITOR's extension, covering `meta.*` only. The player neither reads nor\n// compares it, and no step here may touch `meta.*`.\n//\n// WHY THIS LIVES IN THE LIBRARY, not the editor: the player ships standalone. A viewer opening\n// a file has no editor to repair it first, so the code that understands the version and moves a\n// document forward has to travel with the player. The editor then EXTENDS this — its own fixer\n// runs `convertWireDocument` first and only afterwards touches `meta.*`:\n//\n// editorFixer(json) { json = convertWireDocument(json).doc; /* then meta.* steps */ }\n//\n// THE VERSION IS A DIAGNOSTIC, NOT A GATE. A gap on its own means nothing and must never warn:\n// a bump says the SCHEMA gained something, not that THIS document uses it. A 1.5 file using no\n// post-1.1 feature plays correctly and silently in a 1.1 player. The number is consulted in\n// exactly two situations — a conversion needs it, or unknown content was actually met, where it\n// turns \"something is wrong\" into \"written for 1.5, this player reads 1.1; update the player\".\n//\n// ABSENT means UNKNOWN, never \"the oldest\": nothing is assumed and nothing is migrated on a guess.\n// ============================================================================\n\nimport { PX_WIRE_SCHEMA_VERSION } from './PxSchemaVersion';\n\n/** The wire key, under the animator config block. @public @advanced */\nexport const PX_WIRE_VERSION_KEY = 'version';\n\nconst ANIMATOR_KEY = 'animator';\nconst META_KEY = 'meta';\n\n/** Parsed form. Compare these, NEVER the strings: `\"1.10\" < \"1.9\"` lexically. @public @advanced */\nexport interface PxWireVersion {\n /** Generation. A change no conversion can bridge. */\n readonly a: number;\n /** Player schema revision within the generation. */\n readonly b: number;\n /** Editor extension revision, scoped to `(a,b)`. The player ignores it. */\n readonly c: number;\n}\n\n/** How a file's version relates to a reader's. @public @advanced */\nexport enum PxWireVersionRelation {\n /** No stamp — unknown provenance. Assume nothing, migrate nothing. */\n unstamped = 'unstamped',\n same = 'same',\n /** The file predates this reader. Any conversion its content needs may be applied. */\n older = 'older',\n /** The file is from a later build. Only meaningful once unknown content is actually met. */\n newer = 'newer',\n /** A different generation — no conversion path exists in either direction. */\n otherGeneration = 'otherGeneration',\n}\n\nconst VERSION_RE = /^(\\d+)\\.(\\d+)(?:\\.(\\d+))?$/;\n\n/** `\"1.2.3\"` → `{a:1,b:2,c:3}`; a missing `c` is baseline 0. `undefined` when unparseable —\n * treated exactly like an absent stamp, never as an error. * @public @advanced\n */\nexport function parseWireVersion(raw: unknown): PxWireVersion | undefined {\n if (typeof raw !== 'string') return undefined;\n const m = VERSION_RE.exec(raw.trim());\n if (!m) return undefined;\n return { a: Number(m[1]), b: Number(m[2]), c: m[3] === undefined ? 0 : Number(m[3]) };\n}\n\n/** @public @advanced */\nexport function formatWireVersion(v: PxWireVersion): string {\n return v.a + '.' + v.b + '.' + v.c;\n}\n\n/** The version this PLAYER implements, parsed. `c` is 0: the player has no editor extension. @public @advanced */\nexport const PX_WIRE_VERSION: PxWireVersion =\n parseWireVersion(PX_WIRE_SCHEMA_VERSION) ?? { a: 1, b: 1, c: 0 };\n\n/** The animator config block, at either of its two wire addresses: lifted to the top level in\n * the lightweight JSON, carried under `meta` in a pre-rendered SVG. */\nfunction getAnimatorBlock(doc: unknown): { [key: string]: unknown } | undefined {\n if (!doc || typeof doc !== 'object') return undefined;\n const atRoot = readObjectProp(doc, ANIMATOR_KEY);\n if (atRoot) return atRoot;\n const meta = readObjectProp(doc, META_KEY);\n return meta ? readObjectProp(meta, ANIMATOR_KEY) : undefined;\n}\n\nfunction readObjectProp(obj: object, key: string): { [key: string]: unknown } | undefined {\n const value = (obj as { [k: string]: unknown })[key];\n return value && typeof value === 'object' && !Array.isArray(value)\n ? value as { [key: string]: unknown }\n : undefined;\n}\n\n/** The version stamped on a document, or `undefined` when it carries none. @public @advanced */\nexport function readWireVersion(doc: unknown): PxWireVersion | undefined {\n const animator = getAnimatorBlock(doc);\n return animator ? parseWireVersion(animator[PX_WIRE_VERSION_KEY]) : undefined;\n}\n\n/**\n * How `file` relates to `mine`. `readerReadsEditorPart` separates the two readers: the EDITOR\n * compares all three parts, the PLAYER compares only `a.b` and is blind to `c`.\n * @public @advanced\n */\nexport function compareWireVersion(\n file: PxWireVersion | undefined, mine: PxWireVersion, readerReadsEditorPart: boolean,\n): PxWireVersionRelation {\n if (!file) return PxWireVersionRelation.unstamped;\n if (file.a !== mine.a) return PxWireVersionRelation.otherGeneration;\n if (file.b !== mine.b) return file.b > mine.b ? PxWireVersionRelation.newer : PxWireVersionRelation.older;\n if (!readerReadsEditorPart || file.c === mine.c) return PxWireVersionRelation.same;\n return file.c > mine.c ? PxWireVersionRelation.newer : PxWireVersionRelation.older;\n}\n\n/**\n * What to TELL the user about a version gap — and only ever alongside unknown content actually\n * met. `undefined` means the version explains nothing, so nothing is said.\n *\n * Every gap has one of exactly two remedies: upgrade the file, or upgrade the reader. Neither is\n * a refusal — the reader has already dropped what it could not understand and the rest renders,\n * so the worst case is a document missing a feature plus a sentence saying how to close the gap.\n * @public @advanced\n */\nexport function wireVersionAdvice(\n relation: PxWireVersionRelation, file: PxWireVersion | undefined, mine: PxWireVersion, isPlayer: boolean,\n): string | undefined {\n if (!file) return undefined;\n const target = isPlayer ? 'player' : 'editor';\n const gap = 'written for schema ' + formatWireVersion(file)\n + ', this ' + target + ' reads ' + formatWireVersion(mine);\n switch (relation) {\n case PxWireVersionRelation.newer:\n return 'This file is ' + gap + '. Update the ' + target + ' to open it fully.';\n case PxWireVersionRelation.older:\n // The unknown part is a spelling the format has since dropped, so the FILE is what\n // moves. Re-saving from this build rewrites it in the current spelling.\n return 'This file is ' + gap + '. Saving it from this ' + target\n + ' rewrites it in the current format.';\n case PxWireVersionRelation.otherGeneration:\n // No conversion path exists in either direction — so both remedies are named and the\n // user picks. Still not a refusal: what could be read has been.\n return 'This file is ' + gap + ' \\u2014 a different format generation, which no conversion bridges.'\n + ' Open it in a ' + target\n + ' of that generation, or accept this document without the parts named above.';\n default:\n // `same` and `unstamped`: the version accounts for nothing here.\n return undefined;\n }\n}\n\n\n// ═══════════════════════════════════════════════════════════\n// THE STEP TABLE\n// ═══════════════════════════════════════════════════════════\n\n/** What a step DOES to documents — and therefore whether it needs conversion code. @public @advanced */\nexport enum PxWireStepKind {\n /**\n * Only OPTIONAL fields were added. An older reader ignores them; a newer reader finds them\n * absent and defaults. Nothing to convert either way — but it must still be DECLARED, so\n * that \"no converter\" is a decision on the record rather than an omission.\n */\n additive = 'additive',\n /** A shape or spelling changed. `up` is then mandatory; `down` where it is possible at all. */\n converted = 'converted',\n}\n\n/** One `b` step of the player schema. @public @advanced */\nexport interface PxWireVersionStep {\n /** The version this step converts FROM, e.g. `'1.1'`. */\n readonly from: string;\n /** …and TO. Must be the `from` of the next step, so the table is one unbroken chain. */\n readonly to: string;\n /** Why the format moved — the sentence a future reader needs, not a commit hash. */\n readonly reason: string;\n readonly kind: PxWireStepKind;\n /**\n * Older → newer, MUTATING the document in place. Required for {@link PxWireStepKind.converted}.\n * It may not touch `meta.*`: that subtree is the editor's, and its steps are the `c` part.\n */\n readonly up?: (doc: Record<string, unknown>) => void;\n /** Newer → older. Absent means the step is one-way and down-conversion refuses. */\n readonly down?: (doc: Record<string, unknown>) => void;\n}\n\n/** Where the chain starts: the first RELEASED player schema. Everything older is pre-release. @public @advanced */\nexport const PX_WIRE_BASELINE_VERSION = '1.1';\n\n/**\n * Every `b` step from {@link PX_WIRE_BASELINE_VERSION} to {@link PX_WIRE_SCHEMA_VERSION}.\n *\n * EMPTY IS CORRECT TODAY: 1.1 is the baseline and nothing has moved since. It exists now because\n * the guard spec keys off it — bump `PX_WIRE_SCHEMA_VERSION` without adding the matching step\n * and the suite fails naming the gap. That is the whole point: the last three renames shipped\n * because nothing forced anyone to say they had happened.\n * @public @advanced\n */\nexport const PX_WIRE_STEPS: ReadonlyArray<PxWireVersionStep> = [];\n\n\n/** What a conversion pass did, so a caller can report it. @public @advanced */\nexport interface PxWireConversionResult {\n /**\n * The document to read. A converted COPY when steps applied, otherwise the input itself,\n * unchanged and identical by reference — the caller's object is never mutated, so a failed\n * or partial conversion can never leave a half-migrated document behind.\n */\n readonly doc: unknown;\n /** The version found on the file, if any. */\n readonly from: PxWireVersion | undefined;\n readonly relation: PxWireVersionRelation;\n /** The steps actually applied, oldest first. Empty when nothing was needed. */\n readonly applied: ReadonlyArray<PxWireVersionStep>;\n /** Set only when the version could not be honored — never a refusal to render. */\n readonly advice?: string;\n}\n\n/** Which table to run, and what to bring the document up TO. @public @advanced */\nexport interface PxWireConversionOptions {\n /** The step table — the player's, or the editor's `meta.*` one. */\n readonly steps: ReadonlyArray<PxWireVersionStep>;\n /** The version the document should end up at. */\n readonly target: PxWireVersion;\n /** `true` for the EDITOR (compares and stamps `c`), `false` for the PLAYER (blind to it). */\n readonly readerReadsEditorPart: boolean;\n}\n\n/**\n * THE STEP ENGINE — one implementation, two tables.\n *\n * The player runs it over `PX_WIRE_STEPS`; the editor runs it a second time over its own\n * `meta.*` table, on the document the player pass returned. Keeping it one function is what\n * stops the two halves from drifting into two different ideas of what conversion means.\n *\n * It NEVER refuses and never throws:\n * · unstamped → nothing is assumed, nothing is converted; the file is read as it is.\n * · newer / other generation → no step exists, so nothing is applied; `advice` says which way\n * to close the gap, and the caller renders whatever the schema could keep.\n * · older → the due steps run on a COPY. A step with no `up` is skipped; a step that\n * throws stops the chain, and the ORIGINAL comes back rather than a half-\n * converted one.\n * @public @advanced\n */\nexport function applyWireSteps(doc: unknown, cfg: PxWireConversionOptions): PxWireConversionResult {\n const from = readWireVersion(doc);\n const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);\n if (!from || relation !== PxWireVersionRelation.older) {\n return {\n doc, from, relation, applied: [],\n advice: wireVersionAdvice(relation, from, cfg.target, !cfg.readerReadsEditorPart),\n };\n }\n\n // Which steps this document actually needs, decided BEFORE anything is copied so the common\n // \"older but nothing to do\" case costs nothing. A step is due when the FILE is older than\n // what that step produces — the same comparison the reader itself uses.\n const due: Array<PxWireVersionStep> = [];\n for (const step of cfg.steps) {\n const stepTo = parseWireVersion(step.to);\n if (!stepTo) continue;\n if (compareWireVersion(from, stepTo, cfg.readerReadsEditorPart) !== PxWireVersionRelation.older) continue;\n if (!step.up) continue; // additive, or one-way with no code\n due.push(step);\n }\n if (!due.length || !doc || typeof doc !== 'object') return { doc, from, relation, applied: [] };\n\n // Work on a COPY: a step that throws mid-way must not leave the caller's document\n // half-migrated, and callers routinely hold the parsed file for other purposes.\n const target = clonePlain(doc) as Record<string, unknown>;\n const applied: Array<PxWireVersionStep> = [];\n for (const step of due) {\n // One bad step degrades to \"that step did not happen\" — never to a failed open.\n try {\n step.up!(target);\n applied.push(step);\n } catch {\n break; // stop at the first failure: later steps assume this one ran\n }\n }\n if (!applied.length) return { doc, from, relation, applied: [] };\n // The document now speaks the target schema, so it says so.\n stampVersion(target, cfg.target, cfg.readerReadsEditorPart);\n return { doc: target, from, relation, applied };\n}\n\n/**\n * BRING A DOCUMENT UP TO THIS PLAYER'S SCHEMA — the `playerFixer` half of the pair.\n * Runs {@link applyWireSteps} over {@link PX_WIRE_STEPS}, touching nothing under `meta.*`.\n * @public @advanced\n */\nexport function convertWireDocument(doc: unknown): PxWireConversionResult {\n return applyWireSteps(doc, {\n steps: PX_WIRE_STEPS, target: PX_WIRE_VERSION, readerReadsEditorPart: false,\n });\n}\n\n/** A structural copy of a parsed JSON document. `structuredClone` where the runtime has it\n * (every browser the player targets, and Node 17+), else a JSON round trip — the input is\n * parsed wire data either way, so both are lossless for it. */\nfunction clonePlain<T>(value: T): T {\n const structured = (globalThis as { structuredClone?: (v: unknown) => unknown }).structuredClone;\n return structured ? structured(value) as T : JSON.parse(JSON.stringify(value)) as T;\n}\n\n/**\n * Re-stamp a converted document with the version it now conforms to.\n *\n * A PLAYER pass moves `a.b` and PRESERVES the file's `c`: it did not touch `meta.*`, so it has\n * no business claiming the editor's extension moved with it. An EDITOR pass stamps all three.\n */\nfunction stampVersion(doc: Record<string, unknown>, target: PxWireVersion, readerReadsEditorPart: boolean): void {\n const animator = getAnimatorBlock(doc);\n if (!animator) return;\n const previous = parseWireVersion(animator[PX_WIRE_VERSION_KEY]);\n animator[PX_WIRE_VERSION_KEY] = formatWireVersion({\n a: target.a, b: target.b,\n c: readerReadsEditorPart ? target.c : (previous ? previous.c : 0),\n });\n}\n\n\n// ═══════════════════════════════════════════════════════════\n// DOWN-CONVERSION (task 6.7)\n// ═══════════════════════════════════════════════════════════\n\n/**\n * What an EXPLICIT down-conversion did. Unlike reading, this may refuse — it is an output the\n * user asked for (\"save for an older player\"), and handing back a file that silently lacks what\n * the older schema cannot say would be worse than saying no.\n * @public @advanced\n */\nexport type PxWireDowngradeResult =\n | { readonly ok: true; readonly doc: unknown; readonly applied: ReadonlyArray<PxWireVersionStep> }\n | { readonly ok: false; readonly reason: string; readonly blocking: ReadonlyArray<PxWireVersionStep> };\n\n/** Which table to walk BACK through, from the version the document is at to the one wanted. @public @advanced */\nexport interface PxWireDowngradeOptions {\n readonly steps: ReadonlyArray<PxWireVersionStep>;\n /** The version the document must end up at. */\n readonly target: PxWireVersion;\n /** `true` for the editor table (`c` steps), `false` for the player table (`b` steps). */\n readonly readerReadsEditorPart: boolean;\n}\n\n/**\n * BRING A DOCUMENT DOWN TO AN OLDER SCHEMA — only when EVERY step in between can be undone.\n *\n * All or nothing: if even one step on the way back has no `down` (the shape rework never will —\n * its old shell had one clock and cannot express per-parameter animation), the whole request is\n * refused and the reason names those steps. A partial downgrade is never produced, and the\n * caller's document is never mutated — the work happens on a copy.\n * @public @advanced\n */\nexport function applyWireStepsDown(doc: unknown, cfg: PxWireDowngradeOptions): PxWireDowngradeResult {\n const from = readWireVersion(doc);\n if (!from) {\n return { ok: false, blocking: [], reason: 'The document carries no version, so there is nothing to convert down from.' };\n }\n const relation = compareWireVersion(from, cfg.target, cfg.readerReadsEditorPart);\n if (relation === PxWireVersionRelation.otherGeneration) {\n return {\n ok: false, blocking: [],\n reason: 'Schema ' + formatWireVersion(from) + ' and ' + formatWireVersion(cfg.target)\n + ' are different generations; no conversion bridges them.',\n };\n }\n // Already at (or older than) the target: nothing to undo.\n if (relation !== PxWireVersionRelation.newer) return { ok: true, doc, applied: [] };\n\n // Every step whose RESULT is newer than the target must be undone, newest first.\n const toUndo: Array<PxWireVersionStep> = [];\n for (const step of cfg.steps) {\n const stepTo = parseWireVersion(step.to);\n if (!stepTo) continue;\n if (compareWireVersion(stepTo, cfg.target, cfg.readerReadsEditorPart) !== PxWireVersionRelation.newer) continue;\n if (compareWireVersion(stepTo, from, cfg.readerReadsEditorPart) === PxWireVersionRelation.newer) continue;\n toUndo.push(step);\n }\n toUndo.reverse();\n\n // Additive steps need no `down`: an older reader simply ignores what they added.\n const blocking = toUndo.filter(s => s.kind === PxWireStepKind.converted && !s.down);\n if (blocking.length) {\n return {\n ok: false, blocking,\n reason: 'Cannot convert down to ' + formatWireVersion(cfg.target) + ': '\n + blocking.map(s => s.from + ' → ' + s.to + ' (' + s.reason + ')').join('; ')\n + ' cannot be undone.',\n };\n }\n\n const target = clonePlain(doc) as Record<string, unknown>;\n const applied: Array<PxWireVersionStep> = [];\n for (const step of toUndo) {\n if (!step.down) continue; // additive\n try {\n step.down(target);\n applied.push(step);\n } catch (e) {\n // Output path: a half-downgraded file is exactly what this function exists to avoid.\n return {\n ok: false, blocking: [step],\n reason: 'Undoing ' + step.from + ' → ' + step.to + ' failed: ' + String(e),\n };\n }\n }\n stampVersion(target, cfg.target, cfg.readerReadsEditorPart);\n return { ok: true, doc: target, applied };\n}\n\n/** Down-convert through the PLAYER table only — `meta.*` is untouched, as on the way up. @public @advanced */\nexport function downgradeWireDocument(doc: unknown, target: PxWireVersion): PxWireDowngradeResult {\n return applyWireStepsDown(doc, { steps: PX_WIRE_STEPS, target, readerReadsEditorPart: false });\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n// ============================================================================\n// Wire CONSTANTS and schema-free helpers.\n//\n// Split out of `PxAnimatorTypes` so that code needing only an enum does not drag the\n// SCHEMA ENGINE in with it. `PxAnimatorTypes` builds ~31 schema declarations at module\n// scope through curried `implementsInterface<T>()(px.object(...))` calls, which no\n// minifier can treat as side-effect-free — so a single value import from it pulls in\n// `PxSchema` plus every declaration.\n//\n// That is exactly what happened: `PxDefinitions` imported `PxLoopExtend` (one small const)\n// and the pre-rendered player builds ended up carrying 14 KB of validation code they never\n// call. See dev-docs/plans/prerendered-player-builds.md.\n//\n// RULE: nothing in this file may import a VALUE from `PxAnimatorTypes`. Type-only imports\n// are fine — they are erased at build time and cannot create a runtime edge.\n// ============================================================================\n\nimport type { PxAnimatedSvgDocument, PxAnimatorConfig, PxBinding, PxDefinitions, PxNode, PxScroll, PxTrigger } from './PxAnimatorTypes';\n\n// ── WIRE ENUMS (review §2.7) ────────────────────────────────────────────────\n// ONE shape for every enumerated wire value: an exported `Px*` const namespace plus the\n// string type derived from it, so a call site can write `PxFillMode.forwards` and the\n// schema can reference the same members instead of repeating bare literals.\n//\n// NOT a TypeScript `enum`: these are WIRE values, and a document is authored as plain\n// JSON — `{ fill: 'forwards' }`. A string `enum` is nominal, so that literal would not\n// typecheck without importing the enum; the derived union accepts both spellings. It is\n// also the only form that composes (`PxTimelineEngineSetting` spreads `PxTimelineEngine`)\n// and that survives erasable-syntax / type-stripping builds.\n\n/** WAAPI `fill` — which values apply outside the active period. @public */\nexport const PxFillMode = {\n forwards: 'forwards',\n backwards: 'backwards',\n both: 'both',\n none: 'none',\n} as const;\n\nexport type PxFillMode = typeof PxFillMode[keyof typeof PxFillMode];\n\n/** WAAPI `direction` — which way each iteration runs. @public */\nexport const PxPlaybackDirection = {\n normal: 'normal',\n reverse: 'reverse',\n alternate: 'alternate',\n alternateReverse: 'alternate-reverse',\n} as const;\n\nexport type PxPlaybackDirection = typeof PxPlaybackDirection[keyof typeof PxPlaybackDirection];\n\n\n/** @internal */\nexport const PX_ANIM_SRC_ATTR_NAME = 'data-px-animation-src';\n\n/** @internal */\nexport const PX_ANIM_ATTR_NAME = '_px_animator';\n\n/** `trigger.startOn` — what starts the animation. `programmatic` waits for `play()`. @public */\nexport const PxStartOn = {\n load: 'load',\n mouseOver: 'mouseOver',\n click: 'click',\n scrollIntoView: 'scrollIntoView',\n programmatic: 'programmatic',\n} as const;\n\nexport type PxStartOn = typeof PxStartOn[keyof typeof PxStartOn];\n\n/** `trigger.outAction` — what happens when the trigger condition stops holding. @public */\nexport const PxOutAction = {\n continue: 'continue',\n pause: 'pause',\n reset: 'reset',\n reverse: 'reverse',\n} as const;\n\nexport type PxOutAction = typeof PxOutAction[keyof typeof PxOutAction];\n\n/** `trigger.finishAction` — what happens after a NATURAL finish. @public */\nexport const PxFinishAction = {\n hold: 'hold',\n reset: 'reset',\n} as const;\n\nexport type PxFinishAction = typeof PxFinishAction[keyof typeof PxFinishAction];\n\n/** `scroll.kind` — which scroll-driven timeline member this is: the subject's journey\n * through the scrollport (`view`), or the scroll container's own offset (`scroll`). * @public\n */\nexport const PxScrollKind = {\n view: 'view',\n scroll: 'scroll',\n} as const;\n\nexport type PxScrollKind = typeof PxScrollKind[keyof typeof PxScrollKind];\n\n/** `timeline.axis` — which axis of the scroll container drives progress. @public */\nexport const PxScrollAxis = {\n block: 'block',\n inline: 'inline',\n x: 'x',\n y: 'y',\n} as const;\n\nexport type PxScrollAxis = typeof PxScrollAxis[keyof typeof PxScrollAxis];\n\n/** `timeline.source` (`scroll` kind) — which scroll container is measured. @public */\nexport const PxScrollSource = {\n nearest: 'nearest',\n root: 'root',\n} as const;\n\nexport type PxScrollSource = typeof PxScrollSource[keyof typeof PxScrollSource];\n\n/** `timeline.pin.align` — where the pinned canvas is held in the scrollport. @public */\nexport const PxPinAlign = {\n top: 'top',\n center: 'center',\n bottom: 'bottom',\n} as const;\n\nexport type PxPinAlign = typeof PxPinAlign[keyof typeof PxPinAlign];\n\n/** The subject's journey phases across the scrollport (see scroll-timeline.design.md §4\n * for the exact `u`-space intervals each phase maps to). * @public\n */\nexport const PxScrollPhase = {\n cover: 'cover',\n contain: 'contain',\n entry: 'entry',\n exit: 'exit',\n entryCrossing: 'entry-crossing',\n exitCrossing: 'exit-crossing',\n} as const;\n\nexport type PxScrollPhase = typeof PxScrollPhase[keyof typeof PxScrollPhase];\n\n/** `alongPathMode` — how a value is sampled along a motion path. @public */\nexport const PxAlongPathMode = {\n sampled: 'sampled',\n offsetPath: 'offsetPath',\n} as const;\n\nexport type PxAlongPathMode = typeof PxAlongPathMode[keyof typeof PxAlongPathMode];\n\n/** WIRE `timeline.engine` — who runs the animation. `auto` (default) prefers the\n * platform's animation API and falls back to JS when the document needs something it\n * cannot express; `native` DEMANDS that API (WAAPI — and, for scroll/view timelines,\n * the browser's ScrollTimeline) with no fallback; `js` pins the player's own frame loop\n * and its own progress measurement. Const-namespace + matching string type so call\n * sites use named members (`PxTimelineEngineSetting.js`), not bare literals.\n *\n * NAMED `engine`, not `mode`: it selects HOW the animated attributes get updated, not\n * WHAT you see — an implementation preference. (`native` is the one value that can also\n * change the outcome: being a demand, an attribute WAAPI declines simply does not\n * animate. See `isNativeForced`.) */\n/** Timeline keys that BOTH union members carry, so they survive a change of `type`. */\nexport const PX_TIMELINE_SHARED_KEYS = ['duration', 'iterations', 'engine', 'frameRate'] as const;\n\n/** Timeline keys that exist ONLY on the time-driven member — a scroll/view timeline is\n * scrubbed by position, so nothing starts it and nothing delays it. */\nexport const PX_TIME_ONLY_TIMELINE_KEYS = ['trigger', 'delay', 'fillMode', 'direction'] as const;\n\n/**\n * The flat RUNTIME-VIEW keys — `duration`, `trigger`, `scroll`, … at the animator ROOT.\n *\n * They are the internal view the engines consume, never a wire spelling: on the wire playback\n * lives inside `timeline`. `getAnimatorConfig` drops them from a document, so a stray one is an\n * unknown key the diagnostic reports rather than a second spelling that quietly plays.\n */\nexport const PX_FLAT_RUNTIME_VIEW_KEYS: ReadonlyArray<string> = [\n ...PX_TIMELINE_SHARED_KEYS, ...PX_TIME_ONLY_TIMELINE_KEYS,\n 'fill', 'resetOnFinish', 'timelineSource', 'scroll',\n];\n\n/**\n * THE ENGINES — the two things that can actually update an animated attribute: hand it to the\n * platform's animation API (`native`), or write it from the player's own frame loop (`js`).\n *\n * This is the CORE set. Code that always knows which engine is running takes this (e.g.\n * `normalizeBindings`'s `engine` arg gates motion-along-path materialization).\n * @public\n */\nexport const PxTimelineEngine = {\n native: 'native',\n js: 'js',\n} as const;\n\nexport type PxTimelineEngine = typeof PxTimelineEngine[keyof typeof PxTimelineEngine];\n\n/**\n * What `timeline.engine` ACCEPTS on the wire: the engines above plus `auto` — \"you pick\", which\n * prefers `native` and falls back to `js` per document when the platform API declines an\n * attribute.\n *\n * Built by ADDING to the core set rather than subtracting from a wider one, so the two cannot\n * drift: every engine is automatically an accepted value, and `auto` is visibly the one extra.\n * @public\n */\nexport const PxTimelineEngineSetting = {\n ...PxTimelineEngine,\n auto: 'auto',\n} as const;\n\nexport type PxTimelineEngineSetting = typeof PxTimelineEngineSetting[keyof typeof PxTimelineEngineSetting];\n\n/** What a requested engine resolves to BEFORE the runtime probes support: `js` pins the frame\n * loop, anything else starts at `native`. NOTE this is only the STARTING point — `auto` still\n * falls back to `js` per document when the platform API declines an attribute, which happens at\n * bind time (see `PxAnimatorBind`), not here. * @public @advanced\n */\nexport function resolveTimelineEngine(engine: PxTimelineEngineSetting | undefined): PxTimelineEngine {\n return engine === PxTimelineEngineSetting.js ? PxTimelineEngine.js : PxTimelineEngine.native;\n}\n\n/** `native` is a demand, not a preference: no JS fallback when the platform API declines an attribute. @public @advanced */\nexport function isNativeForced(engine: PxTimelineEngineSetting | undefined): boolean {\n return engine === PxTimelineEngineSetting.native;\n}\n\n/** May the browser's ScrollTimeline/ViewTimeline drive a scroll/view timeline?\n * `auto` tries it first (falling back to the player's own measurement), `native`\n * asks for it, `js` never uses it. * @public @advanced\n */\nexport function mayUseNativeScrollTimeline(engine: PxTimelineEngineSetting | undefined): boolean {\n return engine !== PxTimelineEngineSetting.js;\n}\n\n/**\n * THE TRIGGER DEFAULTS — what a missing `trigger` field means. One table, declared by\n * `PxTriggerSchema` and applied by {@link resolveTrigger}, which every player calls (the web's\n * `setupAnimationTriggers`, the React Native component) — so a file behaves the same everywhere:\n * - `startOn` 'load' — a document is designed to play\n * - `outAction` 'continue' — leaving the trigger does not interrupt playback\n * - `scrollIntoViewThreshold` 0 — any visible pixel counts\n * @public @advanced\n */\nexport const PX_TRIGGER_DEFAULTS = {\n startOn: 'load',\n outAction: 'continue',\n scrollIntoViewThreshold: 0,\n} as const;\n\n/** A trigger with every default filled in. @public @advanced */\nexport interface PxResolvedTrigger {\n readonly startOn: NonNullable<PxTrigger['startOn']>;\n readonly outAction: NonNullable<PxTrigger['outAction']>;\n readonly scrollIntoViewThreshold: number;\n}\n\n// ── CONTROL MODE (API review §1 / §7) ────────────────────────────────────────\n// Which set of props drives playback. Every component picked its own order, so\n// `autoplay` + `progress={0.5}` played on React and Vue but seeked on React Native, and\n// React let a REF choose the mode — `<PixodeskSvgAnimator autoplay apiRef={api} />` never\n// started, because the imperative branch forced `startOn: 'programmatic'`.\n//\n// One order, decided once, used by react / vue / rn. This module owns the LOGIC and the\n// WARNING TEXT only; each component keeps its own `console.warn` wiring.\n\n/** Which props drive playback. `apiRef` is deliberately NOT a mode: the handle is filled in\n * every mode, so passing it alone leaves the document's own trigger in charge. * @public\n */\nexport const PxControlMode = {\n /** No control props — the document's trigger decides, and nothing is taken over. */\n static: 'static',\n /** `progress` / `time` — the host scrubs; the component seeks and stays paused. */\n fixedTime: 'fixedTime',\n /** `play` / `pause` — the host drives playback with booleans. */\n play: 'play',\n /** `autoplay` — the document's own trigger starts it. */\n autoplay: 'autoplay',\n} as const;\n\nexport type PxControlMode = typeof PxControlMode[keyof typeof PxControlMode];\n\n/**\n * The control props every framework component takes. `resolveControlMode` reads only WHICH\n * are set; the components read the values. ONE definition (review §9) — React and React\n * Native extend it, so the hover text below is what their users see.\n * @public\n */\nexport interface PxControlProps {\n /**\n * Show the frame at this position in the whole timeline (duration × iterations): `0` the\n * first frame, `1` the last — of ONE iteration when `iterations` is `'infinite'`, since an\n * endless run has no whole to be a fraction of. Wins over every other control prop.\n */\n progress?: number;\n /** Show the frame at this time, ms from the start of the whole run. Wins like `progress`. */\n time?: number;\n /** `true` plays now, whatever the document's trigger says; `false` holds where it is. */\n play?: boolean;\n /** Hold the current frame; set it back to `false` to resume. */\n pause?: boolean;\n /** Start the way the document says — its own `startOn` / `outAction` trigger. */\n autoplay?: boolean;\n}\n\n/** The chosen mode plus any conflict warnings — ready-made sentences, so three components\n * cannot word the same conflict three ways. * @public\n */\nexport interface PxResolvedControlMode {\n readonly mode: PxControlMode;\n readonly warnings: ReadonlyArray<string>;\n}\n\n/**\n * Picks the control mode from the props a component was given.\n *\n * PRECEDENCE, most specific first:\n * 1. `progress` / `time` — an explicit position is the most precise instruction there is\n * 2. `play` / `pause` — explicit playback state\n * 3. `autoplay` — defer to the document's trigger\n * 4. otherwise `static` — the document's trigger, with nothing taken over\n *\n * `apiRef` is absent on purpose. A ref is a handle, not an instruction: it is populated in\n * every mode, so `autoplay` + `apiRef` autostarts AND gives you the handle.\n *\n * A warning is produced only when props from two different tiers are set together — the\n * lower tier is then ignored, and silence about that is what made this hard to debug.\n * @public\n */\nexport function resolveControlMode(props: PxControlProps): PxResolvedControlMode {\n const hasFixedTime = props.progress !== undefined || props.time !== undefined;\n const hasPlayPause = props.play !== undefined || props.pause !== undefined;\n const hasAutoplay = !!props.autoplay;\n\n const warnings: Array<string> = [];\n const named = (a: string, b: string, winner: string): string =>\n a + ' and ' + b + ' were both set — ' + winner + ' wins, ' + (winner === a ? b : a) + ' is ignored.';\n\n if (hasFixedTime) {\n if (hasPlayPause) warnings.push(named('progress/time', 'play/pause', 'progress/time'));\n if (hasAutoplay) warnings.push(named('progress/time', 'autoplay', 'progress/time'));\n return { mode: PxControlMode.fixedTime, warnings };\n }\n if (hasPlayPause) {\n if (hasAutoplay) warnings.push(named('play/pause', 'autoplay', 'play/pause'));\n return { mode: PxControlMode.play, warnings };\n }\n if (hasAutoplay) return { mode: PxControlMode.autoplay, warnings };\n return { mode: PxControlMode.static, warnings };\n}\n\n/**\n * True when the component must take the document's trigger over, by forcing\n * `startOn: 'programmatic'` into its config patch.\n *\n * Every mode except `autoplay` — INCLUDING `static`. A component given no control props at all\n * must not start on its own: `<PixodeskSvgAnimator doc={…} />` renders the first frame and waits.\n * `autoplay` is the one mode that says \"let the document's trigger decide\".\n * @public\n */\nexport function controlModeTakesOverTrigger(mode: PxControlMode): boolean {\n return mode !== PxControlMode.autoplay;\n}\n\n/** A document's trigger with the defaults filled in. (`finishAction` is not a start/stop decision:\n * it reaches the engines as the runtime view's `resetOnFinish`.) * @public @advanced\n */\nexport function resolveTrigger(trigger: PxTrigger | undefined): PxResolvedTrigger {\n return {\n startOn: trigger?.startOn ?? PX_TRIGGER_DEFAULTS.startOn,\n outAction: trigger?.outAction ?? PX_TRIGGER_DEFAULTS.outAction,\n scrollIntoViewThreshold: trigger?.scrollIntoViewThreshold ?? PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold,\n };\n}\n\n// V3 — every closed value list is a NAMED const + a strict `px.enum` slot, so a\n// typo is a schema ERROR instead of silently shipping. Plain `px.string()` stays\n// ONLY where SVG itself is open-ended (`gradientTransform`, `viewBox`, `path` d,\n// ids/refs, `debugGlobalName`).\n\n/** `loop.repeatAt` — WHICH END of the keyframe sequence the repeated segment is taken\n * from, and therefore which side of the timeline the repetition fills. A named\n * two-way selector (not a boolean) so a third value stays possible. * @public\n */\nexport const PxLoopRepeatAt = {\n /** Segment from the START; the repetition runs BEFORE the first keyframe\n * (intro loops that play until the main timeline begins). */\n start: 'start',\n /** DEFAULT — segment from the END; the repetition runs AFTER the last keyframe\n * (idle/outro loops that continue once the main timeline has finished). */\n end: 'end',\n} as const;\n\nexport type PxLoopRepeatAt = typeof PxLoopRepeatAt[keyof typeof PxLoopRepeatAt];\n\n/** `loop.direction` — how successive repetitions play, spelled like the timeline's\n * own `direction` so the two read as one idea. * @public\n */\nexport const PxLoopDirection = {\n /** DEFAULT — cycle: every repetition replays the segment the same way round. */\n normal: 'normal',\n /** Ping-pong: repetitions alternate forward / backward. */\n alternate: 'alternate',\n} as const;\n\nexport type PxLoopDirection = typeof PxLoopDirection[keyof typeof PxLoopDirection];\n\n/** SVG `mask-type` — how the mask source's pixels become alpha. @public */\nexport const PxMaskType = {\n luminance: 'luminance',\n alpha: 'alpha',\n} as const;\n\nexport type PxMaskType = typeof PxMaskType[keyof typeof PxMaskType];\n\n/** SVG coordinate system for `maskUnits` / `maskContentUnits` (and the gradient twin below). @public */\nexport const PxUnits = {\n userSpaceOnUse: 'userSpaceOnUse',\n objectBoundingBox: 'objectBoundingBox',\n} as const;\n\nexport type PxUnits = typeof PxUnits[keyof typeof PxUnits];\n\n/** `clone.without` — which part of the SOURCE'S OWN transform a `<use>` clone leaves\n * out. Absent = the whole element, as SVG `<use>` (a direct link, moves with the source);\n * `translate` = the source's placement is dropped, so the clone stays where the `<use>` put\n * it but still rotates/scales with the source. A future value `transform` may drop the\n * whole transform (content only) — not implemented yet.\n * (Was `clone.type: 'content'`; the wire is subtractive because the mechanism is a\n * ladder — the `<use>` can only point at one wrapper layer of the source.)\n * Old doc line:\n * `content` excludes the target's own translate (see `contentRefSplit`). * @public\n */\nexport const PxCloneWithout = {\n translate: 'translate',\n // transform: 'transform', // future: drop rotate/scale too (content only)\n} as const;\n\nexport type PxCloneWithout = typeof PxCloneWithout[keyof typeof PxCloneWithout];\n\n/** `textPath.pathOverflow` — glyphs past the path end: hide them, or keep laying\n * them along the tangent extension. * @public\n */\nexport const PxPathOverflow = {\n clip: 'clip',\n extend: 'extend',\n} as const;\n\nexport type PxPathOverflow = typeof PxPathOverflow[keyof typeof PxPathOverflow];\n\n/** SVG `lengthAdjust` — what `textLength` stretches. @public */\nexport const PxLengthAdjust = {\n spacing: 'spacing',\n spacingAndGlyphs: 'spacingAndGlyphs',\n} as const;\n\nexport type PxLengthAdjust = typeof PxLengthAdjust[keyof typeof PxLengthAdjust];\n\n/** SVG `<textPath method>` — how glyphs follow curvature. @public */\nexport const PxTextPathMethod = {\n align: 'align',\n stretch: 'stretch',\n} as const;\n\nexport type PxTextPathMethod = typeof PxTextPathMethod[keyof typeof PxTextPathMethod];\n\n/** SVG `<textPath spacing>` — whether the renderer may adjust spacing. @public */\nexport const PxTextPathSpacing = {\n auto: 'auto',\n exact: 'exact',\n} as const;\n\nexport type PxTextPathSpacing = typeof PxTextPathSpacing[keyof typeof PxTextPathSpacing];\n\n/** `strokeTrim.subPaths` — what the 0..1 `range`/`offset` window is measured over.\n * `separate` (default): each sub-path against its OWN length, all trimmed alike.\n * `combined`: every descendant sub-path chained end-to-end into one virtual path,\n * so the window slides across siblings (AE \"Trim All As One\"). * @public\n */\nexport const PxStrokeTrimSubPaths = {\n separate: 'separate',\n combined: 'combined',\n} as const;\n\nexport type PxStrokeTrimSubPaths = typeof PxStrokeTrimSubPaths[keyof typeof PxStrokeTrimSubPaths];\n\n\n// S8: `textContent` is the ONE text-content key (the DOM property name). `text` is not a wire\n// key: it was triply overloaded (the `text` tag, the `effects.text` group, and a content alias)\n// and no reader accepts it.\n/** @internal */\nexport const PX_TEXT_CONTENT_ATTR = 'textContent';\n\n/** The DOM `class` attribute. A name we EMIT but do not own, so it is written through this\n * constant rather than as an identifier — every other emitted attribute name reaches the\n * DOM as a string, and `class` was the one exception, which is why the minifier renamed it\n * to `ct` in the shipped bundles (dev-docs/plans/minification-boundary.md §1.1). */\nexport const CLASS_ATTR = 'class';\n\n/** The DOM `transform` attribute, and the key the animation record uses for it. Both are\n * DATA names — a dictionary key, not a field of one of our typed structures — so they are\n * written as constants rather than as identifiers. */\nexport const TRANSFORM_ATTR = 'transform';\n\n/** `animate.offsetDistance` — the CSS Motion Path channel the offset-path materializer writes. */\nexport const OFFSET_DISTANCE_ATTR = 'offsetDistance';\n\n// Wire keys that are NEVER DOM attributes (internal use only).\n//\n// `effects` is here for safety rather than necessity: `materializeNodeEffects` deletes it at\n// load, so today nothing reaches the renderer with it still attached. That is a property\n// of the pipeline, though, not of the contract — an effect path that returns early, or a\n// document carrying an effect key the pipeline does not recognize, would otherwise leave\n// the object behind and the renderer would write `effects=\"[object Object]\"` with no error\n// anywhere. Listing it makes the invariant structural (J4).\n/** @internal */\nexport const INTERNAL_ATTRS = new Set([\n 'type', 'children', 'animator', 'meta', 'animate', 'effects', PX_TEXT_CONTENT_ATTR\n]);\n\n// ============================================================================\n// TRANSFORM\n// ============================================================================\n\n/**\n * Names of the transform parts that can appear inside a transform value record.\n * The unified `transform` slot replaces the earlier per-part top-level keys\n * (`translate`, `rotate`, `scale`, `origin`) — those names now live as keys\n * inside a `PxTransformParts` record.\n */\n/** The transform-part names, as a named record — they are keys of a DATA record (the\n * transform value), so code reaches them through this rather than as bare literals. */\nexport const TRANSFORM_PART = {\n translate: 'translate',\n rotate: 'rotate',\n scale: 'scale',\n origin: 'origin',\n} as const;\n\n/** @public */\nexport const PX_TRANSFORM_PART_KEYS = [\n TRANSFORM_PART.translate, TRANSFORM_PART.rotate, TRANSFORM_PART.scale, TRANSFORM_PART.origin,\n] as const;\n\n/** One of the transform-part key strings. @public */\nexport type PxTransformPartKey = typeof PX_TRANSFORM_PART_KEYS[number];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Gradient paint effect — `fillGradient` / `strokeGradient`.\n//\n// Materializer pattern mirrors `maskedByEffect`: at apply time the gradient\n// effect generates a `<linearGradient>` / `<radialGradient>` def into `ctx.defs`,\n// then sets the host element's `fill` / `stroke` to `url(#auto-id)`. The wire\n// gradient is geometry parts (`p1`/`p2` linear, `c`/`r`/`fp` radial — standard\n// animatable slots) + a stop sequence that is either static (bare array) or\n// animated (a single `{keyframes}` block whose each kf's `value` is the FULL\n// `Array<{offset, color}>` snapshot at that time). Per-stop independent\n// timelines are intentionally NOT modelled — the source is a single\n// stop-color keyframe group. Animated geometry is frames-engine only\n// (CSS/WAAPI cannot animate gradient endpoints; `mode: 'auto'` handles it).\n//\n// Stop count is constant across kfs. `gradientTransform` is captured as static\n// only (animated transform is vanishingly rare).\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Loose enums for `spreadMethod` / gradient `type` — kept on the wire as\n * plain strings (matches the rest of the schema's loose-enum stance) but\n * collected here so call sites use named constants instead of bare literals.\n *\n * `gradientUnits` has NO enum of its own: it takes the same two values as every other\n * units slot, so it reuses {@link PxUnits} (review §2.7 — one name per value set). * @public\n */\nexport const PxGradientSpreadMethod = {\n pad: 'pad',\n reflect: 'reflect',\n repeat: 'repeat',\n} as const;\n\nexport type PxGradientSpreadMethod = typeof PxGradientSpreadMethod[keyof typeof PxGradientSpreadMethod];\n\n/** @public */\nexport const PxGradientType = {\n linear: 'linear',\n radial: 'radial',\n} as const;\n\nexport type PxGradientType = typeof PxGradientType[keyof typeof PxGradientType];\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/** @public @advanced */\nexport function isPxDocument(doc: any): doc is PxAnimatedSvgDocument {\n if (!(\n doc &&\n typeof doc === 'object' &&\n !Array.isArray(doc)\n )) {\n return false;\n }\n\n // `type` is the tag, and the ONLY discriminator — it is what the schema requires\n // (`px.literal('svg')`). A `tagName` alternative was accepted here until 2026-08,\n // which meant a tagName-only document passed this gate and then failed\n // `isValidPxDocument`; nothing ever wrote it.\n return doc.type === 'svg';\n}\n\n/**\n * The animator config, at either of its TWO canonical addresses (S4).\n *\n * `animator` is the only name. It has two addresses because the SVG form has no other\n * slot: a `.svga`/JSON document carries it at the top level, while a pre-rendered\n * `.svg` carries it inside the root element's `data-px-meta` blob — i.e. under `meta`.\n * The editor lifts/un-lifts between the two on write/read.\n *\n * The `animation` / `meta.animation` spellings were removed 2026-08: nothing wrote\n * them and they were never in the schema.\n * @public @advanced\n */\nexport function getAnimatorConfig(doc: PxAnimatedSvgDocument): PxAnimatorConfig | undefined {\n const cfg = doc?.animator || doc?.meta?.animator;\n if (!cfg) return undefined;\n const memoised = wireViewMemo.get(cfg as object);\n if (memoised) return memoised;\n\n // A document states playback ONLY inside `timeline`. A flat key at the animator root is not a\n // second spelling to honor — it is an unknown key (`validateDocument` and the entry diagnostic\n // both report it), so it is dropped here and never reaches an engine.\n const wire = cfg as Record<string, unknown>;\n const stray = PX_FLAT_RUNTIME_VIEW_KEYS.filter(k => wire[k] !== undefined);\n const source = stray.length ? { ...wire } : cfg;\n for (const k of stray) delete (source as Record<string, unknown>)[k];\n\n // Every internal consumer sees the FLAT view — the nested `timeline` spelling is\n // folded down here, once, so the engines/effects/drivers never branch on it.\n const view = flattenAnimatorTimeline(source as PxAnimatorConfig);\n // Memoised on the DOCUMENT's config: repeated calls must return the same object (callers\n // compare identity and cache off it), and `source` is a fresh object when keys were dropped.\n wireViewMemo.set(cfg as object, view);\n return view;\n}\n\n/** Memo for {@link getAnimatorConfig} — see the identity note inside it. */\nconst wireViewMemo = new WeakMap<object, PxAnimatorConfig>();\n\n\n// ============================================================================\n// TIMELINE SPELLING (review §2.1)\n//\n// The wire spelling is `animator.timeline: { type?: 'time'|'scroll'|'view', … }` (absent = 'time');\n// the flat form (`timelineSource` + `scroll` + loose clock knobs) is the INTERNAL\n// runtime view only — not a wire format. These two functions convert between them:\n// • flattenAnimatorTimeline — wire → runtime view; applied by `getAnimatorConfig`,\n// so ALL runtime code keeps consuming the flat form it always has.\n// • nestAnimatorTimeline — runtime view → wire; applied by writers (the editor) so\n// files carry only the nested spelling and its mode-dead keys are structurally absent.\n// ============================================================================\n\n/** Memo: flatten allocates a new config; repeated `getAnimatorConfig` calls must keep\n * returning the SAME object (some callers compare identity / cache off it). */\nconst flattenMemo = new WeakMap<object, PxAnimatorConfig>();\n\n/**\n * Folds `cfg.timeline` (the wire spelling) into the flat runtime-view fields the engines\n * consume. Returns `cfg` unchanged when there is nothing to fold. Never mutates input.\n * @public @advanced\n */\nexport function flattenAnimatorTimeline(cfg: PxAnimatorConfig): PxAnimatorConfig {\n const timeline: any = (cfg as any).timeline;\n if (timeline === undefined || timeline === null || typeof timeline !== 'object') return cfg;\n\n const memoised = flattenMemo.get(cfg as object);\n if (memoised) return memoised;\n\n const { timeline: _dropped, ...flat } = cfg as any;\n\n // `engine` and `frameRate` are shared by every timeline type: how the attributes get\n // updated, and at what rate when that is the player's own frame loop.\n if (timeline.engine !== undefined) flat.engine = timeline.engine;\n if (timeline.frameRate !== undefined) flat.frameRate = timeline.frameRate;\n\n if (timeline.type === 'scroll' || timeline.type === 'view') {\n flat.timelineSource = 'scroll';\n if (timeline.duration !== undefined) flat.duration = timeline.duration; // §2.8\n if (timeline.iterations !== undefined) flat.iterations = timeline.iterations;\n const scroll: PxScroll = { ...(flat.scroll || {}) };\n scroll.kind = timeline.type;\n if (timeline.axis !== undefined) scroll.axis = timeline.axis;\n if (timeline.source !== undefined) scroll.source = timeline.source;\n if (timeline.subject !== undefined) scroll.subject = timeline.subject;\n if (timeline.smoothing !== undefined) scroll.smoothing = timeline.smoothing;\n if (timeline.range !== undefined) scroll.range = timeline.range;\n const pin = timeline.pin;\n if (typeof pin === 'boolean') scroll.pin = pin;\n else if (pin && typeof pin === 'object') {\n scroll.pin = true;\n if (pin.align !== undefined) scroll.pinAlign = pin.align;\n if (pin.offset !== undefined) scroll.pinOffset = pin.offset;\n if (pin.distance !== undefined) scroll.pinDistance = pin.distance;\n }\n flat.scroll = scroll;\n } else { // 'time', absent, or unknown — the time-driven timeline is the default\n if (timeline.duration !== undefined) flat.duration = timeline.duration; // §2.8\n if (timeline.trigger !== undefined) {\n const { finishAction, ...restTrigger } = timeline.trigger;\n if (Object.keys(restTrigger).length) flat.trigger = restTrigger;\n if (finishAction !== undefined) flat.resetOnFinish = finishAction === 'reset';\n }\n if (timeline.delay !== undefined) flat.delay = timeline.delay;\n if (timeline.iterations !== undefined) flat.iterations = timeline.iterations;\n if (timeline.direction !== undefined) flat.direction = timeline.direction;\n if (timeline.fillMode !== undefined) flat.fill = timeline.fillMode; // wire `fillMode` → runtime `fill`\n }\n\n flattenMemo.set(cfg as object, flat);\n return flat;\n}\n\n/**\n * Which scroll-driven member an absent `scroll.kind` selects — `'view'`, per `_PxScroll.kind`.\n *\n * The flat view says WHICH FAMILY drives progress (`timelineSource: 'scroll'`) separately from\n * WHICH MEMBER of it (`scroll.kind`), and only the family is named \"scroll\". Defaulting the\n * member to its family's name reads natural and is wrong: it silently rewrote every document\n * that left the kind at its default — which, being the default, is most of them.\n */\nfunction scrollKindOrDefault(kind: unknown): 'view' | 'scroll' {\n return kind === 'scroll' ? 'scroll' : 'view';\n}\n\n/**\n * Converts a FLAT animator config into the written spelling: mode-specific keys fold into\n * one discriminated `timeline` object; the legacy flat keys are removed from the output.\n * Returns a new object (input untouched); a config already carrying `timeline` passes\n * through unchanged; a pure-shared config (duration/mode/… only) gets no `timeline` at all.\n * @public @advanced\n */\nexport function nestAnimatorTimeline(cfg: PxAnimatorConfig): PxAnimatorConfig {\n if (!cfg || (cfg as any).timeline !== undefined) return cfg;\n\n const { timelineSource, scroll, trigger, delay, iterations, direction, fill, resetOnFinish,\n duration, engine, frameRate, ...shared } = cfg as any;\n\n if (timelineSource === 'scroll') {\n const timeline: any = { type: scrollKindOrDefault(scroll?.kind) };\n if (engine !== undefined) timeline.engine = engine;\n if (frameRate !== undefined) timeline.frameRate = frameRate;\n if (duration !== undefined) timeline.duration = duration; // §2.8\n // Finite iterations survive scrubbing (D4); 'infinite' cannot map to a range.\n if (typeof iterations === 'number') timeline.iterations = iterations;\n if (scroll) {\n if (scroll.axis !== undefined) timeline.axis = scroll.axis;\n if (scroll.source !== undefined) timeline.source = scroll.source;\n if (scroll.subject !== undefined) timeline.subject = scroll.subject;\n if (scroll.smoothing !== undefined) timeline.smoothing = scroll.smoothing;\n if (scroll.range !== undefined) timeline.range = scroll.range;\n const hasPinParams = scroll.pinAlign !== undefined || scroll.pinOffset !== undefined || scroll.pinDistance !== undefined;\n if (hasPinParams) {\n timeline.pin = {\n ...(scroll.pinAlign !== undefined ? { align: scroll.pinAlign } : {}),\n ...(scroll.pinOffset !== undefined ? { offset: scroll.pinOffset } : {}),\n ...(scroll.pinDistance !== undefined ? { distance: scroll.pinDistance } : {}),\n };\n } else if (scroll.pin !== undefined) {\n timeline.pin = scroll.pin;\n }\n }\n return { ...shared, timeline };\n }\n\n // Time-driven: `type` is optional on the wire and 'time' is the default, so the\n // writer omits it — the common case declares nothing.\n const timeline: any = {};\n if (engine !== undefined) timeline.engine = engine;\n if (frameRate !== undefined) timeline.frameRate = frameRate;\n if (duration !== undefined) timeline.duration = duration; // §2.8\n if (trigger !== undefined || resetOnFinish) {\n const t: any = { ...(trigger || {}) };\n if (resetOnFinish) t.finishAction = 'reset';\n timeline.trigger = t;\n }\n if (delay !== undefined) timeline.delay = delay;\n if (iterations !== undefined) timeline.iterations = iterations;\n if (direction !== undefined) timeline.direction = direction;\n if (fill !== undefined) timeline.fillMode = fill; // runtime `fill` → wire `fillMode`\n\n // An empty time timeline says nothing — omit the block entirely.\n return Object.keys(timeline).length > 0 ? { ...shared, timeline } : shared;\n}\n\n\n/** @public @advanced */\nexport function getDefinitions(doc: PxAnimatedSvgDocument): PxDefinitions | undefined {\n if (!doc) return undefined;\n return getAnimatorConfig(doc)?.definitions;\n}\n\n/** The bind-by-id document's `animator.bindings`, as written — `target` keeps its `#`. @public @advanced */\nexport function getBindings(doc: PxAnimatedSvgDocument): PxBinding[] | undefined {\n if (!doc) return undefined;\n return getAnimatorConfig(doc)?.bindings;\n}\n\n\n/** @public @advanced */\nexport function getChildren(doc: PxAnimatedSvgDocument): PxNode[] | undefined {\n return doc?.children;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { KeysMatch, PxInfer, PxSchema, PxValidationContext, PxRemoveIndex } from '../schema/PxSchema';\nimport { implementsInterface, px } from '../schema/PxSchema';\n// Constants live in their own module so importing one does not pull the schema engine\n// in; re-exported here so this module's public surface is unchanged. See there.\nexport * from './PxAnimatorConstants';\nimport { getAnimatorConfig, INTERNAL_ATTRS, isPxDocument, PX_TRANSFORM_PART_KEYS, PX_TRIGGER_DEFAULTS, PxTimelineEngineSetting, PxCloneWithout, PxPathOverflow, PxGradientSpreadMethod, PxGradientType, PxLengthAdjust, PxLoopRepeatAt, PxLoopDirection, PxMaskType, PxTextPathMethod, PxTextPathSpacing, PxStrokeTrimSubPaths, PxUnits,\n // Wire enums named in review §2.7 — used as VALUES by the schemas below.\n PxAlongPathMode, PxFillMode, PxFinishAction, PxOutAction, PxPinAlign, PxPlaybackDirection,\n PxScrollAxis, PxScrollKind, PxScrollPhase, PxScrollSource, PxStartOn } from './PxAnimatorConstants';\nimport type { PxTimelineEngine, PxTransformPartKey } from './PxAnimatorConstants';\n// Version stamps are parsed by the reader's own parser (review §2.10) so the validator and the\n// reader can never disagree on what counts as a stamp. `PxWireVersion` imports only\n// `PxSchemaVersion`, so this edge creates no cycle.\nimport { parseWireVersion } from '../version/PxWireVersion';\n// The diagnostics channel's payload, named by `PxEngineCallbacks` below (review §5).\n// `PxDiagnostics` imports nothing, so this edge creates no cycle either.\nimport type { PxDiagnosticKind, PxDiagnosticsConfig } from '../playback/PxDiagnostics';\n\n// ============================================================================\n// EASING\n// ============================================================================\n\n/**\n * Easing function definition.\n * Can be a named reference to a predefined easing or a cubic-bezier array [x1, y1, x2, y2].\n *\n * @example \"ease-in\" | [0.68, -0.55, 0.265, 1.55]\n *\n * `string | [x1, y1, x2, y2]`\n * @public @advanced\n */\nexport const PxEasingOrRefSchema = px.union([\n px.string(),\n px.tuple([px.number(), px.number(), px.number(), px.number()] as const),\n]);\n\n/**\n * Easing function definition.\n * Can be a named reference to a predefined easing or a cubic-bezier array [x1, y1, x2, y2].\n *\n * @example \"ease-in\" | \"easeOut\" | [0.68, -0.55, 0.265, 1.55]\n */\nexport type PxEasingOrRef = PxInfer<typeof PxEasingOrRefSchema>;\n\n\n// ============================================================================\n// KEYFRAME\n// ============================================================================\n\n/**\n * A single animation keyframe defining the state at a specific point in time.\n *\n * THE WIRE FORM, and only that: `time` / `value` / `easing` / `tangentIn` / `tangentOut`.\n * Locked to `PxKeyframeSchema` by the `KeysMatch` assertion below, so this interface and the\n * validator cannot drift apart.\n *\n * The engines consume {@link _PxNormalizedKeyframe} instead — the short-field form\n * `normalizeKeyframes` produces, with easing refs resolved and values parsed. The two used to\n * be ONE interface carrying both spellings, which meant no key-set lock was possible here and\n * nothing in the types said which form a given function expected.\n */\nexport interface _PxKeyframe {\n\n /** Timestamp in milliseconds from animation start */\n time?: number;\n\n /** The value of the animated property at this keyframe */\n value?: any;\n\n /** Easing function applied to the interval from this keyframe to the next */\n easing?: PxEasingOrRef;\n\n /**\n * Outgoing spatial tangent `[dx, dy]` for motion-along-path interpolation\n * (translate animations only).\n *\n * Stored as a *delta relative to* this keyframe's translate position —\n * the cubic Bezier segment between this kf and the next is built from\n * `(P0=value, P1=value+tangentOut, P2=next.value+next.tangentIn, P3=next.value)`.\n *\n * Defined when the segment leaving this keyframe is curved.\n */\n tangentOut?: [number, number];\n\n /**\n * Incoming spatial tangent `[dx, dy]` for motion-along-path interpolation\n * (translate animations only). Delta relative to this keyframe's translate\n * position. See `tangentOut` for the segment construction.\n *\n * Defined when the segment arriving at this keyframe is curved.\n */\n tangentIn?: [number, number];\n\n}\n\n/**\n * Allowed shapes for a single keyframe `value` across the wire schema:\n * - `number` — scalar properties (rotate-degree, opacity, offset-distance, …)\n * - `Array<number>` — vector properties (translate `[x,y]`, scale `[sx,sy]`, stroke-dasharray, RGBA …)\n * - `string` — color (hex / `url(#…)` / named) and other string-valued props\n * - `PxTransformParts` — unified body `transform` parts record\n * `{translate, rotate, scale, origin}`\n * - `{ paths: Array<PxBezierPath> }` — animated SVG path `d` value\n * - `Array<PxGradientStop>` — gradient `stops` timeline (each kf value is\n * the FULL `[{offset, color}, …]` snapshot)\n *\n * Plugged into `PxKeyframeSchema.value` / `.v` — every keyframe value on the\n * wire is validated against this union. The inferred TS type of `PxKeyframe`\n * stays permissive (`value?: any` via the generic default) so the duck-typed\n * interpolator code in `PxDefinitions.ts` (`prevV?.paths`,\n * `Array.isArray(prevV)`, …) keeps working without per-shape narrowing.\n */\nexport type _PxKeyframeValue =\n | string\n | number\n | Array<number>\n | PxTransformParts\n | { pathData: string }\n | Array<_PxGradientStop>;\n\n// `string | number | Array<number> | PxTransformParts | { pathData: string }`\n//\n// `{ pathData: \"M…\" }` is the ONE form for animated path geometry: a single `d` string\n// (a compound shape is one string with several `M…` sub-paths). The Lottie-style\n// `{ paths: [{v,i,o,c}] }` array was retired 2026-09-11 — it lives on only as the\n// interpolator's INTERNAL shape (`normalizePathValue` in `PxDefinitions.ts`).\n//\n// `PxTransformPartsSchema` is declared later in this file — `px.lazy` defers the lookup\n// until validation time so the declarations stay in narrative order without a TDZ at load.\n/** @public @advanced */\nexport const PxKeyframeValueSchema = implementsInterface<_PxKeyframeValue>()(px.union([\n px.string(), // e.g. for colors\n px.number(),\n px.array(px.number()),\n // ORDER LAW: the key-discriminated object shape (`{pathData}`) comes BEFORE the\n // all-optional transform-parts record. In default (non-strict) mode that record accepts\n // ANY object (every key optional, unknown keys ignored), so listing it earlier made\n // Union.sanitize route `{pathData}` values into it and strip them to `{}` —\n // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is\n // order-independent (`some()`); only sanitize routing depends on this order.\n px.object({ pathData: px.string() }),\n // Gradient `stops` timeline — each kf value is the full stops-array snapshot.\n px.lazy<Array<_PxGradientStop>>(() => px.array(PxGradientStopSchema), []),\n px.lazy<PxTransformParts>(() => PxTransformPartsSchema, {}),\n]));\n\n/** A single keyframe `value` — union of all wire-allowed shapes. */\nexport type PxKeyframeValue = PxInfer<typeof PxKeyframeValueSchema>;\n\n// `{ time?:number, t?:number, value?:PxKeyframeValue, v?:PxKeyframeValue,\n// easing?:Easing, e?:Easing, tangentOut?:[dx,dy], tangentIn?:[dx,dy] }`\n//\n// `value` / `v` validate against {@link PxKeyframeValueSchema} — malformed\n// keyframe values are now schema errors instead of passing as `px.any()`\n// (SCHEMA-DESIGN I-5). The `_PxKeyframe` interface keeps `value?: any` (and\n// `PxKeyframe<T = any>` its generic default) so the duck-typed interpolator\n// access in `PxDefinitions.ts` stays untyped-permissive at compile time.\n// LONG SPELLINGS ONLY (review §1.2/§6.1): the short aliases (`t`/`v`/`e`/`to`/`ti`)\n// were removed from the wire outright — one clear spelling, no mixing ambiguity.\n// They survive only as the internal normalized runtime view (see `_PxKeyframe`).\n/** @public @advanced */\nexport const PxKeyframeSchema = implementsInterface<_PxKeyframe>()(px.object({\n time: px.number().optional(),\n value: PxKeyframeValueSchema.optional(),\n easing: PxEasingOrRefSchema.optional(),\n tangentOut: px.tuple([px.number(), px.number()] as const).optional(),\n tangentIn: px.tuple([px.number(), px.number()] as const).optional(),\n // (`selected` — editor timeline-selection UI state — was REMOVED from the wire\n // (review §1.3): editor data lives under `meta`. The editor still carries it on\n // its internal COPY-PASTE payload, which never validates against this schema.)\n}));\n\n/**\n * THE RUNTIME FORM — what `normalizeKeyframes` hands the engines, and what the tree-level\n * materializers (`materializeInternalLoopsInTree` and everything after it in\n * `materializeAllInTree`) write back into the document.\n *\n * Short-named on purpose: these are read once per property per frame. `e` is a RESOLVED easing\n * (named refs already looked up in `definitions.easings`) and `v` is a PARSED value (colors as\n * RGBA arrays, path `d` normalized) — which is the substantive difference from the wire form,\n * not just the spelling. Deliberately NOT a wire shape: `validateDocument` rejects it, and a\n * materialized document is a runtime artefact that is never written to disk.\n */\nexport interface _PxNormalizedKeyframe {\n /** Time in ms from the animation start (the wire spells it `time`). */\n t?: number;\n /** The parsed value at this keyframe (the wire spells it `value`). */\n v?: any;\n /** The RESOLVED easing — never a name (the wire spells it `easing`). */\n e?: PxEasingOrRef;\n /** Incoming spatial tangent, same meaning as the wire's. */\n tangentIn?: [number, number];\n /** Outgoing spatial tangent, same meaning as the wire's. */\n tangentOut?: [number, number];\n}\n\n/** @internal */\nexport type PxNormalizedKeyframe = _PxNormalizedKeyframe;\n\n/**\n * Either spelling. For the handful of helpers that genuinely run on BOTH sides of\n * normalization — read them through the `kf*` accessors below rather than branching inline.\n * @internal\n */\nexport type PxAnyKeyframe = _PxKeyframe | _PxNormalizedKeyframe;\n\nconst anyKf = (kf: PxAnyKeyframe) => kf as _PxKeyframe & _PxNormalizedKeyframe;\n\n/** Time in ms, whichever spelling the keyframe is in. @internal */\nexport const keyframeTime = (kf: PxAnyKeyframe): number => anyKf(kf).time ?? anyKf(kf).t ?? 0;\n/** Value, whichever spelling. @internal */\nexport const keyframeValue = (kf: PxAnyKeyframe): any => anyKf(kf).value ?? anyKf(kf).v;\n/** Easing — resolved on a normalized keyframe, possibly a NAME on a wire one. @internal */\nexport const keyframeEasing = (kf: PxAnyKeyframe): PxEasingOrRef | undefined => anyKf(kf).easing ?? anyKf(kf).e;\n/** Incoming spatial tangent, whichever spelling. @internal */\nexport const keyframeTangentIn = (kf: PxAnyKeyframe): [number, number] | undefined => anyKf(kf).tangentIn;\n/** Outgoing spatial tangent, whichever spelling. @internal */\nexport const keyframeTangentOut = (kf: PxAnyKeyframe): [number, number] | undefined => anyKf(kf).tangentOut;\n\n/**\n * A single animation keyframe defining the state at a specific point in time.\n *\n * Generic over the keyframe `value` type for callers that know the per-property\n * value shape (e.g. `PxKeyframe<PxVec2>` in the effect appliers). Defaults to\n * `any`, matching the schema (`value` is stored as `px.any()` on the wire).\n * @public\n */\n// The WIRE type, generic over the value type. The engines use `PxNormalizedKeyframe`.\nexport type PxKeyframe<T = any> = Omit<_PxKeyframe, 'value'> & { value?: T };\n// Locks the interface to the schema at the default instantiation.\nconst _ck_PxKeyframe: KeysMatch<PxInfer<typeof PxKeyframeSchema>, _PxKeyframe> = true;\n\n/** {@link PxNormalizedKeyframe}, generic over the value type — the runtime counterpart. */\nexport type PxNormalizedKeyframeOf<T = any> = Omit<_PxNormalizedKeyframe, 'v'> & { v?: T };\n\n/**\n * A property animation whose keyframes are in the RUNTIME form.\n *\n * What `normalizeKeyframes` produces, what the engines consume — and what the EDITOR's in-memory\n * model is: its keyframe objects carry the short field names and serialize to the long wire ones\n * through `@serializable`, so the model implements this rather than the wire shape.\n * @internal\n */\nexport type PxNormalizedPropertyAnimation =\n Omit<_PxPropertyAnimation, 'keyframes'> & { keyframes?: Array<_PxNormalizedKeyframe> };\n\n\n// ============================================================================\n// LOOP\n// ============================================================================\n\n/**\n * Defines how a property's keyframe animation is extended beyond its defined keyframe range\n * by continuously repeating a chosen segment of the sequence.\n *\n * The repeated segment is a contiguous run of keyframe *intervals* (gaps between consecutive\n * keyframes). Which end of the sequence is repeated is controlled by `before`, and whether\n * each repetition plays in the same direction or alternates is controlled by `alternate`.\n *\n * **Relationship to `animator.iterations`**\n *\n * `PxLoop` and `animator.iterations` are independent mechanisms operating at different levels:\n *\n * - `PxLoop` is a **pre-processing step**: it expands the property's keyframe list to fill the\n * full `animator.duration` before any playback begins. The runtime sees a single, fully\n * expanded keyframe sequence — it has no knowledge of the loop.\n *\n * - `animator.iterations` repeats the **entire document timeline** (all properties, all\n * elements) as a unit, after the expanded keyframes are already in place.\n *\n * The two compose independently: a property with `loop: true` inside a document with\n * `iterations: \"infinite\"` will cycle its own segment within each document iteration, and\n * that iteration will itself repeat forever — loop-within-loop.\n */\nexport interface _PxLoop {\n\n /**\n * Number of keyframe intervals (gaps between consecutive keyframes) that form the repeating\n * segment.\n *\n * - `undefined` → the entire keyframe sequence is used as the loop segment.\n * - `N` → only the first `N` intervals (when `repeatAt: 'start'`) or the last `N`\n * intervals (when `repeatAt: 'end'`) are looped. Clamped to `[1, keyframes.length - 1]`.\n */\n segmentCount?: number;\n\n /**\n * Which end of the keyframe sequence the repetition fills — see {@link PxLoopRepeatAt}.\n * `'start'` repeats ahead of the first keyframe (intro loop); `'end'` (default)\n * repeats past the last (idle/outro loop).\n */\n repeatAt?: PxLoopRepeatAt;\n\n /**\n * How successive repetitions play — see {@link PxLoopDirection}.\n *\n * - `'normal'` (default) → **cycle**: every repetition replays the segment the same way round.\n * - `'alternate'` → **ping-pong**: repetitions alternate forward and backward\n * (even repetitions play forward, odd ones in reverse).\n */\n direction?: PxLoopDirection;\n}\n\n// `{ segmentCount?:number, repeatAt?:'start'|'end', direction?:'normal'|'alternate' }`\n/** @public @advanced */\nexport const PxLoopSchema = implementsInterface<_PxLoop>()(px.object({\n segmentCount: px.number().optional(),\n repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end] as const).optional(),\n direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate] as const).optional(),\n}));\n\n/**\n * Defines how a property's keyframe animation is extended beyond its defined keyframe range\n * by continuously repeating a chosen segment of the sequence.\n * @public\n */\nexport type PxLoop = PxInfer<typeof PxLoopSchema>;\nconst _ck_PxLoop: KeysMatch<PxLoop, _PxLoop> = true; // the key sets are identical\n\n\n// ============================================================================\n// PROPERTY ANIMATION\n// ============================================================================\n\n/**\n * Animation definition for a single CSS/SVG property.\n * Contains an array of keyframes that define how the property changes over time.\n */\nexport interface _PxPropertyAnimation {\n\n /**\n * Optional static / base value for the animated property.\n *\n * Two uses:\n * - structured static: `{value}` with no keyframes is the static form of\n * the universal animatable pattern (`PxAnimatable<T>`);\n * - base + keyframes: when both are present, `value` is the baseline the\n * animation starts from. For most properties keyframe values are\n * complete and `value` is just the pre-tick DOM baseline; slots with\n * patch semantics (the editor's extended-d `shape` effect) merge each\n * keyframe's partial value over this base.\n */\n value?: any;\n\n /** Array of keyframes defining the animation timeline */\n keyframes?: PxKeyframe[];\n\n /**\n * Optional loop configuration. When set, the keyframe sequence is expanded at pre-processing\n * time to fill the gap between the keyframe range and `animator.duration` by repeating a\n * chosen segment. `true` is shorthand for the default {@link PxLoop} (loop the last segment\n * after the final keyframe, cycling forward). See {@link PxLoop} for details.\n *\n * Note: this operates independently of `animator.iterations` — see {@link _PxLoop} for the\n * interaction between the two.\n */\n loop?: PxLoop | boolean;\n\n /**\n * Motion-along-path \"auto-orient\" flag. Only meaningful for translate\n * animations whose keyframes carry spatial tangents (`tangentIn` /\n * `tangentOut`): when true, the element rotates so its local X axis aligns\n * with the path tangent at the current position. The rotation is computed\n * from the cubic-Bezier derivative at the eased progress along the\n * arc-length-parametrised segment.\n */\n autoOrient?: boolean;\n\n /**\n * How a motion-along-path `transform` animation is RENDERED: `'sampled'` (default,\n * absent) — the path is pre-sampled into plain transform keyframes;\n * `'offsetPath'` — the browser drives it as a CSS Motion Path (`offset-path` /\n * `offset-distance`). Written by the editor, consumed by `materializeAllInTree`.\n */\n alongPathMode?: 'sampled' | 'offsetPath';\n}\n\n// `{ value?:KeyframeValue, keyframes?:Keyframe[], loop?:Loop|boolean, autoOrient?:bool, alongPathMode?:'sampled'|'offsetPath' }`\n// (the `kfs` alias was removed outright — review §1.2/§6.1: one spelling only)\n/** @public @advanced */\nexport const PxPropertyAnimationSchema = implementsInterface<_PxPropertyAnimation>()(px.object({\n value: PxKeyframeValueSchema.optional(),\n keyframes: px.array(PxKeyframeSchema).optional(),\n loop: px.union([PxLoopSchema, px.boolean()]).optional(),\n autoOrient: px.boolean().optional(),\n alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath] as const).optional(),\n}));\n\n/** Animation definition for a single CSS/SVG property. @public */\n// The runtime-VIEW type: its `keyframes` items are runtime-view PxKeyframes (they may\n// carry the internal normalized short fields), which the schema-inferred type cannot.\nexport type PxPropertyAnimation = _PxPropertyAnimation;\n// KeysMatch compares only the KEY SETS, so it still locks the schema to the interface even\n// though the two disagree about the VALUE type of `keyframes` (above). Worth having here in\n// particular: this is the object that carried the `kfs` alias until it was deleted.\nconst _ck_PxPropertyAnimation: KeysMatch<PxInfer<typeof PxPropertyAnimationSchema>, _PxPropertyAnimation> = true;\n\n\n/**\n * Record of transform parts forming a single transform `value`. Each present\n * key contributes one segment of the composed CSS transform string at render /\n * interpolation time, in the canonical order\n * `translate, translate(+origin), rotate, scale, translate(-origin)`.\n *\n * `origin` is meaningful only when `rotate` or `scale` is also present in the\n * same record — see \"When does origin belong inside a keyframe value?\" in\n * `file-format-remaining-design-issues2.md`.\n */\nexport interface _PxTransformParts {\n\n /** Translation offset `[x, y]` in user units. */\n translate?: [number, number];\n\n /** Rotation in degrees. */\n rotate?: number;\n\n /** Skew (skewX) in degrees, pivoting at `origin` — composed between `rotate`\n * and `scale` (matches Lottie's transform order). */\n skew?: number;\n\n /** Scale factor `[sx, sy]`. */\n scale?: [number, number];\n\n /**\n * Pivot for rotate / scale `[x, y]`. Only meaningful alongside `rotate` or\n * `scale` in the same record.\n */\n origin?: [number, number];\n}\n\n// `{ translate?:[x,y], rotate?:deg, skew?:deg, scale?:[sx,sy], origin?:[x,y] }`\n/** @public @advanced */\nexport const PxTransformPartsSchema = implementsInterface<_PxTransformParts>()(px.object({\n translate: px.tuple([px.number(), px.number()] as const).optional(),\n rotate: px.number().optional(),\n skew: px.number().optional(),\n scale: px.tuple([px.number(), px.number()] as const).optional(),\n origin: px.tuple([px.number(), px.number()] as const).optional(),\n}));\n\n/** Record of transform parts forming a single transform `value`. @public */\nexport type PxTransformParts = PxInfer<typeof PxTransformPartsSchema>;\nconst _ck_PxTransformParts: KeysMatch<PxTransformParts, _PxTransformParts> = true; // the key sets are identical\n\n/**\n * Unified `transform` slot value. Valid shapes:\n *\n * - **Bare parts record** — `{translate:[100,100], rotate:45, scale:[1.5,1.5],\n * origin:[25,25]}` — THE canonical lightweight static (SCHEMA-DESIGN §2/S1):\n * the authored parts verbatim, the exact record grammar animated keyframe\n * values use. Unambiguous because a body attr never carries animation — that\n * lives in the parallel `animate` channel (R2); the parts keys are disjoint\n * from the animation-wrapper keys.\n * - **SVG transform string** — `\"translate(125,125)rotate(45)…translate(-25,-25)\"`.\n * The pre-rendered/browser form (origin baked into a pivot sandwich) and the\n * foreign-SVG import path. Read forever.\n * - **Structured static** — `{value: PxTransformParts}`. Read-accepted legacy\n * spelling of the record.\n * - **Animated** — `{keyframes: [{time, value: PxTransformParts, …}, …]}`.\n * Legacy inline form (the editor writes the `animate` channel instead).\n *\n * Replaces the earlier convention of putting each animated transform part\n * under its own top-level attribute name (`translate`, `rotate`, `scale`,\n * `origin`).\n * @public @advanced\n */\nexport const PxTransformValueSchema = px.union([\n px.string(),\n PxTransformPartsSchema,\n px.object({ value: PxTransformPartsSchema }),\n PxPropertyAnimationSchema,\n]);\n\n/** Unified `transform` slot value: string | structured static | animated. @public */\nexport type PxTransformValue = PxInfer<typeof PxTransformValueSchema>;\n\n\n// ============================================================================\n// ANIMATION DEFINITION\n// ============================================================================\n\n/**\n * Complete animation definition containing one or more property animations.\n * Each key is a CSS/SVG property name (e.g., \"opacity\", \"translate\", \"fill\").\n *\n * @example\n * { \"opacity\": { keyframes: [...] }, \"translate\": { keyframes: [...] } }\n */\nexport interface _PxAnimationDefinition {\n [property: string]: PxPropertyAnimation;\n}\n\n// `Record<propName, PropertyAnimation>`\n/** @public @advanced */\nexport const PxAnimationDefinitionSchema = implementsInterface<_PxAnimationDefinition>()(\n px.record(PxPropertyAnimationSchema)\n);\n\n/**\n * Complete animation definition containing one or more property animations.\n * Each key is a CSS/SVG property name (e.g., \"opacity\", \"scale\", \"rotate\").\n * @public\n */\nexport type PxAnimationDefinition = PxInfer<typeof PxAnimationDefinitionSchema>;\n\n\n// ============================================================================\n// ELEMENT ANIMATION\n// ============================================================================\n\n/**\n * Element animation specification. Can be:\n * - A string referencing a named animation from `definitions.animations`\n * - An array of named references\n * - An inline `AnimationDefinition` object\n * - A mixed array of references and inline definitions\n *\n * @example\n * \"fadeIn\"\n * [\"fadeIn\", \"spin\"]\n * { opacity: { keyframes: [...] } }\n * [\"fadeIn\", { scale: { keyframes: [...] } }]\n */\nexport type _PxElementAnimation =\n | string\n | string[]\n | PxAnimationDefinition\n | (string | PxAnimationDefinition)[];\n\n// `string | Array<string|AnimationDefinition> | AnimationDefinition`\n/** @public @advanced */\nexport const PxElementAnimationSchema = implementsInterface<_PxElementAnimation>()(px.union([\n px.string(),\n px.array(px.union([px.string(), PxAnimationDefinitionSchema])),\n PxAnimationDefinitionSchema,\n]));\n\n/**\n * Element animation specification.\n * Can be a string reference, array of references, inline definition, or a mixed array.\n * @public\n */\nexport type PxElementAnimation = PxInfer<typeof PxElementAnimationSchema>;\n\n\n// ============================================================================\n// TRIGGER\n// ============================================================================\n\n/**\n * Defines when and how an animation should be triggered.\n */\nexport interface _PxTrigger {\n\n /** Event that starts the animation. Default `'load'` — a document is designed to play;\n * `'programmatic'` waits for `play()`. */\n startOn?: PxStartOn;\n\n /** Action to take when the trigger condition is no longer met (e.g., mouse leaves).\n * Default `'continue'`. */\n outAction?: PxOutAction;\n\n /** Percentage of element visibility required to trigger (0–1, default 0 = any pixel).\n * Only applies to scrollIntoView. */\n scrollIntoViewThreshold?: number;\n\n /** After a NATURAL finish: `'hold'` (default — keep the end state per `fill`) or `'reset'`\n * (snap back to the start). Named to pair with its sibling `outAction`, and NOT `onFinish`,\n * which is the CALLBACK on `PxEngineCallbacks` — a value key and a function key with\n * one name read badly side by side in a document literal or in JSX. */\n finishAction?: PxFinishAction;\n}\n\n// `{ startOn?:'load'|'mouseOver'|'click'|'scrollIntoView'|'programmatic', outAction?:..., scrollIntoViewThreshold?:number }`\n// An absent field means its PX_TRIGGER_DEFAULTS entry — the table every player resolves through.\n/** @public @advanced */\nexport const PxTriggerSchema = implementsInterface<_PxTrigger>()(px.object({\n startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic] as const, PX_TRIGGER_DEFAULTS.startOn).optional(),\n outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse] as const, PX_TRIGGER_DEFAULTS.outAction).optional(),\n // What happens after a NATURAL finish — `'hold'` (default: keep the end state per\n // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` (\"what\n // happens when the trigger condition ends\"); both end-of-life knobs now read alike.\n finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset] as const).optional(),\n scrollIntoViewThreshold: px.number().optional(),\n}));\n\n/** Defines when and how an animation should be triggered. @public */\nexport type PxTrigger = PxInfer<typeof PxTriggerSchema>;\nconst _ck_PxTrigger: KeysMatch<PxTrigger, _PxTrigger> = true; // the key sets are identical\n\n\n// ============================================================================\n// DEFS\n// ============================================================================\n\n/**\n * A single character's embedded outline (glyph-mode text). Coordinates and\n * advance are in the owning {@link _PxGlyphFont}'s `unitsPerEm` units, so the\n * player can render text without the original font. See svga.text.design.md.\n */\nexport interface _PxGlyph {\n /** Advance width, in the font's `unitsPerEm`. */\n width: number;\n /** Outline path data, in the font's `unitsPerEm` (empty for whitespace). Named\n * `pathData`, never `d`: `d` is SVG's name for the node ATTRIBUTE only, and every\n * structure of ours spells the concept out (review §2.4). */\n pathData: string;\n}\n\nexport const PxGlyphSchema = implementsInterface<_PxGlyph>()(px.object({\n width: px.number(),\n pathData: px.string(),\n}));\n\n/** @public */\nexport type PxGlyph = PxInfer<typeof PxGlyphSchema>;\nconst _ck_PxGlyph: KeysMatch<PxGlyph, _PxGlyph> = true; // the key sets are identical\n\n/**\n * The used glyphs of one font, keyed by character. Referenced by a text's\n * `font-family` (the key in {@link _PxDefs.fonts}).\n */\nexport interface _PxGlyphFont {\n /** CSS family name, e.g. \"Roboto\". */\n fontFamily: string;\n /** Font-style notation, e.g. \"\" | \"italic\" (review §5.2 — `style` would collide with the node's CSS `style`). */\n fontStyle: string;\n /** Ascent, in `unitsPerEm` units (baseline placement). */\n ascent: number;\n /** Units per em the glyph `width`/`pathData` are expressed in, e.g. 1000. */\n unitsPerEm: number;\n /** Outlines of the used characters, keyed by the character itself. */\n glyphs: { [char: string]: PxGlyph; };\n}\n\nexport const PxGlyphFontSchema = implementsInterface<_PxGlyphFont>()(px.object({\n fontFamily: px.string(),\n fontStyle: px.string(),\n ascent: px.number(),\n unitsPerEm: px.number(),\n glyphs: px.record(PxGlyphSchema),\n}));\n\n/** @public */\nexport type PxGlyphFont = PxInfer<typeof PxGlyphFontSchema>;\nconst _ck_PxGlyphFont: KeysMatch<PxGlyphFont, _PxGlyphFont> = true; // the key sets are identical\n\n/**\n * Reusable definitions library for easings, animations and fonts.\n * Defined once here, referenced by name on elements (or, for animations, from bindings).\n * (`styles` — named style presets — was removed on 2026-09-13, review 2.13: nothing wrote it.)\n */\nexport interface _PxDefs {\n\n /** Named cubic-bezier easing functions */\n easings?: { [name: string]: [number, number, number, number]; };\n\n /** Named animation definitions that can be referenced by elements */\n animations?: { [name: string]: PxAnimationDefinition; };\n\n /** Embedded fonts — per-font glyph outlines, keyed by the text's `font-family`.\n * Lets glyph-mode `<text>` render without an external font. */\n fonts?: { [fontName: string]: PxGlyphFont; };\n}\n\n// `{ easings?:Record<name,[x1,y1,x2,y2]>, animations?:Record<name,AnimationDefinition>, fonts?:Record<fontName,PxGlyphFont> }`\n/** @public @advanced */\nexport const PxDefinitionsSchema = implementsInterface<_PxDefs>()(px.object({\n easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()] as const)).optional(),\n animations: px.record(PxAnimationDefinitionSchema).optional(),\n fonts: px.record(PxGlyphFontSchema).optional(),\n}));\n\n/** Reusable definitions library for easings, animations and fonts. @public */\nexport type PxDefinitions = PxInfer<typeof PxDefinitionsSchema>;\nconst _ck_PxDefs: KeysMatch<PxDefinitions, _PxDefs> = true; // the key sets are identical\n\n\n// ============================================================================\n// SCROLL TIMELINE\n// ============================================================================\n\n/**\n * A point on a scroll timeline's range, anchoring where the animation's 0%/100% sit.\n *\n * For `kind: 'view'`, `phase` names WHICH slice of the subject's journey across the\n * scrollport the point is measured in (CSS \"timeline range name\"), and `fraction` is the\n * 0..1 position within that slice. For `kind: 'scroll'` there are no phases — `phase` is\n * ignored and `fraction` is a fraction of the scroller's total scroll range.\n *\n * Structured on purpose (never a CSS string like `\"cover 0%\"`): atomic values, mechanical\n * translation to CSS `animation-range` / WAAPI `rangeStart/rangeEnd` where needed.\n */\nexport interface _PxScrollRangePoint {\n /** `view` kind only: the journey phase this point is anchored in. Default `'cover'`. */\n phase?: PxScrollPhase;\n /** 0..1 within the phase (or of the total scroll range for `kind: 'scroll'`). */\n fraction?: number;\n}\n\n/** @public @advanced */\nexport const PxScrollRangePointSchema = implementsInterface<_PxScrollRangePoint>()(px.object({\n phase: px.enum([PxScrollPhase.cover, PxScrollPhase.contain, PxScrollPhase.entry,\n PxScrollPhase.exit, PxScrollPhase.entryCrossing, PxScrollPhase.exitCrossing] as const).optional(),\n fraction: px.number().optional(),\n}));\n/** @public */\nexport type PxScrollRangePoint = PxInfer<typeof PxScrollRangePointSchema>;\nconst _ck_PxScrollRangePoint: KeysMatch<PxScrollRangePoint, _PxScrollRangePoint> = true; // the key sets are identical\n\n/**\n * Scroll-timeline configuration — consulted only when `timelineSource: 'scroll'`.\n * All fields optional; the defaults give \"scrub the whole animation as the SVG crosses\n * the viewport\" (`view` / `block` / full `cover` range).\n */\nexport interface _PxScroll {\n /** What progress measures. `'view'` (default): the SVG's own journey across the\n * scrollport (enter → leave). `'scroll'`: the scroll container's offset ratio,\n * regardless of where the SVG sits. */\n kind?: 'view' | 'scroll';\n\n /** Scroll axis. `block`/`inline` are writing-mode relative (block = vertical in\n * horizontal writing); `x`/`y` are physical. Default `'block'`. */\n axis?: 'block' | 'inline' | 'x' | 'y';\n\n /** `kind: 'scroll'` only: which scroller. `'nearest'` (default) = nearest scrollable\n * ancestor of the SVG; `'root'` = the document. (`view` always tracks the nearest\n * scrollport.) */\n source?: 'nearest' | 'root';\n\n /**\n * `kind: 'view'` only — WHICH ELEMENT'S journey is measured. Unset (default) = the\n * animation's own `<svg>`. The same indirection CSS gives via `view-timeline-name` +\n * `timeline-scope`, GSAP via `trigger`, Framer via \"Section in view\".\n *\n * - `'parent'` — the nearest ancestor that actually scrolls past: any `sticky`/`fixed`\n * ancestors are skipped and their container is used instead. This is what makes a\n * PINNED section work (a stuck element's rect stops moving, so measuring the graphic\n * itself would freeze); its `contain` phase is exactly the pinned stretch.\n * - `'scroller'` — the scroll container itself.\n * - anything else — a CSS selector, resolved against the host document.\n *\n * An unresolvable selector warns and falls back to the `<svg>` (never a silent freeze).\n */\n subject?: string;\n\n /**\n * MILLISECONDS of catch-up lag — the same idea as GSAP's `scrub: <seconds>`, in the unit\n * the rest of this schema uses (`duration`, `delay`). Unset/0 = the playhead is locked to\n * the scrollbar; above 0 the progress eases toward the scroll position instead of snapping\n * to it, which reads far smoother under momentum scrolling and trackpads.\n * Custom driver only — a browser-native `ScrollTimeline` has no equivalent, so setting\n * this forces the player's own measurement (the browser timeline is skipped).\n */\n smoothing?: number;\n\n /**\n * Hold the canvas still on screen while scrolling scrubs it — GSAP's `pin: true`, done with\n * `position: sticky` (which keeps the element's space in normal flow, so unlike GSAP's\n * `position: fixed` no spacer padding has to be injected into the host's layout).\n *\n * The player owns the DOM inside its own container, so this needs NO host CSS. Pair it with\n * `subject: 'parent'` for the complete scrollytelling pattern.\n */\n pin?: boolean;\n\n /**\n * `pin` only: WHERE in the scrollport the canvas is held — the alignment the sticky\n * offset is computed from. `top` (default) holds it against the top edge; `center`\n * and `bottom` need the canvas's own height, so the player measures it and keeps the\n * offset in sync on resize. `pinOffset` is added on top of whichever alignment is chosen.\n */\n pinAlign?: 'top' | 'center' | 'bottom';\n\n /** `pin` only: offset from the alignment position (see `pinAlign`), in px. Default 0.\n * The runtime-view twin of the wire `timeline.pin.offset` (review §2.6). */\n pinOffset?: number;\n\n /**\n * `pin` only: how much scroll travel the pin should last, in VIEWPORT HEIGHTS — the player\n * injects a wrapper of that height around the canvas to create it. Omit to pin inside\n * whatever tall section the host page already provides.\n */\n pinDistance?: number;\n\n /** The timeline slice mapped onto animation progress 0..1.\n * Default `{ start: {phase:'cover', fraction:0}, end: {phase:'cover', fraction:1} }`. */\n range?: {\n start?: _PxScrollRangePoint;\n end?: _PxScrollRangePoint;\n };\n}\n\n/** The `range` sub-object — named so consumers can derive its keys. @public @advanced */\nexport const PxScrollRangeSchema = px.object({\n start: PxScrollRangePointSchema.optional(),\n end: PxScrollRangePointSchema.optional(),\n});\n\n/** @public @advanced */\nexport const PxScrollSchema = implementsInterface<_PxScroll>()(px.object({\n kind: px.enum([PxScrollKind.view, PxScrollKind.scroll] as const).optional(),\n axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y] as const).optional(),\n source: px.enum([PxScrollSource.nearest, PxScrollSource.root] as const).optional(),\n // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.\n subject: px.string().optional(),\n smoothing: px.number().optional(),\n pin: px.boolean().optional(),\n pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom] as const).optional(),\n pinOffset: px.number().optional(),\n pinDistance: px.number().optional(),\n range: PxScrollRangeSchema.optional(),\n}));\n/** @public */\nexport type PxScroll = PxInfer<typeof PxScrollSchema>;\nconst _ck_PxScroll: KeysMatch<PxScroll, _PxScroll> = true; // the key sets are identical\n\n\n// ============================================================================\n// TIMELINE — what advances the animation's progress (review §2.1)\n// ============================================================================\n//\n// `animator.timeline` is a discriminated object: `type?: 'time' | 'scroll' | 'view'`,\n// deliberately mirroring WAAPI's three timeline classes (DocumentTimeline /\n// ScrollTimeline / ViewTimeline) and CSS `animation-timeline: auto | scroll() | view()`.\n// Each mode carries ONLY its own parameters, so a key that is dead in the other mode is\n// structurally unwritable — the old flat spelling (`timelineSource` + sibling `scroll` +\n// clock knobs loose at the animator root) required design rules (D3/D4) to keep dead keys\n// out; readers accept BOTH spellings (see `flattenAnimatorTimeline`), writers emit only\n// this one.\n\n/** Pin parameters as one object — presence enables pinning (review §2.2; the flat runtime-view\n * spelling is `scroll.pin/pinAlign/pinOffset/pinDistance`). */\nexport interface _PxTimelinePin {\n /** Where the pinned canvas sits in the viewport. Default `'top'`. */\n align?: 'top' | 'center' | 'bottom';\n /** Offset from the alignment position, in px. Default 0. Named `offset`, not `top`: it is a\n * delta from whichever edge `align` picked, so `{ align: 'bottom', top: 20 }` read as a\n * contradiction (review §2.6). */\n offset?: number;\n /** How much scroll travel the pin lasts, in VIEWPORT HEIGHTS. Omit to pin inside\n * whatever tall section the host page already provides. */\n distance?: number;\n}\n\n/** @public @advanced */\nexport const PxTimelinePinSchema = implementsInterface<_PxTimelinePin>()(px.object({\n align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom] as const).optional(),\n offset: px.number().optional(),\n distance: px.number().optional(),\n}));\n/** @public */\nexport type PxTimelinePin = PxInfer<typeof PxTimelinePinSchema>;\nconst _ck_PxTimelinePin: KeysMatch<PxTimelinePin, _PxTimelinePin> = true; // the key sets are identical\n\n// Time-driven — wall-clock playback: something STARTS it (trigger) and it has the\n// WAAPI playback dynamics. `type` is OPTIONAL: an absent `type` (or an absent\n// `timeline` altogether) means this one — the common case declares nothing.\n// `resetOnFinish` has no slot here: its successor is `trigger.finishAction: 'reset'`.\n/** `timeline.engine` — HOW the animated attributes get updated (every timeline type;\n * default `auto`). Not `mode`: an implementation preference, not a behavior switch. */\nconst PxTimelineEngineSchema = px.enum([PxTimelineEngineSetting.auto, PxTimelineEngineSetting.native, PxTimelineEngineSetting.js] as const).optional();\n\n/**\n * The time-driven timeline. Declared as an interface so a rename inside the schema below is a\n * COMPILE error rather than a silent wire-format change — `flattenAnimatorTimeline` reads the\n * timeline through `any`, so without this lock nothing else in the repo would notice.\n */\nexport interface _PxTimeTimeline {\n /** Optional: an absent `type` (or an absent `timeline`) already means this member. */\n type?: 'time';\n /** How the animated attributes get updated. Default `auto`. */\n engine?: PxTimelineEngineSetting;\n /** Target fps for the player's frame loop — a parameter of the `engine` chosen above, so it\n * sits beside it. Uncapped when absent; ignored by every engine except the frame loop. */\n frameRate?: number;\n /** §2.8: how long one pass takes, ms. */\n duration?: number;\n /** What starts it, and what happens when that condition ends. */\n trigger?: _PxTrigger;\n /** Wait before the first iteration, ms. Negative skips ahead. */\n delay?: number;\n /** Repeat count, or `'infinite'`. */\n iterations?: number | 'infinite';\n /** CSS `animation-fill-mode` — what shows outside the active time. NEVER spelled `fill`,\n * which is paint everywhere else in the format; the runtime view calls it `fill`. */\n fillMode?: 'forwards' | 'backwards' | 'both' | 'none';\n /** Forward, backward, or turning around each iteration. */\n direction?: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';\n}\n\nconst PxTimeTimelineSchema = implementsInterface<_PxTimeTimeline>()(px.object({\n type: px.literal('time').optional(),\n engine: PxTimelineEngineSchema,\n frameRate: px.number().optional(),\n // §2.8: duration is a property of the TIMELINE — how long one pass takes.\n duration: px.number().optional(),\n trigger: PxTriggerSchema.optional(),\n delay: px.number().optional(),\n iterations: px.union([px.number(), px.literal('infinite')]).optional(),\n // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)\n // — never `fill`, which is paint everywhere else in the format.\n fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none] as const).optional(),\n direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse] as const).optional(),\n}));\nconst _ck_PxTimeTimeline: KeysMatch<PxInfer<typeof PxTimeTimelineSchema>, _PxTimeTimeline> = true;\n\n// Scroll-driven modes — progress scrubbed from scroll position; nothing starts or\n// finishes it, so none of the clock knobs exist here. `'scroll'` tracks a scroller's\n// scroll offset, `'view'` tracks the subject's visibility through the viewport —\n// exactly WAAPI ScrollTimeline vs ViewTimeline (the old nested `scroll.kind` dissolved\n// into this discriminant). `mode` (shared by every timeline type) says who runs the\n// animation; `pin` is boolean-or-object (§2.2).\nconst scrollishTimelineShape = {\n // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe\n // span the scroll range maps onto.\n duration: px.number().optional(),\n // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto\n // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).\n iterations: px.number().optional(),\n engine: PxTimelineEngineSchema,\n frameRate: px.number().optional(),\n axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y] as const).optional(),\n source: px.enum([PxScrollSource.nearest, PxScrollSource.root] as const).optional(),\n subject: px.string().optional(), // 'parent' | 'scroller' | any CSS selector\n smoothing: px.number().optional(), // ms\n pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),\n range: PxScrollRangeSchema.optional(),\n};\n/** The keys both scroll-driven members carry. Locked the same way as the time member. */\nexport interface _PxScrollishTimelineShape {\n /** §2.8: under scrubbing, the keyframe span the scroll range maps onto. */\n duration?: number;\n /** Finite only — `'infinite'` cannot map onto a range (rule D4). */\n iterations?: number;\n /** How the animated attributes get updated. Default `auto`. */\n engine?: PxTimelineEngineSetting;\n /** Target fps for the player's frame loop (shared with the time member). */\n frameRate?: number;\n /** `block`/`inline` are writing-mode relative; `x`/`y` are physical. Default `'block'`. */\n axis?: 'block' | 'inline' | 'x' | 'y';\n /** `'nearest'` (default) scrollable ancestor, or `'root'`, the document. */\n source?: 'nearest' | 'root';\n /** `'parent'` · `'scroller'` · any CSS selector. */\n subject?: string;\n /** How long the playhead takes to catch up with the scrollbar, ms. */\n smoothing?: number;\n /** `true` to pin with defaults, or the parameters (review §2.2). */\n pin?: boolean | _PxTimelinePin;\n /** The slice of the timeline mapped onto progress 0..1. */\n range?: { start?: _PxScrollRangePoint; end?: _PxScrollRangePoint };\n}\n\n/** `interface X extends Y { type: 'scroll' }` — spelled as an intersection so the key-set\n * check below compares exactly the discriminant plus the shared shape. */\nexport type _PxScrollTimeline = _PxScrollishTimelineShape & { type: 'scroll' };\nexport type _PxViewTimeline = _PxScrollishTimelineShape & { type: 'view' };\n\nconst PxScrollTimelineSchema = implementsInterface<_PxScrollTimeline>()(\n px.object({ type: px.literal('scroll'), ...scrollishTimelineShape }));\nconst PxViewTimelineSchema = implementsInterface<_PxViewTimeline>()(\n px.object({ type: px.literal('view'), ...scrollishTimelineShape }));\nconst _ck_PxScrollTimeline: KeysMatch<PxInfer<typeof PxScrollTimelineSchema>, _PxScrollTimeline> = true;\nconst _ck_PxViewTimeline: KeysMatch<PxInfer<typeof PxViewTimelineSchema>, _PxViewTimeline> = true;\n\n/** @public @advanced */\nexport const PxTimelineSchema = px.discriminatedUnion('type', [\n PxTimeTimelineSchema, // first = the member an absent `type` selects\n PxScrollTimelineSchema,\n PxViewTimelineSchema,\n]);\n/** @public */\nexport type PxTimeline = PxInfer<typeof PxTimelineSchema>;\n\n\n// ============================================================================\n// ANIMATOR CONFIG\n// ============================================================================\n\n/**\n * Global animation configuration that applies to all animations in the document.\n * Defines timing, playback behavior, and rendering strategy.\n */\nexport interface _PxAnimatorConfig {\n\n /** RUNTIME VIEW ONLY (not wire — the wire spells it `timeline.engine`, on every\n * timeline type; same word both sides). How the animated attributes get updated;\n * see {@link PxTimelineEngineSetting}. */\n engine?: PxTimelineEngineSetting;\n\n /** RUNTIME VIEW ONLY (not wire — §2.8: the wire spells it `timeline.duration`).\n * Total animation duration in milliseconds. */\n duration?: number;\n\n /** Delay before animation starts in milliseconds */\n delay?: number;\n\n /**\n * Number of times to repeat the entire document timeline. Use `\"infinite\"` for endless loop.\n *\n * This repeats **all properties across all elements** as a unit. It is independent of\n * per-property `loop` configuration: if a property uses `loop`, its keyframes are already\n * expanded to fill `duration` before `iterations` takes effect — the two do not interfere,\n * but they do compose (a looping property inside an infinitely iterating document loops\n * within each iteration).\n */\n iterations?: number | \"infinite\";\n\n /** After a natural finish, snap the document back to its start state (same\n * mechanics as the trigger `reset` out-action). Off by default — the animation\n * holds its end state per `fill`. */\n resetOnFinish?: boolean;\n\n /**\n * Defines which values are applied before/after the active animation period\n * (maps directly to the Web Animations API `fill` option).\n * Defaults to `'forwards'` when not set so that elements hold their final\n * state after the animation ends — consistent with Lottie and other animation\n * runtimes. Without this default, seeking to the last frame would cause\n * elements to revert to their pre-animation state.\n */\n fill?: PxFillMode;\n\n /** Direction of animation playback */\n direction?: PxPlaybackDirection;\n\n /** RUNTIME VIEW ONLY — the wire spells it `timeline.frameRate`. Target frame rate for the\n * player's frame loop; ignored by WAAPI, React Native and the pre-rendered CSS export. */\n frameRate?: number;\n\n /** Trigger configuration for when animation should start */\n trigger?: PxTrigger;\n\n /** Named easings, animations and embedded fonts — referenced by elements and bindings */\n definitions?: PxDefinitions;\n\n /**\n * The bind-by-id document (a pre-rendered SVG + JS export, no `children`): the elements\n * already exist as markup, so instead of carrying them again the document lists WHICH\n * element plays WHICH named animations — see {@link _PxBinding}. Written by the editor's\n * exporter only; a self-contained document keeps its keyframes on the nodes (`node.animate`).\n *\n * @example [{ target: \"#_px_3cnuvau3\", animateWith: [\"a0\"] }]\n */\n bindings?: Array<PxBinding>;\n\n /**\n * RUNTIME VIEW ONLY (not wire) — what ADVANCES the animation. `'time'` (default)\n * is the wall clock; `'scroll'` is scroll-linked playback (\"scrubbing\"), matching\n * CSS scroll-driven animations.\n *\n * The wire spells this as `timeline.type` ('time' — or absent — vs 'scroll'/'view');\n * `flattenAnimatorTimeline` folds it into this field for the engines.\n * Distinct from `trigger.startOn`, which says what STARTS the animation: one\n * names the beginning, this one names what moves the playhead afterwards.\n * Design: app `svgeditor/animation/scroll-timeline.design.md`.\n */\n timelineSource?: string;\n\n /** RUNTIME VIEW ONLY (not wire) — scroll-timeline parameters, only consulted when\n * `timelineSource: 'scroll'`. The wire spells them inside `timeline`. */\n scroll?: PxScroll;\n\n /** What advances the animation — THE wire spelling (review §2.1): a discriminated\n * `{ type?: 'time' | 'scroll' | 'view', … }` object mirroring WAAPI's timeline\n * classes. Carries the playback dynamics (`trigger`/`delay`/`iterations`/`fillMode`/\n * `direction` for time; scroll geometry for scroll/view); the flat fields above\n * are the internal runtime view `flattenAnimatorTimeline` produces from it. */\n timeline?: PxTimeline;\n\n /** Debug helper: exposes the animator instance as `window[debugGlobalName]`. */\n debugGlobalName?: string;\n\n /**\n * WIRE FORMAT VERSION, `\"a.b.c\"` — the layering, not a build number:\n * `a.b` the PLAYER schema. A reader at `a.b` reads any file at `a.[b' <= b]`.\n * `c` the EDITOR's extension on top of that player schema (`meta.*`). The player\n * ignores it entirely; it is scoped to `(a,b)` and restarts when `b` moves.\n *\n * A mismatch on its own means NOTHING and must never warn: a bump says the schema gained\n * something, not that this document uses it. The number is consulted only when a\n * conversion needs it, or when unknown content was actually met — where it turns\n * \"something is wrong\" into \"written for 1.5, this build reads 1.1; update the player\".\n *\n * ABSENT means unknown, never \"oldest\": no version is assumed and no migration is guessed.\n */\n version?: string;\n}\n\n// ============================================================================\n// BINDINGS — the bind-by-id document (a pre-rendered SVG + JS export)\n// ============================================================================\n\n/**\n * One binding: WHICH element (`target`, `#id`-spelled like every element reference) plays\n * WHICH named animations (`animateWith` — names into `definitions.animations`, applied in\n * order, always an array).\n *\n * `…With` is the format's naming convention for \"by name, from `definitions`\" (review 2.12):\n * a bare key holds the thing itself (`node.animate` holds keyframes); `<key>With` holds an\n * ARRAY of names of the same concept (`animateWith` → `definitions.animations`). Two kinds of\n * reference, two spellings — `source` / `target` point at ELEMENTS (`#id`), `…With` points at\n * DEFINITIONS. Nothing else uses the convention yet; it is written down here so the next\n * key that refers to a definition by name spells it the same way.\n */\nexport interface _PxBinding {\n /** The element to animate — `'#id'`. */\n target: string;\n /** Names into `definitions.animations`, applied in order. */\n animateWith: Array<string>;\n}\n\n/** @public @advanced */\nexport const PxBindingSchema = implementsInterface<_PxBinding>()(px.object({\n target: px.string(),\n animateWith: px.array(px.string()),\n}));\n\n/** @public */\nexport type PxBinding = PxInfer<typeof PxBindingSchema>;\nconst _ck_PxBinding: KeysMatch<PxBinding, _PxBinding> = true; // the key sets are identical\n\n/**\n * RUNTIME VIEW ONLY (not wire) — a binding once `normalizeBindings` has resolved it: the\n * bare DOM id and the merged, normalized animation. A self-contained document yields the same\n * shape from every animated node, so the engines never see which kind of document they play.\n * @internal\n */\nexport interface PxNormalizedBinding {\n id: string;\n animate: PxAnimationDefinition;\n}\n\n// The WIRE format (review §2.1): playback dynamics live only inside `timeline` —\n// the flat spelling (`trigger`/`delay`/`iterations`/`fill`/`direction`/`resetOnFinish`/\n// `timelineSource`/`scroll`) is NOT part of the format. It exists only as the internal\n// runtime VIEW (`_PxAnimatorConfig`) that `flattenAnimatorTimeline` produces for the engines.\n/** @public @advanced */\nexport const PxAnimatorConfigSchema = implementsInterface<_PxAnimatorConfig>()(px.object({\n // (`mode`, `duration` and `frameRate` live INSIDE `timeline` on the wire — §2.8; they exist\n // at this level only on the runtime view, like the rest of the playback dynamics.)\n // THE spelling of \"what advances progress\" — clock / scroll / view (review §2.1).\n timeline: PxTimelineSchema.optional(),\n definitions: PxDefinitionsSchema.optional(),\n bindings: px.array(PxBindingSchema).optional(),\n debugGlobalName: px.string().optional(),\n // Declared HERE because this is a closed object: an undeclared key would be stripped by\n // `sanitize` and flagged by strict validation on our own files.\n version: px.string().optional(),\n}));\n\n/**\n * Global animation configuration that applies to all animations in the document.\n * Defines timing, playback behavior, and rendering strategy.\n *\n * This is the runtime VIEW type: the wire carries the playback dynamics nested in\n * `timeline` (see `PxAnimatorConfigSchema`), and `flattenAnimatorTimeline` folds them\n * into the flat fields the engines consume — so the type is a superset of the wire.\n * @public\n */\nexport type PxAnimatorConfig = _PxAnimatorConfig;\n\n\n\n// ============================================================================\n// NODE\n// ============================================================================\n\n/**\n * Per-attribute value shape on the element body. A property key carries either:\n * - a primitive (string/number) — static SVG attribute\n * - a number array — static number-LIST attribute (`strokeDasharray: [16, 16]`);\n * the canonical static form for list attrs (the \"5,5\" string form is also\n * accepted). Raw arrays are unambiguous — only plain OBJECTS need the\n * `{value}` wrapper.\n * - a `{value: …}` object — structured static parametric source (record-shaped\n * static value, used by attributes whose static representation is itself a\n * record — notably `transform: {value: PxTransformParts}`)\n * - a `{keyframes}` object — inline property animation\n *\n * The unified rule (primitive/array | `{value}` | `{keyframes}`) applies across\n * the format. For most attributes the `{value}` form is rarely used on the body\n * (a primitive suffices for static); for `transform` it is the canonical\n * structured-static shape. See `PxTransformValueSchema`.\n */\n/**\n * Value of an open (undeclared) attribute key on a node — i.e. a BODY attribute.\n *\n * STATIC ONLY (R2/J3): a body attr never carries its own animation. Animation goes\n * in the parallel `animate` channel, keyed by attribute name — that is what keeps a\n * document degradable to valid static SVG. `PxPropertyAnimationSchema` used to be a\n * member here, which made an inline `\"opacity\": {keyframes:[…]}` schema-LEGAL even\n * though nothing writes it and nothing reads it; worse, being an all-optional object\n * schema it was ALSO what (accidentally) validated the transform parts record. The\n * parts record is now declared explicitly, so the two are no longer conflated.\n * @public @advanced\n */\nexport const PxAttrValueSchema = px.union([\n px.string(),\n px.number(),\n px.array(px.number()),\n // Structured static — `{value: …}` (read-accepted transitional spelling, S1).\n // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).\n px.object({ value: px.defined() }),\n // Bare transform parts record — the canonical static `transform` on the wire (T2).\n PxTransformPartsSchema,\n]);\n\n/** Per-attribute value: primitive/number-array for static, `{value}` for structured\n * static, or a bare transform parts record. NEVER an animation — see `animate` (R2). * @public\n */\nexport type PxAttrValue = string | number | Array<number> | { value: any } | PxTransformParts;\n\n\n/**\n * Base interface for all SVG elements.\n * Named properties take precedence over the index signature when accessed.\n */\nexport interface _PxNode {\n\n /** SVG element type (e.g., \"circle\", \"rect\", \"path\", \"g\") */\n type: string;\n\n /** A REAL `type` attribute, for the elements that have one (`<feTurbulence\n * type=\"fractalNoise\">`, `<feFuncR type=\"table\">`) — `type` itself is the tag name.\n * The renderer turns this back into the attribute. */\n domType?: string;\n\n /** Text content of a `<text>` / `<tspan>` — the one text-content key (the DOM property name). */\n textContent?: string;\n\n /** Child elements (for container elements like <g>) */\n children?: PxNode[];\n\n /** Meta informaion about this element */\n meta?: any;\n\n /**\n * Player-effects bucket (transformation/repeater/maskedBy/strokeTrim/retime/ref)\n * emitted by the Editor's lightweight design format. `materializeNodeEffects`\n * materializes and removes these before any other normalization, so the\n * Player never observes a non-empty `effects` after entry-point processing.\n *\n * Typed against `PxEffectsSchema` (closed object — strict-mode validation\n * flags unknown effect keys). Adding a new effect requires extending the\n * `_PxEffects` interface AND the schema in lockstep.\n */\n effects?: PxEffects;\n\n /**\n * In-place property animations for this element. Same shape as the\n * `node.animate` values: string ref, array of refs, inline\n * definition (`{propName: PxPropertyAnimation}`), or mixed array.\n * The static initial value of an animated property is still carried as a\n * plain attribute on the body.\n */\n animate?: PxElementAnimation;\n\n /**\n * Inline style declarations for this element — camelCase CSS property names, exactly like\n * React's `style` prop (`whiteSpace`, `pointerEvents`, `mixBlendMode`) → value. The web\n * player writes them to `element.style`, React Native applies them as props; an explicit\n * attribute on the node wins. An OBJECT only: no CSS text, no preset names\n * (`definitions.styles` was removed — review 2.13).\n */\n style?: Record<string, string | number>;\n\n /**\n * Every other key is an SVG attribute under its camelCase DOM name — the spelling React\n * uses (`strokeWidth`, `fontSize`, `viewBox`, `clipPath`), which is what the editor writes.\n * The player renders it to the standard attribute (`stroke-width`) and accepts that kebab\n * spelling on the way in. A value is either a primitive (static) or a PxPropertyAnimation\n * (in-place animation `{ keyframes: [...] }`).\n */\n [camelCaseDomKey: string]: any;\n}\n\n// ============================================================================\n// PLAYER-EFFECTS BUCKET — INTERFACES + SCHEMAS (linked via `implementsInterface`)\n// ============================================================================\n//\n// Schemas for the `node.effects` payload emitted by the Editor's lightweight\n// design format. `materializeNodeEffects` (in `effects/PlayerEffectsUtil.ts`)\n// materializes and removes these before any other normalization, so the Player\n// never observes a non-empty `effects` after entry-point processing.\n//\n// Each effect is declared as a `_Px*` interface, paired with a `Px*Schema`\n// wrapped in `implementsInterface<_Px*>()(…)`. The runtime schema and the\n// compile-time interface drift together: a new field added to either without\n// matching the other is a TS error. `KeysMatch` asserts key-set equality so\n// renames are caught too. This is the same pattern used by `PxKeyframe`,\n// `PxLoop`, etc. earlier in this file.\n//\n// `effects/types.ts` re-exports these types so the applier internals\n// (`effects/*.ts`) can still `import from './types'` unchanged.\n\n/** Fixed-length 2-number tuple. `[x, y]` for positions, `[sx, sy]` for scale, …. @public */\nexport type PxVec2 = [number, number];\n\n/**\n * Animatable wire value — the ONE grammar for every animatable slot:\n *\n * T — raw static (non-object T)\n * { value: T } — structured static\n * PxPropertyAnimation — animated: `{value?, keyframes, loop?, autoOrient?}`\n *\n * The animated form IS `PxPropertyAnimation` — the exact object `node.animate`\n * channels use — so effect slots and node attributes share one schema, one\n * reader (`effects/transformParts.readAnimatable`) and one loop-materialization\n * path. `value` inside the animated form is the optional static baseline (see\n * `_PxPropertyAnimation.value`).\n *\n * Generic over the per-kf value type `T` for compile-time narrowing of the\n * static / `{value}` forms. The animated form uses the lib's non-generic\n * `PxKeyframe` (whose `value` is `any`) — kf values are read with care in the\n * applier (the visualModel walker / `interpParts` know per-property shapes).\n * @internal\n */\nexport type PxAnimatable<T> = T | { value: T } | _PxPropertyAnimation;\n\n// ORDER LAW (same medicine as PxKeyframeValueSchema): in every animatable union the\n// PropertyAnimation member comes BEFORE the bare `{value}` wrapper. Union.sanitize takes\n// the first member that validates, and default-mode object validation tolerates unknown\n// keys — wrapper-first would route `{value, keyframes}` to the wrapper and silently strip\n// the keyframes. A `{value}`-only static hitting PropertyAnimation first loses nothing\n// (it declares `value` too). Validity is order-independent; only repair cares.\n\n// PxAnimatable<number> — static number OR `{value}` static OR PxPropertyAnimation.\nconst PxAnimatableNumberSchema = px.union([\n px.number(),\n PxPropertyAnimationSchema,\n px.object({ value: px.number() }),\n]);\n\n// PxAnimatable<PxVec2> — static `[x,y]` OR `{value:[x,y]}` OR PxPropertyAnimation.\n// `as const` on the tuples is REQUIRED for TS to infer `[number, number]` (a\n// fixed-length tuple = `PxVec2`) instead of the looser `number[]`.\nconst PxAnimatableVec2Schema = px.union([\n px.tuple([px.number(), px.number()] as const),\n PxPropertyAnimationSchema,\n px.object({ value: px.tuple([px.number(), px.number()] as const) }),\n]);\n\n// PxAnimatable<string> — static `\"M…\"` OR `{value:\"M…\"}` OR PxPropertyAnimation.\nconst PxAnimatableStringSchema = px.union([\n px.string(),\n PxPropertyAnimationSchema,\n px.object({ value: px.string() }),\n]);\n\n// ── CHANNEL vs CONFIG (V2) — the split is declared in the SOURCE, twice over ──\n// An effect slot is one of exactly two kinds, and both declarations must agree:\n// channel (samplable per frame) → interface `PxAnimatable<T>` + a named\n// `PxAnimatable*Schema` in the schema\n// static config (read once) → the bare type + a bare `px.*()` slot\n// Never hand-inline the `[T, {value:T}, PxPropertyAnimation]` union at a slot:\n// the NAME is what makes the split machine-readable. Editor side mirrors this\n// with `isAnimatable: true` on the value's config.\n\n\n/** Per-part editor transform (`transformBy` effect). All parts optional and animatable. */\nexport interface _PxTransformByEffect {\n translate?: PxAnimatable<PxVec2>;\n rotate?: PxAnimatable<number>;\n scale?: PxAnimatable<PxVec2>;\n /** Skew (skewX) in degrees — a NUMBER (matches the editor's scalar skew part). */\n skew?: PxAnimatable<number>;\n origin?: PxAnimatable<PxVec2>;\n}\n/** @public @advanced */\nexport const PxTransformByEffectSchema = implementsInterface<_PxTransformByEffect>()(px.object({\n translate: PxAnimatableVec2Schema.optional(),\n rotate: PxAnimatableNumberSchema.optional(),\n scale: PxAnimatableVec2Schema.optional(),\n skew: PxAnimatableNumberSchema.optional(),\n origin: PxAnimatableVec2Schema.optional(),\n}));\n/** @public */\nexport type PxTransformByEffect = PxInfer<typeof PxTransformByEffectSchema>;\nconst _ck_PxTransformByEffect: KeysMatch<PxTransformByEffect, _PxTransformByEffect> = true;\n\n\n/** Per-copy repeater offsets. Each part is animatable; per-copy values scale\n * with the copy index `i` (translate/rotate/skew × i; scale per-axis `v^i`).\n * Static repeater values pass through as a structured `transform: {value:…}` on\n * the per-copy wrapper; animated values are emitted as `animate.transform.keyframes`\n * with each kf value scaled by `i`. See `effects/repeaterEffect.ts`.\n *\n * NAMING — why `repeater`, NOT `repeat` (SCHEMA-DESIGN R5 / issues N6): this\n * effect repeats in SPACE (N copies, each with a compounding per-copy delta), but\n * in an ANIMATION format a bare `repeat` reads as TIME — and this format has real\n * time-repetition concepts for it to be confused with: `animator.iterations`,\n * per-property `loop {segmentCount, alternate}`, and SVG/SMIL's own\n * `repeatCount`/`repeatDur`. The agent noun keeps it unambiguously spatial, and\n * matches the term the audience already knows (After Effects \"Repeater\",\n * Lottie shape item `rp`). Same principle as `maskedBy` over `mask`: prefer the\n * form that preserves the right MEANING over the grammatically uniform one. */\nexport interface _PxRepeaterEffect {\n copies?: number;\n translate?: PxAnimatable<PxVec2>;\n rotate?: PxAnimatable<number>;\n /** Per-copy skew (skewX) increment in degrees — copy `i` is skewed by `skew × i`. */\n skew?: PxAnimatable<number>;\n scale?: PxAnimatable<PxVec2>; // per-copy FACTOR (0.85 = 85% per copy), like every other scale\n origin?: PxAnimatable<PxVec2>;\n}\n/** @public @advanced */\nexport const PxRepeaterEffectSchema = implementsInterface<_PxRepeaterEffect>()(px.object({\n // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read\n // once at expansion time and never sampled — plain number, no `keyframes`.\n copies: px.number().optional(),\n translate: PxAnimatableVec2Schema.optional(),\n rotate: PxAnimatableNumberSchema.optional(),\n skew: PxAnimatableNumberSchema.optional(),\n scale: PxAnimatableVec2Schema.optional(),\n origin: PxAnimatableVec2Schema.optional(),\n}));\n/** @public */\nexport type PxRepeaterEffect = PxInfer<typeof PxRepeaterEffectSchema>;\nconst _ck_PxRepeaterEffect: KeysMatch<PxRepeaterEffect, _PxRepeaterEffect> = true;\n\n\n/** Mask source ref + standard `<mask>` attributes.\n * `source` is `#id` (canonical ref spelling, SCHEMA-DESIGN §4 E-5); bare `id` is legacy, read-only.\n * `start`/`size` are the `<mask>` viewport — its `x`/`y` and `width`/`height` in\n * `maskUnits` space. Absent = SVG's implicit mask region (−10% … 120% of the\n * bounding box), which is also the editor's default — so they only appear when a\n * document (typically an imported SVG) carries explicit mask bounds. */\nexport interface _PxMaskedByEffect {\n source?: string;\n maskType?: string;\n maskUnits?: string;\n maskContentUnits?: string;\n // Mask viewport in `maskUnits` space — the SVG `<mask>` attrs verbatim (B5).\n // NOT `start`/`size` pairs: those were the EDITOR's model FIELD names, never a\n // wire spelling — the editor has always written these four scalars, so the old\n // pair declaration meant the player silently dropped every non-default viewport.\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n}\n/** @public @advanced */\nexport const PxMaskedByEffectSchema = implementsInterface<_PxMaskedByEffect>()(px.object({\n source: px.string().optional(),\n maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha] as const).optional(),\n maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox] as const).optional(),\n maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox] as const).optional(),\n x: px.number().optional(),\n y: px.number().optional(),\n width: px.number().optional(),\n height: px.number().optional(),\n}));\n/** @public */\nexport type PxMaskedByEffect = PxInfer<typeof PxMaskedByEffectSchema>;\nconst _ck_PxMaskedByEffect: KeysMatch<PxMaskedByEffect, _PxMaskedByEffect> = true;\n\n\n/**\n * Clip-path effect — clips the host element to a vector path. `pathData` is a standard\n * animatable slot (same grammar as the body `d` ATTRIBUTE, which keeps SVG's own name):\n * static = plain SVG path-data string (one or more subpaths); animated = `{keyframes}`\n * whose values are `{pathData:\"M…\"}`.\n * At apply time an animated slot lands on the generated `<path>`'s `animate.d`, so the\n * player's frame loop rewrites the clip path's `d` attribute per frame. `clip-path`\n * is a live reference, so the browser re-clips each frame (unlike `<marker>` —\n * verified across SMIL/CSS/JS/WAAPI).\n *\n * At apply time the effect generates a `<clipPath><path d/></clipPath>` def and sets\n * `clip-path=\"url(#auto-id)\"` on the host (materializer pattern, like `maskedBy` /\n * gradient). See `effects/clipPathEffect.ts`.\n */\nexport interface _PxClipPathEffect {\n pathData?: PxAnimatable<string>;\n}\n/** @public @advanced */\nexport const PxClipPathEffectSchema = implementsInterface<_PxClipPathEffect>()(px.object({\n pathData: PxAnimatableStringSchema.optional(),\n}));\nexport type PxClipPathEffect = PxInfer<typeof PxClipPathEffectSchema>;\nconst _ck_PxClipPathEffect: KeysMatch<PxClipPathEffect, _PxClipPathEffect> = true;\n\n\n/**\n * Stroke-trim effect. `range[0..1]` is the visible fraction of the STROKE; `offset`\n * shifts the visible window along the path (also a fraction). Both are animatable.\n * `subPaths` says what that fraction is measured over: `separate` (default) trims\n * each sub-path against its own length; `combined` chains all descendant sub-path\n * lengths into one virtual path (\"Trim All As One\") so the window slides across\n * siblings — see `effects/strokeTrimEffect.ts`.\n *\n * NAME — renamed from `trimPath` (2026-08, hard rename, no legacy alias): this\n * trims the STROKE only. It emits `stroke-dasharray` / `stroke-dashoffset` (plus\n * `stroke-opacity` for the empty-range hide) and NEVER rewrites `d`, so the fill\n * is untouched. Lottie's same-named `ty:'tm'` is a path OPERATOR that rewrites\n * geometry (and therefore does change the fill) — the old name imported that\n * wrong mental model from the format most authors convert from.\n */\nexport interface _PxStrokeTrimEffect {\n offset?: PxAnimatable<number>;\n range?: PxAnimatable<PxVec2>;\n subPaths?: PxStrokeTrimSubPaths;\n}\n/** @public @advanced */\nexport const PxStrokeTrimEffectSchema = implementsInterface<_PxStrokeTrimEffect>()(px.object({\n offset: PxAnimatableNumberSchema.optional(),\n range: PxAnimatableVec2Schema.optional(),\n subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined] as const).optional(),\n}));\n/** @public */\nexport type PxStrokeTrimEffect = PxInfer<typeof PxStrokeTrimEffectSchema>;\nconst _ck_PxStrokeTrimEffect: KeysMatch<PxStrokeTrimEffect, _PxStrokeTrimEffect> = true;\n\n\n/** Ref-attr naming rule (see editor dev-docs/schema-design.md): `source` = ref to an EXTERNAL element\n * (clone/maskedBy/retime); `coreId` = a unit's own survivor; `partOf` = a derived node's host.\n *\n * `<use>` retime: pure timing — the source ref lives ONCE, on the parent `clone.source`\n * (review §4.3; retime's own duplicate `source` was removed outright — no consumer ever\n * read it: the materializer follows `href`). `start`/`timeCrop` in ms.\n * `timeCrop: [inMs, outMs]` is a VISIBILITY WINDOW on the document timeline — implemented\n * (2026-08) as an opacity gate on a player-side wrapper `<g>`, independent of the\n * `start`/`stretch` remap (see `effects/retimeEffect.ts`). */\nexport interface _PxRetimeEffect {\n start?: number;\n stretch?: number;\n timeCrop?: [number, number];\n}\n/** @public @advanced */\nexport const PxRetimeEffectSchema = implementsInterface<_PxRetimeEffect>()(px.object({\n start: px.number().optional(),\n stretch: px.number().optional(),\n timeCrop: px.tuple([px.number(), px.number()] as const).optional(),\n}));\n/** @public */\nexport type PxRetimeEffect = PxInfer<typeof PxRetimeEffectSchema>;\nconst _ck_PxRetimeEffect: KeysMatch<PxRetimeEffect, _PxRetimeEffect> = true;\n\n\n/**\n * `<use>` CLONE — merges the former `ref` + `retime` effects. A `<use>` is a clone\n * of something: `type`/`source` say WHAT it clones, `retime` says WHEN.\n * - `without: 'translate'` → content-ref: the source's own translate is left out (the\n * clone stays where the `<use>` put it, still rotates/scales with the source);\n * absent → direct / whole-element link (keeps translate). A future `'transform'`\n * value may leave out the whole transform.\n * - `source` = the source element ref, `#id` (canonical spelling, SCHEMA-DESIGN §4 E-5;\n * bare `id` is legacy, read-only). Lives once here; the player follows `href`.\n * - `retime` = optional time-shift (nested).\n * Omitted entirely when all-default (a bare `<use href>` carries no `clone` bucket).\n */\nexport interface _PxCloneEffect {\n without?: string;\n source?: string;\n retime?: _PxRetimeEffect;\n}\n/** @public @advanced */\nexport const PxCloneEffectSchema = implementsInterface<_PxCloneEffect>()(px.object({\n // Subtractive on purpose: the `<use>` can only point at one wrapper layer of the\n // source, so the choices form a ladder — 'translate' now, maybe 'transform' later.\n without: px.enum([PxCloneWithout.translate] as const).optional(),\n source: px.string().optional(),\n retime: PxRetimeEffectSchema.optional(),\n}));\n/** @public */\nexport type PxCloneEffect = PxInfer<typeof PxCloneEffectSchema>;\nconst _ck_PxCloneEffect: KeysMatch<PxCloneEffect, _PxCloneEffect> = true;\n\n\n/** A single color stop. `offset` is in `[0, 1]`; `color` is a CSS color\n * string (`#rrggbb`, `rgb(…)`, `rgba(…)`, or named). */\nexport interface _PxGradientStop {\n offset: number;\n color: string;\n}\n/** @public @advanced */\nexport const PxGradientStopSchema = implementsInterface<_PxGradientStop>()(px.object({\n offset: px.number(),\n color: px.string(),\n}));\n/** @public */\nexport type PxGradientStop = PxInfer<typeof PxGradientStopSchema>;\nconst _ck_PxGradientStop: KeysMatch<PxGradientStop, _PxGradientStop> = true;\n\n/** `PxAnimatable<Array<PxGradientStop>>` schema. Static is the bare array;\n * `{value: […]}` wraps the same; the animated form is `PxPropertyAnimation`\n * (one timeline whose each kf's `value` is the FULL stops array at that time).\n * LAW (SCHEMA-DESIGN R5, S9): stops are ONE animatable value — whole-array\n * snapshots on a single timeline, deliberately NO per-stop keyframes/easing\n * (gradient GEOMETRY animates per-slot with independent timelines). */\nconst PxAnimatableGradientStopsSchema = px.union([\n px.array(PxGradientStopSchema),\n px.object({ value: px.array(PxGradientStopSchema) }),\n PxPropertyAnimationSchema,\n]);\n\n/** Gradient paint effect — used by both `fillGradient` and `strokeGradient`\n * (same shape, different host attribute). Linear: `start`/`end`. Radial:\n * `center`/`radius`/`focal`. Stops animate as one timeline; geometry stays static. */\n// (The old `_PxGradientGeometryAnimation` per-scalar channel record —\n// `animate: {gradientX1: …}` — was REMOVED outright, read included: geometry\n// animates on the `start`/`end`/`center`/`radius`/`focal` slots. Backward compat dropped\n// deliberately. Frames-engine-only note still applies to animated geometry:\n// CSS/WAAPI cannot animate gradient endpoints; `mode: 'auto'` handles it.)\n\nexport interface _PxFillGradientEffect {\n type: PxGradientType; // 'linear' | 'radial'\n start?: PxAnimatable<PxVec2>; // linear start ([x1,y1]; review §4.2 — plain words, no abbreviations)\n end?: PxAnimatable<PxVec2>; // linear end ([x2,y2])\n center?: PxAnimatable<PxVec2>; // radial center ([cx,cy])\n radius?: PxAnimatable<number>; // radial radius (r)\n focal?: PxAnimatable<PxVec2>; // radial focal point ([fx,fy])\n stops?: PxAnimatable<Array<_PxGradientStop>>; // single animation timeline\n gradientUnits?: string; // PxUnits values\n spreadMethod?: string; // PxGradientSpreadMethod values\n gradientTransform?: string; // static only in v1\n}\n/** @public @advanced */\nexport const PxFillGradientEffectSchema = implementsInterface<_PxFillGradientEffect>()(px.object({\n // Contextual kind — the `type` convention, see `PxNodeBaseSchema.type`.\n type: px.enum([PxGradientType.linear, PxGradientType.radial] as const),\n start: PxAnimatableVec2Schema.optional(),\n end: PxAnimatableVec2Schema.optional(),\n center: PxAnimatableVec2Schema.optional(),\n radius: PxAnimatableNumberSchema.optional(),\n focal: PxAnimatableVec2Schema.optional(),\n stops: PxAnimatableGradientStopsSchema.optional(),\n gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox] as const).optional(),\n spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat] as const).optional(),\n gradientTransform: px.string().optional(),\n}));\n/** @public */\nexport type PxFillGradientEffect = PxInfer<typeof PxFillGradientEffectSchema>;\nconst _ck_PxFillGradientEffect: KeysMatch<PxFillGradientEffect, _PxFillGradientEffect> = true;\n\n/** Stroke gradient is the same shape as fill gradient; the difference is\n * only which host attribute (`fill` vs `stroke`) the applier rewrites. */\nexport type _PxStrokeGradientEffect = _PxFillGradientEffect;\n/** @public @advanced */\nexport const PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;\n/** @public */\nexport type PxStrokeGradientEffect = PxFillGradientEffect;\n\n/** Text-path effect on a `<text>` host. The path geometry is carried INLINE as\n * `pathData` (an SVG `d`; static for now, keyframed animation is a later step) — the\n * applier generates a `<path>` def from it and wraps the text's children in a native\n * `<textPath href=\"#…\">` at apply time. All SVG-native textPath attrs\n * (`lengthAdjust`, `method`, `spacing`, `startOffset`, `textLength`) ride on this\n * effect; `startOffset`/`textLength` accept the full `PxAnimatable<number>` shape.\n *\n * `pathOverflow` controls what happens to glyphs past the end of an OPEN path:\n * - `'extend'` (default): glyphs continue straight along the endpoint tangent\n * (Lottie / native-glyph behavior).\n * - `'clip'`: glyphs past the end disappear (native `<textPath>` behavior). */\nexport interface _PxTextPathEffect {\n pathData: string; // inline SVG `d`\n pathOverflow?: string; // 'clip' | 'extend' (default 'extend')\n lengthAdjust?: string; // 'spacing' | 'spacingAndGlyphs'\n method?: string; // 'align' | 'stretch'\n spacing?: string; // 'auto' | 'exact'\n startOffset?: PxAnimatable<number>;\n textLength?: PxAnimatable<number>;\n}\n/** @public @advanced */\nexport const PxTextPathEffectSchema = implementsInterface<_PxTextPathEffect>()(px.object({\n pathData: px.string(),\n pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend] as const).optional(),\n lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs] as const).optional(),\n method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch] as const).optional(),\n spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact] as const).optional(),\n startOffset: PxAnimatableNumberSchema.optional(),\n textLength: PxAnimatableNumberSchema.optional(),\n}));\n/** @public */\nexport type PxTextPathEffect = PxInfer<typeof PxTextPathEffectSchema>;\nconst _ck_PxTextPathEffect: KeysMatch<PxTextPathEffect, _PxTextPathEffect> = true;\n\n\n/**\n * `effects.text` — text-rendering options for a `<text>` node.\n *\n * `useGlyphs: true` tells the player to render this text from the embedded\n * per-glyph outlines in `definitions.fonts` (self-contained, no external\n * font) instead of a native `<text>`. See svga.text.design.md.\n */\nexport interface _PxTextEffect {\n useGlyphs?: boolean;\n}\n/** @public @advanced */\nexport const PxTextEffectSchema = implementsInterface<_PxTextEffect>()(px.object({\n useGlyphs: px.boolean().optional(),\n}));\nexport type PxTextEffect = PxInfer<typeof PxTextEffectSchema>;\nconst _ck_PxTextEffect: KeysMatch<PxTextEffect, _PxTextEffect> = true;\n\n\n/**\n * The full `node.effects` bucket. Closed — each known effect is declared\n * (strict-mode validation flags an unknown effect key as a wire-format drift).\n *\n * DESIGN LAW — attribute vs effect:\n * - An ATTRIBUTE is a value the browser consumes as-is on that element\n * (`fill=\"#f00\"`, `opacity`, `d`); animating it is \"this value over time\" —\n * one channel, zero structure. The test is STRUCTURE, not value-encoding\n * complexity: `transform` has a parts-record wire value but lands in one\n * attribute on the same element, so it stays an attribute.\n * - An EFFECT is anything whose realization requires structure — generating defs\n * (gradient, clipPath, maskedBy, textPath), wrapper nodes (transformation),\n * clones (repeater, clone), or geometry-derived multi-attr rewrites (strokeTrim).\n * - The same attribute name can sit on both sides, split by value: flat `fill`\n * is an attribute; gradient fill is an effect (no value of `fill` IS a\n * gradient — it needs a def + stops + a `url(#id)` indirection).\n * New features follow the same test: pattern fills / filters need defs → effects.\n *\n * COMPOSITION ORDER (SCHEMA-DESIGN §R5): one bag per element — JSON key order\n * carries NO meaning and is never read. The applier composes in one hard-coded\n * order, innermost → outermost:\n * glyphs/textPath → fill/strokeGradient → strokeTrim → repeater → maskedBy\n * → clipPath → clone-href+transformBy (retime = pass 2, time-remap only)\n * \"Other\" orders are expressed by STRUCTURE (nest elements), never by key order.\n * If authorable order is ever demanded: an explicit `effects.order: [names]`\n * extension — never key-order significance (JSON tooling silently reorders).\n */\nexport interface _PxEffects {\n transformBy?: _PxTransformByEffect;\n repeater?: _PxRepeaterEffect;\n maskedBy?: _PxMaskedByEffect;\n clipPath?: _PxClipPathEffect;\n strokeTrim?: _PxStrokeTrimEffect;\n clone?: _PxCloneEffect;\n fillGradient?: _PxFillGradientEffect;\n strokeGradient?: _PxStrokeGradientEffect;\n textPath?: _PxTextPathEffect;\n text?: _PxTextEffect;\n}\n/** @public @advanced */\nexport const PxEffectsSchema = implementsInterface<_PxEffects>()(px.object({\n transformBy: PxTransformByEffectSchema.optional(),\n repeater: PxRepeaterEffectSchema.optional(),\n maskedBy: PxMaskedByEffectSchema.optional(),\n clipPath: PxClipPathEffectSchema.optional(),\n strokeTrim: PxStrokeTrimEffectSchema.optional(),\n clone: PxCloneEffectSchema.optional(),\n fillGradient: PxFillGradientEffectSchema.optional(),\n strokeGradient: PxStrokeGradientEffectSchema.optional(),\n textPath: PxTextPathEffectSchema.optional(),\n text: PxTextEffectSchema.optional(),\n}));\n/** @public */\nexport type PxEffects = PxInfer<typeof PxEffectsSchema>;\nconst _ck_PxEffects: KeysMatch<PxEffects, _PxEffects> = true;\n\n/**\n * Walks `root` and validates every `node.effects` bucket against `PxEffectsSchema`.\n * Returns an array of human-readable warning strings (empty when all good).\n * Doesn't mutate the tree. Called by `createAnimatorImpl` before applying effects.\n *\n * Pass `strict: true` to also flag undeclared keys (useful in dev / tests).\n * @public @advanced\n */\nexport function validateNodeEffects(root: PxNode, options?: { strict?: boolean }): Array<string> {\n const warnings: Array<string> = [];\n // `path` is a human-readable breadcrumb prepended to each warning so the\n // reader can locate the offending node in the tree (e.g.\n // `root.children[0].children[2].effects.transformBy.translate: …`).\n const walk = (node: PxNode, path: string): void => {\n if (node && node.effects) {\n const ctx: PxValidationContext = { errors: [], warnings: [], strict: !!options?.strict };\n const ok = PxEffectsSchema.isValid(node.effects, ctx, [path + '.effects']);\n if (!ok) {\n for (const err of ctx.errors) warnings.push(err);\n }\n }\n if (node && Array.isArray(node.children)) {\n node.children.forEach((c, i) => walk(c, path + '.children[' + i + ']'));\n }\n };\n walk(root, 'root');\n return warnings;\n}\n\n/**\n * Cross-checks glyph-mode text against the embedded faces (review §2.5).\n *\n * A `definitions.fonts` key IS the face name, matched against the node's `font-family`\n * verbatim — so a name with no entry renders a row of □ placeholder boxes behind nothing but\n * a console warning. Nothing else catches that: the schema validates each side's SHAPE, never\n * that the two agree.\n *\n * Deliberately silent in two legal cases:\n * - the document embeds NO faces — browser-font text, a different situation entirely;\n * - a node carries no `font-family` — with exactly one face embedded the player resolves it\n * (`soleFont`), and with none there is nothing to name.\n *\n * The reverse (a face nothing references) is NOT reported: keeping the outlines of a text\n * whose glyph mode is currently off is legal and deliberate, so that toggling it back on\n * needs no font reload.\n */\nexport function validateGlyphFontRefs(root: PxNode, fonts: { [face: string]: unknown; } | undefined): Array<string> {\n if (!fonts || !Object.keys(fonts).length) return [];\n\n const problems: Array<string> = [];\n const walk = (node: PxNode, path: string, inherited: string | undefined, inGlyphText: boolean): void => {\n if (!node) return;\n // `font-family` inherits down the text tree, exactly as the renderer resolves it.\n const own = typeof node.fontFamily === 'string' ? node.fontFamily : undefined;\n const family = own ?? inherited;\n const isGlyphText = inGlyphText || (node.type === 'text' && !!node.effects?.text?.useGlyphs);\n\n // Report at the node that DECLARES the family — one problem per mistake, not one per\n // descendant that merely inherits it.\n if (isGlyphText && own && !Object.prototype.hasOwnProperty.call(fonts, own)) {\n const problem = path + ': glyph-mode text uses font-family \"' + own\n + '\", which has no entry in animator.definitions.fonts';\n if (!problems.includes(problem)) problems.push(problem);\n }\n if (Array.isArray(node.children)) {\n node.children.forEach((c, i) => walk(c, path + '.children[' + i + ']', family, isGlyphText));\n }\n };\n walk(root, 'root', undefined, false);\n return problems;\n}\n\n/**\n * Cross-checks named easing references against `definitions.easings` (review §2.9).\n *\n * A keyframe's `easing` is either a cubic-bezier array or the NAME of an entry in\n * `definitions.easings` — CSS keywords are deliberately not built in (player weight), so\n * `easing: \"ease-in-out\"` validates as a string, resolves to nothing, and plays LINEAR behind\n * one `console.warn`. That makes it the likeliest silent mistake in a generated document, and\n * the schema cannot catch it: it checks the shape of each side, never that the two agree.\n *\n * Only the wire spelling `easing` is read. The runtime view's `e` is an already-RESOLVED curve,\n * never a name, so it has nothing to cross-check.\n */\nexport function validateEasingRefs(root: PxNode, easings: { [name: string]: unknown; } | undefined): Array<string> {\n const problems: Array<string> = [];\n const walk = (node: unknown, path: string): void => {\n if (Array.isArray(node)) {\n node.forEach((item, i) => walk(item, path + '[' + i + ']'));\n return;\n }\n if (!node || typeof node !== 'object') return;\n\n const easing = (node as { easing?: unknown }).easing;\n if (typeof easing === 'string' && !(easings && Object.prototype.hasOwnProperty.call(easings, easing))) {\n const problem = path + '.easing: \"' + easing\n + '\" names no entry in animator.definitions.easings — it will play linear';\n if (!problems.includes(problem)) problems.push(problem);\n }\n for (const [key, value] of Object.entries(node as Record<string, unknown>)) {\n if (key === 'easing') continue; // already handled; a string has nothing to walk\n if (value && typeof value === 'object') walk(value, path + '.' + key);\n }\n };\n walk(root, 'root');\n return problems;\n}\n\n/**\n * Checks the `animator.version` stamp parses (review §2.10).\n *\n * The slot is `px.string()`, so `\"v1\"` validates and is then read as UNSTAMPED — the document\n * silently loses the one diagnostic that says which schema wrote it. Parsing is delegated to\n * {@link parseWireVersion} so this can never disagree with the reader.\n *\n * An ABSENT stamp is legal and silent: only a present-but-unparseable one is reported.\n */\nexport function validateVersionStamp(doc: PxAnimatedSvgDocument): Array<string> {\n const version = getAnimatorConfig(doc)?.version;\n if (version === undefined) return [];\n if (parseWireVersion(version) !== undefined) return [];\n return ['root.animator.version: ' + JSON.stringify(version)\n + ' is not a version stamp (\"a.b\" or \"a.b.c\") — it reads as unstamped'];\n}\n\n/**\n * Validates a WHOLE document against the wire schema — strictly, so undeclared keys are\n * reported too — plus every node's `effects` bucket and the glyph-font references. Returns\n * human-readable problems (`path: what is wrong`), empty when the document is sound; never\n * throws. The player itself only warns and skips what it cannot read; this is the one call\n * for tooling, CI and agents that want a yes/no answer before shipping a document.\n * @public\n */\nexport function validateDocument(doc: unknown, options?: { strict?: boolean }): Array<string> {\n // Strict (the default) rejects keys the schema does not declare — the right answer for a\n // document you are about to ship. `strict: false` tolerates them, which is what a READER\n // wants: an unknown key usually means a newer writer — worth a warning, never a refusal.\n const strict = options?.strict !== false;\n const ctx: PxValidationContext = { errors: [], warnings: [], strict };\n const problems: Array<string> = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ['root']) ? [] : [...ctx.errors];\n if (doc && typeof doc === 'object') {\n for (const w of validateNodeEffects(doc as PxNode, { strict })) {\n if (!problems.includes(w)) problems.push(w);\n }\n const defs = getAnimatorConfig(doc as PxAnimatedSvgDocument)?.definitions;\n for (const w of validateGlyphFontRefs(doc as PxNode, defs?.fonts)) {\n if (!problems.includes(w)) problems.push(w);\n }\n for (const w of validateEasingRefs(doc as PxNode, defs?.easings)) {\n if (!problems.includes(w)) problems.push(w);\n }\n for (const w of validateVersionStamp(doc as PxAnimatedSvgDocument)) {\n if (!problems.includes(w)) problems.push(w);\n }\n }\n return problems;\n}\n\n\n// ============================================================================\n// NODE\n// ============================================================================\n\n/**\n * Base shape for all SVG element nodes.\n * Open object: validated known keys + arbitrary SVG attributes whose values are\n * either primitives (static) or PxPropertyAnimation objects (in-place animation).\n * Non-recursive — excludes `children` (circular reference). Used for type extraction via PxInfer.\n *\n * `{ type:string, style?:…, [key:string]: string|number|PxPropertyAnimation }`\n * @public @advanced\n */\nexport const PxNodeBaseSchema = px.openObject({\n // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for \"what\n // kind of thing is this\", discriminated by its CARRIER — here the node TAG\n // (`rect`, `text`), and inside a sub-object that object's kind (`fillGradient.type`,\n // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so\n // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)\n // would add words that all mean \"type\" and still need the carrier to read.\n // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums\n // (issues V3), never of distinct key names.\n type: px.string(),\n // The escape hatch for elements that carry a REAL `type` attribute — `<feTurbulence\n // type=\"fractalNoise\">`, `<feFuncR type=\"table\">`, `<feColorMatrix type=\"saturate\">`.\n // `type` is taken by the tag name, so the attribute travels here and the renderer puts\n // it back (`PxAnimatorDOM.renderNode`, `PxRnRender`). Declared here — not merely\n // documented — because a wire key that is not in a schema is invisible to the\n // minifier's reserve list and gets renamed (dev-docs/plans/minification-boundary.md §1.1).\n domType: px.string().optional(),\n // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error\n // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.\n textContent: px.string().optional(),\n id: px.string().optional(),\n meta: px.any().optional(),\n // Player-effects bucket emitted by the Editor's lightweight design format.\n // Consumed and removed by `materializeNodeEffects` before any other normalization\n // (see `createAnimatorImpl`), so downstream code never sees it.\n effects: PxEffectsSchema.optional(),\n // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts\n // string ref / array of refs / inline definition / mixed array; mirrors\n // `node.animate` values and what `processNode` resolves at runtime.\n animate: PxElementAnimationSchema.optional(),\n style: px.record(px.union([px.string(), px.number()])).optional(),\n}, PxAttrValueSchema);\n\n// `let` so the lazy closure can capture the variable reference after assignment.\n// By the time the lazy resolves (first isValid/sanitize call), PxNodeSchema is assigned.\n// `PxNodeBaseSchema & { children?:PxNode[] }`\n/** @public @advanced */\nlet PxNodeSchema: PxSchema<any> = px.openObject({\n ...PxNodeBaseSchema._shape,\n children: px.lazy(() => px.array(PxNodeSchema), []).optional(),\n}, PxAttrValueSchema);\nexport { PxNodeSchema };\n\n/**\n * Base interface for all SVG elements.\n * Extends schema-derived typed fields; adds recursive children and the open\n * index signature for arbitrary SVG attributes under their camelCase DOM names\n * (cx, cy, r, fill, strokeWidth, …) — see `_PxNodeBase`.\n * Named properties take precedence over the index signature when accessed.\n * @public\n */\nexport interface PxNode extends PxInfer<typeof PxNodeBaseSchema> {\n children?: PxNode[];\n [camelCaseDomKey: string]: any;\n}\n\n\n// ============================================================================\n// SVG NODE (ROOT)\n// ============================================================================\n\n/**\n * Root SVG element containing the entire animated graphic.\n * Extends PxNode with SVG-specific properties and global configuration.\n */\nexport interface _PxSvgNode extends PxNode {\n\n /** SVG viewport width. `number` OR an SVG length string (`\"100%\"`, `\"12em\"`) —\n * percentages are legal SVG and appear in real documents. */\n width?: number | string;\n\n /** SVG viewport height — `number` or SVG length string, see `width`. */\n height?: number | string;\n\n /** FIXME - do we need it? SVG viewBox attribute defining coordinate system */\n viewBox?: string;\n\n /** Global animation configuration */\n animator?: PxAnimatorConfig;\n}\n\n/**\n * Extra fields present on the root SVG node, on top of PxNode.\n * Used for type extraction via PxInfer.\n *\n * `{ width?:number, height?:number, viewBox?:string, animator?:AnimatorConfig }`\n * @public @advanced\n */\nexport const PxSvgNodeRootSchema = px.object({\n // `\"100%\"` and other SVG length strings are legal here — a number-only slot rejected\n // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.\n width: px.union([px.number(), px.string()]).optional(),\n height: px.union([px.number(), px.string()]).optional(),\n viewBox: px.string().optional(),\n animator: PxAnimatorConfigSchema.optional(),\n});\n\n/**\n * Root SVG element containing the entire animated graphic.\n * Extends PxNode (inheriting the open index signature) plus schema-derived\n * SVG-root fields.\n * @public\n */\nexport interface PxSvgNode extends PxNode, Omit<PxInfer<typeof PxSvgNodeRootSchema>, 'animator'> {\n /** The RUNTIME-VIEW type, not the wire shape: in-memory documents may carry the\n * flat playback fields (`flattenAnimatorTimeline` output, prop overrides in the\n * RN/React wrappers), while `PxAnimatorConfigSchema` validates only the nested\n * `timeline` spelling on the wire (review §2.1). */\n animator?: PxAnimatorConfig;\n}\n\n\n// ============================================================================\n// DOCUMENT\n// ============================================================================\n\n/**\n * Root SVG document schema. Enforces `type === 'svg'` to distinguish from child nodes.\n * This is the root type for the entire file format.\n *\n * `{ type:'svg', style?:…, width?:number, height?:number,\n * viewBox?:string, animator?:AnimatorConfig, children?:PxNode[],\n * [svgAttr]: string|number|PxPropertyAnimation }`\n * @public @advanced\n */\nexport const PxAnimatedSvgDocumentSchema = px.openObject({\n ...PxNodeBaseSchema._shape,\n ...PxSvgNodeRootSchema._shape,\n type: px.literal('svg'), // override string → literal to require 'svg'\n children: px.array(PxNodeSchema).optional()\n}, PxAttrValueSchema);\n\n/**\n * The complete animated SVG document.\n * This is the root type for the entire file format.\n * @public\n */\nexport interface PxAnimatedSvgDocument extends PxSvgNode {\n}\n\n\n// ============================================================================\n// API INTERFACES\n// ============================================================================\n\n// -- Callbacks: one chain, three levels (API review §9, §5; dev-docs/reviews/api-surface-review.md §26.1) ----------------------------\n//\n// PxDiagnosticsConfig onWarn / onError / muteWarn / muteError — what `createDiagnostics` reads\n// PxEngineCallbacks + onPlay / onPause / onCancel / onFinish / onRemove — what an ENGINE takes\n// PxAnimatorCallbacks + onStop — what every PUBLIC surface takes\n//\n// Each level extends the one above, so a field is spelled once and the surfaces cannot drift.\n// The diagnostics rule (`onError` = this instance will not play; `onWarn` = it plays, but\n// something was ignored, degraded or misspelled) is written on `PxDiagnosticsConfig`.\n\n/**\n * The callbacks an ENGINE takes — the frame loop, WAAPI, React Native's sampler: the playback\n * lifecycle plus the diagnostics channel. Public surfaces take `PxAnimatorCallbacks`.\n * @public\n */\nexport interface PxEngineCallbacks extends PxDiagnosticsConfig {\n\n /** Callback executed when the animation starts or resumes. */\n onPlay?: () => void;\n\n /** Callback executed when the animation is paused. */\n onPause?: () => void;\n\n /** Callback executed when the animation is canceled. */\n onCancel?: () => void;\n\n /**\n * Callback executed when the animation reaches its end — it played every iteration, or\n * `finish()` was called. Not fired when playback is stopped early (pause / cancel / remove).\n */\n onFinish?: () => void;\n\n /** Callback executed when the animation is removed. */\n onRemove?: () => void;\n}\n\n/**\n * What every PUBLIC surface takes, inline and under the same names — `createAnimator({ onFinish })`,\n * `loadTagAnimators`, the pre-rendered entries, and `<PixodeskSvgAnimator onFinish />` on React,\n * Vue and React Native (review §9, §24): the engine's callbacks plus `onStop`, which fires after\n * any of `onPause` / `onCancel` / `onFinish` / `onRemove` — for callers who only care that\n * playback is no longer running, whatever the reason.\n *\n * ONE definition: the components derive their props from it instead of each spelling the same\n * names, which is how their comments had already started to drift.\n * @public\n */\nexport interface PxAnimatorCallbacks extends PxEngineCallbacks {\n onStop?: () => void;\n}\n\n\nexport type PxPoint2D = Array<number>;\n\n\n// ============================================================================\n// BEZIER PATH\n// ============================================================================\n\n/** Represents a vector path for SVG shape animations. */\nexport interface _PxBezierPath {\n\n /** An array of vertex points [[x, y], ...]. */\n v: Array<PxPoint2D>;\n\n /** An array of 'in' tangent handles for each vertex [[x, y], ...]. */\n i?: Array<PxPoint2D>;\n\n /** An array of 'out' tangent handles for each vertex [[x, y], ...]. */\n o?: Array<PxPoint2D>;\n\n /** A boolean indicating if the path is closed. */\n c?: boolean;\n}\n\n// `{ v:number[][], i?:number[][], o?:number[][], c?:boolean }`\n/** @public @advanced */\nexport const PxBezierPathSchema = implementsInterface<_PxBezierPath>()(px.object({\n v: px.array(px.array(px.number())),\n i: px.array(px.array(px.number())).optional(),\n o: px.array(px.array(px.number())).optional(),\n c: px.boolean().optional(),\n}));\n\n/** Represents a vector path for SVG shape animations. @public */\nexport type PxBezierPath = PxInfer<typeof PxBezierPathSchema>;\nconst _ck_PxBezierPath: KeysMatch<PxBezierPath, _PxBezierPath> = true; // the key sets are identical\n\n\n// ============================================================================\n// ANIMATOR API\n// ============================================================================\n\n/**\n * Basic animation controls common to all animator types.\n *\n * Generic over the platform's root-element type (`TRoot`) so this package stays\n * platform-neutral: the web player specializes it to the DOM `Element`, a\n * React Native player to its own view handle. Defaults to `unknown`.\n * @public\n */\nexport interface PxPlaybackApi<TRoot = unknown> {\n\n isReady(): boolean;\n\n /** Returns the root element for the animation (platform-specific type). */\n getRootElement(): TRoot | null;\n\n /** Returns true if the animation is currently running. */\n isPlaying(): boolean;\n\n /** Starts or resumes the animation. */\n play(): void;\n\n /** Pauses the animation at its current state. */\n pause(): void;\n\n /** Stops the animation and resets it to its initial state. */\n cancel(): void;\n\n}\n\n/**\n * The full programmatic control interface for an animation.\n *\n * ### The time contract (API review §3)\n *\n * Every engine — the browser's WAAPI, the frame loop, React Native — answers these the same way:\n *\n * - **Time is ms from the start of the WHOLE run**, iterations included; never ms within the\n * current iteration. A time slider therefore reads the same on every player instead of\n * jumping back each time the animation repeats.\n * - **A seek clamps to `[0, duration × iterations]`**, with no upper bound when `iterations`\n * is `'infinite'`.\n * - **A rate of 0 is rejected** with a warning, everywhere. Use `pause()`.\n *\n * The maths behind it lives in `playback/PxPlaybackTime.ts`, so there is one implementation\n * rather than one per engine.\n * @public\n */\nexport interface PxAnimatorApi<TRoot = unknown> extends PxPlaybackApi<TRoot> {\n\n /** Jumps to the end of the animation and holds the final state. */\n finish(): void;\n\n /**\n * Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse.\n * A rate of 0 — or a non-finite one — is rejected with a warning; use `pause()`.\n */\n setPlaybackRate(rate: number): void;\n\n /** Current playback time, ms from the start of the whole run. `null` before ready. */\n getCurrentTime(): number | null;\n\n /** Seeks, ms from the start of the whole run; clamped to `[0, duration × iterations]`. */\n setCurrentTime(time: number): void;\n\n /**\n * Current position as 0–1 of the whole run. `null` before ready.\n *\n * The span is `duration × iterations`, or ONE iteration when `iterations` is `'infinite'`\n * (where the value wraps) — the same rule the components' `progress` prop already uses.\n */\n getCurrentProgress(): number | null;\n\n /** Seeks to 0–1 of the whole run, clamped to `[0, 1]`. The twin of `getCurrentProgress`. */\n setCurrentProgress(progress: number): void;\n\n /** Stops the animation and cleans up all associated resources. */\n destroy(): void;\n}\n\n/**\n * The imperative handle a framework component exposes through its ref: the player API minus\n * what the component itself owns — `isReady` (the document is inline, so it is always ready),\n * `getRootElement` (the framework renders it) and `destroy` (unmounting does it).\n *\n * ONE definition (review §9). `ReactAnimatorApi`, `VueAnimatorApi` and `RnAnimatorApi` are\n * aliases of this, so the three can no longer drift — they had: React Native's\n * `setPlaybackRate` comment had already lost \"negative plays backwards\".\n * @public\n */\nexport type PxAnimatorHandle = Omit<PxAnimatorApi, 'isReady' | 'getRootElement' | 'destroy'>;\n\n\n// ============================================================================\n// DEEP VALIDATION\n// ============================================================================\n\n/** @public @advanced */\nexport interface PxValidationResult {\n valid: boolean;\n errors: Array<string>;\n}\n\n/**\n * The pass/fail form of {@link validateDocument}, NON-strict — unknown keys are tolerated —\n * for readers that want a flag plus messages rather than a list.\n *\n * One implementation (review §10). This used to run the schema on its own and answer\n * `'Document failed schema validation'` without ever saying what failed; now every problem\n * `validateDocument` can name comes back with its path. Non-strict on purpose: the editor calls\n * this on OPEN, where a key from a newer version is worth a warning, never a refusal.\n * @public @advanced\n */\nexport function isValidPxDocument(doc: unknown): PxValidationResult {\n const errors = validateDocument(doc, { strict: false });\n return { valid: errors.length === 0, errors };\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxAnimatedSvgDocument } from '../format/PxAnimatorTypes';\n\n\n/**\n * Generates a unique ID with a random suffix.\n * Format: _px_{random base36 string}\n */\nlet _idCounter = 0;\n/** @internal */\nexport function generateUniqueId(): string {\n const timestamp = Date.now().toString(36);\n const counter = (++_idCounter).toString(36);\n const random = Math.random().toString(36).substring(2, 6);\n return '_px_' + timestamp + counter + random;\n}\n\n/**\n * Deep clones a JSON-like value (objects, arrays, primitives).\n * Does not handle special types like Date, Map, Set, functions, etc.\n * @internal\n */\nexport function deepClone<T>(value: T): T {\n if (value === null || typeof value !== 'object') return value;\n if (Array.isArray(value)) return value.map(item => deepClone(item)) as T;\n\n const obj = value as Record<string, unknown>;\n\n const cloned: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n cloned[key] = deepClone(obj[key]);\n }\n return cloned as T;\n}\n\n/**\n * Regenerates all IDs in the document and updates references.\n *\n * This function:\n * 1. Deep clones the document to avoid mutating the original\n * 2. Traverses all nodes and regenerates IDs, keeping a mapping of old → new\n * 3. Updates all references to old IDs in attributes:\n * - Hash references: \"#old-id\" → \"#new-id\" (href, xlink:href)\n * - URL references: \"url(#old-id)\" → \"url(#new-id)\" (fill, clip-path, mask, marker, etc.)\n * - Style URL references: { offsetPath: \"url(#old-id)\" }\n *\n * @param doc - The animated SVG document to process\n * @returns A new document with regenerated IDs\n * @public @advanced\n */\nexport function generateNewIds(doc: PxAnimatedSvgDocument): PxAnimatedSvgDocument {\n // Deep clone the document\n const cloned: PxAnimatedSvgDocument = deepClone(doc);\n\n // Map of old ID → new ID\n const idMap = new Map<string, string>();\n\n // Attributes that contain hash references (#id)\n const hashRefAttrs = new Set(['href', 'xlink:href']);\n\n // Attributes that contain url(#id) references\n const urlRefAttrs = new Set([\n 'fill', 'stroke', 'clip-path', 'clipPath', 'mask',\n 'marker', 'marker-start', 'marker-mid', 'marker-end',\n 'filter', 'flood-color', 'lighting-color'\n ]);\n\n // Attributes that contain direct ID references (no # or url()). `source` is one\n // only inside an effect bucket (`maskedBy.source`, `clone.source`) — the scroll\n // timeline also has a `source` key ('nearest' | 'root'), which is not an id.\n const directIdRefAttrs = new Set(['targetId', 'boundElementId']);\n const isEffectSourceRef = (key: string, parentKey: string | undefined) =>\n key === 'source' && (parentKey === 'maskedBy' || parentKey === 'clone');\n\n // Phase 1: Collect all IDs and generate new ones\n function collectIds(node: any): void {\n if (!node || typeof node !== 'object') return;\n\n if (node.id && typeof node.id === 'string') {\n const oldId = node.id;\n const newId = generateUniqueId();\n idMap.set(oldId, newId);\n node.id = newId;\n } else if (node.animate) {\n // An animated node needs an id so the animation can bind to its rendered element.\n node.id = generateUniqueId();\n }\n\n // Process children\n if (Array.isArray(node.children)) {\n for (const child of node.children) {\n collectIds(child);\n }\n }\n }\n\n // Phase 2: Update all references to old IDs\n function updateRefs(node: any, parentKey?: string): void {\n if (!node || typeof node !== 'object') return;\n\n for (const [key, value] of Object.entries(node)) {\n if (key === 'children') {\n if (Array.isArray(value)) {\n for (const child of value) {\n updateRefs(child);\n }\n }\n continue;\n }\n\n if (typeof value === 'string') {\n // Check for hash references: href=\"#old-id\"\n if (hashRefAttrs.has(key) && value.startsWith('#')) {\n const oldId = value.slice(1);\n const newId = idMap.get(oldId);\n if (newId) {\n node[key] = '#' + newId;\n }\n }\n // Check for url() references: fill=\"url(#old-id)\"\n else if (urlRefAttrs.has(key)) {\n node[key] = replaceUrlRefs(value, idMap);\n }\n // Check for direct ID references: source=\"#_px_xxx\" (canonical `#id`,\n // SCHEMA-DESIGN §4 E-5) or bare source=\"_px_xxx\" (legacy) —\n // rewrite preserving the incoming spelling.\n else if (directIdRefAttrs.has(key) || isEffectSourceRef(key, parentKey)) {\n const hasHash = value.startsWith('#');\n const newId = idMap.get(hasHash ? value.slice(1) : value);\n if (newId) {\n node[key] = hasHash ? '#' + newId : newId;\n }\n }\n // Check for url() in any string value (e.g., in style strings)\n else if (value.includes('url(#')) {\n node[key] = replaceUrlRefs(value, idMap);\n }\n }\n // Check style object for url() references\n else if (key === 'style' && typeof value === 'object' && value !== null) {\n for (const [styleProp, styleValue] of Object.entries(value)) {\n if (typeof styleValue === 'string') {\n (value as any)[styleProp] = replaceUrlRefs(styleValue, idMap);\n }\n }\n }\n // Recursively process nested objects (effect buckets carry source/targetId refs;\n // in-place animated values like { keyframes: [{ value: \"url(#grad)\" }] }\n // also need ref rewriting on string values they contain).\n else if (typeof value === 'object' && value !== null) {\n updateRefs(value, key);\n }\n }\n }\n\n collectIds(cloned);\n updateRefs(cloned);\n\n // Re-point the bindings of a bind-by-id document. `target` is `#id`-spelled (review\n // §3.2) — strip for the lookup, keep the spelling on the way out.\n const docBindings = cloned.animator?.bindings;\n if (Array.isArray(docBindings)) {\n const updatedBindings = docBindings.map(binding => {\n const hashed = binding.target.startsWith('#');\n const id = hashed ? binding.target.slice(1) : binding.target;\n const newId = idMap.get(id) ?? id;\n return { ...binding, target: hashed ? '#' + newId : newId };\n });\n cloned.animator = { ...cloned.animator, bindings: updatedBindings };\n }\n\n return cloned;\n}\n\n/**\n * Replaces url(#old-id) references in a string with new IDs from the map.\n */\nfunction replaceUrlRefs(value: string, idMap: Map<string, string>): string {\n return value.replace(/url\\(#([^)]+)\\)/g, (match, oldId) => {\n const newId = idMap.get(oldId);\n return newId ? 'url(#' + newId + ')' : match;\n });\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { PxBezierPath, PxTransformParts } from '../format/PxAnimatorTypes';\n\n\n/**\n * Converts a PxBezierPath to an SVG path string.\n * Control points (i, o) are treated as ABSOLUTE coordinates.\n * @param {PxBezierPath} path\n * @returns {string}\n */\n/**\n * @param forceCurves Emit EVERY segment (incl. the closing one) as a cubic `C`, even when\n * its control points are degenerate (a straight line). Needed for keyframe values the\n * BROWSER interpolates (WAAPI / CSS `path()`): CSS only interpolates paths with\n * IDENTICAL command sequences, so an opportunistic `L` in one keyframe vs a `C` in the\n * next (e.g. a round-corner radius animating from 0) turns the whole animation\n * DISCRETE — it flips at 50% instead of morphing.\n * @internal\n */\nexport function bezierToSvgPath(path: PxBezierPath, forceCurves = false): string {\n const v = path.v;\n const i = path.i;\n const o = path.o;\n const c = path.c;\n\n if (!v.length) return \"\";\n\n const d: Array<string> = [];\n const len = v.length;\n d.push(\"M\" + v[0][0] + \",\" + v[0][1]);\n\n for (let idx = 1; idx < len; idx++) {\n const prevV = v[idx - 1];\n const prevO = o?.[idx - 1] ?? prevV;\n const currI = i?.[idx] ?? v[idx];\n const currV = v[idx];\n\n // Check if it's a straight line (control points coincide with vertices)\n const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) &&\n (currI[0] === currV[0] && currI[1] === currV[1]);\n\n if (isLine) {\n d.push(\"L\" + currV[0] + \",\" + currV[1]);\n } else {\n // Control points are absolute coordinates\n d.push(\"C\" + prevO[0] + \",\" + prevO[1] + \",\" + currI[0] + \",\" + currI[1] + \",\" + currV[0] + \",\" + currV[1]);\n }\n }\n\n if (c && len > 0) {\n const lastV = v[len - 1];\n const lastO = o?.[len - 1] ?? lastV;\n const firstI = i?.[0] ?? v[0];\n const firstV = v[0];\n\n // Check if closing segment is a straight line\n const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) &&\n (firstI[0] === firstV[0] && firstI[1] === firstV[1]);\n\n if (!isLine) {\n d.push(\"C\" + lastO[0] + \",\" + lastO[1] + \",\" + firstI[0] + \",\" + firstI[1] + \",\" + firstV[0] + \",\" + firstV[1]);\n }\n\n d.push(\"z\");\n }\n\n return d.join(\"\");\n}\n\n/**\n * @param {number} a \n * @param {number} b \n * @param {number} t \n * @returns {number}\n */\nexport function interpolateNum(a: number, b: number, t: number): number {\n return a + (b - a) * t;\n}\n\n\n/**\n * @param {Array<number>} a \n * @param {Array<number>} b \n * @param {number} t \n * @returns {Array<number>}\n */\nexport function interpolateVec(a: Array<number>, b: Array<number>, t: number): Array<number> {\n const res: Array<number> = [];\n const count = Math.max(a.length, b.length);\n for (let i = 0; i < count; i++) {\n res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);\n }\n return res;\n}\n\n/**\n * Interpolates between two color arrays [r, g, b] or [r, g, b, a].\n * Normalizes both colors to 4 elements, defaulting alpha to 1 if missing.\n */\nexport function interpolateColor(a: Array<number>, b: Array<number>, t: number): Array<number> {\n return [\n interpolateNum(a[0] || 0, b[0] || 0, t),\n interpolateNum(a[1] || 0, b[1] || 0, t),\n interpolateNum(a[2] || 0, b[2] || 0, t),\n interpolateNum(a[3] === undefined ? 1 : a[3], b[3] === undefined ? 1 : b[3], t)\n ];\n}\n\n/**\n * Interpolates between two arrays of bezier paths.\n * @param paths1 The starting array of paths.\n * @param paths2 The ending array of paths.\n * @param progress The interpolation progress from 0.0 to 1.0.\n * @internal\n */\nexport function interpolateBeziers(\n paths1: Array<PxBezierPath>,\n paths2: Array<PxBezierPath>,\n progress: number\n): Array<PxBezierPath> {\n const count = Math.max(paths1.length, paths2.length);\n const res: Array<PxBezierPath> = [];\n for (let i = 0; i < count; i++) {\n res.push(interpolateBezier(paths1[i], paths2[i], progress));\n }\n return res;\n}\n\n/**\n * Interpolates between two bezier paths.\n * Control points (i, o) are treated as ABSOLUTE coordinates.\n * When control points are missing, they default to the vertex position.\n * @param {PxBezierPath} path1\n * @param {PxBezierPath} path2\n * @param {number} progress\n * @returns {PxBezierPath}\n */\nexport function interpolateBezier(\n path1: PxBezierPath | undefined,\n path2: PxBezierPath | undefined,\n progress: number\n): PxBezierPath {\n if (!path1 || !path2) return path1 || path2 || { v: [] };\n\n const t = Math.min(Math.max(progress, 0), 1);\n const len = Math.min(path1.v.length, path2.v.length);\n\n const v: Array<Array<number>> = [];\n const i: Array<Array<number>> = [];\n const o: Array<Array<number>> = [];\n\n for (let idx = 0; idx < len; idx++) {\n const v1 = path1.v[idx];\n const v2 = path2.v[idx];\n v.push(interpolateVec(v1, v2, t));\n\n // For absolute control points, default to vertex position (straight line)\n const i1 = path1.i?.[idx] ?? v1;\n const i2 = path2.i?.[idx] ?? v2;\n i.push(interpolateVec(i1, i2, t));\n\n const o1 = path1.o?.[idx] ?? v1;\n const o2 = path2.o?.[idx] ?? v2;\n o.push(interpolateVec(o1, o2, t));\n }\n\n return { v, i: i.length ? i : undefined, o: o.length ? o : undefined, c: path1.c ?? path2.c };\n}\n\n\n/**\n * Remap a number from one range to another.\n *\n * @param {number} value - The input value.\n * @param {number} inMin - Lower bound of the input range.\n * @param {number} inMax - Upper bound of the input range.\n * @param {number} outMin - Lower bound of the output range.\n * @param {number} outMax - Upper bound of the output range.\n * @returns The remapped value.\n */\nexport function remap(\n value: number,\n inMin: number,\n inMax: number,\n outMin: number,\n outMax: number\n): number {\n if (inMax === inMin) return outMin; // avoid divide-by-zero\n const t = (value - inMin) / (inMax - inMin);\n return outMin + t * (outMax - outMin);\n}\n\n/**\n * Solves for the parameter t such that the cubic bezier X(t) = x,\n * where the bezier has control point x-coordinates p1x and p2x\n * (endpoints are fixed at x=0 and x=1).\n * Uses Newton-Raphson with bisection fallback.\n */\nexport function solveCubicBezierX(p1x: number, p2x: number, x: number): number {\n if (x <= 0) return 0;\n if (x >= 1) return 1;\n\n const cx = 3 * p1x;\n const bx = 3 * (p2x - p1x) - cx;\n const ax = 1 - cx - bx;\n\n function sampleX(t: number) { return ((ax * t + bx) * t + cx) * t; }\n function sampleDX(t: number) { return (3 * ax * t + 2 * bx) * t + cx; }\n\n let t2 = x;\n let t0 = 0;\n let t1 = 1;\n\n for (let i = 0; i < 8; i++) {\n const x2 = sampleX(t2) - x;\n if (Math.abs(x2) < 1e-6) return t2;\n const d2 = sampleDX(t2);\n if (Math.abs(d2) < 1e-6) break;\n t2 -= x2 / d2;\n }\n\n t2 = x;\n while (t0 < t1) {\n const x2 = sampleX(t2);\n if (Math.abs(x2 - x) < 1e-6) return t2;\n if (x > x2) t0 = t2;\n else t1 = t2;\n t2 = (t1 + t0) / 2;\n }\n\n return t2;\n}\n\n/**\n * Creates a cubic-bezier easing function.\n * @param easing An array of four numbers [x1, y1, x2, y2] defining the bezier curve.\n * @returns A function that takes a progress value (0-1) and returns an eased value.\n * @internal\n */\nexport function cubicBezier(easing: [number, number, number, number]) {\n const [p1x, p1y, p2x, p2y] = easing;\n\n const cy = 3 * p1y;\n const by = 3 * (p2y - p1y) - cy;\n const ay = 1 - cy - by;\n\n function sampleCurveY(t: number) { return ((ay * t + by) * t + cy) * t; }\n\n return function (x: number) {\n return sampleCurveY(solveCubicBezierX(p1x, p2x, x));\n };\n}\n\ntype Point2 = [number, number];\n\nfunction lerp2(a: Point2, b: Point2, t: number): Point2 {\n return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];\n}\n\n/**\n * Splits a cubic bezier curve at parameter t using De Casteljau's algorithm.\n * Returns the left and right sub-curves as 4-point tuples.\n * @internal\n */\nexport function subdivideCubicBezier(\n p0: Point2, p1: Point2, p2: Point2, p3: Point2, t: number\n): { left: [Point2, Point2, Point2, Point2], right: [Point2, Point2, Point2, Point2] } {\n const q0 = lerp2(p0, p1, t);\n const q1 = lerp2(p1, p2, t);\n const q2 = lerp2(p2, p3, t);\n const r0 = lerp2(q0, q1, t);\n const r1 = lerp2(q1, q2, t);\n const s = lerp2(r0, r1, t);\n return {\n left: [p0, q0, r0, s],\n right: [s, r1, q2, p3]\n };\n}\n\ntype Easing = [number, number, number, number];\n\n/**\n * Splits a CSS cubic-bezier easing [x1,y1,x2,y2] at a given x-axis fraction.\n * Each half is re-normalized to map [0,0]→[1,1].\n * Returns undefined for either half if the input is undefined (linear) or the split is degenerate.\n * @internal\n */\nexport function splitEasing(\n easing: Easing | undefined,\n xFraction: number\n): { left: Easing | undefined, right: Easing | undefined } {\n if (!easing) return { left: undefined, right: undefined };\n if (xFraction <= 0) return { left: undefined, right: easing };\n if (xFraction >= 1) return { left: easing, right: undefined };\n\n const [x1, y1, x2, y2] = easing;\n const t = solveCubicBezierX(x1, x2, xFraction);\n\n const p0: Point2 = [0, 0];\n const p1: Point2 = [x1, y1];\n const p2: Point2 = [x2, y2];\n const p3: Point2 = [1, 1];\n\n const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);\n\n // Split point coordinates\n const sx = left[3][0];\n const sy = left[3][1];\n\n let leftEasing: Easing | undefined;\n if (sx > 1e-9 && Math.abs(sy) > 1e-9) {\n leftEasing = [\n left[1][0] / sx, left[1][1] / sy,\n left[2][0] / sx, left[2][1] / sy\n ];\n }\n\n let rightEasing: Easing | undefined;\n const rx = 1 - sx;\n const ry = 1 - sy;\n if (rx > 1e-9 && Math.abs(ry) > 1e-9) {\n rightEasing = [\n (right[1][0] - sx) / rx, (right[1][1] - sy) / ry,\n (right[2][0] - sx) / rx, (right[2][1] - sy) / ry\n ];\n }\n\n return { left: leftEasing, right: rightEasing };\n}\n\n/**\n * Reverses a cubic-bezier easing for backward playback.\n * [x1,y1,x2,y2] → [1-x2, 1-y2, 1-x1, 1-y1].\n * @internal\n */\nexport function reverseEasing(easing: Easing | undefined): Easing | undefined {\n if (!easing) return undefined;\n return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];\n}\n\n/**\n * Converts a color from a [r, g, b, a] array (where values are 0-1) to an rgba() or rgb() CSS string.\n * @param color The color array.\n * @internal\n */\nexport function toRGBA(color: Array<number>): string {\n const r = Math.round(color[0] * 255);\n const g = Math.round(color[1] * 255);\n const b = Math.round(color[2] * 255);\n return color.length === 4 ?\n 'rgba(' + r + ',' + g + ',' + b + ',' + color[3] + ')' :\n 'rgb(' + r + ',' + g + ',' + b + ')';\n}\n\n/** Parse rgb/rgba string to normalized array */\nexport function parseRgba(s: string): number[] {\n const inner = s.match(/rgba?\\((.*)\\)/)?.[1];\n if (!inner) throw new Error('Invalid rgb/rgba format');\n const parts = inner.split(',').map(v => +v.trim());\n return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...(parts[3] !== undefined ? [parts[3]] : [])];\n}\n\n/** Parse hex string to normalized array (#RGB, #RGBA, #RRGGBB, #RRGGBBAA) */\nfunction parseHex(s: string): number[] {\n const hex = s.slice(1); // Remove '#'\n const isShort = hex.length <= 4; // #RGB or #RGBA vs #RRGGBB or #RRGGBBAA\n\n const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);\n const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);\n const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);\n const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;\n\n const result = [\n parseInt(r, 16) / 255,\n parseInt(g, 16) / 255,\n parseInt(b, 16) / 255\n ];\n\n if (a !== null) {\n result.push(parseInt(a, 16) / 255);\n }\n\n return result;\n}\n\n//// FIXME - support normalization of config from different formats\n/** Parse color string (hex or rgb/rgba) to normalized [r, g, b] or [r, g, b, a] array (0-1 range) */\nexport function parseColor(s: any): number[] | undefined {\n if (!s) return undefined;\n if (Array.isArray(s)) return s;\n if (typeof s !== 'string') return undefined;\n if (s.startsWith('#')) {\n return parseHex(s);\n } else if (s.startsWith('rgb')) {\n return parseRgba(s);\n } else {\n // FIXME - come up with some solution how to report errors...\n console.warn('Unsupported color format: ' + s);\n }\n return undefined;\n}\n\n/** @internal */\nexport const PX_COLOR_ATTR_NAMES = new Set([\"color\", \"fill\", \"flood-color\", \"lighting-color\", \"stop-color\", \"stroke\"]);\n/** @internal */\nexport const PX_TRANSFORM_FN_NAMES = new Set([\"translate\", \"rotate\", \"scale\", \"skew\"]);\n/** @internal */\nexport const PX_PCT_BASED_ATTR_NAMES = new Set([\"offset-distance\", \"offsetDistance\"]);\n\n/**\n * Compose a `PxTransformParts` record into a single SVG/CSS transform string in\n * the canonical order:\n *\n * translate, translate(+origin), rotate, scale, translate(-origin)\n *\n * Each part is omitted when not present. `origin` becomes a `translate(+o)` /\n * `translate(-o)` pair surrounding the rotate/scale segment — the SVG-native\n * way to render a transform-origin pivot.\n *\n * @param parts the parts record (translate / rotate / scale / origin)\n * @param opts.withUnits when true (default), translates use `px` and rotate\n * uses `deg` — required for CSS / WebAnimations keyframes. When false, no\n * units are emitted — required for the SVG `transform` attribute.\n * @internal\n */\nexport function composeTransformParts(\n parts: PxTransformParts | null | undefined,\n opts?: { withUnits?: boolean }\n): string {\n if (!parts) return '';\n const withUnits = opts?.withUnits ?? true;\n const segs: Array<string> = [];\n const t = parts.translate;\n const o = parts.origin;\n const r = parts.rotate;\n const k = parts.skew;\n const s = parts.scale;\n const tu = withUnits ? 'px' : '';\n const ru = withUnits ? 'deg' : '';\n if (t) segs.push('translate(' + t[0] + tu + ',' + t[1] + tu + ')');\n if (o) segs.push('translate(' + o[0] + tu + ',' + o[1] + tu + ')');\n if (r !== undefined && r !== null) segs.push('rotate(' + r + ru + ')');\n // Canonical slot: between rotate and scale (Lottie-compatible; pivots at origin).\n if (k !== undefined && k !== null) segs.push('skewX(' + k + ru + ')');\n if (s) segs.push('scale(' + s[0] + ',' + s[1] + ')');\n if (o) segs.push('translate(' + (-o[0]) + tu + ',' + (-o[1]) + tu + ')');\n return segs.join('');\n}\n/**\n * Parses an SVG `transform` attribute string back into a `PxTransformParts` record —\n * the inverse of {@link composeTransformParts} for its canonical shapes.\n *\n * Deliberately CONSERVATIVE (review §0.4 — used to merge a static transform under an\n * animation, where a wrong guess is worse than no merge): accepts only a linear\n * sequence with at most one `translate`, `rotate`, `skewX`, `scale` in the canonical\n * order. Anything else — `matrix(…)`, repeated functions, the ±origin translate\n * sandwich, three-arg `rotate(a cx cy)` — returns `undefined` (caller skips the merge).\n * @internal\n */\nexport function parseTransformParts(str: string | null | undefined): PxTransformParts | undefined {\n if (!str || typeof str !== 'string') return undefined;\n const out: PxTransformParts = {};\n const re = /([a-zA-Z]+)\\s*\\(([^)]*)\\)/g;\n const order = ['translate', 'rotate', 'skewX', 'scale'];\n let lastIdx = -1;\n let m: RegExpExecArray | null;\n while ((m = re.exec(str)) !== null) {\n const fn = m[1];\n const idx = order.indexOf(fn);\n if (idx < 0 || idx <= lastIdx) return undefined; // unknown fn, repeat, or out of order\n lastIdx = idx;\n const nums = m[2].split(/[\\s,]+/).filter(Boolean).map(Number);\n if (nums.some(n => Number.isNaN(n))) return undefined;\n if (fn === 'translate') {\n if (nums.length < 1 || nums.length > 2) return undefined;\n out.translate = [nums[0], nums[1] ?? 0];\n } else if (fn === 'rotate') {\n if (nums.length !== 1) return undefined; // rotate(a cx cy) has no parts spelling\n out.rotate = nums[0];\n } else if (fn === 'skewX') {\n if (nums.length !== 1) return undefined;\n out.skew = nums[0];\n } else { // scale\n if (nums.length < 1 || nums.length > 2) return undefined;\n out.scale = [nums[0], nums[1] ?? nums[0]];\n }\n }\n // Reject when anything but whitespace remains outside the parsed functions.\n if (str.replace(/([a-zA-Z]+)\\s*\\(([^)]*)\\)/g, '').replace(/[\\s,]/g, '').length) return undefined;\n return Object.keys(out).length ? out : undefined;\n}\n\n/** @internal */\nexport const PX_STYLE_ATTR_NAMES = new Set([\"offset-distance\", \"offsetDistance\"]); // Props that need to go to style\n/** @internal */\nexport const PX_DEFAULT_DURATION_MS = 1000;\n\n/**\n * Converts a kebab-case string to camelCase.\n * @param kebab The kebab-case string.\n * @internal\n */\nexport function kebabToCamelCaseWord(kebab: string): string {\n return kebab.includes('-') ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;\n}\n\n/**\n * Checks if a string is in camelCase.\n * @param word The string to check.\n */\nexport function isCamelCaseWord(word: string): boolean {\n return !word.includes('-') && /[a-z][A-Z]/.test(word);\n}\n\n// FIXME - docs, rename?\nconst SVG_CAMEL_CASE_ATTRS = new Set([\n // Transform/positioning\n 'viewBox',\n 'preserveAspectRatio',\n\n // Gradient\n 'gradientUnits',\n 'gradientTransform',\n 'spreadMethod',\n\n // Pattern\n 'patternUnits',\n 'patternContentUnits',\n 'patternTransform',\n\n // Clipping/masking\n 'clipPathUnits',\n 'maskUnits',\n 'maskContentUnits',\n\n // Marker (SVG spec keeps these camelCase, like viewBox)\n 'markerUnits',\n 'markerWidth',\n 'markerHeight',\n 'refX',\n 'refY',\n\n // Text\n 'textLength',\n 'lengthAdjust',\n 'startOffset',\n\n // Filter\n 'filterUnits',\n 'primitiveUnits',\n 'tableValues', // feFuncR/G/B/A transfer table (type=\"table\")\n 'stdDeviation',\n 'baseFrequency',\n 'numOctaves',\n 'surfaceScale',\n 'diffuseConstant',\n 'specularConstant',\n 'specularExponent',\n 'kernelMatrix',\n 'kernelUnitLength',\n 'edgeMode',\n 'preserveAlpha',\n 'targetX',\n 'targetY',\n\n // // Animation\n // 'attributeName',\n // 'attributeType',\n // 'calcMode',\n // 'keyTimes',\n // 'keySplines',\n // 'repeatCount',\n // 'repeatDur' \n]);\n\n/**\n * Converts a camelCase string to kebab-case.\n * @param camel The camelCase string.\n * @internal\n */\nexport function camelCaseToKebabWordIfNeeded(camel: string): string { // FIXME - docs, rename function?\n return SVG_CAMEL_CASE_ATTRS.has(camel) ?\n camel :\n camel.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n}\n\n/**\n * Checks if a CSS property is set inline on an element's style.\n *\n * Typed structurally (not as the DOM `CSSStyleDeclaration`) so this package\n * stays platform-neutral; a real `element.style` satisfies the shape.\n *\n * @param style - element.style (CSSStyleDeclaration-shaped)\n * @param propName - property name (camelCase or kebab-case)\n */\nexport function hasStyleProp(\n style: { getPropertyValue(propName: string): string },\n propName: string\n): boolean {\n return style.getPropertyValue(propName) !== '';\n}\n\n/**\n * Clamps a number between a minimum and maximum value.\n * @param value The number to clamp.\n * @param min The minimum value.\n * @param max The maximum value.\n * @internal\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max));\n}\n\n\n// ============================================================================\n// 2D CUBIC BÉZIER PRIMITIVES — motion-along-path support\n// ============================================================================\n//\n// Hand-written, dependency-free 2D Bézier maths used by the motion-along-path\n// playback paths (both WAAPI normalization and frames-mode direct compute).\n// See `fix-motion-along-path--fix-plan.md` for the wider plan.\n//\n// Conventions:\n// - Points are `[x, y]` tuples (`Point2`) — matches the wire format.\n// - A cubic segment is `(P0, P1, P2, P3)` where `P0` and `P3` are the\n// endpoints and `P1`, `P2` are the control points in ABSOLUTE coordinates.\n// - The Lottie-style tangent storage convention is `kf.to` =\n// outgoing-from-kf-as-a-delta, `kf.ti` = incoming-at-the-next-kf-as-a-delta.\n// The wire format re-attaches them to the natural endpoints as\n// `tangentOut` on the FROM keyframe and `tangentIn` on the TO keyframe.\n// Caller is responsible for the position-to-control-point lift, i.e.\n// `P1 = fromKf.value + fromKf.tangentOut`, `P2 = toKf.value + toKf.tangentIn`.\n\n\n/**\n * Evaluate a 2D cubic Bézier at parameter `t ∈ [0, 1]` via Bernstein form:\n *\n * B(t) = (1-t)³ P0 + 3t(1-t)² P1 + 3t²(1-t) P2 + t³ P3\n *\n * `t` is the curve PARAMETER, not arc-length. For arc-length (CSS Motion Path\n * / `offset-distance`) semantics, use `bezier2D_tForDistance` first to convert\n * a distance to its parameter, then call this. Out-of-range `t` is clamped.\n */\nexport function bezier2D_pointAt(\n P0: Point2, P1: Point2, P2: Point2, P3: Point2,\n t: number\n): Point2 {\n if (t <= 0) return [P0[0], P0[1]];\n if (t >= 1) return [P3[0], P3[1]];\n const u = 1 - t;\n const u2 = u * u;\n const u3 = u2 * u;\n const t2 = t * t;\n const t3 = t2 * t;\n const w0 = u3;\n const w1 = 3 * t * u2;\n const w2 = 3 * t2 * u;\n const w3 = t3;\n return [\n w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],\n w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1],\n ];\n}\n\n\n/**\n * Evaluate the derivative `B'(t)` of a 2D cubic Bézier at parameter `t`.\n *\n * B'(t) = 3(1-t)² (P1-P0) + 6t(1-t) (P2-P1) + 3t² (P3-P2)\n *\n * Returns the tangent VECTOR (not a unit vector). For auto-orient rotation,\n * caller computes `Math.atan2(d.y, d.x)`.\n *\n * Epsilon-nudge for degenerate endpoints: when a handle coincides with its\n * endpoint (e.g. `P1 === P0` and `t === 0`, common for the start/end of a\n * Lottie spatial-tangent path), the derivative collapses to zero. The\n * exact-endpoint value is then meaningless; we nudge `t` inward by `1e-4`\n * and retry.\n */\nconst BEZIER_T_NUDGE = 1e-4;\nexport function bezier2D_derivativeAt(\n P0: Point2, P1: Point2, P2: Point2, P3: Point2,\n t: number\n): Point2 {\n const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);\n if (result[0] === 0 && result[1] === 0) {\n // Degenerate (handle = endpoint). Nudge inward and retry.\n const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;\n return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);\n }\n return result;\n}\n\nfunction _bezier2D_derivativeAtRaw(\n P0: Point2, P1: Point2, P2: Point2, P3: Point2,\n t: number\n): Point2 {\n const u = 1 - t;\n const a = 3 * u * u;\n const b = 6 * t * u;\n const c = 3 * t * t;\n return [\n a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),\n a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1]),\n ];\n}\n\n\n/**\n * Arc-length lookup table for a 2D cubic Bézier.\n *\n * Samples the curve at `steps + 1` evenly-spaced parameter values\n * (`t = 0, 1/steps, 2/steps, …, 1`), computes the cumulative Euclidean\n * distance between consecutive samples, and returns parallel\n * `Float64Array`s for parameter (`ts`) and arc length (`ds`). `ds[steps]`\n * is the total arc length of the curve.\n *\n * The LUT shape is `{ts, ds}` with parallel Float64Arrays rather than\n * `Array<{t, d}>` because:\n * - One contiguous allocation per array instead of `steps+1` objects.\n * - Binary search in `bezier2D_tForDistance` reads `Float64Array` directly.\n * - The structure is read-only after construction — no need for per-sample\n * field access.\n *\n * Approximation error is roughly `O((1/steps)²)` for smooth curves; the\n * default 100 samples gives <1% error vs analytic arc length on typical\n * motion paths.\n */\nexport interface ArcLengthLUT {\n readonly ts: Float64Array;\n readonly ds: Float64Array;\n}\n\nexport function bezier2D_arcLengthLUT(\n P0: Point2, P1: Point2, P2: Point2, P3: Point2,\n steps: number = 100\n): ArcLengthLUT {\n const n = steps + 1;\n const ts = new Float64Array(n);\n const ds = new Float64Array(n);\n\n let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);\n ts[0] = 0;\n ds[0] = 0;\n\n let cum = 0;\n for (let i = 1; i < n; i++) {\n const t = i / steps;\n const cur = bezier2D_pointAt(P0, P1, P2, P3, t);\n const dx = cur[0] - prev[0];\n const dy = cur[1] - prev[1];\n cum += Math.sqrt(dx * dx + dy * dy);\n ts[i] = t;\n ds[i] = cum;\n prev = cur;\n }\n return { ts, ds };\n}\n\n\n/**\n * Inverse of `bezier2D_arcLengthLUT` lookup: given a distance along the\n * curve, return the curve parameter `t` reached at that distance via\n * binary search on `lut.ds` + linear interpolation between adjacent\n * samples.\n *\n * Distance is clamped to `[0, lut.ds[last]]`. The returned `t` is in\n * `[0, 1]`. Pair with `bezier2D_pointAt` to get the point at that\n * arc-length distance:\n *\n * const t = bezier2D_tForDistance(lut, distance);\n * const point = bezier2D_pointAt(P0, P1, P2, P3, t);\n */\nexport function bezier2D_tForDistance(lut: ArcLengthLUT, distance: number): number {\n const { ts, ds } = lut;\n const last = ds.length - 1;\n if (distance <= 0) return ts[0];\n if (distance >= ds[last]) return ts[last];\n\n // Binary search for the upper-bound index `hi` such that ds[hi-1] <= distance < ds[hi].\n let lo = 1;\n let hi = last;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (ds[mid] < distance) lo = mid + 1;\n else hi = mid;\n }\n // Linear interpolate between the bracketing samples.\n const dPrev = ds[hi - 1];\n const dCur = ds[hi];\n const span = dCur - dPrev;\n const frac = span > 0 ? (distance - dPrev) / span : 0;\n return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);\n}\n\n\n/**\n * `bezier2D_tForDistance` convenience taking a fraction of the total arc\n * length instead of an absolute distance. `pct` is in `[0, 1]` (CSS Motion\n * Path `offset-distance` semantics — `offset-distance: 50%` ≡\n * `bezier2D_tForDistancePct(lut, 0.5)`). Out-of-range values clamp.\n */\nexport function bezier2D_tForDistancePct(lut: ArcLengthLUT, pct: number): number {\n const total = lut.ds[lut.ds.length - 1];\n return bezier2D_tForDistance(lut, pct * total);\n}\n\n\n/**\n * Inverse of {@link bezier2D_tForDistance}: given a curve parameter `t`,\n * returns the arc length from the start. Binary searches the LUT's `ts`\n * (uniformly spaced) and linearly interpolates `ds` between adjacent samples.\n */\nexport function bezier2D_arcAtT(lut: ArcLengthLUT, t: number): number {\n const { ts, ds } = lut;\n const last = ts.length - 1;\n if (t <= ts[0]) return ds[0];\n if (t >= ts[last]) return ds[last];\n let lo = 1, hi = last;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (ts[mid] < t) lo = mid + 1;\n else hi = mid;\n }\n const tPrev = ts[hi - 1];\n const span = ts[hi] - tPrev;\n const frac = span > 0 ? (t - tPrev) / span : 0;\n return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);\n}\n\n\n/**\n * Inverse of {@link cubicBezier}: for a CSS easing `[x1,y1,x2,y2]` and a\n * target output `y`, returns the input `x` such that\n * `cubicBezier(easing)(x) ≈ y`. Works for monotonic easings (the CSS\n * default) by swapping the easing's x/y axes — the inverse easing has\n * controls `[y1, x1, y2, x2]`, which `cubicBezier` evaluates directly.\n *\n * `undefined` easing (linear) → identity function.\n */\nexport function invertEasing(easing: Easing | undefined): (y: number) => number {\n if (!easing) return (y) => y;\n const flipped: Easing = [easing[1], easing[0], easing[3], easing[2]];\n return cubicBezier(flipped);\n}","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { type PxDefinitions } from '../format/PxAnimatorTypes';\nimport { INTERNAL_ATTRS, TRANSFORM_ATTR } from '../format/PxAnimatorConstants';\nimport { PX_COLOR_ATTR_NAMES, composeTransformParts, kebabToCamelCaseWord, toRGBA, PX_TRANSFORM_FN_NAMES } from './PxAnimatorUtil';\n\n\n/**\n * Tags that MUST never be created — the only real XSS surfaces in SVG:\n * - `<script>` — direct JS execution.\n * - `<foreignObject>` — embeds arbitrary HTML (incl. `<script>`, `<iframe>`).\n *\n * Everything else (shape elements, gradients, patterns, markers, filters\n * including `feComponentTransfer` / `feFuncA` / `feFlood` / `feComposite` /\n * `feImage`, SMIL `<animate>` family, `<a>` hyperlinks, …) is allowed. URL\n * sanitization in `sanitizeAttributeValue` blocks `javascript:` / external\n * refs on `href` / `src` / `mask` / `marker*`.\n * @internal\n */\nexport const PX_DISALLOWED_SVG_TAGS_LOWER = new Set([\n 'script',\n 'foreignobject',\n]);\n\n\n/**\n * URL-valued attributes that must reference an internal `#id` / `url(#id)`\n * only — never an external URL, `javascript:`, etc. Values for these names\n * are sanitized in `sanitizeAttributeValue`; non-internal refs are dropped.\n *\n * Exception: image-ref attributes (`href` / `xlink:href` / `src`) ALSO\n * accept `data:image/…` URIs — base64 raster (`image/png`, `image/jpeg`,\n * `image/gif`, `image/webp`, `image/bmp`) and `image/svg+xml` (base64 or\n * URL-encoded). Browsers render any image referenced from `<image>` in\n * SVG \"secure static mode\": scripts inside the referenced SVG do NOT\n * execute, external resources don't load, and interaction is disabled —\n * the same sandbox `<img src=…svg>` uses. The `image/svg+xml` form is\n * therefore safe as an image source even though a top-level SVG document\n * with the same bytes could embed scripts.\n *\n * Stored lowercased so `sanitizeAttributeValue`'s `name.toLowerCase()`\n * lookup matches regardless of input casing (`href` / `xlink:href` /\n * `clipPath` / `clip-path` all hit the same entry).\n */\nconst URL_VALUE_ATTRS_LOWER = new Set([\n 'href', // <use>, <image>\n 'xlink:href', // legacy <use>\n 'src', // <image>\n 'filter', // url(#filterId)\n 'clippath', // clip-path=\"url(#…)\"\n 'mask', // url(#maskId)\n 'markerstart', // marker-start=\"url(#…)\"\n 'markermid', // marker-mid=\"url(#…)\"\n 'markerend', // marker-end=\"url(#…)\"\n]);\n\n/** Attrs where a `data:image/…` URI is a legitimate value (i.e. the SVG\n * element actually renders the bytes — `<image>`). Other URL-valued\n * attrs ignore data URIs at the browser layer, so widening the allow-\n * list there would be cargo-culted and noisy. */\nconst IMAGE_REF_ATTRS_LOWER = new Set(['href', 'xlink:href', 'src']);\n\n/** CSS-only properties that are NOT SVG presentation attributes — the browser\n * ignores them via `setAttribute`, so they must be applied through `element.style`.\n * Keyed camelCase to match the normalized prop names (`element.style.mixBlendMode`). * @internal\n */\nexport const PX_CSS_ONLY_STYLE_PROPS = new Set<string>(['mixBlendMode', 'isolation']);\n\n/** Matches `data:image/{png|jpeg|jpg|gif|webp|bmp};base64,<payload>`.\n * Rejects any non-base64-encoded raster form. */\nconst DATA_RASTER_IMAGE_RE = /^data:image\\/(?:png|jpe?g|gif|webp|bmp);base64,/i;\n\n/** Matches `data:image/svg+xml[;params],<payload>` — base64\n * (`;base64,`), `;utf8,` / `;charset=UTF-8,`, and bare `,` (URL-encoded)\n * forms. Safe because the browser sandboxes any SVG referenced from an\n * image source (no scripts, no external loads, no interaction). */\nconst DATA_SVG_IMAGE_RE = /^data:image\\/svg\\+xml(?:;[^,]*)?,/i;\n\n/** Content-sniff fallback for `data:image/*;base64,…` URIs whose declared\n * subtype isn't a known raster type — e.g. `data:image/undefined;base64,<png>`,\n * which some Lottie exporters emit. The browser (and lottie-web) render these by\n * sniffing the leading bytes; we mirror that by matching the base64 payload\n * against common raster magic numbers (PNG `\\x89PNG`, JPEG `\\xFF\\xD8\\xFF`, GIF\n * `GIF8`, WebP/RIFF, BMP `BM`). Accepting on real image bytes keeps the\n * sanitizer's safety guarantee — raster bytes are inert — without trusting the\n * (here bogus) subtype, so the image renders instead of being dropped. */\nconst DATA_IMAGE_BASE64_PAYLOAD_RE = /^data:image\\/[^;,]*;base64,([A-Za-z0-9+/]{8})/i;\nconst BASE64_RASTER_MAGICS = ['iVBORw0K', '/9j/', 'R0lGOD', 'UklGR', 'Qk'];\nfunction isContentSniffedRasterImage(str: string): boolean {\n const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str);\n return !!m && BASE64_RASTER_MAGICS.some(magic => m[1].startsWith(magic));\n}\n\n\n/**\n * Attribute-name predicate: anything `name` matching this is dropped at\n * `setAttribute` time. The list is intentionally small — SVG's real\n * security surface is event handlers; every other concerning attribute\n * (URL refs, fill/stroke `url(…)`) is value-sanitized below, not name-\n * blocked. Adding entries here is a structural decision, not whack-a-mole.\n */\nfunction isDangerousAttrName(nameLower: string): boolean {\n // Event handlers — `onclick`, `onload`, `onerror`, `onmouseover`,\n // `onfocus`, `onfocusin`, SMIL `onbegin`/`onend`/`onrepeat`, … and any\n // future one. No legitimate SVG attribute starts with `on`, so this\n // prefix is a safe blanket block.\n if (nameLower.startsWith('on')) return true;\n return false;\n}\n\n\n/**\n * Returns the value to pass to `setAttribute`, or `undefined` to drop the\n * attribute entirely. Dropping leaves the DOM clean — the caller skips\n * `setAttribute` when this returns `undefined`.\n *\n * Three layers:\n * 1. Drop dangerous names (`on*` event handlers).\n * 2. Restrict `url(…)` in `fill` / `stroke` / `stop-color` to\n * internal `url(#id)` references.\n * 3. Restrict URL-valued attrs (`href`, `src`, `filter`, `clip-path`,\n * `mask`, `marker*`) to internal `#id` / `url(#id)`. Image-ref\n * attrs (`href` / `xlink:href` / `src`) additionally accept\n * `data:image/…` URIs — base64 raster (png/jpeg/gif/webp/bmp) and\n * `image/svg+xml` (sandboxed by the browser when used as an image\n * source). Blocks `javascript:` and external URLs.\n * Everything else passes through.\n * @internal\n */\nexport function sanitizeAttributeValue(name: string, value: any): any | undefined {\n const nameLower = name.toLowerCase();\n\n if (isDangerousAttrName(nameLower)) {\n console.warn('Attribute blocked (event handler / dangerous): ', nameLower);\n return undefined;\n }\n\n if (nameLower === 'fill' || nameLower === 'stroke' || nameLower === 'stopcolor') {\n const str = String(value);\n if (str.includes('url(') && !/^url\\(#[^)]+\\)$/.test(str)) {\n console.warn('Attribute \"' + nameLower + '\" blocked: url() must be internal url(#id), got:', value);\n return undefined;\n }\n return value;\n }\n\n if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {\n const str = String(value);\n if (str.startsWith('#')) return value; // internal fragment ref\n if (/^url\\(#[^)]+\\)$/.test(str)) return value; // internal `url(#id)`\n // Image-ref attrs accept `data:image/…` URIs — raster bytes are\n // inert, and SVG referenced via an image source is sandboxed by\n // the browser (no script execution).\n if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str) || DATA_SVG_IMAGE_RE.test(str) || isContentSniffedRasterImage(str))) return value;\n console.warn('Attribute \"' + nameLower + '\" blocked: must be #id, url(#id), or data:image/… URI, got:', value);\n return undefined;\n }\n\n return value;\n}\n\n/** @public @advanced */\nexport function toDomProps(props: Record<string, any>) {\n const propsCopy: Record<string, any> = {};\n\n // Process regular attributes\n for (const rawKey of Object.keys(props)) {\n // Wire-format inputs may use kebab-case SVG attribute names (e.g.\n // `stroke-width`); normalize to camelCase up-front so the whitelist\n // (camelCase) and the `camelCaseToKebabWordIfNeeded` re-conversion\n // at write time both work. `kebabToCamelCaseWord` is a no-op for\n // keys with no `-`, leaving camelCase inputs untouched.\n const key = kebabToCamelCaseWord(rawKey);\n if (INTERNAL_ATTRS.has(key)) continue;\n if (key === 'style') continue;\n\n let value = props[rawKey];\n\n if (PX_COLOR_ATTR_NAMES.has(key) && Array.isArray(value)) {\n propsCopy[key] = toRGBA(value);\n } else if (\n key === 'transform' && value !== null && typeof value === 'object' &&\n !Array.isArray(value) && !value.keyframes\n ) {\n // Unified transform static record — bare `{translate, rotate, …}`\n // (canonical) or the legacy `{value: PxTransformParts}` wrapper.\n // Compose into an SVG transform string (no units — SVG transform attribute).\n const parts = value.value && typeof value.value === 'object' ? value.value : value;\n propsCopy[TRANSFORM_ATTR] = composeTransformParts(parts, { withUnits: false });\n } else if (PX_TRANSFORM_FN_NAMES.has(key)) {\n if (Array.isArray(value)) {\n if (key === 'translate') value = value.map((v: number) => v + 'px');\n value = value.join(',');\n }\n if (key === 'rotate') value = value + 'deg';\n propsCopy[TRANSFORM_ATTR] = key + '(' + value + ')';\n } else if (Array.isArray(value)) {\n // Raw-array STATIC form of number-list attributes — `strokeDasharray: [16, 16]`\n // (the wire's canonical static shape; the string form \"16,16\" is also accepted\n // and passes through the String() branch below). SVG list attributes take the\n // comma-separated string. Color arrays were already handled above.\n propsCopy[key] = value.join(',');\n } else if (value !== undefined && value !== null) {\n propsCopy[key] = String(value);\n }\n }\n\n return propsCopy;\n}\n\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * Motion-along-path → plain transform keyframes.\n *\n * Editor wire format for a curved-translation (and/or `autoOrient`) animation\n * carries per-kf `tangentIn` / `tangentOut` plus an animation-level `autoOrient`\n * flag — a parametric representation that any consumer must evaluate per frame.\n *\n * This module DESUGARS that shape into a regular unified-transform animation:\n * extra `{ translate, rotate? }` keyframes are inserted at curve extrema and\n * adaptive bisection points so the linear chord between adjacent samples stays\n * within `flatnessTolerance` of the true Bezier, and the original easing is\n * SPLIT (via De Casteljau, `splitEasing` in `PxAnimatorUtil`) across the\n * sub-segments so the combined timing reproduces the input easing exactly.\n *\n * Output kfs have no tangents and no `autoOrient` — both engines (`frames` and\n * `waapi`) and any future renderer (e.g. react-native-svg) consume them via\n * their normal unified-transform code path.\n *\n * The plan + rationale (extremes-aware sampling, easing-split, full pipeline\n * order) is in `motion-along-path-waapi-rework.md`.\n */\n\n\nimport { bezier2D_arcAtT, bezier2D_arcLengthLUT, bezier2D_derivativeAt, bezier2D_pointAt, clamp, invertEasing, splitEasing } from '../util/PxAnimatorUtil';\nimport type { ArcLengthLUT } from '../util/PxAnimatorUtil';\nimport type { PxAnyKeyframe, PxKeyframe, PxNormalizedKeyframe, PxNode, PxPropertyAnimation, PxTransformParts } from '../format/PxAnimatorTypes';\nimport { keyframeTime, keyframeValue, keyframeEasing, keyframeTangentIn, keyframeTangentOut } from '../format/PxAnimatorTypes';\n\n\ntype Point2 = [number, number];\ntype Easing = [number, number, number, number];\n\n\nfunction getKfTranslate(kf: PxAnyKeyframe): Point2 | undefined {\n const v = keyframeValue(kf);\n if (!v) return undefined;\n if (Array.isArray(v) && v.length >= 2 && typeof v[0] === 'number' && typeof v[1] === 'number') {\n // Composite per-part shape: `value: [x, y]` directly.\n return [v[0], v[1]];\n }\n const tr = (v as PxTransformParts).translate;\n if (Array.isArray(tr) && tr.length >= 2) return [tr[0], tr[1]];\n return undefined;\n}\n\nfunction getKfTime(kf: PxAnyKeyframe): number {\n return keyframeTime(kf) as number;\n}\n\nfunction getKfEasing(kf: PxAnyKeyframe): Easing | undefined {\n return keyframeEasing(kf) as Easing | undefined;\n}\n\n\n/**\n * True when `anim` is a motion-along-path animation — at least one keyframe\n * carries spatial tangents (`tangentIn` / `tangentOut`) and/or the animation\n * has `autoOrient` set. Animation-level helper; works for either the body\n * `transform` slot or a composite per-part `translate` slot.\n * @internal\n */\nexport function propAnimIsMotionPath(anim: PxPropertyAnimation): boolean {\n const kfs: Array<PxAnyKeyframe> | undefined = anim.keyframes;\n if (!Array.isArray(kfs)) return false;\n if (anim.autoOrient) return true;\n for (const kf of kfs) {\n if (keyframeTangentIn(kf) || keyframeTangentOut(kf)) return true;\n }\n return false;\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Segment cache — shared by `evaluateMotionPathSegment` (frames-mode kernel)\n// and the materializer. Keyed by FROM-keyframe identity (WeakMap), so cache\n// entries vanish automatically when keyframes are replaced.\n// ─────────────────────────────────────────────────────────────────────────────\n\n\ninterface MotionPathSegmentCache {\n readonly P0: Point2;\n readonly P1: Point2;\n readonly P2: Point2;\n readonly P3: Point2;\n readonly lut: ArcLengthLUT;\n readonly totalArc: number;\n}\n\n// Keyed on the PAIR, not on `prevKf` alone: one keyframe can start different segments\n// across evaluations (a lookup that falls outside the keyframe range answers with a\n// first→last pair), and a `prevKf`-only key let that bogus segment's Bezier be served\n// for every later evaluation of the real `prevKf`→next segment.\nconst _segmentCache = new WeakMap<PxAnyKeyframe, WeakMap<PxAnyKeyframe, MotionPathSegmentCache>>();\n\nfunction getSegmentCache(\n prevKf: PxAnyKeyframe,\n nextKf: PxAnyKeyframe,\n prevPos: Point2,\n nextPos: Point2,\n): MotionPathSegmentCache {\n let byNext = _segmentCache.get(prevKf);\n const existing = byNext?.get(nextKf);\n if (existing) return existing;\n const to = keyframeTangentOut(prevKf);\n const ti = keyframeTangentIn(nextKf);\n const P1: Point2 = [prevPos[0] + (to ? to[0] : 0), prevPos[1] + (to ? to[1] : 0)];\n const P2: Point2 = [nextPos[0] + (ti ? ti[0] : 0), nextPos[1] + (ti ? ti[1] : 0)];\n const lut = bezier2D_arcLengthLUT(prevPos, P1, P2, nextPos);\n const entry: MotionPathSegmentCache = {\n P0: prevPos, P1, P2, P3: nextPos,\n lut,\n totalArc: lut.ds[lut.ds.length - 1],\n };\n if (!byNext) { byNext = new WeakMap<PxAnyKeyframe, MotionPathSegmentCache>(); _segmentCache.set(prevKf, byNext); }\n byNext.set(nextKf, entry);\n return entry;\n}\n\n/** Test helper. No-op in production (WeakMap; entries self-evict). Tests\n * should use fresh keyframe objects to force cache misses. */\nexport function _resetMotionPathSegmentCache(): void {\n // Intentionally empty — kept for backwards-compat with any callers.\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Frames-mode kernel — preserved for any caller that still wants parametric\n// evaluation. The binding pipeline no longer needs it (motion-path is\n// materialized at `normalizeBindings` time), but it's a useful primitive\n// on its own.\n// ─────────────────────────────────────────────────────────────────────────────\n\n\n/** @internal */\nexport interface MotionPathSample {\n /** Translate at the current time (motion-path arc-length-parametrised). */\n readonly translate: Point2;\n /** Auto-orient rotation in degrees (only when `autoOrient` is set). */\n readonly rotateDeg?: number;\n}\n\n/**\n * Evaluates the motion-path position (and optional auto-orient rotation) for a\n * single segment kf[i] → kf[i+1], given local progress already remapped to\n * `[0, 1]` and eased. Builds (or reuses cached) Bezier control points\n * `P1 = P0 + tangentOut`, `P2 = P3 + tangentIn`, maps `localProgress` to arc\n * length, then to curve parameter `t` via the arc-length LUT.\n * @internal\n */\nexport function evaluateMotionPathSegment(\n prevKf: PxKeyframe,\n nextKf: PxKeyframe,\n prevPos: Point2,\n nextPos: Point2,\n localProgress: number,\n autoOrient: boolean,\n): MotionPathSample {\n const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);\n const t = seg.totalArc === 0\n ? localProgress\n : tFromArcFraction(seg.lut, localProgress);\n const point = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);\n if (!autoOrient) return { translate: point };\n const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);\n const rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;\n return { translate: point, rotateDeg };\n}\n\nfunction tFromArcFraction(lut: ArcLengthLUT, arcFrac: number): number {\n const total = lut.ds[lut.ds.length - 1];\n // Binary search on `ds` for `arcFrac * total` (mirrors bezier2D_tForDistance).\n const target = arcFrac * total;\n const { ts, ds } = lut;\n const last = ds.length - 1;\n if (target <= 0) return ts[0];\n if (target >= ds[last]) return ts[last];\n let lo = 1, hi = last;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (ds[mid] < target) lo = mid + 1;\n else hi = mid;\n }\n const dPrev = ds[hi - 1];\n const span = ds[hi] - dPrev;\n const frac = span > 0 ? (target - dPrev) / span : 0;\n return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API — materialize parametric motion-path into plain transform kfs\n// ─────────────────────────────────────────────────────────────────────────────\n\n\n/** Sampling configuration shared by `materializeMotionPathInPropAnim` + `materializeMotionPathsInTree`. @internal */\nexport interface MotionPathMaterializationOptions {\n /** Max chord-to-curve deviation per sub-interval, in user units (default 0.5). */\n flatnessTolerance?: number;\n /** Max rotation delta (in degrees) between adjacent samples when `autoOrient`\n * is set (default 5). */\n rotationTolerance?: number;\n /** Hard cap on samples per original segment; prevents runaway recursion on\n * pathological inputs (default 32). */\n maxSamplesPerSegment?: number;\n}\n\nconst DEFAULT_FLATNESS_TOL = 0.5;\nconst DEFAULT_ROTATION_TOL = 5;\nconst DEFAULT_MAX_SAMPLES = 32;\n\n\n/**\n * Converts ONE animated property to sampled transform kfs.\n *\n * Returns a NEW `PxPropertyAnimation` whose `kfs` are flat\n * `{ translate, rotate? }` records placed at curve extrema and adaptive\n * bisection points. Positions are arc-length-parametrised; easing is split via\n * De Casteljau so per-sub-segment easings reproduce the input easing exactly.\n * Original `loop` is carried across; `autoOrient` and per-kf `tangentIn` /\n * `tangentOut` are consumed.\n *\n * Returns the input unchanged (by reference) when it's not a motion-path\n * animation — callers can blindly run it through every propAnim.\n * @internal\n */\nexport function materializeMotionPathInPropAnim(\n anim: PxPropertyAnimation,\n opts?: MotionPathMaterializationOptions,\n): PxPropertyAnimation {\n if (!propAnimIsMotionPath(anim)) return anim;\n const kfs = anim.keyframes as Array<PxAnyKeyframe> | undefined;\n if (!Array.isArray(kfs) || kfs.length < 2) return anim;\n\n const autoOrient = !!anim.autoOrient;\n const flatnessTol = opts?.flatnessTolerance ?? DEFAULT_FLATNESS_TOL;\n const rotationTol = opts?.rotationTolerance ?? DEFAULT_ROTATION_TOL;\n const maxSamples = opts?.maxSamplesPerSegment ?? DEFAULT_MAX_SAMPLES;\n\n const out: Array<PxNormalizedKeyframe> = [];\n\n // First output kf — translate from input; rotate from segment-0 derivative\n // at t=0 if autoOrient. All other transform parts (`origin`, `scale`, an\n // explicit `rotate` when `autoOrient` is false, …) come from kfs[0].value.\n const firstPos = getKfTranslate(kfs[0]);\n if (!firstPos) return anim;\n const firstRotate = autoOrient ? derivAngleForFirstKf(kfs[0], kfs[1]) : undefined;\n out.push(makeOutKf(\n getKfTime(kfs[0]),\n buildOutKfValue(getKfValueParts(kfs[0]), getKfValueParts(kfs[0]), 0, firstPos, firstRotate, autoOrient),\n ));\n\n for (let i = 0; i < kfs.length - 1; i++) {\n const prevKf = kfs[i];\n const nextKf = kfs[i + 1];\n const prevPos = getKfTranslate(prevKf);\n const nextPos = getKfTranslate(nextKf);\n if (!prevPos || !nextPos) {\n // Skip undefined translate kfs — just push next as-is.\n out.push(makeOutKf(\n getKfTime(nextKf),\n buildOutKfValue(getKfValueParts(nextKf), getKfValueParts(nextKf), 1, nextPos ?? [0, 0], undefined, autoOrient),\n ));\n continue;\n }\n\n // Sharp-corner step: between adjacent segments, the prev-segment's\n // exit tangent angle (already on out[last]) can differ from this\n // segment's entry tangent angle (deriv at t=0 of the segment about to\n // start) by a lot — e.g. a rectangular path has 90° steps at each\n // corner. Linear interp from prev-exit to the FAR-END kf of this\n // segment would slide rotation through the whole segment instead of\n // stepping at the boundary. Fix: insert a duplicate kf at the\n // boundary time carrying this segment's entry angle. With `e=undef`\n // on the prior kf, the engines render an instant step boundary then\n // constant rotation through the segment.\n if (autoOrient && i > 0) {\n insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);\n }\n\n materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);\n }\n\n // The very last out-kf inherits the original last kf's `easing` (which\n // applies to the NEXT segment after this animation, or nothing — but the\n // wire format preserves it regardless).\n const lastInE = getKfEasing(kfs[kfs.length - 1]);\n if (lastInE) out[out.length - 1].e = lastInE;\n\n // Unwrap autoOrient rotations so linear interp between samples doesn't\n // take the long way around the circle. atan2 returns in (-180°, 180°];\n // a tangent rotating slowly across the +X axis (e.g. -179° → +179°)\n // would otherwise be lerp'd as a ~358° spin instead of a ~2° step.\n if (autoOrient) unwrapAutoOrientRotations(out);\n\n // Output converges on `keyframes` — the `kfs` alias is gone (review §1.2/§6.1).\n const result: PxPropertyAnimation = { keyframes: out };\n if (anim.loop !== undefined) (result as { loop?: unknown }).loop = anim.loop;\n return result;\n}\n\n\n/** Walks `kfs` in order; for each kf with a `rotate` value, shifts it by ±360°\n * multiples so the delta from the previous kf's rotate stays within ±180°.\n * Linear interpolation between consecutive samples then always takes the\n * shorter arc. The accumulated shift means a continuously-rotating element\n * may end up with rotate values well outside [-180°, 180°], which is fine —\n * CSS / SVG rotation accepts any range. Exported — the glyph along-path baker\n * (`buildAnimatedAlongPath`) needs the identical seam fix for its sampled\n * per-glyph tangent rotations. */\nexport function unwrapAutoOrientRotations(kfs: Array<PxAnyKeyframe>): void {\n let prev: number | undefined;\n for (const kf of kfs) {\n const v = keyframeValue(kf) as { rotate?: number } | undefined;\n if (!v || typeof v.rotate !== 'number') continue;\n if (prev === undefined) { prev = v.rotate; continue; }\n let r = v.rotate;\n while (r - prev > 180) r -= 360;\n while (r - prev < -180) r += 360;\n v.rotate = r;\n prev = r;\n }\n}\n\n\nfunction makeOutKf(time: number, value: PxTransformParts): PxNormalizedKeyframe {\n return { t: time, v: value };\n}\n\n/** Reads the kf's value-as-parts (object form). Returns `undefined` if the kf\n * has no value or it's an array form (single-part composite). */\nfunction getKfValueParts(kf: PxAnyKeyframe): PxTransformParts | undefined {\n const v = keyframeValue(kf);\n if (!v || typeof v !== 'object' || Array.isArray(v)) return undefined;\n return v as PxTransformParts;\n}\n\n/** Linearly interpolates one transform-part value (number / PxVec2). Returns the\n * non-undefined input when only one side is present, falls back to `prev`\n * for unsupported types. */\nfunction interpolatePart(prev: unknown, next: unknown, p: number): unknown {\n if (prev === undefined) return next;\n if (next === undefined) return prev;\n if (typeof prev === 'number' && typeof next === 'number') {\n return prev + (next - prev) * p;\n }\n if (Array.isArray(prev) && Array.isArray(next) && prev.length === next.length) {\n const out: Array<number> = new Array(prev.length);\n for (let i = 0; i < prev.length; i++) {\n const a = typeof prev[i] === 'number' ? prev[i] : 0;\n const b = typeof next[i] === 'number' ? next[i] : 0;\n out[i] = a + (b - a) * p;\n }\n return out;\n }\n return p < 0.5 ? prev : next;\n}\n\n/** Builds the value-record for one sampled output kf. `translate` overrides\n * whatever the per-part interpolation would have produced (motion path is the\n * source of truth for position); `rotateDegFromAutoOrient`, when defined, is\n * ADDED on top of the (interpolated) explicit animated `rotate` — auto-orient\n * and a user-set rotation compose, matching After Effects / Lottie semantics.\n * All OTHER parts present on `prevV` / `nextV` (origin, scale, etc.) are\n * interpolated at the eased arc-progress `p` — mirroring the frames-mode\n * `calcPropertyValue` loop. */\nfunction buildOutKfValue(\n prevV: PxTransformParts | undefined,\n nextV: PxTransformParts | undefined,\n p: number,\n translate: Point2,\n rotateDegFromAutoOrient: number | undefined,\n autoOrient: boolean,\n): PxTransformParts {\n const value: { [k: string]: unknown } = { translate };\n const keys = new Set<string>();\n if (prevV) for (const k of Object.keys(prevV)) keys.add(k);\n if (nextV) for (const k of Object.keys(nextV)) keys.add(k);\n for (const k of keys) {\n if (k === 'translate') continue; // overridden by motion path\n if (k === 'rotate' && autoOrient) continue; // composed below with autoOrient\n const pv = (prevV as Record<string, unknown> | undefined)?.[k];\n const nv = (nextV as Record<string, unknown> | undefined)?.[k];\n if (pv === undefined && nv === undefined) continue;\n value[k] = interpolatePart(pv, nv, p);\n }\n if (rotateDegFromAutoOrient !== undefined) {\n // Sum the auto-orient tangent angle with the element's own animated\n // rotation (interpolated at `p`, 0 when absent) rather than discarding it.\n value.rotate = rotateDegFromAutoOrient + explicitRotateAt(prevV, nextV, p);\n }\n return value as PxTransformParts;\n}\n\n/** Interpolated explicit `rotate` from a transform-parts pair at arc-progress\n * `p`; 0 when neither side carries a numeric rotate. */\nfunction explicitRotateAt(\n prevV: PxTransformParts | undefined,\n nextV: PxTransformParts | undefined,\n p: number,\n): number {\n const pv = typeof prevV?.rotate === 'number' ? prevV.rotate : undefined;\n const nv = typeof nextV?.rotate === 'number' ? nextV.rotate : undefined;\n if (pv === undefined && nv === undefined) return 0;\n const r = interpolatePart(pv, nv, p);\n return typeof r === 'number' ? r : 0;\n}\n\n\n/** Derivative angle at t=0 of segment kf[0] → kf[1]. Used to seed the first\n * output kf's rotation; without this the very first frame would render with\n * no rotation while every subsequent sample has one. */\nfunction derivAngleForFirstKf(kf0: PxAnyKeyframe, kf1: PxAnyKeyframe): number {\n const p0 = getKfTranslate(kf0);\n const p1 = getKfTranslate(kf1);\n if (!p0 || !p1) return 0;\n const seg = getSegmentCache(kf0, kf1, p0, p1);\n const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);\n return Math.atan2(tan[1], tan[0]) * 180 / Math.PI;\n}\n\n\n/** Shortest signed difference of `a − b` wrapped into (-180°, 180°]. */\nfunction wrappedAngleDelta(a: number, b: number): number {\n let d = a - b;\n while (d > 180) d -= 360;\n while (d < -180) d += 360;\n return d;\n}\n\n\n/**\n * Appends a \"step\" kf to `out` at the boundary time iff the next segment's\n * entry tangent direction differs from the last emitted kf's rotation by more\n * than `rotationTol`. The new kf carries the SAME translate / origin / scale\n * as the boundary kf already in `out` (continuous in space), but a different\n * `rotate` — making engines render an instant rotation snap at the boundary\n * rather than linearly sliding rotation across the whole next segment.\n *\n * Called between `materializeSegment` calls. The boundary kf already in `out`\n * keeps its outgoing easing as undefined (no easing between the two duplicates\n * — the step is instant); the next `materializeSegment` will then attach its\n * sequential-split easing to the newly-inserted duplicate, so the per-sample\n * easing on segment `i+1` works exactly as before.\n */\nfunction insertSharpCornerStepKfIfNeeded(\n out: Array<PxNormalizedKeyframe>,\n prevKf: PxAnyKeyframe, nextKf: PxAnyKeyframe,\n prevPos: Point2, nextPos: Point2,\n rotationTol: number,\n): void {\n const lastKf = out[out.length - 1];\n const lastV = keyframeValue(lastKf) as { rotate?: number } | undefined;\n const prevExit = lastV?.rotate;\n if (typeof prevExit !== 'number') return;\n\n // `prevExit` is the SUMMED rotation (tangent + explicit). Compare pure\n // tangent-to-tangent by subtracting the boundary kf's explicit rotate,\n // which is shared by both adjoining segments at this shared keyframe.\n const boundaryV = getKfValueParts(prevKf);\n const prevExitTangent = prevExit - explicitRotateAt(boundaryV, boundaryV, 0);\n\n const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);\n const tanAtStart = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);\n const nextEntry = Math.atan2(tanAtStart[1], tanAtStart[0]) * 180 / Math.PI;\n const delta = wrappedAngleDelta(nextEntry, prevExitTangent);\n if (Math.abs(delta) <= rotationTol) return; // continuous within tolerance\n\n // Step kf carrying the new entry angle, a hair AFTER the boundary — the boundary\n // time itself must render the PREVIOUS segment's exit pose. A duplicate at the exact\n // boundary time made CSS/WAAPI resolve the LATER keyframe there, so scrubbing to\n // exactly the corner showed the next segment's angle while the editor (and the\n // parametric frames engine, whose segment lookup treats a boundary as the END of the\n // segment before it) showed the previous one. The offset is far below a frame, so\n // playback still reads as an instant step at the corner.\n const prevTime = getKfTime(prevKf);\n const stepTime = Math.min(prevTime + CORNER_STEP_AFTER_BOUNDARY_MS, (prevTime + getKfTime(nextKf)) / 2);\n const dupValue = buildOutKfValue(\n getKfValueParts(prevKf), getKfValueParts(prevKf), 0,\n prevPos, nextEntry, true,\n );\n out.push(makeOutKf(stepTime, dupValue));\n}\n\n/** How far past a sharp corner the entry-angle step kf sits (ms). Small enough to be\n * invisible in playback (a frame is ~16 ms) — and strictly under the 0.1 ms step-width\n * budget the corner-step CSS spec asserts — while still a distinct WAAPI offset. */\nconst CORNER_STEP_AFTER_BOUNDARY_MS = 0.05;\n\n\n/** Materializes a single segment into `out`. Appends one kf per sample (interior\n * critical/adaptive points + the next-kf endpoint), with positions, optional\n * rotations, and split easings. */\nfunction materializeSegment(\n out: Array<PxNormalizedKeyframe>,\n prevKf: PxKeyframe, nextKf: PxKeyframe,\n prevPos: Point2, nextPos: Point2,\n autoOrient: boolean,\n flatnessTol: number, rotationTol: number, maxSamples: number,\n): void {\n const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);\n const prevTime = getKfTime(prevKf);\n const nextTime = getKfTime(nextKf);\n const prevEasing = getKfEasing(prevKf);\n const invertFn = invertEasing(prevEasing);\n const prevV = getKfValueParts(prevKf);\n const nextV = getKfValueParts(nextKf);\n\n // 1. Critical t-values: axis extrema + endpoints.\n const interiorTs = computeSampleTs(seg, autoOrient, flatnessTol, rotationTol, maxSamples);\n // `interiorTs` is the list of t in (0, 1] in ascending order, ending with t=1.\n\n // 2. For each sample t, compute position, rotation, the eased arc-fraction\n // `p` (= the value frames-mode would use for non-translate part interp),\n // and the linear-time fraction `u` (via invertEasing of `p`).\n interface Sample { u: number; p: number; pos: Point2; rotateDeg?: number; }\n const samples: Array<Sample> = [];\n for (const t of interiorTs) {\n const arc = bezier2D_arcAtT(seg.lut, t);\n const p = clamp(seg.totalArc > 0 ? arc / seg.totalArc : t, 0, 1);\n const u = clamp(invertFn(p), 0, 1);\n const pos = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);\n const sample: Sample = { u, p, pos };\n if (autoOrient) {\n const tan = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);\n sample.rotateDeg = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;\n }\n samples.push(sample);\n }\n\n // 3. Sequential easing split. The easing for sub-segment k (out[L+k-1] → out[L+k])\n // is the `left` half of splitting the still-unconsumed easing at\n // `(u_k - u_{k-1}) / (1 - u_{k-1})`.\n let remaining = prevEasing;\n let prevU = 0;\n const startIdx = out.length - 1; // out[startIdx] is the prev kf — it owns the FIRST sub-easing.\n for (let i = 0; i < samples.length; i++) {\n const s = samples[i];\n const xFrac = prevU < 1 ? clamp((s.u - prevU) / (1 - prevU), 0, 1) : 1;\n const { left, right } = splitEasing(remaining, xFrac);\n\n // Assign `left` as the outgoing easing of the kf at the end of `out`\n // (which is the kf that PRECEDES this sub-kf — the prev kf for i=0,\n // or the previously-emitted sub-kf for i>0).\n const ownerIdx = i === 0 ? startIdx : out.length - 1;\n if (left) out[ownerIdx].e = left;\n else delete out[ownerIdx].e;\n\n const tGlobal = prevTime + s.u * (nextTime - prevTime);\n const value = buildOutKfValue(prevV, nextV, s.p, s.pos, s.rotateDeg, autoOrient);\n out.push(makeOutKf(tGlobal, value));\n\n remaining = right;\n prevU = s.u;\n }\n}\n\n\n/** Returns t-values in (0, 1], sorted ascending, ending with t=1. The list\n * always includes the input segment's axis extrema interior to (0, 1), plus\n * adaptive bisection samples wherever the chord deviates from the curve by\n * more than `flatnessTol` (or the rotation delta exceeds `rotationTol` for\n * autoOrient). Capped at `maxSamples`. */\nfunction computeSampleTs(\n seg: MotionPathSegmentCache, autoOrient: boolean,\n flatnessTol: number, rotationTol: number, maxSamples: number,\n): Array<number> {\n // Axis extrema (interior to (0, 1)).\n const extremes: Array<number> = [];\n addAxisExtremes(seg.P0[0], seg.P1[0], seg.P2[0], seg.P3[0], extremes);\n addAxisExtremes(seg.P0[1], seg.P1[1], seg.P2[1], seg.P3[1], extremes);\n extremes.sort((a, b) => a - b);\n\n const critical: Array<number> = [0];\n for (const t of extremes) {\n if (t > critical[critical.length - 1] + 1e-6 && t < 1 - 1e-6) {\n critical.push(t);\n }\n }\n critical.push(1);\n\n const out: Array<number> = [];\n const budget = { remaining: maxSamples - critical.length }; // already-committed critical points count against the budget\n for (let i = 0; i < critical.length - 1; i++) {\n bisect(critical[i], critical[i + 1], out, seg, autoOrient, flatnessTol, rotationTol, budget);\n }\n return out;\n}\n\n\n/** Solves `P'(t).axis = 0` for one axis (a quadratic in t). Pushes any real\n * roots in `(0, 1)` into `out`. Coefficients via standard cubic Bezier\n * derivative: with `a = p1 − p0, b = p2 − p1, c = p3 − p2`, the equation is\n * `(a − 2b + c)·t² + 2(b − a)·t + a = 0`. */\nfunction addAxisExtremes(p0: number, p1: number, p2: number, p3: number, out: Array<number>): void {\n const a = p1 - p0;\n const b = p2 - p1;\n const c = p3 - p2;\n const A = a - 2 * b + c;\n const B = 2 * (b - a);\n const C = a;\n if (Math.abs(A) < 1e-10) {\n if (Math.abs(B) > 1e-10) {\n const t = -C / B;\n if (t > 1e-6 && t < 1 - 1e-6) out.push(t);\n }\n return;\n }\n const disc = B * B - 4 * A * C;\n if (disc < 0) return;\n const sq = Math.sqrt(disc);\n const t1 = (-B - sq) / (2 * A);\n const t2 = (-B + sq) / (2 * A);\n if (t1 > 1e-6 && t1 < 1 - 1e-6) out.push(t1);\n if (t2 > 1e-6 && t2 < 1 - 1e-6) out.push(t2);\n}\n\n\n/** Adaptive bisection between `tA` and `tB`. Always appends `tB` exactly once\n * (either directly when the chord is flat enough, or via recursion).\n *\n * Flatness is tested at THREE interior points (t = 0.25, 0.5, 0.75 of the\n * sub-interval), not just the midpoint. Symmetric Bezier segments often have\n * the curve crossing the chord exactly at t=0.5 — a single-midpoint check\n * would mistake that for flatness and skip subdivision, leaving visible\n * chord deviation between samples. */\nfunction bisect(\n tA: number, tB: number,\n out: Array<number>,\n seg: MotionPathSegmentCache,\n autoOrient: boolean,\n flatnessTol: number, rotationTol: number,\n budget: { remaining: number },\n): void {\n const tMid = (tA + tB) / 2;\n const pA = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);\n const pB = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);\n const span = tB - tA;\n const p25 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.25);\n const p50 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tMid);\n const p75 = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, tA + span * 0.75);\n\n const dev = Math.max(\n perpDist(p25, pA, pB),\n perpDist(p50, pA, pB),\n perpDist(p75, pA, pB),\n );\n let rotOk = true;\n if (autoOrient) {\n const tanA = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tA);\n const tanB = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, tB);\n const angA = Math.atan2(tanA[1], tanA[0]) * 180 / Math.PI;\n const angB = Math.atan2(tanB[1], tanB[0]) * 180 / Math.PI;\n let delta = Math.abs(angA - angB);\n if (delta > 180) delta = 360 - delta;\n if (delta > rotationTol) rotOk = false;\n }\n\n if ((dev <= flatnessTol && rotOk) || budget.remaining <= 0 || span < 1e-6) {\n out.push(tB);\n return;\n }\n\n budget.remaining -= 1;\n bisect(tA, tMid, out, seg, autoOrient, flatnessTol, rotationTol, budget);\n bisect(tMid, tB, out, seg, autoOrient, flatnessTol, rotationTol, budget);\n}\n\n\nfunction perpDist(q: Point2, pA: Point2, pB: Point2): number {\n const dx = pB[0] - pA[0];\n const dy = pB[1] - pA[1];\n const len2 = dx * dx + dy * dy;\n if (len2 < 1e-20) {\n const qdx = q[0] - pA[0];\n const qdy = q[1] - pA[1];\n return Math.sqrt(qdx * qdx + qdy * qdy);\n }\n const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;\n return Math.abs(cross) / Math.sqrt(len2);\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Tree walker — applies `materializeMotionPathInPropAnim` to every `node.animate.transform`\n// whose propAnim is a motion-path. Immutable: returns the input by reference\n// when no changes were needed; otherwise clones along the path to each\n// converted node and shares all other sub-trees.\n// ─────────────────────────────────────────────────────────────────────────────\n\n\n/** @internal */\nexport function materializeMotionPathsInTree(\n root: PxNode,\n opts?: MotionPathMaterializationOptions,\n): PxNode {\n const out = walkAndMaterialize(root, opts);\n return out ?? root;\n}\n\nfunction walkAndMaterialize(node: PxNode, opts?: MotionPathMaterializationOptions): PxNode | null {\n let newChildren: Array<PxNode> | undefined;\n if (node.children) {\n for (let i = 0; i < node.children.length; i++) {\n const ch = node.children[i];\n const ret = walkAndMaterialize(ch, opts);\n if (ret !== null) {\n if (!newChildren) newChildren = node.children.slice();\n newChildren[i] = ret;\n }\n }\n }\n\n let newAnimate: Record<string, PxPropertyAnimation> | undefined;\n const animBucket = node.animate;\n if (animBucket && typeof animBucket === 'object' && !Array.isArray(animBucket)) {\n const animDef = animBucket as Record<string, PxPropertyAnimation>;\n const transformAnim = animDef.transform;\n if (transformAnim && typeof transformAnim === 'object' && propAnimIsMotionPath(transformAnim)) {\n const materialized = materializeMotionPathInPropAnim(transformAnim, opts);\n if (materialized !== transformAnim) {\n newAnimate = { ...animDef, transform: materialized };\n }\n }\n }\n\n if (!newChildren && !newAnimate) return null;\n const cloned: PxNode = { ...node };\n if (newChildren) cloned.children = newChildren;\n if (newAnimate) cloned.animate = newAnimate as PxNode['animate'];\n return cloned;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { type PxAnimatedSvgDocument, type PxAnimationDefinition, type PxBezierPath, type PxNormalizedBinding, type PxBinding, type PxDefinitions, type PxElementAnimation, type PxKeyframe, type PxNormalizedKeyframe, type PxLoop, type PxNode, type PxPropertyAnimation, type PxTransformParts, keyframeTime, keyframeValue, keyframeEasing, keyframeTangentIn, keyframeTangentOut } from '../format/PxAnimatorTypes';\nimport { getBindings, getDefinitions, TRANSFORM_ATTR } from '../format/PxAnimatorConstants';\nimport { getAnimatorConfig, PxTimelineEngine, PxLoopDirection, PxLoopRepeatAt } from '../format/PxAnimatorConstants';\nimport { bezierToSvgPath, camelCaseToKebabWordIfNeeded, clamp, PX_COLOR_ATTR_NAMES, composeTransformParts, cubicBezier, interpolateBeziers, interpolateColor, interpolateNum, interpolateVec, isCamelCaseWord, parseColor, parseTransformParts, PX_PCT_BASED_ATTR_NAMES, remap, reverseEasing, splitEasing, toRGBA, PX_TRANSFORM_FN_NAMES } from '../util/PxAnimatorUtil';\nimport { evaluateMotionPathSegment, materializeMotionPathInPropAnim, propAnimIsMotionPath } from '../materialize/PxMotionPath';\n\n/**\n * Time separation between a cycle's snap-back keyframe and the previous repetition's\n * end, in ms.\n *\n * SINGLE SOURCE OF TRUTH — the editor imports this and converts to its own frame unit\n * (`TLoop.smallFrameShift = PX_LOOP_JUMP_SHIFT_MS / FRAME_DURATION_MS`), so the two sides\n * cannot drift apart and materialize different keyframes (B7).\n *\n * 1ms, not one 10ms editor frame: a 10ms snap-back is long enough to read as a visible\n * jump in a looping animation (confirmed visually). The gap only has to be non-zero — it\n * exists so the snap-back is a discontinuity rather than an interpolated tween.\n *\n * ⚠️ The editor works in FRAMES (`FRAME_DURATION_MS = 10`), so this is a sub-frame shift\n * there. `TKeyframeGroup` rounds keyframe times to integer frames in some paths; the\n * editor side keeps the fractional value and must not be re-clamped to a whole frame.\n * @internal\n */\nexport const PX_LOOP_JUMP_SHIFT_MS = 1;\n\n/** Structural equality for keyframe values (numbers, arrays, transform-part records). */\nfunction deepEqualValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== typeof b || a === null || b === null || typeof a !== 'object') return false;\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const ka = Object.keys(a as object);\n const kb = Object.keys(b as object);\n if (ka.length !== kb.length) return false;\n return ka.every(k => deepEqualValue((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]));\n}\n\n\n\n// ============================================================================\n// PATH PARSING: Convert \"path(...)\" strings to PxBezierPath format\n// ============================================================================\n\ninterface PathCommand {\n type: string;\n values: Array<number>;\n}\n\n/**\n * Parses an SVG path string into command tokens.\n * Supports M, L, C, Z commands (case-insensitive).\n */\nfunction parsePathCommands(d: string): Array<PathCommand> {\n const tokens = d.split(/([MLCZmlcz]|[\\s,]+)/).map(t => t.trim()).filter(t => t && t !== ',');\n\n const commands: Array<PathCommand> = [];\n let currentCommand: PathCommand | null = null;\n\n for (const token of tokens) {\n if (/[MLCZmlcz]/.test(token)) {\n currentCommand = { type: token, values: [] };\n commands.push(currentCommand);\n } else if (currentCommand) {\n const value = +token;\n currentCommand.values.push(Number.isNaN(value) ? 0 : value);\n }\n }\n\n return commands;\n}\n\n/**\n * Parses an internal SVG path string into PxBezierPath array.\n * Handles M (moveto), L (lineto), C (curveto), Z (close) commands.\n */\nexport function parseSvgPathToBezier(d: string): Array<PxBezierPath> {\n const res: Array<PxBezierPath> = [];\n let currentPath: PxBezierPath | undefined;\n\n const commands = parsePathCommands(d);\n\n for (const command of commands) {\n const type = command.type;\n const values = command.values;\n\n if (type === 'M' || type === 'm') {\n const x = values[0] || 0;\n const y = values[1] || 0;\n currentPath = {\n v: [[x, y]],\n i: [[x, y]],\n o: [[x, y]],\n c: false\n };\n res.push(currentPath);\n continue;\n }\n\n // Ensure we have a current path\n if (!currentPath) {\n currentPath = {\n v: [[0, 0]],\n i: [[0, 0]],\n o: [[0, 0]],\n c: false\n };\n res.push(currentPath);\n }\n\n if (type === 'L') {\n const x = values[0] || 0;\n const y = values[1] || 0;\n currentPath.v.push([x, y]);\n currentPath.i!.push([x, y]);\n currentPath.o!.push([x, y]);\n\n } else if (type === 'C') {\n const outX = values[0] || 0;\n const outY = values[1] || 0;\n const inX2 = values[2] || 0;\n const inY2 = values[3] || 0;\n const x2 = values[4] || 0;\n const y2 = values[5] || 0;\n\n // Update out-point of previous vertex\n currentPath.o![currentPath.o!.length - 1] = [outX, outY];\n\n // Add new vertex with its in-point\n currentPath.v.push([x2, y2]);\n currentPath.i!.push([inX2, inY2]);\n currentPath.o!.push([x2, y2]);\n\n } else if (type === 'Z' || type === 'z') {\n currentPath.c = true;\n\n } else {\n console.warn('Unsupported path command \"' + type + '\"');\n }\n }\n\n return res;\n}\n\n/**\n * Extracts SVG path data from a string.\n * Handles both \"path(M...)\" wrapper format and raw \"M...\" format.\n * @returns The path data string, or undefined if not a valid path string\n */\nfunction extractPathData(str: string): string | undefined {\n if (str.startsWith('path(') && str.endsWith(')')) {\n return str.slice(5, -1); // Remove \"path(\" and \")\"\n }\n // Raw path string starting with a path command (M, m, or other commands)\n if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str)) {\n return str;\n }\n return undefined;\n}\n\n/**\n * Checks if the value is a path string (either \"path(...)\" or raw \"M...\").\n */\nfunction isPathString(value: any): value is string {\n return typeof value === 'string' && extractPathData(value) !== undefined;\n}\n\n/**\n * Normalizes a 'd' attribute value to { paths: PxBezierPath[] } format.\n * Handles:\n * - { pathData: \"M...\" } / { pathData: \"path(...)\" } -> { paths: [PxBezierPath] } (THE wire form)\n * - { paths: [\"path(...)\"] } -> { paths: [PxBezierPath] }\n * - { paths: [\"M...\"] } -> { paths: [PxBezierPath] }\n * - [\"path(...)\"] -> { paths: [PxBezierPath] }\n * - [\"M...\"] -> { paths: [PxBezierPath] }\n * - \"path(...)\" -> { paths: [PxBezierPath] }\n * - \"M...\" -> { paths: [PxBezierPath] }\n * - { paths: [PxBezierPath] } -> as-is\n */\nfunction normalizePathValue(value: any): { paths: Array<PxBezierPath> } | any {\n // THE wire form: { pathData: \"M...\" } (compound = multiple `M…` sub-paths in one string).\n // The `{ paths: [...] }` shapes below are this function's OWN output, not wire spellings.\n if (value && typeof value === 'object' && typeof value.pathData === 'string') {\n const d = extractPathData(value.pathData);\n return d ? { paths: parseSvgPathToBezier(d) } : value;\n }\n\n // If already in { paths: [...] } format\n if (value && typeof value === 'object' && 'paths' in value) {\n const pathsArray = value.paths;\n if (Array.isArray(pathsArray) && pathsArray.length > 0) {\n // Check if paths contain path strings that need parsing\n if (isPathString(pathsArray[0])) {\n const paths: Array<PxBezierPath> = [];\n for (const pathStr of pathsArray) {\n const d = extractPathData(pathStr);\n if (d) {\n paths.push(...parseSvgPathToBezier(d));\n }\n }\n return { paths };\n }\n }\n // Already in correct format\n return value;\n }\n\n // If it's an array of path strings\n if (Array.isArray(value)) {\n if (value.length > 0 && isPathString(value[0])) {\n const paths: Array<PxBezierPath> = [];\n for (const pathStr of value) {\n const d = extractPathData(pathStr);\n if (d) {\n paths.push(...parseSvgPathToBezier(d));\n }\n }\n return { paths };\n }\n // Already an array of PxBezierPath - wrap in { paths: }\n return { paths: value };\n }\n\n // If it's a single path string\n if (isPathString(value)) {\n const d = extractPathData(value)!;\n return { paths: parseSvgPathToBezier(d) };\n }\n\n return value;\n}\n\n\n// ============================================================================\n// NORMALIZATION: Convert new API format to internal normalized format\n// ============================================================================\n\n/**\n * Resolves an easing reference to a cubic-bezier array.\n * @param easing The easing reference (string name or bezier array)\n * @param defs The definitions containing named easings\n * @returns The resolved cubic-bezier array or undefined\n */\nfunction resolveEasing(\n easing: string | [number, number, number, number] | undefined,\n defs?: PxDefinitions\n): [number, number, number, number] | undefined {\n if (!easing) return undefined;\n\n if (Array.isArray(easing)) {\n return easing;\n }\n\n // Look up named easing in defs\n if (defs?.easings?.[easing]) {\n return defs.easings[easing];\n }\n\n // Unknown easing name - return undefined\n console.warn('Unknown easing name: ' + easing);\n return undefined;\n}\n\n/**\n * Resolves an animation reference to an AnimationDefinition.\n * @param animRef The animation reference (string name or inline definition)\n * @param defs The definitions containing named animations\n * @returns The resolved animation definition\n */\nfunction resolveAnimation(\n animRef: string | PxAnimationDefinition,\n defs?: PxDefinitions\n): PxAnimationDefinition | undefined {\n if (typeof animRef === 'string') {\n // Look up named animation in defs\n const resolved = defs?.animations?.[animRef];\n if (!resolved) {\n console.warn('Unknown animation name: ' + animRef);\n }\n return resolved;\n }\n\n // It's an inline definition\n return animRef;\n}\n\n/**\n * Resolves an element animation (which can be string, array, or inline) to an array of AnimationDefinitions.\n * @param animate The element animation specification\n * @param defs The definitions containing named animations\n * @returns Array of resolved animation definitions\n */\nfunction resolveElementAnimation(\n animate: PxElementAnimation | undefined,\n defs?: PxDefinitions\n): PxAnimationDefinition[] {\n if (!animate) return [];\n\n const results: PxAnimationDefinition[] = [];\n\n if (typeof animate === 'string') {\n const resolved = resolveAnimation(animate, defs);\n if (resolved) results.push(resolved);\n } else if (Array.isArray(animate)) {\n for (const item of animate) {\n const resolved = resolveAnimation(item, defs);\n if (resolved) results.push(resolved);\n }\n } else {\n // It's an inline AnimationDefinition\n results.push(animate);\n }\n\n return results;\n}\n\n// ============================================================================\n// LOOP EXPANSION: Duplicate keyframe segments to fill gaps in the timeline\n// ============================================================================\n\n/**\n * Interpolates between two keyframe values based on property type.\n * Returns the raw interpolated value (not a CSS string).\n *\n * Dispatch order matters — the unified-transform-record branch must run\n * BEFORE the standalone-`rotate` branch, otherwise a `transform`-named\n * animation whose kfs are number-typed (rare but valid) would be routed\n * through the vec path.\n * @internal\n */\nexport function interpolateValue(propName: string, a: any, b: any, t: number): any {\n if (propName === 'd') {\n const aPaths = a?.paths ?? (Array.isArray(a) ? a : []);\n const bPaths = b?.paths ?? (Array.isArray(b) ? b : []);\n return { paths: interpolateBeziers(aPaths, bPaths, t) };\n }\n if (PX_COLOR_ATTR_NAMES.has(propName)) {\n return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);\n }\n // Unified-transform record (`{translate, rotate, scale, origin}`) — the\n // most common animated `propName === 'transform'` shape. Per-part interp\n // so `+({}) = NaN` (the old fall-through) doesn't poison the boundary kf\n // at a loop seam.\n if (propName === 'transform'\n && typeof a === 'object' && a !== null && !Array.isArray(a)\n && typeof b === 'object' && b !== null && !Array.isArray(b)\n ) {\n return interpolateTransformParts(a as PxTransformParts, b as PxTransformParts, t);\n }\n // Standalone `rotate` as a propAnim — value is a NUMBER, not a vector.\n // The general PX_TRANSFORM_FN_NAMES branch below would route it through\n // `interpolateVec`, which on a scalar returns `[]` (length NaN → no loop)\n // — wrong CSS output.\n if (propName === 'rotate' && typeof a === 'number' && typeof b === 'number') {\n return interpolateNum(a, b, t);\n }\n if (PX_TRANSFORM_FN_NAMES.has(propName) || propName === 'stroke-dasharray' || propName === 'strokeDasharray') {\n return interpolateVec(a || [], b || [], t);\n }\n return interpolateNum(+(a || 0), +(b || 0), t);\n}\n\n/** Per-part interpolation for a unified-transform parts record. Mirrors the\n * inline logic in `calcPropertyValue`'s transform branch. */\nfunction interpolateTransformParts(a: PxTransformParts, b: PxTransformParts, t: number): PxTransformParts {\n const keys = new Set<string>([...Object.keys(a ?? {}), ...Object.keys(b ?? {})]);\n const out: { [k: string]: unknown } = {};\n for (const k of keys) {\n const av = (a as { [k: string]: unknown })?.[k];\n const bv = (b as { [k: string]: unknown })?.[k];\n if (k === 'rotate' || k === 'skew') {\n out[k] = interpolateNum(+(av ?? 0), +(bv ?? 0), t);\n } else if (k === 'translate' || k === 'scale' || k === 'origin') {\n const fallback: Array<number> = k === 'scale' ? [1, 1] : [0, 0];\n out[k] = interpolateVec((av as Array<number>) || fallback, (bv as Array<number>) || fallback, t);\n } else {\n // Unknown part — prefer next if present, otherwise prev.\n out[k] = bv ?? av;\n }\n }\n return out as PxTransformParts;\n}\n\ninterface LoopTemplateEntry {\n relT: number; // 0..1 relative position within segment\n v: any;\n e: [number, number, number, number] | undefined;\n // Per-vertex spatial tangents (motion-along-path). Carried so repeated\n // segments keep their curvature; reversed reps swap in<->out (see appendRep).\n tangentIn?: [number, number];\n tangentOut?: [number, number];\n}\n\n/**\n * Expands keyframes by repeating a segment to fill the gap between the keyframe\n * range and the global animation duration, implementing PxLoop \"local loop\" behavior.\n */\nfunction expandLoopKeyframes(\n propName: string,\n keyframes: PxNormalizedKeyframe[],\n loop: PxLoop,\n duration: number\n): PxNormalizedKeyframe[] {\n const totalIntervals = keyframes.length - 1;\n const segCount = clamp(loop.segmentCount ?? totalIntervals, 1, totalIntervals);\n\n // Extract segment keyframes\n let segKfs: PxNormalizedKeyframe[];\n if (loop.repeatAt === PxLoopRepeatAt.start) {\n segKfs = keyframes.slice(0, segCount + 1);\n } else {\n segKfs = keyframes.slice(totalIntervals - segCount);\n }\n\n // Determine fill region\n const firstT = keyframes[0].t ?? 0;\n const lastT = keyframes[keyframes.length - 1].t ?? 0;\n\n let fillStart: number, fillEnd: number;\n if (loop.repeatAt === PxLoopRepeatAt.start) {\n fillStart = 0;\n fillEnd = firstT;\n } else {\n fillStart = lastT;\n fillEnd = duration;\n }\n\n const fillDuration = fillEnd - fillStart;\n if (fillDuration <= 0) return keyframes;\n\n // Segment timing\n const segStartT = segKfs[0].t ?? 0;\n const segEndT = segKfs[segKfs.length - 1].t ?? 0;\n const segDuration = segEndT - segStartT;\n if (segDuration <= 0) return keyframes;\n\n // Build template with relative offsets (0..1)\n const template: LoopTemplateEntry[] = segKfs.map(kf => ({\n relT: (kf.t! - segStartT) / segDuration,\n v: kf.v,\n e: kf.e as [number, number, number, number] | undefined,\n tangentIn: keyframeTangentIn(kf) as [number, number] | undefined,\n tangentOut: keyframeTangentOut(kf) as [number, number] | undefined\n }));\n\n const fullReps = Math.floor(fillDuration / segDuration);\n const remainder = fillDuration - fullReps * segDuration;\n const partialFraction = remainder / segDuration;\n\n const looped: PxNormalizedKeyframe[] = [];\n\n // A cycle's first keyframe lands at the SAME time as the previous repetition's\n // last one. Emitting both at that time makes the value at that instant depend on\n // the sampler's tie-break, and left the player disagreeing with the editor (B7).\n // Mirror `TLoop.toKeyframes` exactly:\n // - values EQUAL (pingpong turn, closed loop) → the duplicate says nothing, skip it;\n // - values DIFFER (a real cycle snap) → separate them by PX_LOOP_JUMP_SHIFT_MS.\n // The editor's shift is one 10ms frame (`smallFrameShift`), so the two sides\n // materialize identical keyframes. Anything smaller is blocked editor-side: a\n // fractional-frame shift was tried there and reverted (TKeyframeGroup mishandles it).\n // SCOPE: loopOut (`after`) only — see the note above. For loopIn the pair sits in\n // the opposite order in the array, so separating it means moving the EARLIER\n // keyframe earlier; done naively it inverts keyframe order and re-breaks the\n // loopIn `f0` regression (`appendRepTail`). Left as-is until it has its own\n // editor-CSS evidence; the two sides may still differ at a loopIn boundary.\n const separateBoundary = loop.repeatAt !== PxLoopRepeatAt.start;\n // The keyframe the FIRST repetition butts up against: loopOut tiles forward from\n // the last original keyframe (the originals are concatenated only at assembly).\n const originalTerminalKf: PxNormalizedKeyframe | undefined = keyframes[keyframes.length - 1];\n\n // Easing that a skipped boundary keyframe hands to the ORIGINAL terminal keyframe.\n // Easing describes the interval that FOLLOWS a keyframe, so when a pingpong turn's\n // duplicate is dropped (same value, nothing to say about position) its easing is NOT\n // redundant — it owns the return leg. Without this hand-off the return leg renders\n // LINEAR while the outbound is eased. The originals belong to the caller, so it is\n // applied by replacing the terminal with a copy at assembly, never by mutation.\n let terminalEasingOverride: PxNormalizedKeyframe['e'] | undefined;\n let hasTerminalEasingOverride = false;\n\n // Helper: append one full or partial repetition\n function appendRep(repStart: number, isReversed: boolean, partial?: number) {\n let entries: LoopTemplateEntry[];\n if (isReversed) {\n // Reverse keyframe order and reverse easings\n entries = [];\n for (let i = template.length - 1; i >= 0; i--) {\n entries.push({\n relT: 1 - template[i].relT,\n v: template[i].v,\n // Easing for reversed transition: use reversed easing from the forward \"from\" keyframe\n e: i > 0 ? reverseEasing(template[i - 1].e) : undefined,\n // Reversed traversal swaps each vertex's in/out spatial tangents\n // (geometry is identical, walked backwards), so curvature and\n // auto-orientation survive the reversed rep.\n tangentIn: template[i].tangentOut,\n tangentOut: template[i].tangentIn\n });\n }\n } else {\n entries = template;\n }\n\n const cutRelT = partial !== undefined ? partial : 1;\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n if (entry.relT > cutRelT + 1e-9) {\n // Past the cut point — insert interpolated keyframe\n const prev = entries[i - 1];\n const intervalSpan = entry.relT - prev.relT;\n const localFrac = (cutRelT - prev.relT) / intervalSpan;\n\n // Apply easing to get the eased progress for value interpolation\n const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;\n const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);\n\n // Split easing — use left portion for the truncated interval\n const { left: leftEasing } = splitEasing(prev.e, localFrac);\n\n // Update previous keyframe's easing to the left portion\n if (looped.length > 0 && prev.relT <= cutRelT) {\n looped[looped.length - 1].e = leftEasing;\n }\n\n looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: undefined });\n return;\n }\n\n // Repetition boundary: this entry coincides in time with whatever precedes\n // it. For the FIRST rep that neighbour is the last ORIGINAL keyframe (the\n // originals are concatenated only at assembly time), not a `looped` entry.\n const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;\n const isBoundary = separateBoundary && i === 0 && prevKf !== undefined\n && Math.abs((prevKf.t ?? 0) - (repStart + entry.relT * segDuration)) < 1e-9;\n if (isBoundary) {\n if (deepEqualValue(prevKf.v, entry.v)) {\n // Pingpong turn — the duplicate says nothing about VALUE, but it carries\n // the easing (and out-tangent) for the interval that follows it. Hand\n // those to the surviving neighbour instead of discarding them.\n if (looped.length > 0) {\n prevKf.e = entry.e;\n prevKf.tangentOut = entry.tangentOut;\n } else {\n terminalEasingOverride = entry.e;\n hasTerminalEasingOverride = true;\n }\n continue;\n }\n // Real snap: the jump segment must not carry motion-path tangents.\n // Only ours are safe to mutate — never the caller's originals.\n if (looped.length > 0) { delete prevKf.tangentIn; delete prevKf.tangentOut; }\n }\n\n const pushed: PxNormalizedKeyframe = {\n t: repStart + entry.relT * segDuration + (isBoundary ? PX_LOOP_JUMP_SHIFT_MS : 0),\n v: entry.v,\n e: i < entries.length - 1 ? entry.e : undefined\n };\n // Carry per-vertex spatial tangents so the repeated segment keeps its\n // motion-path curvature (reversed reps already have in/out swapped above).\n if (entry.tangentIn) pushed.tangentIn = entry.tangentIn;\n if (entry.tangentOut) pushed.tangentOut = entry.tangentOut;\n looped.push(pushed);\n }\n }\n\n // Like {@link appendRep} but emits only the TAIL of the segment — relT ∈\n // [1-tailFraction, 1] — over [repStart, repStart + tailFraction*segDuration].\n // Used for the leftover (partial) rep of a `before` loop: it sits at fillStart\n // and runs UP TO the segment-end value, so the full reps after it align to end\n // exactly at the first original keyframe (firstT). A head-truncated partial here\n // (as appendRep does) would land the leftover ADJACENT to firstT and desync the\n // whole backward fill — the loopIn `f0` bug.\n function appendRepTail(repStart: number, isReversed: boolean, tailFraction: number) {\n let entries: LoopTemplateEntry[];\n if (isReversed) {\n entries = [];\n for (let i = template.length - 1; i >= 0; i--) {\n entries.push({\n relT: 1 - template[i].relT,\n v: template[i].v,\n e: i > 0 ? reverseEasing(template[i - 1].e) : undefined,\n tangentIn: template[i].tangentOut,\n tangentOut: template[i].tangentIn\n });\n }\n } else {\n entries = template;\n }\n\n const startRelT = 1 - tailFraction;\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n if (entry.relT < startRelT - 1e-9) continue; // wholly before the tail window\n const prev = entries[i - 1];\n\n // If startRelT falls strictly inside (prev, entry), the tail begins\n // mid-interval — emit an interpolated keyframe at repStart carrying the\n // RIGHT split of prev's easing.\n if (prev && prev.relT < startRelT - 1e-9 && entry.relT > startRelT + 1e-9) {\n const intervalSpan = entry.relT - prev.relT;\n const localFrac = (startRelT - prev.relT) / intervalSpan;\n const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;\n const startValue = interpolateValue(propName, prev.v, entry.v, easedFrac);\n const { right: rightEasing } = splitEasing(prev.e, localFrac);\n looped.push({ t: repStart, v: startValue, e: rightEasing });\n }\n\n const pushed: PxNormalizedKeyframe = {\n t: repStart + (entry.relT - startRelT) * segDuration,\n v: entry.v,\n e: i < entries.length - 1 ? entry.e : undefined\n };\n if (entry.tangentIn) pushed.tangentIn = entry.tangentIn;\n if (entry.tangentOut) pushed.tangentOut = entry.tangentOut;\n looped.push(pushed);\n }\n }\n\n // Generate repetitions.\n // The rep closest to the original keyframes boundary must be reversed first\n // in pingpong mode (the animation just finished going forward, so the next\n // iteration goes backward).\n if (loop.repeatAt === PxLoopRepeatAt.start) {\n // loopIn — the fill must END exactly at the first keyframe (firstT), so the\n // reps tile BACKWARD from that boundary: the leftover (partial) rep sits at\n // fillStart showing the segment's tail, then `fullReps` full reps run up to\n // firstT. (Forward-tiling — as loopOut does — would push the partial next to\n // firstT and desync the fill: the loopIn `f0` regression.)\n if (partialFraction > 1e-9) {\n const isReversed = loop.direction === PxLoopDirection.alternate && (fullReps % 2 === 0);\n appendRepTail(fillStart, isReversed, partialFraction);\n }\n for (let rep = 0; rep < fullReps; rep++) {\n const distFromBoundary = fullReps - 1 - rep;\n const isReversed = loop.direction === PxLoopDirection.alternate && (distFromBoundary % 2 === 0);\n const repStart = fillStart + remainder + rep * segDuration;\n appendRep(repStart, isReversed);\n }\n } else {\n // loopOut — boundary is at fillStart (lastT); tile forward, partial at the end.\n for (let rep = 0; rep < fullReps; rep++) {\n const isReversed = loop.direction === PxLoopDirection.alternate && (rep % 2 === 0);\n const repStart = fillStart + rep * segDuration;\n appendRep(repStart, isReversed);\n }\n if (partialFraction > 1e-9) {\n const isReversed = loop.direction === PxLoopDirection.alternate && (fullReps % 2 === 0);\n const repStart = fillStart + fullReps * segDuration;\n appendRep(repStart, isReversed, partialFraction);\n }\n }\n\n // Assemble: looped keyframes go before or after the original keyframes.\n // No junction deduplication — cycle mode relies on value jumps at boundaries.\n if (loop.repeatAt === PxLoopRepeatAt.start) {\n return [...looped, ...keyframes];\n } else {\n if (hasTerminalEasingOverride && keyframes.length > 0) {\n const head = keyframes.slice(0, -1);\n const tail = { ...keyframes[keyframes.length - 1], e: terminalEasingOverride };\n return [...head, tail, ...looped];\n }\n return [...keyframes, ...looped];\n }\n}\n\n\n// ============================================================================\n// KEYFRAME NORMALIZATION\n// ============================================================================\n\n/**\n * Normalizes keyframes from the new API format (time in ms) to internal format (time as 0-1 fraction).\n * Resolves easing references, normalizes times, and converts path strings for 'd' attribute.\n * If a loop configuration is present, expands the keyframes to fill the global duration.\n * @param propName The property name (e.g., 'd' for path)\n * @param propAnim The property animation with keyframes\n * @param duration The total animation duration in ms\n * @param defs The definitions containing named easings\n * @returns Array of normalized keyframes (same structure, resolved refs, normalized times)\n */\nfunction normalizeKeyframes(\n propName: string,\n propAnim: PxPropertyAnimation,\n duration: number,\n defs?: PxDefinitions\n): PxNormalizedKeyframe[] {\n const keyframes = propAnim.keyframes || [];\n\n const normalized: PxNormalizedKeyframe[] = [];\n\n for (const kf of keyframes) {\n const timePct = keyframeTime(kf);\n let value = keyframeValue(kf);\n const easing = keyframeEasing(kf);\n\n // Normalize path values for 'd' attribute\n if (propName === 'd') {\n value = normalizePathValue(value);\n }\n\n // Normalize color values (hex/rgb/rgba strings to [0-1] vectors).\n // `PX_COLOR_ATTR_NAMES` is keyed in kebab-case (`stop-color`, `flood-color`,\n // `lighting-color`); the wire format uses both kebab AND camelCase\n // (`stopColor`) for these props. Without converting, frames-mode would\n // call `interpolateColor` on the raw strings and produce `NaN` channels\n // — the visible \"rgba(NaN,NaN,NaN,…)\" bug on stop-color animations.\n const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;\n if (PX_COLOR_ATTR_NAMES.has(propNameKebab)) {\n value = parseColor(value) ?? value;\n }\n\n const normKf: PxNormalizedKeyframe = {\n t: timePct,\n v: value,\n e: resolveEasing(easing, defs)\n };\n // Motion-along-path: keep the spatial tangents so the downstream\n // `materializeMotionPathInPropAnim` (called in `normalizeAnimationDefinition`) can\n // sample them into transform kfs. Short aliases `ti` / `to` collapse\n // into their canonical names.\n const tIn = keyframeTangentIn(kf);\n const tOut = keyframeTangentOut(kf);\n if (tIn) normKf.tangentIn = tIn;\n if (tOut) normKf.tangentOut = tOut;\n\n normalized.push(normKf);\n }\n\n // Sort by time\n normalized.sort((a, b) => (a.t ?? 0) - (b.t ?? 0));\n\n // Expand loop if configured (loop:true is shorthand for default PxLoop)\n const loopRaw = propAnim.loop;\n const loop: PxLoop | undefined = loopRaw === true ? {} : loopRaw || undefined;\n if (loop && normalized.length >= 2) {\n return expandLoopKeyframes(propName, normalized, loop, duration);\n }\n\n return normalized;\n}\n\n/**\n * Merges multiple animation definitions into a single combined definition.\n * Later definitions override earlier ones for the same property.\n */\nfunction mergeAnimationDefinitions(\n animations: PxAnimationDefinition[]\n): PxAnimationDefinition {\n const merged: PxAnimationDefinition = {};\n\n for (const anim of animations) {\n for (const [prop, propAnim] of Object.entries(anim)) {\n merged[prop] = propAnim;\n }\n }\n\n return merged;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public loop-materialization API\n//\n// Used internally by `normalizeKeyframes` (where `expandLoopKeyframes` is\n// already called at the tail of normalization). Exposed here at the propAnim\n// and tree levels so the Editor (or any external caller) can compose:\n// root = materializeNodeEffects(root).root;\n// root = materializeInternalLoopsInTree(root, duration);\n// root = materializeMotionPathsInTree(root);\n// to produce a fully-flat document with no `loop`, no `effects`, no tangents.\n// ─────────────────────────────────────────────────────────────────────────────\n\n\n/**\n * Replaces `propAnim.loop` with explicit repeated keyframes via\n * `expandLoopKeyframes`. Returns the input by reference when no loop is\n * configured (no-op). Output drops the `loop` field (consumed).\n * @internal\n */\nexport function materializeInternalLoopsInPropAnim(\n propName: string,\n propAnim: PxPropertyAnimation,\n duration: number,\n): PxPropertyAnimation {\n const loopRaw = propAnim.loop;\n if (loopRaw === undefined || loopRaw === null || loopRaw === false) return propAnim;\n const loop: PxLoop = loopRaw === true ? {} : (loopRaw as PxLoop);\n const rawKfs = propAnim.keyframes as PxKeyframe[] | undefined;\n if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;\n\n // `expandLoopKeyframes` reads kf.t / kf.v / kf.e (short form). When this\n // function is called from the materialization pipeline OUTSIDE the\n // binding-normalization path (e.g. by `materializeAllInTree`), the input\n // kfs may still be in long form (`time` / `value` / `easing`) AND the\n // values may be unparsed (hex color strings, raw path-`d`). Normalize\n // both here so `interpolateValue` (called by `expandLoopKeyframes` at the\n // loop seam) sees structured data — without this, a color boundary kf\n // ends up `[NaN,NaN,NaN,NaN]` and the bug stays visible until the\n // animation cycle restarts.\n const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;\n const isColor = PX_COLOR_ATTR_NAMES.has(propNameKebab);\n const kfs: PxNormalizedKeyframe[] = rawKfs.map(kf => {\n const t = keyframeTime(kf);\n let v: unknown = keyframeValue(kf);\n if (propName === 'd') v = normalizePathValue(v);\n if (isColor) v = parseColor(v) ?? v;\n const e = keyframeEasing(kf);\n const out: PxNormalizedKeyframe = { t, v, e };\n const tIn = keyframeTangentIn(kf);\n const tOut = keyframeTangentOut(kf);\n if (tIn) out.tangentIn = tIn;\n if (tOut) out.tangentOut = tOut;\n return out;\n });\n\n const expanded = expandLoopKeyframes(propName, kfs, loop, duration);\n const out: PxPropertyAnimation = { keyframes: expanded };\n if (propAnim.autoOrient !== undefined) (out as { autoOrient?: unknown }).autoOrient = propAnim.autoOrient;\n return out;\n}\n\n\n/**\n * Walks `root` and materializes every animated property's `loop` via\n * `materializeInternalLoopsInPropAnim`. Immutable — returns the input by\n * reference when no loop was found anywhere; otherwise clones along the path\n * to each affected node, sharing untouched sub-trees.\n * @internal\n */\nexport function materializeInternalLoopsInTree(\n root: PxNode,\n duration: number,\n): PxNode {\n const ret = walkAndMaterializeLoops(root, duration);\n return ret ?? root;\n}\n\nfunction walkAndMaterializeLoops(node: PxNode, duration: number): PxNode | null {\n let newChildren: Array<PxNode> | undefined;\n if (node.children) {\n for (let i = 0; i < node.children.length; i++) {\n const ret = walkAndMaterializeLoops(node.children[i], duration);\n if (ret !== null) {\n if (!newChildren) newChildren = node.children.slice();\n newChildren[i] = ret;\n }\n }\n }\n let newAnimate: Record<string, PxPropertyAnimation> | undefined;\n const animBucket = node.animate;\n if (animBucket && typeof animBucket === 'object' && !Array.isArray(animBucket)) {\n const animDef = animBucket as Record<string, PxPropertyAnimation>;\n for (const propName of Object.keys(animDef)) {\n const propAnim = animDef[propName];\n const materialized = materializeInternalLoopsInPropAnim(propName, propAnim, duration);\n if (materialized !== propAnim) {\n if (!newAnimate) newAnimate = { ...animDef };\n newAnimate[propName] = materialized;\n }\n }\n }\n if (!newChildren && !newAnimate) return null;\n const cloned: PxNode = { ...node };\n if (newChildren) cloned.children = newChildren;\n if (newAnimate) cloned.animate = newAnimate as PxNode['animate'];\n return cloned;\n}\n\n\n/**\n * Generates a unique element ID for internal tracking during DOM rendering.\n */\nlet _elementIdCounter = 0;\nexport function generateElementId(): string {\n return '_px_el_' + (++_elementIdCounter);\n}\n\n/**\n * Resets the element ID counter (useful for testing).\n */\nexport function resetElementIdCounter(): void {\n _elementIdCounter = 0;\n}\n\n/**\n * TRANSFORM PRECEDENCE (review §0.4/§1.6) — CSS's own composition rule, applied at READ:\n * a static `transform` on the element composes UNDER the animated transform, instead of\n * being silently clobbered by it. Implemented as a keyframe-value MERGE during\n * normalization, so both engines (and every consumer downstream) see complete parts:\n *\n * 1. `animate.transform` with PARTIAL parts records — every keyframe value (and the\n * base `value`) inherits the static parts it does not set:\n * static `{rotate: 45}` + kf `{translate: [80, 0]}` → kf `{rotate: 45, translate: [80, 0]}`.\n * 2. ONE individual channel (`translate` / `rotate` / `scale` / `skew`) and no\n * `transform` channel — the channel is REWRITTEN as a unified `transform` channel\n * whose values carry the static parts: the rect stays rotated 45° AND slides.\n *\n * The static transform may be a parts record or an attribute string (parsed by the\n * conservative {@link parseTransformParts} — unparseable strings skip the merge).\n * NOT merged (documented limitations): several individual channels animated at once\n * (they still last-write-wins against each other), and an individual channel next to an\n * animated `transform` (the `transform` channel wins, as before).\n * @internal\n */\nexport function mergeStaticTransformIntoAnimDef(\n animDef: PxAnimationDefinition,\n staticTransform: unknown,\n): PxAnimationDefinition {\n if (!animDef) return animDef;\n const staticParts: PxTransformParts | undefined =\n staticTransform && typeof staticTransform === 'object' && !Array.isArray(staticTransform)\n ? staticTransform as PxTransformParts\n : parseTransformParts(staticTransform as string);\n if (!staticParts || !Object.keys(staticParts).length) return animDef;\n\n const mergeKfValue = (v: unknown): unknown =>\n v && typeof v === 'object' && !Array.isArray(v) ? { ...staticParts, ...(v as PxTransformParts) } : v;\n\n const transformAnim = animDef[TRANSFORM_ATTR];\n if (transformAnim && typeof transformAnim === 'object') {\n const anim = transformAnim as PxPropertyAnimation;\n if (Array.isArray(anim.keyframes)) {\n const out: PxPropertyAnimation = {\n ...anim,\n keyframes: anim.keyframes.map(kf => ({ ...kf, value: mergeKfValue(kf.value) })),\n };\n if (out.value !== undefined) out.value = mergeKfValue(out.value) as PxPropertyAnimation['value'];\n return { ...animDef, transform: out };\n }\n return animDef;\n }\n\n const channels = Object.keys(animDef).filter(k => PX_TRANSFORM_FN_NAMES.has(k));\n if (channels.length !== 1) return animDef; // several channels: unchanged (documented)\n const ch = channels[0];\n const chAnim = animDef[ch] as PxPropertyAnimation;\n if (!chAnim || typeof chAnim !== 'object' || !Array.isArray(chAnim.keyframes)) return animDef;\n const lifted: PxPropertyAnimation = {\n ...chAnim,\n keyframes: chAnim.keyframes.map(kf => ({ ...kf, value: { ...staticParts, [ch]: kf.value } })),\n };\n if (lifted.value !== undefined) lifted.value = { ...staticParts, [ch]: lifted.value };\n const rest: PxAnimationDefinition = { ...animDef };\n delete rest[ch];\n return { ...rest, transform: lifted };\n}\n\n/**\n * Normalizes an animation definition by resolving easing references and normalizing keyframe times.\n * Keeps the key/value mapping structure. `engine` controls motion-along-path\n * handling — see {@link PxTimelineEngine}.\n */\nfunction normalizeAnimationDefinition(\n animDef: PxAnimationDefinition,\n duration: number,\n defs?: PxDefinitions,\n engine: PxTimelineEngine = PxTimelineEngine.native,\n): PxAnimationDefinition {\n const normalized: PxAnimationDefinition = {};\n\n for (const [propName, propAnim] of Object.entries(animDef)) {\n // `alongPathMode: 'offsetPath'` — this transform's motion is rendered by CSS\n // Motion Path (`offset-path` style on the element + an `offsetDistance` track in\n // the same dict). The tangented keyframes stay on the wire as the DESIGN source\n // (the editor round-trip reads them back), but the player must not ALSO drive\n // them: doing both moved the element to the path position and then translated it\n // again (double position). Skip the binding; `offsetDistance` owns the motion.\n if (propName === 'transform'\n && (propAnim as { alongPathMode?: string }).alongPathMode === 'offsetPath'\n // …but ONLY when the offset infrastructure actually exists (an `offsetDistance`\n // track in the same definition — the pre-rendered dict shape, or a lightweight\n // doc the offset materializer rewrote). A marked transform the materializer\n // BAILED on (e.g. rotate animated in the same keyframes — inexpressible as\n // offset-path) must fall through to the ordinary sampled pipeline; skipping it\n // unconditionally froze those elements at their base pose.\n && (animDef as Record<string, unknown>)['offsetDistance'] !== undefined) {\n continue;\n }\n const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);\n if (normalizedKfs.length > 0) {\n // Internal normalized form converges on `keyframes` too — the `kfs` alias\n // is gone from the format AND the runtime (review §1.2/§6.1).\n const out: PxPropertyAnimation = { keyframes: normalizedKfs };\n // Carry top-level animation flags through normalization — `materializeMotionPathInPropAnim`\n // and the runtime evaluators need `autoOrient` / `loop` to be present\n // alongside the kfs.\n if (propAnim.autoOrient !== undefined) out.autoOrient = propAnim.autoOrient;\n if (propAnim.loop !== undefined) out.loop = propAnim.loop;\n\n // Pipeline: loops are already expanded by `normalizeKeyframes` above.\n // For the `waapi` engine ONLY, materialize motion-along-path\n // (tangented `transform` kfs + autoOrient) into plain sampled\n // `{ translate, rotate? }` kfs — CSS WAAPI can't evaluate parametric\n // tangents at runtime. Frames-mode keeps the parametric form so the\n // frame-loop kernel `evaluateMotionPathSegment` can sample per frame\n // (better spatial fidelity than any finite sampling).\n // `materializeMotionPathInPropAnim` is a no-op for non-motion-path\n // animations, so non-transform props pay zero cost.\n normalized[propName] = (engine === PxTimelineEngine.native && propName === 'transform')\n ? materializeMotionPathInPropAnim(out)\n : out;\n }\n }\n\n return normalized;\n}\n\n/**\n * Normalizes a PxAnimatedSvgDocument to a PxAnimatorConfig for the animation engines.\n * This is the main entry point for converting the new API format to internal format.\n * Resolves animation/easing references. `engine` controls motion-along-path\n * handling — see {@link PxTimelineEngine}.\n * @public @advanced\n */\nexport function normalizeBindings(\n doc: PxAnimatedSvgDocument,\n engine: PxTimelineEngine = PxTimelineEngine.native,\n): PxNormalizedBinding[] {\n const animatorConfig = getAnimatorConfig(doc) || {};\n const defs = getDefinitions(doc);\n const duration = animatorConfig.duration || 1000; // FIXME - get rid of 1000 here\n\n const bindings: PxNormalizedBinding[] = [];\n\n // Helper to merge and normalize the resolved animation definitions of one element\n const processAnimation = (\n id: string,\n animDefs: PxAnimationDefinition[],\n staticTransform?: unknown,\n ): PxNormalizedBinding | null => {\n if (animDefs.length === 0) return null;\n\n // CSS transform precedence (review §0.4/§1.6): the node's static transform\n // composes under the animated one — merged BEFORE normalization so both\n // engines see complete parts records.\n const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);\n const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);\n\n if (Object.keys(normalizedAnim).length === 0) return null;\n\n return {\n id,\n animate: normalizedAnim\n };\n };\n\n // Process bindings (for pre-rendered DOM): `target` is `#id`-spelled on the wire (every\n // element reference carries the hash — review §3.2); the engines get the bare DOM id.\n const docBindings = getBindings(doc);\n if (docBindings) {\n for (const binding of docBindings) {\n const id = binding.target.startsWith('#') ? binding.target.slice(1) : binding.target;\n const animDefs = binding.animateWith\n .map(name => resolveAnimation(name, defs))\n .filter((d): d is PxAnimationDefinition => !!d);\n const normalized = processAnimation(id, animDefs);\n if (normalized) bindings.push(normalized);\n }\n }\n\n // Process children (for rendered DOM).\n //\n // Per-element animations live under the node's `animate` bucket, keyed by\n // SVG/CSS property name — a PxAnimationDefinition (`{ transform: {keyframes},\n // fill: {keyframes}, … }`). The static initial value of each animated\n // property is carried separately as a plain attribute on the element body.\n // On-disk locations: top-level `node.animate` (JSON form).\n const processNode = (node: PxNode) => {\n const inlineAnim = node.animate;\n if (inlineAnim && Object.keys(inlineAnim).length > 0) {\n const nodeId = node.id || generateElementId();\n node.id = nodeId; // Ensure the node has an ID\n const normalized = processAnimation(nodeId, resolveElementAnimation(inlineAnim, defs), node.transform);\n if (normalized) bindings.push(normalized);\n }\n\n // Process children\n if (node.children) {\n for (let i = 0; i < node.children.length; i++) {\n processNode(node.children[i]);\n }\n }\n };\n\n // Process children of the root\n if (doc.children) {\n for (let i = 0; i < doc.children.length; i++) {\n processNode(doc.children[i]);\n }\n }\n\n return bindings;\n}\n\n\n// ============================================================================\n// ATTRIBUTE VALUE CALCULATION (used by frame loop animator)\n// ============================================================================\n\n/**\n * Finds prev/next keyframes for a given progress.\n */\nfunction getKeyframesPair(keyframes: PxNormalizedKeyframe[], progress: number) {\n // Outside the keyframe range, clamp to the NEAREST REAL segment (the caller clamps\n // `localProgress` to 0/1, so that holds the boundary pose). Spanning first→last\n // instead would invent a segment that exists nowhere in the animation: for keyframes\n // that start part-way into the timeline, the pre-start frames used to interpolate\n // straight from the first to the LAST keyframe — skipping everything between, and\n // handing motion-path evaluation a chord it then cached (see `getSegmentCache`).\n const last = keyframes.length - 1;\n let prevKf = keyframes[0];\n let nextKf = keyframes[last > 0 ? 1 : 0];\n\n for (let j = 0; j < last; j++) {\n const aOff = (keyframes[j].t ?? 0);\n const bOff = (keyframes[j + 1].t ?? 0);\n if (aOff <= progress && progress <= bOff) {\n prevKf = keyframes[j];\n nextKf = keyframes[j + 1];\n break;\n }\n // Past this segment and not bracketed by any later one → hold the final segment.\n if (progress > bOff && j === last - 1) {\n prevKf = keyframes[last > 0 ? last - 1 : 0];\n nextKf = keyframes[last];\n }\n }\n return { prevKf, nextKf };\n}\n\n/**\n * Calculates interpolated value for a single property animation.\n */\nfunction calcPropertyValue(\n propName: string,\n propAnim: PxPropertyAnimation,\n progress: number\n): { k: string, v: string } | null {\n const keyframes = propAnim.keyframes || [];\n if (keyframes.length === 0) return null;\n\n const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);\n\n // remap to local 0..1 within prevKf..nextKf\n let localProgress = (prevKf === nextKf) ? 0 : remap(progress, prevKf.t ?? 0, nextKf.t ?? 0, 0, 1);\n localProgress = clamp(localProgress, 0, 1);\n const easing = keyframeEasing(prevKf); // e is on the source keyframe: applied from this KF to the next\n if (easing && Array.isArray(easing)) {\n try {\n localProgress = cubicBezier(easing as [number, number, number, number])(localProgress);\n } catch (e) {\n // fallback: ignore easing if parsing fails\n }\n }\n\n let cssAttrName = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;\n let cssValue: string | number | null = null;\n\n const prevV = prevKf?.v;\n const nextV = nextKf?.v;\n\n if (cssAttrName === 'd') {\n // Extract paths from { paths: [...] } format\n const prevPaths = prevV?.paths ?? (Array.isArray(prevV) ? prevV : []);\n const nextPaths = nextV?.paths ?? (Array.isArray(nextV) ? nextV : []);\n cssValue = interpolateBeziers(\n prevPaths,\n nextPaths,\n localProgress\n ).map(bz => bezierToSvgPath(bz)).join('');\n } else if (PX_COLOR_ATTR_NAMES.has(cssAttrName)) {\n cssValue = toRGBA(interpolateColor(\n prevV || [0, 0, 0, 1],\n nextV || [0, 0, 0, 1],\n localProgress\n ));\n cssAttrName = propName;\n } else if (cssAttrName === 'stroke-dasharray') {\n cssValue = interpolateVec(\n prevV || [],\n nextV || [],\n localProgress\n ).join(' ');\n cssAttrName = propName;\n } else if (\n cssAttrName === 'transform' &&\n prevV !== null && typeof prevV === 'object' && !Array.isArray(prevV)\n ) {\n // Unified transform: keyframe values are PxTransformParts records.\n // Interpolate each present part separately, then compose into a transform\n // string for the SVG `transform` attribute (no units).\n const partKeys = new Set<string>([\n ...(prevV ? Object.keys(prevV) : []),\n ...(nextV ? Object.keys(nextV) : []),\n ]);\n const partsResult: PxTransformParts = {};\n for (const partKey of partKeys) {\n const prevPart = prevV?.[partKey];\n const nextPart = nextV?.[partKey];\n if (partKey === 'rotate' || partKey === 'skew') {\n partsResult[partKey] = interpolateNum(+(prevPart ?? 0), +(nextPart ?? 0), localProgress);\n } else if (partKey === 'translate' || partKey === 'scale' || partKey === 'origin') {\n const fallback = partKey === 'scale' ? [1, 1] : [0, 0];\n const interp = interpolateVec(prevPart || fallback, nextPart || fallback, localProgress);\n (partsResult as any)[partKey] = interp;\n }\n }\n // Motion-along-path override (frames-mode only). The WAAPI binding\n // pipeline materializes tangents + autoOrient into sampled\n // `{translate, rotate}` kfs upstream (in `normalizeAnimationDefinition`),\n // so for WAAPI this branch is a no-op (`propAnimIsMotionPath` returns\n // false on already-materialized kfs). Frames-mode preserves the\n // parametric form and we evaluate the Bezier per frame here — gives\n // exact spatial fidelity vs. any finite sampling.\n if (propAnimIsMotionPath(propAnim)) {\n const prevTr = (prevV as { translate?: [number, number] }).translate;\n const nextTr = (nextV as { translate?: [number, number] }).translate;\n if (Array.isArray(prevTr) && Array.isArray(nextTr)) {\n const sample = evaluateMotionPathSegment(\n prevKf, nextKf,\n [+prevTr[0], +prevTr[1]],\n [+nextTr[0], +nextTr[1]],\n localProgress,\n !!propAnim.autoOrient,\n );\n partsResult.translate = [sample.translate[0], sample.translate[1]];\n if (sample.rotateDeg !== undefined) partsResult.rotate = sample.rotateDeg;\n }\n }\n cssValue = composeTransformParts(partsResult, { withUnits: false });\n cssAttrName = 'transform';\n } else if (cssAttrName === 'translate') {\n const v = interpolateVec(\n prevV || [0, 0],\n nextV || [0, 0],\n localProgress\n );\n cssValue = 'translate(' + v.join(',') + ')';\n cssAttrName = 'transform';\n } else if (cssAttrName === 'rotate') {\n const v = interpolateNum(\n +(prevV || 0),\n +(nextV || 0),\n localProgress\n );\n cssValue = 'rotate(' + v + ')';\n cssAttrName = 'transform';\n } else if (cssAttrName === 'scale') {\n const v = interpolateVec(\n prevV || [1, 1],\n nextV || [1, 1],\n localProgress\n );\n cssValue = 'scale(' + v.join(',') + ')';\n cssAttrName = 'transform';\n } else {\n // numeric attr\n const num = interpolateNum(\n +(prevV || 0),\n +(nextV || 0),\n localProgress\n );\n cssValue = num;\n }\n\n if (PX_PCT_BASED_ATTR_NAMES.has(cssAttrName) && typeof cssValue === 'number') {\n cssValue = (cssValue * 100) + '%';\n }\n\n return { k: cssAttrName, v: cssValue === null ? '' : '' + cssValue };\n}\n\n/**\n * Calculates interpolated attribute values for an animation definition.\n * @param animDef The animation definition (with resolved refs and normalized times)\n * @param progress The current animation progress (0-1)\n * @returns Object with computed attribute name/value pairs\n * @public @advanced\n */\nexport function calcAnimationValues(\n animDef: PxAnimationDefinition,\n progress: number\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const [propName, propAnim] of Object.entries(animDef)) { \n const computed = calcPropertyValue(propName, propAnim, progress);\n if (computed) {\n result[computed.k] = computed.v;\n }\n }\n\n return result;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n\n/**\n * Arc-length sampler for an SVG path `d` — the geometry backing along-path glyph\n * placement. Parses the path into cubic Bézier segments (lines and quadratics\n * up-converted), builds a per-segment arc-length LUT, and answers\n * `sampleAtDistance(dist) → { x, y, angle }` (angle = path tangent, radians).\n *\n * Supported commands: M/L/H/V/C/S/Q/T/Z (absolute + relative). Arcs (A/a) are\n * approximated as a straight line to the endpoint (editor paths never emit them;\n * this only guards odd imports). Multiple subpaths are concatenated by arc\n * length (gaps between them are ignored — text flows continuously).\n */\n\nimport { bezier2D_arcLengthLUT, bezier2D_derivativeAt, bezier2D_pointAt, bezier2D_tForDistance, type ArcLengthLUT } from '../../util/PxAnimatorUtil';\n\ntype Pt = [number, number];\n\ninterface Cubic { P0: Pt; P1: Pt; P2: Pt; P3: Pt; lut: ArcLengthLUT; len: number; }\n\n/** @internal */\nexport interface PathPoint { x: number; y: number; angle: number; }\n\n/** @internal */\nexport interface PathSampler {\n totalLength: number;\n /** True when the path loops back on itself (explicit `Z` or coincident ends) —\n * no open tip to run off, so overflow clamps/wraps rather than clipping. */\n closed: boolean;\n sampleAtDistance(dist: number): PathPoint;\n}\n\nconst LUT_STEPS = 48;\nconst CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;\n\n/** Tokenises `d` into command letters and numbers, preserving order. */\nfunction tokenize(d: string): Array<string> {\n const tokens: Array<string> = [];\n const re = /([MmLlHhVvCcSsQqTtAaZz])|(-?\\d*\\.?\\d+(?:[eE][-+]?\\d+)?)/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(d)) !== null) tokens.push(m[0]);\n return tokens;\n}\n\nfunction quadToCubic(P0: Pt, Qc: Pt, P3: Pt): { P1: Pt; P2: Pt } {\n return {\n P1: [P0[0] + 2 / 3 * (Qc[0] - P0[0]), P0[1] + 2 / 3 * (Qc[1] - P0[1])],\n P2: [P3[0] + 2 / 3 * (Qc[0] - P3[0]), P3[1] + 2 / 3 * (Qc[1] - P3[1])],\n };\n}\n\n/** Parses `d` into cubic segments. Returns null when nothing usable was found. */\nfunction parseCubics(d: string): Array<Cubic> | null {\n const tokens = tokenize(d);\n const segs: Array<Cubic> = [];\n\n let i = 0;\n let cx = 0, cy = 0; // current point\n let sx = 0, sy = 0; // subpath start\n let pcx = 0, pcy = 0; // previous cubic control point (for S)\n let pqx = 0, pqy = 0; // previous quad control point (for T)\n let prevCmd = '';\n\n const num = (): number => parseFloat(tokens[i++]);\n const push = (P1: Pt, P2: Pt, P3: Pt): void => {\n const P0: Pt = [cx, cy];\n const lut = bezier2D_arcLengthLUT(P0, P1, P2, P3, LUT_STEPS);\n segs.push({ P0, P1, P2, P3, lut, len: lut.ds[lut.ds.length - 1] });\n cx = P3[0]; cy = P3[1];\n };\n // Straight line as a cubic with controls at 1/3 and 2/3 — this makes\n // `B(t) = P0 + t·(P3−P0)` EXACTLY, so arc length is linear in t and sampling\n // is precise (degenerate `P1=P0,P2=P3` controls would reparametrise it).\n const pushLine = (x: number, y: number): void => {\n push(\n [cx + (x - cx) / 3, cy + (y - cy) / 3],\n [cx + 2 * (x - cx) / 3, cy + 2 * (y - cy) / 3],\n [x, y],\n );\n };\n\n while (i < tokens.length) {\n let cmd = tokens[i];\n if (CMD_RE.test(cmd)) i++;\n else cmd = prevCmd === 'M' ? 'L' : prevCmd === 'm' ? 'l' : prevCmd; // implicit repeat\n const rel = cmd >= 'a';\n const U = cmd.toUpperCase();\n\n if (U === 'Z') { pushLine(sx, sy); cx = sx; cy = sy; prevCmd = cmd; continue; }\n if (U === 'M') {\n const x = num() + (rel ? cx : 0), y = num() + (rel ? cy : 0);\n cx = x; cy = y; sx = x; sy = y; prevCmd = cmd; continue;\n }\n if (U === 'L') {\n pushLine(num() + (rel ? cx : 0), num() + (rel ? cy : 0));\n } else if (U === 'H') {\n pushLine(num() + (rel ? cx : 0), cy);\n } else if (U === 'V') {\n pushLine(cx, num() + (rel ? cy : 0));\n } else if (U === 'C') {\n const p1: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n const p2: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n const p3: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n pcx = p2[0]; pcy = p2[1];\n push(p1, p2, p3);\n } else if (U === 'S') {\n const smooth = (prevCmd.toUpperCase() === 'C' || prevCmd.toUpperCase() === 'S');\n const p1: Pt = smooth ? [2 * cx - pcx, 2 * cy - pcy] : [cx, cy];\n const p2: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n const p3: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n pcx = p2[0]; pcy = p2[1];\n push(p1, p2, p3);\n } else if (U === 'Q') {\n const qc: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n const p3: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n pqx = qc[0]; pqy = qc[1];\n const { P1, P2 } = quadToCubic([cx, cy], qc, p3);\n push(P1, P2, p3);\n } else if (U === 'T') {\n const smooth = (prevCmd.toUpperCase() === 'Q' || prevCmd.toUpperCase() === 'T');\n const qc: Pt = smooth ? [2 * cx - pqx, 2 * cy - pqy] : [cx, cy];\n const p3: Pt = [num() + (rel ? cx : 0), num() + (rel ? cy : 0)];\n pqx = qc[0]; pqy = qc[1];\n const { P1, P2 } = quadToCubic([cx, cy], qc, p3);\n push(P1, P2, p3);\n } else if (U === 'A') {\n // Arc — skip rx ry rot large sweep, use endpoint as a straight line.\n i += 5;\n pushLine(num() + (rel ? cx : 0), num() + (rel ? cy : 0));\n } else { i++; continue; } // unknown — skip a token defensively\n\n prevCmd = cmd;\n }\n\n return segs.length ? segs : null;\n}\n\nfunction clamp(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v;\n}\n\n/** @internal */\nexport function createPathSampler(d: string): PathSampler | null {\n const segs = parseCubics(d);\n if (!segs) return null;\n\n // Cumulative start distance per segment; cum[segs.length] === total length.\n const cum = new Float64Array(segs.length + 1);\n for (let k = 0; k < segs.length; k++) cum[k + 1] = cum[k] + segs[k].len;\n const totalLength = cum[segs.length];\n\n // A path is CLOSED when it returns to its start (an explicit `Z`, or coincident\n // first/last points). Open paths get straight-line extrapolation past either end\n // (below); closed paths loop back on themselves, so there's no tip to run off.\n const start = segs[0].P0, end = segs[segs.length - 1].P3;\n const closed = Math.hypot(end[0] - start[0], end[1] - start[1]) < 1e-3;\n\n // Sample strictly within [0, totalLength].\n const sampleOn = (dist: number): PathPoint => {\n let k = 0;\n while (k < segs.length - 1 && dist > cum[k + 1]) k++;\n const seg = segs[k];\n const local = dist - cum[k];\n const t = seg.len > 0 ? bezier2D_tForDistance(seg.lut, local) : 0;\n const [x, y] = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);\n const [dx, dy] = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);\n return { x, y, angle: Math.atan2(dy, dx) };\n };\n\n return {\n totalLength,\n closed,\n sampleAtDistance(dist: number): PathPoint {\n // A CLOSED path loops: a distance outside [0, totalLength] wraps around\n // (modulo the length) rather than piling up at the seam. Without this a\n // negative startOffset collapses every pre-start glyph onto the path start\n // (e.g. text on a circle with startOffset < 0 stacking its first word).\n if (closed && totalLength > 0 && (dist < 0 || dist > totalLength)) {\n return sampleOn(((dist % totalLength) + totalLength) % totalLength);\n }\n // Past an end of an OPEN path: continue in a straight line along that\n // end's tangent, so along-path motion keeps going instead of piling up\n // at the tip. (The caller only asks for distances a glyph actually\n // reaches — startOffset + text length — so this never runs off forever.)\n if (!closed && (dist < 0 || dist > totalLength)) {\n const edge = dist < 0 ? 0 : totalLength;\n const p = sampleOn(edge);\n const over = dist - edge;\n return { x: p.x + Math.cos(p.angle) * over, y: p.y + Math.sin(p.angle) * over, angle: p.angle };\n }\n return sampleOn(clamp(dist, 0, totalLength));\n },\n };\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n\n/**\n * Helpers for reading animatable transform parts and shaping them into the\n * player's `PxTransformParts` records. Shared by the transformation and\n * masked-by effects (the latter builds INVERSE parts).\n */\n\nimport type { PxAnimatable, PxKeyframe, PxLoop, PxNode, PxVec2 } from '../../format/PxAnimatorTypes';\nimport type { ApplyContext } from './types';\n\n\n/**\n * Names of the transform parts emitted into a `PxTransformParts` record. The\n * enum's STRING VALUES double as the wire-format object keys, so callers can\n * write `rec[TransformPart.Translate] = …` and produce `{translate: …}`.\n */\nexport enum TransformPart {\n Translate = 'translate',\n Rotate = 'rotate',\n Scale = 'scale',\n Skew = 'skew',\n Origin = 'origin',\n}\n\n\n/** Result kinds for `readAnimatable` — discriminator on `ReadPart<T>`. */\nexport enum ReadKind {\n Absent = 'absent',\n Static = 'static',\n Animated = 'animated',\n}\n\n\n/** Builds a player `PxTransformParts` record for one part (+ optional origin). */\nexport function partsRecord(part: TransformPart, value: any, origin: PxVec2 | undefined) {\n const rec: { translate?: PxVec2; rotate?: number; skew?: number; scale?: PxVec2; origin?: PxVec2 } = {};\n if (part === TransformPart.Translate) rec.translate = value;\n else if (part === TransformPart.Rotate) rec.rotate = value;\n else if (part === TransformPart.Skew) rec.skew = value;\n else rec.scale = value;\n if (origin && part !== TransformPart.Translate) rec.origin = origin;\n return rec;\n}\n\nexport type ReadPart<T> =\n | { kind: ReadKind.Absent }\n | { kind: ReadKind.Static; value: T }\n | { kind: ReadKind.Animated; keyframes: Array<PxKeyframe<T>>; autoOrient?: boolean; loop?: PxLoop | boolean; base?: T };\n\n/** Normalizes an animatable field into a static value or a keyframe list (with\n * `autoOrient` and `loop` propagated — the latter so timeline-level loop config\n * reaches the per-attribute `animate.X.loop` emitted by callers; without it,\n * effect-driven animations would silently ignore `loop.alternate`/cycle while\n * every non-effect property loops fine). A `value` present NEXT TO keyframes\n * is surfaced as `base` (the static baseline of the unified animatable form). */\nexport function readAnimatable<T>(raw: PxAnimatable<T> | undefined): ReadPart<T> {\n if (raw === undefined) return { kind: ReadKind.Absent };\n if (Array.isArray(raw)) return { kind: ReadKind.Static, value: raw as unknown as T };\n if (typeof raw === 'object') {\n const obj = raw as {\n value?: T; v?: T;\n keyframes?: Array<PxKeyframe<T>>;\n autoOrient?: boolean; loop?: PxLoop | boolean;\n };\n const kfs = obj.keyframes;\n if (kfs) {\n // Normalize the wire's short aliases ONCE, here, so every consumer\n // downstream (transformation, repeater, …) only ever sees the long\n // form. Without this a keyframe authored `{t, v}` lost both its time\n // and its value and the animation silently froze at frame 0.\n const out: ReadPart<T> = { kind: ReadKind.Animated, keyframes: kfs.map(normalizeKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };\n const base = obj.value ?? obj.v;\n if (base !== undefined && out.kind === ReadKind.Animated) out.base = base;\n return out;\n }\n const staticValue = obj.value ?? obj.v;\n if (staticValue !== undefined) return { kind: ReadKind.Static, value: staticValue };\n }\n return { kind: ReadKind.Static, value: raw as T };\n}\n\n/**\n * Writes a normalized animatable (`ReadPart`) onto a node as attribute/animation —\n * the ONE emit path shared by the effect appliers (strokeTrim, textPath, …):\n * - Static → `node[attrName] = value` (stringified when `opts.asString`).\n * - Animated → `node.animate[attrName] = {keyframes, loop?, autoOrient?}` PLUS a\n * static baseline attr (`base` if present, else the first kf's value). The\n * animator only pushes animated values to the DOM on its first rAF tick — a\n * DOM snapshot between mount and that tick (visual-test live-mode sample at\n * t=0) must render the kf-at-time-0 state, not the un-styled default.\n */\nexport function writeAnimatableChannel(\n node: PxNode,\n attrName: string,\n read: ReadPart<any>,\n opts?: { asString?: boolean },\n): void {\n const toOut = (v: unknown): unknown => (opts?.asString && v !== undefined && v !== null) ? String(v) : v;\n if (read.kind === ReadKind.Absent) return;\n if (read.kind === ReadKind.Static) {\n node[attrName] = toOut(read.value);\n return;\n }\n const prevAnimate = node.animate && typeof node.animate === 'object' && !Array.isArray(node.animate) ? node.animate : undefined;\n const animate: Record<string, any> = { ...(prevAnimate || {}) };\n const block: { keyframes: Array<PxKeyframe>; loop?: PxLoop | boolean; autoOrient?: boolean } = { keyframes: read.keyframes };\n if (read.loop !== undefined) block.loop = read.loop;\n if (read.autoOrient !== undefined) block.autoOrient = read.autoOrient;\n animate[attrName] = block;\n node.animate = animate;\n const baseline = read.base ?? read.keyframes[0]?.value ?? (read.keyframes[0] as { v?: unknown } | undefined)?.v;\n if (baseline !== undefined) node[attrName] = toOut(baseline);\n}\n\n/** Rewrites a keyframe's short aliases (`t`/`v`/`e`/`to`/`ti`) to their long\n * names. Long names win when both are present, matching `PxMotionPath`'s\n * `tangentIn ?? ti` precedence. */\nfunction normalizeKeyframe<T>(kf: PxKeyframe<T>): PxKeyframe<T> {\n if (!kf || typeof kf !== 'object') return kf;\n const k = kf as PxKeyframe<T> & { t?: number; v?: T; e?: unknown; to?: PxVec2; ti?: PxVec2 };\n if (k.t === undefined && k.v === undefined && k.e === undefined && k.to === undefined && k.ti === undefined) {\n return kf; // already long-form — keep the same object\n }\n const out: any = { ...k };\n if (out.time === undefined && k.t !== undefined) out.time = k.t;\n if (out.value === undefined && k.v !== undefined) out.value = k.v;\n if (out.easing === undefined && k.e !== undefined) out.easing = k.e;\n if (out.tangentOut === undefined && k.to !== undefined) out.tangentOut = k.to;\n if (out.tangentIn === undefined && k.ti !== undefined) out.tangentIn = k.ti;\n return out as PxKeyframe<T>;\n}\n\n/** Origin used inside rotate/scale records. Animated origin falls back to frame 0. */\nexport function readStaticOrigin(raw: PxAnimatable<PxVec2> | undefined, ctx: ApplyContext): PxVec2 | undefined {\n const o = readAnimatable<PxVec2>(raw);\n if (o.kind === ReadKind.Absent) return undefined;\n if (o.kind === ReadKind.Static) return o.value;\n ctx.warnings.push('transformBy.origin: animated origin approximated by its first keyframe');\n return o.keyframes[0]?.value;\n}\n\n/** Copies a keyframe's time / easing / motion-path tangent handles onto a new parts-record value. */\nexport function keyframeWith(kf: PxKeyframe<any>, value: any): PxKeyframe<any> {\n const out: PxKeyframe<any> = { value };\n if (kf.time !== undefined) out.time = kf.time;\n if (kf.easing !== undefined) out.easing = kf.easing;\n if (kf.tangentOut !== undefined) out.tangentOut = kf.tangentOut;\n if (kf.tangentIn !== undefined) out.tangentIn = kf.tangentIn;\n return out;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * Shared \"clone a subtree and rewire its internal references\" primitives.\n *\n * Used by:\n * - The retime effect's `<use>` chain materializer (`effects/util.ts`'s\n * `clone` + `regenerateIdsInClone`, which now delegate here).\n * - `PxAnimatorUseMaterializer` — the WAAPI-side post-pass that replaces\n * `<use>` instances referencing animated subtrees with deep clones.\n *\n * Both call sites need the exact same two operations: a structural deep clone\n * of a `PxNode` subtree, and a renumber-all-ids pass that also rewrites\n * internal `href=\"#X\"` / `url(#X)` references to the new ids while leaving\n * outward-facing references alone.\n */\n\nimport type { PxNode } from '../format/PxAnimatorTypes';\n\n\n/** Recursive deep clone for plain JSON-shaped `PxNode` data (objects, arrays,\n * primitives). Faster than `JSON.parse(JSON.stringify(x))` for large trees,\n * no behavior difference for our wire format (no `Date` / `Map` / functions).\n */\nexport function deepClonePxNode<T>(value: T): T {\n if (value === null || typeof value !== 'object') return value;\n if (Array.isArray(value)) return value.map(deepClonePxNode) as unknown as T;\n const out: { [k: string]: unknown } = {};\n for (const k of Object.keys(value as object)) out[k] = deepClonePxNode((value as { [k: string]: unknown })[k]);\n return out as T;\n}\n\n\n/**\n * Regenerates every `id` inside `root` (root included) using fresh ids from\n * `genId()`, then rewrites internal DOM references (`href=\"#oldId\"` and\n * `url(#oldId)` inside string attrs) to the new ids. References that point\n * OUTSIDE the cloned subtree are left untouched.\n *\n * `meta.*`, `effects.*`, `animate.*` are intentionally skipped — they don't\n * carry DOM-reference syntax, and walking them per-string is wasted work.\n *\n * Returns the old→new id map so callers can rewrite their own outward-facing\n * references (e.g. a `<use>` href pointing at the cloned subtree root).\n */\nexport function regenerateIdsAndRewriteRefs(\n root: PxNode,\n genId: () => string,\n): Map<string, string> {\n const oldToNew = new Map<string, string>();\n\n const walkAssign = (n: PxNode): void => {\n if (typeof n.id === 'string') {\n const newId = genId();\n oldToNew.set(n.id, newId);\n n.id = newId;\n }\n n.children?.forEach(walkAssign);\n };\n walkAssign(root);\n\n const rewriteUrl = (s: string): string => s.replace(/url\\(#([^)]+)\\)/g, (m, oldId) => {\n const newId = oldToNew.get(oldId);\n return newId ? 'url(#' + newId + ')' : m;\n });\n\n const walkRewrite = (n: PxNode): void => {\n if (typeof n.href === 'string' && n.href.startsWith('#')) {\n const newId = oldToNew.get(n.href.slice(1));\n if (newId) n.href = '#' + newId;\n }\n for (const k of Object.keys(n)) {\n if (k === 'children' || k === 'effects' || k === 'meta' || k === 'animate' || k === 'href' || k === 'id') continue;\n const v = (n as { [k: string]: unknown })[k];\n if (typeof v === 'string' && v.indexOf('url(#') !== -1) {\n (n as { [k: string]: unknown })[k] = rewriteUrl(v);\n }\n }\n n.children?.forEach(walkRewrite);\n };\n walkRewrite(root);\n\n return oldToNew;\n}\n\n\nfunction toFiniteNum(v: unknown): number {\n const n = typeof v === 'number' ? v : typeof v === 'string' ? parseFloat(v) : NaN;\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Applies a `<use>`'s `x`/`y` offset when it is materialized into a `<g>`.\n *\n * Per SVG 2, `<use x y>` is an extra `translate(x, y)` appended AFTER the use's\n * own `transform`, so it composes innermost (closest to the referenced content).\n * `<g>` has no `x`/`y`, so the offset must become a transform — and when the use\n * also carries a (possibly animated) `transform`, the two can't be merged into a\n * single attribute, so the content is wrapped in an inner offset `<g>`:\n *\n * <use transform=\"T\" x=\"X\" y=\"Y\">\n * → <g transform=\"T\"><g transform=\"translate(X,Y)\">…content…</g></g>\n *\n * With no transform/animation, a single `<g transform=\"translate(X,Y)\">` suffices.\n *\n * `gNode` is the `<g>` already derived from the use (type:'g', href dropped, the\n * use's `transform`/`animate`/etc. carried over, `x`/`y` still present). Mutates\n * and returns it; `x`/`y` are removed.\n */\nexport function applyUseOffsetToG(gNode: PxNode): PxNode {\n const x = toFiniteNum((gNode as { x?: unknown }).x);\n const y = toFiniteNum((gNode as { y?: unknown }).y);\n delete (gNode as { x?: unknown }).x;\n delete (gNode as { y?: unknown }).y;\n if (!x && !y) return gNode;\n\n const offset = 'translate(' + x + ',' + y + ')';\n\n // Any existing transform/animation on the outer <g> must apply OUTSIDE the\n // offset, so push the offset into an inner wrapper rather than risk\n // overwriting/conflicting with the carried-over `transform`/`animate`.\n const carriesTransform =\n (gNode as { transform?: unknown }).transform !== undefined ||\n (gNode as { animate?: unknown }).animate !== undefined;\n\n if (carriesTransform) {\n const inner: PxNode = { type: 'g', transform: offset, children: gNode.children ?? [] } as PxNode;\n gNode.children = [inner];\n } else {\n (gNode as { transform?: string }).transform = offset;\n }\n return gNode;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n\n/** Generic, effect-agnostic helpers for the player-effects applier. */\n\nimport { deepClonePxNode, regenerateIdsAndRewriteRefs } from '../../util/PxNodeCloneUtil';\nimport type { PxNode, PxVec2 } from '../../format/PxAnimatorTypes';\nimport type { ApplyContext } from './types';\n\n/** Generates a deterministic id for a generated node (`<mask>`, retimed `<symbol>`, …). */\nexport function genId(ctx: ApplyContext, prefix: string): string {\n return '_lw_' + prefix + '_' + (ctx.nextId++);\n}\n\nexport function stripHash(href: any): string | undefined {\n return typeof href === 'string' ? href.replace(/^#/, '') : undefined;\n}\n\n/** Reads the leading `translate(x,y)` from an SVG transform string. */\nexport function readTranslateFromTransform(transform: any): PxVec2 | undefined {\n if (typeof transform !== 'string') return undefined;\n const m = transform.match(/translate\\(\\s*(-?[\\d.]+)\\s*,\\s*(-?[\\d.]+)\\s*\\)/);\n return m ? [Number(m[1]), Number(m[2])] : undefined;\n}\n\n/** Records every node carrying an `id` into the lookup map. */\nexport function indexById(node: PxNode, map: Map<string, PxNode>): void {\n if (typeof node.id === 'string') map.set(node.id, node);\n node.children?.forEach(child => indexById(child, map));\n}\n\n/** Inserts generated <defs> nodes at the front of the root's children. */\nexport function spliceDefs(root: PxNode, defs: Array<PxNode>): void {\n if (!defs.length) return;\n const existing = root.children || (root.children = []);\n existing.unshift({ type: 'defs', children: defs });\n}\n\n/** Deep-clone a `PxNode` subtree. Thin wrapper around the shared\n * {@link deepClonePxNode}; retained as `clone` for the existing call sites. */\nexport const clone = deepClonePxNode;\n\n/**\n * Regenerates every `id` inside `root` (root included) using `genId(ctx, 'retimed')`\n * and rewrites internal `href=\"#X\"` / `url(#X)` refs. Thin wrapper around the\n * shared {@link regenerateIdsAndRewriteRefs}; encapsulates the retime-specific\n * id-prefix convention so retime call sites stay unchanged.\n */\nexport function regenerateIdsInClone(root: PxNode, ctx: ApplyContext): Map<string, string> {\n return regenerateIdsAndRewriteRefs(root, () => genId(ctx, 'retimed'));\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n\nimport type { PxAnimatable, PxKeyframe, PxLoop, PxNode, PxTextPathEffect } from '../../format/PxAnimatorTypes';\nimport type { ApplyContext } from '../shared/types';\nimport { createPathSampler } from './pathSampler';\nimport { ReadKind, readAnimatable, writeAnimatableChannel } from '../shared/transformParts';\nimport { genId } from '../shared/util';\n\n\nconst EXTEND_MARGIN_FRAC = 0.15; // slack (× path length) to absorb sampling/measure error\n\n\n/** {min,max} over a `PxAnimatable<number>`'s keyframe values (or its single static\n * value; {0,0} when absent). The tangent extension must cover the FULL animation\n * range: the MOST-NEGATIVE startOffset drives the START extension, and the LARGEST\n * startOffset(+textLength) drives the END — using only one value (e.g. the max)\n * misses the other end when startOffset is animated. */\nfunction numRange(v: PxAnimatable<number> | undefined): { min: number; max: number } {\n const read = readAnimatable<number>(v);\n if (read.kind === ReadKind.Static && typeof read.value === 'number') return { min: read.value, max: read.value };\n if (read.kind === ReadKind.Animated && read.keyframes.length) {\n const vals = read.keyframes.map(k => Number(k.value) || 0);\n return { min: Math.min(...vals), max: Math.max(...vals) };\n }\n return { min: 0, max: 0 };\n}\n\n/** Generous upper bound on the text's advance width: char-count × largest font\n * (~1em/char). Over-estimating is safe — the extension is an invisible tail of the\n * reference `<path>`, so extra length just goes unused. */\nfunction estimateTextAdvance(node: PxNode): number {\n let chars = 0, maxFont = 16;\n const walk = (el: PxNode): void => {\n const fs = parseFloat(String((el as any).fontSize ?? '')) || 0;\n if (fs) maxFont = Math.max(maxFont, fs);\n const t = el.textContent;\n if (typeof t === 'string') chars += t.length;\n if (el.children) for (const c of el.children) walk(c);\n };\n walk(node);\n return chars * maxFont;\n}\n\nconst r3 = (n: number): number => Math.round(n * 1000) / 1000;\n\n/** Inputs for {@link extendedPathForBrowser}. `advance` = the text run-width used to\n * size the end extension (caller-measured; the player estimates it from the node,\n * the editor from its text model — browser fonts have no glyph metrics available). * @internal\n */\nexport interface ExtendPathOptions {\n pathOverflow?: string;\n startOffset?: PxAnimatable<number>;\n textLength?: PxAnimatable<number>;\n advance?: number;\n}\n\n/** Result of {@link extendedPathForBrowser}: the (possibly) extended `d`, plus\n * `startShift` — the length of the prepended START lead-in. Because that lead-in\n * moves the `<textPath>` origin back by `startShift`, EVERY `startOffset` (all\n * keyframes) MUST be shifted by `+startShift` so the text lands where it would on\n * the un-extended path (`extend` only adds a tail, it must never move the text). * @internal\n */\nexport interface ExtendedPath {\n d: string;\n startShift: number;\n}\n\n/** Shift a `PxAnimatable<number>` by a constant (base + all keyframes). No-op for `0`.\n * Reads via the shared `readAnimatable` (kfs/loop aliases handled), emits the\n * normalized long form. * @internal\n */\nexport function shiftAnimatable(v: PxAnimatable<number> | undefined, by: number): PxAnimatable<number> | undefined {\n if (!by || v === undefined || v === null) return v;\n const read = readAnimatable<number>(v);\n if (read.kind === ReadKind.Absent) return v;\n if (read.kind === ReadKind.Static) return typeof v === 'number' ? read.value + by : { value: read.value + by };\n const out: { keyframes: Array<PxKeyframe<number>>; loop?: PxLoop | boolean; autoOrient?: boolean; value?: number } = {\n keyframes: read.keyframes.map(k => ({ ...k, value: (Number(k.value) || 0) + by })),\n };\n if (read.loop !== undefined) out.loop = read.loop;\n if (read.autoOrient !== undefined) out.autoOrient = read.autoOrient;\n if (read.base !== undefined) out.value = read.base + by;\n return out;\n}\n\n/** For `pathOverflow:'extend'` (browser-font): extend an OPEN path along its endpoint\n * tangents so the browser lays overflow glyphs onto the straight extension (matching\n * glyph-mode's tangent behavior) instead of dropping them. `'clip'`/closed paths are\n * returned unchanged (browser clips natively). Shared by the player's browser-font\n * applier and the editor's live/heavy `<textPath>` def generate (single source of truth).\n * Returns the extended `d` AND `startShift` — see {@link ExtendedPath}. * @internal\n */\nexport function extendedPathForBrowser(pathD: string, opts: ExtendPathOptions): ExtendedPath {\n if (opts.pathOverflow === 'clip') return { d: pathD, startShift: 0 };\n const sampler = createPathSampler(pathD);\n if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };\n\n const L = sampler.totalLength;\n const margin = EXTEND_MARGIN_FRAC * L;\n const so = numRange(opts.startOffset);\n const runWidth = numRange(opts.textLength).max || (opts.advance ?? 0);\n // START: how far the EARLIEST (most-negative) startOffset reaches before the path\n // start. END: how far the LATEST run (max startOffset + run width) reaches past the\n // path end. Only add the slack `margin` when actually extending, so a non-negative\n // startOffset that fits leaves the corresponding end alone (no phantom shift).\n const startOverflow = Math.max(0, -so.min);\n const endOverflow = Math.max(0, so.max + runWidth - L);\n const startExt = startOverflow > 0 ? startOverflow + margin : 0;\n const endExt = endOverflow > 0 ? endOverflow + margin : 0;\n if (endExt <= 0 && startExt <= 0) return { d: pathD, startShift: 0 };\n\n const s = sampler.sampleAtDistance(0);\n const e = sampler.sampleAtDistance(L);\n let d = pathD;\n if (startExt > 0) {\n const sx = s.x - Math.cos(s.angle) * startExt, sy = s.y - Math.sin(s.angle) * startExt;\n // Prepend a lead-in: M(extended start) L(original start) + the original path\n // minus its own leading `M x y` (we've re-stated the start via the `L`).\n const rest = pathD.replace(/^\\s*[Mm]\\s*-?[\\d.]+[\\s,]+-?[\\d.]+/, '');\n d = 'M' + r3(sx) + ',' + r3(sy) + 'L' + r3(s.x) + ',' + r3(s.y) + rest;\n }\n if (endExt > 0) {\n const ex = e.x + Math.cos(e.angle) * endExt, ey = e.y + Math.sin(e.angle) * endExt;\n d += 'L' + r3(ex) + ',' + r3(ey);\n }\n // The `<textPath>` distance origin moved back by exactly the start lead-in length.\n return { d, startShift: startExt };\n}\n\n\n/**\n * `effects.textPath` materializer (browser-font / non-glyph path).\n *\n * The path geometry is carried INLINE on the effect as `path` (an SVG `d`). SVG's\n * native rendering requires a `<textPath href=\"#…\">` wrapper referencing a `<path>`\n * def, so this applier generates that `<path>` def from the inline geometry, wraps the\n * text node's children in the `<textPath>`, and forwards the textPath SVG attrs\n * (`lengthAdjust`, `method`, `spacing`, `startOffset`, `textLength`).\n *\n * `startOffset` / `textLength` accept the full `PxAnimatable<number>` shape: a static\n * number is set as an attribute; the `{keyframes}` form is forwarded to\n * `<textPath>.animate.<attr>`; `{value}` is unwrapped to the static shape.\n *\n * `pathOverflow:'extend'` tangent-extends the generated `<path>` (see\n * {@link extendedPathForBrowser}) so the browser lays overflow glyphs onto the straight\n * extension; `'clip'` generates the geometry as-is and native `<textPath>` drops overflow.\n */\nexport function applyTextPathEffect(\n node: PxNode,\n fx: PxTextPathEffect | undefined,\n ctx: ApplyContext,\n): PxNode {\n if (!fx || typeof fx.pathData !== 'string' || !fx.pathData) return node;\n\n const pathId = genId(ctx, 'tpath');\n const { d, startShift } = extendedPathForBrowser(fx.pathData, {\n pathOverflow: fx.pathOverflow, startOffset: fx.startOffset,\n textLength: fx.textLength, advance: estimateTextAdvance(node),\n });\n ctx.defs.push({ type: 'path', id: pathId, d });\n\n const textPath: PxNode = {\n type: 'textPath',\n href: '#' + pathId,\n children: node.children ?? [],\n };\n if (fx.lengthAdjust !== undefined) textPath.lengthAdjust = fx.lengthAdjust;\n if (fx.method !== undefined) textPath.method = fx.method;\n if (fx.spacing !== undefined) textPath.spacing = fx.spacing;\n // Compensate the start lead-in: shift startOffset (all keyframes) by `startShift`\n // so `extend` doesn't move the text vs the un-extended path.\n applyAnimatableNumber(textPath, 'startOffset', shiftAnimatable(fx.startOffset, startShift));\n applyAnimatableNumber(textPath, 'textLength', fx.textLength);\n\n node.children = [textPath];\n return node;\n}\n\n\n/** Routes a `PxAnimatable<number>` onto a node via the shared reader + emit\n * path (`readAnimatable` → `writeAnimatableChannel`): statics land as string\n * attrs, animations as `animate[attrName]` blocks with `loop`/`autoOrient`\n * carried through and a static first-kf baseline attr. */\nfunction applyAnimatableNumber(node: PxNode, attrName: string, raw: PxAnimatable<number> | undefined): void {\n if (raw === undefined || raw === null) return;\n writeAnimatableChannel(node, attrName, readAnimatable<number>(raw), { asString: true });\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n\n/**\n * Element-creation factory — abstracts WHAT an \"element\" is so the same\n * geometry/layout code (e.g. the glyph text materializer) can emit plain wire\n * nodes here, or the editor's React / px elements when called from the editor.\n *\n * The signature intentionally mirrors the editor's `createPxElement(type,\n * props, children, fixReactKeysIfNeeded?)` so the editor's own factory drops in\n * unchanged.\n * @internal\n */\nexport type PxCreateElement<E = any> = (\n type: string,\n props: { [k: string]: any },\n children?: Array<E> | E | null,\n fixReactKeysIfNeeded?: boolean,\n) => E;\n\n\n/**\n * Default factory → a plain wire node `{ type, ...props, children? }`.\n * Drops `undefined` props and empty `children` so output matches the shape the\n * effects pipeline (and `JSON.stringify`) expects.\n * @internal\n */\nexport const jsonElementFactory: PxCreateElement<any> = (type, props, children) => {\n const node: { [k: string]: any } = { type };\n for (const k in props) if (props[k] !== undefined) node[k] = props[k];\n const arr = Array.isArray(children) ? children.filter(c => c != null) : (children != null ? [children] : []);\n if (arr.length) node.children = arr;\n return node;\n};\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n\n/**\n * Bakes an affine transform into an SVG path-`d` string so per-glyph outlines\n * (in em units) can be placed at their pen position and merged into a single\n * `<path>`. Parses the absolute `M`/`L`/`C`/`Q`/`Z` commands opentype's\n * `toPathData` emits — glyph outlines never use relative or arc commands.\n *\n * Matrix order matches SVG: `x' = a·x + c·y + e`, `y' = b·x + d·y + f`.\n * For horizontal text it's just scale+translate `[s,0,0,s,tx,ty]`; the full\n * 6-tuple leaves room for rotation (along-path, later).\n */\nexport type Affine = [a: number, b: number, c: number, d: number, e: number, f: number];\n\n\nfunction fmt(v: number, decimals: number): string {\n // Match opentype's `floatToString`: integers stay bare, else fixed decimals.\n return Math.round(v) === v ? '' + Math.round(v) : v.toFixed(decimals);\n}\n\n/** Packs numbers the way opentype does: a space separates a value from the\n * previous one only when it doesn't already start with a `-`. */\nfunction pack(nums: Array<number>, decimals: number): string {\n let s = '';\n for (let i = 0; i < nums.length; i++) {\n const str = fmt(nums[i], decimals);\n if (i > 0 && str.charCodeAt(0) !== 45 /* '-' */) s += ' ';\n s += str;\n }\n return s;\n}\n\nfunction apply(m: Affine, x: number, y: number): [number, number] {\n return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];\n}\n\nconst TOKEN_RE = /([MLCQZ])|(-?\\d*\\.?\\d+(?:e[-+]?\\d+)?)/gi;\n\n/**\n * Applies `m` to every coordinate in `d` (absolute M/L/C/Q/Z) and re-emits.\n * Unknown tokens are skipped defensively; the input is always opentype output.\n */\nexport function transformPathData(d: string, m: Affine, decimals: number = 2): string {\n const tokens: Array<string> = [];\n let match: RegExpExecArray | null;\n TOKEN_RE.lastIndex = 0;\n while ((match = TOKEN_RE.exec(d)) !== null) tokens.push(match[0]);\n\n let out = '';\n let i = 0;\n const num = (): number => parseFloat(tokens[i++]);\n\n while (i < tokens.length) {\n const cmd = tokens[i++];\n if (cmd === 'M' || cmd === 'L') {\n const [x, y] = apply(m, num(), num());\n out += cmd + pack([x, y], decimals);\n } else if (cmd === 'C') {\n const [x1, y1] = apply(m, num(), num());\n const [x2, y2] = apply(m, num(), num());\n const [x, y] = apply(m, num(), num());\n out += 'C' + pack([x1, y1, x2, y2, x, y], decimals);\n } else if (cmd === 'Q') {\n const [x1, y1] = apply(m, num(), num());\n const [x, y] = apply(m, num(), num());\n out += 'Q' + pack([x1, y1, x, y], decimals);\n } else if (cmd === 'Z' || cmd === 'z') {\n out += 'Z';\n }\n // else: stray number without a command — skip (never happens for glyph data).\n }\n return out;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n\n/**\n * Glyph text materializer — turns a `<text>`/`<tspan>` subtree into `<path>`\n * outlines from `definitions.fonts`, so the text renders with no external font.\n *\n * - HORIZONTAL ({@link materializeGlyphTextHorizontal}) — left-to-right by\n * advance width; honors font-size, text-anchor, letter/word-spacing,\n * per-tspan x/y/dx/dy, fill/stroke, nested tspans.\n * - ALONG-PATH ({@link materializeGlyphTextAlongPath}) — each glyph placed and\n * rotated to the referenced path's tangent. Static `startOffset` → glyphs\n * bake+merge; animated `startOffset` → per-glyph `<path>` with sampled\n * `animate.transform`. Text-level `x`/`dx` add distance ALONG the path (≈\n * startOffset) and `dy` shifts PERPENDICULAR — matching native `<textPath>`\n * (see {@link alongPathNodeOffsets}); `y` and per-tspan positioning are ignored\n * (a single run).\n *\n * Element creation goes through an injected {@link PxCreateElement} factory, so\n * the SAME layout produces plain wire nodes here (the effects pipeline) or the\n * editor's React/px elements when the editor calls it — see\n * {@link materializeGlyphText}.\n *\n * v1 scope (see svga.text.design.md): keyframe-interval easing is linear;\n * kerning/ligatures, per-tspan opacity, text-level animated fill are out of scope.\n */\n\nimport { type PxAnimatable, type PxGlyphFont, type PxNode, type PxTextEffect } from '../../format/PxAnimatorTypes';\nimport { PX_TEXT_CONTENT_ATTR, CLASS_ATTR } from '../../format/PxAnimatorConstants';\nimport { jsonElementFactory, type PxCreateElement } from './elementFactory';\nimport { transformPathData, type Affine } from './glyphPathBake';\nimport { createPathSampler, type PathSampler } from './pathSampler';\nimport { unwrapAutoOrientRotations } from '../../materialize/PxMotionPath';\nimport { ReadKind, readAnimatable, TransformPart } from '../shared/transformParts';\nimport type { ApplyContext } from '../shared/types';\n\n\nconst DEFAULT_FONT_SIZE = 16;\n\n/** Text/tspan attribute keys that don't belong on the materialized `<g>`. */\nconst TEXT_ATTR_KEYS: ReadonlyArray<string> = [\n 'fontFamily', 'fontSize', 'fontWeight', 'fontStyle', 'textAnchor',\n 'letterSpacing', 'wordSpacing', 'textDecoration', 'textTransform',\n 'whiteSpace', 'x', 'y', 'dx', 'dy', 'lengthAdjust',\n 'fill', 'stroke', 'strokeWidth', 'effects',\n PX_TEXT_CONTENT_ATTR, 'xml:space',\n];\n\n/** Inputs for a glyph materialization, decoupled from the effects `ApplyContext`\n * so the editor can call the materializer directly. * @internal\n */\nexport interface GlyphMaterializeOptions<E = any> {\n /** Embedded glyph fonts, keyed by `font-family`. */\n glyphs: Record<string, PxGlyphFont>;\n /** Element factory — defaults to plain wire nodes ({@link jsonElementFactory}). */\n create?: PxCreateElement<E>;\n /** Optional diagnostics sink. */\n warnings?: Array<string>;\n}\n\n// All paint values are OPAQUE pass-throughs — copied verbatim onto the emitted element.\n// The wire uses plain values (hex strings, numbers, arrays); the editor threads its own\n// model VALUES through unchanged (the factory maps them back to shape paint).\n//\n// A SPAN's paint must fold into the baked paths — the span element itself disappears in\n// the bake, so anything left on it is silently lost. TEXT-level values are NOT part of\n// the paint: they ride the emitted `<g>` (via `toGroup`), so `resolveStyle` skips\n// `type:'text'` nodes' own values. `animate` is the span's animate bag filtered to\n// PAINT keys only (see `PAINT_ANIMATE_KEYS`) — forwarded verbatim onto the emitted\n// `<path>` (the wire's keyframe bags, or the editor's animated-value riders).\ninterface Paint {\n fill?: any; stroke?: any; strokeWidth?: any;\n opacity?: number;\n fillOpacity?: any; fillRule?: any;\n strokeOpacity?: any; strokeDasharray?: any; strokeDashoffset?: any;\n strokeLinecap?: any; strokeLinejoin?: any; strokeMiterlimit?: any;\n mixBlendMode?: any; filter?: any;\n animate?: { [k: string]: any };\n}\n/** The per-span statics that fold into `Paint` by simple nearest-wins lookup. */\nconst PAINT_STATIC_KEYS = [\n 'fillOpacity', 'fillRule', 'strokeOpacity', 'strokeDasharray', 'strokeDashoffset',\n 'strokeLinecap', 'strokeLinejoin', 'strokeMiterlimit', 'mixBlendMode', 'filter',\n] as const;\n/** `animate.<key>`s that are PAINT (ride the baked path). Geometry keys — x/dx/fontSize/\n * letterSpacing/… — are baked into the outlines and must NOT be forwarded. */\nconst PAINT_ANIMATE_KEYS = ['fill', 'stroke', 'strokeWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'strokeDasharray', 'strokeDashoffset'];\ninterface Style extends Paint { fontFamily?: string; fontSize: number; letterSpacing: number; wordSpacing: number; }\n/** A glyph ready to emit: its em outline + the affine placing it in the doc.\n * `isMissing` marks the □ placeholder — kept out of the merged real-glyph paths so a\n * consumer can style it (see `MISSING_GLYPH_CLASS_NAME`). */\ninterface Placement { glyphD: string; m: Affine; paint: Paint; isMissing?: boolean; }\n/** Minimal keyframe shape (avoids `PxKeyframe`'s non-generic type). Input\n * `startOffset` kfs carry a number `value`; emitted kfs carry transform parts. */\ninterface TransformKeyframe<V = any> { time?: number; value: V; }\n\n\nfunction parseLen(v: unknown): number | undefined {\n if (typeof v === 'number') return v;\n if (typeof v === 'string') { const n = parseFloat(v); return isNaN(n) ? undefined : n; }\n return undefined;\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' ? v : undefined;\n}\n\n/** A span's paint-only `animate` bag, or undefined when it has none (see `PAINT_ANIMATE_KEYS`). */\nfunction paintAnimateOf(node: PxNode): { [k: string]: any } | undefined {\n const bag = node.animate as { [k: string]: any } | undefined;\n if (!bag || typeof bag !== 'object') return undefined;\n let out: { [k: string]: any } | undefined;\n for (const k of PAINT_ANIMATE_KEYS) {\n if (bag[k] !== undefined) (out ??= {})[k] = bag[k];\n }\n return out;\n}\n\nfunction resolveStyle(node: PxNode, parent: Style): Style {\n // SPAN paint only: the root `<text>`'s own values (and its whole `animate` bag) ride\n // the emitted `<g>` via `toGroup` — reading them here too would apply them twice.\n //\n // NEAREST WINS, deliberately NOT composed: the editor wire used to emit a collapsed\n // single-span line as a line-`<tspan>` carrying the folded span style AND the child\n // span with the same style — the same opacity on BOTH nesting levels; multiplying\n // would square it. Same override semantics as the other style props (fill, fontSize).\n const isTextRoot = node.type === 'text';\n const nodeStyle = node.style as { [k: string]: any } | undefined;\n const own = (key: string): any => isTextRoot ? undefined : ((node as { [k: string]: any })[key] ?? nodeStyle?.[key]);\n\n const res: Style = {\n fontFamily: str(node.fontFamily) ?? parent.fontFamily,\n fontSize: parseLen(node.fontSize) ?? parent.fontSize,\n fill: node.fill ?? parent.fill,\n stroke: node.stroke ?? parent.stroke,\n strokeWidth: node.strokeWidth ?? parent.strokeWidth,\n letterSpacing: parseLen(node.letterSpacing) ?? parent.letterSpacing,\n wordSpacing: parseLen(node.wordSpacing) ?? parent.wordSpacing,\n opacity: parseLen(own('opacity')) ?? parent.opacity,\n animate: (isTextRoot ? undefined : paintAnimateOf(node)) ?? parent.animate,\n };\n for (const key of PAINT_STATIC_KEYS) {\n const v = own(key) ?? parent[key];\n if (v !== undefined) res[key] = v;\n }\n return res;\n}\n\nfunction rootStyleOf(node: PxNode): Style {\n return {\n fontFamily: str(node.fontFamily),\n fontSize: parseLen(node.fontSize) ?? DEFAULT_FONT_SIZE,\n fill: node.fill,\n stroke: node.stroke,\n strokeWidth: node.strokeWidth,\n letterSpacing: parseLen(node.letterSpacing) ?? 0,\n wordSpacing: parseLen(node.wordSpacing) ?? 0,\n };\n}\n\nfunction paintOf(s: Style): Paint {\n // Field order is FIXED (it feeds the JSON.stringify merge key in `buildPaths`).\n const p: Paint = {};\n if (s.fill !== undefined) p.fill = s.fill;\n if (s.stroke !== undefined) p.stroke = s.stroke;\n if (s.strokeWidth !== undefined) p.strokeWidth = s.strokeWidth;\n if (s.opacity !== undefined && s.opacity !== 1) p.opacity = s.opacity;\n for (const key of PAINT_STATIC_KEYS) {\n if (s[key] !== undefined) p[key] = s[key];\n }\n if (s.animate !== undefined) p.animate = s.animate;\n return p;\n}\n\n/** The embedded outlines for a span. `font-family` holds the FACE name the author picked\n * (`Roboto-Light`), which is exactly the key the writer stored, so this is a direct lookup —\n * weight/slant are CSS attrs and never select a face. */\nfunction glyphFontFor(s: Style, glyphs: Record<string, PxGlyphFont>, soleFont: PxGlyphFont | undefined, warnings?: Array<string>): PxGlyphFont | undefined {\n const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;\n if (!gf) warnings?.push('textGlyphs: no glyphs for font \"' + (s.fontFamily ?? '') + '\"');\n return gf;\n}\n\nfunction soleFontOf(glyphs: Record<string, PxGlyphFont>): PxGlyphFont | undefined {\n const names = Object.keys(glyphs);\n return names.length === 1 ? glyphs[names[0]] : undefined;\n}\n\n\n/** Default advance (in em units) for a MISSING glyph with no known width, so its\n * placeholder box gets a plausible letter-cell instead of collapsing to nothing. */\nconst MISSING_GLYPH_ADVANCE_EM = 0.6;\n\n/**\n * Class stamped on the `<path>` holding the □ placeholders — and ONLY on it: the missing\n * boxes are emitted separately from the real glyphs so a consumer can style them on their\n * own. The editor uses it to fade them in with a delay: a freshly typed character is\n * missing for a few frames until its glyph is fetched asynchronously, and a □ that flashes\n * for that long reads as a rendering glitch.\n * @internal\n */\nexport const MISSING_GLYPH_CLASS_NAME = 'px-missing-glyph';\n\n/**\n * A HOLLOW FRAME outline (em/glyph units, baseline at y=0 rising to y=-ascent) for a\n * MISSING glyph — so a font that can't supply a char renders a visible □ instead of\n * silently disappearing. Outer rect + a reversed inner rect → a plain nonzero `fill`\n * (the SAME paint a real glyph uses) leaves the middle empty, i.e. a thin outline (a\n * solid block reads as too brutal). Empty string for degenerate sizes.\n */\nfunction missingGlyphBoxEm(advanceEm: number, ascentEm: number): string {\n if (advanceEm <= 0 || ascentEm <= 0) return '';\n const inset = 0.08;\n const x0 = advanceEm * inset, x1 = advanceEm * (1 - inset);\n const y1 = -ascentEm * (1 - inset); // box top (baseline at 0)\n const bw = x1 - x0, bh = -y1;\n const t = Math.max(1, Math.min(bw, bh) * 0.12); // frame border thickness\n const outer = 'M' + x0 + ' 0L' + x1 + ' 0L' + x1 + ' ' + y1 + 'L' + x0 + ' ' + y1 + 'Z';\n if (bw <= 2 * t || bh <= 2 * t) return outer; // too small for a hole → solid\n const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;\n // Inner rect wound OPPOSITE the outer → nonzero fill carves a hole (the outline).\n return outer + 'M' + ix0 + ' ' + iyb + 'L' + ix0 + ' ' + iyt + 'L' + ix1 + ' ' + iyt + 'L' + ix1 + ' ' + iyb + 'Z';\n}\n\n\n// ── HORIZONTAL ──────────────────────────────────────────────────────────────\n\n/** @internal */\nexport function materializeGlyphTextHorizontal<E = any>(node: PxNode, opts: GlyphMaterializeOptions<E>): E {\n const { glyphs, create = jsonElementFactory as PxCreateElement<E>, warnings } = opts;\n const soleFont = soleFontOf(glyphs);\n\n const pen = { x: parseLen(node.x) ?? 0, y: parseLen(node.y) ?? 0 };\n const placements: Array<Placement & { line: number; x: number; y: number; scale: number }> = [];\n const lines: Array<{ start: number; end: number }> = [{ start: pen.x, end: pen.x }];\n let line = 0;\n\n const renderChars = (content: string, s: Style): void => {\n const gf = glyphFontFor(s, glyphs, soleFont, warnings);\n const upm = gf?.unitsPerEm || 1000;\n const scale = s.fontSize / upm;\n const ascentEm = gf?.ascent ?? 0.9 * upm;\n const paint = paintOf(s);\n for (let i = 0; i < content.length; i++) {\n const ch = content.charAt(i);\n const g = gf?.glyphs[ch];\n if (g && g.pathData) {\n placements.push({ glyphD: g.pathData, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });\n pen.x += g.width * scale;\n } else if (/\\S/.test(ch)) {\n // Missing glyph (font absent, or the char has no outline) → a visible □\n // placeholder box so the text doesn't just silently vanish.\n const advEm = (g && g.width > 0) ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;\n 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 });\n pen.x += advEm * scale;\n } else {\n pen.x += (g ? g.width : 0) * scale; // whitespace: advance only\n }\n pen.x += s.letterSpacing + (ch === ' ' ? s.wordSpacing : 0);\n lines[line].end = pen.x;\n }\n };\n\n const walk = (el: PxNode, parentStyle: Style): void => {\n const s = resolveStyle(el, parentStyle);\n const x = parseLen(el.x);\n const y = parseLen(el.y);\n if (x !== undefined) { pen.x = x; line = lines.length; lines.push({ start: pen.x, end: pen.x }); }\n if (y !== undefined) pen.y = y;\n pen.x += parseLen(el.dx) ?? 0;\n pen.y += parseLen(el.dy) ?? 0;\n const content = str(el[PX_TEXT_CONTENT_ATTR]);\n // Render a node's OWN text only when it has no element children. In the glyph\n // text model text lives on leaf spans; a container that ALSO carries folded\n // text — a single-span line collapsed onto its line-`<tspan>` — would\n // otherwise render its run twice (the fold AND the child span).\n if (content && !el.children?.length) renderChars(content, s);\n if (el.children) for (const ch of el.children) walk(ch, s);\n };\n\n const rootStyle = rootStyleOf(node);\n if (node.children) for (const ch of node.children) walk(ch, rootStyle);\n const rootContent = str(node[PX_TEXT_CONTENT_ATTR]);\n if (rootContent && !node.children?.length) renderChars(rootContent, rootStyle);\n\n // text-anchor: shift each line by its own advance width, then rebuild `m`.\n const anchor = str(node.textAnchor);\n if (anchor === 'middle' || anchor === 'end') {\n for (const p of placements) {\n const w = lines[p.line].end - lines[p.line].start;\n const shift = anchor === 'middle' ? -w / 2 : -w;\n p.m = [p.scale, 0, 0, p.scale, p.x + shift, p.y];\n }\n }\n\n return toGroup(node, buildPaths(placements, create, warnings), create);\n}\n\n\n/** Per-CHARACTER advance box (local, pre-transform coords). `x,y` = the char's baseline start,\n * `width` = its advance, `ascent`/`fontSize` size its bbox. * @internal\n */\nexport interface PxGlyphCharBox {\n x: number; y: number; width: number; ascent: number; fontSize: number;\n /** Along-path only: baseline END point (leading edge of the next char). Absent for\n * horizontal, where the end is `x + width` on the same baseline. */\n endX?: number; endY?: number;\n /** Along-path only: char rotation in DEGREES (path tangent; 0 = horizontal). */\n rotation?: number;\n}\n\n/** Optional along-path geometry for {@link layoutGlyphTextChars}: when given, chars are\n * placed + rotated along `pathD` (mirrors {@link materializeGlyphTextAlongPath}) at the\n * STATIC / frame-0 startOffset, so the editor caret follows the path. * @internal\n */\nexport interface GlyphCharBoxAlongPath { pathD?: string; startOffset?: PxAnimatable<number>; textLength?: PxAnimatable<number>; pathOverflow?: string; }\n\n/** Per-character layout boxes for a glyph text, in reading/DOM order INCLUDING spaces\n * (a space has no glyph but advances the pen) AND one zero-width filler box per EMPTY\n * line — the editor's edit canvas renders a zero-width filler char for an empty line\n * (so the caret has something to measure), and DOM char indices must stay aligned.\n * HORIZONTAL by default — mirrors `materializeGlyphTextHorizontal`'s pen-walk exactly\n * (same x/y/dx/dy, spacing and text-anchor). When `opts.alongPath` is given, mirrors\n * `materializeGlyphTextAlongPath` (each char placed + rotated to the path tangent). So\n * an editor caret built from these lands on the rendered glyphs. Empty for a text with\n * no glyph font / unparsable path. * @internal\n */\nexport function layoutGlyphTextChars(node: PxNode, opts: Pick<GlyphMaterializeOptions, 'glyphs' | 'warnings'> & { alongPath?: GlyphCharBoxAlongPath }): Array<PxGlyphCharBox> {\n if (opts.alongPath?.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);\n const { glyphs, warnings } = opts;\n const soleFont = soleFontOf(glyphs);\n\n const pen = { x: parseLen(node.x) ?? 0, y: parseLen(node.y) ?? 0 };\n const boxes: Array<PxGlyphCharBox & { line: number }> = [];\n const lines: Array<{ start: number; end: number }> = [{ start: pen.x, end: pen.x }];\n let line = 0;\n\n const renderChars = (content: string, s: Style): void => {\n const gf = glyphFontFor(s, glyphs, soleFont, warnings);\n const upm = gf?.unitsPerEm || 1000;\n const scale = s.fontSize / upm;\n const ascent = (gf?.ascent ?? 0.9 * upm) * scale;\n for (let i = 0; i < content.length; i++) {\n const ch = content.charAt(i);\n const g = gf?.glyphs[ch];\n const advance = (g ? g.width : 0) * scale + s.letterSpacing + (ch === ' ' ? s.wordSpacing : 0);\n boxes.push({ x: pen.x, y: pen.y, width: advance, ascent, fontSize: s.fontSize, line });\n pen.x += advance;\n lines[line].end = pen.x;\n }\n };\n\n const walk = (el: PxNode, parentStyle: Style): void => {\n const s = resolveStyle(el, parentStyle);\n const x = parseLen(el.x);\n const y = parseLen(el.y);\n if (x !== undefined) { pen.x = x; line = lines.length; lines.push({ start: pen.x, end: pen.x }); }\n if (y !== undefined) pen.y = y;\n pen.x += parseLen(el.dx) ?? 0;\n pen.y += parseLen(el.dy) ?? 0;\n const content = str(el[PX_TEXT_CONTENT_ATTR]);\n if (content && !el.children?.length) renderChars(content, s);\n if (el.children) for (const ch of el.children) walk(ch, s);\n };\n\n const rootStyle = rootStyleOf(node);\n if (node.children) for (const ch of node.children) {\n const before = boxes.length;\n walk(ch, rootStyle);\n // An EMPTY line (a line-tspan whose subtree yields no chars) still occupies ONE\n // DOM slot on the edit canvas — the zero-width filler the editor renders so the\n // caret has something to measure. Mirror it: one zero-width box at the line's\n // pen position, sized by the line's own resolved font (ascent for caret height,\n // and its hit quad extends the element bbox to include the empty line).\n if (boxes.length === before) {\n const s = resolveStyle(ch, rootStyle);\n const gf = glyphFontFor(s, glyphs, soleFont); // no warning — an empty line has nothing to render\n const upm = gf?.unitsPerEm || 1000;\n boxes.push({ x: pen.x, y: pen.y, width: 0, ascent: (gf?.ascent ?? 0.9 * upm) * (s.fontSize / upm), fontSize: s.fontSize, line });\n }\n }\n const rootContent = str(node[PX_TEXT_CONTENT_ATTR]);\n if (rootContent && !node.children?.length) renderChars(rootContent, rootStyle);\n\n // text-anchor: shift each line's chars by its own advance width (matches the placement shift).\n const anchor = str(node.textAnchor);\n if (anchor === 'middle' || anchor === 'end') {\n for (const b of boxes) {\n const w = lines[b.line].end - lines[b.line].start;\n b.x += anchor === 'middle' ? -w / 2 : -w;\n }\n }\n return boxes.map(({ line: _l, ...b }) => b);\n}\n\n/** Along-path variant of {@link layoutGlyphTextChars}: one box per DOM char (spaces\n * included), placed + rotated along `pathD` at the static / frame-0 startOffset.\n * Mirrors `collectAlongPathCells` + `materializeGlyphTextAlongPath`, but records EVERY\n * char (the materializer's cells skip glyph-less chars). `pStart`=char leading edge on\n * the path, `end`=trailing edge, `rotation`=tangent at the char midpoint. */\nfunction layoutGlyphTextCharsAlongPath(node: PxNode, pathD: string, opts: Pick<GlyphMaterializeOptions, 'glyphs' | 'warnings'> & { alongPath?: GlyphCharBoxAlongPath }): Array<PxGlyphCharBox> {\n const { glyphs, warnings, alongPath } = opts;\n const sampler = createPathSampler(pathD);\n if (!sampler) { warnings?.push('textGlyphs: unparsable along-path geometry (caret)'); return []; }\n const soleFont = soleFontOf(glyphs);\n\n // Reading-order pass over leaf text (positioning attrs ignored — along-path is a\n // single run), recording each char's [advStart, advEnd], its glyph advance (WITHOUT\n // spacing) for the rotation midpoint, and bbox metrics.\n const chars: Array<{ advStart: number; advEnd: number; glyphW: number; ascent: number; fontSize: number }> = [];\n let adv = 0;\n const walk = (el: PxNode, parentStyle: Style): void => {\n const s = resolveStyle(el, parentStyle);\n const content = str(el[PX_TEXT_CONTENT_ATTR]);\n if (content && !el.children?.length) {\n const gf = glyphFontFor(s, glyphs, soleFont, warnings);\n const upm = gf?.unitsPerEm || 1000;\n const scale = s.fontSize / upm;\n const ascent = (gf?.ascent ?? 0.9 * upm) * scale;\n for (let i = 0; i < content.length; i++) {\n const ch = content.charAt(i);\n const g = gf?.glyphs[ch];\n const glyphW = (g ? g.width : 0) * scale;\n const advance = glyphW + s.letterSpacing + (ch === ' ' ? s.wordSpacing : 0);\n chars.push({ advStart: adv, advEnd: adv + advance, glyphW, ascent, fontSize: s.fontSize });\n adv += advance;\n }\n }\n if (el.children) for (const ch of el.children) walk(ch, s);\n };\n walk(node, rootStyleOf(node));\n\n const width = adv;\n // textLength (lengthAdjust=spacing): scale positions so the run spans textLength.\n // Static / frame-0 read — the caret is a static-frame layout (like startOffset below).\n const tlr = readAnimatable<number>(alongPath?.textLength);\n const tlv = tlr.kind === ReadKind.Animated ? (Number(tlr.keyframes[0]?.value) || 0)\n : tlr.kind === ReadKind.Static ? (Number(tlr.value) || 0) : 0;\n const k = (tlv > 0 && width > 0) ? tlv / width : 1;\n // startOffset base — static or frame-0 keyframe (matches the materializer's static place).\n // x/dx add along-path distance; dy shifts perpendicular (both mirror the materializer).\n const so = readAnimatable<number>(alongPath?.startOffset);\n const { along: alongOffset, perp } = alongPathNodeOffsets(node);\n const base = alongOffset + (so.kind === ReadKind.Animated ? (Number(so.keyframes[0]?.value) || 0)\n : so.kind === ReadKind.Static ? (Number(so.value) || 0) : 0);\n\n // Shift a sampled point perpendicular to the path (left normal) by `perp`.\n const withPerp = (p: { x: number; y: number; angle: number }) => ({\n x: p.x - perp * Math.sin(p.angle), y: p.y + perp * Math.cos(p.angle), angle: p.angle,\n });\n\n return chars.map(c => {\n const dStart = base + c.advStart * k;\n const dEnd = base + c.advEnd * k;\n const p0 = withPerp(sampler.sampleAtDistance(dStart));\n const p1 = withPerp(sampler.sampleAtDistance(dEnd));\n // Caret rotation = tangent at the GLYPH's own midpoint (advStart + glyphW/2), which\n // DISREGARDS the char's letter/word spacing. This keeps the synthetic caret aligned\n // with the baked glyph outline (which is placed at its glyph center), so letter\n // spacing doesn't add extra tilt to the caret.\n const glyphMid = sampler.sampleAtDistance(base + (c.advStart + c.glyphW / 2) * k);\n return {\n x: p0.x, y: p0.y,\n width: c.advEnd - c.advStart,\n ascent: c.ascent, fontSize: c.fontSize,\n endX: p1.x, endY: p1.y,\n rotation: glyphMid.angle * 180 / Math.PI,\n };\n });\n}\n\n\n// ── ALONG-PATH ──────────────────────────────────────────────────────────────\n\n/** One glyph in path order: its outline + geometry, and `midBase` = the arc-\n * distance from the text start (startOffset 0) to the glyph's advance midpoint. */\ninterface AlongCell { glyphD: string; widthEm: number; scale: number; paint: Paint; midBase: number; isMissing?: boolean; }\n\n/** Walks the tspans in reading order, accumulating advance (whitespace included)\n * so each rendered glyph gets its `midBase`. Positioning attrs are ignored —\n * along-path text is a single run. */\nfunction collectAlongPathCells(node: PxNode, glyphs: Record<string, PxGlyphFont>, soleFont: PxGlyphFont | undefined, warnings?: Array<string>): { cells: Array<AlongCell>; width: number } {\n const cells: Array<AlongCell> = [];\n let adv = 0;\n const walk = (el: PxNode, parentStyle: Style): void => {\n const s = resolveStyle(el, parentStyle);\n const content = str(el[PX_TEXT_CONTENT_ATTR]);\n // Only leaf text (no children) — a single-span line folds its text onto the\n // line-`<tspan>` AND keeps the child span; rendering both would duplicate it.\n if (content && !el.children?.length) {\n const gf = glyphFontFor(s, glyphs, soleFont, warnings);\n if (gf) {\n const scale = s.fontSize / gf.unitsPerEm;\n const ascentEm = gf.ascent ?? 0.9 * gf.unitsPerEm;\n const paint = paintOf(s);\n for (let i = 0; i < content.length; i++) {\n const ch = content.charAt(i);\n const g = gf.glyphs[ch];\n if (g && g.pathData) {\n const glyphAdv = g.width * scale;\n cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });\n adv += glyphAdv;\n } else if (/\\S/.test(ch)) {\n // Missing glyph → a visible □ placeholder box (see missingGlyphBoxEm).\n const wEm = (g && g.width > 0) ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;\n const boxAdv = wEm * scale;\n cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, isMissing: true, midBase: adv + boxAdv / 2 });\n adv += boxAdv;\n } else {\n adv += (g ? g.width : 0) * scale; // whitespace: advance only\n }\n adv += s.letterSpacing + (ch === ' ' ? s.wordSpacing : 0);\n }\n }\n }\n if (el.children) for (const ch of el.children) walk(ch, s);\n };\n walk(node, rootStyleOf(node));\n return { cells, width: adv };\n}\n\n/** Affine placing a glyph so its mid-advance baseline sits at path-distance\n * `dist`, rotated to the tangent (scale baked in). `perp` shifts the glyph\n * PERPENDICULAR to the path (SVG `dy` on text-on-a-path), along the left normal\n * (−sinθ, cosθ) — in path/user units, NOT scaled by the glyph size. */\nfunction alongAffine(sampler: PathSampler, dist: number, scale: number, widthEm: number, perp = 0): Affine {\n const { x, y, angle } = sampler.sampleAtDistance(dist);\n const cos = Math.cos(angle), sin = Math.sin(angle), hw = widthEm / 2;\n return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];\n}\n\n/** Text-on-a-path offsets from the `<text>`/`<tspan>` x/dx/dy attributes (horizontal\n * writing mode; see the SVG \"text on a path\" layout rules):\n * • `x` and `dx` shift ALONG the path (both add to the startpoint distance),\n * • `dy` shifts PERPENDICULAR to the path,\n * • `y` is IGNORED (the path, not `y`, sets the cross-axis position).\n * Matches the browser's native `<textPath>` so our baked glyphs line up with it. */\nfunction alongPathNodeOffsets(node: PxNode): { along: number; perp: number } {\n return {\n along: (parseLen(node.x) ?? 0) + (parseLen(node.dx) ?? 0),\n perp: parseLen(node.dy) ?? 0,\n };\n}\n\n/** @internal */\nexport function materializeGlyphTextAlongPath<E = any>(\n node: PxNode,\n pathD: string | undefined,\n startOffset: PxAnimatable<number> | undefined,\n opts: GlyphMaterializeOptions<E>,\n textLength?: PxAnimatable<number>,\n pathOverflow?: string,\n): E | null {\n const { glyphs, create = jsonElementFactory as PxCreateElement<E>, warnings } = opts;\n const sampler = pathD ? createPathSampler(pathD) : null;\n if (!sampler) { warnings?.push('textGlyphs: unparsable along-path geometry'); return null; }\n\n const soleFont = soleFontOf(glyphs);\n const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);\n if (!cells.length) return toGroup(node, [], create);\n\n // x/dx → extra distance ALONG the path (added to startOffset); dy → perpendicular.\n const { along: alongOffset, perp } = alongPathNodeOffsets(node);\n\n // Both drivers as piecewise-linear tracks. textLength (lengthAdjust=spacing) scales\n // each glyph's position along the path so the run spans `textLength(t)` (glyph\n // outlines keep their natural size): distance(t) = startOffset(t) + k(t)·midBase.\n const soTrack = numTrackOf(startOffset);\n const tlTrack = numTrackOf(textLength);\n const kOf = (tl: number): number => (tl > 0 && width > 0) ? tl / width : 1;\n\n // pathOverflow 'clip' (open path): a glyph whose mid-advance point falls past an\n // end disappears (native <textPath> semantics), vs 'extend' (default) where the\n // sampler continues along the tangent. See svga.text.path-overflow.plan.md.\n const isClip = pathOverflow === 'clip' && !sampler.closed;\n\n if (soTrack.animated || tlTrack.animated) {\n // startOffset and/or textLength animate → each glyph slides along the path: its\n // own <path> with sampled translate+rotate keyframes (no merge). Per merged-\n // timeline interval both tracks are linear, so the glyph distance is linear too.\n const times = mergeTrackTimes(soTrack.times, tlTrack.times);\n const distOf = (c: AlongCell, t: number): number => alongOffset + soTrack.at(t) + kOf(tlTrack.at(t)) * c.midBase;\n const loop = soTrack.animated ? soTrack.loop : tlTrack.loop;\n return toGroup(node, buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isClip, perp), create);\n }\n\n // Static (or single-keyframe): place + bake; glyphs sharing paint still merge.\n const k = kOf(tlTrack.at(0));\n const base = alongOffset + soTrack.at(0);\n const placeCells = isClip\n ? cells.filter(c => { const d = base + c.midBase * k; return d >= 0 && d <= sampler.totalLength; })\n : cells;\n const placements: Array<Placement> = placeCells.map(c => ({\n glyphD: c.glyphD, paint: c.paint, isMissing: c.isMissing,\n m: alongAffine(sampler, base + c.midBase * k, c.scale, c.widthEm, perp),\n }));\n return toGroup(node, buildPaths(placements, create, warnings), create);\n}\n\n/** A `PxAnimatable<number>` as a clamped piecewise-LINEAR sampler: constant for\n * static / absent / single-keyframe, keyframe-interpolated when animated — the same\n * linear-per-interval interpretation the along-path baking has always used. */\ninterface NumTrack { animated: boolean; times: Array<number>; loop?: unknown; at(t: number): number; }\n\nfunction numTrackOf(raw: PxAnimatable<number> | undefined): NumTrack {\n const r = readAnimatable<number>(raw);\n if (r.kind === ReadKind.Animated && r.keyframes.length >= 2) {\n const kfs = [...r.keyframes].sort((k1, k2) => (Number(k1.time) || 0) - (Number(k2.time) || 0));\n const times = kfs.map(kf => Number(kf.time) || 0);\n const vals = kfs.map(kf => Number(kf.value) || 0);\n return {\n animated: true, times, loop: r.loop,\n at(t: number): number {\n if (t <= times[0]) return vals[0];\n for (let i = 1; i < times.length; i++) {\n if (t <= times[i]) {\n const span = times[i] - times[i - 1];\n const f = span > 0 ? (t - times[i - 1]) / span : 1;\n return vals[i - 1] + f * (vals[i] - vals[i - 1]);\n }\n }\n return vals[vals.length - 1];\n },\n };\n }\n const v = r.kind === ReadKind.Animated ? (Number(r.keyframes[0]?.value) || 0)\n : r.kind === ReadKind.Static ? (Number(r.value) || 0) : 0;\n return { animated: false, times: [], at: () => v };\n}\n\n/** Sorted union of two keyframe-time lists (deduped) — the merged animation timeline. */\nfunction mergeTrackTimes(a: Array<number>, b: Array<number>): Array<number> {\n const all = [...a, ...b].sort((t1, t2) => t1 - t2);\n const out: Array<number> = [];\n for (const t of all) if (!out.length || t !== out[out.length - 1]) out.push(t);\n return out;\n}\n\n\n// Sampling density for a glyph's motion-path keyframes: aim for ~≤ this many\n// steps across the whole path so linear interpolation follows the curve.\nconst ALONG_PATH_MAX_STEPS = 48;\nconst ALONG_PATH_MAX_STEPS_PER_SEGMENT = 64;\n\nfunction roundN(v: number, n: number): number {\n const f = 10 ** n;\n return Math.round(v * f) / f;\n}\n\n/** Builds a separate glyph element per glyph, its outline baked centered at the\n * origin (mid-advance baseline) so `animate.transform` translate+rotate places\n * it along the path over time. `distOf` gives the glyph's along-path distance at a\n * time (startOffset(t) + textLength-scale(t)·midBase + x/dx — both drivers merged\n * into `times`); each interval is sub-sampled so the glyph tracks a curved path.\n * Interval interp is linear (per-keyframe easing shaping isn't reproduced — a v1\n * limitation). */\nfunction buildAnimatedAlongPath<E>(\n cells: Array<AlongCell>,\n sampler: PathSampler,\n distOf: (c: AlongCell, t: number) => number,\n times: Array<number>,\n loop: unknown,\n create: PxCreateElement<E>,\n isClip: boolean,\n perp = 0,\n): Array<E> {\n const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);\n const onPath = (dist: number): boolean => dist >= 0 && dist <= sampler.totalLength;\n\n const out: Array<E> = [];\n for (const c of cells) {\n const centered: Affine = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];\n const d = transformPathData(c.glyphD, centered);\n\n const sampleKf = (dist: number, time: number): TransformKeyframe => {\n const { x, y, angle } = sampler.sampleAtDistance(dist);\n const cos = Math.cos(angle), sin = Math.sin(angle);\n // dy shifts perpendicular to the path (left normal), in path units.\n return {\n time,\n value: {\n [TransformPart.Translate]: [roundN(x - perp * sin, 3), roundN(y + perp * cos, 3)],\n [TransformPart.Rotate]: roundN(angle * 180 / Math.PI, 3),\n },\n };\n };\n\n const kfs: Array<TransformKeyframe> = [];\n // Clip: opacity 1 while the glyph's center is on the path, 0 off — the\n // sampling is dense (`step`), so the linear fade across one step reads as a\n // near-sharp pop (a robust stand-in for the hard native-<textPath> drop).\n const opKfs: Array<TransformKeyframe<number>> = [];\n const pushKf = (dist: number, time: number): void => {\n kfs.push(sampleKf(dist, time));\n if (isClip) opKfs.push({ time, value: onPath(dist) ? 1 : 0 });\n };\n\n pushKf(distOf(c, times[0]), times[0]);\n for (let k = 1; k < times.length; k++) {\n const t0 = times[k - 1], t1 = times[k];\n const d0 = distOf(c, t0), d1 = distOf(c, t1);\n const n = Math.min(ALONG_PATH_MAX_STEPS_PER_SEGMENT, Math.max(1, Math.ceil(Math.abs(d1 - d0) / step)));\n for (let s = 1; s <= n; s++) {\n const f = s / n;\n const t = t0 + f * (t1 - t0);\n pushKf(distOf(c, t), t);\n }\n }\n\n // Tangent angles come from atan2 and wrap at ±180° — crossing that seam (e.g.\n // the bottom of a circle) would otherwise lerp the ~358° long way between two\n // samples and visibly flip the glyph. Same fix as motion-path auto-orient.\n unwrapAutoOrientRotations(kfs);\n\n const transform: { keyframes: Array<TransformKeyframe>; loop?: unknown } = { keyframes: kfs };\n if (loop !== undefined) transform.loop = loop;\n const animate: { [k: string]: any } = { transform };\n // Only add an opacity track when it actually toggles (a glyph fully on-path\n // the whole time needs none).\n // Span-level animated paint rides along (dasharray, fill, …).\n if (c.paint.animate) Object.assign(animate, c.paint.animate);\n if (isClip && opKfs.some(k => k.value === 0)) {\n // The CLIP visibility track owns the opacity slot — two opacity animations\n // aren't expressible on one element, and visibility is what makes clip mode\n // work at all, so it overrides a span's own animated opacity.\n const op: { keyframes: Array<TransformKeyframe<number>>; loop?: unknown } = { keyframes: opKfs };\n if (loop !== undefined) op.loop = loop;\n animate.opacity = op;\n }\n\n out.push(create('path', { d, ...paintProps(c.paint), ...missingGlyphProps(c.isMissing), animate }, []));\n }\n return out;\n}\n\n\n// ── shared emit ───────────────────────────────────────────────────────────────\n\nfunction paintProps(paint: Paint): { [k: string]: any } {\n const p: { [k: string]: any } = {};\n if (paint.fill !== undefined) p.fill = paint.fill;\n if (paint.stroke !== undefined) p.stroke = paint.stroke;\n if (paint.strokeWidth !== undefined) p.strokeWidth = paint.strokeWidth;\n if (paint.opacity !== undefined) p.opacity = paint.opacity;\n for (const key of PAINT_STATIC_KEYS) {\n if (paint[key] !== undefined) p[key] = paint[key];\n }\n // NOT `animate` — it merges into the emitted `animate` bag at each emit site.\n return p;\n}\n\n/** Marks a □-placeholder `<path>` for consumers; nothing at all for real glyphs. */\nfunction missingGlyphProps(isMissing: boolean | undefined): { [k: string]: any } {\n return isMissing ? { [CLASS_ATTR]: MISSING_GLYPH_CLASS_NAME } : {};\n}\n\n/** Merges placements sharing paint into baked `<path>` elements. MISSING-glyph boxes merge\n * only with each other, so they end up in their own classed `<path>` (see\n * `MISSING_GLYPH_CLASS_NAME`) instead of being indistinguishable subpaths of a real one. */\nfunction buildPaths<E>(placements: Array<Placement>, create: PxCreateElement<E>, warnings?: Array<string>): Array<E> {\n if (!placements.length) { warnings?.push('textGlyphs: nothing to render'); return []; }\n\n const byPaint = new Map<string, { paint: Paint; d: string; isMissing?: boolean }>();\n for (const p of placements) {\n // Stable key across any paint value type (hex string, [r,g,b], gradient object).\n // The WHOLE paint — statics AND the animate bag — is the key (`paintOf` builds it\n // with a fixed field order): spans that differ in ANY paint aspect must not merge.\n const key = JSON.stringify([p.paint, !!p.isMissing]);\n const baked = transformPathData(p.glyphD, p.m);\n const entry = byPaint.get(key);\n if (entry) entry.d += baked;\n else byPaint.set(key, { paint: p.paint, d: baked, isMissing: p.isMissing });\n }\n\n const out: Array<E> = [];\n for (const { paint, d, isMissing } of byPaint.values()) {\n out.push(create('path', {\n d, ...paintProps(paint), ...missingGlyphProps(isMissing),\n // A span's ANIMATED paint rides the merged path as a standard animate bag.\n ...(paint.animate !== undefined ? { animate: { ...paint.animate } } : {}),\n }, []));\n }\n return out;\n}\n\n/** Builds the `<g>` that replaces the `<text>`: keeps its transform / id /\n * animate / opacity, drops text-specific attributes, holds the glyph elements. */\nfunction toGroup<E>(node: PxNode, children: Array<E>, create: PxCreateElement<E>): E {\n const gProps: { [k: string]: any } = {};\n for (const k of Object.keys(node)) {\n if (k === 'type' || k === 'children' || TEXT_ATTR_KEYS.indexOf(k) !== -1) continue;\n gProps[k] = (node as { [k: string]: any })[k];\n }\n if (gProps.style && typeof gProps.style === 'object') {\n const style = { ...(gProps.style as Record<string, unknown>) };\n delete style['white-space'];\n if (Object.keys(style).length) gProps.style = style; else delete gProps.style;\n }\n return create('g', gProps, children);\n}\n\n\n// ── editor-facing convenience + pipeline adapters ──────────────────────────────\n\n/** Single entry the EDITOR calls: materializes a glyph `<text>` node into the\n * factory's element type, choosing along-path when `alongPath` is given. * @internal\n */\nexport function materializeGlyphText<E = any>(\n node: PxNode,\n opts: GlyphMaterializeOptions<E> & { alongPath?: { pathD?: string; startOffset?: PxAnimatable<number>; textLength?: PxAnimatable<number>; pathOverflow?: string } },\n): E | null {\n if (opts.alongPath) return materializeGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);\n return materializeGlyphTextHorizontal(node, opts);\n}\n\n/** Pipeline adapter (plain wire nodes) — `effects.text.useGlyphs`, horizontal. */\nexport function applyTextGlyphsEffect(node: PxNode, fx: PxTextEffect | undefined, ctx: ApplyContext): PxNode {\n if (!fx?.useGlyphs) return node;\n if (!ctx.glyphs) { ctx.warnings.push('textGlyphs: no definitions.fonts — left as native <text>'); return node; }\n return materializeGlyphTextHorizontal<PxNode>(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });\n}\n\n/** Pipeline adapter (plain wire nodes) — glyph text along a referenced path. */\nexport function applyTextGlyphsAlongPath(node: PxNode, ctx: ApplyContext, pathD: string | undefined, startOffset: PxAnimatable<number> | undefined, textLength?: PxAnimatable<number>, pathOverflow?: string): PxNode | null {\n if (!ctx.glyphs) { ctx.warnings.push('textGlyphs: no definitions.fonts'); return null; }\n return materializeGlyphTextAlongPath<PxNode>(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n// ONE diagnostics channel for every player (API review §5, §25.1).\n//\n// Before this, only React Native had an error channel (`onError` + `fallback`). The web player\n// sent a failed fetch or an invalid document to `console.error` and then answered\n// `isReady() === false` for ever, and React and Vue could not offer anything at all because\n// the engine callbacks had no slot for it. Everything else — validation warnings, config\n// overrides, unsupported attributes — went straight to `console.warn`, where an embedding app\n// could neither see it nor quiet it.\n//\n// THE RULE — two severities, one meaning each, on every player:\n//\n// - `onError`: THIS INSTANCE WILL NOT PLAY. Nothing is rendered, `isReady()` stays false,\n// the component shows its `fallback`. The player reports it and stays inert rather than\n// throwing at the caller — a throw would land in a fetch callback or a render, where no\n// one can catch it. (A wrong CALL — `createAnimator()` with neither `src` nor `doc` — still\n// throws: that is a bug at the call site, found the moment the line runs.)\n// - `onWarn`: IT PLAYS, but something was ignored, degraded or misspelled — an unknown\n// easing, an override that could not apply, an attribute the platform will not animate.\n//\n// - a handler takes over from the console: give `onWarn` / `onError` and the console stays\n// out of it; give none and the console is the fallback, so nothing is lost by default;\n// - `muteWarn` / `muteError` switch that console fallback off — for a host that knows\n// about the warnings and is prepared to tolerate them. A handler you passed still fires.\n//\n// Severity (warn vs error) and SOURCE (`kind`) are separate axes on purpose: `invalid animation\n// document format` is a document problem AND fatal, while an effects-shape warning is a document\n// problem that still plays. Splitting the callbacks by source would have produced four handlers\n// and forced anyone who just wants everything to wire all of them.\n\n/**\n * Who can do something about a diagnostic.\n *\n * A const object rather than a TypeScript `enum`: consumers compare against these values, so\n * they must accept plain string literals too (the same pattern as `PxControlMode`).\n * @public\n */\nexport const PxDiagnosticKind = {\n /** The document is wrong — regenerate or repair the file. */\n document: 'document',\n /** The page or app cannot provide what the document asks for — fix the mount. */\n host: 'host',\n /** The platform cannot do it and the player degraded — usually nothing to fix. */\n platform: 'platform',\n /** The call is wrong or self-contradictory — fix the options or props you passed. */\n usage: 'usage',\n /** The player failed where it did not expect to — report it to us. */\n internal: 'internal',\n} as const;\nexport type PxDiagnosticKind = typeof PxDiagnosticKind[keyof typeof PxDiagnosticKind];\n\n/** One thing a player has to say. @public */\nexport interface PxDiagnostic {\n /** Who can act on it — see {@link PxDiagnosticKind}. */\n readonly kind: PxDiagnosticKind;\n /** Human-readable, and never carries the console prefix. */\n readonly message: string;\n /**\n * Whatever the site had to hand: the offending binding, the element map, the raw error —\n * or, for a React Native render failure, `{ componentStack }`.\n */\n readonly detail?: unknown;\n /** Present on errors: the Error that stopped the player. Its message is `message`. */\n readonly error?: Error;\n}\n\n/**\n * Where a player sends what it wants to say. Every field is optional.\n *\n * The SHARED base of every callbacks object (dev-docs/reviews/api-surface-review.md §26.1): `createDiagnostics` reads it directly,\n * `PxEngineCallbacks` extends it with the playback lifecycle, `PxAnimatorCallbacks` adds `onStop`\n * on top — so the four diagnostics fields are spelled once, here.\n * @public\n */\nexport interface PxDiagnosticsConfig {\n\n /**\n * IT PLAYS, but something was ignored, degraded or misspelled — an unknown easing, an\n * override that could not apply, an attribute the platform will not animate. Each\n * diagnostic says WHO can act on it via `kind` (`document` / `host` / `platform` / `usage` /\n * `internal`). Without this: `console.warn`.\n */\n onWarn?: (diagnostic: PxDiagnostic) => void;\n\n /**\n * THIS INSTANCE WILL NOT PLAY — the document failed to load, parse or build, or the render\n * threw: nothing rendered, `isReady()` false, the component's `fallback` shown. The player\n * stays inert rather than throwing at the caller. `diagnostic.error` is the Error; on React\n * Native `diagnostic.detail` carries `{ componentStack }` when the error boundary caught it.\n * Without this: `console.error`.\n */\n onError?: (diagnostic: PxDiagnostic) => void;\n\n /**\n * Switch the `console.warn` fallback off. For a host that knows the player has something\n * to say about this document and is prepared to tolerate it — a chatty player is not what\n * an end user's console is for. A handler you passed (`onWarn`) still fires: mute is\n * about the console, not about you.\n */\n muteWarn?: boolean;\n\n /** The same switch for the `console.error` fallback. `onError` still fires. */\n muteError?: boolean;\n}\n\n/** The reporting channel a player writes to. @public */\nexport interface PxDiagnostics {\n /** Report something survivable — it plays. */\n warn(kind: PxDiagnosticKind, message: string, detail?: unknown): void;\n /** Report a failure that stopped this instance — it will not play. */\n error(kind: PxDiagnosticKind, error: Error | string, detail?: unknown): void;\n}\n\n/** Anything not already an Error becomes one, so handlers get a single shape. */\nfunction asError(error: Error | string): Error {\n return typeof error === 'string' ? new Error(error) : error;\n}\n\n/**\n * Builds the channel a player reports through.\n *\n * `prefix` labels the console fallback (e.g. `'[PixodeskSvgAnimator]'`) and is NOT added to the\n * diagnostic handed to a handler — a caller that wants to prefix its own log can, and one\n * feeding a UI should not have to strip ours.\n * @internal\n */\nexport function createDiagnostics(config?: PxDiagnosticsConfig, prefix?: string): PxDiagnostics {\n const tag = prefix ? prefix + ' ' : '';\n return {\n warn: (kind: PxDiagnosticKind, message: string, detail?: unknown): void => {\n if (config?.onWarn) { config.onWarn({ kind, message, detail }); return; }\n if (config?.muteWarn) return;\n const line = tag + kind + ': ' + message;\n if (detail === undefined) console.warn(line);\n else console.warn(line, detail);\n },\n error: (kind: PxDiagnosticKind, error: Error | string, detail?: unknown): void => {\n const err = asError(error);\n if (config?.onError) { config.onError({ kind, message: err.message, error: err, detail }); return; }\n if (config?.muteError) return;\n const line = tag + kind + ': ' + err.message;\n if (detail === undefined) console.error(line);\n else console.error(line, detail);\n },\n };\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * THE ENTRY DIAGNOSTIC — how a consumer whose build renamed our keys finds out.\n *\n * Property mangling across the document boundary fails SILENTLY: the keys no longer match, the\n * player reads an empty configuration rather than an invalid one, and the animation renders a\n * blank canvas with nothing in the console. That is the failure this exists to name.\n *\n * It is a DIAGNOSTIC, not a gate. Nothing is rejected — the player still does its best with\n * whatever it can read, exactly as before.\n *\n * What it can and cannot see (dev-docs/plans/minification-boundary.md §3):\n * - keyframes, the animator block and every effect are strict `px.object`, so an unexpected\n * key there IS detectable;\n * - nodes are `px.openObject`, so an unknown attribute on a node is indistinguishable from a\n * legitimate SVG attribute. The diagnostic therefore keys off the strict parts.\n */\nimport { validateDocument } from './PxAnimatorTypes';\n\n/** How many problems to print before summarizing the rest. A wall of text gets scrolled past. */\nconst MAX_REPORTED = 6;\n\n/**\n * A document's schema findings. The pre-2026-09 FLAT animator spelling is NOT a category of its\n * own: those keys are no longer read (`getAnimatorConfig` drops them), so a document still\n * carrying them is reported like any other unrecognized key — silence would hide a file that\n * plays with its playback settings ignored.\n * @public @advanced\n */\nexport interface PxDocumentDiagnosis {\n /** Findings worth showing — unrecognized keys and shape violations. */\n problems: Array<string>;\n}\n\n/** Pure: collect a document's schema findings. Never throws. @public @advanced */\nexport function diagnoseDocument(doc: unknown): PxDocumentDiagnosis {\n try {\n return { problems: validateDocument(doc) };\n } catch {\n return { problems: [] }; // a diagnostic must never be the thing that breaks\n }\n}\n\n/**\n * Runs the diagnosis and reports it on the console, naming property mangling as the likely cause\n * — a bare \"unexpected extra key\" leaves the reader no wiser, which is the whole point.\n *\n * `where` names the entry the document came in through, so the message says which call to look at.\n * @internal\n */\nexport function reportDocumentDiagnostics(doc: unknown, where: string): void {\n const { problems } = diagnoseDocument(doc);\n if (!problems.length) return;\n\n const shown = problems.slice(0, MAX_REPORTED);\n const more = problems.length - shown.length;\n console.warn(\n where + ': this document does not match the animation schema in '\n + problems.length + ' place' + (problems.length === 1 ? '' : 's') + '.\\n'\n + shown.map(p => ' - ' + p).join('\\n')\n + (more > 0 ? '\\n … and ' + more + ' more' : '')\n + '\\n\\nIf you did not author these keys, the usual cause is a build that MANGLES PROPERTY '\n + 'NAMES. An animation document is data loaded at runtime, so renaming the property reads '\n + 'inside the player stops them matching the keys in the JSON, and the animation silently '\n + 'does nothing. Feed the published reserved-name list to your minifier — '\n + '@pixodesk/svg-animator-web/mangle-reserved.json — see docs/library/minification.md.');\n}\n"],"mappings":"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","names":["_a","PxWireVersionRelation","PxWireStepKind","_a","timeline","_a","_a","_a","_a","str","str","_a","str","pathStr","_a","out","_a","clamp","_a","genId","_a","_a","_a","str","_a","_b","_c"]}
|