@pixerate/flair 0.24.0 → 0.26.0

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +1 -0
  3. package/dist/catalog/index.js +2 -2
  4. package/dist/{chunk-WAMA45G3.js → chunk-5USSDEQL.js} +77 -21
  5. package/dist/chunk-5USSDEQL.js.map +1 -0
  6. package/dist/{chunk-GTIAOYOK.js → chunk-74ZLCZOG.js} +13 -10
  7. package/dist/chunk-74ZLCZOG.js.map +1 -0
  8. package/dist/{chunk-NGKNI3QX.js → chunk-CK6EV37I.js} +19 -495
  9. package/dist/chunk-CK6EV37I.js.map +1 -0
  10. package/dist/chunk-DBTLCXKY.js +332 -0
  11. package/dist/chunk-DBTLCXKY.js.map +1 -0
  12. package/dist/chunk-G2B5L234.js +414 -0
  13. package/dist/chunk-G2B5L234.js.map +1 -0
  14. package/dist/{chunk-VP6IEWIK.js → chunk-H6L67KHI.js} +1 -1
  15. package/dist/chunk-H6VDFBIO.js +498 -0
  16. package/dist/chunk-H6VDFBIO.js.map +1 -0
  17. package/dist/{chunk-OQ4EWZ3B.js → chunk-HVXWNGTW.js} +83 -6
  18. package/dist/{chunk-OQ4EWZ3B.js.map → chunk-HVXWNGTW.js.map} +1 -1
  19. package/dist/chunk-JL6TI6II.js +724 -0
  20. package/dist/chunk-JL6TI6II.js.map +1 -0
  21. package/dist/{chunk-OHW7UG6D.js → chunk-ORAFCHX3.js} +26 -2
  22. package/dist/{chunk-OHW7UG6D.js.map → chunk-ORAFCHX3.js.map} +1 -1
  23. package/dist/{chunk-ARKC7LDW.js → chunk-RDU63CDO.js} +2 -331
  24. package/dist/chunk-RDU63CDO.js.map +1 -0
  25. package/dist/{chunk-LVPIIWPP.js → chunk-STKEKXCK.js} +18 -8
  26. package/dist/chunk-STKEKXCK.js.map +1 -0
  27. package/dist/chunk-UCZ43ARE.js +902 -0
  28. package/dist/chunk-UCZ43ARE.js.map +1 -0
  29. package/dist/chunk-YBGRXVAE.js +407 -0
  30. package/dist/chunk-YBGRXVAE.js.map +1 -0
  31. package/dist/cli.js +74 -11
  32. package/dist/cli.js.map +1 -1
  33. package/dist/editor/index.d.ts +1 -1
  34. package/dist/editor/index.js +14 -12
  35. package/dist/editor/index.js.map +1 -1
  36. package/dist/effect-GGH3OSOT.js +47 -0
  37. package/dist/embed/index.d.ts +215 -0
  38. package/dist/embed/index.js +21 -0
  39. package/dist/{export-DH2HMACO.js → export-QVW474KM.js} +3 -3
  40. package/dist/export-QVW474KM.js.map +1 -0
  41. package/dist/frames-VEcqa40g.d.ts +161 -0
  42. package/dist/index.d.ts +47 -164
  43. package/dist/index.js +102 -80
  44. package/dist/index.js.map +1 -1
  45. package/dist/node.d.ts +167 -7
  46. package/dist/node.js +25 -3
  47. package/dist/react/index.d.ts +33 -2
  48. package/dist/react/index.js +54 -9
  49. package/dist/react/index.js.map +1 -1
  50. package/dist/recorder-CDPPTJMG.js +31 -0
  51. package/dist/recorder-CDPPTJMG.js.map +1 -0
  52. package/dist/{renderer-C2P1qGzP.d.ts → renderer-teaa98RE.d.ts} +1 -1
  53. package/dist/svelte/index.d.ts +33 -4
  54. package/dist/svelte/index.js +51 -9
  55. package/dist/svelte/index.js.map +1 -1
  56. package/dist/vector/index.d.ts +52 -1
  57. package/dist/vector/index.js +8 -4
  58. package/package.json +1 -1
  59. package/dist/chunk-ARKC7LDW.js.map +0 -1
  60. package/dist/chunk-GTIAOYOK.js.map +0 -1
  61. package/dist/chunk-LVPIIWPP.js.map +0 -1
  62. package/dist/chunk-NGKNI3QX.js.map +0 -1
  63. package/dist/chunk-UP6QQVRS.js +0 -331
  64. package/dist/chunk-UP6QQVRS.js.map +0 -1
  65. package/dist/chunk-WAMA45G3.js.map +0 -1
  66. package/dist/recorder-HKFFHQES.js +0 -10
  67. /package/dist/{chunk-VP6IEWIK.js.map → chunk-H6L67KHI.js.map} +0 -0
  68. /package/dist/{export-DH2HMACO.js.map → effect-GGH3OSOT.js.map} +0 -0
  69. /package/dist/{recorder-HKFFHQES.js.map → embed/index.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/export/recorder.ts"],"sourcesContent":["// gifenc ships without types; the reference brings them along.\n/// <reference path=\"../shader/gifenc.d.ts\" />\nimport http from 'node:http';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { controlValue, parseControls, type ControlValue, type TextureSettings } from '../shader/controls.js';\nimport { MAX_CLICKS, MAX_TRAIL, PointerTracker, TRAIL_SECONDS } from '../shader/pointer.js';\nimport { VERTEX_SOURCE, wrapSource } from '../shader/program.js';\nimport { SVG_EDGE } from '../shader/textures.js';\n\n// ==========================================\n// Tools: Chrome and ffmpeg\n// ==========================================\n\nconst CHROME_CANDIDATES = [\n '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n '/Applications/Chromium.app/Contents/MacOS/Chromium',\n 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium',\n '/usr/bin/chromium-browser',\n];\n\n/** Chromium builds Playwright downloaded (`npx playwright install chromium`), newest first. */\nfunction playwrightChromes(): string[] {\n const roots = [\n process.env.PLAYWRIGHT_BROWSERS_PATH,\n path.join(os.homedir(), 'Library/Caches/ms-playwright'),\n path.join(os.homedir(), '.cache/ms-playwright'),\n ].filter((r): r is string => Boolean(r));\n const found: string[] = [];\n for (const root of roots) {\n let dirs: string[] = [];\n try {\n dirs = fs.readdirSync(root).filter((d) => /^chromium-\\d+$/.test(d));\n } catch {\n continue;\n }\n dirs.sort((a, b) => Number(b.split('-')[1]) - Number(a.split('-')[1]));\n for (const dir of dirs) {\n for (const bin of [\n 'chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',\n 'chrome-mac/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',\n 'chrome-mac/Chromium.app/Contents/MacOS/Chromium',\n 'chrome-linux/chrome',\n 'chrome-linux64/chrome',\n ]) found.push(path.join(root, dir, bin));\n }\n }\n return found;\n}\n\n/**\n * Finds a local Chrome or Chromium executable, or `null`: `CHROME_PATH` (or\n * `CHROME_BIN`), then the usual install places, then a Chromium Playwright\n * downloaded.\n */\nexport function findChrome(): string | null {\n const env = process.env.CHROME_PATH || process.env.CHROME_BIN;\n if (env) return env;\n return [...CHROME_CANDIDATES, ...playwrightChromes()].find((candidate) => fs.existsSync(candidate)) ?? null;\n}\n\n/** The ffmpeg to run: `FFMPEG_PATH`, else `ffmpeg` on the `PATH`. */\nexport function ffmpegPath(): string {\n return process.env.FFMPEG_PATH || 'ffmpeg';\n}\n\nconst NO_FFMPEG =\n 'ffmpeg is not installed (or not on the PATH). Install it (brew install ffmpeg, apt install ffmpeg), or set FFMPEG_PATH; GIF, PNG and SVG output do not need it.';\n\n// ==========================================\n// Output formats\n// ==========================================\n\n/** A file type the exporter writes, from the output path. */\nexport type OutputFormat = 'mp4' | 'webm' | 'mov' | 'gif' | 'png' | 'svg';\n\n/** What to write and how. */\nexport interface OutputPlan {\n format: OutputFormat;\n /** The output path, resolved. For a PNG sequence, a printf pattern (`…/frame_%04d.png`). */\n path: string;\n /** Whether the frames keep their alpha. */\n alpha: boolean;\n /** ffmpeg's arguments after the input (for mp4, webm and mov). */\n ffmpegArgs?: string[];\n}\n\n/**\n * Works out the format from `outputPath`'s extension and what alpha it can\n * keep. A path with no extension, or ending in a slash, is a folder of PNG\n * frames; a `.png` path with a `%d` pattern (`out_%04d.png`) names each\n * frame, and one without gets `_%04d` added (unless there is one frame).\n * Throws a sentence for formats it cannot write, and for alpha in MP4.\n */\nexport function planOutput(outputPath: string, options: { alpha?: boolean; frames?: number } = {}): OutputPlan {\n const resolved = path.resolve(process.cwd(), outputPath);\n const trailingSlash = /[\\\\/]$/.test(outputPath);\n const ext = trailingSlash ? '' : path.extname(resolved).toLowerCase();\n const alpha = Boolean(options.alpha);\n switch (ext) {\n case '': {\n return { format: 'png', path: path.join(resolved, 'frame_%04d.png'), alpha };\n }\n case '.png': {\n if (/%0?\\d*d/.test(resolved) || (options.frames ?? 2) === 1) return { format: 'png', path: resolved, alpha };\n return { format: 'png', path: resolved.replace(/\\.png$/i, '_%04d.png'), alpha };\n }\n case '.gif':\n return { format: 'gif', path: resolved, alpha };\n case '.svg':\n return { format: 'svg', path: resolved, alpha };\n case '.mp4':\n case '.m4v': {\n if (alpha) throw new Error('MP4 (H.264) cannot hold alpha; write .webm, .mov, .gif or .png frames for a transparent render, or drop --alpha.');\n return {\n format: 'mp4',\n path: resolved,\n alpha,\n ffmpegArgs: [\n // yuv420p needs even sizes; sRGB pixels go to BT.709, tagged so players show the same colours.\n '-vf', 'pad=ceil(iw/2)*2:ceil(ih/2)*2,scale=out_color_matrix=bt709:out_range=tv,format=yuv420p',\n '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-crf', '18', '-preset', 'medium',\n '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709', '-color_range', 'tv',\n '-movflags', '+faststart',\n ],\n };\n }\n case '.webm':\n return {\n format: 'webm',\n path: resolved,\n alpha,\n ffmpegArgs: alpha\n ? ['-c:v', 'libvpx-vp9', '-pix_fmt', 'yuva420p', '-b:v', '0', '-crf', '30', '-auto-alt-ref', '0', '-row-mt', '1']\n : ['-vf', 'scale=out_color_matrix=bt709:out_range=tv,format=yuv420p', '-c:v', 'libvpx-vp9', '-pix_fmt', 'yuv420p', '-b:v', '0', '-crf', '30', '-row-mt', '1',\n '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709'],\n };\n case '.mov':\n return {\n format: 'mov',\n path: resolved,\n alpha,\n ffmpegArgs: [\n '-c:v', 'prores_ks', '-profile:v', '4444', '-vendor', 'apl0',\n '-pix_fmt', alpha ? 'yuva444p10le' : 'yuv444p10le',\n ...(alpha ? ['-alpha_bits', '16'] : []),\n '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709',\n ],\n };\n default:\n throw new Error(`Flair cannot write \"${ext}\" files; write .mp4, .webm, .mov, .gif, .svg, or .png frames (a folder, or a pattern like out_%04d.png).`);\n }\n}\n\n/** A frame number put into a PNG sequence's printf pattern (`%04d`, `%d`). */\nexport function sequencePath(pattern: string, frame: number): string {\n return pattern.replace(/%(0?)(\\d*)d/, (_, zero: string, width: string) => String(frame).padStart(Number(width || 0), zero ? '0' : ' '));\n}\n\n// ==========================================\n// The pointer, scripted\n// ==========================================\n\n/** Pointer uniforms for one frame. */\nexport interface PointerFrame {\n mouse: [number, number, number, number];\n pointer: [number, number, number, number];\n /** `iClicks`, MAX_CLICKS × 4 numbers. */\n clicks: number[];\n /** `iTrail`, MAX_TRAIL × 4 numbers. */\n trail: number[];\n}\n\n/**\n * A pointer that shows off an interactive shader in a recording: it hovers\n * over the canvas from the start, wanders a figure-of-eight (so trails have\n * a path), and clicks every `interval` seconds, holding each press for a\n * moment. Returns the uniforms for each frame time, in order.\n */\nexport function scriptedPointer(width: number, height: number, times: readonly number[], options: { interval?: number; period?: number } = {}): PointerFrame[] {\n const interval = options.interval ?? 0.8;\n const period = Math.max(2, options.period ?? (times[times.length - 1] ?? 2));\n const at = (t: number): [number, number] => [\n width * (0.5 + 0.3 * Math.sin((2 * Math.PI * t) / period)),\n height * (0.5 + 0.22 * Math.sin((4 * Math.PI * t) / period)),\n ];\n const press = 0.25;\n const tracker = new PointerTracker();\n tracker.hover(true, 0);\n tracker.move(...at(0), 0);\n let clock = 0;\n let nextClick = 0.25;\n let release = Infinity;\n let mouse: [number, number, number, number] = [0, 0, 0, 0];\n const frames: PointerFrame[] = [];\n for (const time of times) {\n // Walk the script up to `time` in trail-sized steps, so the trail and clicks land where they would live.\n while (clock < time) {\n const next = Math.min(time, clock + TRAIL_SECONDS, nextClick, release);\n clock = next;\n const [x, y] = at(clock);\n tracker.move(x, y, clock);\n if (mouse[2] > 0) mouse = [x, y, mouse[2], mouse[3]];\n if (clock >= release) {\n tracker.up(clock);\n mouse = [mouse[0], mouse[1], -mouse[2], -Math.abs(mouse[3])];\n release = Infinity;\n }\n if (clock >= nextClick) {\n tracker.down(x, y, clock);\n mouse = [x, y, x, y];\n release = clock + press;\n nextClick = clock + interval;\n }\n }\n frames.push({\n mouse: [...mouse],\n pointer: tracker.pointer(time),\n clicks: [...tracker.clicksAt(time)],\n trail: [...tracker.trailAt(time)],\n });\n }\n return frames;\n}\n\n// ==========================================\n// The page\n// ==========================================\n\n/** A shader control as the page sets it. */\nexport interface PageControl {\n name: string;\n type: string;\n value: ControlValue;\n texture?: TextureSettings;\n}\n\n/** What the render page draws. */\nexport interface PageConfig {\n width: number;\n height: number;\n frames: number;\n /** Keep alpha in the frames (else they are composited over `background`). */\n alpha: boolean;\n /** CSS colour under transparent pixels when `alpha` is false. */\n background: string;\n /** How frames go back: PNG files, or raw RGBA (rows top down). */\n send: 'png' | 'rgba';\n /** A shader to run, or (when absent) SVG frame markup from `/state`. */\n shader?: {\n /** The full GLSL ES 3.00 fragment shader (see {@link fragmentSource}). */\n fragment: string;\n controls: PageControl[];\n /** Draws its frame opaque, as `ShaderRenderer` does without `alpha`: its own alpha is ignored. */\n opaque: boolean;\n };\n}\n\n/** JSON that is safe inside a `<script>`. */\nconst scriptJson = (value: unknown) => JSON.stringify(value).replace(/</g, '\\\\u003c');\n\n/**\n * The page headless Chrome runs: it compiles the shader with the same\n * wrapper as `ShaderRenderer` (`wrapSource`, so every built-in, `iPointer`,\n * `iClicks` and `iTrail` included, is declared), sets each control by its\n * type (`int` and `bool` as integers), loads image controls the way\n * `loadImage` does (SVGs sized to their long edge first) before the first\n * frame, and flips them as the renderer does. Each frame asks `/state` for\n * its time, pointer, video frames or SVG markup, draws, and posts the\n * pixels to `/frame`.\n */\nexport function renderPageHtml(config: PageConfig): string {\n return `<!doctype html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<style>html,body{margin:0;background:transparent;overflow:hidden}</style>\n</head>\n<body>\n<script>\nconst CONFIG = ${scriptJson(config)};\nconst VERTEX = ${scriptJson(VERTEX_SOURCE)};\nconst W = CONFIG.width, H = CONFIG.height;\nconst report = (message) => fetch(\"/error\", { method: \"POST\", body: String(message) });\naddEventListener(\"error\", (e) => report(\"The render page failed: \" + e.message));\naddEventListener(\"unhandledrejection\", (e) => report((e.reason && e.reason.message) || String(e.reason)));\n\n// SVGs decode at their own (often icon) size: give them ${SVG_EDGE} px on the long edge, and a viewBox.\nfunction sizeSvg(markup, w0, h0) {\n const doc = new DOMParser().parseFromString(markup, \"image/svg+xml\");\n const svg = doc.documentElement;\n if (svg.localName !== \"svg\" || doc.getElementsByTagName(\"parsererror\").length) throw new Error(\"Not an SVG document.\");\n const len = (n) => { const m = (svg.getAttribute(n) || \"\").trim().match(/^([\\\\d.]+)(px)?$/); return m && +m[1] > 0 ? +m[1] : 0; };\n const box = (svg.getAttribute(\"viewBox\") || \"\").trim().split(/[\\\\s,]+/).map(Number);\n const hasBox = box.length === 4 && box[2] > 0 && box[3] > 0;\n const w = len(\"width\") || (hasBox ? box[2] : 300), h = len(\"height\") || (hasBox ? box[3] : 150);\n if (!hasBox) svg.setAttribute(\"viewBox\", \"0 0 \" + w + \" \" + h);\n const scale = w0 ? 1 : ${SVG_EDGE} / Math.max(w, h);\n svg.setAttribute(\"width\", w0 || Math.max(1, Math.round(w * scale)));\n svg.setAttribute(\"height\", h0 || Math.max(1, Math.round(h * scale)));\n return new XMLSerializer().serializeToString(svg);\n}\nconst isSvg = (url) => /^data:image\\\\/svg\\\\+xml[;,]/i.test(url) || /^(?!data:)[^?#]*\\\\.svg([?#]|$)/i.test(url);\nasync function decode(src, name) {\n const img = new Image();\n img.src = src;\n try { await img.decode(); } catch (e) { throw new Error(\"Could not load the image \" + name + \".\"); }\n return img;\n}\nasync function loadImage(url, name) {\n if (!isSvg(url)) return decode(url, name);\n const text = await (await fetch(url)).text();\n const blob = URL.createObjectURL(new Blob([sizeSvg(text)], { type: \"image/svg+xml\" }));\n try { return await decode(blob, name); } finally { URL.revokeObjectURL(blob); }\n}\n\nconst out = document.createElement(\"canvas\");\nout.width = W; out.height = H;\nconst ctx = out.getContext(\"2d\", { willReadFrequently: CONFIG.send === \"rgba\" });\nlet gl = null, glCanvas = null, u = null;\nconst textures = {};\n\nfunction setupShader() {\n glCanvas = document.createElement(\"canvas\");\n glCanvas.width = W; glCanvas.height = H;\n // As createContext: no antialiasing, depth or stencil; unpremultiplied alpha so pixels read back exactly.\n gl = glCanvas.getContext(\"webgl2\", { alpha: true, premultipliedAlpha: false, preserveDrawingBuffer: true, antialias: false, depth: false, stencil: false, powerPreference: \"high-performance\" });\n if (!gl) throw new Error(\"WebGL2 is not available in headless Chrome.\");\n const compile = (type, src) => {\n const s = gl.createShader(type);\n gl.shaderSource(s, src);\n gl.compileShader(s);\n if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(\"The shader does not compile: \" + gl.getShaderInfoLog(s));\n return s;\n };\n const program = gl.createProgram();\n gl.attachShader(program, compile(gl.VERTEX_SHADER, VERTEX));\n gl.attachShader(program, compile(gl.FRAGMENT_SHADER, CONFIG.shader.fragment));\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw new Error(\"The shader does not link: \" + gl.getProgramInfoLog(program));\n gl.useProgram(program);\n u = (n) => gl.getUniformLocation(program, n);\n gl.viewport(0, 0, W, H);\n if (CONFIG.shader.opaque) {\n // An opaque canvas, as ShaderRenderer has without alpha: alpha stays 1 whatever the shader writes.\n gl.clearColor(0, 0, 0, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.colorMask(true, true, true, false);\n }\n}\n\nfunction makeTexture(unit, texture) {\n const t = gl.createTexture();\n const settings = texture || { filter: \"mipmap\", wrap: \"repeat\" };\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, t);\n // Black until (or unless) a picture arrives, as TextureCache does.\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 255]));\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, { mipmap: gl.LINEAR_MIPMAP_LINEAR, linear: gl.LINEAR, nearest: gl.NEAREST }[settings.filter]);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, settings.filter === \"nearest\" ? gl.NEAREST : gl.LINEAR);\n const wrap = { repeat: gl.REPEAT, clamp: gl.CLAMP_TO_EDGE, mirror: gl.MIRRORED_REPEAT }[settings.wrap];\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);\n return { unit, texture: t };\n}\n\nfunction upload(name, img) {\n const slot = textures[name];\n if (!slot) return;\n gl.activeTexture(gl.TEXTURE0 + slot.unit);\n gl.bindTexture(gl.TEXTURE_2D, slot.texture);\n // Rows bottom up, as the renderer's TextureCache uploads them.\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.generateMipmap(gl.TEXTURE_2D);\n}\n\nasync function setControls() {\n let unit = 0;\n const loads = [];\n for (const c of CONFIG.shader.controls) {\n const loc = u(c.name);\n const v = c.value;\n if (c.type === \"sampler2D\") {\n textures[c.name] = makeTexture(unit, c.texture);\n if (loc) gl.uniform1i(loc, unit);\n unit++;\n if (v) loads.push(loadImage(v, \"for \" + c.name).then((img) => upload(c.name, img)));\n continue;\n }\n if (!loc) continue;\n if (c.type === \"float\") gl.uniform1f(loc, v);\n else if (c.type === \"int\") gl.uniform1i(loc, Math.round(v));\n else if (c.type === \"bool\") gl.uniform1i(loc, v ? 1 : 0);\n else if (Array.isArray(v)) gl[\"uniform\" + v.length + \"fv\"](loc, v);\n }\n await Promise.all(loads);\n}\n\nfunction drawShader(s) {\n gl.viewport(0, 0, W, H);\n const set = (n, f) => { const l = u(n); if (l) f(l); };\n set(\"iResolution\", (l) => gl.uniform3f(l, W, H, 1));\n set(\"iTime\", (l) => gl.uniform1f(l, s.time));\n set(\"iTimeDelta\", (l) => gl.uniform1f(l, s.delta));\n set(\"iFrame\", (l) => gl.uniform1i(l, s.frame));\n set(\"iMouse\", (l) => gl.uniform4fv(l, s.mouse));\n set(\"iPointer\", (l) => gl.uniform4fv(l, s.pointer));\n set(\"iClicks\", (l) => gl.uniform4fv(l, new Float32Array(s.clicks)));\n set(\"iTrail\", (l) => gl.uniform4fv(l, new Float32Array(s.trail)));\n // glslsandbox-style names, for complete programs.\n set(\"u_resolution\", (l) => gl.uniform2f(l, W, H));\n set(\"u_time\", (l) => gl.uniform1f(l, s.time));\n set(\"u_mouse\", (l) => gl.uniform2f(l, s.pointer[0], s.pointer[1]));\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n}\n\nasync function frameImage(s) {\n if (CONFIG.shader) {\n for (const [name, url] of Object.entries(s.video || {})) upload(name, await decode(url, \"of the video frame\"));\n drawShader(s);\n return glCanvas;\n }\n const markup = sizeSvg(s.svg, W, H);\n const url = URL.createObjectURL(new Blob([markup], { type: \"image/svg+xml\" }));\n try { return await decode(url, \"of the SVG frame\"); } finally { URL.revokeObjectURL(url); }\n}\n\nasync function capture(src) {\n // The WebGL canvas reads back exactly when nothing is composited under it.\n const direct = CONFIG.shader && (CONFIG.alpha || CONFIG.shader.opaque);\n if (direct) {\n if (CONFIG.send === \"png\") return new Promise((r) => glCanvas.toBlob(r, \"image/png\"));\n const px = new Uint8Array(W * H * 4);\n gl.readPixels(0, 0, W, H, gl.RGBA, gl.UNSIGNED_BYTE, px);\n const flipped = new Uint8Array(px.length), row = W * 4;\n for (let y = 0; y < H; y++) flipped.set(px.subarray((H - 1 - y) * row, (H - y) * row), y * row);\n return flipped;\n }\n ctx.clearRect(0, 0, W, H);\n if (!CONFIG.alpha) { ctx.fillStyle = CONFIG.background; ctx.fillRect(0, 0, W, H); }\n ctx.drawImage(src, 0, 0, W, H);\n if (CONFIG.send === \"png\") return new Promise((r) => out.toBlob(r, \"image/png\"));\n return ctx.getImageData(0, 0, W, H).data;\n}\n\n(async () => {\n if (CONFIG.shader) { setupShader(); await setControls(); }\n for (let i = 0; i < CONFIG.frames; i++) {\n const s = await (await fetch(\"/state?i=\" + i)).json();\n const body = await capture(await frameImage(s));\n const r = await fetch(\"/frame?i=\" + i, { method: \"POST\", body });\n if (!r.ok) return;\n }\n})().catch((e) => report((e && e.message) || String(e)));\n</script>\n</body>\n</html>\n`;\n}\n\n// ==========================================\n// The render loop\n// ==========================================\n\n/** One frame's state, as the page asks for it. */\nexport interface FrameState {\n time: number;\n delta: number;\n frame: number;\n mouse: [number, number, number, number];\n pointer: [number, number, number, number];\n clicks: number[];\n trail: number[];\n /** SVG markup to draw (vector frames). */\n svg?: string;\n /** Image control → local file to show this frame (video frames). */\n video?: Record<string, string>;\n}\n\n/** A render: the page to run, each frame's state, and where it goes. */\nexport interface RenderJob {\n page: PageConfig;\n state: (frame: number) => FrameState;\n plan: OutputPlan;\n fps: number;\n onProgress?: (frame: number, total: number) => void;\n}\n\n/** Frames written somewhere: a sink takes them in order and finishes. */\ninterface Sink {\n write(frame: number, data: Buffer): Promise<void>;\n finish(): Promise<void>;\n abort(): void;\n}\n\nfunction ffmpegSink(plan: OutputPlan, fps: number): Sink {\n const args = ['-y', '-hide_banner', '-loglevel', 'error', '-f', 'image2pipe', '-framerate', String(fps), '-c:v', 'png', '-i', '-', ...plan.ffmpegArgs!, '-r', String(fps), plan.path];\n const proc = spawn(ffmpegPath(), args, { stdio: ['pipe', 'ignore', 'pipe'] });\n let stderr = '';\n let failed: Error | null = null;\n proc.stderr!.on('data', (d) => (stderr += d.toString()));\n const done = new Promise<void>((resolve, reject) => {\n proc.on('error', (err: NodeJS.ErrnoException) => {\n failed = err.code === 'ENOENT' ? new Error(NO_FFMPEG) : new Error(`ffmpeg could not start: ${err.message}`);\n reject(failed);\n });\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject((failed ??= new Error(`ffmpeg failed (exit ${code}): ${stderr.trim() || 'no message'}`)));\n });\n });\n done.catch(() => {});\n proc.stdin!.on('error', () => {});\n return {\n async write(_frame, data) {\n if (failed) throw failed;\n if (!proc.stdin!.write(data)) await new Promise((r) => proc.stdin!.once('drain', r));\n },\n async finish() {\n proc.stdin!.end();\n await done;\n },\n abort() {\n proc.kill('SIGKILL');\n },\n };\n}\n\nfunction pngSink(plan: OutputPlan): Sink {\n fs.mkdirSync(path.dirname(plan.path), { recursive: true });\n return {\n async write(frame, data) {\n await fs.promises.writeFile(plan.path.includes('%') ? sequencePath(plan.path, frame) : plan.path, data);\n },\n async finish() {},\n abort() {},\n };\n}\n\nasync function gifSink(plan: OutputPlan, width: number, height: number, fps: number): Promise<Sink> {\n // gifenc is CommonJS in Node: its functions may only be on the default export.\n const mod = (await import('gifenc')) as Partial<typeof import('gifenc')> & { default?: typeof import('gifenc') };\n const { GIFEncoder, quantize, applyPalette } = (typeof mod.GIFEncoder === 'function' ? mod : mod.default!) as typeof import('gifenc');\n const gif = GIFEncoder();\n const delay = 1000 / fps;\n return {\n async write(frame, data) {\n const rgba = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n const first = frame === 0 ? { repeat: 0 } : {};\n if (plan.alpha) {\n // One-bit alpha: each frame replaces the last (dispose 2), with a transparent palette entry.\n const palette = quantize(rgba, 256, { format: 'rgba4444', oneBitAlpha: true });\n const transparentIndex = palette.findIndex((c) => c[3] === 0);\n gif.writeFrame(applyPalette(rgba, palette, 'rgba4444'), width, height, {\n palette,\n delay,\n dispose: 2,\n ...(transparentIndex >= 0 ? { transparent: true, transparentIndex } : {}),\n ...first,\n });\n } else {\n const palette = quantize(rgba, 256);\n gif.writeFrame(applyPalette(rgba, palette), width, height, { palette, delay, ...first });\n }\n },\n async finish() {\n gif.finish();\n fs.mkdirSync(path.dirname(plan.path), { recursive: true });\n await fs.promises.writeFile(plan.path, gif.bytes());\n },\n abort() {},\n };\n}\n\n/** Chrome's flags: GPU WebGL where there is one (Metal on macOS), SwiftShader otherwise. */\nfunction chromeArgs(userDataDir: string, width: number, height: number, url: string): string[] {\n return [\n '--headless=new',\n `--user-data-dir=${userDataDir}`,\n `--window-size=${Math.max(64, width)},${Math.max(64, height)}`,\n '--use-gl=angle',\n ...(process.platform === 'darwin' ? ['--use-angle=metal'] : []),\n '--enable-webgl',\n '--enable-unsafe-swiftshader',\n '--ignore-gpu-blocklist',\n '--disable-gpu-sandbox',\n '--force-color-profile=srgb',\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-renderer-backgrounding',\n '--disable-extensions',\n url,\n ];\n}\n\nconst STALL_MS = 60_000;\n\n/**\n * Runs a render: serves the page to headless Chrome on 127.0.0.1, hands it\n * each frame's state, and writes the frames it posts back. Resolves with the\n * output path (a PNG sequence's pattern).\n */\nexport async function runRender(job: RenderJob): Promise<string> {\n const { page, plan, fps, onProgress } = job;\n const total = page.frames;\n const chromeBin = findChrome();\n if (!chromeBin) {\n throw new Error('Chrome or Chromium is needed to render, and none was found. Install Google Chrome, run \"npx playwright install chromium\", or set CHROME_PATH.');\n }\n fs.mkdirSync(path.dirname(plan.path), { recursive: true });\n const sink = plan.format === 'gif' ? await gifSink(plan, page.width, page.height, fps) : plan.format === 'png' ? pngSink(plan) : ffmpegSink(plan, fps);\n const html = renderPageHtml(page);\n const userDataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'flair-chrome-'));\n\n return new Promise<string>((resolve, reject) => {\n let chrome: ChildProcess | null = null;\n let finished = false;\n let written = 0;\n let stall: NodeJS.Timeout | undefined;\n const sockets = new Set<import('node:net').Socket>();\n\n const cleanup = () => {\n clearTimeout(stall);\n try {\n chrome?.kill('SIGKILL');\n } catch {}\n for (const s of sockets) s.destroy();\n server.close();\n fs.rm(userDataDir, { recursive: true, force: true }, () => {});\n };\n const fail = (err: Error) => {\n if (finished) return;\n finished = true;\n sink.abort();\n cleanup();\n reject(err);\n };\n const succeed = () => {\n if (finished) return;\n finished = true;\n cleanup();\n resolve(plan.path);\n };\n const watchdog = () => {\n clearTimeout(stall);\n stall = setTimeout(() => fail(new Error(`The render stalled: no frame for ${STALL_MS / 1000} s after frame ${written} of ${total}. Is WebGL2 available to headless Chrome?`)), STALL_MS);\n };\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || '/', 'http://127.0.0.1');\n if (url.pathname === '/' && req.method === 'GET') {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' });\n res.end(html);\n return;\n }\n if (url.pathname === '/state') {\n const i = Number(url.searchParams.get('i'));\n try {\n const s = job.state(i);\n const body = { ...s, ...(s.video ? { video: Object.fromEntries(Object.keys(s.video).map((k) => [k, `/video?i=${i}&name=${encodeURIComponent(k)}`])) } : {}) };\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(body));\n } catch (e) {\n res.writeHead(500);\n res.end();\n fail(e as Error);\n }\n return;\n }\n if (url.pathname === '/video') {\n const i = Number(url.searchParams.get('i'));\n const file = job.state(i).video?.[url.searchParams.get('name') ?? ''];\n if (!file) {\n res.writeHead(404);\n res.end();\n return;\n }\n res.writeHead(200, { 'Content-Type': 'image/png' });\n fs.createReadStream(file).pipe(res);\n return;\n }\n if (url.pathname === '/frame' && req.method === 'POST') {\n const i = Number(url.searchParams.get('i'));\n const chunks: Buffer[] = [];\n req.on('data', (c: Buffer) => chunks.push(c));\n req.on('end', () => {\n sink\n .write(i, Buffer.concat(chunks))\n .then(async () => {\n written++;\n watchdog();\n onProgress?.(written, total);\n res.writeHead(200);\n res.end('ok');\n if (written >= total) {\n await sink.finish();\n succeed();\n }\n })\n .catch((e: Error) => {\n res.writeHead(500);\n res.end();\n fail(e);\n });\n });\n return;\n }\n if (url.pathname === '/error' && req.method === 'POST') {\n let message = '';\n req.on('data', (c) => (message += c));\n req.on('end', () => {\n res.writeHead(200);\n res.end();\n fail(new Error(message || 'The render page failed.'));\n });\n return;\n }\n res.writeHead(404);\n res.end();\n });\n server.on('connection', (s) => {\n sockets.add(s);\n s.on('close', () => sockets.delete(s));\n });\n\n server.listen(0, '127.0.0.1', () => {\n const { port } = server.address() as import('node:net').AddressInfo;\n chrome = spawn(chromeBin, chromeArgs(userDataDir, page.width, page.height, `http://127.0.0.1:${port}/`), { stdio: 'ignore' });\n chrome.on('error', (err) => fail(new Error(`Could not launch Chrome at ${chromeBin}: ${err.message}`)));\n chrome.on('exit', (code) => {\n if (!finished && written < total) fail(new Error(`Chrome quit (exit ${code}) after ${written} of ${total} frames.`));\n });\n watchdog();\n });\n });\n}\n\n// ==========================================\n// Shader export\n// ==========================================\n\n/** Where the pointer is in a recording: nowhere (`none`), or the scripted pointer of {@link scriptedPointer} (`auto`). */\nexport type PointerMode = 'none' | 'auto';\n\nexport interface ExportOptions {\n /** GLSL fragment shader source (Shadertoy-style `mainImage`). */\n source: string;\n /**\n * Control values over the declared defaults. An image control takes a\n * URL, a `data:` URL, or a local file path (read into a `data:` URL).\n */\n values?: Record<string, ControlValue>;\n /** Destination: .mp4, .webm, .mov, .gif, or PNG frames (a folder or `out_%04d.png`). */\n outputPath: string;\n width?: number;\n height?: number;\n fps?: number;\n /** Seconds (default 3). */\n duration?: number;\n /** Keep the shader's alpha (WebM, MOV, GIF and PNG; MP4 is always opaque). */\n alpha?: boolean;\n /**\n * The shader draws over other content (`fragColor.a` is coverage): without\n * `alpha` it is composited over `background`. Otherwise its alpha is\n * ignored without `alpha`, as on an opaque canvas.\n */\n transparent?: boolean;\n /** CSS colour under transparent pixels when `alpha` is off (default black). */\n background?: string;\n /** The pointer: `none` (default) or `auto`, a scripted pointer that hovers, wanders and clicks. */\n pointer?: PointerMode;\n onProgress?: (frame: number, total: number) => void;\n}\n\nconst MIME: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.svg': 'image/svg+xml',\n};\n\n/**\n * An image for the page, as a `data:` URL: a local file is read, an\n * `http(s):` URL fetched (so CORS does not matter); `data:` URLs stay.\n */\nexport async function imageDataUrl(source: string, cwd = process.cwd()): Promise<string> {\n if (/^data:/i.test(source) || source === '') return source;\n if (/^https?:/i.test(source)) {\n const res = await fetch(source);\n if (!res.ok) throw new Error(`Could not download the image at ${source} (HTTP ${res.status}).`);\n const type = res.headers.get('content-type')?.split(';')[0] || MIME[path.extname(new URL(source).pathname).toLowerCase()] || 'application/octet-stream';\n return `data:${type};base64,${Buffer.from(await res.arrayBuffer()).toString('base64')}`;\n }\n const file = path.resolve(cwd, source.replace(/^file:\\/\\//, ''));\n if (!fs.existsSync(file)) throw new Error(`There is no image at ${file}.`);\n const type = MIME[path.extname(file).toLowerCase()];\n if (!type) throw new Error(`${path.basename(file)} is not an image Flair can show; give it a PNG, JPEG, GIF, WebP, AVIF, BMP or SVG.`);\n return `data:${type};base64,${fs.readFileSync(file).toString('base64')}`;\n}\n\n/**\n * The fragment shader the page compiles: a Shadertoy-style `mainImage`\n * source goes in `wrapSource`, as `ShaderRenderer` compiles it. A complete\n * program (one with its own `void main()`, glslsandbox-style, reading\n * `u_time` and `u_resolution`) is kept as written, with `#version 300 es`\n * added when it has none.\n */\nexport function fragmentSource(source: string): string {\n if (!/\\bvoid\\s+main\\s*\\(\\s*\\)/.test(source)) return wrapSource(source);\n return /^\\s*#version\\b/.test(source) ? source : `#version 300 es\\n#line 1\\n${source}`;\n}\n\n/** Shader controls with their values, images as `data:` URLs, ready for the page. */\nexport async function pageControls(source: string, values: Record<string, ControlValue> = {}): Promise<PageControl[]> {\n return Promise.all(\n parseControls(source).map(async (c) => {\n let value = controlValue(c, values);\n if (c.type === 'sampler2D' && typeof value === 'string') value = await imageDataUrl(value);\n return { name: c.name, type: c.type, value, ...(c.texture ? { texture: c.texture } : {}) };\n }),\n );\n}\n\n/** Frame times and pointer uniforms for `frames` frames at `fps`. */\nexport function frameStates(frames: number, fps: number, width: number, height: number, pointer: PointerMode): FrameState[] {\n const times = Array.from({ length: frames }, (_, i) => i / fps);\n const scripted = pointer === 'auto' ? scriptedPointer(width, height, times) : undefined;\n const none = { mouse: [0, 0, 0, 0] as [number, number, number, number], pointer: [0, 0, 0, 0] as [number, number, number, number], clicks: new Array(MAX_CLICKS * 4).fill(0), trail: new Array(MAX_TRAIL * 4).fill(0) };\n return times.map((time, i) => ({ time, delta: i === 0 ? 0 : 1 / fps, frame: i, ...(scripted?.[i] ?? none) }));\n}\n\n/**\n * Renders a shader animation frame by frame with WebGL2 in headless Chrome,\n * the way `ShaderRenderer` draws it (the same GLSL wrapper and built-ins,\n * images, int and bool controls), and writes MP4 (H.264), WebM (VP9, with\n * alpha when asked), MOV (ProRes 4444), GIF or PNG frames. MP4, WebM and\n * MOV need ffmpeg; GIF and PNG do not.\n */\nexport async function exportMotionGraphic(options: ExportOptions): Promise<string> {\n const { source, values = {}, outputPath, fps = 30, duration = 3, onProgress } = options;\n const width = Math.max(1, Math.round(options.width ?? 720));\n const height = Math.max(1, Math.round(options.height ?? 720));\n const frames = Math.max(1, Math.round(duration * fps));\n const plan = planOutput(outputPath, { alpha: options.alpha, frames });\n if (plan.format === 'svg') throw new Error('A shader cannot be written as SVG; write .mp4, .webm, .mov, .gif or .png frames.');\n const states = frameStates(frames, fps, width, height, options.pointer ?? 'none');\n return runRender({\n page: {\n width,\n height,\n frames,\n alpha: plan.alpha,\n background: options.background ?? '#000000',\n send: plan.format === 'gif' ? 'rgba' : 'png',\n shader: {\n fragment: fragmentSource(source),\n controls: await pageControls(source, values),\n opaque: !plan.alpha && !options.transparent,\n },\n },\n state: (i) => states[i]!,\n plan,\n fps,\n onProgress,\n });\n}\n"],"mappings":"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","names":["type"]}
@@ -328,9 +328,33 @@ function morphPaths(from, to, options = {}) {
328
328
  const [a, b] = morphSequence([from, to], options);
329
329
  return [a, b];
330
330
  }
331
+ function pathPointAt(d, at) {
332
+ let rings;
333
+ try {
334
+ rings = flatten(d);
335
+ } catch {
336
+ return void 0;
337
+ }
338
+ const lines = [];
339
+ for (const ring of rings) {
340
+ const pts = ring.closed ? [...ring.points, ring.points[0]] : ring.points;
341
+ for (let i = 1; i < pts.length; i++)
342
+ lines.push([pts[i - 1], pts[i], Math.hypot(pts[i][0] - pts[i - 1][0], pts[i][1] - pts[i - 1][1])]);
343
+ }
344
+ const first = rings[0]?.points[0];
345
+ if (!first) return void 0;
346
+ let left = Math.min(Math.max(at, 0), 1) * lines.reduce((sum, l) => sum + l[2], 0);
347
+ for (const [a, b, length] of lines) {
348
+ if (left <= length && length > 0) return [a[0] + (b[0] - a[0]) * left / length, a[1] + (b[1] - a[1]) * left / length];
349
+ left -= length;
350
+ }
351
+ const last = lines[lines.length - 1];
352
+ return last ? [last[1][0], last[1][1]] : [first[0], first[1]];
353
+ }
331
354
 
332
355
  export {
333
356
  morphSequence,
334
- morphPaths
357
+ morphPaths,
358
+ pathPointAt
335
359
  };
336
- //# sourceMappingURL=chunk-OHW7UG6D.js.map
360
+ //# sourceMappingURL=chunk-ORAFCHX3.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/vector/morph.ts"],"sourcesContent":["/**\n * Shape morphing: any SVG paths turned into paths with the same structure, so\n * an `attrs` change on `d` (see `SvgAnimation`) blends one into the other\n * point by point. Pure functions of their arguments, with no DOM.\n */\n\ntype Point = [number, number];\n\n/** One piece of a path: its outline as points, and whether it closes. */\ninterface Ring {\n points: Point[];\n closed: boolean;\n}\n\nexport interface MorphOptions {\n /** Points per piece of the shape (default 72): more follows curves more closely. */\n points?: number;\n /** Decimals in the numbers written (default 2). */\n decimals?: number;\n}\n\n/** Segments a curve is split into before resampling. */\nconst CURVE_STEPS = 24;\n\nconst TOKEN = /[MmLlHhVvCcSsQqTtAaZz]|-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\n\n/** Arguments each command takes (repeated commands take them again). */\nconst ARGS: Record<string, number> = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0 };\n\n/**\n * The pieces of a path's `d` as outlines: lines kept, curves and arcs split\n * into short lines. Throws on a command it does not know.\n */\nfunction flatten(d: string): Ring[] {\n const stray = d.replace(TOKEN, \"\").replace(/[\\s,]+/g, \"\");\n if (stray) throw new Error(`\"${stray[0]}\" is not a path command`);\n const tokens = d.match(TOKEN) ?? [];\n const rings: Ring[] = [];\n // Typed by a cast: the helpers below assign it, which narrowing would miss.\n let ring = null as Ring | null;\n let x = 0;\n let y = 0;\n let startX = 0;\n let startY = 0;\n // The last control point, for S and T.\n let cx = 0;\n let cy = 0;\n let prev = \"\";\n let i = 0;\n let command = \"\";\n const add = (px: number, py: number) => ring!.points.push([px, py]);\n const begin = (px: number, py: number) => {\n if (ring && ring.points.length) rings.push(ring);\n ring = { points: [[px, py]], closed: false };\n };\n while (i < tokens.length) {\n if (/[a-z]/i.test(tokens[i]!)) command = tokens[i++]!;\n else if (!command) throw new Error(`\"${tokens[i]}\" needs a command (M, L, C, …) before it`);\n const lower = command.toLowerCase();\n if (!(lower in ARGS)) throw new Error(`Unknown path command \"${command}\"`);\n const rel = command !== command.toUpperCase();\n const n = ARGS[lower]!;\n const args = tokens.slice(i, i + n).map(Number);\n if (args.length < n || args.some((v) => Number.isNaN(v))) break;\n i += n;\n const ox = rel ? x : 0;\n const oy = rel ? y : 0;\n if (lower === \"z\") {\n if (ring) {\n ring.closed = true;\n rings.push(ring);\n ring = null;\n }\n x = startX;\n y = startY;\n prev = \"z\";\n // A Z takes no arguments: wait for the next command.\n command = \"\";\n continue;\n }\n if (!ring) begin(x, y);\n switch (lower) {\n case \"m\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n startX = x;\n startY = y;\n begin(x, y);\n // Pairs after a moveto are linetos.\n command = rel ? \"l\" : \"L\";\n break;\n case \"l\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n add(x, y);\n break;\n case \"h\":\n x = ox + args[0]!;\n add(x, y);\n break;\n case \"v\":\n y = (rel ? y : 0) + args[0]!;\n add(x, y);\n break;\n case \"c\":\n case \"s\": {\n let x1: number;\n let y1: number;\n let rest: number[];\n if (lower === \"c\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n rest = args.slice(2);\n } else {\n const smooth = prev === \"c\" || prev === \"s\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n rest = args;\n }\n const x2 = ox + rest[0]!;\n const y2 = oy + rest[1]!;\n const ex = ox + rest[2]!;\n const ey = oy + rest[3]!;\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(\n u * u * u * x + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * ex,\n u * u * u * y + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * ey,\n );\n }\n cx = x2;\n cy = y2;\n x = ex;\n y = ey;\n break;\n }\n case \"q\":\n case \"t\": {\n let x1: number;\n let y1: number;\n let ex: number;\n let ey: number;\n if (lower === \"q\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n ex = ox + args[2]!;\n ey = oy + args[3]!;\n } else {\n const smooth = prev === \"q\" || prev === \"t\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n ex = ox + args[0]!;\n ey = oy + args[1]!;\n }\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(u * u * x + 2 * u * t * x1 + t * t * ex, u * u * y + 2 * u * t * y1 + t * t * ey);\n }\n cx = x1;\n cy = y1;\n x = ex;\n y = ey;\n break;\n }\n case \"a\": {\n const ex = ox + args[5]!;\n const ey = oy + args[6]!;\n for (const p of arcPoints(x, y, args[0]!, args[1]!, args[2]!, args[3]! !== 0, args[4]! !== 0, ex, ey)) add(p[0], p[1]);\n x = ex;\n y = ey;\n break;\n }\n }\n prev = lower;\n }\n if (ring && ring.points.length) rings.push(ring);\n return rings\n .map((r) => {\n // A ring that ends where it starts is closed, Z or not.\n const [a, b] = [r.points[0]!, r.points[r.points.length - 1]!];\n const closes = r.points.length > 2 && Math.hypot(a[0] - b[0], a[1] - b[1]) < 1e-6;\n return { points: closes ? r.points.slice(0, -1) : r.points, closed: r.closed || closes };\n })\n .filter((r) => r.points.length > 1);\n}\n\n/** Points along an SVG arc (endpoint form), not including its start. */\nfunction arcPoints(\n x1: number,\n y1: number,\n rx: number,\n ry: number,\n angle: number,\n large: boolean,\n sweep: boolean,\n x2: number,\n y2: number,\n): Point[] {\n rx = Math.abs(rx);\n ry = Math.abs(ry);\n if (!rx || !ry || (x1 === x2 && y1 === y2)) return [[x2, y2]];\n const phi = (angle * Math.PI) / 180;\n const cos = Math.cos(phi);\n const sin = Math.sin(phi);\n const dx = (x1 - x2) / 2;\n const dy = (y1 - y2) / 2;\n const x1p = cos * dx + sin * dy;\n const y1p = -sin * dx + cos * dy;\n // Radii too small to reach are scaled up, as SVG says.\n const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);\n if (lambda > 1) {\n rx *= Math.sqrt(lambda);\n ry *= Math.sqrt(lambda);\n }\n const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;\n const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;\n const k = (large === sweep ? -1 : 1) * Math.sqrt(Math.max(0, num / den));\n const cxp = (k * rx * y1p) / ry;\n const cyp = (-k * ry * x1p) / rx;\n const cx = cos * cxp - sin * cyp + (x1 + x2) / 2;\n const cy = sin * cxp + cos * cyp + (y1 + y2) / 2;\n const theta = (ux: number, uy: number, vx: number, vy: number) =>\n Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);\n const start = theta(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);\n let delta = theta((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);\n if (!sweep && delta > 0) delta -= 2 * Math.PI;\n if (sweep && delta < 0) delta += 2 * Math.PI;\n const steps = Math.max(2, Math.ceil((Math.abs(delta) / (Math.PI / 2)) * (CURVE_STEPS / 2)));\n const out: Point[] = [];\n for (let s = 1; s <= steps; s++) {\n const t = start + (delta * s) / steps;\n const px = rx * Math.cos(t);\n const py = ry * Math.sin(t);\n out.push([cos * px - sin * py + cx, sin * px + cos * py + cy]);\n }\n out[out.length - 1] = [x2, y2];\n return out;\n}\n\n/**\n * `n` points evenly spaced along a ring. A closed ring goes round once; an\n * open one (a stroke) is resampled as closed by going there and back, so it\n * can turn into a closed shape.\n */\nfunction resample(ring: Ring, n: number): Point[] {\n const pts = ring.closed ? [...ring.points, ring.points[0]!] : [...ring.points, ...ring.points.slice(0, -1).reverse()];\n const lengths = [0];\n for (let i = 1; i < pts.length; i++)\n lengths.push(lengths[i - 1]! + Math.hypot(pts[i]![0] - pts[i - 1]![0], pts[i]![1] - pts[i - 1]![1]));\n const total = lengths[lengths.length - 1]!;\n if (total === 0) return Array.from({ length: n }, () => [pts[0]![0], pts[0]![1]] as Point);\n const out: Point[] = [];\n let j = 1;\n for (let k = 0; k < n; k++) {\n const at = (k / n) * total;\n while (j < lengths.length - 1 && lengths[j]! < at) j++;\n const seg = lengths[j]! - lengths[j - 1]!;\n const t = seg > 0 ? (at - lengths[j - 1]!) / seg : 0;\n const a = pts[j - 1]!;\n const b = pts[j]!;\n out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);\n }\n return out;\n}\n\nconst signedArea = (pts: Point[]) => {\n let sum = 0;\n for (let i = 0; i < pts.length; i++) {\n const a = pts[i]!;\n const b = pts[(i + 1) % pts.length]!;\n sum += a[0] * b[1] - b[0] * a[1];\n }\n return sum / 2;\n};\n\nconst centroid = (pts: Point[]): Point => {\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p[0];\n y += p[1];\n }\n return [x / pts.length, y / pts.length];\n};\n\n/** How big a piece is: its area, or for a stroke its length times a little. */\nfunction size(ring: Ring, pts: Point[]): number {\n const area = Math.abs(signedArea(pts));\n if (ring.closed && area > 0) return area;\n let length = 0;\n for (let i = 1; i < ring.points.length; i++)\n length += Math.hypot(ring.points[i]![0] - ring.points[i - 1]![0], ring.points[i]![1] - ring.points[i - 1]![1]);\n return length;\n}\n\ninterface Piece {\n pts: Point[];\n centre: Point;\n size: number;\n}\n\n/**\n * Pairs the pieces of one shape with the slots of the shape before it,\n * nearest and most alike first: a slot left over is empty (a piece that\n * shrinks away), and a piece left over takes an empty slot (it grows).\n */\nfunction assign(before: (Piece | null)[], pieces: Piece[], scale: number): (Piece | null)[] {\n const out: (Piece | null)[] = before.map(() => null);\n const pairs: { slot: number; piece: number; cost: number }[] = [];\n before.forEach((slot, s) => {\n if (!slot) return;\n pieces.forEach((p, i) => {\n const distance = Math.hypot(slot.centre[0] - p.centre[0], slot.centre[1] - p.centre[1]) / scale;\n const likeness = Math.abs(Math.log((slot.size + 1e-9) / (p.size + 1e-9)));\n pairs.push({ slot: s, piece: i, cost: distance + 0.5 * likeness });\n });\n });\n pairs.sort((a, b) => a.cost - b.cost);\n const used = new Set<number>();\n for (const { slot, piece } of pairs) {\n if (out[slot] || used.has(piece)) continue;\n out[slot] = pieces[piece]!;\n used.add(piece);\n }\n let free = 0;\n pieces.forEach((p, i) => {\n if (used.has(i)) return;\n while (out[free] || before[free]) free++;\n out[free] = p;\n });\n return out;\n}\n\n/** `pts` turned and started so it lines up with `ref` point by point (the shortest moves). */\nfunction align(ref: Point[], pts: Point[]): Point[] {\n const n = pts.length;\n let best = pts;\n let bestCost = Infinity;\n for (const candidate of [pts, [...pts].reverse()]) {\n for (let shift = 0; shift < n; shift++) {\n let cost = 0;\n for (let k = 0; k < n && cost < bestCost; k++) {\n const a = ref[k]!;\n const b = candidate[(k + shift) % n]!;\n cost += (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;\n }\n if (cost < bestCost) {\n bestCost = cost;\n best = candidate.slice(shift).concat(candidate.slice(0, shift));\n }\n }\n }\n return best;\n}\n\n/**\n * Paths with one structure for a sequence of shapes, so each blends into the\n * next (and the last into the first) with `attrs: { d: [a, b] }`. Any path\n * commands work, curves and arcs included, and shapes can have different\n * numbers of pieces (an icon's parts, a letter's holes): pieces are paired by\n * position and size, and one without a partner grows from or shrinks to a\n * point. Draw the results with `fill-rule=\"evenodd\"`, since a piece's\n * direction can change. Throws a sentence when a path cannot be read.\n */\nexport function morphSequence(paths: readonly string[], options: MorphOptions = {}): string[] {\n const n = Math.max(8, Math.round(options.points ?? 72));\n const decimals = options.decimals ?? 2;\n const shapes = paths.map((d, i) => {\n let rings: Ring[];\n try {\n rings = flatten(d);\n } catch (e) {\n throw new Error(`Path ${i + 1} cannot be read: ${(e as Error).message}`);\n }\n if (!rings.length) throw new Error(`Path ${i + 1} draws nothing: give it at least two points`);\n return rings.map((r): Piece => {\n const pts = resample(r, n);\n return { pts, centre: centroid(pts), size: size(r, pts) };\n });\n });\n if (!shapes.length) return [];\n const slots = Math.max(...shapes.map((s) => s.length));\n // How far apart counts as far, from the shapes' extent.\n const xs = shapes.flat().flatMap((p) => p.pts.map((q) => q[0]));\n const ys = shapes.flat().flatMap((p) => p.pts.map((q) => q[1]));\n const scale = Math.max(1e-6, Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));\n // Biggest pieces first, so the main outlines keep the first slots.\n const first = [...shapes[0]!].sort((a, b) => b.size - a.size);\n const assigned: (Piece | null)[][] = [[...first, ...Array<null>(slots - first.length).fill(null)]];\n for (let i = 1; i < shapes.length; i++) assigned.push(assign(assigned[i - 1]!, shapes[i]!, scale));\n // An empty slot is a point: where the piece in that slot is in the nearest shape that has one.\n const resolved = assigned.map((shape, i) =>\n shape.map((piece, s): Point[] => {\n if (piece) return piece.pts;\n for (let k = 1; k < shapes.length; k++) {\n const near = assigned[(i + k) % shapes.length]![s] ?? assigned[(i - k + shapes.length) % shapes.length]![s];\n if (near) return Array.from({ length: n }, () => [near.centre[0], near.centre[1]] as Point);\n }\n return Array.from({ length: n }, () => [0, 0] as Point);\n }),\n );\n for (let i = 1; i < resolved.length; i++)\n resolved[i] = resolved[i]!.map((pts, s) => align(resolved[i - 1]![s]!, pts));\n const num = (v: number) => {\n const r = Number(v.toFixed(decimals));\n return String(Object.is(r, -0) ? 0 : r);\n };\n return resolved.map((shape) =>\n shape.map((pts) => `M${pts.map((p) => `${num(p[0])} ${num(p[1])}`).join(\" L\")} Z`).join(\" \"),\n );\n}\n\n/**\n * Two paths turned into paths with one structure, so `attrs: { d: [from, to] }`\n * blends one into the other (see {@link morphSequence}).\n */\nexport function morphPaths(from: string, to: string, options: MorphOptions = {}): [string, string] {\n const [a, b] = morphSequence([from, to], options);\n return [a!, b!];\n}\n"],"mappings":";AAsBA,IAAM,cAAc;AAEpB,IAAM,QAAQ;AAGd,IAAM,OAA+B,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAMlG,SAAS,QAAQ,GAAmB;AAClC,QAAM,QAAQ,EAAE,QAAQ,OAAO,EAAE,EAAE,QAAQ,WAAW,EAAE;AACxD,MAAI,MAAO,OAAM,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,yBAAyB;AAChE,QAAM,SAAS,EAAE,MAAM,KAAK,KAAK,CAAC;AAClC,QAAM,QAAgB,CAAC;AAEvB,MAAI,OAAO;AACX,MAAI,IAAI;AACR,MAAI,IAAI;AACR,MAAI,SAAS;AACb,MAAI,SAAS;AAEb,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,OAAO;AACX,MAAI,IAAI;AACR,MAAI,UAAU;AACd,QAAM,MAAM,CAAC,IAAY,OAAe,KAAM,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AAClE,QAAM,QAAQ,CAAC,IAAY,OAAe;AACxC,QAAI,QAAQ,KAAK,OAAO,OAAQ,OAAM,KAAK,IAAI;AAC/C,WAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,QAAQ,MAAM;AAAA,EAC7C;AACA,SAAO,IAAI,OAAO,QAAQ;AACxB,QAAI,SAAS,KAAK,OAAO,CAAC,CAAE,EAAG,WAAU,OAAO,GAAG;AAAA,aAC1C,CAAC,QAAS,OAAM,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,+CAA0C;AAC1F,UAAM,QAAQ,QAAQ,YAAY;AAClC,QAAI,EAAE,SAAS,MAAO,OAAM,IAAI,MAAM,yBAAyB,OAAO,GAAG;AACzE,UAAM,MAAM,YAAY,QAAQ,YAAY;AAC5C,UAAM,IAAI,KAAK,KAAK;AACpB,UAAM,OAAO,OAAO,MAAM,GAAG,IAAI,CAAC,EAAE,IAAI,MAAM;AAC9C,QAAI,KAAK,SAAS,KAAK,KAAK,KAAK,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC,EAAG;AAC1D,SAAK;AACL,UAAM,KAAK,MAAM,IAAI;AACrB,UAAM,KAAK,MAAM,IAAI;AACrB,QAAI,UAAU,KAAK;AACjB,UAAI,MAAM;AACR,aAAK,SAAS;AACd,cAAM,KAAK,IAAI;AACf,eAAO;AAAA,MACT;AACA,UAAI;AACJ,UAAI;AACJ,aAAO;AAEP,gBAAU;AACV;AAAA,IACF;AACA,QAAI,CAAC,KAAM,OAAM,GAAG,CAAC;AACrB,YAAQ,OAAO;AAAA,MACb,KAAK;AACH,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,KAAK,KAAK,CAAC;AACf,iBAAS;AACT,iBAAS;AACT,cAAM,GAAG,CAAC;AAEV,kBAAU,MAAM,MAAM;AACtB;AAAA,MACF,KAAK;AACH,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,GAAG,CAAC;AACR;AAAA,MACF,KAAK;AACH,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,GAAG,CAAC;AACR;AAAA,MACF,KAAK;AACH,aAAK,MAAM,IAAI,KAAK,KAAK,CAAC;AAC1B,YAAI,GAAG,CAAC;AACR;AAAA,MACF,KAAK;AAAA,MACL,KAAK,KAAK;AACR,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI,UAAU,KAAK;AACjB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAChB,iBAAO,KAAK,MAAM,CAAC;AAAA,QACrB,OAAO;AACL,gBAAM,SAAS,SAAS,OAAO,SAAS;AACxC,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,iBAAO;AAAA,QACT;AACA,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,iBAAS,IAAI,GAAG,KAAK,aAAa,KAAK;AACrC,gBAAM,IAAI,IAAI;AACd,gBAAM,IAAI,IAAI;AACd;AAAA,YACE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;AAAA,YACtE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;AAAA,UACxE;AAAA,QACF;AACA,aAAK;AACL,aAAK;AACL,YAAI;AACJ,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK,KAAK;AACR,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI,UAAU,KAAK;AACjB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAAA,QAClB,OAAO;AACL,gBAAM,SAAS,SAAS,OAAO,SAAS;AACxC,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAAA,QAClB;AACA,iBAAS,IAAI,GAAG,KAAK,aAAa,KAAK;AACrC,gBAAM,IAAI,IAAI;AACd,gBAAM,IAAI,IAAI;AACd,cAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE;AAAA,QACtF;AACA,aAAK;AACL,aAAK;AACL,YAAI;AACJ,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACR,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,mBAAW,KAAK,UAAU,GAAG,GAAG,KAAK,CAAC,GAAI,KAAK,CAAC,GAAI,KAAK,CAAC,GAAI,KAAK,CAAC,MAAO,GAAG,KAAK,CAAC,MAAO,GAAG,IAAI,EAAE,EAAG,KAAI,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;AACrH,YAAI;AACJ,YAAI;AACJ;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,KAAK,OAAO,OAAQ,OAAM,KAAK,IAAI;AAC/C,SAAO,MACJ,IAAI,CAAC,MAAM;AAEV,UAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,GAAI,EAAE,OAAO,EAAE,OAAO,SAAS,CAAC,CAAE;AAC5D,UAAM,SAAS,EAAE,OAAO,SAAS,KAAK,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI;AAC7E,WAAO,EAAE,QAAQ,SAAS,EAAE,OAAO,MAAM,GAAG,EAAE,IAAI,EAAE,QAAQ,QAAQ,EAAE,UAAU,OAAO;AAAA,EACzF,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,OAAO,SAAS,CAAC;AACtC;AAGA,SAAS,UACP,IACA,IACA,IACA,IACA,OACA,OACA,OACA,IACA,IACS;AACT,OAAK,KAAK,IAAI,EAAE;AAChB,OAAK,KAAK,IAAI,EAAE;AAChB,MAAI,CAAC,MAAM,CAAC,MAAO,OAAO,MAAM,OAAO,GAAK,QAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,QAAM,MAAO,QAAQ,KAAK,KAAM;AAChC,QAAM,MAAM,KAAK,IAAI,GAAG;AACxB,QAAM,MAAM,KAAK,IAAI,GAAG;AACxB,QAAM,MAAM,KAAK,MAAM;AACvB,QAAM,MAAM,KAAK,MAAM;AACvB,QAAM,MAAM,MAAM,KAAK,MAAM;AAC7B,QAAM,MAAM,CAAC,MAAM,KAAK,MAAM;AAE9B,QAAM,SAAU,MAAM,OAAQ,KAAK,MAAO,MAAM,OAAQ,KAAK;AAC7D,MAAI,SAAS,GAAG;AACd,UAAM,KAAK,KAAK,MAAM;AACtB,UAAM,KAAK,KAAK,MAAM;AAAA,EACxB;AACA,QAAM,MAAM,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM;AACtE,QAAM,MAAM,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM;AAClD,QAAM,KAAK,UAAU,QAAQ,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,GAAG,MAAM,GAAG,CAAC;AACvE,QAAM,MAAO,IAAI,KAAK,MAAO;AAC7B,QAAM,MAAO,CAAC,IAAI,KAAK,MAAO;AAC9B,QAAM,KAAK,MAAM,MAAM,MAAM,OAAO,KAAK,MAAM;AAC/C,QAAM,KAAK,MAAM,MAAM,MAAM,OAAO,KAAK,MAAM;AAC/C,QAAM,QAAQ,CAAC,IAAY,IAAY,IAAY,OACjD,KAAK,MAAM,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE;AACjD,QAAM,QAAQ,MAAM,GAAG,IAAI,MAAM,OAAO,KAAK,MAAM,OAAO,EAAE;AAC5D,MAAI,QAAQ,OAAO,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,OAAO,EAAE;AAC1F,MAAI,CAAC,SAAS,QAAQ,EAAG,UAAS,IAAI,KAAK;AAC3C,MAAI,SAAS,QAAQ,EAAG,UAAS,IAAI,KAAK;AAC1C,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,KAAM,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,MAAO,cAAc,EAAE,CAAC;AAC1F,QAAM,MAAe,CAAC;AACtB,WAAS,IAAI,GAAG,KAAK,OAAO,KAAK;AAC/B,UAAM,IAAI,QAAS,QAAQ,IAAK;AAChC,UAAM,KAAK,KAAK,KAAK,IAAI,CAAC;AAC1B,UAAM,KAAK,KAAK,KAAK,IAAI,CAAC;AAC1B,QAAI,KAAK,CAAC,MAAM,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,MAAM,KAAK,EAAE,CAAC;AAAA,EAC/D;AACA,MAAI,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE;AAC7B,SAAO;AACT;AAOA,SAAS,SAAS,MAAY,GAAoB;AAChD,QAAM,MAAM,KAAK,SAAS,CAAC,GAAG,KAAK,QAAQ,KAAK,OAAO,CAAC,CAAE,IAAI,CAAC,GAAG,KAAK,QAAQ,GAAG,KAAK,OAAO,MAAM,GAAG,EAAE,EAAE,QAAQ,CAAC;AACpH,QAAM,UAAU,CAAC,CAAC;AAClB,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ;AAC9B,YAAQ,KAAK,QAAQ,IAAI,CAAC,IAAK,KAAK,MAAM,IAAI,CAAC,EAAG,CAAC,IAAI,IAAI,IAAI,CAAC,EAAG,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,IAAI,IAAI,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC;AACrG,QAAM,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AACxC,MAAI,UAAU,EAAG,QAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAG,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,CAAC,CAAU;AACzF,QAAM,MAAe,CAAC;AACtB,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAM,IAAI,IAAK;AACrB,WAAO,IAAI,QAAQ,SAAS,KAAK,QAAQ,CAAC,IAAK,GAAI;AACnD,UAAM,MAAM,QAAQ,CAAC,IAAK,QAAQ,IAAI,CAAC;AACvC,UAAM,IAAI,MAAM,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAM,MAAM;AACnD,UAAM,IAAI,IAAI,IAAI,CAAC;AACnB,UAAM,IAAI,IAAI,CAAC;AACf,QAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,IAAM,aAAa,CAAC,QAAiB;AACnC,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,IAAI,IAAI,CAAC;AACf,UAAM,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM;AAClC,WAAO,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;AAAA,EACjC;AACA,SAAO,MAAM;AACf;AAEA,IAAM,WAAW,CAAC,QAAwB;AACxC,MAAI,IAAI;AACR,MAAI,IAAI;AACR,aAAW,KAAK,KAAK;AACnB,SAAK,EAAE,CAAC;AACR,SAAK,EAAE,CAAC;AAAA,EACV;AACA,SAAO,CAAC,IAAI,IAAI,QAAQ,IAAI,IAAI,MAAM;AACxC;AAGA,SAAS,KAAK,MAAY,KAAsB;AAC9C,QAAM,OAAO,KAAK,IAAI,WAAW,GAAG,CAAC;AACrC,MAAI,KAAK,UAAU,OAAO,EAAG,QAAO;AACpC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ;AACtC,cAAU,KAAK,MAAM,KAAK,OAAO,CAAC,EAAG,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,EAAG,CAAC,GAAG,KAAK,OAAO,CAAC,EAAG,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,EAAG,CAAC,CAAC;AAC/G,SAAO;AACT;AAaA,SAAS,OAAO,QAA0B,QAAiB,OAAiC;AAC1F,QAAM,MAAwB,OAAO,IAAI,MAAM,IAAI;AACnD,QAAM,QAAyD,CAAC;AAChE,SAAO,QAAQ,CAAC,MAAM,MAAM;AAC1B,QAAI,CAAC,KAAM;AACX,WAAO,QAAQ,CAAC,GAAG,MAAM;AACvB,YAAM,WAAW,KAAK,MAAM,KAAK,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI;AAC1F,YAAM,WAAW,KAAK,IAAI,KAAK,KAAK,KAAK,OAAO,SAAS,EAAE,OAAO,KAAK,CAAC;AACxE,YAAM,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,WAAW,MAAM,SAAS,CAAC;AAAA,IACnE,CAAC;AAAA,EACH,CAAC;AACD,QAAM,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AACpC,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,EAAE,MAAM,MAAM,KAAK,OAAO;AACnC,QAAI,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,EAAG;AAClC,QAAI,IAAI,IAAI,OAAO,KAAK;AACxB,SAAK,IAAI,KAAK;AAAA,EAChB;AACA,MAAI,OAAO;AACX,SAAO,QAAQ,CAAC,GAAG,MAAM;AACvB,QAAI,KAAK,IAAI,CAAC,EAAG;AACjB,WAAO,IAAI,IAAI,KAAK,OAAO,IAAI,EAAG;AAClC,QAAI,IAAI,IAAI;AAAA,EACd,CAAC;AACD,SAAO;AACT;AAGA,SAAS,MAAM,KAAc,KAAuB;AAClD,QAAM,IAAI,IAAI;AACd,MAAI,OAAO;AACX,MAAI,WAAW;AACf,aAAW,aAAa,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,QAAQ,CAAC,GAAG;AACjD,aAAS,QAAQ,GAAG,QAAQ,GAAG,SAAS;AACtC,UAAI,OAAO;AACX,eAAS,IAAI,GAAG,IAAI,KAAK,OAAO,UAAU,KAAK;AAC7C,cAAM,IAAI,IAAI,CAAC;AACf,cAAM,IAAI,WAAW,IAAI,SAAS,CAAC;AACnC,iBAAS,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM;AAAA,MAChD;AACA,UAAI,OAAO,UAAU;AACnB,mBAAW;AACX,eAAO,UAAU,MAAM,KAAK,EAAE,OAAO,UAAU,MAAM,GAAG,KAAK,CAAC;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,cAAc,OAA0B,UAAwB,CAAC,GAAa;AAC5F,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,UAAU,EAAE,CAAC;AACtD,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,SAAS,MAAM,IAAI,CAAC,GAAG,MAAM;AACjC,QAAI;AACJ,QAAI;AACF,cAAQ,QAAQ,CAAC;AAAA,IACnB,SAAS,GAAG;AACV,YAAM,IAAI,MAAM,QAAQ,IAAI,CAAC,oBAAqB,EAAY,OAAO,EAAE;AAAA,IACzE;AACA,QAAI,CAAC,MAAM,OAAQ,OAAM,IAAI,MAAM,QAAQ,IAAI,CAAC,6CAA6C;AAC7F,WAAO,MAAM,IAAI,CAAC,MAAa;AAC7B,YAAM,MAAM,SAAS,GAAG,CAAC;AACzB,aAAO,EAAE,KAAK,QAAQ,SAAS,GAAG,GAAG,MAAM,KAAK,GAAG,GAAG,EAAE;AAAA,IAC1D,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,OAAO,OAAQ,QAAO,CAAC;AAC5B,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAErD,QAAM,KAAK,OAAO,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,QAAM,KAAK,OAAO,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,QAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,GAAG,EAAE,IAAI,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,EAAE,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;AAEjG,QAAM,QAAQ,CAAC,GAAG,OAAO,CAAC,CAAE,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AAC5D,QAAM,WAA+B,CAAC,CAAC,GAAG,OAAO,GAAG,MAAY,QAAQ,MAAM,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;AACjG,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,UAAS,KAAK,OAAO,SAAS,IAAI,CAAC,GAAI,OAAO,CAAC,GAAI,KAAK,CAAC;AAEjG,QAAM,WAAW,SAAS;AAAA,IAAI,CAAC,OAAO,MACpC,MAAM,IAAI,CAAC,OAAO,MAAe;AAC/B,UAAI,MAAO,QAAO,MAAM;AACxB,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAM,OAAO,UAAU,IAAI,KAAK,OAAO,MAAM,EAAG,CAAC,KAAK,UAAU,IAAI,IAAI,OAAO,UAAU,OAAO,MAAM,EAAG,CAAC;AAC1G,YAAI,KAAM,QAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAK,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC,CAAU;AAAA,MAC5F;AACA,aAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAU;AAAA,IACxD,CAAC;AAAA,EACH;AACA,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ;AACnC,aAAS,CAAC,IAAI,SAAS,CAAC,EAAG,IAAI,CAAC,KAAK,MAAM,MAAM,SAAS,IAAI,CAAC,EAAG,CAAC,GAAI,GAAG,CAAC;AAC7E,QAAM,MAAM,CAAC,MAAc;AACzB,UAAM,IAAI,OAAO,EAAE,QAAQ,QAAQ,CAAC;AACpC,WAAO,OAAO,OAAO,GAAG,GAAG,EAAE,IAAI,IAAI,CAAC;AAAA,EACxC;AACA,SAAO,SAAS;AAAA,IAAI,CAAC,UACnB,MAAM,IAAI,CAAC,QAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG;AAAA,EAC7F;AACF;AAMO,SAAS,WAAW,MAAc,IAAY,UAAwB,CAAC,GAAqB;AACjG,QAAM,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,MAAM,EAAE,GAAG,OAAO;AAChD,SAAO,CAAC,GAAI,CAAE;AAChB;","names":[]}
1
+ {"version":3,"sources":["../src/vector/morph.ts"],"sourcesContent":["/**\n * Shape morphing: any SVG paths turned into paths with the same structure, so\n * an `attrs` change on `d` (see `SvgAnimation`) blends one into the other\n * point by point. Pure functions of their arguments, with no DOM.\n */\n\ntype Point = [number, number];\n\n/** One piece of a path: its outline as points, and whether it closes. */\ninterface Ring {\n points: Point[];\n closed: boolean;\n}\n\nexport interface MorphOptions {\n /** Points per piece of the shape (default 72): more follows curves more closely. */\n points?: number;\n /** Decimals in the numbers written (default 2). */\n decimals?: number;\n}\n\n/** Segments a curve is split into before resampling. */\nconst CURVE_STEPS = 24;\n\nconst TOKEN = /[MmLlHhVvCcSsQqTtAaZz]|-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\n\n/** Arguments each command takes (repeated commands take them again). */\nconst ARGS: Record<string, number> = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0 };\n\n/**\n * The pieces of a path's `d` as outlines: lines kept, curves and arcs split\n * into short lines. Throws on a command it does not know.\n */\nfunction flatten(d: string): Ring[] {\n const stray = d.replace(TOKEN, \"\").replace(/[\\s,]+/g, \"\");\n if (stray) throw new Error(`\"${stray[0]}\" is not a path command`);\n const tokens = d.match(TOKEN) ?? [];\n const rings: Ring[] = [];\n // Typed by a cast: the helpers below assign it, which narrowing would miss.\n let ring = null as Ring | null;\n let x = 0;\n let y = 0;\n let startX = 0;\n let startY = 0;\n // The last control point, for S and T.\n let cx = 0;\n let cy = 0;\n let prev = \"\";\n let i = 0;\n let command = \"\";\n const add = (px: number, py: number) => ring!.points.push([px, py]);\n const begin = (px: number, py: number) => {\n if (ring && ring.points.length) rings.push(ring);\n ring = { points: [[px, py]], closed: false };\n };\n while (i < tokens.length) {\n if (/[a-z]/i.test(tokens[i]!)) command = tokens[i++]!;\n else if (!command) throw new Error(`\"${tokens[i]}\" needs a command (M, L, C, …) before it`);\n const lower = command.toLowerCase();\n if (!(lower in ARGS)) throw new Error(`Unknown path command \"${command}\"`);\n const rel = command !== command.toUpperCase();\n const n = ARGS[lower]!;\n const args = tokens.slice(i, i + n).map(Number);\n if (args.length < n || args.some((v) => Number.isNaN(v))) break;\n i += n;\n const ox = rel ? x : 0;\n const oy = rel ? y : 0;\n if (lower === \"z\") {\n if (ring) {\n ring.closed = true;\n rings.push(ring);\n ring = null;\n }\n x = startX;\n y = startY;\n prev = \"z\";\n // A Z takes no arguments: wait for the next command.\n command = \"\";\n continue;\n }\n if (!ring) begin(x, y);\n switch (lower) {\n case \"m\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n startX = x;\n startY = y;\n begin(x, y);\n // Pairs after a moveto are linetos.\n command = rel ? \"l\" : \"L\";\n break;\n case \"l\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n add(x, y);\n break;\n case \"h\":\n x = ox + args[0]!;\n add(x, y);\n break;\n case \"v\":\n y = (rel ? y : 0) + args[0]!;\n add(x, y);\n break;\n case \"c\":\n case \"s\": {\n let x1: number;\n let y1: number;\n let rest: number[];\n if (lower === \"c\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n rest = args.slice(2);\n } else {\n const smooth = prev === \"c\" || prev === \"s\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n rest = args;\n }\n const x2 = ox + rest[0]!;\n const y2 = oy + rest[1]!;\n const ex = ox + rest[2]!;\n const ey = oy + rest[3]!;\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(\n u * u * u * x + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * ex,\n u * u * u * y + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * ey,\n );\n }\n cx = x2;\n cy = y2;\n x = ex;\n y = ey;\n break;\n }\n case \"q\":\n case \"t\": {\n let x1: number;\n let y1: number;\n let ex: number;\n let ey: number;\n if (lower === \"q\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n ex = ox + args[2]!;\n ey = oy + args[3]!;\n } else {\n const smooth = prev === \"q\" || prev === \"t\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n ex = ox + args[0]!;\n ey = oy + args[1]!;\n }\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(u * u * x + 2 * u * t * x1 + t * t * ex, u * u * y + 2 * u * t * y1 + t * t * ey);\n }\n cx = x1;\n cy = y1;\n x = ex;\n y = ey;\n break;\n }\n case \"a\": {\n const ex = ox + args[5]!;\n const ey = oy + args[6]!;\n for (const p of arcPoints(x, y, args[0]!, args[1]!, args[2]!, args[3]! !== 0, args[4]! !== 0, ex, ey)) add(p[0], p[1]);\n x = ex;\n y = ey;\n break;\n }\n }\n prev = lower;\n }\n if (ring && ring.points.length) rings.push(ring);\n return rings\n .map((r) => {\n // A ring that ends where it starts is closed, Z or not.\n const [a, b] = [r.points[0]!, r.points[r.points.length - 1]!];\n const closes = r.points.length > 2 && Math.hypot(a[0] - b[0], a[1] - b[1]) < 1e-6;\n return { points: closes ? r.points.slice(0, -1) : r.points, closed: r.closed || closes };\n })\n .filter((r) => r.points.length > 1);\n}\n\n/** Points along an SVG arc (endpoint form), not including its start. */\nfunction arcPoints(\n x1: number,\n y1: number,\n rx: number,\n ry: number,\n angle: number,\n large: boolean,\n sweep: boolean,\n x2: number,\n y2: number,\n): Point[] {\n rx = Math.abs(rx);\n ry = Math.abs(ry);\n if (!rx || !ry || (x1 === x2 && y1 === y2)) return [[x2, y2]];\n const phi = (angle * Math.PI) / 180;\n const cos = Math.cos(phi);\n const sin = Math.sin(phi);\n const dx = (x1 - x2) / 2;\n const dy = (y1 - y2) / 2;\n const x1p = cos * dx + sin * dy;\n const y1p = -sin * dx + cos * dy;\n // Radii too small to reach are scaled up, as SVG says.\n const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);\n if (lambda > 1) {\n rx *= Math.sqrt(lambda);\n ry *= Math.sqrt(lambda);\n }\n const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;\n const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;\n const k = (large === sweep ? -1 : 1) * Math.sqrt(Math.max(0, num / den));\n const cxp = (k * rx * y1p) / ry;\n const cyp = (-k * ry * x1p) / rx;\n const cx = cos * cxp - sin * cyp + (x1 + x2) / 2;\n const cy = sin * cxp + cos * cyp + (y1 + y2) / 2;\n const theta = (ux: number, uy: number, vx: number, vy: number) =>\n Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);\n const start = theta(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);\n let delta = theta((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);\n if (!sweep && delta > 0) delta -= 2 * Math.PI;\n if (sweep && delta < 0) delta += 2 * Math.PI;\n const steps = Math.max(2, Math.ceil((Math.abs(delta) / (Math.PI / 2)) * (CURVE_STEPS / 2)));\n const out: Point[] = [];\n for (let s = 1; s <= steps; s++) {\n const t = start + (delta * s) / steps;\n const px = rx * Math.cos(t);\n const py = ry * Math.sin(t);\n out.push([cos * px - sin * py + cx, sin * px + cos * py + cy]);\n }\n out[out.length - 1] = [x2, y2];\n return out;\n}\n\n/**\n * `n` points evenly spaced along a ring. A closed ring goes round once; an\n * open one (a stroke) is resampled as closed by going there and back, so it\n * can turn into a closed shape.\n */\nfunction resample(ring: Ring, n: number): Point[] {\n const pts = ring.closed ? [...ring.points, ring.points[0]!] : [...ring.points, ...ring.points.slice(0, -1).reverse()];\n const lengths = [0];\n for (let i = 1; i < pts.length; i++)\n lengths.push(lengths[i - 1]! + Math.hypot(pts[i]![0] - pts[i - 1]![0], pts[i]![1] - pts[i - 1]![1]));\n const total = lengths[lengths.length - 1]!;\n if (total === 0) return Array.from({ length: n }, () => [pts[0]![0], pts[0]![1]] as Point);\n const out: Point[] = [];\n let j = 1;\n for (let k = 0; k < n; k++) {\n const at = (k / n) * total;\n while (j < lengths.length - 1 && lengths[j]! < at) j++;\n const seg = lengths[j]! - lengths[j - 1]!;\n const t = seg > 0 ? (at - lengths[j - 1]!) / seg : 0;\n const a = pts[j - 1]!;\n const b = pts[j]!;\n out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);\n }\n return out;\n}\n\nconst signedArea = (pts: Point[]) => {\n let sum = 0;\n for (let i = 0; i < pts.length; i++) {\n const a = pts[i]!;\n const b = pts[(i + 1) % pts.length]!;\n sum += a[0] * b[1] - b[0] * a[1];\n }\n return sum / 2;\n};\n\nconst centroid = (pts: Point[]): Point => {\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p[0];\n y += p[1];\n }\n return [x / pts.length, y / pts.length];\n};\n\n/** How big a piece is: its area, or for a stroke its length times a little. */\nfunction size(ring: Ring, pts: Point[]): number {\n const area = Math.abs(signedArea(pts));\n if (ring.closed && area > 0) return area;\n let length = 0;\n for (let i = 1; i < ring.points.length; i++)\n length += Math.hypot(ring.points[i]![0] - ring.points[i - 1]![0], ring.points[i]![1] - ring.points[i - 1]![1]);\n return length;\n}\n\ninterface Piece {\n pts: Point[];\n centre: Point;\n size: number;\n}\n\n/**\n * Pairs the pieces of one shape with the slots of the shape before it,\n * nearest and most alike first: a slot left over is empty (a piece that\n * shrinks away), and a piece left over takes an empty slot (it grows).\n */\nfunction assign(before: (Piece | null)[], pieces: Piece[], scale: number): (Piece | null)[] {\n const out: (Piece | null)[] = before.map(() => null);\n const pairs: { slot: number; piece: number; cost: number }[] = [];\n before.forEach((slot, s) => {\n if (!slot) return;\n pieces.forEach((p, i) => {\n const distance = Math.hypot(slot.centre[0] - p.centre[0], slot.centre[1] - p.centre[1]) / scale;\n const likeness = Math.abs(Math.log((slot.size + 1e-9) / (p.size + 1e-9)));\n pairs.push({ slot: s, piece: i, cost: distance + 0.5 * likeness });\n });\n });\n pairs.sort((a, b) => a.cost - b.cost);\n const used = new Set<number>();\n for (const { slot, piece } of pairs) {\n if (out[slot] || used.has(piece)) continue;\n out[slot] = pieces[piece]!;\n used.add(piece);\n }\n let free = 0;\n pieces.forEach((p, i) => {\n if (used.has(i)) return;\n while (out[free] || before[free]) free++;\n out[free] = p;\n });\n return out;\n}\n\n/** `pts` turned and started so it lines up with `ref` point by point (the shortest moves). */\nfunction align(ref: Point[], pts: Point[]): Point[] {\n const n = pts.length;\n let best = pts;\n let bestCost = Infinity;\n for (const candidate of [pts, [...pts].reverse()]) {\n for (let shift = 0; shift < n; shift++) {\n let cost = 0;\n for (let k = 0; k < n && cost < bestCost; k++) {\n const a = ref[k]!;\n const b = candidate[(k + shift) % n]!;\n cost += (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;\n }\n if (cost < bestCost) {\n bestCost = cost;\n best = candidate.slice(shift).concat(candidate.slice(0, shift));\n }\n }\n }\n return best;\n}\n\n/**\n * Paths with one structure for a sequence of shapes, so each blends into the\n * next (and the last into the first) with `attrs: { d: [a, b] }`. Any path\n * commands work, curves and arcs included, and shapes can have different\n * numbers of pieces (an icon's parts, a letter's holes): pieces are paired by\n * position and size, and one without a partner grows from or shrinks to a\n * point. Draw the results with `fill-rule=\"evenodd\"`, since a piece's\n * direction can change. Throws a sentence when a path cannot be read.\n */\nexport function morphSequence(paths: readonly string[], options: MorphOptions = {}): string[] {\n const n = Math.max(8, Math.round(options.points ?? 72));\n const decimals = options.decimals ?? 2;\n const shapes = paths.map((d, i) => {\n let rings: Ring[];\n try {\n rings = flatten(d);\n } catch (e) {\n throw new Error(`Path ${i + 1} cannot be read: ${(e as Error).message}`);\n }\n if (!rings.length) throw new Error(`Path ${i + 1} draws nothing: give it at least two points`);\n return rings.map((r): Piece => {\n const pts = resample(r, n);\n return { pts, centre: centroid(pts), size: size(r, pts) };\n });\n });\n if (!shapes.length) return [];\n const slots = Math.max(...shapes.map((s) => s.length));\n // How far apart counts as far, from the shapes' extent.\n const xs = shapes.flat().flatMap((p) => p.pts.map((q) => q[0]));\n const ys = shapes.flat().flatMap((p) => p.pts.map((q) => q[1]));\n const scale = Math.max(1e-6, Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));\n // Biggest pieces first, so the main outlines keep the first slots.\n const first = [...shapes[0]!].sort((a, b) => b.size - a.size);\n const assigned: (Piece | null)[][] = [[...first, ...Array<null>(slots - first.length).fill(null)]];\n for (let i = 1; i < shapes.length; i++) assigned.push(assign(assigned[i - 1]!, shapes[i]!, scale));\n // An empty slot is a point: where the piece in that slot is in the nearest shape that has one.\n const resolved = assigned.map((shape, i) =>\n shape.map((piece, s): Point[] => {\n if (piece) return piece.pts;\n for (let k = 1; k < shapes.length; k++) {\n const near = assigned[(i + k) % shapes.length]![s] ?? assigned[(i - k + shapes.length) % shapes.length]![s];\n if (near) return Array.from({ length: n }, () => [near.centre[0], near.centre[1]] as Point);\n }\n return Array.from({ length: n }, () => [0, 0] as Point);\n }),\n );\n for (let i = 1; i < resolved.length; i++)\n resolved[i] = resolved[i]!.map((pts, s) => align(resolved[i - 1]![s]!, pts));\n const num = (v: number) => {\n const r = Number(v.toFixed(decimals));\n return String(Object.is(r, -0) ? 0 : r);\n };\n return resolved.map((shape) =>\n shape.map((pts) => `M${pts.map((p) => `${num(p[0])} ${num(p[1])}`).join(\" L\")} Z`).join(\" \"),\n );\n}\n\n/**\n * Two paths turned into paths with one structure, so `attrs: { d: [from, to] }`\n * blends one into the other (see {@link morphSequence}).\n */\nexport function morphPaths(from: string, to: string, options: MorphOptions = {}): [string, string] {\n const [a, b] = morphSequence([from, to], options);\n return [a!, b!];\n}\n\n/**\n * @internal The point `at` (0–1) of the way along a path's `d` by length, as\n * a browser's `getPointAtLength` finds it (moves between pieces not counted),\n * with curves split into short lines. Undefined when `d` does not parse.\n */\nexport function pathPointAt(d: string, at: number): [number, number] | undefined {\n let rings: Ring[];\n try {\n rings = flatten(d);\n } catch {\n return undefined;\n }\n const lines: [Point, Point, number][] = [];\n for (const ring of rings) {\n const pts = ring.closed ? [...ring.points, ring.points[0]!] : ring.points;\n for (let i = 1; i < pts.length; i++)\n lines.push([pts[i - 1]!, pts[i]!, Math.hypot(pts[i]![0] - pts[i - 1]![0], pts[i]![1] - pts[i - 1]![1])]);\n }\n const first = rings[0]?.points[0];\n if (!first) return undefined;\n let left = Math.min(Math.max(at, 0), 1) * lines.reduce((sum, l) => sum + l[2], 0);\n for (const [a, b, length] of lines) {\n if (left <= length && length > 0) return [a[0] + ((b[0] - a[0]) * left) / length, a[1] + ((b[1] - a[1]) * left) / length];\n left -= length;\n }\n const last = lines[lines.length - 1];\n return last ? [last[1][0], last[1][1]] : [first[0], first[1]];\n}\n"],"mappings":"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","names":[]}
@@ -639,316 +639,6 @@ function createContext(canvas, preserveDrawingBuffer = false, alpha = false) {
639
639
  });
