/** Direct DOM transforms for path playback — avoids React re-renders on every RAF tick. */ export type TokenPathViewport = { x: number; y: number; w: number; h: number }; type NodeReg = { el: HTMLElement; viewport: TokenPathViewport; rotate: boolean; }; const registry = new Map(); export function writeTokenPathTransform( el: HTMLElement, nx: number, ny: number, rotationDeg: number, viewport: TokenPathViewport, rotate: boolean, ): void { const x = viewport.x + nx * viewport.w; const y = viewport.y + ny * viewport.h; const rot = rotate ? ` rotate(${String(rotationDeg)}deg)` : ''; el.style.transform = `translate3d(${String(x)}px, ${String(y)}px, 0) translate(-50%, -50%)${rot}`; } export function registerPathTokenNode( key: string, el: HTMLElement | null, viewport: TokenPathViewport, rotate: boolean, ): void { if (!el) { registry.delete(key); return; } registry.set(key, { el, viewport, rotate }); } export function applyLivePathPose( key: string, nx: number, ny: number, rotationDeg: number, animating: boolean, ): void { const n = registry.get(key); if (!n) return; n.el.dataset.pathLive = '1'; n.el.style.willChange = animating ? 'transform' : ''; writeTokenPathTransform(n.el, nx, ny, rotationDeg, n.viewport, n.rotate); } export function endLivePathPose(key: string): void { const n = registry.get(key); if (!n) return; delete n.el.dataset.pathLive; n.el.style.willChange = ''; } export function endAllLivePathPoses(): void { for (const key of [...registry.keys()]) { endLivePathPose(key); } }