@pixerate/flair 0.35.1 → 0.36.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.
- package/CHANGELOG.md +12 -0
- package/README.md +2 -2
- package/dist/catalog/index.d.ts +3 -3
- package/dist/catalog/index.js +2 -2
- package/dist/{chunk-VKIDRHBG.js → chunk-6B62CBTP.js} +49 -4
- package/dist/chunk-6B62CBTP.js.map +1 -0
- package/dist/{chunk-YXPMECWY.js → chunk-D4GVMDHE.js} +7 -7
- package/dist/{chunk-MOLJPWME.js → chunk-G5M777AN.js} +3 -3
- package/dist/{chunk-N5HXMQOK.js → chunk-OIRDNPMD.js} +22 -7
- package/dist/chunk-OIRDNPMD.js.map +1 -0
- package/dist/{chunk-JETRHCP3.js → chunk-XAQ5FWKS.js} +4 -4
- package/dist/chunk-XAQ5FWKS.js.map +1 -0
- package/dist/{chunk-2O3RMSOE.js → chunk-XFTSWPSX.js} +3 -3
- package/dist/{chunk-IHUNCBMF.js → chunk-Z3LKEODP.js} +2 -2
- package/dist/{chunk-JS2RTKMM.js → chunk-Z5EETGR4.js} +29 -7
- package/dist/chunk-Z5EETGR4.js.map +1 -0
- package/dist/cli.js +3 -3
- package/dist/editor/index.d.ts +2 -2
- package/dist/editor/index.js +3 -3
- package/dist/{effect-XN5FXSN5.js → effect-RXOSCAK2.js} +9 -9
- package/dist/embed/index.d.ts +2 -2
- package/dist/embed/index.js +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.js +8 -8
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +5 -5
- package/dist/{recorder-VGJ64QSM.js → recorder-YXZL6SXM.js} +2 -2
- package/dist/svelte/index.d.ts +2 -2
- package/dist/svelte/index.js +5 -5
- package/dist/{svg-DaKRPA9v.d.ts → svg-cunB0HBn.d.ts} +23 -6
- package/dist/{types-B4Wjzde0.d.ts → types-CVgiEJyP.d.ts} +1 -1
- package/dist/vector/index.d.ts +2 -2
- package/dist/vector/index.js +12 -4
- package/package.json +1 -1
- package/dist/chunk-JETRHCP3.js.map +0 -1
- package/dist/chunk-JS2RTKMM.js.map +0 -1
- package/dist/chunk-N5HXMQOK.js.map +0 -1
- package/dist/chunk-VKIDRHBG.js.map +0 -1
- /package/dist/{chunk-YXPMECWY.js.map → chunk-D4GVMDHE.js.map} +0 -0
- /package/dist/{chunk-MOLJPWME.js.map → chunk-G5M777AN.js.map} +0 -0
- /package/dist/{chunk-2O3RMSOE.js.map → chunk-XFTSWPSX.js.map} +0 -0
- /package/dist/{chunk-IHUNCBMF.js.map → chunk-Z3LKEODP.js.map} +0 -0
- /package/dist/{effect-XN5FXSN5.js.map → effect-RXOSCAK2.js.map} +0 -0
- /package/dist/{recorder-VGJ64QSM.js.map → recorder-YXZL6SXM.js.map} +0 -0
|
@@ -57,6 +57,22 @@ declare const EASES: {
|
|
|
57
57
|
readonly out: (t: number) => number;
|
|
58
58
|
};
|
|
59
59
|
type EaseName = keyof typeof EASES;
|
|
60
|
+
/**
|
|
61
|
+
* A CSS `cubic-bezier(x1, y1, x2, y2)` curve: the two control points of a
|
|
62
|
+
* curve from (0, 0) to (1, 1). `x1` and `x2` are 0–1; `y1` and `y2` may go
|
|
63
|
+
* past 0–1 to overshoot (a back ease).
|
|
64
|
+
*/
|
|
65
|
+
type CubicBezier = readonly [number, number, number, number];
|
|
66
|
+
/** An easing: one of {@link EASES} by name, or any {@link CubicBezier} curve. */
|
|
67
|
+
type SvgEase = EaseName | CubicBezier;
|
|
68
|
+
/** Whether `value` is a {@link CubicBezier}: four finite numbers with `x1` and `x2` in 0–1. */
|
|
69
|
+
declare function isCubicBezier(value: unknown): value is CubicBezier;
|
|
70
|
+
/** Whether `value` is an easing Flair plays: a name in {@link EASES} or a {@link CubicBezier}. */
|
|
71
|
+
declare const isSvgEase: (value: unknown) => value is SvgEase;
|
|
72
|
+
/** The curve as a function of time (0–1), solved for x by Newton's method with a bisection fallback. */
|
|
73
|
+
declare function cubicBezierEase([x1, y1, x2, y2]: CubicBezier): (t: number) => number;
|
|
74
|
+
/** An easing as a function of time (0–1); `fallback` when it is not given. */
|
|
75
|
+
declare function easeFunction(ease: SvgEase | undefined, fallback?: EaseName): (t: number) => number;
|
|
60
76
|
/** How long a change takes by default, in ms. */
|
|
61
77
|
declare const STEP_MS = 800;
|
|
62
78
|
/**
|
|
@@ -71,7 +87,7 @@ declare function stepStart(steps: readonly number[], step: number): number | und
|
|
|
71
87
|
declare function stepProgress(steps: readonly number[], timeMs: number, step: number, options?: {
|
|
72
88
|
delay?: number;
|
|
73
89
|
ms?: number;
|
|
74
|
-
ease?:
|
|
90
|
+
ease?: SvgEase;
|
|
75
91
|
}): number;
|
|
76
92
|
/** The key an item in a list of data keeps from one state to the next. */
|
|
77
93
|
type DataKey = (item: unknown, index: number) => string;
|
|
@@ -95,7 +111,7 @@ declare function lerpData<D>(a: D, b: D, u: number, keyOf?: DataKey): D;
|
|
|
95
111
|
*/
|
|
96
112
|
declare function stepData<D>(states: readonly D[], steps: readonly number[], timeMs: number, options?: {
|
|
97
113
|
ms?: number;
|
|
98
|
-
ease?:
|
|
114
|
+
ease?: SvgEase;
|
|
99
115
|
keyOf?: DataKey;
|
|
100
116
|
}): D;
|
|
101
117
|
/**
|
|
@@ -120,7 +136,8 @@ interface SvgAnimation {
|
|
|
120
136
|
delay?: number;
|
|
121
137
|
/** How long it takes, in ms (default {@link STEP_MS}). */
|
|
122
138
|
ms?: number;
|
|
123
|
-
|
|
139
|
+
/** A name in {@link EASES} (default `"in-out"`) or a `[x1, y1, x2, y2]` cubic-bezier curve. */
|
|
140
|
+
ease?: SvgEase;
|
|
124
141
|
/**
|
|
125
142
|
* Attributes from one value to another: numbers, colours (`#rrggbb`), or
|
|
126
143
|
* strings whose numbers change while the rest stays the same (a path's
|
|
@@ -400,8 +417,8 @@ interface AnimateCountOptions {
|
|
|
400
417
|
ms?: number;
|
|
401
418
|
/** Delay before starting in ms (default 0). */
|
|
402
419
|
delay?: number;
|
|
403
|
-
/** Easing curve (default `"out"`). */
|
|
404
|
-
ease?:
|
|
420
|
+
/** Easing curve (default `"out"`), by name or as a `[x1, y1, x2, y2]` cubic-bezier. */
|
|
421
|
+
ease?: SvgEase;
|
|
405
422
|
/** Number of decimal places (default 0). */
|
|
406
423
|
decimals?: number;
|
|
407
424
|
/** Format template where `{n}` is replaced by the formatted number (default `"{n}"`). */
|
|
@@ -418,4 +435,4 @@ interface AnimateCountOptions {
|
|
|
418
435
|
*/
|
|
419
436
|
declare function animateCount(options: AnimateCountOptions): () => void;
|
|
420
437
|
|
|
421
|
-
export { type AnimateCountOptions as A,
|
|
438
|
+
export { type AnimateCountOptions as A, parseSvg as B, type Clock as C, type DataKey as D, EASES as E, realClock as F, stepData as G, stepProgress as H, stepStart as I, svgDuration as J, svgFrame as K, svgMotionIssues as L, ManualClock as M, svgOpeningTag as N, svgView as O, writtenText as P, type SvgMotion as S, type SvgTrigger as a, SvgPlayer as b, type CubicBezier as c, type EaseName as d, SCRAMBLE_MS as e, SCROLL_RANGE as f, STEP_MS as g, SVG_PICTURE as h, type SvgAnimation as i, type SvgBox as j, type SvgEase as k, type SvgElementFrame as l, type SvgPlayerOptions as m, type SvgView as n, type SvgViewOptions as o, animateCount as p, cubicBezierEase as q, defaultDataKey as r, easeFunction as s, formatCount as t, isCubicBezier as u, isSvgEase as v, jitter as w, lerpAttr as x, lerpData as y, pageHidden as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as ControlValue, a as ControlDef } from './controls-Ec6P0Vpy.js';
|
|
2
|
-
import { S as SvgMotion, a as SvgTrigger } from './svg-
|
|
2
|
+
import { S as SvgMotion, a as SvgTrigger } from './svg-cunB0HBn.js';
|
|
3
3
|
|
|
4
4
|
/** What an effect is for, used to group the catalog. */
|
|
5
5
|
type EffectCategory = "gradient" | "organic" | "pattern" | "light" | "lighting" | "space" | "retro" | "image" | "overlay" | "text" | "morph" | "interaction" | "pyrotechnics" | "timewarp" | "melt" | "electric" | "splatter" | "bubble" | "sticker" | "trail" | "particles" | "debris" | "impact" | "comic" | "atmosphere" | "glow" | "shadow" | "distortion" | "audio" | "scroll" | "broadcast" | "annotation" | "ui" | "3d" | "weather" | "water" | "transition" | "loader" | "data" | "icon";
|
package/dist/vector/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { A as AnimateCountOptions, D as DataKey, E as EASES,
|
|
1
|
+
import { j as SvgBox, S as SvgMotion } from '../svg-cunB0HBn.js';
|
|
2
|
+
export { A as AnimateCountOptions, c as CubicBezier, D as DataKey, E as EASES, d as EaseName, e as SCRAMBLE_MS, f as SCROLL_RANGE, g as STEP_MS, h as SVG_PICTURE, i as SvgAnimation, k as SvgEase, l as SvgElementFrame, b as SvgPlayer, m as SvgPlayerOptions, a as SvgTrigger, n as SvgView, o as SvgViewOptions, p as animateCount, q as cubicBezierEase, r as defaultDataKey, s as easeFunction, t as formatCount, u as isCubicBezier, v as isSvgEase, x as lerpAttr, y as lerpData, B as parseSvg, G as stepData, H as stepProgress, I as stepStart, J as svgDuration, K as svgFrame, L as svgMotionIssues, N as svgOpeningTag, O as svgView, P as writtenText } from '../svg-cunB0HBn.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Shape morphing: any SVG paths turned into paths with the same structure, so
|
package/dist/vector/index.js
CHANGED
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
} from "../chunk-H6L67KHI.js";
|
|
8
8
|
import {
|
|
9
9
|
svgAnimatedMarkup
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-OIRDNPMD.js";
|
|
11
11
|
import {
|
|
12
12
|
parseViewBox,
|
|
13
13
|
svgFrameMarkup,
|
|
14
14
|
svgInlineLayout,
|
|
15
15
|
svgViewBox
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-G5M777AN.js";
|
|
17
17
|
import {
|
|
18
18
|
SCROLL_RANGE,
|
|
19
19
|
SvgPlayer,
|
|
@@ -21,15 +21,19 @@ import {
|
|
|
21
21
|
parseSvg,
|
|
22
22
|
svgDuration,
|
|
23
23
|
svgView
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-XAQ5FWKS.js";
|
|
25
25
|
import "../chunk-WMZQCUFJ.js";
|
|
26
26
|
import {
|
|
27
27
|
EASES,
|
|
28
28
|
SCRAMBLE_MS,
|
|
29
29
|
STEP_MS,
|
|
30
30
|
SVG_PICTURE,
|
|
31
|
+
cubicBezierEase,
|
|
31
32
|
defaultDataKey,
|
|
33
|
+
easeFunction,
|
|
32
34
|
formatCount,
|
|
35
|
+
isCubicBezier,
|
|
36
|
+
isSvgEase,
|
|
33
37
|
lerpAttr,
|
|
34
38
|
lerpData,
|
|
35
39
|
morphPaths,
|
|
@@ -41,7 +45,7 @@ import {
|
|
|
41
45
|
svgMotionIssues,
|
|
42
46
|
svgOpeningTag,
|
|
43
47
|
writtenText
|
|
44
|
-
} from "../chunk-
|
|
48
|
+
} from "../chunk-6B62CBTP.js";
|
|
45
49
|
export {
|
|
46
50
|
EASES,
|
|
47
51
|
SCRAMBLE_MS,
|
|
@@ -51,9 +55,13 @@ export {
|
|
|
51
55
|
SvgPlayer,
|
|
52
56
|
animateCount,
|
|
53
57
|
computeBoxFit,
|
|
58
|
+
cubicBezierEase,
|
|
54
59
|
defaultDataKey,
|
|
60
|
+
easeFunction,
|
|
55
61
|
formatCount,
|
|
56
62
|
formatUnit,
|
|
63
|
+
isCubicBezier,
|
|
64
|
+
isSvgEase,
|
|
57
65
|
layoutStack,
|
|
58
66
|
lerpAttr,
|
|
59
67
|
lerpData,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/flair",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"description": "Web visual effects and motion graphics: WebGL2 shader effects, animated vector effects, a catalog of ready-made effects, and a UI-agnostic, agent-ready effect editor.",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/vector/svg.ts"],"sourcesContent":["/**\n * Drawing animated SVG pictures (see `SvgMotion`) in the DOM: a sanitising\n * parser, a view that applies frames, and a player that runs on a `Clock`.\n */\n\nimport { realClock, type Clock } from \"../time/clock.js\";\nimport {\n EASES,\n formatCount,\n STEP_MS,\n SVG_PICTURE,\n svgFrame,\n svgOpeningTag,\n type EaseName,\n type SvgBox,\n type SvgMotion,\n} from \"./motion.js\";\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\";\n\n/**\n * The `<svg>` in `markup`, parsed and made safe to show: no scripts, event\n * handlers, `<foreignObject>` or links outside itself. Undefined when it is\n * not an SVG.\n */\nexport function parseSvg(markup: string): SVGSVGElement | undefined {\n // Parsed as XML, an <svg> without its namespace is not an SVG at all.\n let source = markup.trim();\n const open = svgOpeningTag(source);\n if (!/\\sxmlns\\s*=/i.test(open)) source = source.replace(/^<svg/i, `<svg xmlns=\"${SVG_NS}\"`);\n if (/xlink:/.test(source) && !/\\sxmlns:xlink\\s*=/i.test(open))\n source = source.replace(/^<svg/i, '<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"');\n const doc = new DOMParser().parseFromString(source, \"image/svg+xml\");\n const svg = doc.documentElement;\n if (svg.namespaceURI !== SVG_NS || svg.localName !== \"svg\" || doc.querySelector(\"parsererror\"))\n return undefined;\n for (const bad of svg.querySelectorAll(\"script, foreignObject\")) bad.remove();\n for (const el of [svg, ...svg.querySelectorAll(\"*\")]) {\n for (const attr of [...el.attributes]) {\n const name = attr.name.toLowerCase();\n const link = name === \"href\" || name === \"xlink:href\" || name === \"src\";\n if (name.startsWith(\"on\") || (link && !/^(#|data:image\\/)/i.test(attr.value.trim())))\n el.removeAttribute(attr.name);\n }\n }\n return document.importNode(svg, true) as unknown as SVGSVGElement;\n}\n\n/** Live views made so far, for ids unique on the page (see {@link scopeIds}). */\nlet views = 0;\n\nconst URL_REF = /url\\(\\s*(['\"]?)#([^'\")\\s]+)\\1\\s*\\)/g;\n\n/**\n * Gives the ids a live picture refers to (by `url(#…)` in attributes and\n * styles, or `href=\"#…\"`: its gradients, filters, clips, masks, `<use>`d\n * shapes) `suffix`, and points the references at the new ids, so two\n * pictures on one page that both define `id=\"glow\"` each use their own.\n * Other ids stay as written. The original id is kept in `data-flair-id`;\n * returns how ids map.\n */\nfunction scopeIds(svg: Element, suffix: string): Map<string, string> {\n const all = [svg, ...svg.querySelectorAll(\"*\")];\n const referred = new Set<string>();\n for (const el of all) {\n const texts = [...el.attributes].map((a) => [a.name.toLowerCase(), a.value] as const);\n if (el.localName === \"style\") texts.push([\"\", el.textContent ?? \"\"]);\n for (const [name, value] of texts) {\n if ((name === \"href\" || name === \"xlink:href\") && value.startsWith(\"#\")) referred.add(value.slice(1));\n for (const m of value.matchAll(URL_REF)) referred.add(m[2]!);\n }\n }\n const ids = new Map<string, string>();\n for (const el of all) {\n if (!el.id || !referred.has(el.id) || ids.has(el.id)) continue;\n ids.set(el.id, `${el.id}-${suffix}`);\n el.setAttribute(\"data-flair-id\", el.id);\n el.id = `${el.id}-${suffix}`;\n }\n if (ids.size)\n for (const el of [svg, ...svg.querySelectorAll(\"*\")]) {\n for (const attr of [...el.attributes]) {\n const scoped = scopedRefs(attr.value, ids, attr.name);\n if (scoped !== attr.value) attr.value = scoped;\n }\n if (el.localName === \"style\" && el.textContent) el.textContent = scopedRefs(el.textContent, ids);\n }\n return ids;\n}\n\n/** `value` with its references to ids in `ids` pointed at their scoped ids. */\nfunction scopedRefs(value: string, ids: ReadonlyMap<string, string>, attr = \"\"): string {\n const name = attr.toLowerCase();\n if (name === \"href\" || name === \"xlink:href\") {\n const to = value.startsWith(\"#\") ? ids.get(value.slice(1)) : undefined;\n return to ? `#${to}` : value;\n }\n if (!value.includes(\"url(\")) return value;\n return value.replace(URL_REF, (whole, quote: string, id: string) => {\n const to = ids.get(id);\n return to ? `url(${quote}#${to}${quote})` : whole;\n });\n}\n\n/** Share of an element's size left round it when a `view` frames it. */\nconst VIEW_MARGIN = 0.12;\n\n/**\n * The box a `view` frames, in viewBox units: a box as given, an element's\n * box with a margin, widened to the picture's shape so the zoom does not\n * skew, or the whole picture for `null`.\n */\nfunction viewBox(view: SvgBox | string | null, whole: SvgBox, byId: Map<string, Element>): SvgBox {\n if (view === null) return whole;\n if (typeof view !== \"string\") return view;\n const el = byId.get(view) as SVGGraphicsElement | undefined;\n let box: DOMRect | undefined;\n try {\n box = el?.getBBox?.();\n } catch {\n // Not laid out (or not drawable): keep the whole picture.\n }\n if (!box || !(box.width > 0 || box.height > 0)) return whole;\n // In the picture's own units: through the element's transforms (a point\n // placed with one), which its box leaves out.\n try {\n const svg = el!.ownerSVGElement;\n const m = svg?.getScreenCTM()?.inverse().multiply(el!.getScreenCTM()!);\n if (m) {\n const corners = [\n [box.x, box.y],\n [box.x + box.width, box.y],\n [box.x, box.y + box.height],\n [box.x + box.width, box.y + box.height],\n ].map(([x, y]) => new DOMPoint(x, y).matrixTransform(m));\n const xs = corners.map((p) => p.x);\n const ys = corners.map((p) => p.y);\n box = new DOMRect(\n Math.min(...xs),\n Math.min(...ys),\n Math.max(...xs) - Math.min(...xs),\n Math.max(...ys) - Math.min(...ys),\n );\n }\n } catch {\n // Not laid out: keep its own box.\n }\n const aspect = whole[2] / whole[3];\n let w = box.width * (1 + 2 * VIEW_MARGIN);\n let h = box.height * (1 + 2 * VIEW_MARGIN);\n if (w / h > aspect) h = w / aspect;\n else w = h * aspect;\n return [box.x + box.width / 2 - w / 2, box.y + box.height / 2 - h / 2, w, h];\n}\n\n/**\n * Keeps the picture's `data-nonscaling` elements (a map's pins and labels)\n * the same size on screen as a `view` zooms: each is scaled round its own\n * origin by how far the picture is zoomed (so draw it round (0, 0) inside a\n * group that places it).\n */\nfunction keepSize(svg: SVGSVGElement, whole: SvgBox, nonscaling: Element[]) {\n if (!nonscaling.length) return;\n const width = Number((svg.getAttribute(\"viewBox\") ?? \"\").trim().split(/[\\s,]+/)[2]);\n const zoom = width > 0 ? width / whole[2] : 1;\n const transform = Math.abs(zoom - 1) < 1e-4 ? \"\" : `scale(${+zoom.toFixed(4)})`;\n for (const el of nonscaling)\n if ((el.getAttribute(\"transform\") ?? \"\") !== transform)\n if (transform) el.setAttribute(\"transform\", transform);\n else el.removeAttribute(\"transform\");\n}\n\n/** Applies a frame of the media's animations to `svg`. */\nfunction apply(\n svg: SVGSVGElement,\n whole: SvgBox,\n byId: Map<string, Element>,\n motion: SvgMotion,\n timeMs: number,\n steps: readonly number[],\n ids: ReadonlyMap<string, string> = new Map(),\n) {\n for (const [id, frame] of svgFrame(motion.animate ?? [], steps, timeMs)) {\n if (id === SVG_PICTURE && frame.view) {\n const a = viewBox(frame.view.from, whole, byId);\n const b = viewBox(frame.view.to, whole, byId);\n const u = frame.view.u;\n svg.setAttribute(\"viewBox\", a.map((n, i) => +(n + (b[i]! - n) * u).toFixed(2)).join(\" \"));\n continue;\n }\n const el = byId.get(id);\n if (!el) continue;\n for (const [name, value] of Object.entries(frame.attrs)) el.setAttribute(name, scopedRefs(value, ids, name));\n if (frame.draw !== undefined) {\n // A path length of 1 lets the dash be a fraction, with nothing measured.\n el.setAttribute(\"pathLength\", \"1\");\n el.setAttribute(\"stroke-dasharray\", \"1 1\");\n el.setAttribute(\"stroke-dashoffset\", String(1 - frame.draw));\n }\n if (frame.text !== undefined) el.textContent = frame.text;\n if (frame.solo !== undefined) {\n const children = Array.from(el.children);\n children.forEach((child, idx) => {\n if (child instanceof SVGElement || child instanceof HTMLElement) {\n if (idx === frame.solo) {\n child.removeAttribute(\"display\");\n } else {\n child.setAttribute(\"display\", \"none\");\n }\n }\n });\n }\n if (frame.along) {\n const path = byId.get(frame.along.path) as SVGGeometryElement | undefined;\n try {\n const length = path?.getTotalLength?.();\n if (path && length !== undefined) {\n const p = path.getPointAtLength(frame.along.at * length);\n el.setAttribute(\"transform\", `translate(${+p.x.toFixed(2)} ${+p.y.toFixed(2)})`);\n }\n } catch {\n // Not laid out: leave it where it is.\n }\n }\n }\n}\n\nconst VAR = /var\\(\\s*(--[\\w-]+)\\s*(?:,\\s*([^()]*(?:\\([^()]*\\)[^()]*)*))?\\)/g;\n\n/**\n * `copy` with the CSS variables in its attributes and styles replaced by\n * their values on `live` (its original, in the page), or their fallbacks:\n * an image of the SVG is drawn on its own, where the page's variables (a\n * host's palette) mean nothing.\n */\nfunction resolveVariables(live: SVGSVGElement, copy: SVGSVGElement) {\n const originals = [live, ...live.querySelectorAll(\"*\")];\n const copies = [copy, ...copy.querySelectorAll(\"*\")];\n copies.forEach((el, i) => {\n let style: CSSStyleDeclaration | undefined;\n for (const attr of [...el.attributes]) {\n if (!attr.value.includes(\"var(\")) continue;\n style ??= getComputedStyle(originals[i] ?? live);\n el.setAttribute(\n attr.name,\n attr.value.replace(\n VAR,\n (_, name: string, fallback?: string) =>\n style!.getPropertyValue(name).trim() || fallback?.trim() || \"\",\n ),\n );\n }\n });\n}\n\n/** An image of the picture as drawn now (its layers in order), at `pixels`. */\nasync function rasterize(layers: SVGSVGElement[], pixels: { width: number; height: number }): Promise<HTMLCanvasElement> {\n const canvas = document.createElement(\"canvas\");\n canvas.width = pixels.width;\n canvas.height = pixels.height;\n const defs = layers[0]?.querySelector(\"defs\");\n for (const [i, svg] of layers.entries()) {\n const copy = svg.cloneNode(true) as SVGSVGElement;\n resolveVariables(svg, copy);\n // A fixed layer's gradients and markers live in the picture's <defs>.\n if (i > 0 && defs) copy.prepend(defs.cloneNode(true));\n copy.setAttribute(\"xmlns\", SVG_NS);\n copy.setAttribute(\"width\", String(pixels.width));\n copy.setAttribute(\"height\", String(pixels.height));\n const url = URL.createObjectURL(\n new Blob([new XMLSerializer().serializeToString(copy)], { type: \"image/svg+xml\" }),\n );\n try {\n const image = new Image();\n image.src = url;\n await image.decode();\n canvas.getContext(\"2d\")!.drawImage(image, 0, 0, pixels.width, pixels.height);\n } finally {\n URL.revokeObjectURL(url);\n }\n }\n return canvas;\n}\n\n/**\n * Moves the picture's `data-fixed` elements (titles, legends, notes) into a\n * layer over it that keeps the original `viewBox`, so a `view` zooms the\n * picture under them while they stay put. Undefined when it has none.\n */\nfunction fixedLayer(svg: SVGSVGElement): SVGSVGElement | undefined {\n const fixed = [...svg.querySelectorAll(\"[data-fixed]\")].filter(\n (el) => !el.parentElement?.closest(\"[data-fixed]\"),\n );\n if (!fixed.length) return undefined;\n // The picture's own attributes (viewBox, fonts, fills) without its id.\n const layer = svg.cloneNode(false) as SVGSVGElement;\n layer.removeAttribute(\"id\");\n layer.setAttribute(\"aria-hidden\", \"true\");\n layer.style.cssText = \"position:absolute;inset:0;overflow:visible\";\n for (const el of fixed) layer.appendChild(el);\n return layer;\n}\n\nexport interface SvgViewOptions {\n /**\n * Called with the id of the innermost element with an id that is clicked:\n * its id in the motion's markup (in the page, ids carry a suffix that keeps\n * them unique, so several pictures can use the same ones).\n */\n onPick?: (id: string) => void;\n}\n\n/** An {@link SvgMotion} drawn into an element; call `draw` with a time to show it then. */\nexport interface SvgView {\n /** A `div` filled by the picture; put it anywhere. */\n readonly element: HTMLDivElement;\n /** Shows the picture at `timeMs`, with steps starting at `steps` (ms). */\n draw(timeMs: number, steps?: readonly number[]): void;\n /** An image of the picture as drawn now. */\n capture(pixels: { width: number; height: number }): Promise<HTMLCanvasElement | undefined>;\n}\n\n/** Shows an {@link SvgMotion} as a live view; with `onPick`, clicks report the id of the element clicked. */\nexport function svgView(motion: SvgMotion, options: SvgViewOptions = {}): SvgView {\n const element = document.createElement(\"div\");\n element.style.width = \"100%\";\n element.style.height = \"100%\";\n const { onPick } = options;\n if (onPick)\n element.addEventListener(\"click\", (event) => {\n // The innermost element with an id, up to the picture itself.\n for (let el = event.target as Element | null; el && el !== element; el = el.parentElement)\n if (el.id && el.localName !== \"svg\") return onPick(el.getAttribute(\"data-flair-id\") ?? el.id);\n });\n let svg: SVGSVGElement | undefined | null = null;\n let fixed: SVGSVGElement | undefined;\n let nonscaling: Element[] = [];\n let whole: SvgBox = [0, 0, 100, 100];\n const byId = new Map<string, Element>();\n let ids: ReadonlyMap<string, string> = new Map();\n const suffix = `f${++views}`;\n return {\n element,\n draw(timeMs, steps = []) {\n if (svg === null) {\n // Parsed on first use, so a view made and dropped costs nothing.\n svg = parseSvg(motion.svg);\n if (svg) {\n ids = scopeIds(svg, suffix);\n svg.setAttribute(\"width\", \"100%\");\n svg.setAttribute(\"height\", \"100%\");\n element.appendChild(svg);\n fixed = fixedLayer(svg);\n if (fixed) {\n element.style.position = \"relative\";\n element.appendChild(fixed);\n }\n for (const layer of [svg, fixed])\n for (const el of layer?.querySelectorAll(\"[id]\") ?? [])\n byId.set(el.getAttribute(\"data-flair-id\") ?? el.id, el);\n nonscaling = [...svg.querySelectorAll(\"[data-nonscaling]\")];\n const box = (svg.getAttribute(\"viewBox\") ?? \"\")\n .trim()\n .split(/[\\s,]+/)\n .map(Number);\n if (box.length === 4 && box.every(Number.isFinite)) whole = box as unknown as SvgBox;\n }\n }\n if (svg) {\n apply(svg, whole, byId, motion, timeMs, steps, ids);\n keepSize(svg, whole, nonscaling);\n }\n },\n capture: async (pixels) => (svg ? rasterize(fixed ? [svg, fixed] : [svg], pixels) : undefined),\n };\n}\n\n/** How long an {@link SvgMotion} runs: its last change's end, in ms (at least 1). */\nexport function svgDuration(motion: SvgMotion, steps: readonly number[] = []): number {\n let end = 0;\n for (const a of motion.animate ?? []) {\n const step = a.step ?? 0;\n const start = step <= 0 ? 0 : steps[step - 1];\n if (start === undefined) continue;\n end = Math.max(end, start + (a.delay ?? 0) + (a.ms ?? 800));\n }\n return Math.max(1, end);\n}\n\nexport interface SvgPlayerOptions extends SvgViewOptions {\n /** Time source (default: animation frames). Pass a `ManualClock` to step frames yourself. */\n clock?: Clock;\n /** Start playing at once (default `true`). */\n autoplay?: boolean;\n /**\n * Start again at the end (default `true`). When `false` it plays once and\n * stays on the last frame (hidden instead with `hideWhenPaused`).\n */\n loop?: boolean;\n /** Loop length in ms (default: the picture's own, see {@link svgDuration}, plus `hold`). */\n duration?: number;\n /** Ms to rest on the last frame before looping (default 600). */\n hold?: number;\n /** Playback speed (default 1). */\n speed?: number;\n /** Step start times in ms, for pictures that change on steps (default none). */\n steps?: readonly number[];\n /** Pause the animation loop when scrolled out of view via IntersectionObserver (default false). */\n pauseWhenHidden?: boolean;\n /** Wait to start playing until the element enters the viewport via IntersectionObserver (default false). When true, autoplay is deferred until first visible. */\n playOnEnter?: boolean;\n /** Hide the view (`visibility: hidden`) whenever playback is paused or reset (default false). */\n hideWhenPaused?: boolean;\n /**\n * Plays in answer to the pointer or the page instead of on its own (see\n * {@link SvgTrigger}): `\"hover\"` and `\"press\"` play to the end while\n * hovered or held and back to the start after; `\"click\"` plays the next\n * step on each click, starting over after the last; `\"scroll\"` follows\n * the trigger target's progress through the viewport (see `scrollRange`),\n * scrubbing back and forth as the page scrolls. `autoplay`, `loop` and\n * `steps` are ignored.\n */\n trigger?: SvgTrigger;\n /** The element whose pointer events trigger it, or whose scrolling a scroll trigger follows (default the container). */\n triggerTarget?: HTMLElement;\n /**\n * For a scroll trigger: the stretch of the target's progress through the\n * viewport (0 as its top comes in at the bottom, 1 as its bottom leaves at\n * the top) over which the picture plays from start to end (default\n * `[0.1, 0.6]`: from just after it comes into view to a little past the\n * middle).\n */\n scrollRange?: readonly [number, number];\n}\n\n/** What makes a triggered {@link SvgPlayer} play. */\nexport type SvgTrigger = \"hover\" | \"press\" | \"click\" | \"scroll\";\n\n/** The stretch of the viewport a scroll-triggered picture plays over (see `SvgPlayerOptions.scrollRange`). */\nexport const SCROLL_RANGE: readonly [number, number] = [0.1, 0.6];\n\n/**\n * Plays an {@link SvgMotion} inside `container`: loops by default, and can be\n * paused, sought and sped up. Dispose it to stop and remove the picture.\n */\nexport class SvgPlayer {\n readonly view: SvgView;\n private readonly clock: Clock;\n private steps: readonly number[];\n private readonly loop: boolean;\n private length: number;\n private readonly motion: SvgMotion;\n private readonly trigger?: SvgTrigger;\n private readonly triggerTarget?: HTMLElement;\n /** With a hover or press trigger: 1 playing to the end, -1 back to the start. */\n private direction = 1;\n /** With a click trigger: when each click came, in ms of playback. */\n private clicks: number[] = [];\n private readonly hideWhenPaused: boolean;\n private speed: number;\n private time = 0;\n private last = 0;\n private playing = false;\n private disposed = false;\n private wasPlayingBeforeHidden = false;\n private hasEnteredViewport = false;\n private intersectionObserver?: IntersectionObserver;\n private readonly scrollRange: readonly [number, number];\n /** A scroll trigger's pending update (one per frame). */\n private scrollFrame = 0;\n private followingScroll = false;\n\n constructor(\n private readonly container: HTMLElement,\n motion: SvgMotion,\n options: SvgPlayerOptions = {},\n ) {\n this.clock = options.clock ?? realClock;\n this.motion = motion;\n this.trigger = options.trigger;\n this.steps = this.trigger ? [] : (options.steps ?? []);\n this.loop = this.trigger ? false : (options.loop ?? true);\n this.speed = options.speed ?? 1;\n this.hideWhenPaused = Boolean(options.hideWhenPaused);\n this.scrollRange = options.scrollRange ?? SCROLL_RANGE;\n this.length = options.duration ?? svgDuration(motion, this.steps) + (options.hold ?? 600);\n this.view = svgView(motion, options);\n container.appendChild(this.view.element);\n this.view.draw(0, this.steps);\n\n const needsObserver =\n (options.pauseWhenHidden || options.playOnEnter) && typeof IntersectionObserver !== \"undefined\";\n\n if (needsObserver) {\n this.intersectionObserver = new IntersectionObserver(([entry]) => {\n if (!entry) return;\n if (entry.isIntersecting) {\n if (options.playOnEnter && !this.hasEnteredViewport) {\n this.hasEnteredViewport = true;\n if (options.autoplay ?? true) {\n this.play();\n }\n } else if (this.wasPlayingBeforeHidden) {\n this.wasPlayingBeforeHidden = false;\n this.play();\n }\n } else {\n if (this.playing && options.pauseWhenHidden) {\n this.wasPlayingBeforeHidden = true;\n this.pause();\n }\n }\n });\n this.intersectionObserver.observe(this.view.element);\n }\n\n if (this.trigger === \"scroll\") {\n this.length = options.duration ?? svgDuration(motion);\n this.triggerTarget = options.triggerTarget ?? container;\n this.followingScroll = true;\n this.listen(true);\n this.followScroll();\n return;\n }\n\n if (this.trigger) {\n // A click-triggered picture runs until its latest step is over, however many clicks.\n // Hovers and presses run to the last change and back, with no rest to wait through.\n this.length = this.trigger === \"click\" ? Infinity : (options.duration ?? svgDuration(motion));\n this.triggerTarget = options.triggerTarget ?? container;\n this.listen(true);\n return;\n }\n\n // Without IntersectionObserver (a server, a test), nothing would say it entered: play at once.\n const shouldAutoplay = (options.autoplay ?? true) && !(options.playOnEnter && needsObserver);\n if (shouldAutoplay) {\n this.play();\n } else if (this.hideWhenPaused) {\n this.view.element.style.visibility = \"hidden\";\n }\n }\n\n /** The loop length in ms. */\n get duration(): number {\n return this.length;\n }\n\n /** The time shown, in ms. */\n get currentTime(): number {\n return this.time;\n }\n\n get isPlaying(): boolean {\n return this.playing;\n }\n\n play(): void {\n if (this.playing || this.disposed) return;\n this.playing = true;\n if (this.hideWhenPaused) this.view.element.style.visibility = \"visible\";\n this.last = this.clock.now();\n void this.run();\n }\n\n pause(): void {\n this.playing = false;\n if (this.hideWhenPaused) this.view.element.style.visibility = \"hidden\";\n }\n\n /** Stops playback, rewinds to `0 ms`, and hides the view if `hideWhenPaused` is enabled. */\n reset(): void {\n this.playing = false;\n this.wasPlayingBeforeHidden = false;\n this.seek(0);\n if (this.hideWhenPaused) this.view.element.style.visibility = \"hidden\";\n }\n\n /** Shows the picture at `ms` (wrapped into the loop when looping). */\n seek(ms: number): void {\n this.time = this.loop\n ? ((ms % this.length) + this.length) % this.length\n : Math.min(Math.max(ms, 0), this.length);\n this.view.draw(this.time, this.steps);\n }\n\n /**\n * Shows the picture at `progress` of the way through it, 0–1: how hosts\n * scrub it themselves (a slider, a scroll position of their own). A scroll\n * trigger stops following the page once a host calls this.\n */\n setProgress(progress: number): void {\n if (this.followingScroll) {\n this.followingScroll = false;\n this.listen(false);\n }\n this.playing = false;\n this.seek(Math.min(1, Math.max(0, progress)) * (Number.isFinite(this.length) ? this.length : svgDuration(this.motion, this.steps)));\n }\n\n /**\n * A scroll trigger's playback position, 0–1, for the trigger target's\n * `progress` through the viewport (see {@link SvgPlayerOptions.scrollRange}).\n */\n scrollPosition(progress: number): number {\n const [from, to] = this.scrollRange;\n return to > from ? Math.min(1, Math.max(0, (progress - from) / (to - from))) : progress >= to ? 1 : 0;\n }\n\n setSpeed(speed: number): void {\n this.speed = speed;\n }\n\n /**\n * Plays to the end (`true`) or back to the start (`false`) from wherever it\n * is: what a hover or press trigger does, for hosts that drive it themselves\n * (a hovered card, a focused button).\n */\n setActive(active: boolean): void {\n this.direction = active ? 1 : -1;\n this.play();\n }\n\n /**\n * Plays the picture's next step (what a click trigger does): steps 1, 2, …\n * in turn, then step 1 again, so a picture whose last step leads back to\n * how it started toggles; one with no steps plays again from the start.\n */\n advance(): void {\n const last = Math.max(0, ...(this.motion.animate ?? []).map((a) => a.step ?? 0));\n if (last === 0) {\n this.clicks = [];\n this.time = 0;\n } else {\n this.clicks.push(this.time);\n // Only the clicks of the current round count, so each round starts from how the last ended.\n this.steps = this.clicks.slice(Math.floor((this.clicks.length - 1) / last) * last);\n }\n this.view.draw(this.time, this.steps);\n this.play();\n }\n\n dispose(): void {\n this.disposed = true;\n this.playing = false;\n if (this.trigger && (this.trigger !== \"scroll\" || this.followingScroll)) this.listen(false);\n if (this.scrollFrame && typeof cancelAnimationFrame !== \"undefined\") cancelAnimationFrame(this.scrollFrame);\n this.intersectionObserver?.disconnect();\n this.view.element.remove();\n }\n\n private onEnter = () => this.setActive(true);\n private onLeave = () => this.setActive(false);\n private onClick = () => this.advance();\n\n /** Seeks to where the trigger target is in the viewport. */\n private followScroll = () => {\n this.scrollFrame = 0;\n if (!this.followingScroll || this.disposed) return;\n const rect = this.triggerTarget!.getBoundingClientRect();\n const viewport = window.innerHeight || document.documentElement.clientHeight || 1;\n const travel = viewport + rect.height;\n const progress = travel > 0 ? Math.min(1, Math.max(0, (viewport - rect.top) / travel)) : 0;\n this.seek(this.scrollPosition(progress) * this.length);\n };\n\n /** A scroll or resize: follow it on the next frame (or now, without frames). */\n private onScroll = () => {\n if (typeof requestAnimationFrame === \"undefined\") return this.followScroll();\n if (!this.scrollFrame) this.scrollFrame = requestAnimationFrame(this.followScroll);\n };\n\n private listen(on: boolean) {\n const target = this.triggerTarget!;\n const method = on ? \"addEventListener\" : \"removeEventListener\";\n if (this.trigger === \"scroll\") {\n // Any scroll that may move the target: the page's or a scrolling element's.\n window[method](\"scroll\", this.onScroll, { capture: true, passive: true } as AddEventListenerOptions);\n window[method](\"resize\", this.onScroll, { passive: true } as AddEventListenerOptions);\n } else if (this.trigger === \"hover\") {\n target[method](\"pointerenter\", this.onEnter);\n target[method](\"pointerleave\", this.onLeave);\n } else if (this.trigger === \"press\") {\n target[method](\"pointerdown\", this.onEnter);\n window[method](\"pointerup\", this.onLeave);\n window[method](\"pointercancel\", this.onLeave);\n } else target[method](\"click\", this.onClick);\n }\n\n private async run(): Promise<void> {\n while (this.playing && !this.disposed) {\n await this.clock.frame();\n if (!this.playing || this.disposed) return;\n const now = this.clock.now();\n const dt = (now - this.last) * this.speed;\n this.last = now;\n if (this.trigger === \"click\") {\n // Rest once the latest step is over, until the next click.\n const end = svgDuration(this.motion, this.steps);\n this.time = Math.min(this.time + dt, Math.max(end, this.time));\n this.view.draw(this.time, this.steps);\n if (this.time >= end) this.playing = false;\n continue;\n }\n if (this.trigger) {\n const next = Math.min(Math.max(this.time + dt * this.direction, 0), this.length);\n this.seek(next);\n if (next === 0 || next === this.length) this.playing = false;\n continue;\n }\n const next = this.time + dt;\n if (!this.loop && next >= this.length) {\n this.seek(this.length);\n this.playing = false;\n if (this.hideWhenPaused) this.view.element.style.visibility = \"hidden\";\n return;\n }\n this.seek(next);\n }\n }\n}\n\nexport interface AnimateCountOptions {\n /** Starting number. */\n from: number;\n /** Ending number. */\n to: number;\n /** Duration in ms (default {@link STEP_MS}). */\n ms?: number;\n /** Delay before starting in ms (default 0). */\n delay?: number;\n /** Easing curve (default `\"out\"`). */\n ease?: EaseName;\n /** Number of decimal places (default 0). */\n decimals?: number;\n /** Format template where `{n}` is replaced by the formatted number (default `\"{n}\"`). */\n format?: string;\n /** Time source (default: animation frames). */\n clock?: Clock;\n /** Called with each formatted text frame (and raw numeric value). */\n onUpdate: (text: string, value: number) => void;\n}\n\n/**\n * Counts a number from `from` to `to` over `ms` using Flair's easing curves\n * and `Clock`, calling `onUpdate` with the formatted string on each frame.\n * Returns a cancel function that stops the animation.\n */\nexport function animateCount(options: AnimateCountOptions): () => void {\n const clock = options.clock ?? realClock;\n const ms = options.ms ?? STEP_MS;\n const delay = options.delay ?? 0;\n const ease = EASES[options.ease ?? \"out\"];\n const start = clock.now();\n let stopped = false;\n\n const emit = (u: number) => {\n const v = options.from + (options.to - options.from) * ease(u);\n options.onUpdate(formatCount(v, options), v);\n };\n\n emit(ms <= 0 && delay <= 0 ? 1 : 0);\n if (ms <= 0 && delay <= 0) return () => {};\n\n void (async () => {\n while (!stopped) {\n await clock.frame();\n if (stopped) return;\n const elapsed = clock.now() - start - delay;\n if (elapsed < 0) continue;\n if (ms <= 0 || elapsed >= ms) {\n emit(1);\n return;\n }\n emit(elapsed / ms);\n }\n })();\n\n return () => {\n stopped = true;\n };\n}\n"],"mappings":"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","names":["next"]}
|
|
@@ -1 +0,0 @@
|
|
|
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`, `iTrail`, `iAudio`, `iSpectrum`, `iBeat` and `iScroll` included, is\n * declared; the audio and scroll ones stay 0, so those effects play their idle\n * demos), 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 '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\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 = Number(process.env.FLAIR_STALL_TIMEOUT_MS) || 120_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"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/vector/animated.ts"],"sourcesContent":["/**\n * An {@link SvgMotion} as one self-contained animated `.svg` file, with no\n * DOM and no script: its changes written as SMIL (`<animate>`,\n * `<animateTransform>`, `<animateMotion>`), so it plays on its own wherever\n * an SVG image does (an `<img src>`, a file opened directly, inline markup).\n */\n\nimport { pathPointAt } from \"./morph.js\";\nimport {\n STEP_MS,\n SVG_PICTURE,\n stepStart,\n svgFrame,\n type EaseName,\n type SvgAnimation,\n type SvgBox,\n type SvgElementFrame,\n type SvgMotion,\n} from \"./motion.js\";\nimport { getAttr, serialize, setAttr, svgFrameTree, type SvgNode } from \"./static.js\";\nimport { svgDuration } from \"./svg.js\";\n\nexport interface AnimatedSvgOptions {\n /** Loop length in ms (default: `svgDuration(motion, steps)` + `hold`). */\n duration?: number;\n /** Ms to rest on the last frame before looping (default 600, like `SvgPlayer`). */\n hold?: number;\n /** Loop forever (default true); false plays once and holds the last frame. */\n loop?: boolean;\n /** Step start times in ms, for pictures that change on steps (like `SvgPlayer`'s `steps`). */\n steps?: readonly number[];\n /**\n * Samples per second for what cannot be written exactly (counts, written\n * text, a change cut short by the next, a `matrix` transform); default 30.\n */\n fps?: number;\n /**\n * Added to the ids the picture refers to (its gradients, filters, clips,\n * paths followed), so two files inlined in one page each use their own.\n * Default: a hash of the motion, so the same motion gives the same file;\n * `\"\"` keeps ids as written.\n */\n idSuffix?: string;\n}\n\n/** How a value gets to a keyframe from the one before: the shapes `EASES` are made of. */\ntype Shape = \"linear\" | \"in\" | \"out\";\n\n/** A channel's value at a time, reached from the keyframe before along `shape`. */\ninterface Key {\n t: number;\n v: string;\n shape: Shape;\n}\n\n/** One change to a channel, when it starts. */\ninterface Change {\n anim: SvgAnimation;\n start: number;\n}\n\n/**\n * Cubic Bézier timing for each shape. `out` (1 − (1 − t)³) is exactly the\n * curve (0, 1, 1, 1), and `in-out` is `in` (t³, the curve (0, 0, 0, 1)) to\n * its middle then `out`, so eases are written exactly, not sampled.\n */\nconst SPLINES: Record<Shape, string> = { linear: \"0 0 1 1\", in: \"0.3333 0 0.6667 0\", out: \"0.3333 1 0.6667 1\" };\n\n/** When an ease is halfway (where a value that cannot blend switches), as a share of its time. */\nconst HALFWAY: Record<EaseName, number> = { linear: 0.5, \"in-out\": 0.5, out: 1 - 0.5 ** (1 / 3) };\n\nconst NUMBER = /-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\nconst HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\nconst TRANSFORMS = new Set([\"transform\", \"gradienttransform\", \"patterntransform\"]);\nconst URL_REF = /url\\(\\s*(['\"]?)#([^'\")\\s]+)\\1\\s*\\)/g;\n\n/** Whether `lerpAttr` blends two values (else it switches halfway), so SMIL can interpolate them. */\nfunction blends(a: string | number, b: string | number): boolean {\n if (typeof a === \"number\" && typeof b === \"number\") return true;\n const [sa, sb] = [String(a), String(b)];\n if (HEX.test(sa) && HEX.test(sb)) return true;\n const na = sa.match(NUMBER) ?? [];\n return na.length > 0 && na.length === (sb.match(NUMBER) ?? []).length && sa.replace(NUMBER, \"#\") === sb.replace(NUMBER, \"#\");\n}\n\nconst num = (n: number) => String(+n.toFixed(3));\n\n/** A short, stable hash of a string, for default id suffixes. */\nfunction hash(s: string): string {\n let h = 0x811c9dc5;\n for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 0x01000193);\n return (h >>> 0).toString(36);\n}\n\n/** An element: `<tag attrs/>`. */\nconst node = (tag: string, attrs: Record<string, string | undefined>, children: SvgNode[\"children\"] = []): SvgNode => ({\n tag,\n attrs: Object.entries(attrs).filter((e): e is [string, string] => e[1] !== undefined),\n children,\n});\n\n/**\n * The transform functions in a `transform` value, with their arguments:\n * `translate(10 20) rotate(45)` → [[\"translate\", [10, 20]], [\"rotate\", [45]]].\n */\nfunction transformList(value: string): [string, number[]][] {\n return [...value.matchAll(/([a-z]+)\\s*\\(([^)]*)\\)/gi)].map((m) => [m[1]!, (m[2]!.match(NUMBER) ?? []).map(Number)]);\n}\n\n/** A transform list as one matrix [a b c d e f]. */\nfunction transformMatrix(value: string): number[] {\n let m = [1, 0, 0, 1, 0, 0];\n const times = (n: number[]) => {\n const [a, b, c, d, e, f] = m as [number, number, number, number, number, number];\n m = [a * n[0]! + c * n[1]!, b * n[0]! + d * n[1]!, a * n[2]! + c * n[3]!, b * n[2]! + d * n[3]!, a * n[4]! + c * n[5]! + e, b * n[4]! + d * n[5]! + f];\n };\n const rad = Math.PI / 180;\n for (const [name, [p = 0, q, r = 0, s = 0, t = 0, u = 0]] of transformList(value)) {\n if (name === \"translate\") times([1, 0, 0, 1, p, q ?? 0]);\n else if (name === \"scale\") times([p, 0, 0, q ?? p, 0, 0]);\n else if (name === \"rotate\") {\n const [cos, sin] = [Math.cos(p * rad), Math.sin(p * rad)];\n const [cx, cy] = [q ?? 0, r];\n times([1, 0, 0, 1, cx, cy]);\n times([cos, sin, -sin, cos, 0, 0]);\n times([1, 0, 0, 1, -cx, -cy]);\n } else if (name === \"skewX\") times([1, 0, Math.tan(p * rad), 1, 0, 0]);\n else if (name === \"skewY\") times([1, Math.tan(p * rad), 0, 1, 0, 0]);\n else if (name === \"matrix\") times([p, q ?? 0, r, s, t, u]);\n }\n return m;\n}\n\n/** A matrix as translate · rotate · skewX · scale (degrees), the order SMIL can add them in. */\nfunction decompose([a, b, c, d, e, f]: number[]): [number, number, number, number, number, number] {\n const sx = Math.hypot(a!, b!);\n const angle = sx ? Math.atan2(b!, a!) : 0;\n const [cos, sin] = [Math.cos(angle), Math.sin(angle)];\n const sy = -sin * c! + cos * d!;\n const skew = sy ? Math.atan((cos * c! + sin * d!) / sy) : 0;\n return [e!, f!, (angle * 180) / Math.PI, (skew * 180) / Math.PI, sx, sy];\n}\n\n/** A shape's outline as a path `d`, for following it with `along`. */\nfunction outline(el: SvgNode): string | undefined {\n const at = (name: string) => Number(getAttr(el, name) ?? 0);\n switch (el.tag.toLowerCase()) {\n case \"path\":\n return getAttr(el, \"d\");\n case \"line\":\n return `M${at(\"x1\")} ${at(\"y1\")}L${at(\"x2\")} ${at(\"y2\")}`;\n case \"polyline\":\n case \"polygon\":\n return `M${getAttr(el, \"points\") ?? \"\"}${el.tag.toLowerCase() === \"polygon\" ? \"Z\" : \"\"}`;\n default:\n return undefined;\n }\n}\n\n/**\n * The timing attributes that play `keys` over the loop: `keyTimes` and,\n * where a key eases in, `keySplines`. Keys at the same time are a jump.\n */\nfunction timing(keys: readonly Key[], loop: number, repeat: boolean, discrete = false): Record<string, string | undefined> {\n const spline = !discrete && keys.some((k, i) => i > 0 && k.shape !== \"linear\");\n return {\n ...clock(loop, repeat),\n keyTimes: keys.map((k) => String(+(k.t / loop).toFixed(5))).join(\";\"),\n calcMode: discrete ? \"discrete\" : spline ? \"spline\" : \"linear\",\n keySplines: spline ? keys.slice(1).map((k) => SPLINES[k.shape]).join(\";\") : undefined,\n };\n}\n\n/** How long an animation runs, and whether it repeats or holds its end. */\nconst clock = (loop: number, repeat: boolean) => ({\n dur: `${+(loop / 1000).toFixed(4)}s`,\n repeatCount: repeat ? \"indefinite\" : undefined,\n fill: repeat ? undefined : \"freeze\",\n});\n\n/** Keys with their repeats dropped: a key between two of the same value, or a copy of the one before. */\nfunction collapse(keys: Key[]): Key[] {\n const out: Key[] = [];\n keys.forEach((k, i) => {\n const prev = out[out.length - 1];\n if (prev && prev.v === k.v && (prev.t === k.t || (keys[i + 1]?.v === k.v && i < keys.length - 1))) return;\n out.push(k);\n });\n return out;\n}\n\n/** Keys reduced to where the value changes, for a discrete animation (the last at a time wins). */\nfunction runs(keys: readonly Key[]): Key[] {\n const out: Key[] = [];\n for (const k of keys) {\n const prev = out[out.length - 1];\n if (prev?.t === k.t) out.pop();\n if (out[out.length - 1]?.v !== k.v) out.push(k);\n }\n return out;\n}\n\n/**\n * The {@link SvgMotion} as one animated SVG file that plays and loops on its\n * own, as `SvgPlayer` plays it, with no script: save it as `.svg`, put it in\n * an `<img src>`, or inline it. Each element starts as the motion's first\n * frame, so it still shows that where SMIL does not run.\n *\n * Attribute changes become one `<animate>` per attribute (`<animateTransform>`\n * per function of a `transform`), with the eases written exactly as splines;\n * `draw` animates `stroke-dashoffset`; `along` becomes `<animateMotion>` on\n * the path; `view` animates the root `viewBox` (keeping `data-fixed` and\n * `data-nonscaling` elements as the player does); `solo` toggles `display`.\n * Counts and written text are sampled at `fps`, each text shown in its own\n * `<tspan>` in turn.\n *\n * Limits: a `view` that frames an element by id stays where it is (it needs\n * layout, as in `svgFrameMarkup`); `style` and other attributes SMIL cannot\n * interpolate change in steps; ids are suffixed only where the picture\n * refers to them (CSS `#id` selectors in a `<style>` are left as written).\n * Undefined when `motion.svg` is not an `<svg>`.\n */\nexport function svgAnimatedMarkup(motion: SvgMotion, options: AnimatedSvgOptions = {}): string | undefined {\n const steps = options.steps ?? [];\n const repeat = options.loop ?? true;\n const fps = options.fps ?? 30;\n const loop = Math.max(1, options.duration ?? svgDuration(motion, steps) + (options.hold ?? 600));\n const animations = motion.animate ?? [];\n const tree = svgFrameTree(motion, steps, 0);\n if (!tree) return undefined;\n const { svg, byId, whole } = tree;\n\n // Each property's changes in the order they start, as `svgFrame` keeps them.\n const tracks = new Map<string, Change[]>();\n animations.forEach((anim) => {\n const s = stepStart(steps, anim.step ?? 0);\n const start = s === undefined ? Infinity : s + (anim.delay ?? 0);\n const add = (prop: string) => {\n const key = `${prop === \"view\" ? SVG_PICTURE : anim.id}\\u0000${prop}`;\n tracks.set(key, [...(tracks.get(key) ?? []), { anim, start }]);\n };\n for (const name of Object.keys(anim.attrs ?? {})) add(`@${name}`);\n if (anim.draw) add(\"draw\");\n if (anim.count || anim.write !== undefined) add(\"text\");\n if (anim.solo !== undefined) add(\"solo\");\n if (anim.view !== undefined) add(\"view\");\n if (anim.along) add(\"along\");\n });\n for (const list of tracks.values()) list.sort((x, y) => x.start - y.start);\n\n const frames = new Map<number, Map<string, SvgElementFrame>>();\n const frameAt = (t: number) => {\n let f = frames.get(t);\n if (!f) frames.set(t, (f = svgFrame(animations, steps, t)));\n return f;\n };\n const boxOf = (v: SvgBox | string | null) => (v === null ? whole : typeof v === \"string\" ? undefined : v);\n /** A channel's value in a frame, as written into the file. */\n const read = (frame: Map<string, SvgElementFrame>, id: string, prop: string): string | undefined => {\n const f = frame.get(id);\n if (!f) return undefined;\n if (prop.startsWith(\"@\")) return f.attrs[prop.slice(1)];\n if (prop === \"draw\") return f.draw === undefined ? undefined : num(1 - f.draw);\n if (prop === \"along\") return f.along && num(f.along.at);\n if (prop === \"solo\") return f.solo === undefined ? undefined : String(f.solo);\n if (prop === \"text\") return f.text;\n if (!f.view) return undefined;\n const [a, b] = [boxOf(f.view.from), boxOf(f.view.to)];\n const box = a && b ? a.map((n, i) => n + (b[i]! - n) * f.view!.u) : (b ?? a ?? whole);\n return box?.map(num).join(\" \");\n };\n\n /**\n * A channel's keyframes over the loop: before its first change its start,\n * then each change from its start to its end (or the next change), eased\n * exactly or (with `sampled`, or when cut short) sampled at `fps`.\n */\n const keyframes = (id: string, prop: string, list: readonly Change[], sampled = false): Key[] => {\n const shown = list.filter((c, i) => c.start < loop && !(list[i + 1] && list[i + 1]!.start <= c.start));\n // A change alone (with the one before it, where a view starts) gives its own value at any time.\n const value = (k: number, t: number) =>\n read(svgFrame(shown.slice(Math.max(0, k - 1), k + 1).map((c) => c.anim), steps, t), id, prop) ?? \"\";\n const keys: Key[] = [];\n const push = (t: number, v: string, shape: Shape = \"linear\") => keys.push({ t, v, shape });\n if (!shown.length) return [];\n push(0, read(frameAt(0), id, prop) ?? value(0, 0));\n shown.forEach((c, k) => {\n const next = Math.min(shown[k + 1]?.start ?? loop, loop);\n const ms = c.anim.ms ?? STEP_MS;\n const end = Math.min(c.start + ms, next);\n // Held until it starts, where it may jump.\n push(c.start, keys[keys.length - 1]!.v);\n push(c.start, value(k, c.start));\n if (!(ms > 0)) return;\n const ease = c.anim.ease ?? \"in-out\";\n const pair = prop.startsWith(\"@\") ? c.anim.attrs![prop.slice(1)]! : undefined;\n if (pair && !blends(pair[0], pair[1])) {\n const at = c.start + ms * HALFWAY[ease];\n if (at < next) {\n push(at, value(k, c.start));\n push(at, value(k, end));\n }\n } else if (!sampled && end === c.start + ms && ease !== \"linear\") {\n if (ease === \"in-out\") push(c.start + ms / 2, value(k, c.start + ms / 2), \"in\");\n push(end, value(k, end), \"out\");\n } else if (!sampled && ease === \"linear\") push(end, value(k, end));\n else {\n for (let t = c.start + 1000 / fps; t < end; t += 1000 / fps) push(t, value(k, t));\n push(end, value(k, end));\n }\n });\n if (keys[keys.length - 1]!.t < loop) push(loop, keys[keys.length - 1]!.v);\n return collapse(keys);\n };\n\n /** Times to sample text at: every 1/fps, and wherever a change starts or ends. */\n const sampleTimes = (list: readonly Change[]) => {\n const times = new Set<number>();\n for (let t = 0; t < loop; t += 1000 / fps) times.add(+t.toFixed(3));\n for (const c of list)\n for (const t of [c.start, c.start + (c.anim.ms ?? STEP_MS)]) if (t < loop) times.add(t);\n return [...times].sort((a, b) => a - b);\n };\n\n // What to add to each element, appended once all are worked out (so a solo's children stay as written).\n const added = new Map<SvgNode, SvgNode[]>();\n const add = (el: SvgNode, ...anims: SvgNode[]) => added.set(el, [...(added.get(el) ?? []), ...anims]);\n const animate = (name: string, keys: readonly Key[], values = keys.map((k) => k.v), discrete = false) =>\n node(\"animate\", { attributeName: name, values: values.join(\";\"), ...timing(keys, loop, repeat, discrete) });\n const followers = new Set(animations.filter((a) => a.along).map((a) => a.id));\n let viewKeys: Key[] | undefined;\n\n for (const [key, list] of tracks) {\n const [id, prop] = key.split(\"\\u0000\") as [string, string];\n const el = id === SVG_PICTURE ? svg : byId.get(id);\n if (!el) continue;\n const name = prop.slice(1);\n if (prop === \"text\") {\n // One <tspan> per text it shows, each shown in its turn.\n const own = list.map((c) => c.anim);\n const text = (t: number) => read(svgFrame(own, steps, t), id, prop) ?? \"\";\n const shown: Key[] = [];\n let last = -1;\n for (const t of sampleTimes(list)) {\n const v = text(t);\n if (shown.length && v !== shown[shown.length - 1]!.v) {\n let [lo, hi] = [last, t];\n while (hi - lo > 0.5) {\n const mid = (lo + hi) / 2;\n if (text(mid) === shown[shown.length - 1]!.v) lo = mid;\n else hi = mid;\n }\n // One change between them is placed exactly; several (a fast count) change at the middle.\n shown.push({ t: text(hi) === v ? hi : (last + t) / 2, v, shape: \"linear\" });\n }\n if (v !== shown[shown.length - 1]?.v) shown.push({ t, v, shape: \"linear\" });\n last = t;\n }\n const texts = [...new Set(shown.map((k) => k.v))];\n el.children = texts.map((value, i) => {\n const keys = runs(shown.map((k) => ({ ...k, v: k.v === value ? \"inline\" : \"none\" })));\n const span = node(\"tspan\", { display: i === 0 ? undefined : \"none\" }, [value]);\n if (keys.length > 1) span.children.push(animate(\"display\", keys, undefined, true));\n return span;\n });\n continue;\n }\n if (prop.startsWith(\"@\") && TRANSFORMS.has(name.toLowerCase())) {\n if (followers.has(id) && name === \"transform\") continue;\n let keys = keyframes(id, prop, list);\n if (keys.length < 2) continue;\n const lists = keys.map((k) => transformList(k.v));\n const shape = (l: [string, number[]][]) => l.map(([f, args]) => `${f}${args.length}`).join(\" \");\n if (lists.every((l) => shape(l) === shape(lists[0]!)) && !/matrix|skewY/.test(shape(lists[0]!))) {\n // The same functions throughout: each animated on its own, added up in order.\n lists[0]!.forEach(([type], j) =>\n add(el, node(\"animateTransform\", {\n attributeName: name,\n type,\n additive: j ? \"sum\" : undefined,\n values: lists.map((l) => l[j]![1].map(num).join(\" \")).join(\";\"),\n ...timing(keys, loop, repeat),\n })),\n );\n } else {\n // Anything else as translate · rotate · skewX · scale, sampled, with the angle kept continuous.\n keys = keyframes(id, prop, list, true);\n const parts = keys.map((k) => decompose(transformMatrix(k.v)));\n parts.forEach((p, i) => {\n const before = parts[i - 1];\n if (before) p[2] += 360 * Math.round((before[2] - p[2]) / 360);\n });\n const types: [string, (p: number[]) => number[]][] = [\n [\"translate\", (p) => [p[0]!, p[1]!]],\n [\"rotate\", (p) => [p[2]!]],\n [\"skewX\", (p) => [p[3]!]],\n [\"scale\", (p) => [p[4]!, p[5]!]],\n ];\n types.forEach(([type, pick], j) =>\n add(el, node(\"animateTransform\", {\n attributeName: name,\n type,\n additive: j ? \"sum\" : undefined,\n values: parts.map((p) => pick(p).map(num).join(\" \")).join(\";\"),\n ...timing(keys, loop, repeat),\n })),\n );\n }\n continue;\n }\n if (prop === \"along\") {\n const paths = new Set(list.map((c) => c.anim.along!));\n const pathEl = byId.get([...paths][0]!);\n const d = pathEl && outline(pathEl);\n if (!d) continue;\n const point = (at: string) => pathPointAt(d, Number(at));\n const first = point(read(frameAt(0), id, prop) ?? \"0\");\n if (first) setAttr(el, \"transform\", `translate(${num(first[0])} ${num(first[1])})`);\n if (paths.size === 1 && pathEl.tag.toLowerCase() === \"path\") {\n // The browser follows the path itself: the markup's place (for no SMIL) set aside while it does.\n const keys = keyframes(id, prop, list);\n add(\n el,\n node(\"animateTransform\", { attributeName: \"transform\", type: \"translate\", values: \"0 0\", ...clock(loop, repeat) }),\n node(\"animateMotion\", { keyPoints: keys.map((k) => k.v).join(\";\"), ...timing(keys, loop, repeat) }, [\n node(\"mpath\", { href: `#${[...paths][0]}` }),\n ]),\n );\n } else {\n // Along several paths, or a shape SMIL cannot follow: its points, sampled.\n const keys = sampleTimes(list).map((t): Key => {\n const f = frameAt(t).get(id)?.along;\n const p = f && byId.get(f.path) && pathPointAt(outline(byId.get(f.path)!) ?? \"\", f.at);\n return { t, v: p ? `${num(p[0])} ${num(p[1])}` : \"0 0\", shape: \"linear\" };\n });\n keys.push({ t: loop, v: keys[keys.length - 1]!.v, shape: \"linear\" });\n const ks = collapse(keys);\n add(el, node(\"animateTransform\", { attributeName: \"transform\", type: \"translate\", values: ks.map((k) => k.v).join(\";\"), ...timing(ks, loop, repeat) }));\n }\n continue;\n }\n const keys = keyframes(id, prop, list);\n if (keys.length < 2) continue;\n if (prop === \"solo\") {\n const shown = runs(keys);\n let i = 0;\n for (const child of el.children) {\n if (typeof child === \"string\") continue;\n const index = String(i++);\n const toggles = runs(shown.map((k) => ({ ...k, v: k.v === index ? \"inline\" : \"none\" })));\n if (toggles.length > 1) add(child, animate(\"display\", toggles, undefined, true));\n }\n } else if (prop === \"view\") {\n viewKeys = keys;\n add(svg, animate(\"viewBox\", keys));\n } else add(el, animate(prop === \"draw\" ? \"stroke-dashoffset\" : name, keys));\n }\n\n if (viewKeys && whole) {\n // As the view zooms, `data-nonscaling` elements keep their size and `data-fixed` ones their place.\n const boxes = viewKeys.map((k) => k.v.split(\" \").map(Number));\n const all: SvgNode[] = [];\n const walk = (n: SvgNode) => {\n all.push(n);\n for (const c of n.children) if (typeof c !== \"string\") walk(c);\n };\n walk(svg);\n const zooms = boxes.map((b) => num(b[2]! / whole[2]));\n for (const el of all.filter((n) => getAttr(n, \"data-nonscaling\") !== undefined)) {\n setAttr(el, \"transform\", zooms[0] === \"1\" ? undefined : `scale(${zooms[0]})`);\n add(el, node(\"animateTransform\", { attributeName: \"transform\", type: \"scale\", values: zooms.join(\";\"), ...timing(viewKeys, loop, repeat) }));\n }\n const fixed = all.filter((n) => getAttr(n, \"data-fixed\") !== undefined);\n const top = fixed.filter((n) => !fixed.some((f) => f !== n && contains(f, n)));\n if (top.length) {\n for (const el of top) for (const n of all) n.children = n.children.filter((c) => c !== el);\n // A layer that maps the whole picture onto the view as it moves (as a nested <svg> with the\n // whole viewBox would, but with transforms, which images animate where they do not re-lay out one).\n const fit = boxes.map(([x, y, w, h]) => {\n const k = Math.min(w! / whole[2], h! / whole[3]);\n return { at: `${num(x! + (w! - whole[2] * k) / 2 - whole[0] * k)} ${num(y! + (h! - whole[3] * k) / 2 - whole[1] * k)}`, k: num(k) };\n });\n const layer = node(\"g\", { transform: `translate(${fit[0]!.at}) scale(${fit[0]!.k})` }, top);\n add(\n layer,\n node(\"animateTransform\", { attributeName: \"transform\", type: \"translate\", values: fit.map((f) => f.at).join(\";\"), ...timing(viewKeys, loop, repeat) }),\n node(\"animateTransform\", { attributeName: \"transform\", type: \"scale\", additive: \"sum\", values: fit.map((f) => f.k).join(\";\"), ...timing(viewKeys, loop, repeat) }),\n );\n svg.children.push(layer);\n }\n }\n\n for (const [el, anims] of added) el.children.push(...anims);\n scopeIds(svg, options.idSuffix ?? hash(motion.svg + JSON.stringify(animations)));\n setAttr(svg, \"width\", \"100%\");\n setAttr(svg, \"height\", \"100%\");\n setAttr(svg, \"xmlns\", \"http://www.w3.org/2000/svg\");\n const markup = serialize(svg);\n // Read as XML (an image, a file), `xlink:` attributes need their namespace declared.\n return /\\sxlink:/.test(markup) && !/\\sxmlns:xlink=/.test(markup)\n ? markup.replace(/^<svg/, '<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"')\n : markup;\n}\n\nconst contains = (outer: SvgNode, inner: SvgNode): boolean =>\n outer.children.some((c) => c === inner || (typeof c !== \"string\" && contains(c, inner)));\n\n/**\n * Gives the ids the picture refers to (by `url(#…)` or `href=\"#…\"`) `-suffix`,\n * and points the references at them, as a live player does.\n */\nfunction scopeIds(svg: SvgNode, suffix: string) {\n if (!suffix) return;\n const all: SvgNode[] = [];\n const walk = (n: SvgNode) => {\n all.push(n);\n for (const c of n.children) if (typeof c !== \"string\") walk(c);\n };\n walk(svg);\n const referred = new Set<string>();\n for (const n of all) {\n const css = n.tag.toLowerCase() === \"style\" ? n.children.filter((c): c is string => typeof c === \"string\") : [];\n for (const [name, value] of [...n.attrs, ...css.map((c) => [\"\", c] as const)]) {\n if (/^(xlink:)?href$/i.test(name) && value.startsWith(\"#\")) referred.add(value.slice(1));\n for (const m of value.matchAll(URL_REF)) referred.add(m[2]!);\n }\n }\n const ids = new Map<string, string>();\n for (const n of all) {\n const id = getAttr(n, \"id\");\n if (id && referred.has(id) && !ids.has(id)) ids.set(id, `${id}-${suffix}`);\n }\n if (!ids.size) return;\n const scoped = (value: string) =>\n value.replace(URL_REF, (whole, quote: string, id: string) => (ids.has(id) ? `url(${quote}#${ids.get(id)}${quote})` : whole));\n for (const n of all) {\n for (const attr of n.attrs) {\n if (attr[0] === \"id\") attr[1] = ids.get(attr[1]) ?? attr[1];\n else if (/^(xlink:)?href$/i.test(attr[0])) attr[1] = attr[1].startsWith(\"#\") && ids.has(attr[1].slice(1)) ? `#${ids.get(attr[1].slice(1))}` : attr[1];\n else attr[1] = scoped(attr[1]);\n }\n if (n.tag.toLowerCase() === \"style\") n.children = n.children.map((c) => (typeof c === \"string\" ? scoped(c) : c));\n }\n}\n"],"mappings":"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","names":["add","keys"]}
|