640
640
  }
641
641
 
642
- // src/shader/color.ts
643
- function srgbToLinear(c) {
644
- const v = Math.max(0, c);
645
- return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
646
- }
647
- function linearToSrgb(c) {
648
- const v = Math.max(0, c);
649
- return v <= 31308e-7 ? v * 12.92 : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
650
- }
651
- function srgbToLinearRgb(rgb) {
652
- return [srgbToLinear(rgb[0]), srgbToLinear(rgb[1]), srgbToLinear(rgb[2])];
653
- }
654
- function linearRgbToSrgb(rgb) {
655
- return [linearToSrgb(rgb[0]), linearToSrgb(rgb[1]), linearToSrgb(rgb[2])];
656
- }
657
- function linearSrgbToOklab(rgb) {
658
- const [r, g, b] = rgb;
659
- const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
660
- const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
661
- const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
662
- const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
663
- const a = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
664
- const bVal = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
665
- return [L, a, bVal];
666
- }
667
- function oklabToLinearSrgb(lab) {
668
- const [L, a, b] = lab;
669
- const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
670
- const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
671
- const s_ = L - 0.0894841775 * a - 1.291485548 * b;
672
- const l = l_ * l_ * l_;
673
- const m = m_ * m_ * m_;
674
- const s = s_ * s_ * s_;
675
- const r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
676
- const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
677
- const bVal = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
678
- return [r, g, bVal];
679
- }
680
- function srgbToOklab(rgb) {
681
- return linearSrgbToOklab(srgbToLinearRgb(rgb));
682
- }
683
- function oklabToSrgb(lab) {
684
- const linear = oklabToLinearSrgb(lab);
685
- return linearRgbToSrgb(linear);
686
- }
687
- function oklabToOklch(lab) {
688
- const [L, a, b] = lab;
689
- const C = Math.sqrt(a * a + b * b);
690
- let h = Math.atan2(b, a);
691
- if (h < 0) h += 2 * Math.PI;
692
- return [L, C, h];
693
- }
694
- function oklchToOklab(lch) {
695
- const [L, C, h] = lch;
696
- return [L, C * Math.cos(h), C * Math.sin(h)];
697
- }
698
- function interpolateOklab(c1, c2, t) {
699
- const lab1 = srgbToOklab(c1);
700
- const lab2 = srgbToOklab(c2);
701
- const clampedT = Math.max(0, Math.min(1, t));
702
- const lab = [
703
- lab1[0] + (lab2[0] - lab1[0]) * clampedT,
704
- lab1[1] + (lab2[1] - lab1[1]) * clampedT,
705
- lab1[2] + (lab2[2] - lab1[2]) * clampedT
706
- ];
707
- const res = oklabToSrgb(lab);
708
- return [
709
- Math.max(0, Math.min(1, res[0])),
710
- Math.max(0, Math.min(1, res[1])),
711
- Math.max(0, Math.min(1, res[2]))
712
- ];
713
- }
714
- function interpolateOklch(c1, c2, t) {
715
- const lch1 = oklabToOklch(srgbToOklab(c1));
716
- const lch2 = oklabToOklch(srgbToOklab(c2));
717
- const clampedT = Math.max(0, Math.min(1, t));
718
- const L = lch1[0] + (lch2[0] - lch1[0]) * clampedT;
719
- const C = lch1[1] + (lch2[1] - lch1[1]) * clampedT;
720
- let dHue = lch2[2] - lch1[2];
721
- if (dHue > Math.PI) dHue -= 2 * Math.PI;
722
- if (dHue < -Math.PI) dHue += 2 * Math.PI;
723
- let h = lch1[2] + dHue * clampedT;
724
- if (h < 0) h += 2 * Math.PI;
725
- if (h >= 2 * Math.PI) h -= 2 * Math.PI;
726
- const res = oklabToSrgb(oklchToOklab([L, C, h]));
727
- return [
728
- Math.max(0, Math.min(1, res[0])),
729
- Math.max(0, Math.min(1, res[1])),
730
- Math.max(0, Math.min(1, res[2]))
731
- ];
732
- }
733
- function mulMat3(m, v) {
734
- return [
735
- m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
736
- m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
737
- m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
738
- ];
739
- }
740
- var MAT_LINEAR_SRGB_TO_P3 = [
741
- 0.822462,
742
- 0.177538,
743
- 0,
744
- 0.033194,
745
- 0.966806,
746
- 0,
747
- 0.017083,
748
- 0.072397,
749
- 0.91052
750
- ];
751
- var MAT_P3_TO_LINEAR_SRGB = [
752
- 1.22494,
753
- -0.22494,
754
- 0,
755
- -0.042057,
756
- 1.042057,
757
- 0,
758
- -0.019638,
759
- -0.078636,
760
- 1.098274
761
- ];
762
- var MAT_LINEAR_SRGB_TO_ACESCG = [
763
- 0.613097,
764
- 0.339523,
765
- 0.047379,
766
- 0.070194,
767
- 0.916354,
768
- 0.013452,
769
- 0.020616,
770
- 0.10957,
771
- 0.869815
772
- ];
773
- var MAT_ACESCG_TO_LINEAR_SRGB = [
774
- 1.704859,
775
- -0.621714,
776
- -0.083299,
777
- -0.130078,
778
- 1.140735,
779
- -0.01056,
780
- -0.023964,
781
- -0.128975,
782
- 1.153014
783
- ];
784
- function convertColorSpace(color, from, to) {
785
- if (from === to) return [...color];
786
- let lin;
787
- switch (from) {
788
- case "srgb":
789
- lin = srgbToLinearRgb(color);
790
- break;
791
- case "linear-srgb":
792
- lin = [...color];
793
- break;
794
- case "rec709":
795
- lin = [
796
- Math.pow(Math.max(0, color[0]), 2.4),
797
- Math.pow(Math.max(0, color[1]), 2.4),
798
- Math.pow(Math.max(0, color[2]), 2.4)
799
- ];
800
- break;
801
- case "display-p3": {
802
- const p3Lin = srgbToLinearRgb(color);
803
- lin = mulMat3(MAT_P3_TO_LINEAR_SRGB, p3Lin);
804
- break;
805
- }
806
- case "acescg":
807
- lin = mulMat3(MAT_ACESCG_TO_LINEAR_SRGB, color);
808
- break;
809
- }
810
- switch (to) {
811
- case "linear-srgb":
812
- return lin;
813
- case "srgb":
814
- return linearRgbToSrgb(lin);
815
- case "rec709":
816
- return [
817
- Math.pow(Math.max(0, lin[0]), 1 / 2.4),
818
- Math.pow(Math.max(0, lin[1]), 1 / 2.4),
819
- Math.pow(Math.max(0, lin[2]), 1 / 2.4)
820
- ];
821
- case "display-p3": {
822
- const p3Lin = mulMat3(MAT_LINEAR_SRGB_TO_P3, lin);
823
- return linearRgbToSrgb(p3Lin);
824
- }
825
- case "acescg":
826
- return mulMat3(MAT_LINEAR_SRGB_TO_ACESCG, lin);
827
- }
828
- }
829
- function applyAscCdl(color, cdl) {
830
- const slope = cdl.slope ?? [1, 1, 1];
831
- const offset = cdl.offset ?? [0, 0, 0];
832
- const power = cdl.power ?? [1, 1, 1];
833
- const sat = cdl.saturation ?? 1;
834
- let r = Math.pow(Math.max(0, color[0] * slope[0] + offset[0]), power[0]);
835
- let g = Math.pow(Math.max(0, color[1] * slope[1] + offset[1]), power[1]);
836
- let b = Math.pow(Math.max(0, color[2] * slope[2] + offset[2]), power[2]);
837
- if (sat !== 1) {
838
- const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
839
- r = luma + sat * (r - luma);
840
- g = luma + sat * (g - luma);
841
- b = luma + sat * (b - luma);
842
- }
843
- return [Math.max(0, r), Math.max(0, g), Math.max(0, b)];
844
- }
845
- function applyLiftGammaGain(color, lgg) {
846
- const lift = lgg.lift ?? [0, 0, 0];
847
- const gamma = lgg.gamma ?? [1, 1, 1];
848
- const gain = lgg.gain ?? [1, 1, 1];
849
- const processChannel = (val, l, gm, gn) => {
850
- const lifted = val + l * (1 - val);
851
- const gained = Math.max(0, lifted * gn);
852
- const safeGamma = Math.max(1e-4, gm);
853
- return Math.pow(gained, 1 / safeGamma);
854
- };
855
- return [
856
- processChannel(color[0], lift[0], gamma[0], gain[0]),
857
- processChannel(color[1], lift[1], gamma[1], gain[1]),
858
- processChannel(color[2], lift[2], gamma[2], gain[2])
859
- ];
860
- }
861
- function applyVibrance(color, amount) {
862
- if (Math.abs(amount) < 1e-4) return [...color];
863
- const [r, g, b] = color;
864
- const maxC = Math.max(r, g, b);
865
- const minC = Math.min(r, g, b);
866
- const sat = maxC > 1e-5 ? (maxC - minC) / maxC : 0;
867
- let skinProtection = 1;
868
- if (r > g && g > b) {
869
- const skinFactor = (g - b) / (r - b + 1e-5);
870
- skinProtection = Math.max(0.2, 1 - skinFactor * 0.5);
871
- }
872
- const boost = amount * (1 - sat) * skinProtection;
873
- const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
874
- const newR = Math.max(0, Math.min(1, luma + (1 + boost) * (r - luma)));
875
- const newG = Math.max(0, Math.min(1, luma + (1 + boost) * (g - luma)));
876
- const newB = Math.max(0, Math.min(1, luma + (1 + boost) * (b - luma)));
877
- return [newR, newG, newB];
878
- }
879
- function getWhiteBalanceGains(kelvin, tint = 0) {
880
- const k = Math.max(2e3, Math.min(12e3, kelvin)) / 100;
881
- let r;
882
- let g;
883
- let b;
884
- if (k <= 66) {
885
- r = 255;
886
- g = 99.4708025861 * Math.log(k) - 161.1195681661;
887
- b = k <= 19 ? 0 : 138.5177312231 * Math.log(k - 10) - 305.0447927307;
888
- } else {
889
- r = 329.698727446 * Math.pow(k - 60, -0.1332047592);
890
- g = 288.1221695283 * Math.pow(k - 60, -0.0755148492);
891
- b = 255;
892
- }
893
- const d65R = 255;
894
- const d65G = 250.7;
895
- const d65B = 255;
896
- let gainR = r / d65R;
897
- let gainG = g / d65G;
898
- let gainB = b / d65B;
899
- const tintFactor = tint / 100;
900
- gainG *= 1 - tintFactor * 0.15;
901
- gainR *= 1 + tintFactor * 0.05;
902
- gainB *= 1 + tintFactor * 0.05;
903
- return [gainR, gainG, gainB];
904
- }
905
- function getOklabGLSL() {
906
- return `
907
- // Oklab <-> Linear sRGB (Bj\xF6rn Ottosson)
908
- vec3 flair_linear_to_oklab(vec3 c) {
909
- float l = pow(0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b, 1.0 / 3.0);
910
- float m = pow(0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b, 1.0 / 3.0);
911
- float s = pow(0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b, 1.0 / 3.0);
912
- return vec3(
913
- 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s,
914
- 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s,
915
- 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s
916
- );
917
- }
918
-
919
- vec3 flair_oklab_to_linear(vec3 lab) {
920
- float l_ = lab.x + 0.3963377774 * lab.y + 0.2158037573 * lab.z;
921
- float m_ = lab.x - 0.1055613458 * lab.y - 0.0638541728 * lab.z;
922
- float s_ = lab.x - 0.0894841775 * lab.y - 1.2914855480 * lab.z;
923
- float l = l_ * l_ * l_;
924
- float m = m_ * m_ * m_;
925
- float s = s_ * s_ * s_;
926
- return vec3(
927
- +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
928
- -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
929
- -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
930
- );
931
- }
932
- `.trim();
933
- }
934
- function getColorGradingGLSL() {
935
- return `
936
- // ASC CDL Grading
937
- vec3 flair_cdl(vec3 color, vec3 slope, vec3 offset, vec3 power, float sat) {
938
- vec3 c = pow(max(color * slope + offset, vec3(0.0)), power);
939
- float luma = dot(c, vec3(0.2126, 0.7152, 0.0722));
940
- return mix(vec3(luma), c, sat);
941
- }
942
-
943
- // 3-Way Lift / Gamma / Gain Grading
944
- vec3 flair_lift_gamma_gain(vec3 color, vec3 lift, vec3 gamma, vec3 gain) {
945
- vec3 lifted = color + lift * (vec3(1.0) - color);
946
- vec3 gained = max(lifted * gain, vec3(0.0));
947
- return pow(gained, 1.0 / max(gamma, vec3(0.0001)));
948
- }
949
- `.trim();
950
- }
951
-
952
642
  export {
953
643
  ImageLoadError,
954
644
  SVG_EDGE,
@@ -976,25 +666,6 @@ export {
976
666
  resetGlCaches,
977
667
  compileShader,
978
668
  drawFrame,
979
- createContext,
980
- srgbToLinear,
981
- linearToSrgb,
982
- srgbToLinearRgb,
983
- linearRgbToSrgb,
984
- linearSrgbToOklab,
985
- oklabToLinearSrgb,
986
- srgbToOklab,
987
- oklabToSrgb,
988
- oklabToOklch,
989
- oklchToOklab,
990
- interpolateOklab,
991
- interpolateOklch,
992
- convertColorSpace,
993
- applyAscCdl,
994
- applyLiftGammaGain,
995
- applyVibrance,
996
- getWhiteBalanceGains,
997
- getOklabGLSL,
998
- getColorGradingGLSL
669
+ createContext
999
670
  };
1000
- //# sourceMappingURL=chunk-ARKC7LDW.js.map
671
+ //# sourceMappingURL=chunk-RDU63CDO.js.map