@pixodesk/svg-animator-web 1.0.21 → 1.0.24
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 +3 -3
- package/dist/index.cjs +615 -412
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -3
- package/dist/index.d.ts +16 -3
- package/dist/index.js +613 -411
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.prerendered-waapi.umd.js +1687 -0
- package/dist/index.prerendered-waapi.umd.js.map +1 -0
- package/dist/index.prerendered-waapi.umd.min.js +1 -0
- package/dist/index.prerendered.umd.js +2200 -0
- package/dist/index.prerendered.umd.js.map +1 -0
- package/dist/index.prerendered.umd.min.js +1 -0
- package/dist/index.umd.js +756 -976
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +17 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.prerendered-waapi.ts","../../svg-animator-core/src/PxAnimatorConstants.ts","../../svg-animator-core/src/PxAnimatorUtil.ts","../../svg-animator-core/src/PxMotionPath.ts","../../svg-animator-core/src/PxDefinitions.ts","../src/PxAnimatorTriggers.ts","../src/PxAnimatorFrameLoop.ts","../src/PxAnimatorWebApi.ts","../src/PxAnimatorBind.ts","../src/PxAnimatorKeys.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// UMD entry for PRE-RENDERED SVG — WAAPI only. The smallest build.\n//\n// Inlined by the Editor into SVG+JS exports whose animator mode is `waapi`. On top of\n// what `index.prerendered.ts` drops, this also excludes the frame-loop engine: waapi is\n// forced, so there is no fallback path to link against (`createWebApiAnimator` never\n// returns null when forced — it only warns about unsupported attrs).\n//\n// Exported AS `createAnimator` so the emitted `<script>` is identical across bundles.\n// See PRERENDERED-PLAYER-BUILDS.md.\n// ============================================================================\n\nexport { createPrerenderedWaapiAnimator as createAnimator } from './PxAnimatorBind';\nexport { PX_ANIMATOR_DATA_KEY } from './PxAnimatorKeys';\n\nexport { setupAnimationTriggers } from './PxAnimatorTriggers';\n\nexport type { PxPrerenderedOptions } from './PxAnimatorBind';\nexport type { PxAnimatorAPI, PxBasicAnimatorAPI } from './PxAnimatorWebTypes';\nexport type { PxAnimatedSvgDocument, PxAnimatorCallbacksConfig } from '@pixodesk/svg-animator-core';\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 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, PxDefs, PxNode } from './PxAnimatorTypes';\n\nexport type FillMode = 'forwards' | 'backwards' | 'both' | 'none';\n\nexport type PlaybackDirection = 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';\n\nexport const PX_ANIM_SRC_ATTR_NAME = 'data-px-animation-src';\n\nexport const PX_ANIM_ATTR_NAME = '_px_animator';\n\nexport type StartOn = 'load' | 'mouseOver' | 'click' | 'scrollIntoView';\n\nexport type OutAction = 'continue' | 'pause' | 'reset' | 'reverse';\n\n/** Animation engine selection (config level). `auto` means \"try `waapi`, fall\n * back to `frames`\"; the runtime resolves it to a concrete {@link PxAnimatorEngine}\n * via `createAnimatorFromConfig`. Wire as a const-namespace + matching string\n * type so call sites can use named members (`PxAnimatorMode.frames`) instead of\n * bare string literals. */\nexport const PxAnimatorMode = {\n auto: 'auto',\n waapi: 'waapi',\n frames: 'frames',\n} as const;\n\nexport type PxAnimatorMode = typeof PxAnimatorMode[keyof typeof PxAnimatorMode];\n\n/** Resolved engine after `auto` dispatch — used downstream by code that always\n * knows exactly which engine is running (e.g. `getNormalisedBindings`'s\n * `engine` arg gates motion-along-path materialisation). Strictly a subset of\n * {@link PxAnimatorMode} (no `auto`). */\nexport const PxAnimatorEngine = {\n waapi: PxAnimatorMode.waapi,\n frames: PxAnimatorMode.frames,\n} as const;\n\nexport type PxAnimatorEngine = typeof PxAnimatorEngine[keyof typeof PxAnimatorEngine];\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, `debugInstName`).\n\n/** `loop.extend` — WHICH END of the keyframe sequence the loop segment is taken from,\n * and therefore which side the animation is extended on. Replaced the boolean\n * `before` (N8): a bare preposition named no subject (\"before what?\"), and a\n * two-way selector reads better as a named enum — which also leaves room for a\n * third value (e.g. both ends) that a boolean forecloses. */\nexport const PxLoopExtend = {\n /** Segment from the START; the animation is extended BEFORE the first keyframe\n * (intro loops that run before the main timeline begins). */\n before: 'before',\n /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro\n * loops that continue once the main timeline has finished). */\n after: 'after',\n} as const;\n\nexport type PxLoopExtend = typeof PxLoopExtend[keyof typeof PxLoopExtend];\n\n/** SVG `mask-type` — how the mask source's pixels become alpha. */\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). */\nexport const PxUnits = {\n userSpaceOnUse: 'userSpaceOnUse',\n objectBoundingBox: 'objectBoundingBox',\n} as const;\n\nexport type PxUnits = typeof PxUnits[keyof typeof PxUnits];\n\n/** `clone.type` — WHAT a `<use>` clones. Absent = the whole element (a direct link);\n * `content` excludes the target's own translate (see `contentRefSplit`). */\nexport const PxCloneType = {\n content: 'content',\n} as const;\n\nexport type PxCloneType = typeof PxCloneType[keyof typeof PxCloneType];\n\n/** `textPath.pathOverflow` — glyphs past the path end: hide them, or keep laying\n * them along the tangent extension. */\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. */\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. */\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. */\nexport const PxTextPathSpacing = {\n auto: 'auto',\n exact: 'exact',\n} as const;\n\nexport type PxTextPathSpacing = typeof PxTextPathSpacing[keyof typeof PxTextPathSpacing];\n\n/** `trimPath.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\"). */\nexport const PxTrimSubPaths = {\n separate: 'separate',\n combined: 'combined',\n} as const;\n\nexport type PxTrimSubPaths = typeof PxTrimSubPaths[keyof typeof PxTrimSubPaths];\n\n/** @deprecated Backwards-compatibility alias — use {@link PxAnimatorMode} for the type. */\nexport type JsMode = PxAnimatorMode;\n\n// S8: `textContent` is the CANONICAL text-content key (DOM property name;\n// `text` was triply overloaded: the `text` tag, the `effects.text` group, and\n// this key). `text` is READ-ONLY legacy — readers accept both, writers emit\n// only `textContent`.\nexport const TEXT_ATTR = 'text';\n\nexport const TEXT_CONTENT_ATTR = 'textContent';\n\n// Wire keys that are NEVER DOM attributes (internal use only).\n//\n// `effects` is here for safety rather than necessity: `applyPlayerEffects` 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 recognise, 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).\nexport const INTERNAL_ATTRS = new Set([\n 'type', 'children', 'animator', 'meta', 'animate', 'effects', TEXT_ATTR, 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 */\nexport const PX_TRANSFORM_PART_KEYS = ['translate', 'rotate', 'scale', 'origin'] as const;\n\n/** One of the transform-part key strings. */\nexport type PxTransformPartKey = typeof PX_TRANSFORM_PART_KEYS[number];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Gradient paint effect — `fillGradient` / `strokeGradient`.\n//\n// Materialiser pattern mirrors `maskedByEffect`: at apply time the gradient\n// effect mints 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-colour 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 `gradientUnits` / `spreadMethod` — 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. */\nexport const PxGradientUnits = {\n userSpaceOnUse: 'userSpaceOnUse',\n objectBoundingBox: 'objectBoundingBox',\n} as const;\n\nexport type PxGradientUnits = typeof PxGradientUnits[keyof typeof PxGradientUnits];\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\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\nexport function isPxElementFileFormat(fileJson: any): fileJson is PxAnimatedSvgDocument {\n if (!(\n fileJson &&\n typeof fileJson === 'object' &&\n !Array.isArray(fileJson)\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 // `isPxElementFileFormatDeep`; nothing ever wrote it.\n return fileJson['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 */\nexport function getAnimatorConfig(doc: PxAnimatedSvgDocument): PxAnimatorConfig | undefined {\n return doc?.animator || doc?.meta?.animator;\n}\n\n\nexport function getDefs(doc: PxAnimatedSvgDocument): PxDefs | undefined {\n if (!doc) return undefined;\n return getAnimatorConfig(doc)?.definitions;\n}\n\nexport function getBindings(doc: PxAnimatedSvgDocument): PxBinding[] | undefined {\n if (!doc) return undefined;\n const animateById = getAnimatorConfig(doc)?.animateById;\n if (!animateById) return undefined;\n return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));\n}\n\n\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 { PxBezierPath, PxTransformParts } from './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 */\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 */\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 */\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 */\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 */\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 */\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 */\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 normalisation 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\nexport const COLOUR_ATTR_NAMES = new Set([\"color\", \"fill\", \"flood-color\", \"lighting-color\", \"stop-color\", \"stroke\"]);\nexport const TRANSFORM_FN_NAMES = new Set([\"translate\", \"rotate\", \"scale\", \"skew\"]);\nexport const 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 */\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}\nexport const STYLE_ATTR_NAMES = new Set([\"offset-distance\", \"offsetDistance\"]); // Props that need to go to style\nexport const DEFAULT_DURATION_MS = 1000;\n\n/**\n * Converts a kebab-case string to camelCase.\n * @param kebab The kebab-case string.\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 */\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 */\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 normalisation 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\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 './PxAnimatorUtil';\nimport type { ArcLengthLUT } from './PxAnimatorUtil';\nimport type { PxKeyframe, PxNode, PxPropertyAnimation, PxTransformParts } from './PxAnimatorTypes';\n\n\ntype Point2 = [number, number];\ntype Easing = [number, number, number, number];\n\n\nfunction getKfTranslate(kf: PxKeyframe): Point2 | undefined {\n const v = kf.value ?? kf.v;\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: PxKeyframe): number {\n return (kf.time ?? kf.t ?? 0) as number;\n}\n\nfunction getKfEasing(kf: PxKeyframe): Easing | undefined {\n return (kf.easing ?? kf.e) 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 */\nexport function propAnimIsMotionPath(anim: PxPropertyAnimation): boolean {\n const kfs: Array<PxKeyframe> | undefined = anim.keyframes ?? anim.kfs;\n if (!Array.isArray(kfs)) return false;\n if (anim.autoOrient) return true;\n for (const kf of kfs) {\n if ((kf.tangentIn ?? kf.ti) || (kf.tangentOut ?? kf.to)) return true;\n }\n return false;\n}\n\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Segment cache — shared by `evaluateMotionPathSegment` (frames-mode kernel)\n// and the materialiser. 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<PxKeyframe, WeakMap<PxKeyframe, MotionPathSegmentCache>>();\n\nfunction getSegmentCache(\n prevKf: PxKeyframe,\n nextKf: PxKeyframe,\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 = prevKf.tangentOut ?? prevKf.to;\n const ti = nextKf.tangentIn ?? nextKf.ti;\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<PxKeyframe, 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// materialised at `getNormalisedBindings` time), but it's a useful primitive\n// on its own.\n// ─────────────────────────────────────────────────────────────────────────────\n\n\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 */\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 — materialise parametric motion-path into plain transform kfs\n// ─────────────────────────────────────────────────────────────────────────────\n\n\n/** Sampling configuration shared by `materialiseMotionPathInPropAnim` + `materialiseMotionPathsInTree`. */\nexport interface MotionPathMaterialisationOptions {\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 */\nexport function materialiseMotionPathInPropAnim(\n anim: PxPropertyAnimation,\n opts?: MotionPathMaterialisationOptions,\n): PxPropertyAnimation {\n if (!propAnimIsMotionPath(anim)) return anim;\n const kfs = (anim.keyframes ?? anim.kfs) as Array<PxKeyframe> | 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<PxKeyframe> = [];\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 materialiseSegment(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 const result: PxPropertyAnimation = { kfs: out } as PxPropertyAnimation;\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<PxKeyframe>): void {\n let prev: number | undefined;\n for (const kf of kfs) {\n const v = (kf.v ?? kf.value) 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): PxKeyframe {\n return { t: time, v: value } as PxKeyframe;\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: PxKeyframe): PxTransformParts | undefined {\n const v = kf.value ?? kf.v;\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 / Vec2). 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: PxKeyframe, kf1: PxKeyframe): 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 `materialiseSegment` 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 `materialiseSegment` 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<PxKeyframe>,\n prevKf: PxKeyframe, nextKf: PxKeyframe,\n prevPos: Point2, nextPos: Point2,\n rotationTol: number,\n): void {\n const lastKf = out[out.length - 1];\n const lastV = (lastKf.v ?? lastKf.value) 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/** Materialises 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 materialiseSegment(\n out: Array<PxKeyframe>,\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 `materialiseMotionPathInPropAnim` 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\nexport function materialiseMotionPathsInTree(\n root: PxNode,\n opts?: MotionPathMaterialisationOptions,\n): PxNode {\n const out = walkAndMaterialise(root, opts);\n return out ?? root;\n}\n\nfunction walkAndMaterialise(node: PxNode, opts?: MotionPathMaterialisationOptions): 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 = walkAndMaterialise(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 materialised = materialiseMotionPathInPropAnim(transformAnim, opts);\n if (materialised !== transformAnim) {\n newAnimate = { ...animDef, transform: materialised };\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 PxBinding, type PxDefs, type PxElementAnimation, type PxKeyframe, type PxLoop, type PxNode, type PxPropertyAnimation, type PxTransformParts } from './PxAnimatorTypes';\nimport { getBindings, getDefs } from './PxAnimatorConstants';\nimport { getAnimatorConfig, PxAnimatorEngine, PxLoopExtend } from './PxAnimatorConstants';\nimport { bezierToSvgPath, camelCaseToKebabWordIfNeeded, clamp, COLOUR_ATTR_NAMES, composeTransformParts, cubicBezier, interpolateBeziers, interpolateColor, interpolateNum, interpolateVec, isCamelCaseWord, parseColor, PCT_BASED_ATTR_NAMES, remap, reverseEasing, splitEasing, toRGBA, TRANSFORM_FN_NAMES } from './PxAnimatorUtil';\nimport { evaluateMotionPathSegment, materialiseMotionPathInPropAnim, propAnimIsMotionPath } from './PxMotionPath';\n\n/**\n * Time separation between a cycle's snap-back keyframe and the previous repetition's\n * end, in ms. Matches the editor's `TLoop.smallFrameShift` — ONE 10ms editor frame —\n * so both sides materialise the same keyframes (B7). Do not shrink below a frame\n * without fixing the editor first: a fractional shift was tried there and reverted\n * because `TKeyframeGroup` mishandles fractional-frame keyframes.\n */\nconst LOOP_JUMP_SHIFT_MS = 10;\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 * - { path: \"M...\" } / { path: \"path(...)\" } -> { paths: [PxBezierPath] } (unified single-string 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 // Unified single-string form: { path: \"M...\" } (compound = multiple `M…` sub-paths in one string).\n if (value && typeof value === 'object' && typeof value.path === 'string') {\n const d = extractPathData(value.path);\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?: PxDefs\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?: PxDefs\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?: PxDefs\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 */\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 (COLOUR_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 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 (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: PxKeyframe[],\n loop: PxLoop,\n duration: number\n): PxKeyframe[] {\n const totalIntervals = keyframes.length - 1;\n const segCount = clamp(loop.segmentCount ?? totalIntervals, 1, totalIntervals);\n\n // Extract segment keyframes\n let segKfs: PxKeyframe[];\n if (loop.extend === PxLoopExtend.before) {\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.extend === PxLoopExtend.before) {\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: (kf.tangentIn ?? kf.ti) as [number, number] | undefined,\n tangentOut: (kf.tangentOut ?? kf.to) 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: PxKeyframe[] = [];\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 LOOP_JUMP_SHIFT_MS.\n // The editor's shift is one 10ms frame (`smallFrameShift`), so the two sides\n // materialise 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.extend !== PxLoopExtend.before;\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: PxKeyframe | undefined = keyframes[keyframes.length - 1];\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)) continue; // pingpong turn — nothing to say\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: PxKeyframe = {\n t: repStart + entry.relT * segDuration + (isBoundary ? 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: PxKeyframe = {\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.extend === PxLoopExtend.before) {\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.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.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.alternate && (rep % 2 === 0);\n const repStart = fillStart + rep * segDuration;\n appendRep(repStart, isReversed);\n }\n if (partialFraction > 1e-9) {\n const isReversed = !!loop.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.extend === PxLoopExtend.before) {\n return [...looped, ...keyframes];\n } else {\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?: PxDefs\n): PxKeyframe[] {\n const keyframes = propAnim.keyframes || propAnim.kfs || [];\n\n const normalized: PxKeyframe[] = [];\n\n for (const kf of keyframes) {\n const timePct = kf.time ?? kf.t ?? 0;\n let value = kf.value ?? kf.v;\n const easing = kf.easing ?? kf.e;\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 // `COLOUR_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 (COLOUR_ATTR_NAMES.has(propNameKebab)) {\n value = parseColor(value) ?? value;\n }\n\n const normKf: PxKeyframe = {\n t: timePct,\n v: value,\n e: resolveEasing(easing, defs)\n };\n // Motion-along-path: keep the spatial tangents so the downstream\n // `materialiseMotionPathInPropAnim` (called in `normalizeAnimationDefinition`) can\n // sample them into transform kfs. Short aliases `ti` / `to` collapse\n // into their canonical names.\n const tIn = kf.tangentIn ?? kf.ti;\n const tOut = kf.tangentOut ?? kf.to;\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-materialisation API\n//\n// Used internally by `normalizeKeyframes` (where `expandLoopKeyframes` is\n// already called at the tail of normalisation). Exposed here at the propAnim\n// and tree levels so the Editor (or any external caller) can compose:\n// root = applyPlayerEffects(root).root;\n// root = materialiseInternalLoopsInTree(root, duration);\n// root = materialiseMotionPathsInTree(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 */\nexport function materialiseInternalLoopsInPropAnim(\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 ?? propAnim.kfs) 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 materialisation pipeline OUTSIDE the\n // binding-normalisation path (e.g. by `materialiseAllInTree`), the input\n // kfs may still be in long form (`time` / `value` / `easing`) AND the\n // values may be unparsed (hex colour strings, raw path-`d`). Normalise\n // both here so `interpolateValue` (called by `expandLoopKeyframes` at the\n // loop seam) sees structured data — without this, a colour 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 isColour = COLOUR_ATTR_NAMES.has(propNameKebab);\n const kfs: PxKeyframe[] = rawKfs.map(kf => {\n const t = kf.t ?? kf.time;\n let v: unknown = kf.v ?? kf.value;\n if (propName === 'd') v = normalizePathValue(v);\n if (isColour) v = parseColor(v) ?? v;\n const e = kf.e ?? kf.easing;\n const out: PxKeyframe = { t, v, e } as PxKeyframe;\n if (kf.tangentIn ?? kf.ti) out.tangentIn = (kf.tangentIn ?? kf.ti) as [number, number];\n if (kf.tangentOut ?? kf.to) out.tangentOut = (kf.tangentOut ?? kf.to) as [number, number];\n return out;\n });\n\n const expanded = expandLoopKeyframes(propName, kfs, loop, duration);\n const out: PxPropertyAnimation = { kfs: expanded } as PxPropertyAnimation;\n if (propAnim.autoOrient !== undefined) (out as { autoOrient?: unknown }).autoOrient = propAnim.autoOrient;\n return out;\n}\n\n\n/**\n * Walks `root` and materialises every animated property's `loop` via\n * `materialiseInternalLoopsInPropAnim`. 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 */\nexport function materialiseInternalLoopsInTree(\n root: PxNode,\n duration: number,\n): PxNode {\n const ret = walkAndMaterialiseLoops(root, duration);\n return ret ?? root;\n}\n\nfunction walkAndMaterialiseLoops(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 = walkAndMaterialiseLoops(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 materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);\n if (materialised !== propAnim) {\n if (!newAnimate) newAnimate = { ...animDef };\n newAnimate[propName] = materialised;\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 * 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 PxAnimatorEngine}.\n */\nfunction normalizeAnimationDefinition(\n animDef: PxAnimationDefinition,\n duration: number,\n defs?: PxDefs,\n engine: PxAnimatorEngine = PxAnimatorEngine.waapi,\n): PxAnimationDefinition {\n const normalized: PxAnimationDefinition = {};\n\n for (const [propName, propAnim] of Object.entries(animDef)) {\n const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);\n if (normalizedKfs.length > 0) {\n const out: PxPropertyAnimation = { kfs: normalizedKfs };\n // Carry top-level animation flags through normalization — `materialiseMotionPathInPropAnim`\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, materialise 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 // `materialiseMotionPathInPropAnim` is a no-op for non-motion-path\n // animations, so non-transform props pay zero cost.\n normalized[propName] = (engine === PxAnimatorEngine.waapi && propName === 'transform')\n ? materialiseMotionPathInPropAnim(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 PxAnimatorEngine}.\n */\nexport function getNormalisedBindings(\n doc: PxAnimatedSvgDocument,\n engine: PxAnimatorEngine = PxAnimatorEngine.waapi,\n): PxBinding[] {\n const animatorConfig = getAnimatorConfig(doc) || {};\n const defs = getDefs(doc);\n const duration = animatorConfig.duration || 1000; // FIXME - get rid of 1000 here\n\n const bindings: PxBinding[] = [];\n\n // Helper to resolve and normalize animation for a binding\n const processAnimation = (\n id: string,\n animate: PxElementAnimation | undefined\n ): PxBinding | null => {\n if (!animate) return null;\n\n const animDefs = resolveElementAnimation(animate, defs);\n if (animDefs.length === 0) return null;\n\n const merged = mergeAnimationDefinitions(animDefs);\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)\n const docBindings = getBindings(doc);\n if (docBindings) {\n for (const binding of docBindings) {\n const normalized = processAnimation(binding.id, binding.animate);\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, inlineAnim);\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: PxKeyframe[], 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.kfs || 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 = prevKf.e ?? prevKf.easing; // 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 ?? prevKf?.value;\n const nextV = nextKf?.v ?? nextKf?.value;\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 (COLOUR_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 materialises 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-materialised 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 (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 */\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\nimport type { PxTrigger } from '@pixodesk/svg-animator-core';\nimport type { PxAnimatorAPI } from './PxAnimatorWebTypes';\n\n\n/**\n * Sets up event-based triggers for an animation.\n *\n * This function attaches event listeners to the animation's root element based on the\n * provided configuration, allowing animations to be started by user interactions\n * or visibility changes.\n *\n * ### Trigger Options (startOn):\n * - 'load': Starts after the page loads.\n * - 'mouseOver': Starts on mouse enter.\n * - 'click': Toggles play/end action on click.\n * - 'scrollIntoView': Starts when the element scrolls into the viewport.\n * - 'programmatic': No automatic start. Must be controlled via the API.\n *\n * ### End Action Options (outAction):\n * Defines behavior when the trigger condition ends (e.g., mouse leave).\n * - 'continue': Animation continues playing.\n * - 'pause': Pauses the animation.\n * - 'reset': Cancels the animation, resetting it to the start.\n * - 'reverse': Reverses the animation playback.\n *\n * @param {!PxAnimatorAPI} api The animator API instance to control.\n * @param {!PxTrigger} config The trigger configuration object.\n * @returns {!PxAnimatorAPI} The same animator API instance, for chaining.\n */\nexport function setupAnimationTriggers(\n api: PxAnimatorAPI,\n config: PxTrigger\n): PxAnimatorAPI {\n // Threshold default 0 — \"any pixel visible starts it\". Keep in sync with the editor\n // model's default (TSvgSvgAnimationAttr.scrollIntoViewThreshold), which OMITS the\n // value on the wire when it equals this default.\n const { startOn, outAction = 'continue', scrollIntoViewThreshold = 0 } = config;\n\n const root = api.getRootElement();\n\n if (!root) {\n console.warn('setupAnimationTriggers: No root element found for animation.');\n return api;\n }\n\n // Tracks whether the LAST out-action put the animation into reverse, so the\n // next trigger start can restore forward playback without clobbering a\n // custom playback rate the user may have set through the API.\n let reversed = false;\n\n /** Ensures forward playback and starts or resumes the animation. */\n const start = () => {\n if (reversed) {\n reversed = false;\n api.setPlaybackRate(1);\n }\n api.play();\n };\n\n /** Handles what to do when the element leaves the active trigger condition. */\n const handleEndAction = () => {\n switch (outAction) {\n case 'pause':\n api.pause();\n break;\n case 'reset':\n api.cancel();\n break;\n case 'reverse':\n // Play the animation backwards from its current position.\n reversed = true;\n api.setPlaybackRate(-1);\n api.play();\n break;\n case 'continue':\n default:\n // Do nothing\n break;\n }\n };\n\n // ---- Setup event-based start logic ----\n switch (startOn) {\n case 'load': {\n const startHandler = () => start();\n if (document.readyState === 'complete') {\n startHandler();\n } else {\n window.addEventListener('load', startHandler, { once: true });\n }\n break;\n }\n\n case 'mouseOver': {\n // An OUT may only follow an IN. A `mouseleave` with no preceding `mouseenter` happens\n // when the pointer is already over the element at load and then moves away — and for\n // `outAction: 'reverse'` the out action PLAYS (`setPlaybackRate(-1); play()`), so an\n // untriggered leave would start the animation running backwards. Same class of bug as\n // the scrollIntoView initial-intersection case handled below.\n let enteredOnce = false;\n const mouseOverHandler = () => { enteredOnce = true; start(); };\n const mouseOutHandler = () => { if (enteredOnce) handleEndAction(); };\n\n root.addEventListener('mouseenter', mouseOverHandler);\n root.addEventListener('mouseleave', mouseOutHandler);\n break;\n }\n\n case 'click': {\n const clickHandler = () => {\n if (api.isPlaying()) {\n handleEndAction();\n } else {\n start();\n }\n };\n root.addEventListener('click', clickHandler);\n break;\n }\n\n case 'scrollIntoView': {\n // `observe()` delivers an INITIAL entry describing the CURRENT state, which is how an\n // element that is already on screen starts without any scrolling. But that same initial\n // entry also reports \"not intersecting\" for an element merely below the fold — and\n // treating that as an out-action ran it before anything had ever played. For `reverse`\n // that meant `setPlaybackRate(-1)` + `play()`, i.e. the animation started running\n // BACKWARDS on page load. An OUT is only meaningful after an IN, so require one.\n // A target TALLER than the viewport can never reach a high ratio (ratio is measured\n // against the TARGET's own size), so a 0.5/0.9 threshold would be unsatisfiable and the\n // animation would never play. Normalise by what could possibly be visible, and register\n // a granular threshold list — registering the raw threshold would mean the callback\n // never fires at all for such a target.\n const effectiveRatio = (entry: IntersectionObserverEntry): number => {\n const target = entry.boundingClientRect;\n const visible = entry.intersectionRect;\n // Simplified entries (tests, older engines) may omit the rects — fall back to the\n // browser's own ratio rather than inventing one.\n if (!target?.height || !visible) return entry.intersectionRatio;\n // Use the SMALLER of `rootBounds` and the live viewport. `rootBounds` can be null\n // (implicit root in some embeddings) and can also report a box LARGER than the\n // actual viewport — trusting it then reinstates the very cap this normalisation\n // exists to remove. `intersectionRect` is already clipped to the real viewport, so\n // the denominator must be too.\n const live = typeof window !== 'undefined' && window.innerHeight ? window.innerHeight : Infinity;\n const declared = entry.rootBounds?.height ?? Infinity;\n const viewport = Math.min(live, declared);\n const denom = Math.min(target.height, Number.isFinite(viewport) ? viewport : target.height);\n return denom > 0 ? visible.height / denom : entry.intersectionRatio;\n };\n const thresholdSteps = Array.from({ length: 21 }, (_, i) => i / 20);\n let wasIntersecting = false;\n const observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n // If the element is at least partially visible\n if (entry.isIntersecting && effectiveRatio(entry) >= scrollIntoViewThreshold) {\n wasIntersecting = true;\n start();\n } else if (wasIntersecting) {\n // Element scrolled OFF screen after having been on it -> out action\n wasIntersecting = false;\n handleEndAction();\n }\n });\n },\n { threshold: thresholdSteps }\n );\n observer.observe(root);\n break;\n }\n\n case 'programmatic':\n // No auto-start; external code must call play()\n break;\n }\n\n return api;\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 { camelCaseToKebabWordIfNeeded, createBasicFrameLoopAnimator, getAnimatorConfig, STYLE_ATTR_NAMES, type PxAnimatedSvgDocument, type PxAnimatorCallbacksConfig, type PxPlatformAdapter } from '@pixodesk/svg-animator-core';\nimport { setupAnimationTriggers } from './PxAnimatorTriggers';\nimport type { PxAnimatorAPI } from './PxAnimatorWebTypes';\n\n// Re-export the platform-neutral pieces from their historical home so the\n// package surface is unchanged by the core extraction.\nexport { createBasicFrameLoopAnimator };\nexport type { PxPlatformAdapter };\n\nexport function getSelector(id: string) {\n // return `[data-px-id=\"${id}\"]`; FIXME\n return '#' + id;\n}\n\n\n////////////////////////////////////////////////////////////////\n// Browser DOM implementation\n////////////////////////////////////////////////////////////////\n\n\n\n/**\n * Creates an animator instance that uses a requestAnimationFrame loop for animations.\n * This is the browser DOM-specific version.\n *\n * @param {PxAnimatorCallbacksConfig=} callbacks Optional lifecycle callbacks.\n * @param {Element=} rootElement Optional pre-rendered root element.\n * @returns {PxAnimatorAPI} A PxAnimatorAPI instance.\n */\nexport function createFrameLoopAnimator(\n doc: PxAnimatedSvgDocument,\n adapter?: PxPlatformAdapter,\n callbacks?: PxAnimatorCallbacksConfig,\n rootElement?: Element | null\n): PxAnimatorAPI {\n\n const config = getAnimatorConfig(doc) || {};\n\n // Use provided root element or try to find by selector\n if (!rootElement) {\n if (doc.id) {\n const rootSelector = getSelector(doc.id);\n rootElement = document.querySelector(rootSelector);\n if (!rootElement) console.warn(\"createFrameLoopAnimator: No root element found for selector: \", rootSelector);\n } else {\n console.warn(\"createFrameLoopAnimator: No root element provided\");\n }\n }\n\n const basicApi = createBasicFrameLoopAnimator(\n doc,\n adapter || createDomAdapter(rootElement),\n callbacks\n );\n\n // Specialise the platform-neutral API to the DOM: the root is an Element.\n const api: PxAnimatorAPI = {\n ...basicApi,\n \"getRootElement\": () => rootElement || null\n };\n if (config.trigger) setupAnimationTriggers(api, config.trigger);\n return api;\n}\n\nexport function createDomAdapter(rootElement?: Element | null) {\n // Track warnings to avoid spamming console\n const warnedSelectors = new Set<string>();\n\n const adapter: PxPlatformAdapter = {\n isConnected: () => {\n if (!rootElement) return true; // No root element means we're always \"connected\"\n return rootElement.isConnected;\n },\n setAttribute: (id, attrName, value) => {\n\n attrName = camelCaseToKebabWordIfNeeded(attrName);\n\n const selector = getSelector(id);\n\n // Query elements by selector within root (or document if no root)\n const elements = rootElement?.querySelectorAll(selector) || document.querySelectorAll(selector);\n\n if (elements.length === 0 && !warnedSelectors.has(selector)) {\n warnedSelectors.add(selector);\n console.warn('setAttribute: No elements found for selector \"' + selector + '\"');\n }\n\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n // `<pattern>` ignores the plain `transform` ATTRIBUTE (it transforms via\n // `patternTransform`). The WAAPI engine drives the same animation through\n // CSS `transform`, which browsers do apply to patterns — remap here so the\n // frames engine animates everything WAAPI animates.\n const effectiveAttrName = attrName === 'transform' && element.tagName === 'pattern'\n ? 'patternTransform'\n : attrName;\n element.setAttribute(effectiveAttrName, value);\n if (STYLE_ATTR_NAMES.has(attrName)) {\n (element as HTMLElement).style[attrName as any] = value;\n }\n }\n },\n };\n return adapter;\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 { bezierToSvgPath, camelCaseToKebabWordIfNeeded, clamp, COLOUR_ATTR_NAMES, composeTransformParts, cubicBezier, getAnimatorConfig, getNormalisedBindings, interpolateValue, kebabToCamelCaseWord, PxAnimatorEngine, splitEasing, toRGBA, TRANSFORM_FN_NAMES, type PxAnimatedSvgDocument, type PxAnimationDefinition, type PxAnimatorCallbacksConfig, type PxAnimatorConfig, type PxBezierPath, type PxKeyframe } from '@pixodesk/svg-animator-core';\nimport { getSelector } from './PxAnimatorFrameLoop';\nimport { setupAnimationTriggers } from './PxAnimatorTriggers';\nimport type { PxAnimatorAPI } from './PxAnimatorWebTypes';\n\n\n/**\n * Converts a single PxKeyframe into a Web Animations API Keyframe object.\n *\n * Handles three categories of CSS property:\n * - **Colour attributes** (e.g. fill, stroke): array values are converted to an rgba() string.\n * - **Transform functions** (e.g. translate, rotate, scale): values are formatted as a\n * CSS transform function string and mapped to the transform property.\n * - **All other properties**: the value is coerced to a string as-is.\n *\n * If the resulting (cssKey, cssValue) pair is not supported by the browser (CSS.supports returns\n * false), cssKey is added to unsupportedSet so the caller can decide whether to fall back to the\n * frame-loop animator.\n */\nfunction createCssKf(kf: PxKeyframe, t: number, propName: string, unsupportedSet: Set<string>) {\n let value = kf.v ?? kf.value;\n const e = kf.e ?? kf.easing; // e is on the source keyframe: applied from this KF to the next (matches WAAPI easing convention)\n\n const cssKf: Keyframe = {\n offset: t,\n easing: e && Array.isArray(e) ? \"cubic-bezier(\" + e.join(',') + \")\" : undefined\n };\n\n let cssValue: any;\n let cssKey = propName;\n\n if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {\n cssValue = toRGBA(value);\n } else if (propName === 'transform' && value !== null && typeof value === 'object' && !Array.isArray(value)) {\n // Unified transform: keyframe value is a parts record (PxTransformParts).\n // Compose all present parts into one CSS transform string.\n cssValue = composeTransformParts(value, { withUnits: true });\n cssKey = 'transform';\n } else if (TRANSFORM_FN_NAMES.has(propName)) {\n if (Array.isArray(value)) {\n if (propName === 'translate') value = value.map(v => v + 'px');\n value = value.join(',');\n }\n if (propName === 'rotate') value = value + 'deg';\n cssValue = propName + '(' + value + ')';\n cssKey = 'transform';\n } else if (propName === 'd') {\n // Animated path. The value is a { paths: PxBezierPath[] } record (same shape the CSS/frame\n // builder consumes). Without this branch it stringified to \"[object Object]\", an invalid\n // `d`, which empties the <path> — the shape vanished in forced WAAPI while svg-css (which\n // emits `d: path(...)`) rendered it. Emit the CSS `d` presentation-attr syntax `path(\"…\")`\n // via the same bezierToSvgPath used by the CSS path, so WAAPI animates it identically.\n const paths: Array<PxBezierPath> = (value && typeof value === 'object' && Array.isArray(value.paths))\n ? value.paths : [];\n // forceCurves: CSS/WAAPI only interpolates `path()` values with IDENTICAL command\n // sequences — uniform all-`C` output keeps every keyframe structurally equal\n // (mixed L/C, e.g. round-corner radius 0 vs >0, would go DISCRETE → 50% flip).\n cssValue = 'path(\"' + paths.map(bz => bezierToSvgPath(bz, true)).join('') + '\")';\n } else {\n cssValue = '' + value;\n }\n\n // `CSS.supports` takes a CSS PROPERTY name, so it must be asked in kebab-case —\n // `CSS.supports('strokeDasharray', …)` is always false. Prop names reach us in\n // either form (the app materialises trim paths as camelCase `strokeDasharray` /\n // `strokeDashoffset` / `strokeOpacity`), and an unsupported entry makes the caller\n // discard EVERY animation on the document, so a false negative here is costly.\n if (!CSS.supports(camelCaseToKebabWordIfNeeded(cssKey), cssValue)) unsupportedSet.add(cssKey);\n\n cssKey = kebabToCamelCaseWord(cssKey);\n cssKf[cssKey] = cssValue;\n return cssKf;\n}\n\n/**\n * Clips keyframes to the [0, duration] range.\n * If a keyframe pair straddles a boundary (t=0 or t=duration), inserts an interpolated\n * keyframe at the boundary with the correct value and split easing, so WAAPI sees\n * exact start/end values rather than out-of-range ones.\n */\nfunction clipKeyframesToDuration(\n propName: string,\n keyframes: PxKeyframe[],\n duration: number\n): PxKeyframe[] {\n const result: PxKeyframe[] = [];\n\n for (let i = 0; i < keyframes.length; i++) {\n const kf = keyframes[i];\n const t = kf.t ?? 0;\n\n if (t < 0) {\n // If the next keyframe is in range, interpolate value at t=0\n const next = keyframes[i + 1];\n if (next && (next.t ?? 0) >= 0) {\n const nextT = next.t ?? 0;\n const localFrac = (0 - t) / (nextT - t);\n const easedFrac = kf.e ? cubicBezier(kf.e as [number, number, number, number])(localFrac) : localFrac;\n const { right: rightEasing } = splitEasing(kf.e as any, localFrac);\n result.push({ t: 0, v: interpolateValue(propName, kf.v, next.v, easedFrac), e: rightEasing });\n }\n continue;\n }\n\n if (t > duration) {\n // If the previous keyframe was in range, interpolate value at t=duration\n const prev = keyframes[i - 1];\n if (prev && (prev.t ?? 0) <= duration) {\n const prevT = prev.t ?? 0;\n const localFrac = (duration - prevT) / (t - prevT);\n const easedFrac = prev.e ? cubicBezier(prev.e as [number, number, number, number])(localFrac) : localFrac;\n const { left: leftEasing } = splitEasing(prev.e as any, localFrac);\n if (result.length > 0) result[result.length - 1] = { ...result[result.length - 1], e: leftEasing };\n result.push({ t: duration, v: interpolateValue(propName, prev.v, kf.v, easedFrac), e: undefined });\n }\n break;\n }\n\n result.push(kf);\n }\n\n return result;\n}\n\n/**\n * Converts a PxAnimationDefinition into a map of Web Animations API Keyframe arrays, one per\n * animated property.\n *\n * For each property in the definition the function:\n * 1. Clips keyframes to [0, duration], interpolating boundary values when a pair straddles an edge.\n * 2. Normalises keyframe time values to the [0, 1] offset range (time / duration).\n * 3. Delegates CSS value conversion to createCssKf.\n * 4. Ensures the keyframe sequence always starts at offset: 0 and ends at offset: 1 — a\n * requirement of the Web Animations API for correct looping behaviour. If the first keyframe\n * starts after 0 or the last keyframe ends before 1, a copy of that keyframe is inserted at the\n * boundary with the adjusted offset.\n */\nexport function convertToWebApiKeyframes(\n animDef: PxAnimationDefinition,\n unsupportedSet: Set<string>,\n config: PxAnimatorConfig\n): Map<string, Keyframe[]> {\n const result = new Map<string, Keyframe[]>();\n\n for (const [propName, propAnim] of Object.entries(animDef)) {\n const duration = config.duration || 1;\n const clippedKeyframes = clipKeyframesToDuration(propName, propAnim.kfs || propAnim.keyframes || [], duration);\n const cssKeyframes: Keyframe[] = [];\n\n for (let i = 0; i < clippedKeyframes.length; i++) {\n const kf = clippedKeyframes[i];\n\n const t = clamp((kf.t ?? 0) / duration, 0, 1);\n const cssKf: Keyframe = createCssKf(kf, t, propName, unsupportedSet);\n\n // Keyframes need to start with offset:0 to work correctly with loops\n if (i === 0 && (cssKf.offset || 0) > 0) {\n cssKeyframes.push({ ...cssKf, offset: 0 });\n }\n\n cssKeyframes.push(cssKf);\n }\n\n // Keyframes need to end with offset:1 to work correctly with loops\n if (cssKeyframes.length > 0 && (cssKeyframes[cssKeyframes.length - 1].offset || 0) < 1) {\n cssKeyframes.push({\n ...cssKeyframes[cssKeyframes.length - 1],\n offset: 1\n });\n }\n\n if (cssKeyframes.length > 0) {\n result.set(propName, cssKeyframes);\n }\n }\n\n return result;\n}\n\n/**\n * Creates an animator instance that uses the native Web Animations API.\n *\n * This is the preferred, more performant animator. It will return null if the\n * animation configuration contains properties not supported by the browser's\n * Web Animations API implementation, unless forceEvenIfHasUnsupportedAttrs is true.\n *\n * @param callbacks Optional lifecycle callbacks.\n * @param rootElement Root element.\n * @param forceEvenIfHasUnsupportedAttrs If true, an animator will be created even if some CSS properties are not supported.\n * @returns An PxAnimatorAPI instance, or null if unsupported features are used and not forced.\n */\nexport function createWebApiAnimator(\n doc: PxAnimatedSvgDocument,\n callbacks?: PxAnimatorCallbacksConfig,\n rootElement?: Element | null,\n forceEvenIfHasUnsupportedAttrs?: boolean\n): PxAnimatorAPI | null {\n\n const config = getAnimatorConfig(doc) || {};\n\n // Use provided root element or try to find by selector\n if (!rootElement) {\n if (doc.id) {\n const rootSelector = getSelector(doc.id);\n rootElement = document.querySelector(rootSelector);\n if (!rootElement) console.warn(\"createFrameLoopAnimator: No root element found for selector: \", rootSelector);\n } else {\n console.warn(\"createFrameLoopAnimator: No root element provided\");\n }\n }\n\n // WAAPI bindings: motion-along-path is materialised into plain `{ translate,\n // rotate }` transform kfs inside `normalizeAnimationDefinition` (gated on\n // `engine === 'waapi'`). The WAAPI keyframe builder then sees a vanilla\n // unified-transform animation — no DOM-style mutation, no offset-path.\n const bindings = getNormalisedBindings(doc, PxAnimatorEngine.waapi);\n\n const animations: Array<Animation> = [];\n\n const _iterations = config.iterations;\n let iterations: number | undefined;\n if (typeof _iterations === 'number') iterations = _iterations;\n if (_iterations === 'infinite') iterations = Infinity;\n\n const unsupportedSet = new Set<string>();\n\n // A document commonly produces many Animation objects (one per element ×\n // animated property), but the public callbacks describe the document\n // timeline as a whole — guard so each fires once per finish/remove episode.\n // `finishNotified` re-arms on play/cancel/seek.\n let finishNotified = false;\n let removeCalled = false;\n\n ////////////////////////////////////////////////////////////////\n\n // Warn if no bindings defined\n if (!bindings?.length) {\n console.warn('createWebApiAnimator: No animation bindings defined');\n }\n\n for (const binding of bindings || []) {\n const animDef = binding.animate;\n if (!animDef || typeof animDef !== 'object' || Array.isArray(animDef)) {\n console.warn('createWebApiAnimator: Empty or unresolved binding', binding);\n continue;\n }\n\n const selector = getSelector(binding.id);\n\n // Use CSS selector to find elements\n const elements = rootElement?.querySelectorAll(selector) || document.querySelectorAll(selector);\n\n if (elements.length === 0) {\n console.warn('createWebApiAnimator: No elements found for selector \"' + selector + '\"');\n }\n\n // Convert animation definition to Web API keyframes\n const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);\n\n\n // Delay handling:\n // - Positive delay (e.g., 500): Wait before starting → use delay option\n // - Negative delay (e.g., -500): Start mid-animation → use currentTime to seek\n // (Web Animations API doesn't reliably support negative delay values)\n // WAAPI `currentTime` spans ALL iterations, so a finite timeline clamps\n // the seek to duration × iterations (seeking to exactly the end must\n // land on the final frame, not wrap to 0); an infinite timeline wraps\n // within one iteration instead.\n const positiveDelay = config.delay && config.delay > 0 ? config.delay : undefined;\n let seekPosition: number | undefined;\n if (config.delay && config.delay < 0 && config.duration) {\n const rawSeek = -config.delay;\n seekPosition = iterations === Infinity\n ? rawSeek % config.duration\n : Math.min(rawSeek, config.duration * (iterations ?? 1));\n }\n\n const effectOptions: KeyframeEffectOptions = {\n duration: config.duration,\n delay: positiveDelay,\n // Default to 'forwards' so elements hold their final state after the\n // animation ends — consistent with Lottie and other animation runtimes.\n // Without this, seeking to the last frame reverts elements to their\n // pre-animation state (the Web Animations API \"after\" phase with fill:'none').\n fill: config.fill ?? 'forwards',\n direction: config.direction,\n iterations: iterations\n };\n\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n\n for (const [, keyframes] of keyframesMap) {\n if (keyframes.length > 0) {\n try {\n const effect = new KeyframeEffect(element, keyframes, effectOptions);\n const anim = new Animation(effect, document.timeline);\n\n if (callbacks?.onFinish) anim.onfinish = () => {\n if (finishNotified) return;\n finishNotified = true;\n callbacks.onFinish?.();\n };\n if (callbacks?.onRemove) anim.onremove = () => {\n if (removeCalled) return;\n removeCalled = true;\n callbacks.onRemove?.();\n };\n\n // Seek forward for negative delay (e.g., delay=-500 → seek to 500ms).\n // `!== undefined` — a seek of exactly 0 is still a seek.\n if (seekPosition !== undefined) {\n anim.currentTime = seekPosition;\n }\n\n animations.push(anim);\n } catch (e) {\n console.warn(e);\n }\n }\n }\n }\n }\n\n ////////////////////////////////////////////////////////////////\n\n if (!forceEvenIfHasUnsupportedAttrs && unsupportedSet.size) {\n console.warn('Unsupported CSS attrs: ' + [...unsupportedSet].join(', '));\n return null;\n }\n\n ////////////////////////////////////////////////////////////////\n\n const api: PxAnimatorAPI = {\n\n \"isReady\": () => true,\n\n \"getRootElement\": () => rootElement || null,\n\n \"isPlaying\": (): boolean => { return animations[0]?.playState === 'running'; },\n\n \"play\": () => {\n finishNotified = false; // re-arm finish notification\n animations.forEach(a => a.play());\n callbacks?.onPlay?.();\n },\n \"pause\": () => {\n animations.forEach(a => a.pause());\n callbacks?.onPause?.();\n },\n \"cancel\": () => {\n finishNotified = false; // re-arm finish notification\n animations.forEach(a => a.cancel());\n callbacks?.onCancel?.();\n },\n \"finish\": () => {\n for (const a of animations) {\n try {\n if (a.effect?.getTiming().iterations === Infinity) {\n a.effect.updateTiming({ iterations: 1 });\n a.finish();\n a.effect.updateTiming({ iterations: Infinity });\n } else {\n a.finish();\n }\n } catch (e) {\n a.cancel();\n }\n }\n // Natural finish also reaches onFinish via the native `anim.onfinish`\n // handler wired at construction time.\n },\n\n \"setPlaybackRate\": (rate: number) => {\n animations.forEach(a => (a.playbackRate = rate));\n return api;\n },\n \"getCurrentTime\": (): number | null => {\n const res = animations[0]?.currentTime ?? null;\n return res !== null ? +res : null;\n },\n \"setCurrentTime\": (time: number) => {\n finishNotified = false; // re-arm finish notification\n animations.forEach(a => {\n a.currentTime = time;\n });\n },\n\n \"destroy\": () => {\n api.cancel();\n animations.splice(0, animations.length);\n if (!removeCalled) {\n removeCalled = true;\n callbacks?.onRemove?.();\n }\n }\n };\n\n ////////////////////////////////////////////////////////////////\n\n if (config.trigger) {\n setupAnimationTriggers(api, config.trigger);\n }\n\n return api;\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 { getAnimatorConfig, PxAnimatorMode, type PxAnimatedSvgDocument, type PxAnimatorCallbacksConfig, type PxAnimatorConfig, type PxPlatformAdapter } from '@pixodesk/svg-animator-core';\nimport { createFrameLoopAnimator } from './PxAnimatorFrameLoop';\nimport type { PxAnimatorAPI } from './PxAnimatorWebTypes';\nimport { createWebApiAnimator } from './PxAnimatorWebApi';\n\n/**\n * Engine construction, shared by the full player and the pre-rendered builds.\n *\n * Everything here operates on a document that is ALREADY in its final shape — no\n * validation, no materialisation, no rendering. `createAnimatorImpl` calls in after it\n * has done those stages; the pre-rendered entries call in directly, because the Editor\n * did them at export time. See PRERENDERED-PLAYER-BUILDS.md.\n */\n\n/**\n * Applies the two `animator` config behaviours that are engine-independent, then hands\n * off to `make` for the actual engine.\n *\n * `resetOnFinish` is composed here so BOTH engines get it: after a NATURAL finish the\n * document snaps back to its start state (same mechanics as the trigger `reset`\n * out-action). The caller's own `onFinish` still fires first. `apiRef` is assigned right\n * after creation — finish always happens asynchronously later.\n */\nexport function finaliseAnimator(\n animatorConfig: PxAnimatorConfig,\n callbacks: PxAnimatorCallbacksConfig | undefined,\n make: (effectiveCallbacks?: PxAnimatorCallbacksConfig) => PxAnimatorAPI\n): PxAnimatorAPI {\n\n let apiRef: PxAnimatorAPI | undefined;\n let effectiveCallbacks = callbacks;\n if (animatorConfig.resetOnFinish) {\n effectiveCallbacks = {\n ...callbacks,\n onFinish: () => {\n callbacks?.onFinish?.();\n apiRef?.cancel();\n },\n };\n }\n\n const res = make(effectiveCallbacks);\n apiRef = res;\n\n if (animatorConfig.debugInstName) {\n (window as any)[animatorConfig.debugInstName] = res; // Exposing as global variable for debug\n }\n\n return res;\n}\n\n/**\n * Picks the engine the way the full player does: `frames` when forced, otherwise waapi\n * with a frames fallback for unsupported attrs.\n */\nexport function bindWithEngineChoice(\n doc: PxAnimatedSvgDocument,\n adapter?: PxPlatformAdapter,\n callbacks?: PxAnimatorCallbacksConfig,\n rootElement?: Element | null\n): PxAnimatorAPI {\n const animatorConfig = getAnimatorConfig(doc) || {};\n return finaliseAnimator(animatorConfig, callbacks, cb => {\n if (animatorConfig.mode === PxAnimatorMode.frames) {\n // Forcing frames, even if waapi could be used.\n return createFrameLoopAnimator(doc, adapter, cb, rootElement);\n }\n // Try waapi first; fall back to frames if it returns null (unsupported\n // attrs) unless the user explicitly forced waapi.\n return (\n createWebApiAnimator(doc, cb, rootElement,\n animatorConfig.mode === PxAnimatorMode.waapi // forcing waapi\n ) ||\n createFrameLoopAnimator(doc, adapter, cb, rootElement)\n );\n });\n}\n\n/** Options accepted by the pre-rendered entry points. A subset of `PxAnimatorOptions`: */\nexport interface PxPrerenderedOptions {\n /**\n * The animation document. For a pre-rendered SVG this carries `animator.definitions`\n * and `animator.animateById` only — no `children`, because the elements are already\n * in the DOM.\n */\n data: PxAnimatedSvgDocument;\n /** Callback functions for animation lifecycle events. */\n callbacks?: PxAnimatorCallbacksConfig;\n /** Platform adapter for frame-loop rendering. */\n adapter?: PxPlatformAdapter;\n}\n\nfunction requireData(options: PxPrerenderedOptions): PxAnimatedSvgDocument {\n if (!options?.data) throw new Error('createAnimator: `data` is required');\n return options.data;\n}\n\n/**\n * Pre-rendered entry, both engines (`auto` / `frames` / `waapi` all honoured).\n *\n * Deliberately skips `validateNodeEffects`, `materialiseAllInTree`, `generateNewIds` and\n * `renderNode`. Safe because the payload has no `children`, so all four are provably\n * no-ops for this document shape — and none of them reads `animator.animateById`.\n */\nexport function createPrerenderedAnimator(options: PxPrerenderedOptions): PxAnimatorAPI {\n return bindWithEngineChoice(requireData(options), options.adapter, options.callbacks, null);\n}\n\n/**\n * Pre-rendered entry, WAAPI only — the smallest build. Forces waapi so there is no\n * frames fallback to link against (`createWebApiAnimator` never returns null when\n * forced; it only warns about unsupported attrs).\n */\nexport function createPrerenderedWaapiAnimator(options: PxPrerenderedOptions): PxAnimatorAPI {\n const doc = requireData(options);\n const animatorConfig = getAnimatorConfig(doc) || {};\n return finaliseAnimator(animatorConfig, options.callbacks,\n cb => createWebApiAnimator(doc, cb, null, 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 * Wire keys shared by every entry point.\n *\n * These live here rather than in `PxAnimator.ts` on purpose: that module ends with a\n * top-level `if (typeof window !== 'undefined')` block that publishes `createAnimator` /\n * `loadTagAnimators` as globals. A module-level side effect cannot be tree-shaken, so\n * importing ANY symbol from `PxAnimator.ts` pulls the entire full player in with it —\n * which silently made the pre-rendered builds the same size as the full one until this\n * constant was moved out. See PRERENDERED-PLAYER-BUILDS.md.\n */\n\n/** Key under which `createAnimator` options carry an inline animation document. */\nexport const PX_ANIMATOR_DATA_KEY = 'data';\n"],"mappings":"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","names":["_a","_b","_a"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var PixodeskAnimator=(()=>{var n=Object.defineProperty,t=Object.defineProperties,o=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyDescriptors,e=Object.getOwnPropertyNames,l=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,u=Object.prototype.propertyIsEnumerable,c=(t,o,r)=>o in t?n(t,o,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[o]=r,f=(n,t)=>{for(var o in t||(t={}))i.call(t,o)&&c(n,o,t[o]);if(l)for(var o of l(t))u.call(t,o)&&c(n,o,t[o]);return n},s=(n,o)=>t(n,r(o)),a={};((t,o)=>{for(var r in o)n(t,r,{get:o[r],enumerable:!0})})(a,{PX_ANIMATOR_DATA_KEY:()=>Mn,createAnimator:()=>gn,setupAnimationTriggers:()=>pn});var v={waapi:"waapi",frames:"frames"},d={before:"before",after:"after"};function p(n){var t;return(null==n?void 0:n.animator)||(null==(t=null==n?void 0:n.meta)?void 0:t.animator)}function h(n,t,o){return n+(t-n)*o}function m(n,t,o){const r=[],e=Math.max(n.length,t.length);for(let l=0;l<e;l++)r[l]=h(n[l]||0,t[l]||0,o);return r}function b(n,t,o){const r=Math.max(n.length,t.length),e=[];for(let l=0;l<r;l++)e.push(y(n[l],t[l],o));return e}function y(n,t,o){var r,e,l,i,u,c,f,s,a;if(!n||!t)return n||t||{v:[]};const v=Math.min(Math.max(o,0),1),d=Math.min(n.v.length,t.v.length),p=[],h=[],b=[];for(let o=0;o<d;o++){const a=n.v[o],d=t.v[o];p.push(m(a,d,v));const y=null!=(e=null==(r=n.i)?void 0:r[o])?e:a,g=null!=(i=null==(l=t.i)?void 0:l[o])?i:d;h.push(m(y,g,v));const A=null!=(c=null==(u=n.o)?void 0:u[o])?c:a,M=null!=(s=null==(f=t.o)?void 0:f[o])?s:d;b.push(m(A,M,v))}return{v:p,i:h.length?h:void 0,o:b.length?b:void 0,c:null!=(a=n.c)?a:t.c}}function g(n,t,o){if(o<=0)return 0;if(o>=1)return 1;const r=3*n,e=3*(t-n)-r,l=1-r-e;function i(n){return((l*n+e)*n+r)*n}function u(n){return(3*l*n+2*e)*n+r}let c=o,f=0,s=1;for(let n=0;n<8;n++){const n=i(c)-o;if(Math.abs(n)<1e-6)return c;const t=u(c);if(Math.abs(t)<1e-6)break;c-=n/t}for(c=o;f<s;){const n=i(c);if(Math.abs(n-o)<1e-6)return c;o>n?f=c:s=c,c=(s+f)/2}return c}function A(n){const[t,o,r,e]=n,l=3*o,i=3*(e-o)-l,u=1-l-i;return function(n){return o=g(t,r,n),((u*o+i)*o+l)*o;var o}}function M(n,t,o){return[n[0]+(t[0]-n[0])*o,n[1]+(t[1]-n[1])*o]}function w(n,t){if(!n)return{left:void 0,right:void 0};if(t<=0)return{left:void 0,right:n};if(t>=1)return{left:n,right:void 0};const[o,r,e,l]=n,i=g(o,e,t),u=[o,r],c=[e,l],{left:f,right:s}=function(n,t,o,r,e){const l=M(n,t,e),i=M(t,o,e),u=M(o,r,e),c=M(l,i,e),f=M(i,u,e),s=M(c,f,e);return{left:[n,l,c,s],right:[s,f,u,r]}}([0,0],u,c,[1,1],i),a=f[3][0],v=f[3][1];let d,p;a>1e-9&&Math.abs(v)>1e-9&&(d=[f[1][0]/a,f[1][1]/v,f[2][0]/a,f[2][1]/v]);const h=1-a,m=1-v;return h>1e-9&&Math.abs(m)>1e-9&&(p=[(s[1][0]-a)/h,(s[1][1]-v)/m,(s[2][0]-a)/h,(s[2][1]-v)/m]),{left:d,right:p}}function j(n){if(n)return[1-n[2],1-n[3],1-n[0],1-n[1]]}function k(n){if(n){if(Array.isArray(n))return n;if("string"==typeof n)return n.startsWith("#")?function(n){const t=n.slice(1),o=t.length<=4,r=o?t[0]+t[0]:t.slice(0,2),e=o?t[1]+t[1]:t.slice(2,4),l=o?t[2]+t[2]:t.slice(4,6),i=4===t.length?t[3]+t[3]:8===t.length?t.slice(6,8):null,u=[parseInt(r,16)/255,parseInt(e,16)/255,parseInt(l,16)/255];return null!==i&&u.push(parseInt(i,16)/255),u}(n):n.startsWith("rgb")?function(n){var t;const o=null==(t=n.match(/rgba?\((.*)\)/))?void 0:t[1];if(!o)throw new Error("Invalid rgb/rgba format");const r=o.split(",").map(n=>+n.trim());return[r[0]/255,r[1]/255,r[2]/255,...void 0!==r[3]?[r[3]]:[]]}(n):void console.warn("Unsupported color format: "+n)}}var O=new Set(["color","fill","flood-color","lighting-color","stop-color","stroke"]),U=new Set(["translate","rotate","scale","skew"]);function C(n){return!n.includes("-")&&/[a-z][A-Z]/.test(n)}var T=new Set(["viewBox","preserveAspectRatio","gradientUnits","gradientTransform","spreadMethod","patternUnits","patternContentUnits","patternTransform","clipPathUnits","maskUnits","maskContentUnits","markerUnits","markerWidth","markerHeight","refX","refY","textLength","lengthAdjust","startOffset","filterUnits","primitiveUnits","tableValues","stdDeviation","baseFrequency","numOctaves","surfaceScale","diffuseConstant","specularConstant","specularExponent","kernelMatrix","kernelUnitLength","edgeMode","preserveAlpha","targetX","targetY"]);function I(n){return T.has(n)?n:n.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function S(n,t,o){return Math.max(t,Math.min(n,o))}function z(n,t,o,r,e){if(e<=0)return[n[0],n[1]];if(e>=1)return[r[0],r[1]];const l=1-e,i=l*l,u=e*e,c=i*l,f=3*e*i,s=3*u*l,a=u*e;return[c*n[0]+f*t[0]+s*o[0]+a*r[0],c*n[1]+f*t[1]+s*o[1]+a*r[1]]}var L=1e-4;function P(n,t,o,r,e){const l=x(n,t,o,r,e);return 0===l[0]&&0===l[1]?x(n,t,o,r,e<.5?e+L:e-L):l}function x(n,t,o,r,e){const l=1-e,i=3*l*l,u=6*e*l,c=3*e*e;return[i*(t[0]-n[0])+u*(o[0]-t[0])+c*(r[0]-o[0]),i*(t[1]-n[1])+u*(o[1]-t[1])+c*(r[1]-o[1])]}function N(n,t){const{ts:o,ds:r}=n,e=o.length-1;if(t<=o[0])return r[0];if(t>=o[e])return r[e];let l=1,i=e;for(;l<i;){const n=l+i>>>1;o[n]<t?l=n+1:i=n}const u=o[i-1],c=o[i]-u,f=c>0?(t-u)/c:0;return r[i-1]+f*(r[i]-r[i-1])}function _(n){var t;const o=null!=(t=n.value)?t:n.v;if(!o)return;if(Array.isArray(o)&&o.length>=2&&"number"==typeof o[0]&&"number"==typeof o[1])return[o[0],o[1]];const r=o.translate;return Array.isArray(r)&&r.length>=2?[r[0],r[1]]:void 0}function E(n){var t,o;return null!=(o=null!=(t=n.time)?t:n.t)?o:0}function F(n){var t;return null!=(t=n.easing)?t:n.e}var W=new WeakMap;function Z(n,t,o,r){var e,l;let i=W.get(n);const u=null==i?void 0:i.get(t);if(u)return u;const c=null!=(e=n.tangentOut)?e:n.to,f=null!=(l=t.tangentIn)?l:t.ti,s=[o[0]+(c?c[0]:0),o[1]+(c?c[1]:0)],a=[r[0]+(f?f[0]:0),r[1]+(f?f[1]:0)],v=function(n,t,o,r,e=100){const l=e+1,i=new Float64Array(l),u=new Float64Array(l);let c=z(n,t,o,r,0);i[0]=0,u[0]=0;let f=0;for(let s=1;s<l;s++){const l=s/e,a=z(n,t,o,r,l),v=a[0]-c[0],d=a[1]-c[1];f+=Math.sqrt(v*v+d*d),i[s]=l,u[s]=f,c=a}return{ts:i,ds:u}}(o,s,a,r),d={P0:o,P1:s,P2:a,P3:r,l:v,h:v.ds[v.ds.length-1]};return i||(i=new WeakMap,W.set(n,i)),i.set(t,d),d}var R=.5,V=5,X=32;function q(n,t){var o,r,e,l;if(!function(n){var t,o,r;const e=null!=(t=n.keyframes)?t:n.kfs;if(!Array.isArray(e))return!1;if(n.autoOrient)return!0;for(const n of e)if((null!=(o=n.tangentIn)?o:n.ti)||(null!=(r=n.tangentOut)?r:n.to))return!0;return!1}(n))return n;const i=null!=(o=n.keyframes)?o:n.kfs;if(!Array.isArray(i)||i.length<2)return n;const u=!!n.autoOrient,c=null!=(r=null==t?void 0:t.m)?r:R,f=null!=(e=null==t?void 0:t.A)?e:V,s=null!=(l=null==t?void 0:t.M)?l:X,a=[],v=_(i[0]);if(!v)return n;const d=u?function(n,t){const o=_(n),r=_(t);if(!o||!r)return 0;const e=Z(n,t,o,r),l=P(e.P0,e.P1,e.P2,e.P3,0);return 180*Math.atan2(l[1],l[0])/Math.PI}(i[0],i[1]):void 0;a.push(D(E(i[0]),K(Y(i[0]),Y(i[0]),0,v,d,u)));for(let n=0;n<i.length-1;n++){const t=i[n],o=i[n+1],r=_(t),e=_(o);r&&e?(u&&n>0&&B(a,t,o,r,e,f),G(a,t,o,r,e,u,c,f,s)):a.push(D(E(o),K(Y(o),Y(o),1,null!=e?e:[0,0],void 0,u)))}const p=F(i[i.length-1]);p&&(a[a.length-1].e=p),u&&function(n){var t;let o;for(const r of n){const n=null!=(t=r.v)?t:r.value;if(!n||"number"!=typeof n.rotate)continue;if(void 0===o){o=n.rotate;continue}let e=n.rotate;for(;e-o>180;)e-=360;for(;e-o<-180;)e+=360;n.rotate=e,o=e}}(a);const h={kfs:a};return void 0!==n.loop&&(h.loop=n.loop),h}function D(n,t){return{t:n,v:t}}function Y(n){var t;const o=null!=(t=n.value)?t:n.v;if(o&&"object"==typeof o&&!Array.isArray(o))return o}function H(n,t,o){if(void 0===n)return t;if(void 0===t)return n;if("number"==typeof n&&"number"==typeof t)return n+(t-n)*o;if(Array.isArray(n)&&Array.isArray(t)&&n.length===t.length){const r=new Array(n.length);for(let e=0;e<n.length;e++){const l="number"==typeof n[e]?n[e]:0,i="number"==typeof t[e]?t[e]:0;r[e]=l+(i-l)*o}return r}return o<.5?n:t}function K(n,t,o,r,e,l){const i={translate:r},u=new Set;if(n)for(const t of Object.keys(n))u.add(t);if(t)for(const n of Object.keys(t))u.add(n);for(const r of u){if("translate"===r)continue;if("rotate"===r&&l)continue;const e=null==n?void 0:n[r],u=null==t?void 0:t[r];void 0===e&&void 0===u||(i[r]=H(e,u,o))}return void 0!==e&&(i.rotate=e+$(n,t,o)),i}function $(n,t,o){const r="number"==typeof(null==n?void 0:n.rotate)?n.rotate:void 0,e="number"==typeof(null==t?void 0:t.rotate)?t.rotate:void 0;if(void 0===r&&void 0===e)return 0;const l=H(r,e,o);return"number"==typeof l?l:0}function B(n,t,o,r,e,l){var i;const u=n[n.length-1],c=null!=(i=u.v)?i:u.value,f=null==c?void 0:c.rotate;if("number"!=typeof f)return;const s=Y(t),a=f-$(s,s,0),v=Z(t,o,r,e),d=P(v.P0,v.P1,v.P2,v.P3,0),p=180*Math.atan2(d[1],d[0])/Math.PI,h=function(n,t){let o=n-t;for(;o>180;)o-=360;for(;o<-180;)o+=360;return o}(p,a);if(Math.abs(h)<=l)return;const m=E(t),b=Math.min(m+Q,(m+E(o))/2),y=K(Y(t),Y(t),0,r,p,!0);n.push(D(b,y))}var Q=.05;function G(n,t,o,r,e,l,i,u,c){const f=Z(t,o,r,e),s=E(t),a=E(o),v=F(t),d=(p=v)?A([p[1],p[0],p[3],p[2]]):n=>n;var p;const h=Y(t),m=Y(o),b=function(n,t,o,r,e){const l=[];J(n.P0[0],n.P1[0],n.P2[0],n.P3[0],l),J(n.P0[1],n.P1[1],n.P2[1],n.P3[1],l),l.sort((n,t)=>n-t);const i=[0];for(const n of l)n>i[i.length-1]+1e-6&&n<.999999&&i.push(n);i.push(1);const u=[],c={j:e-i.length};for(let e=0;e<i.length-1;e++)nn(i[e],i[e+1],u,n,t,o,r,c);return u}(f,l,i,u,c),y=[];for(const n of b){const t=N(f.l,n),o=S(f.h>0?t/f.h:n,0,1),r={u:S(d(o),0,1),p:o,k:z(f.P0,f.P1,f.P2,f.P3,n)};if(l){const t=P(f.P0,f.P1,f.P2,f.P3,n);r.O=180*Math.atan2(t[1],t[0])/Math.PI}y.push(r)}let g=v,M=0;const j=n.length-1;for(let t=0;t<y.length;t++){const o=y[t],r=M<1?S((o.u-M)/(1-M),0,1):1,{left:e,right:i}=w(g,r),u=0===t?j:n.length-1;e?n[u].e=e:delete n[u].e;const c=s+o.u*(a-s),f=K(h,m,o.p,o.k,o.O,l);n.push(D(c,f)),g=i,M=o.u}}function J(n,t,o,r,e){const l=t-n,i=o-t,u=l-2*i+(r-o),c=2*(i-l),f=l;if(Math.abs(u)<1e-10){if(Math.abs(c)>1e-10){const n=-f/c;n>1e-6&&n<.999999&&e.push(n)}return}const s=c*c-4*u*f;if(s<0)return;const a=Math.sqrt(s),v=(-c-a)/(2*u),d=(-c+a)/(2*u);v>1e-6&&v<.999999&&e.push(v),d>1e-6&&d<.999999&&e.push(d)}function nn(n,t,o,r,e,l,i,u){const c=(n+t)/2,f=z(r.P0,r.P1,r.P2,r.P3,n),s=z(r.P0,r.P1,r.P2,r.P3,t),a=t-n,v=z(r.P0,r.P1,r.P2,r.P3,n+.25*a),d=z(r.P0,r.P1,r.P2,r.P3,c),p=z(r.P0,r.P1,r.P2,r.P3,n+.75*a),h=Math.max(tn(v,f,s),tn(d,f,s),tn(p,f,s));let m=!0;if(e){const o=P(r.P0,r.P1,r.P2,r.P3,n),e=P(r.P0,r.P1,r.P2,r.P3,t),l=180*Math.atan2(o[1],o[0])/Math.PI,u=180*Math.atan2(e[1],e[0])/Math.PI;let c=Math.abs(l-u);c>180&&(c=360-c),c>i&&(m=!1)}h<=l&&m||u.j<=0||a<1e-6?o.push(t):(u.j-=1,nn(n,c,o,r,e,l,i,u),nn(c,t,o,r,e,l,i,u))}function tn(n,t,o){const r=o[0]-t[0],e=o[1]-t[1],l=r*r+e*e;if(l<1e-20){const o=n[0]-t[0],r=n[1]-t[1];return Math.sqrt(o*o+r*r)}const i=(n[0]-t[0])*e-(n[1]-t[1])*r;return Math.abs(i)/Math.sqrt(l)}var on=10;function rn(n,t){if(n===t)return!0;if(typeof n!=typeof t||null===n||null===t||"object"!=typeof n)return!1;if(Array.isArray(n)!==Array.isArray(t))return!1;const o=Object.keys(n),r=Object.keys(t);return o.length===r.length&&o.every(o=>rn(n[o],t[o]))}function en(n){const t=[];let o;const r=function(n){const t=n.split(/([MLCZmlcz]|[\s,]+)/).map(n=>n.trim()).filter(n=>n&&","!==n),o=[];let r=null;for(const n of t)if(/[MLCZmlcz]/.test(n))r={type:n,values:[]},o.push(r);else if(r){const t=+n;r.values.push(Number.isNaN(t)?0:t)}return o}(n);for(const n of r){const r=n.type,e=n.values;if("M"===r||"m"===r){const n=e[0]||0,r=e[1]||0;o={v:[[n,r]],i:[[n,r]],o:[[n,r]],c:!1},t.push(o);continue}if(o||(o={v:[[0,0]],i:[[0,0]],o:[[0,0]],c:!1},t.push(o)),"L"===r){const n=e[0]||0,t=e[1]||0;o.v.push([n,t]),o.i.push([n,t]),o.o.push([n,t])}else if("C"===r){const n=e[0]||0,t=e[1]||0,r=e[2]||0,l=e[3]||0,i=e[4]||0,u=e[5]||0;o.o[o.o.length-1]=[n,t],o.v.push([i,u]),o.i.push([r,l]),o.o.push([i,u])}else"Z"===r||"z"===r?o.c=!0:console.warn('Unsupported path command "'+r+'"')}return t}function ln(n){return n.startsWith("path(")&&n.endsWith(")")?n.slice(5,-1):/^[MmZzLlHhVvCcSsQqTtAa]/.test(n)?n:void 0}function un(n){return"string"==typeof n&&void 0!==ln(n)}function cn(n){if(n&&"object"==typeof n&&"string"==typeof n.path){const t=ln(n.path);return t?{paths:en(t)}:n}if(n&&"object"==typeof n&&"paths"in n){const t=n.paths;if(Array.isArray(t)&&t.length>0&&un(t[0])){const n=[];for(const o of t){const t=ln(o);t&&n.push(...en(t))}return{paths:n}}return n}if(Array.isArray(n)){if(n.length>0&&un(n[0])){const t=[];for(const o of n){const n=ln(o);n&&t.push(...en(n))}return{paths:t}}return{paths:n}}return un(n)?{paths:en(ln(n))}:n}function fn(n,t){var o;if(n)return Array.isArray(n)?n:(null==(o=null==t?void 0:t.easings)?void 0:o[n])?t.easings[n]:void console.warn("Unknown easing name: "+n)}function sn(n,t){var o;if("string"==typeof n){const r=null==(o=null==t?void 0:t.animations)?void 0:o[n];return r||console.warn("Unknown animation name: "+n),r}return n}function an(n,t,o,r){var e,l;return"d"===n?{paths:b(null!=(e=null==t?void 0:t.paths)?e:Array.isArray(t)?t:[],null!=(l=null==o?void 0:o.paths)?l:Array.isArray(o)?o:[],r)}:O.has(n)?function(n,t,o){return[h(n[0]||0,t[0]||0,o),h(n[1]||0,t[1]||0,o),h(n[2]||0,t[2]||0,o),h(void 0===n[3]?1:n[3],void 0===t[3]?1:t[3],o)]}(t||[0,0,0,1],o||[0,0,0,1],r):"transform"!==n||"object"!=typeof t||null===t||Array.isArray(t)||"object"!=typeof o||null===o||Array.isArray(o)?"rotate"===n&&"number"==typeof t&&"number"==typeof o?h(t,o,r):U.has(n)||"stroke-dasharray"===n||"strokeDasharray"===n?m(t||[],o||[],r):h(+(t||0),+(o||0),r):function(n,t,o){const r=new Set([...Object.keys(null!=n?n:{}),...Object.keys(null!=t?t:{})]),e={};for(const l of r){const r=null==n?void 0:n[l],i=null==t?void 0:t[l];if("rotate"===l||"skew"===l)e[l]=h(+(null!=r?r:0),+(null!=i?i:0),o);else if("translate"===l||"scale"===l||"origin"===l){const n="scale"===l?[1,1]:[0,0];e[l]=m(r||n,i||n,o)}else e[l]=null!=i?i:r}return e}(t,o,r)}function vn(n,t,o,r){var e,l,i,u,c,f,s;const a=t.keyframes||t.kfs||[],v=[];for(const t of a){const o=null!=(l=null!=(e=t.time)?e:t.t)?l:0;let a=null!=(i=t.value)?i:t.v;const d=null!=(u=t.easing)?u:t.e;"d"===n&&(a=cn(a));const p=C(n)?I(n):n;O.has(p)&&(a=null!=(c=k(a))?c:a);const h={t:o,v:a,e:fn(d,r)},m=null!=(f=t.tangentIn)?f:t.ti,b=null!=(s=t.tangentOut)?s:t.to;m&&(h.tangentIn=m),b&&(h.tangentOut=b),v.push(h)}v.sort((n,t)=>{var o,r;return(null!=(o=n.t)?o:0)-(null!=(r=t.t)?r:0)});const p=t.loop,h=!0===p?{}:p||void 0;return h&&v.length>=2?function(n,t,o,r){var e,l,i,u,c;const f=t.length-1,s=S(null!=(e=o.segmentCount)?e:f,1,f);let a;a=o.extend===d.before?t.slice(0,s+1):t.slice(f-s);const v=null!=(l=t[0].t)?l:0,p=null!=(i=t[t.length-1].t)?i:0;let h,m;o.extend===d.before?(h=0,m=v):(h=p,m=r);const b=m-h;if(b<=0)return t;const y=null!=(u=a[0].t)?u:0,g=(null!=(c=a[a.length-1].t)?c:0)-y;if(g<=0)return t;const M=a.map(n=>{var t,o;return{U:(n.t-y)/g,v:n.v,e:n.e,tangentIn:null!=(t=n.tangentIn)?t:n.ti,tangentOut:null!=(o=n.tangentOut)?o:n.to}}),k=Math.floor(b/g),O=b-k*g,U=O/g,C=[],T=o.extend!==d.before,I=t[t.length-1];function z(t,o,r){var e;let l;if(o){l=[];for(let n=M.length-1;n>=0;n--)l.push({U:1-M[n].U,v:M[n].v,e:n>0?j(M[n-1].e):void 0,tangentIn:M[n].tangentOut,tangentOut:M[n].tangentIn})}else l=M;const i=void 0!==r?r:1;for(let o=0;o<l.length;o++){const r=l[o];if(r.U>i+1e-9){const e=l[o-1],u=r.U-e.U,c=(i-e.U)/u,f=e.e?A(e.e)(c):c,s=an(n,e.v,r.v,f),{left:a}=w(e.e,c);return C.length>0&&e.U<=i&&(C[C.length-1].e=a),void C.push({t:t+i*g,v:s,e:void 0})}const u=C.length>0?C[C.length-1]:I,c=T&&0===o&&void 0!==u&&Math.abs((null!=(e=u.t)?e:0)-(t+r.U*g))<1e-9;if(c){if(rn(u.v,r.v))continue;C.length>0&&(delete u.tangentIn,delete u.tangentOut)}const f={t:t+r.U*g+(c?on:0),v:r.v,e:o<l.length-1?r.e:void 0};r.tangentIn&&(f.tangentIn=r.tangentIn),r.tangentOut&&(f.tangentOut=r.tangentOut),C.push(f)}}if(o.extend===d.before){U>1e-9&&function(t,o,r){let e;if(o){e=[];for(let n=M.length-1;n>=0;n--)e.push({U:1-M[n].U,v:M[n].v,e:n>0?j(M[n-1].e):void 0,tangentIn:M[n].tangentOut,tangentOut:M[n].tangentIn})}else e=M;const l=1-r;for(let o=0;o<e.length;o++){const r=e[o];if(r.U<l-1e-9)continue;const i=e[o-1];if(i&&i.U<l-1e-9&&r.U>l+1e-9){const o=r.U-i.U,e=(l-i.U)/o,u=i.e?A(i.e)(e):e,c=an(n,i.v,r.v,u),{right:f}=w(i.e,e);C.push({t:t,v:c,e:f})}const u={t:t+(r.U-l)*g,v:r.v,e:o<e.length-1?r.e:void 0};r.tangentIn&&(u.tangentIn=r.tangentIn),r.tangentOut&&(u.tangentOut=r.tangentOut),C.push(u)}}(h,!!o.alternate&&k%2==0,U);for(let n=0;n<k;n++){const t=k-1-n,r=!!o.alternate&&t%2==0;z(h+O+n*g,r)}}else{for(let n=0;n<k;n++){const t=!!o.alternate&&n%2==0;z(h+n*g,t)}if(U>1e-9){const n=!!o.alternate&&k%2==0;z(h+k*g,n,U)}}return o.extend===d.before?[...C,...t]:[...t,...C]}(n,v,h,o):v}var dn=0;function pn(n,t){const{startOn:o,outAction:r="continue",scrollIntoViewThreshold:e=0}=t,l=n.getRootElement();if(!l)return console.warn("setupAnimationTriggers: No root element found for animation."),n;let i=!1;const u=()=>{i&&(i=!1,n.setPlaybackRate(1)),n.play()},c=()=>{switch(r){case"pause":n.pause();break;case"reset":n.cancel();break;case"reverse":i=!0,n.setPlaybackRate(-1),n.play()}};switch(o){case"load":{const n=()=>u();"complete"===document.readyState?n():window.addEventListener("load",n,{once:!0});break}case"mouseOver":{let n=!1;const t=()=>{n=!0,u()},o=()=>{n&&c()};l.addEventListener("mouseenter",t),l.addEventListener("mouseleave",o);break}case"click":{const t=()=>{n.isPlaying()?c():u()};l.addEventListener("click",t);break}case"scrollIntoView":{const n=n=>{var t,o;const r=n.boundingClientRect,e=n.intersectionRect;if(!(null==r?void 0:r.height)||!e)return n.intersectionRatio;const l="undefined"!=typeof window&&window.innerHeight?window.innerHeight:1/0,i=null!=(o=null==(t=n.rootBounds)?void 0:t.height)?o:1/0,u=Math.min(l,i),c=Math.min(r.height,Number.isFinite(u)?u:r.height);return c>0?e.height/c:n.intersectionRatio},t=Array.from({length:21},(n,t)=>t/20);let o=!1;new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting&&n(t)>=e?(o=!0,u()):o&&(o=!1,c())})},{threshold:t}).observe(l);break}}return n}function hn(n){return"#"+n}function mn(n,t,o,r){var e,l;let i=null!=(e=n.v)?e:n.value;const u=null!=(l=n.e)?l:n.easing,c={offset:t,easing:u&&Array.isArray(u)?"cubic-bezier("+u.join(",")+")":void 0};let f,s=o;var a;return O.has(o)&&Array.isArray(i)?f=function(n){const t=Math.round(255*n[0]),o=Math.round(255*n[1]),r=Math.round(255*n[2]);return 4===n.length?"rgba("+t+","+o+","+r+","+n[3]+")":"rgb("+t+","+o+","+r+")"}(i):"transform"!==o||null===i||"object"!=typeof i||Array.isArray(i)?U.has(o)?(Array.isArray(i)&&("translate"===o&&(i=i.map(n=>n+"px")),i=i.join(",")),"rotate"===o&&(i+="deg"),f=o+"("+i+")",s="transform"):f="d"===o?'path("'+(i&&"object"==typeof i&&Array.isArray(i.paths)?i.paths:[]).map(n=>function(n,t=!1){var o,r,e,l;const i=n.v,u=n.i,c=n.o,f=n.c;if(!i.length)return"";const s=[],a=i.length;s.push("M"+i[0][0]+","+i[0][1]);for(let n=1;n<a;n++){const e=i[n-1],l=null!=(o=null==c?void 0:c[n-1])?o:e,f=null!=(r=null==u?void 0:u[n])?r:i[n],a=i[n];t||l[0]!==e[0]||l[1]!==e[1]||f[0]!==a[0]||f[1]!==a[1]?s.push("C"+l[0]+","+l[1]+","+f[0]+","+f[1]+","+a[0]+","+a[1]):s.push("L"+a[0]+","+a[1])}if(f&&a>0){const n=i[a-1],o=null!=(e=null==c?void 0:c[a-1])?e:n,r=null!=(l=null==u?void 0:u[0])?l:i[0],f=i[0];!t&&o[0]===n[0]&&o[1]===n[1]&&r[0]===f[0]&&r[1]===f[1]||s.push("C"+o[0]+","+o[1]+","+r[0]+","+r[1]+","+f[0]+","+f[1]),s.push("z")}return s.join("")}(n,!0)).join("")+'")':""+i:(f=function(n,t){var o;if(!n)return"";const r=null==(o=null==t?void 0:t.C)||o,e=[],l=n.translate,i=n.origin,u=n.rotate,c=n.skew,f=n.scale,s=r?"px":"",a=r?"deg":"";return l&&e.push("translate("+l[0]+s+","+l[1]+s+")"),i&&e.push("translate("+i[0]+s+","+i[1]+s+")"),null!=u&&e.push("rotate("+u+a+")"),null!=c&&e.push("skewX("+c+a+")"),f&&e.push("scale("+f[0]+","+f[1]+")"),i&&e.push("translate("+-i[0]+s+","+-i[1]+s+")"),e.join("")}(i,{C:!0}),s="transform"),CSS.supports(I(s),f)||r.add(s),s=(a=s).includes("-")?a.replace(/-([a-z])/g,(n,t)=>t.toUpperCase()):a,c[s]=f,c}function bn(n,t,o){var r,e,l,i,u;const c=[];for(let a=0;a<t.length;a++){const v=t[a],d=null!=(r=v.t)?r:0;if(d<0){const o=t[a+1];if(o&&(null!=(e=o.t)?e:0)>=0){const t=(0-d)/((null!=(l=o.t)?l:0)-d),r=v.e?A(v.e)(t):t,{right:e}=w(v.e,t);c.push({t:0,v:an(n,v.v,o.v,r),e:e})}continue}if(d>o){const r=t[a-1];if(r&&(null!=(i=r.t)?i:0)<=o){const t=null!=(u=r.t)?u:0,e=(o-t)/(d-t),l=r.e?A(r.e)(e):e,{left:i}=w(r.e,e);c.length>0&&(c[c.length-1]=s(f({},c[c.length-1]),{e:i})),c.push({t:o,v:an(n,r.v,v.v,l),e:void 0})}break}c.push(v)}return c}function yn(n,t,o){var r;const e=new Map;for(const[l,i]of Object.entries(n)){const n=o.duration||1,u=bn(l,i.kfs||i.keyframes||[],n),c=[];for(let o=0;o<u.length;o++){const e=u[o],i=mn(e,S((null!=(r=e.t)?r:0)/n,0,1),l,t);0===o&&(i.offset||0)>0&&c.push(s(f({},i),{offset:0})),c.push(i)}c.length>0&&(c[c.length-1].offset||0)<1&&c.push(s(f({},c[c.length-1]),{offset:1})),c.length>0&&e.set(l,c)}return e}function gn(n){const t=function(n){if(!(null==n?void 0:n.data))throw new Error("createAnimator: `data` is required");return n.data}(n);return function(n,o){let r,e=o;n.resetOnFinish&&(e=s(f({},o),{T:()=>{var n;null==(n=null==o?void 0:o.T)||n.call(o),null==r||r.cancel()}}));const l=function(n,t,o){var r;const e=p(n)||{};if(!o)if(n.id){const t=hn(n.id);(o=document.querySelector(t))||console.warn("createFrameLoopAnimator: No root element found for selector: ",t)}else console.warn("createFrameLoopAnimator: No root element provided");const l=function(n,t=v.waapi){const o=p(n)||{},r=function(n){var t;if(n)return null==(t=p(n))?void 0:t.definitions}(n),e=o.duration||1e3,l=[],i=(n,o)=>{if(!o)return null;const l=function(n,t){if(!n)return[];const o=[];if("string"==typeof n){const r=sn(n,t);r&&o.push(r)}else if(Array.isArray(n))for(const r of n){const n=sn(r,t);n&&o.push(n)}else o.push(n);return o}(o,r);if(0===l.length)return null;const i=function(n,t,o,r=v.waapi){const e={};for(const[l,i]of Object.entries(n)){const n=vn(l,i,t,o);if(n.length>0){const t={kfs:n};void 0!==i.autoOrient&&(t.autoOrient=i.autoOrient),void 0!==i.loop&&(t.loop=i.loop),e[l]=r===v.waapi&&"transform"===l?q(t):t}}return e}(function(n){const t={};for(const o of n)for(const[n,r]of Object.entries(o))t[n]=r;return t}(l),e,r,t);return 0===Object.keys(i).length?null:{id:n,animate:i}},u=function(n){var t;if(!n)return;const o=null==(t=p(n))?void 0:t.animateById;return o?Object.entries(o).map(([n,t])=>({id:n,animate:t})):void 0}(n);if(u)for(const n of u){const t=i(n.id,n.animate);t&&l.push(t)}const c=n=>{const t=n.animate;if(t&&Object.keys(t).length>0){const o=n.id||"_px_el_"+ ++dn;n.id=o;const r=i(o,t);r&&l.push(r)}if(n.children)for(let t=0;t<n.children.length;t++)c(n.children[t])};if(n.children)for(let t=0;t<n.children.length;t++)c(n.children[t]);return l}(n,v.waapi),i=[],u=e.iterations;let c;"number"==typeof u&&(c=u),"infinite"===u&&(c=1/0);const f=new Set;let s=!1,a=!1;(null==l?void 0:l.length)||console.warn("createWebApiAnimator: No animation bindings defined");for(const n of l||[]){const l=n.animate;if(!l||"object"!=typeof l||Array.isArray(l)){console.warn("createWebApiAnimator: Empty or unresolved binding",n);continue}const u=hn(n.id),v=(null==o?void 0:o.querySelectorAll(u))||document.querySelectorAll(u);0===v.length&&console.warn('createWebApiAnimator: No elements found for selector "'+u+'"');const d=yn(l,f,e),p=e.delay&&e.delay>0?e.delay:void 0;let h;if(e.delay&&e.delay<0&&e.duration){const n=-e.delay;h=c===1/0?n%e.duration:Math.min(n,e.duration*(null!=c?c:1))}const m={duration:e.duration,delay:p,fill:null!=(r=e.fill)?r:"forwards",direction:e.direction,iterations:c};for(let n=0;n<v.length;n++){const o=v[n];for(const[,n]of d)if(n.length>0)try{const r=new KeyframeEffect(o,n,m),e=new Animation(r,document.timeline);(null==t?void 0:t.T)&&(e.onfinish=()=>{var n;s||(s=!0,null==(n=t.T)||n.call(t))}),(null==t?void 0:t.I)&&(e.onremove=()=>{var n;a||(a=!0,null==(n=t.I)||n.call(t))}),void 0!==h&&(e.currentTime=h),i.push(e)}catch(n){console.warn(n)}}}const d={isReady:()=>!0,getRootElement:()=>o||null,isPlaying:()=>{var n;return"running"===(null==(n=i[0])?void 0:n.playState)},play:()=>{var n;s=!1,i.forEach(n=>n.play()),null==(n=null==t?void 0:t.S)||n.call(t)},pause:()=>{var n;i.forEach(n=>n.pause()),null==(n=null==t?void 0:t.L)||n.call(t)},cancel:()=>{var n;s=!1,i.forEach(n=>n.cancel()),null==(n=null==t?void 0:t.P)||n.call(t)},finish:()=>{var n;for(const t of i)try{(null==(n=t.effect)?void 0:n.getTiming().iterations)===1/0?(t.effect.updateTiming({iterations:1}),t.finish(),t.effect.updateTiming({iterations:1/0})):t.finish()}catch(n){t.cancel()}},setPlaybackRate:n=>(i.forEach(t=>t.playbackRate=n),d),getCurrentTime:()=>{var n,t;const o=null!=(t=null==(n=i[0])?void 0:n.currentTime)?t:null;return null!==o?+o:null},setCurrentTime:n=>{s=!1,i.forEach(t=>{t.currentTime=n})},destroy:()=>{var n;d.cancel(),i.splice(0,i.length),a||(a=!0,null==(n=null==t?void 0:t.I)||n.call(t))}};return e.trigger&&pn(d,e.trigger),d}(t,e,null);return r=l,n.debugInstName&&(window[n.debugInstName]=l),l}(p(t)||{},n.N)}var An,Mn="data";return An=a,((t,r,l,u)=>{if(r&&"object"==typeof r||"function"==typeof r)for(let l of e(r))i.call(t,l)||void 0===l||n(t,l,{get:()=>r[l],enumerable:!(u=o(r,l))||u.enumerable});return t})(n({},"__esModule",{value:!0}),An)})();
|