interactive-bg 0.1.0 → 0.2.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/README.md +55 -7
- package/dist/fluid/canvas2d.cjs +14 -0
- package/dist/fluid/canvas2d.cjs.map +1 -0
- package/dist/fluid/canvas2d.d.cts +5 -0
- package/dist/fluid/canvas2d.d.ts +5 -0
- package/dist/fluid/canvas2d.js +13 -0
- package/dist/fluid/canvas2d.js.map +1 -0
- package/dist/fluid/index.cjs +16 -0
- package/dist/fluid/index.cjs.map +1 -0
- package/dist/fluid/index.d.cts +5 -0
- package/dist/fluid/index.d.ts +5 -0
- package/dist/fluid/index.js +15 -0
- package/dist/fluid/index.js.map +1 -0
- package/dist/fluid/webgl.cjs +14 -0
- package/dist/fluid/webgl.cjs.map +1 -0
- package/dist/fluid/webgl.d.cts +5 -0
- package/dist/fluid/webgl.d.ts +5 -0
- package/dist/fluid/webgl.js +13 -0
- package/dist/fluid/webgl.js.map +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -1
- package/dist/index.umd.js +255 -12
- package/dist/index.umd.js.map +1 -1
- package/dist/shimmer/canvas2d.cjs +14 -0
- package/dist/shimmer/canvas2d.cjs.map +1 -0
- package/dist/shimmer/canvas2d.d.cts +5 -0
- package/dist/shimmer/canvas2d.d.ts +5 -0
- package/dist/shimmer/canvas2d.js +13 -0
- package/dist/shimmer/canvas2d.js.map +1 -0
- package/dist/shimmer/index.cjs +16 -0
- package/dist/shimmer/index.cjs.map +1 -0
- package/dist/shimmer/index.d.cts +5 -0
- package/dist/shimmer/index.d.ts +5 -0
- package/dist/shimmer/index.js +15 -0
- package/dist/shimmer/index.js.map +1 -0
- package/dist/shimmer/webgl.cjs +14 -0
- package/dist/shimmer/webgl.cjs.map +1 -0
- package/dist/shimmer/webgl.d.cts +5 -0
- package/dist/shimmer/webgl.d.ts +5 -0
- package/dist/shimmer/webgl.js +13 -0
- package/dist/shimmer/webgl.js.map +1 -0
- package/dist/styles/fluid/canvas2d.cjs +155 -0
- package/dist/styles/fluid/canvas2d.cjs.map +1 -0
- package/dist/styles/fluid/canvas2d.d.cts +8 -0
- package/dist/styles/fluid/canvas2d.d.ts +8 -0
- package/dist/styles/fluid/canvas2d.js +155 -0
- package/dist/styles/fluid/canvas2d.js.map +1 -0
- package/dist/styles/fluid/color.cjs +40 -0
- package/dist/styles/fluid/color.cjs.map +1 -0
- package/dist/styles/fluid/color.d.cts +4 -0
- package/dist/styles/fluid/color.d.ts +4 -0
- package/dist/styles/fluid/color.js +40 -0
- package/dist/styles/fluid/color.js.map +1 -0
- package/dist/styles/fluid/definition.cjs +14 -0
- package/dist/styles/fluid/definition.cjs.map +1 -0
- package/dist/styles/fluid/definition.d.cts +8 -0
- package/dist/styles/fluid/definition.d.ts +8 -0
- package/dist/styles/fluid/definition.js +15 -0
- package/dist/styles/fluid/definition.js.map +1 -0
- package/dist/styles/fluid/options.cjs +29 -0
- package/dist/styles/fluid/options.cjs.map +1 -0
- package/dist/styles/fluid/options.d.cts +31 -0
- package/dist/styles/fluid/options.d.ts +31 -0
- package/dist/styles/fluid/options.js +28 -0
- package/dist/styles/fluid/options.js.map +1 -0
- package/dist/styles/fluid/settings.cjs +32 -0
- package/dist/styles/fluid/settings.cjs.map +1 -0
- package/dist/styles/fluid/settings.d.cts +24 -0
- package/dist/styles/fluid/settings.d.ts +24 -0
- package/dist/styles/fluid/settings.js +23 -0
- package/dist/styles/fluid/settings.js.map +1 -0
- package/dist/styles/fluid/simulation.cjs +183 -0
- package/dist/styles/fluid/simulation.cjs.map +1 -0
- package/dist/styles/fluid/simulation.d.cts +22 -0
- package/dist/styles/fluid/simulation.d.ts +22 -0
- package/dist/styles/fluid/simulation.js +183 -0
- package/dist/styles/fluid/simulation.js.map +1 -0
- package/dist/styles/fluid/size.cjs +17 -0
- package/dist/styles/fluid/size.cjs.map +1 -0
- package/dist/styles/fluid/size.d.cts +5 -0
- package/dist/styles/fluid/size.d.ts +5 -0
- package/dist/styles/fluid/size.js +17 -0
- package/dist/styles/fluid/size.js.map +1 -0
- package/dist/styles/fluid/webgl.cjs +607 -0
- package/dist/styles/fluid/webgl.cjs.map +1 -0
- package/dist/styles/fluid/webgl.d.cts +3 -0
- package/dist/styles/fluid/webgl.d.ts +3 -0
- package/dist/styles/fluid/webgl.js +607 -0
- package/dist/styles/fluid/webgl.js.map +1 -0
- package/dist/styles/shimmer/canvas2d.cjs +84 -0
- package/dist/styles/shimmer/canvas2d.cjs.map +1 -0
- package/dist/styles/shimmer/canvas2d.d.cts +3 -0
- package/dist/styles/shimmer/canvas2d.d.ts +3 -0
- package/dist/styles/shimmer/canvas2d.js +84 -0
- package/dist/styles/shimmer/canvas2d.js.map +1 -0
- package/dist/styles/shimmer/definition.cjs +15 -0
- package/dist/styles/shimmer/definition.cjs.map +1 -0
- package/dist/styles/shimmer/definition.d.cts +8 -0
- package/dist/styles/shimmer/definition.d.ts +8 -0
- package/dist/styles/shimmer/definition.js +16 -0
- package/dist/styles/shimmer/definition.js.map +1 -0
- package/dist/styles/shimmer/field.cjs +79 -0
- package/dist/styles/shimmer/field.cjs.map +1 -0
- package/dist/styles/shimmer/field.d.cts +11 -0
- package/dist/styles/shimmer/field.d.ts +11 -0
- package/dist/styles/shimmer/field.js +78 -0
- package/dist/styles/shimmer/field.js.map +1 -0
- package/dist/styles/shimmer/options.cjs +28 -0
- package/dist/styles/shimmer/options.cjs.map +1 -0
- package/dist/styles/shimmer/options.d.cts +22 -0
- package/dist/styles/shimmer/options.d.ts +22 -0
- package/dist/styles/shimmer/options.js +27 -0
- package/dist/styles/shimmer/options.js.map +1 -0
- package/dist/styles/shimmer/webgl.cjs +89 -0
- package/dist/styles/shimmer/webgl.cjs.map +1 -0
- package/dist/styles/shimmer/webgl.d.cts +4 -0
- package/dist/styles/shimmer/webgl.d.ts +4 -0
- package/dist/styles/shimmer/webgl.js +89 -0
- package/dist/styles/shimmer/webgl.js.map +1 -0
- package/package.json +76 -2
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","names":["FRAGMENT","UNIFORMS","VERTEX","FRAGMENT","UNIFORMS","factory","global","exports","fades","fade","createSurface","ordered","preference","renderers","r","k","renderer","replaceCanvas","surface","canvas","options","invalidate","engineDefaults","createBackground","host","target","definition","style","engine","engineOptions","backgroundColor","resolveColor","resolveFade","ownsCanvas","hostPosition","mountCanvas","wake","fresh","blankSurface","width","height","dpr","pointerX","pointerY","targetX","targetY","influence","targetInfluence","clicks","frameClicks","pointer","frameState","styleBusy","lastFrame","rafId","timerId","paused","visible","intersecting","destroyed","needsDraw","reducedMotionQuery","reducedMotion","holdStill","animating","busy","pointerEasing","effectiveIdleFps","configured","needed","frameInterval","fps","canRun","resize","rect","nextWidth","nextHeight","nextDpr","frame","minInterval","now","schedule","dt","wasBusy","ease","moving","delay","onTimer","cancel","onPointerMove","x","event","y","inside","onPointerDown","onPointerLeave","onVisibilityChange","onReducedMotionChange","dprQuery","watchDpr","onDprChange","resizeObserver","intersectionObserver","entries","next","previous","needs","color","SIDES","canvas2dRenderer","ctx","createRenderer","gradients","fadeSide","size","side","cache","length","x0","y0","x1","y1","strip","fading","defineStyle","TRANSPARENT","probe","parseColor","cached","g","b","rgba","FULLSCREEN_VERTEX_SHADER","createProgram","program","gl","vertex","fragment","compile","vertexSource","fragmentSource","error","getUniforms","names","name","shader","type","source","log","WEBGL_ATTRIBUTES","FADE_FRAGMENT","webglRenderer","initial","fadePass","onLost","fadeEdges","uniforms","a","background","onRestored","createFloatBuffer","capacity","reserve","buffer","count","grown","traceContours","j","rows","cellSize","i","cols","idx","field","c","d","min","max","first","step","last","level","code","topX","frac","rightY","bottomX","leftY","emit","centreAbove","to","from","t","topoDefaults","resolveTopoOptions","F3","G3","GRAD3","mulberry32","seed","createNoise3D","random","p","tmp","perm","permMod12","s","z","z0","i1","j1","k1","i2","j2","k2","z1","x2","y2","z2","x3","y3","z3","ii","jj","kk","n","KEY_DT","createKeyframeField","params","noise","norm","keyA","keyB","keyNext","keyTime","keyNextRows","valid","version","allocate","nextCols","nextRows","sampleRows","fromRow","toRow","value","o","amp","freq","scale","octaves","prev","time","progress","wanted","createTerrain","speed","createTopoCanvas2D","terrain","minor","major","collectSegment","data","stroke","lineWidth","sampleField","blend","bump","radius2","pointerRadius","reach","i0","j0","dy","dx","topoStyle","FRAGMENT$2","UNIFORMS$2","createTopoWebGL","textures","texture","textureCols","textureRows","uploadedVersion","upload","resized","keys","unit","opacity","topo","TAU","gridLayout","spacing","cellPhase","salt","createPhaseCache","phases","phaseCols","px","py","wanderClock","clock","pointerFalloff","distance","radius","waveRing","ringRadius","waveEnvelope","age","duration","WANDER_STEP","wanderFps","maxSpeed","jitter","jitterSpeed","wanderIdleFps","createWaveList","waves","wave","enabled","click","out","WAVE_GROW","dotsDefaults","resolveDotsOptions","SIZE_STEPS","MAX_SIZE_STEP","createDotsCanvas2D","waveData","sizes","add","phasesFor","wander","push","waveCount","waveReach","waveWidth","restY","originY","restX","originX","sx","cx","cy","sy","amount","grow","w","outer","ring","waveStrength","dotsStyle","GRID_UNIFORMS","GRID_VERTEX_GLSL","setGridUniforms","grid","VERTEX$1","FRAGMENT$1","UNIFORMS$1","createDotsWebGL","dots","plusDefaults","resolvePlusOptions","wavesEnabled","atanUnit","r2","facingAngle","ax","QUARTER","SETTLED_PX","wrap","angle","createSignTurns","packWaves","changed","settling","lastX","lastY","lastAlign","lastOriginX","lastOriginY","lastOptions","hadWaves","align","unchanged","waveSpeed","waveDuration","settled","waveAlign","remaining","WEIGHT_STEPS","MAX_WEIGHT_STEP","createPlusCanvas2D","turns","weights","weight","turn","a2","cos","sin","plusStyle","VERTEX","FRAGMENT","UNIFORMS","createPlusWebGL","uploaded","vao","plus"],"sources":["../src/core/surface.ts","../src/core/engine.ts","../src/core/canvas2d-renderer.ts","../src/core/style.ts","../src/core/color.ts","../src/core/webgl.ts","../src/core/webgl-renderer.ts","../src/shared/buffer.ts","../src/styles/topo/contours.ts","../src/styles/topo/options.ts","../src/shared/noise.ts","../src/styles/topo/field.ts","../src/styles/topo/terrain.ts","../src/styles/topo/canvas2d.ts","../src/styles/topo/definition.ts","../src/styles/topo/webgl.ts","../src/topo/index.ts","../src/shared/grid.ts","../src/styles/dots/motion.ts","../src/styles/dots/options.ts","../src/styles/dots/canvas2d.ts","../src/styles/dots/definition.ts","../src/shared/grid-webgl.ts","../src/styles/dots/webgl.ts","../src/dots/index.ts","../src/styles/plus/options.ts","../src/styles/plus/motion.ts","../src/styles/plus/turns.ts","../src/styles/plus/canvas2d.ts","../src/styles/plus/definition.ts","../src/styles/plus/webgl.ts","../src/plus/index.ts"],"sourcesContent":["import type { Frame, RendererName } from './style';\n\n/** How far in from each edge the style's drawing fades out, in CSS pixels. `0` = no fade on that side. */\nexport interface Fade {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\n/** Whether any side fades. */\nexport function fades(fade: Fade): boolean {\n return fade.top > 0 || fade.right > 0 || fade.bottom > 0 || fade.left > 0;\n}\n\n/** A canvas context plus the style renderer drawing into it. */\nexport interface Surface<O> {\n readonly name: RendererName;\n update(options: O): void;\n /**\n * Clear to `backgroundColor` (`null` = transparent) and let the style draw, then fade the\n * style's drawing out towards the edges as `fade` says, keeping the background colour solid.\n * Fades on several sides multiply. Returns `true` while the style has a short-lived effect playing.\n */\n render(frame: Frame, backgroundColor: string | null, fade: Fade): boolean;\n /** Leave the canvas blank. */\n clear(): void;\n destroy(): void;\n}\n\n/**\n * One way to draw a style: a kind of canvas context plus the style's renderer\n * for it. Made with `webglRenderer()` or `canvas2dRenderer()`, each in its own\n * module, so a style only bundles the backends it lists.\n */\nexport interface Renderer<O> {\n readonly name: RendererName;\n /** Set up on `canvas`, or return `null` if this kind of context isn't available. */\n create(canvas: HTMLCanvasElement, options: O, invalidate: () => void): Surface<O> | null;\n}\n\n/**\n * Set up the first renderer that works here, trying them in the style's order,\n * with `preference` (if the style has it) first. `null` if none works.\n *\n * A canvas keeps the first kind of context it hands out, so after a renderer\n * fails, `replaceCanvas` (if given) swaps in a fresh canvas for the next one.\n */\nexport function createSurface<O>(\n canvas: () => HTMLCanvasElement,\n renderers: readonly Renderer<O>[],\n options: O,\n preference: 'auto' | RendererName,\n invalidate: () => void,\n replaceCanvas?: () => void,\n): Surface<O> | null {\n const ordered =\n preference === 'auto'\n ? renderers\n : [...renderers.filter((r) => r.name === preference), ...renderers.filter((r) => r.name !== preference)];\n for (const [k, renderer] of ordered.entries()) {\n if (k > 0) replaceCanvas?.();\n const surface = renderer.create(canvas(), options, invalidate);\n if (surface) return surface;\n }\n return null;\n}\n","import type { Frame, Point, RendererName, Style, StyleDefinition } from './style';\nimport { createSurface, type Fade, type Surface } from './surface';\n\n/** Options shared by every style: how and when the background is rendered. */\nexport interface EngineOptions {\n /**\n * Rendering backend, chosen when the background is created (changing it later has no effect).\n * `'auto'` uses the style's renderers in their own order (WebGL2 first for the built-in styles)\n * and falls back to the next when the browser lacks one. Naming one tries it first.\n */\n renderer: 'auto' | RendererName;\n /** Fill colour painted behind the style. `null` or `'transparent'` keeps the canvas transparent. */\n backgroundColor: string | null;\n /**\n * Fade the pattern out towards the top edge over this many CSS pixels: from its own opacity\n * this far in from the edge to fully transparent at the edge. The background colour isn't\n * faded. `0` = no fade. Fades on several sides multiply where they overlap.\n */\n fadeOutTop: number;\n /** Like `fadeOutTop`, towards the right edge. */\n fadeOutRight: number;\n /** Like `fadeOutTop`, towards the bottom edge. */\n fadeOutBottom: number;\n /** Like `fadeOutTop`, towards the left edge. */\n fadeOutLeft: number;\n /** React to the pointer and to clicks / taps. */\n interactive: boolean;\n /**\n * Upper limit for the canvas pixel density. Canvas memory grows with its square:\n * a 1920×1080 canvas takes 8 MB at 1, 18 MB at 1.5 and 32 MB at 2.\n */\n maxDpr: number;\n /** Frame-rate cap while the pointer is moving the background. `0` = uncapped. */\n maxFps: number;\n /** Frame-rate cap while only the style's own animation runs. Lower saves CPU and battery. `0` = same as `maxFps`. */\n idleFps: number;\n /** Hold the style's own animation still when the user prefers reduced motion. */\n respectReducedMotion: boolean;\n}\n\nexport const engineDefaults: Readonly<EngineOptions> = Object.freeze({\n renderer: 'auto',\n backgroundColor: null,\n fadeOutTop: 0,\n fadeOutRight: 0,\n fadeOutBottom: 0,\n fadeOutLeft: 0,\n interactive: true,\n maxDpr: 1.5,\n maxFps: 60,\n idleFps: 30,\n respectReducedMotion: true,\n});\n\nexport interface Background<O extends object> {\n readonly canvas: HTMLCanvasElement;\n /** Name of the style, e.g. `'topo'`. */\n readonly style: string;\n /**\n * The rendering backend actually in use, or `null` when none of the style's renderers works in\n * this browser (e.g. a WebGL-only style without WebGL2): the background then stays blank.\n */\n readonly renderer: RendererName | null;\n readonly options: Readonly<O>;\n readonly engineOptions: Readonly<EngineOptions>;\n /** Update any of the style's options on the fly. */\n setOptions(options: Partial<O>): void;\n /** Update any engine options on the fly (except `renderer`). */\n setEngineOptions(options: Partial<EngineOptions>): void;\n pause(): void;\n resume(): void;\n /** Stop rendering, remove listeners and (if it was created by us) the canvas. */\n destroy(): void;\n}\n\n/**\n * Mount an interactive background.\n *\n * - `target` `null`/omitted: a fixed, full-viewport canvas is placed behind the page.\n * - `target` is a `<canvas>`: it is drawn into directly and sized by your CSS.\n * - `target` is any other element (or a selector): a canvas is appended that\n * fills it. The element gets `position: relative` if it was `static`.\n *\n * @example createBackground('#hero', topo({ levels: 14 }), { maxFps: 30 })\n */\nexport function createBackground<O extends object>(\n target: HTMLElement | string | null | undefined,\n style: Style<O>,\n engineOptions: Partial<EngineOptions> = {},\n): Background<O> {\n const host = typeof target === 'string' ? document.querySelector<HTMLElement>(target) : target;\n if (typeof target === 'string' && !host) {\n throw new Error(`interactive-bg: no element matches \"${target}\"`);\n }\n\n const definition = style.definition;\n let options: O = { ...style.options };\n let engine: EngineOptions = { ...engineDefaults, ...engineOptions };\n let backgroundColor = resolveColor(engine.backgroundColor);\n let fade = resolveFade(engine);\n\n const ownsCanvas = !(host instanceof HTMLCanvasElement);\n // We may switch the host to `position: relative`; remember what to restore on destroy().\n const hostPosition = ownsCanvas && host ? host.style.position : null;\n let canvas = ownsCanvas ? mountCanvas(host ?? null) : (host as HTMLCanvasElement);\n const surface =\n createSurface(\n () => canvas,\n definition.renderers,\n options,\n engine.renderer,\n () => {\n needsDraw = true;\n wake();\n },\n // A renderer that failed may have claimed the canvas's context; the next one needs a fresh canvas.\n ownsCanvas\n ? () => {\n const fresh = mountCanvas(host ?? null);\n canvas.remove();\n canvas = fresh;\n }\n : undefined,\n ) ?? blankSurface(definition);\n\n // Canvas size in CSS pixels, and the pixel density it is rendered at.\n let width = 0;\n let height = 0;\n let dpr = 1;\n\n // Pointer state: `target*` is where the pointer is, the rest eases toward it.\n let pointerX = 0;\n let pointerY = 0;\n let targetX = 0;\n let targetY = 0;\n let influence = 0;\n let targetInfluence = 0;\n /** Clicks since the last rendered frame, and the array handed to the style for the current one (swapped each frame). */\n let clicks: Point[] = [];\n let frameClicks: Point[] = [];\n // Reused for every frame: styles only read them during render().\n const pointer = { x: 0, y: 0, influence: 0 };\n const frameState: Frame = { width: 0, height: 0, dpr: 1, dt: 0, reducedMotion: false, pointer, clicks: frameClicks };\n /** The style reported a short-lived effect still playing in its last frame. */\n let styleBusy = false;\n\n let lastFrame = 0;\n let rafId = 0;\n let timerId = 0;\n let paused = false;\n let visible = true;\n let intersecting = true;\n let destroyed = false;\n let needsDraw = true;\n\n const reducedMotionQuery = window.matchMedia?.('(prefers-reduced-motion: reduce)');\n let reducedMotion = reducedMotionQuery?.matches ?? false;\n\n function holdStill(): boolean {\n return engine.respectReducedMotion && reducedMotion;\n }\n\n /** Is the style's own ambient animation running (as opposed to only reacting to the pointer)? */\n function animating(): boolean {\n return surface.name !== null && definition.animates(options) && !holdStill();\n }\n\n /** Does something need the full frame rate: the pointer's effect easing, or a style effect playing? */\n function busy(): boolean {\n return styleBusy || clicks.length > 0 || pointerEasing();\n }\n\n /** Frame rate for the ambient animation; `0` means uncapped for the engine options. */\n function effectiveIdleFps(): number {\n const configured =\n engine.maxFps <= 0\n ? engine.idleFps\n : engine.idleFps <= 0\n ? engine.maxFps\n : Math.min(engine.maxFps, engine.idleFps);\n const needed = definition.idleFps?.(options) ?? 0;\n if (needed <= 0) return configured;\n return configured <= 0 ? needed : Math.min(configured, needed);\n }\n\n function frameInterval(fps: number): number {\n return fps > 0 ? 1000 / fps : 0;\n }\n\n function canRun(): boolean {\n return !destroyed && !paused && visible;\n }\n\n /** Is the pointer's effect still catching up with the pointer? */\n function pointerEasing(): boolean {\n if (influence !== targetInfluence) return true;\n return influence > 0 && (Math.abs(targetX - pointerX) > 0.5 || Math.abs(targetY - pointerY) > 0.5);\n }\n\n function resize(): void {\n const rect = canvas.getBoundingClientRect();\n const nextWidth = Math.max(1, Math.round(rect.width));\n const nextHeight = Math.max(1, Math.round(rect.height));\n const nextDpr = Math.min(window.devicePixelRatio || 1, Math.max(0.5, engine.maxDpr));\n if (nextWidth === width && nextHeight === height && nextDpr === dpr) return;\n width = nextWidth;\n height = nextHeight;\n dpr = nextDpr;\n canvas.width = Math.round(width * dpr);\n canvas.height = Math.round(height * dpr);\n needsDraw = true;\n }\n\n function frame(now: number): void {\n rafId = 0;\n if (!canRun()) return;\n\n // Full frame rate only while reacting to the pointer or playing an effect.\n const minInterval = frameInterval(busy() ? engine.maxFps : effectiveIdleFps());\n // 15% tolerance so a 60 fps cap doesn't drop frames on 60 Hz displays.\n if (lastFrame && now - lastFrame < minInterval * 0.85) {\n schedule(minInterval - (now - lastFrame));\n return;\n }\n const dt = lastFrame ? Math.min((now - lastFrame) / 1000, 0.1) : 0;\n lastFrame = now;\n\n const wasBusy = busy();\n // Frame-rate independent easing.\n const ease = 1 - Math.exp(-dt * 8);\n pointerX += (targetX - pointerX) * ease;\n pointerY += (targetY - pointerY) * ease;\n influence += (targetInfluence - influence) * ease;\n if (Math.abs(targetInfluence - influence) < 0.001) influence = targetInfluence;\n\n const moving = animating();\n if (moving || wasBusy || needsDraw) {\n needsDraw = false;\n [frameClicks, clicks] = [clicks, frameClicks];\n clicks.length = 0;\n pointer.x = pointerX;\n pointer.y = pointerY;\n pointer.influence = influence;\n frameState.width = width;\n frameState.height = height;\n frameState.dpr = dpr;\n frameState.dt = dt;\n frameState.reducedMotion = holdStill();\n frameState.clicks = frameClicks;\n styleBusy = surface.render(frameState, backgroundColor, fade);\n }\n\n // Nothing left to animate: stop until a pointer move, click, resize or option change wakes us.\n if (busy()) schedule();\n else if (moving) schedule(frameInterval(effectiveIdleFps()));\n else lastFrame = 0;\n }\n\n /** Request a frame `delay` ms from now. */\n function schedule(delay = 0): void {\n if (rafId || timerId || !canRun()) return;\n // requestAnimationFrame alone wakes up on every display refresh (up to 120–165 Hz),\n // so sleep through longer gaps with a timer and only then wait for the next frame.\n // The timer wakes slightly early so the next frame lands within frame()'s tolerance.\n if (delay > 8) {\n timerId = window.setTimeout(onTimer, delay * 0.8);\n } else {\n rafId = requestAnimationFrame(frame);\n }\n }\n\n function onTimer(): void {\n timerId = 0;\n schedule();\n }\n\n /** Render as soon as possible, cutting short any idle sleep. */\n function wake(): void {\n if (timerId) clearTimeout(timerId);\n timerId = 0;\n schedule();\n }\n\n function cancel(): void {\n if (rafId) cancelAnimationFrame(rafId);\n if (timerId) clearTimeout(timerId);\n rafId = timerId = 0;\n }\n\n function onPointerMove(event: PointerEvent): void {\n if (!engine.interactive || !canRun()) return;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const inside = x >= 0 && y >= 0 && x <= rect.width && y <= rect.height;\n if (inside && targetInfluence === 0) {\n // Entering: start where the pointer is instead of sliding in.\n pointerX = x;\n pointerY = y;\n }\n targetX = x;\n targetY = y;\n targetInfluence = inside ? 1 : 0;\n if (inside || influence > 0) wake();\n }\n\n function onPointerDown(event: PointerEvent): void {\n if (!engine.interactive || !canRun()) return;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n if (x < 0 || y < 0 || x > rect.width || y > rect.height) return;\n clicks.push({ x, y });\n wake();\n }\n\n function onPointerLeave(): void {\n targetInfluence = 0;\n wake();\n }\n\n function onVisibilityChange(): void {\n visible = document.visibilityState === 'visible' && intersecting;\n lastFrame = 0;\n if (visible) wake();\n else cancel();\n }\n\n function onReducedMotionChange(event: MediaQueryListEvent): void {\n reducedMotion = event.matches;\n needsDraw = true;\n wake();\n }\n\n // ResizeObserver doesn't fire when only the pixel density changes (e.g. the window moves to\n // another screen), so watch the current density with a media query, re-armed after each change.\n let dprQuery: MediaQueryList | null = null;\n function watchDpr(): void {\n dprQuery?.removeEventListener?.('change', onDprChange);\n dprQuery = window.matchMedia?.(`(resolution: ${window.devicePixelRatio || 1}dppx)`) ?? null;\n dprQuery?.addEventListener?.('change', onDprChange);\n }\n function onDprChange(): void {\n resize();\n wake();\n watchDpr();\n }\n watchDpr();\n\n const resizeObserver = new ResizeObserver(() => {\n resize();\n wake();\n });\n resizeObserver.observe(canvas);\n\n const intersectionObserver =\n typeof IntersectionObserver === 'function'\n ? new IntersectionObserver((entries) => {\n intersecting = entries[entries.length - 1].isIntersecting;\n onVisibilityChange();\n })\n : null;\n intersectionObserver?.observe(canvas);\n\n window.addEventListener('pointermove', onPointerMove, { passive: true });\n window.addEventListener('pointerdown', onPointerDown, { passive: true });\n document.documentElement.addEventListener('pointerleave', onPointerLeave);\n document.addEventListener('visibilitychange', onVisibilityChange);\n reducedMotionQuery?.addEventListener?.('change', onReducedMotionChange);\n\n resize();\n schedule();\n\n return {\n canvas,\n style: definition.name,\n renderer: surface.name,\n get options() {\n return options;\n },\n get engineOptions() {\n return engine;\n },\n setOptions(next) {\n options = { ...options, ...next };\n surface.update(options);\n needsDraw = true;\n wake();\n },\n setEngineOptions(next) {\n const previous = engine;\n engine = { ...engine, ...next };\n backgroundColor = resolveColor(engine.backgroundColor);\n fade = resolveFade(engine);\n if (engine.maxDpr !== previous.maxDpr) resize();\n if (!engine.interactive) {\n influence = targetInfluence = 0;\n clicks.length = 0;\n }\n needsDraw = true;\n wake();\n },\n pause() {\n paused = true;\n cancel();\n },\n resume() {\n paused = false;\n lastFrame = 0;\n wake();\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n cancel();\n resizeObserver.disconnect();\n intersectionObserver?.disconnect();\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerdown', onPointerDown);\n document.documentElement.removeEventListener('pointerleave', onPointerLeave);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n reducedMotionQuery?.removeEventListener?.('change', onReducedMotionChange);\n dprQuery?.removeEventListener?.('change', onDprChange);\n if (!ownsCanvas) surface.clear();\n surface.destroy();\n if (ownsCanvas) {\n // Free the GPU context now rather than at garbage collection: browsers cap live WebGL contexts.\n if (surface.name === 'webgl') canvas.getContext('webgl2')?.getExtension('WEBGL_lose_context')?.loseContext();\n canvas.remove();\n if (host && hostPosition !== null) host.style.position = hostPosition;\n }\n },\n };\n}\n\n/** Stands in when none of the style's renderers works here: draws nothing, and says so once. */\nfunction blankSurface<O extends object>(definition: StyleDefinition<O>): Omit<Surface<O>, 'name'> & { name: null } {\n const needs = definition.renderers.map((r) => (r.name === 'webgl' ? 'WebGL2' : 'Canvas 2D')).join(' or ');\n console.warn(`interactive-bg: style \"${definition.name}\" needs ${needs}, which this browser doesn't provide`);\n return { name: null, update() {}, render: () => false, clear() {}, destroy() {} };\n}\n\nfunction resolveFade(engine: EngineOptions): Fade {\n return {\n top: Math.max(0, engine.fadeOutTop),\n right: Math.max(0, engine.fadeOutRight),\n bottom: Math.max(0, engine.fadeOutBottom),\n left: Math.max(0, engine.fadeOutLeft),\n };\n}\n\nfunction resolveColor(color: string | null): string | null {\n return color && color !== 'transparent' ? color : null;\n}\n\n/** Create the background canvas inside `host`, or fixed behind the page when there is no host. */\nfunction mountCanvas(host: HTMLElement | null): HTMLCanvasElement {\n const canvas = document.createElement('canvas');\n canvas.setAttribute('aria-hidden', 'true');\n Object.assign(canvas.style, {\n position: host ? 'absolute' : 'fixed',\n inset: '0',\n width: '100%',\n height: '100%',\n display: 'block',\n pointerEvents: 'none',\n zIndex: host ? '0' : '-1',\n });\n if (host) {\n if (getComputedStyle(host).position === 'static') host.style.position = 'relative';\n host.prepend(canvas);\n } else {\n document.body.prepend(canvas);\n }\n return canvas;\n}\n","import type { StyleRenderer } from './style';\nimport { fades, type Fade, type Renderer } from './surface';\n\nconst SIDES: readonly (keyof Fade)[] = ['top', 'right', 'bottom', 'left'];\n\n/**\n * Draw a style with Canvas 2D. The engine clears to the background colour and\n * sets the transform so the style draws in CSS pixels.\n */\nexport function canvas2dRenderer<O>(\n createRenderer: (ctx: CanvasRenderingContext2D, options: O) => StyleRenderer<O>,\n): Renderer<O> {\n return {\n name: 'canvas2d',\n create(canvas, options) {\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n const renderer = createRenderer(ctx, options);\n\n // One gradient per side, kept while the canvas size and fade length stay the same.\n const gradients: { gradient: CanvasGradient | null; size: number; length: number }[] = SIDES.map(() => ({\n gradient: null,\n size: 0,\n length: 0,\n }));\n\n /**\n * Erase the style's drawing gradually along one side: nothing `length` px in from the edge,\n * all of it at the edge. Erasing multiplies, so overlapping sides combine.\n */\n const fadeSide = (side: number, length: number, width: number, height: number): void => {\n const horizontal = side === 1 || side === 3; // right, left\n const size = horizontal ? width : height;\n const cache = gradients[side];\n if (!cache.gradient || cache.size !== size || cache.length !== length) {\n // From the inner end of the strip to the edge.\n const [x0, y0, x1, y1] = [\n [0, length, 0, 0], // top\n [width - length, 0, width, 0], // right\n [0, height - length, 0, height], // bottom\n [length, 0, 0, 0], // left\n ][side];\n cache.gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n cache.gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');\n cache.gradient.addColorStop(1, 'rgba(0, 0, 0, 1)');\n cache.size = size;\n cache.length = length;\n }\n const strip = Math.min(length, size);\n ctx.fillStyle = cache.gradient;\n if (side === 0) ctx.fillRect(0, 0, width, strip);\n else if (side === 1) ctx.fillRect(width - strip, 0, strip, height);\n else if (side === 2) ctx.fillRect(0, height - strip, width, strip);\n else ctx.fillRect(0, 0, strip, height);\n };\n\n return {\n name: 'canvas2d',\n update(next) {\n renderer.update(next);\n },\n render(frame, backgroundColor, fade) {\n const { width, height, dpr } = frame;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.globalAlpha = 1;\n ctx.globalCompositeOperation = 'source-over';\n ctx.clearRect(0, 0, width, height);\n // With a fade, the background goes in last, behind the faded drawing, so it stays solid.\n const fading = fades(fade);\n if (backgroundColor && !fading) {\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, width, height);\n }\n const busy = renderer.render(frame) === true;\n if (fading) {\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.globalAlpha = 1;\n ctx.globalCompositeOperation = 'destination-out';\n for (let side = 0; side < SIDES.length; side++) {\n const length = fade[SIDES[side]];\n if (length > 0) fadeSide(side, length, width, height);\n }\n if (backgroundColor) {\n ctx.globalCompositeOperation = 'destination-over';\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, width, height);\n }\n ctx.globalCompositeOperation = 'source-over';\n }\n return busy;\n },\n clear() {\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n },\n destroy() {\n renderer.destroy?.();\n },\n };\n },\n };\n}\n","import type { Renderer } from './surface';\n\nexport type RendererName = 'webgl' | 'canvas2d';\n\n/** A position in CSS pixels relative to the canvas. */\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** The pointer as a style sees it. */\nexport interface Pointer extends Point {\n /** Eases from 0 to 1 while the pointer is over the canvas, and back when it leaves. Always 0 when not interactive. */\n influence: number;\n}\n\n/** What a style gets for each frame. The engine reuses this object: read it during `render()`, don't keep it. */\nexport interface Frame {\n /** Canvas size in CSS pixels. */\n width: number;\n height: number;\n /** Pixel density the canvas is rendered at. */\n dpr: number;\n /** Seconds since the previous frame (`0` on the first frame after a pause). */\n dt: number;\n /**\n * The user prefers reduced motion (and `respectReducedMotion` is on): hold the\n * style's own ambient animation still. Reactions to the pointer and clicks may still play.\n */\n reducedMotion: boolean;\n pointer: Pointer;\n /** Clicks / taps on the canvas since the previous frame. Empty when not interactive. */\n clicks: readonly Point[];\n}\n\n/**\n * Draws one style into a canvas. The engine has already cleared the canvas, and\n * takes care of the background colour and the edge fades, so just draw the pattern:\n * - Canvas 2D: the transform is set so you draw in CSS pixels.\n * - WebGL: the viewport covers the canvas, and blending is set up for premultiplied alpha\n * (`ONE, ONE_MINUS_SRC_ALPHA`), so output premultiplied colour.\n */\nexport interface StyleRenderer<O> {\n /** The style's options changed. */\n update(options: O): void;\n /**\n * Draw one frame. Return `true` while a short-lived effect (e.g. a click ripple)\n * is still playing: the engine then keeps rendering at the full frame rate.\n */\n render(frame: Frame): boolean | void;\n /** Free GPU resources and the like. */\n destroy?(): void;\n}\n\nexport interface StyleDefinition<O extends object> {\n /** Unique, lowercase name, e.g. `'topo'`. */\n name: string;\n defaults: Readonly<O>;\n /**\n * Whether the background moves on its own with these options. When it doesn't,\n * the engine only renders on pointer movement and option changes.\n */\n animates(options: O): boolean;\n /**\n * The lowest frame rate at which the ambient animation still looks smooth with\n * these options. The engine renders the ambient animation at the lower of this\n * and its `idleFps`. Omit to always use `idleFps`.\n */\n idleFps?(options: O): number;\n /**\n * How the style can be drawn, made with `webglRenderer()` and `canvas2dRenderer()`, in order of\n * preference: the engine uses the first one the browser supports. At least one.\n */\n renderers: readonly Renderer<O>[];\n}\n\n/** Everything about a style except how it's drawn: shared by its WebGL-only, Canvas 2D-only and auto builds. */\nexport type StyleBase<O extends object> = Omit<StyleDefinition<O>, 'renderers'>;\n\n/** A style with its options filled in, ready for `createBackground()`. */\nexport interface Style<O extends object> {\n readonly definition: StyleDefinition<O>;\n readonly options: Readonly<O>;\n}\n\nexport interface StyleFactory<O extends object> {\n (options?: Partial<O>): Style<O>;\n readonly styleName: string;\n readonly defaults: Readonly<O>;\n}\n\n/**\n * Turn a style definition into the function users call, e.g. `topo({ levels: 14 })`.\n */\nexport function defineStyle<O extends object>(definition: StyleDefinition<O>): StyleFactory<O> {\n if (definition.renderers.length === 0) {\n throw new Error(`interactive-bg: style \"${definition.name}\" has no renderer`);\n }\n const factory = (options: Partial<O> = {}): Style<O> => ({\n definition,\n options: { ...definition.defaults, ...options },\n });\n return Object.assign(factory, { styleName: definition.name, defaults: definition.defaults });\n}\n","export type RGBA = readonly [r: number, g: number, b: number, a: number];\n\nconst TRANSPARENT: RGBA = [0, 0, 0, 0];\n\nlet probe: CanvasRenderingContext2D | null = null;\nconst cache = new Map<string, RGBA>();\n\n/**\n * Resolve any CSS colour to straight (non-premultiplied) sRGB components in 0–1,\n * by letting the browser paint it into a 1×1 canvas. Results are cached.\n */\nexport function parseColor(color: string | null): RGBA {\n if (!color || color === 'transparent') return TRANSPARENT;\n const cached = cache.get(color);\n if (cached) return cached;\n\n if (!probe) {\n const canvas = document.createElement('canvas');\n canvas.width = canvas.height = 1;\n probe = canvas.getContext('2d', { willReadFrequently: true });\n if (!probe) return [0, 0, 0, 1];\n }\n probe.clearRect(0, 0, 1, 1);\n // An invalid colour leaves fillStyle unchanged, so it falls back to black.\n probe.fillStyle = '#000';\n probe.fillStyle = color;\n probe.fillRect(0, 0, 1, 1);\n const [r, g, b, a] = probe.getImageData(0, 0, 1, 1).data;\n const rgba: RGBA = [r / 255, g / 255, b / 255, a / 255];\n if (cache.size > 64) cache.clear();\n cache.set(color, rgba);\n return rgba;\n}\n","/**\n * Vertex shader for one triangle that covers the whole viewport, drawn with\n * `gl.drawArrays(gl.TRIANGLES, 0, 3)` and no vertex buffers. Pair it with a\n * fragment shader that works per pixel from `gl_FragCoord`.\n */\nexport const FULLSCREEN_VERTEX_SHADER = `#version 300 es\nvoid main() {\n vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));\n gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}`;\n\n/**\n * Compile and link a shader program. Returns `null` if the context is lost, and\n * throws with the driver's message if a shader doesn't compile or link (the\n * engine then falls back to the style's next renderer). Nothing is left behind\n * on failure.\n */\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n): WebGLProgram | null {\n const program = gl.createProgram();\n let vertex: WebGLShader | null = null;\n let fragment: WebGLShader | null = null;\n try {\n vertex = compile(gl, gl.VERTEX_SHADER, vertexSource);\n fragment = compile(gl, gl.FRAGMENT_SHADER, fragmentSource);\n if (!program || !vertex || !fragment) {\n gl.deleteProgram(program);\n return null;\n }\n gl.attachShader(program, vertex);\n gl.attachShader(program, fragment);\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS) && !gl.isContextLost()) {\n throw new Error(`interactive-bg: shader link error: ${gl.getProgramInfoLog(program)}`);\n }\n return program;\n } catch (error) {\n gl.deleteProgram(program);\n throw error;\n } finally {\n // Linked programs keep their own copy; the shader objects aren't needed either way.\n gl.deleteShader(vertex);\n gl.deleteShader(fragment);\n }\n}\n\n/** Look up uniform locations by name. */\nexport function getUniforms<N extends string>(\n gl: WebGL2RenderingContext,\n program: WebGLProgram,\n names: readonly N[],\n): Record<N, WebGLUniformLocation | null> {\n return Object.fromEntries(names.map((name) => [name, gl.getUniformLocation(program, name)])) as Record<\n N,\n WebGLUniformLocation | null\n >;\n}\n\nfunction compile(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS) && !gl.isContextLost()) {\n const log = gl.getShaderInfoLog(shader);\n gl.deleteShader(shader);\n throw new Error(`interactive-bg: shader error: ${log}`);\n }\n return shader;\n}\n","import { parseColor, type RGBA } from './color';\nimport type { StyleRenderer } from './style';\nimport { fades, type Fade, type Renderer } from './surface';\nimport { createProgram, FULLSCREEN_VERTEX_SHADER, getUniforms } from './webgl';\n\nconst WEBGL_ATTRIBUTES: WebGLContextAttributes = {\n alpha: true,\n premultipliedAlpha: true,\n antialias: false, // styles antialias in their shaders; MSAA would only cost memory\n depth: false,\n stencil: false,\n preserveDrawingBuffer: false,\n powerPreference: 'low-power',\n};\n\n// The edge fades, drawn after the style. Mode 0 scales what's there by how much of it each side\n// keeps (1 inside, down to 0 at a fading edge, multiplied over the sides) with blend\n// ZERO, ONE_MINUS_SRC_ALPHA. Mode 1 paints the premultiplied background colour behind it, where\n// the drawing is transparent (blend ONE_MINUS_DST_ALPHA, ONE).\nconst FADE_FRAGMENT = `#version 300 es\nprecision highp float;\nuniform float uMode;\nuniform vec4 uFade; // top, right, bottom, left, device px (0 = no fade)\nuniform vec2 uSize; // drawing buffer size, device px\nuniform vec4 uColor; // premultiplied background colour\nout vec4 outColor;\n\nfloat keep(float distance, float length) {\n return length > 0.0 ? clamp(distance / length, 0.0, 1.0) : 1.0;\n}\n\nvoid main() {\n if (uMode > 0.5) {\n outColor = uColor;\n return;\n }\n vec2 p = gl_FragCoord.xy; // origin at the bottom left\n float kept = keep(uSize.y - p.y, uFade.x) * keep(uSize.x - p.x, uFade.y) * keep(p.y, uFade.z) * keep(p.x, uFade.w);\n outColor = vec4(0.0, 0.0, 0.0, 1.0 - kept);\n}`;\n\n/**\n * Draw a style with WebGL2. The engine clears to the background colour, sets\n * the viewport and premultiplied-alpha blending, and recreates the renderer\n * after a lost context is restored.\n */\nexport function webglRenderer<O>(createRenderer: (gl: WebGL2RenderingContext, options: O) => StyleRenderer<O>): Renderer<O> {\n return {\n name: 'webgl',\n create(canvas, initial, invalidate) {\n const gl = canvas.getContext('webgl2', WEBGL_ATTRIBUTES);\n if (!gl) return null;\n\n let options = initial;\n // `null` while the context is lost: its GPU resources are gone.\n let renderer: StyleRenderer<O> | null;\n try {\n renderer = createRenderer(gl, options);\n } catch (error) {\n // E.g. a shader this GPU's driver rejects: let the engine try the next renderer.\n console.warn('interactive-bg: WebGL setup failed, trying the next renderer', error);\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n return null;\n }\n // Compiled the first time a fade is drawn, and again after a lost context.\n let fadePass: {\n program: WebGLProgram;\n uniforms: Record<'uMode' | 'uFade' | 'uSize' | 'uColor', WebGLUniformLocation | null>;\n } | null = null;\n\n const onLost = (event: Event): void => {\n event.preventDefault(); // allow the context to be restored\n renderer = null;\n fadePass = null;\n };\n\n /** Fade the drawing out towards the edges (`fade` in CSS px), then put `background` (RGBA) behind it. */\n const fadeEdges = (fade: Fade, dpr: number, background: RGBA): void => {\n if (!fadePass) {\n const program = createProgram(gl, FULLSCREEN_VERTEX_SHADER, FADE_FRAGMENT);\n if (!program) return; // context lost\n fadePass = { program, uniforms: getUniforms(gl, program, ['uMode', 'uFade', 'uSize', 'uColor'] as const) };\n }\n const { uniforms } = fadePass;\n gl.useProgram(fadePass.program);\n gl.uniform1f(uniforms.uMode, 0);\n gl.uniform4f(uniforms.uFade, fade.top * dpr, fade.right * dpr, fade.bottom * dpr, fade.left * dpr);\n gl.uniform2f(uniforms.uSize, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n const [r, g, b, a] = background;\n if (a > 0) {\n gl.uniform1f(uniforms.uMode, 1);\n gl.uniform4f(uniforms.uColor, r * a, g * a, b * a, a);\n gl.blendFunc(gl.ONE_MINUS_DST_ALPHA, gl.ONE);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n }\n };\n\n const onRestored = (): void => {\n renderer = createRenderer(gl, options);\n invalidate();\n };\n\n canvas.addEventListener('webglcontextlost', onLost);\n canvas.addEventListener('webglcontextrestored', onRestored);\n\n return {\n name: 'webgl',\n update(next) {\n options = next;\n renderer?.update(next);\n },\n render(frame, backgroundColor, fade) {\n if (!renderer) return false;\n const background = parseColor(backgroundColor);\n const [r, g, b, a] = background;\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n // With a fade, the background goes in last, behind the faded drawing, so it stays solid.\n const fading = fades(fade);\n if (fading) gl.clearColor(0, 0, 0, 0);\n else gl.clearColor(r * a, g * a, b * a, a);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n const busy = renderer.render(frame) === true;\n if (fading) fadeEdges(fade, frame.dpr, background);\n return busy;\n },\n clear() {\n if (!renderer) return;\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n },\n destroy() {\n canvas.removeEventListener('webglcontextlost', onLost);\n canvas.removeEventListener('webglcontextrestored', onRestored);\n renderer?.destroy?.();\n renderer = null;\n if (fadePass) gl.deleteProgram(fadePass.program);\n fadePass = null;\n },\n };\n },\n };\n}\n","/**\n * Numbers collected during a frame, in an array that's reused from frame to\n * frame and only ever grows, so drawing allocates nothing once it's warm.\n */\nexport interface FloatBuffer {\n data: Float32Array<ArrayBuffer>;\n length: number;\n}\n\nexport function createFloatBuffer(capacity: number): FloatBuffer {\n return { data: new Float32Array(capacity), length: 0 };\n}\n\n/** Make room for `count` more values (doubling the array if needed) and return the array to write into. */\nexport function reserve(buffer: FloatBuffer, count: number): Float32Array<ArrayBuffer> {\n if (buffer.length + count > buffer.data.length) {\n const grown = new Float32Array(Math.max(buffer.data.length * 2, buffer.length + count));\n grown.set(buffer.data);\n buffer.data = grown;\n }\n return buffer.data;\n}\n","export type SegmentSink = (\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n level: number,\n) => void;\n\n/**\n * Marching squares over a regular grid of samples.\n *\n * `field` holds `cols * rows` samples in row-major order, spaced `cellSize`\n * apart. Contour lines are traced at every multiple of `step`; each segment is\n * passed to `emit` together with its integer level index (threshold / step).\n */\nexport function traceContours(\n field: ArrayLike<number>,\n cols: number,\n rows: number,\n cellSize: number,\n step: number,\n emit: SegmentSink,\n): void {\n if (step <= 0) return;\n\n for (let j = 0; j < rows - 1; j++) {\n const y0 = j * cellSize;\n const y1 = y0 + cellSize;\n for (let i = 0; i < cols - 1; i++) {\n const idx = j * cols + i;\n // a ── b\n // │ │\n // d ── c\n const a = field[idx];\n const b = field[idx + 1];\n const c = field[idx + cols + 1];\n const d = field[idx + cols];\n\n const min = Math.min(a, b, c, d);\n const max = Math.max(a, b, c, d);\n const first = Math.ceil(min / step);\n const last = Math.floor(max / step);\n if (first > last) continue;\n\n const x0 = i * cellSize;\n const x1 = x0 + cellSize;\n\n for (let level = first; level <= last; level++) {\n const t = level * step;\n const code =\n (a >= t ? 8 : 0) | (b >= t ? 4 : 0) | (c >= t ? 2 : 0) | (d >= t ? 1 : 0);\n if (code === 0 || code === 15) continue;\n\n // Crossing points on each edge (only valid when that edge is crossed).\n const topX = x0 + cellSize * frac(t, a, b);\n const rightY = y0 + cellSize * frac(t, b, c);\n const bottomX = x0 + cellSize * frac(t, d, c);\n const leftY = y0 + cellSize * frac(t, a, d);\n\n switch (code) {\n case 1:\n case 14:\n emit(x0, leftY, bottomX, y1, level);\n break;\n case 2:\n case 13:\n emit(bottomX, y1, x1, rightY, level);\n break;\n case 3:\n case 12:\n emit(x0, leftY, x1, rightY, level);\n break;\n case 4:\n case 11:\n emit(topX, y0, x1, rightY, level);\n break;\n case 6:\n case 9:\n emit(topX, y0, bottomX, y1, level);\n break;\n case 7:\n case 8:\n emit(x0, leftY, topX, y0, level);\n break;\n case 5:\n case 10: {\n // Saddle: disambiguate with the cell centre.\n const centreAbove = (a + b + c + d) / 4 >= t;\n const isolateAC = (code === 5) === centreAbove;\n if (isolateAC) {\n emit(x0, leftY, topX, y0, level);\n emit(bottomX, y1, x1, rightY, level);\n } else {\n emit(topX, y0, x1, rightY, level);\n emit(x0, leftY, bottomX, y1, level);\n }\n break;\n }\n }\n }\n }\n }\n}\n\nfunction frac(t: number, from: number, to: number): number {\n const d = to - from;\n return d === 0 ? 0.5 : (t - from) / d;\n}\n","export interface TopoOptions {\n /** Stroke colour of regular contour lines. Any CSS colour. */\n lineColor: string;\n /** Stroke colour of every `majorEvery`-th (\"index\") line. Defaults to `lineColor`. */\n majorLineColor?: string;\n /** Opacity of all lines, from `0` (invisible) to `1` (opaque). Multiplies any alpha in the colours. */\n lineOpacity: number;\n /** Width of regular lines, in CSS pixels. */\n lineWidth: number;\n /** Width of index lines, in CSS pixels. */\n majorLineWidth: number;\n /** Every n-th contour is drawn as an index line. `0` disables index lines. */\n majorEvery: number;\n /** Number of contour levels across the full elevation range. More = denser lines. */\n levels: number;\n /** Noise frequency per CSS pixel. Smaller = larger, smoother landforms. */\n scale: number;\n /** Noise octaves. More = more detailed, rougher terrain (and more CPU). */\n octaves: number;\n /** How fast the terrain morphs, in noise units per second. `0` = static. */\n speed: number;\n /** Size of a sampling cell in CSS pixels. Smaller = smoother lines, more CPU. */\n resolution: number;\n /** Seed for the terrain. Same seed, same landscape. Pass a random number for a different one on every load. */\n seed: number;\n /** Radius of the pointer's influence, in CSS pixels. */\n pointerRadius: number;\n /** Height of the bump under the pointer. Negative values dig a crater. */\n pointerStrength: number;\n}\n\nexport const topoDefaults: Readonly<TopoOptions> = Object.freeze({\n lineColor: '#5b6576',\n majorLineColor: '#7dd3a8',\n lineOpacity: 0.5,\n lineWidth: 1,\n majorLineWidth: 1.75,\n majorEvery: 5,\n levels: 12,\n scale: 0.0025,\n octaves: 2,\n speed: 0.025,\n resolution: 6,\n seed: 1332056948,\n pointerRadius: 100,\n pointerStrength: 0.35,\n});\n\n/** Options after clamping and deriving: what the field and the renderers consume. */\nexport interface ResolvedTopoOptions {\n lineColor: string;\n majorLineColor: string;\n lineOpacity: number;\n lineWidth: number;\n majorLineWidth: number;\n /** Integer; `0` = no index lines. */\n majorEvery: number;\n /** Height difference between neighbouring contour levels. */\n levelStep: number;\n /** Grid spacing of the height field, in CSS pixels. */\n cellSize: number;\n octaves: number;\n scale: number;\n speed: number;\n seed: number;\n pointerRadius: number;\n pointerStrength: number;\n}\n\nexport function resolveTopoOptions(options: TopoOptions): ResolvedTopoOptions {\n return {\n lineColor: options.lineColor,\n majorLineColor: options.majorLineColor ?? options.lineColor,\n lineOpacity: Math.min(1, Math.max(0, options.lineOpacity)),\n lineWidth: Math.max(0.1, options.lineWidth),\n majorLineWidth: Math.max(0.1, options.majorLineWidth),\n majorEvery: Math.max(0, Math.round(options.majorEvery)),\n // The height field spans roughly [-1, 1], so the levels cover a range of 2.\n levelStep: 2 / Math.max(1, options.levels),\n cellSize: Math.max(2, options.resolution),\n octaves: Math.max(1, Math.round(options.octaves)),\n scale: options.scale,\n // The keyframes only step forwards in time; morphing backwards looks the same, so use the magnitude.\n speed: Math.abs(options.speed),\n seed: options.seed,\n pointerRadius: Math.max(1, options.pointerRadius),\n pointerStrength: options.pointerStrength,\n };\n}\n","/** Returns a value in roughly [-1, 1]. */\nexport type Noise3D = (x: number, y: number, z: number) => number;\n\nconst F3 = 1 / 3;\nconst G3 = 1 / 6;\n\n// prettier-ignore\nconst GRAD3 = new Float32Array([\n 1, 1, 0, -1, 1, 0, 1, -1, 0, -1, -1, 0,\n 1, 0, 1, -1, 0, 1, 1, 0, -1, -1, 0, -1,\n 0, 1, 1, 0, -1, 1, 0, 1, -1, 0, -1, -1,\n]);\n\n/** Small, fast seeded PRNG returning floats in [0, 1). */\nfunction mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/** Seeded 3D simplex noise (Gustavson). The third axis is used as time. */\nexport function createNoise3D(seed: number = Math.random() * 2 ** 32): Noise3D {\n const random = mulberry32(seed);\n const p = new Uint8Array(256);\n for (let i = 0; i < 256; i++) p[i] = i;\n for (let i = 255; i > 0; i--) {\n const j = Math.floor(random() * (i + 1));\n const tmp = p[i];\n p[i] = p[j];\n p[j] = tmp;\n }\n const perm = new Uint8Array(512);\n const permMod12 = new Uint8Array(512);\n for (let i = 0; i < 512; i++) {\n perm[i] = p[i & 255];\n permMod12[i] = perm[i] % 12;\n }\n\n return (x, y, z) => {\n const s = (x + y + z) * F3;\n const i = Math.floor(x + s);\n const j = Math.floor(y + s);\n const k = Math.floor(z + s);\n const t = (i + j + k) * G3;\n const x0 = x - (i - t);\n const y0 = y - (j - t);\n const z0 = z - (k - t);\n\n let i1: number, j1: number, k1: number, i2: number, j2: number, k2: number;\n if (x0 >= y0) {\n if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }\n else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; }\n else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; }\n } else {\n if (y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; }\n else if (x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; }\n else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }\n }\n\n const x1 = x0 - i1 + G3;\n const y1 = y0 - j1 + G3;\n const z1 = z0 - k1 + G3;\n const x2 = x0 - i2 + 2 * G3;\n const y2 = y0 - j2 + 2 * G3;\n const z2 = z0 - k2 + 2 * G3;\n const x3 = x0 - 1 + 3 * G3;\n const y3 = y0 - 1 + 3 * G3;\n const z3 = z0 - 1 + 3 * G3;\n\n const ii = i & 255;\n const jj = j & 255;\n const kk = k & 255;\n\n let n = 0;\n let c = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;\n if (c > 0) {\n const g = permMod12[ii + perm[jj + perm[kk]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x0 + GRAD3[g + 1] * y0 + GRAD3[g + 2] * z0);\n }\n c = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;\n if (c > 0) {\n const g = permMod12[ii + i1 + perm[jj + j1 + perm[kk + k1]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x1 + GRAD3[g + 1] * y1 + GRAD3[g + 2] * z1);\n }\n c = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;\n if (c > 0) {\n const g = permMod12[ii + i2 + perm[jj + j2 + perm[kk + k2]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x2 + GRAD3[g + 1] * y2 + GRAD3[g + 2] * z2);\n }\n c = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;\n if (c > 0) {\n const g = permMod12[ii + 1 + perm[jj + 1 + perm[kk + 1]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x3 + GRAD3[g + 1] * y3 + GRAD3[g + 2] * z3);\n }\n return 32 * n;\n };\n}\n","import { createNoise3D, type Noise3D } from '../../shared/noise';\nimport type { ResolvedTopoOptions } from './options';\n\n/** Noise-time distance between sampled keyframes; frames in between are blended. */\nconst KEY_DT = 0.02;\n\nexport type FieldParams = Pick<ResolvedTopoOptions, 'seed' | 'scale' | 'octaves' | 'cellSize'>;\n\nexport interface KeyframeField {\n readonly cols: number;\n readonly rows: number;\n /** The terrain at time `t` is `keyA + (keyB - keyA) * blend`, see `advance()`. */\n readonly keyA: Float32Array;\n readonly keyB: Float32Array;\n /** Changes whenever the contents of `keyA` / `keyB` change. */\n readonly version: number;\n /** Apply new parameters; resamples only if something actually changed. */\n configure(params: FieldParams): void;\n /** Size of the area to cover, in CSS pixels. */\n resize(width: number, height: number): void;\n /** Bring the keyframes up to `time` and return the blend factor between them. */\n advance(time: number): number;\n}\n\n/**\n * The terrain height field, sampled on a grid `cellSize` pixels apart.\n *\n * Sampling noise for every grid point is the most expensive step, but the\n * terrain changes slowly. So noise is only sampled at keyframes KEY_DT apart\n * (A at `keyTime`, B at `keyTime + KEY_DT`) and every frame blends between them.\n * The keyframe after B is built a few rows per frame to avoid spikes.\n */\nexport function createKeyframeField(initial: FieldParams): KeyframeField {\n let params = initial;\n let noise: Noise3D = createNoise3D(params.seed);\n // Sum of octave amplitudes (1 + 1/2 + 1/4 + …), to normalise the result to [-1, 1].\n let norm = 2 - 2 ** (1 - params.octaves);\n\n let width = 0;\n let height = 0;\n let cols = 0;\n let rows = 0;\n let keyA = new Float32Array(0);\n let keyB = new Float32Array(0);\n let keyNext = new Float32Array(0);\n let keyTime = 0;\n let keyNextRows = 0;\n let valid = false;\n let version = 0;\n\n function allocate(): void {\n const nextCols = Math.ceil(width / params.cellSize) + 1;\n const nextRows = Math.ceil(height / params.cellSize) + 1;\n if (nextCols === cols && nextRows === rows) return;\n cols = nextCols;\n rows = nextRows;\n keyA = new Float32Array(cols * rows);\n keyB = new Float32Array(cols * rows);\n keyNext = new Float32Array(cols * rows);\n valid = false;\n }\n\n function sampleRows(target: Float32Array, t: number, fromRow: number, toRow: number): void {\n const { cellSize, octaves, scale } = params;\n for (let j = fromRow; j < toRow; j++) {\n const y = j * cellSize;\n for (let i = 0; i < cols; i++) {\n const x = i * cellSize;\n let value = 0;\n for (let o = 0, amp = 1, freq = scale; o < octaves; o++, amp *= 0.5, freq *= 2) {\n value += amp * noise(x * freq, y * freq, t + o * 17.3);\n }\n target[j * cols + i] = value / norm;\n }\n }\n }\n\n return {\n get cols() {\n return cols;\n },\n get rows() {\n return rows;\n },\n get keyA() {\n return keyA;\n },\n get keyB() {\n return keyB;\n },\n get version() {\n return version;\n },\n\n configure(next) {\n const prev = params;\n if (\n next.seed === prev.seed &&\n next.scale === prev.scale &&\n next.octaves === prev.octaves &&\n next.cellSize === prev.cellSize\n ) {\n return;\n }\n params = { seed: next.seed, scale: next.scale, octaves: next.octaves, cellSize: next.cellSize };\n if (next.seed !== prev.seed) noise = createNoise3D(next.seed);\n norm = 2 - 2 ** (1 - next.octaves);\n allocate();\n valid = false;\n },\n\n resize(nextWidth, nextHeight) {\n width = nextWidth;\n height = nextHeight;\n allocate();\n },\n\n advance(time) {\n if (!valid || time < keyTime || time >= keyTime + 2 * KEY_DT) {\n keyTime = time;\n sampleRows(keyA, keyTime, 0, rows);\n sampleRows(keyB, keyTime + KEY_DT, 0, rows);\n keyNextRows = 0;\n valid = true;\n version++;\n }\n if (time >= keyTime + KEY_DT) {\n sampleRows(keyNext, keyTime + 2 * KEY_DT, keyNextRows, rows);\n [keyA, keyB, keyNext] = [keyB, keyNext, keyA];\n keyTime += KEY_DT;\n keyNextRows = 0;\n version++;\n }\n // Spread the next keyframe over the first 80% of the interval.\n const progress = (time - keyTime) / KEY_DT;\n const wanted = Math.min(rows, Math.ceil((rows * progress) / 0.8));\n if (wanted > keyNextRows) {\n sampleRows(keyNext, keyTime + 2 * KEY_DT, keyNextRows, wanted);\n keyNextRows = wanted;\n }\n return progress;\n },\n };\n}\n","import type { Frame } from '../../core/style';\nimport { createKeyframeField, type KeyframeField } from './field';\nimport type { ResolvedTopoOptions } from './options';\n\n/** The animated height field both topo renderers draw: keyframes plus the clock that drives them. */\nexport interface Terrain {\n readonly field: KeyframeField;\n configure(options: ResolvedTopoOptions): void;\n /** Move the terrain forward by one frame and return the blend factor between the keyframes. */\n advance(frame: Frame): number;\n}\n\nexport function createTerrain(initial: ResolvedTopoOptions): Terrain {\n const field = createKeyframeField(initial);\n let speed = initial.speed;\n let time = 0;\n return {\n field,\n configure(options) {\n field.configure(options);\n speed = options.speed;\n },\n advance(frame) {\n field.resize(frame.width, frame.height);\n if (!frame.reducedMotion) time += frame.dt * speed;\n return field.advance(time);\n },\n };\n}\n","import type { StyleRenderer } from '../../core/style';\nimport { createFloatBuffer, reserve, type FloatBuffer } from '../../shared/buffer';\nimport { traceContours } from './contours';\nimport { resolveTopoOptions, type TopoOptions } from './options';\nimport { createTerrain } from './terrain';\n\n/** Marching squares on the CPU, stroked with the Canvas 2D API. */\nexport function createTopoCanvas2D(ctx: CanvasRenderingContext2D, initial: TopoOptions): StyleRenderer<TopoOptions> {\n let options = resolveTopoOptions(initial);\n const terrain = createTerrain(options);\n let field = new Float32Array(0);\n\n // Segments are collected into reusable buffers and stroked from the context's\n // own path, so a frame allocates nothing. Path2D objects per frame pile up as\n // native garbage faster than the browser frees them.\n // Line segments as x1, y1, x2, y2.\n const minor = createFloatBuffer(4096);\n const major = createFloatBuffer(1024);\n\n function collectSegment(x1: number, y1: number, x2: number, y2: number, level: number): void {\n const buffer = options.majorEvery > 0 && level % options.majorEvery === 0 ? major : minor;\n const data = reserve(buffer, 4);\n data[buffer.length++] = x1;\n data[buffer.length++] = y1;\n data[buffer.length++] = x2;\n data[buffer.length++] = y2;\n }\n\n function stroke(buffer: FloatBuffer, color: string, lineWidth: number): void {\n const { data, length } = buffer;\n ctx.beginPath();\n for (let k = 0; k < length; k += 4) {\n ctx.moveTo(data[k], data[k + 1]);\n ctx.lineTo(data[k + 2], data[k + 3]);\n }\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.stroke();\n }\n\n /** Blend the keyframes and add the pointer bump into `field`. */\n function sampleField(blend: number, pointerX: number, pointerY: number, bump: number): void {\n const { cols, rows, keyA, keyB } = terrain.field;\n const size = cols * rows;\n if (field.length !== size) field = new Float32Array(size);\n for (let idx = 0; idx < size; idx++) {\n const a = keyA[idx];\n field[idx] = a + (keyB[idx] - a) * blend;\n }\n\n if (bump === 0) return;\n const { cellSize, pointerRadius } = options;\n const radius2 = pointerRadius * pointerRadius;\n // Beyond 3 radii the bump adds < 0.0001, so only touch the cells around the pointer.\n const reach = 3 * pointerRadius;\n const i0 = Math.max(0, Math.floor((pointerX - reach) / cellSize));\n const i1 = Math.min(cols - 1, Math.ceil((pointerX + reach) / cellSize));\n const j0 = Math.max(0, Math.floor((pointerY - reach) / cellSize));\n const j1 = Math.min(rows - 1, Math.ceil((pointerY + reach) / cellSize));\n for (let j = j0; j <= j1; j++) {\n const dy = j * cellSize - pointerY;\n for (let i = i0; i <= i1; i++) {\n const dx = i * cellSize - pointerX;\n field[j * cols + i] += bump * Math.exp(-(dx * dx + dy * dy) / radius2);\n }\n }\n }\n\n return {\n update(next) {\n options = resolveTopoOptions(next);\n terrain.configure(options);\n },\n render(frame) {\n const blend = terrain.advance(frame);\n const { pointer } = frame;\n sampleField(blend, pointer.x, pointer.y, options.pointerStrength * pointer.influence);\n\n minor.length = major.length = 0;\n const { cols, rows } = terrain.field;\n traceContours(field, cols, rows, options.cellSize, options.levelStep, collectSegment);\n\n ctx.globalAlpha = options.lineOpacity;\n stroke(minor, options.lineColor, options.lineWidth);\n if (options.majorEvery > 0) stroke(major, options.majorLineColor, options.majorLineWidth);\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { topoDefaults, type TopoOptions } from './options';\n\n/**\n * Animated topographic contour lines. The terrain drifts slowly and rises\n * (or, with a negative `pointerStrength`, sinks) under the pointer.\n */\nexport const topoStyle: StyleBase<TopoOptions> = {\n name: 'topo',\n defaults: topoDefaults,\n animates: (options) => options.speed !== 0,\n};\n","import { parseColor } from '../../core/color';\nimport type { StyleRenderer } from '../../core/style';\nimport { createProgram, FULLSCREEN_VERTEX_SHADER, getUniforms } from '../../core/webgl';\nimport { resolveTopoOptions, type TopoOptions } from './options';\nimport { createTerrain } from './terrain';\n\nconst FRAGMENT = `#version 300 es\nprecision highp float;\nprecision highp sampler2D;\n\nuniform sampler2D uKeyA;\nuniform sampler2D uKeyB;\nuniform float uBlend;\nuniform vec2 uGrid; // cols, rows\nuniform float uCellSize; // CSS px between grid samples\nuniform float uDpr;\nuniform float uHeight; // canvas height in device px\nuniform vec3 uPointer; // x, y (CSS px), bump height\nuniform float uRadius2;\nuniform float uStep; // height difference between contour levels\nuniform float uMajorEvery;\nuniform vec2 uHalfWidth; // half line widths (device px): minor, major\nuniform vec4 uMinor; // straight RGBA, opacity applied\nuniform vec4 uMajor;\n\nout vec4 outColor;\n\nfloat heightAt(ivec2 c) {\n return mix(texelFetch(uKeyA, c, 0).r, texelFetch(uKeyB, c, 0).r, uBlend);\n}\n\nvoid main() {\n vec2 p = vec2(gl_FragCoord.x, uHeight - gl_FragCoord.y) / uDpr;\n\n // Bilinear interpolation of the height field (same surface the CPU renderer traces).\n vec2 g = p / uCellSize;\n vec2 cell = clamp(floor(g), vec2(0.0), uGrid - 2.0);\n vec2 f = g - cell;\n ivec2 c = ivec2(cell);\n float h = mix(\n mix(heightAt(c), heightAt(c + ivec2(1, 0)), f.x),\n mix(heightAt(c + ivec2(0, 1)), heightAt(c + ivec2(1, 1)), f.x),\n f.y);\n\n vec2 d = p - uPointer.xy;\n h += uPointer.z * exp(-dot(d, d) / uRadius2);\n\n // Distance to the nearest contour, in device pixels, from the screen-space gradient.\n float v = h / uStep;\n float level = floor(v + 0.5);\n float dist = abs(v - level) / max(fwidth(v), 1e-5);\n\n bool major = uMajorEvery > 0.0 && mod(level, uMajorEvery) == 0.0;\n float halfWidth = major ? uHalfWidth.y : uHalfWidth.x;\n vec4 line = major ? uMajor : uMinor;\n // Analytic antialiasing: coverage ramps over one pixel at the line edge.\n float a = line.a * clamp(halfWidth + 0.5 - dist, 0.0, 1.0);\n outColor = vec4(line.rgb * a, a); // premultiplied; the engine blends it over the background\n}`;\n\nconst UNIFORMS = [\n 'uKeyA', 'uKeyB', 'uBlend', 'uGrid', 'uCellSize', 'uDpr', 'uHeight', 'uPointer', 'uRadius2',\n 'uStep', 'uMajorEvery', 'uHalfWidth', 'uMinor', 'uMajor',\n] as const;\n\n/**\n * Per-pixel contour lines in a fragment shader. The CPU only uploads the two noise\n * keyframes when they change (once per keyframe interval) and sets a few uniforms per frame.\n */\nexport function createTopoWebGL(gl: WebGL2RenderingContext, initial: TopoOptions): StyleRenderer<TopoOptions> {\n let options = resolveTopoOptions(initial);\n const terrain = createTerrain(options);\n\n const program = createProgram(gl, FULLSCREEN_VERTEX_SHADER, FRAGMENT);\n const uniforms = program ? getUniforms(gl, program, UNIFORMS) : null;\n const textures = [gl.createTexture(), gl.createTexture()] as const;\n for (const texture of textures) {\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n }\n let textureCols = 0;\n let textureRows = 0;\n let uploadedVersion = -1;\n\n /** Upload the keyframes when they changed since the last frame. */\n function upload(): void {\n const { field } = terrain;\n const resized = textureCols !== field.cols || textureRows !== field.rows;\n if (!resized && uploadedVersion === field.version) return;\n const keys = [field.keyA, field.keyB];\n for (let unit = 0; unit < 2; unit++) {\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, textures[unit]);\n if (resized) {\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, field.cols, field.rows, 0, gl.RED, gl.FLOAT, keys[unit]);\n } else {\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, field.cols, field.rows, gl.RED, gl.FLOAT, keys[unit]);\n }\n }\n textureCols = field.cols;\n textureRows = field.rows;\n uploadedVersion = field.version;\n }\n\n return {\n update(next) {\n options = resolveTopoOptions(next);\n terrain.configure(options);\n },\n render(frame) {\n const blend = terrain.advance(frame);\n if (!program || !uniforms) return; // context lost during setup; the engine recreates us\n upload();\n\n const minor = parseColor(options.lineColor);\n const major = parseColor(options.majorLineColor);\n const opacity = options.lineOpacity;\n const { field } = terrain;\n\n gl.useProgram(program);\n gl.uniform1i(uniforms.uKeyA, 0);\n gl.uniform1i(uniforms.uKeyB, 1);\n gl.uniform1f(uniforms.uBlend, blend);\n gl.uniform2f(uniforms.uGrid, field.cols, field.rows);\n gl.uniform1f(uniforms.uCellSize, options.cellSize);\n gl.uniform1f(uniforms.uDpr, frame.dpr);\n gl.uniform1f(uniforms.uHeight, gl.drawingBufferHeight);\n gl.uniform3f(uniforms.uPointer, frame.pointer.x, frame.pointer.y, options.pointerStrength * frame.pointer.influence);\n gl.uniform1f(uniforms.uRadius2, options.pointerRadius * options.pointerRadius);\n gl.uniform1f(uniforms.uStep, options.levelStep);\n gl.uniform1f(uniforms.uMajorEvery, options.majorEvery);\n gl.uniform2f(uniforms.uHalfWidth, (options.lineWidth * frame.dpr) / 2, (options.majorLineWidth * frame.dpr) / 2);\n gl.uniform4f(uniforms.uMinor, minor[0], minor[1], minor[2], minor[3] * opacity);\n gl.uniform4f(uniforms.uMajor, major[0], major[1], major[2], major[3] * opacity);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n },\n destroy() {\n gl.deleteTexture(textures[0]);\n gl.deleteTexture(textures[1]);\n gl.deleteProgram(program);\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createTopoCanvas2D } from '../styles/topo/canvas2d';\nimport { topoStyle } from '../styles/topo/definition';\nimport type { TopoOptions } from '../styles/topo/options';\nimport { createTopoWebGL } from '../styles/topo/webgl';\n\nexport type { TopoOptions };\n\n/** Animated topographic contour lines, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const topo: StyleFactory<TopoOptions> = defineStyle({\n ...topoStyle,\n renderers: [webglRenderer(createTopoWebGL), canvas2dRenderer(createTopoCanvas2D)],\n});\n","import type { Frame } from '../core/style';\n\n// The motion model shared by the grid styles (dots, plus): a grid of marks that\n// wander around their places, react to the pointer and to click waves. The\n// WebGL vertex shaders mirror parts of it in GLSL (grid-webgl.ts); keep them in step.\n\nexport const TAU = Math.PI * 2;\n\n/** At most this many waves play at once; a new click replaces the oldest. */\nexport const MAX_WAVES = 8;\n\nexport interface Grid {\n cols: number;\n rows: number;\n /** Position of mark (0, 0), in CSS pixels. */\n originX: number;\n originY: number;\n}\n\n/**\n * A grid that fits inside the canvas, centred, leaving at least half a\n * `spacing` of padding on every side so marks at the edges are never clipped.\n * Any space left over is shared equally between opposite sides. A canvas too\n * small for the padding still gets one mark, in its centre.\n */\nexport function gridLayout(width: number, height: number, spacing: number): Grid {\n const cols = Math.max(1, Math.floor(width / spacing));\n const rows = Math.max(1, Math.floor(height / spacing));\n return {\n cols,\n rows,\n originX: (width - (cols - 1) * spacing) / 2,\n originY: (height - (rows - 1) * spacing) / 2,\n };\n}\n\n/** A stable pseudo-random phase in [0, 2π) for mark (i, j). */\nexport function cellPhase(i: number, j: number, salt: number): number {\n const s = Math.sin(i * 12.9898 + j * 78.233 + salt) * 43758.5453;\n return (s - Math.floor(s)) * TAU;\n}\n\n/**\n * Each mark's wander phases (px, py) as cos px, sin px, cos py, sin py,\n * recomputed only when the grid changes size. The wander offset is\n * `jitter × (sin(clock + px), cos(clock × 1.3 + py))`; see wanderClock.\n */\nexport function createPhaseCache(): (cols: number, rows: number) => Float32Array {\n let phases = new Float32Array(0);\n let phaseCols = 0;\n return (cols, rows) => {\n if (phaseCols === cols && phases.length === cols * rows * 4) return phases;\n phases = new Float32Array(cols * rows * 4);\n for (let j = 0; j < rows; j++) {\n for (let i = 0; i < cols; i++) {\n const k = (j * cols + i) * 4;\n const px = cellPhase(i, j, 0);\n const py = cellPhase(i, j, 1);\n phases[k] = Math.cos(px);\n phases[k + 1] = Math.sin(px);\n phases[k + 2] = Math.cos(py);\n phases[k + 3] = Math.sin(py);\n }\n }\n phaseCols = cols;\n return phases;\n };\n}\n\n/**\n * The trig of the wander clock for one frame. With a mark's cached phases\n * (createPhaseCache), its offset is\n * x = jitter × (sx × cos px + cx × sin px) = jitter × sin(clock + px)\n * y = jitter × (cy × cos py − sy × sin py) = jitter × cos(clock × 1.3 + py)\n * so a frame needs four trig calls in all instead of two per mark.\n */\nexport function wanderClock(clock: number): { sx: number; cx: number; sy: number; cy: number } {\n return { sx: Math.sin(clock), cx: Math.cos(clock), sy: Math.sin(clock * 1.3), cy: Math.cos(clock * 1.3) };\n}\n\n/** How strongly the pointer affects a mark `distance` away: 1 at the pointer, easing to 0 at `radius`. */\nexport function pointerFalloff(distance: number, radius: number): number {\n const k = Math.max(0, 1 - distance / radius);\n return k * k;\n}\n\n/** Height of a wave's ring at `distance` from its centre: 1 on the ring, fading over `width` either side. */\nexport function waveRing(distance: number, ringRadius: number, width: number): number {\n const x = (distance - ringRadius) / width;\n return Math.exp(-x * x);\n}\n\n/** How much of a wave is left at `age`: 1 when it starts, easing out to 0 at `duration`. */\nexport function waveEnvelope(age: number, duration: number): number {\n const k = Math.max(0, 1 - age / duration);\n return k * k;\n}\n\n/** The wander moves each mark at most this far between frames, in CSS pixels; finer steps can't be seen. */\nconst WANDER_STEP = 0.25;\n\n/**\n * Frame rate that keeps every wander step below WANDER_STEP. The fastest a mark\n * wanders is along y: amplitude × angular speed × 1.3.\n */\nexport function wanderFps(jitter: number, jitterSpeed: number): number {\n const maxSpeed = jitter * jitterSpeed * TAU * 1.3;\n return Math.ceil(maxSpeed / WANDER_STEP);\n}\n\n/** Idle frame rate for a wandering grid: just enough for a smooth wander, at least 5 fps. */\nexport function wanderIdleFps(options: { jitter: number; jitterSpeed: number }): number {\n return Math.max(5, wanderFps(options.jitter, options.jitterSpeed));\n}\n\nexport interface Wave {\n x: number;\n y: number;\n age: number;\n}\n\n/** The click waves currently playing. */\nexport interface WaveList {\n readonly waves: readonly Wave[];\n /**\n * Start waves for this frame's clicks (unless `enabled` is false), age the\n * rest, and drop those older than `duration` seconds.\n */\n advance(frame: Frame, duration: number, enabled: boolean): void;\n /** Writes each wave as x, y, ring radius, envelope into `out` (MAX_WAVES × 4), zeroing unused slots. */\n pack(out: Float32Array, speed: number, duration: number): void;\n}\n\nexport function createWaveList(): WaveList {\n const waves: Wave[] = [];\n return {\n waves,\n advance(frame, duration, enabled) {\n for (const wave of waves) wave.age += frame.dt;\n for (let k = waves.length - 1; k >= 0; k--) {\n if (waves[k].age >= duration) waves.splice(k, 1);\n }\n if (!enabled) return;\n for (const click of frame.clicks) {\n if (waves.length === MAX_WAVES) waves.shift();\n waves.push({ x: click.x, y: click.y, age: 0 });\n }\n },\n pack(out, speed, duration) {\n out.fill(0);\n for (let k = 0; k < waves.length; k++) {\n const wave = waves[k];\n out[k * 4] = wave.x;\n out[k * 4 + 1] = wave.y;\n out[k * 4 + 2] = speed * wave.age;\n out[k * 4 + 3] = waveEnvelope(wave.age, duration);\n }\n },\n };\n}\n","// The dots-specific part of the motion model; the rest is shared with other\n// grid styles in shared/grid.ts.\n\n/** Size boost of a dot riding the crest of a wave (1 + WAVE_GROW × ring). */\nexport const WAVE_GROW = 0.6;\n","export interface DotsOptions {\n /** Dot colour. Any CSS colour. */\n color: string;\n /** Opacity of the dots, from `0` to `1`. Multiplies any alpha in the colour. */\n opacity: number;\n /** Dot radius in CSS pixels. */\n size: number;\n /**\n * Distance between neighbouring dots in CSS pixels. The grid also keeps at least half of\n * this as empty space along every edge, so dots at the edges aren't clipped.\n */\n spacing: number;\n /** How far each dot wanders around its place, in CSS pixels. `0` = still. */\n jitter: number;\n /** How fast the dots wander, in cycles per second. `0` = still. */\n jitterSpeed: number;\n /** Radius around the pointer within which dots are pushed away, in CSS pixels. */\n pointerRadius: number;\n /** How far the dots right next to the pointer are pushed, in CSS pixels. Negative values pull them in. */\n pointerStrength: number;\n /** How fast a click wave travels outwards, in CSS pixels per second. */\n waveSpeed: number;\n /** How far a click wave pushes dots, in CSS pixels. `0` disables waves. */\n waveStrength: number;\n /** Width of a click wave's ring, in CSS pixels. */\n waveWidth: number;\n /** How long a click wave lasts before it has faded out, in seconds. */\n waveDuration: number;\n}\n\nexport const dotsDefaults: Readonly<DotsOptions> = Object.freeze({\n color: '#8b95a5',\n opacity: 0.6,\n size: 1.6,\n spacing: 26,\n jitter: 1.2,\n jitterSpeed: 0.35,\n pointerRadius: 160,\n pointerStrength: 22,\n waveSpeed: 520,\n waveStrength: 10,\n waveWidth: 60,\n waveDuration: 1.8,\n});\n\n/** Options after clamping: what the renderers consume. */\nexport type ResolvedDotsOptions = DotsOptions;\n\nexport function resolveDotsOptions(options: DotsOptions): ResolvedDotsOptions {\n return {\n ...options,\n opacity: Math.min(1, Math.max(0, options.opacity)),\n size: Math.max(0.1, options.size),\n spacing: Math.max(4, options.spacing),\n jitter: Math.max(0, options.jitter),\n jitterSpeed: Math.max(0, options.jitterSpeed),\n pointerRadius: Math.max(1, options.pointerRadius),\n waveSpeed: Math.max(1, options.waveSpeed),\n waveWidth: Math.max(1, options.waveWidth),\n waveDuration: Math.max(0.05, options.waveDuration),\n };\n}\n","import type { StyleRenderer } from '../../core/style';\nimport { createFloatBuffer, reserve, type FloatBuffer } from '../../shared/buffer';\nimport {\n createPhaseCache,\n createWaveList,\n gridLayout,\n MAX_WAVES,\n pointerFalloff,\n TAU,\n wanderClock,\n waveRing,\n} from '../../shared/grid';\nimport { WAVE_GROW } from './motion';\nimport { resolveDotsOptions, type DotsOptions } from './options';\n\n/** Dots grown by waves are drawn in this many size steps per unit of growth (steps of ~0.25 px). */\nconst SIZE_STEPS = 4;\n/** Growth beyond this is clamped (two overlapping wave crests). */\nconst MAX_SIZE_STEP = 2 * SIZE_STEPS;\n\n/**\n * Every dot's position computed on the CPU. Dots are drawn as zero-length lines\n * with round caps: that renders the same round dots as `arc()`, about 4× faster.\n */\nexport function createDotsCanvas2D(ctx: CanvasRenderingContext2D, initial: DotsOptions): StyleRenderer<DotsOptions> {\n let options = resolveDotsOptions(initial);\n const waves = createWaveList();\n // Each wave as x, y, ring radius, envelope, worked out once per frame instead of once per dot.\n const waveData = new Float32Array(MAX_WAVES * 4);\n let clock = 0;\n\n // Dot centres as x, y pairs, one buffer per size step; dots outside a wave all land in step 0.\n const sizes = Array.from({ length: MAX_SIZE_STEP + 1 }, () => createFloatBuffer(256));\n\n function add(buffer: FloatBuffer, x: number, y: number): void {\n const data = reserve(buffer, 2);\n data[buffer.length++] = x;\n data[buffer.length++] = y;\n }\n\n function stroke(buffer: FloatBuffer, radius: number): void {\n const { data, length } = buffer;\n ctx.lineWidth = 2 * radius;\n ctx.beginPath();\n for (let k = 0; k < length; k += 2) {\n ctx.moveTo(data[k], data[k + 1]);\n // A tiny length: some browsers skip the caps of exactly zero-length lines.\n ctx.lineTo(data[k] + 0.01, data[k + 1]);\n }\n ctx.stroke();\n }\n\n const phasesFor = createPhaseCache();\n\n return {\n update(next) {\n options = resolveDotsOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, options.waveStrength !== 0);\n\n const { spacing, size, jitter, pointerRadius, waveWidth, waveStrength } = options;\n const { cols, rows, originX, originY } = gridLayout(frame.width, frame.height, spacing);\n const wander = phasesFor(cols, rows);\n const { sx, cx, sy, cy } = wanderClock(clock);\n const push = options.pointerStrength * frame.pointer.influence;\n const { x: px, y: py } = frame.pointer;\n const waveCount = waves.waves.length;\n waves.pack(waveData, options.waveSpeed, options.waveDuration);\n // Further than 3 widths from its ring a wave moves a dot by less than e⁻⁹ of its strength.\n const waveReach = 3 * waveWidth;\n for (const buffer of sizes) buffer.length = 0;\n\n for (let j = 0; j < rows; j++) {\n const restY = originY + j * spacing;\n for (let i = 0; i < cols; i++) {\n const restX = originX + i * spacing;\n const k = (j * cols + i) * 4;\n let x = restX + jitter * (sx * wander[k] + cx * wander[k + 1]);\n let y = restY + jitter * (cy * wander[k + 2] - sy * wander[k + 3]);\n\n if (push !== 0) {\n const dx = restX - px;\n const dy = restY - py;\n if (Math.abs(dx) < pointerRadius && Math.abs(dy) < pointerRadius) {\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (distance > 0 && distance < pointerRadius) {\n const amount = (push * pointerFalloff(distance, pointerRadius)) / distance;\n x += dx * amount;\n y += dy * amount;\n }\n }\n }\n\n let grow = 0;\n for (let w = 0; w < waveCount * 4; w += 4) {\n const dx = restX - waveData[w];\n const dy = restY - waveData[w + 1];\n const outer = waveData[w + 2] + waveReach;\n if (Math.abs(dx) > outer || Math.abs(dy) > outer) continue;\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (distance === 0 || Math.abs(distance - waveData[w + 2]) > waveReach) continue;\n const ring = waveRing(distance, waveData[w + 2], waveWidth) * waveData[w + 3];\n const amount = (waveStrength * ring) / distance;\n x += dx * amount;\n y += dy * amount;\n grow += ring;\n }\n\n add(sizes[Math.min(MAX_SIZE_STEP, Math.round(grow * SIZE_STEPS))], x, y);\n }\n }\n\n ctx.globalAlpha = options.opacity;\n ctx.strokeStyle = options.color;\n ctx.lineCap = 'round';\n for (let step = 0; step <= MAX_SIZE_STEP; step++) {\n if (sizes[step].length > 0) stroke(sizes[step], size * (1 + (WAVE_GROW * step) / SIZE_STEPS));\n }\n return waveCount > 0;\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { wanderIdleFps } from '../../shared/grid';\nimport { dotsDefaults, type DotsOptions } from './options';\n\n/**\n * A grid of dots that wander gently around their places. The pointer pushes\n * nearby dots away, more the closer they are, and clicks send out a wave.\n */\nexport const dotsStyle: StyleBase<DotsOptions> = {\n name: 'dots',\n defaults: dotsDefaults,\n animates: (options) => options.jitter > 0 && options.jitterSpeed > 0,\n // The wander is slow and sub-pixel, so it rarely needs the engine's full idle frame rate.\n idleFps: wanderIdleFps,\n};\n","import type { Frame } from '../core/style';\nimport { TAU, type Grid } from './grid';\n\n/** The uniforms GRID_VERTEX_GLSL declares; set them with setGridUniforms(). */\nexport const GRID_UNIFORMS = ['uCols', 'uOrigin', 'uSpacing', 'uViewport', 'uDpr', 'uClock', 'uJitter'] as const;\n\n/**\n * Vertex-shader preamble for the grid styles, which draw one GL point per mark.\n * Mirrors gridLayout, cellPhase and the wander in grid.ts; keep them in step.\n */\nexport const GRID_VERTEX_GLSL = `\nuniform int uCols;\nuniform vec2 uOrigin; // CSS px of mark (0, 0)\nuniform float uSpacing;\nuniform vec2 uViewport; // canvas size in CSS px\nuniform float uDpr;\nuniform float uClock; // wander phase, radians\nuniform float uJitter;\n\nfloat phase(vec2 ij, float salt) {\n return fract(sin(ij.x * 12.9898 + ij.y * 78.233 + salt) * 43758.5453) * ${TAU.toFixed(6)};\n}\n\n// This vertex's mark as (column, row). Integer maths: float division can put the first\n// mark of a row at the end of the previous one on some GPUs.\nvec2 markCell() {\n return vec2(float(gl_VertexID % uCols), float(gl_VertexID / uCols));\n}\n\nvec2 restPosition(vec2 ij) {\n return uOrigin + ij * uSpacing;\n}\n\nvec2 wander(vec2 ij) {\n return uJitter * vec2(sin(uClock + phase(ij, 0.0)), cos(uClock * 1.3 + phase(ij, 1.0)));\n}\n\n// CSS px (origin top left) to clip space.\nvec4 toClip(vec2 p) {\n vec2 clip = p / uViewport * 2.0 - 1.0;\n return vec4(clip.x, -clip.y, 0.0, 1.0);\n}\n`;\n\nexport function setGridUniforms(\n gl: WebGL2RenderingContext,\n uniforms: Record<(typeof GRID_UNIFORMS)[number], WebGLUniformLocation | null>,\n grid: Grid,\n frame: Frame,\n spacing: number,\n clock: number,\n jitter: number,\n): void {\n gl.uniform1i(uniforms.uCols, grid.cols);\n gl.uniform2f(uniforms.uOrigin, grid.originX, grid.originY);\n gl.uniform1f(uniforms.uSpacing, spacing);\n gl.uniform2f(uniforms.uViewport, frame.width, frame.height);\n gl.uniform1f(uniforms.uDpr, frame.dpr);\n gl.uniform1f(uniforms.uClock, clock);\n gl.uniform1f(uniforms.uJitter, jitter);\n}\n","import { parseColor } from '../../core/color';\nimport type { StyleRenderer } from '../../core/style';\nimport { createProgram, getUniforms } from '../../core/webgl';\nimport { createWaveList, gridLayout, MAX_WAVES, TAU } from '../../shared/grid';\nimport { GRID_UNIFORMS, GRID_VERTEX_GLSL, setGridUniforms } from '../../shared/grid-webgl';\nimport { WAVE_GROW } from './motion';\nimport { resolveDotsOptions, type DotsOptions } from './options';\n\n// Mirrors the motion model in shared/grid.ts: pointerFalloff, waveRing.\nconst VERTEX = `#version 300 es\nprecision highp float;\n\n${GRID_VERTEX_GLSL}\nuniform float uSize; // dot radius, CSS px\nuniform vec3 uPointer; // x, y, push distance (strength × influence)\nuniform float uPointerRadius;\nuniform vec4 uWaves[${MAX_WAVES}]; // x, y, ring radius, envelope (0 = inactive)\nuniform float uWaveStrength;\nuniform float uWaveWidth;\n\nout float vRadius; // device px\nout float vPointSize; // device px\n\nvoid main() {\n vec2 ij = markCell();\n vec2 rest = restPosition(ij);\n vec2 p = rest + wander(ij);\n\n vec2 d = rest - uPointer.xy;\n float dist = length(d);\n if (dist > 0.0 && dist < uPointerRadius) {\n float k = 1.0 - dist / uPointerRadius;\n p += d / dist * uPointer.z * k * k;\n }\n\n float grow = 0.0;\n for (int w = 0; w < ${MAX_WAVES}; w++) {\n vec4 wave = uWaves[w];\n if (wave.w <= 0.0) continue;\n vec2 dw = rest - wave.xy;\n float dd = length(dw);\n if (dd == 0.0) continue;\n float x = (dd - wave.z) / uWaveWidth;\n float ring = exp(-x * x) * wave.w;\n p += dw / dd * uWaveStrength * ring;\n grow += ring;\n }\n\n vRadius = uSize * (1.0 + ${WAVE_GROW.toFixed(3)} * grow) * uDpr;\n vPointSize = 2.0 * vRadius + 2.0; // room for the antialiased edge\n gl_PointSize = vPointSize;\n gl_Position = toClip(p);\n}`;\n\nconst FRAGMENT = `#version 300 es\nprecision highp float;\n\nuniform vec4 uColor; // straight RGBA, opacity applied\nin float vRadius;\nin float vPointSize;\nout vec4 outColor;\n\nvoid main() {\n float dist = length(gl_PointCoord - 0.5) * vPointSize;\n float a = uColor.a * clamp(vRadius + 0.5 - dist, 0.0, 1.0);\n outColor = vec4(uColor.rgb * a, a); // premultiplied; the engine blends it over the background\n}`;\n\nconst UNIFORMS = [\n ...GRID_UNIFORMS, 'uSize', 'uPointer', 'uPointerRadius', 'uWaves', 'uWaveStrength', 'uWaveWidth', 'uColor',\n] as const;\n\n/** Every dot is one GL point; the vertex shader places it, so the CPU only sets uniforms. */\nexport function createDotsWebGL(gl: WebGL2RenderingContext, initial: DotsOptions): StyleRenderer<DotsOptions> {\n let options = resolveDotsOptions(initial);\n const waves = createWaveList();\n const waveData = new Float32Array(MAX_WAVES * 4);\n let clock = 0;\n\n const program = createProgram(gl, VERTEX, FRAGMENT);\n const uniforms = program ? getUniforms(gl, program, UNIFORMS) : null;\n\n return {\n update(next) {\n options = resolveDotsOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, options.waveStrength !== 0);\n if (!program || !uniforms) return waves.waves.length > 0; // context lost during setup\n\n waves.pack(waveData, options.waveSpeed, options.waveDuration);\n\n const grid = gridLayout(frame.width, frame.height, options.spacing);\n const color = parseColor(options.color);\n\n gl.useProgram(program);\n setGridUniforms(gl, uniforms, grid, frame, options.spacing, clock, options.jitter);\n gl.uniform1f(uniforms.uSize, options.size);\n gl.uniform3f(uniforms.uPointer, frame.pointer.x, frame.pointer.y, options.pointerStrength * frame.pointer.influence);\n gl.uniform1f(uniforms.uPointerRadius, options.pointerRadius);\n gl.uniform4fv(uniforms.uWaves, waveData);\n gl.uniform1f(uniforms.uWaveStrength, options.waveStrength);\n gl.uniform1f(uniforms.uWaveWidth, options.waveWidth);\n gl.uniform4f(uniforms.uColor, color[0], color[1], color[2], color[3] * options.opacity);\n gl.drawArrays(gl.POINTS, 0, grid.cols * grid.rows);\n return waves.waves.length > 0;\n },\n destroy() {\n gl.deleteProgram(program);\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createDotsCanvas2D } from '../styles/dots/canvas2d';\nimport { dotsStyle } from '../styles/dots/definition';\nimport type { DotsOptions } from '../styles/dots/options';\nimport { createDotsWebGL } from '../styles/dots/webgl';\n\nexport type { DotsOptions };\n\n/** A grid of wandering dots, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const dots: StyleFactory<DotsOptions> = defineStyle({\n ...dotsStyle,\n renderers: [webglRenderer(createDotsWebGL), canvas2dRenderer(createDotsCanvas2D)],\n});\n","export interface PlusOptions {\n /** Colour of the signs. Any CSS colour. */\n color: string;\n /** Opacity of the signs, from `0` to `1`. Multiplies any alpha in the colour. */\n opacity: number;\n /** Length of each arm from the centre, in CSS pixels. */\n size: number;\n /** Stroke weight of the arms, in CSS pixels. */\n weight: number;\n /**\n * Distance between neighbouring signs in CSS pixels. The grid also keeps at least half of\n * this as empty space along every edge, so signs at the edges aren't clipped.\n */\n spacing: number;\n /** How far each sign wanders around its place, in CSS pixels. `0` = still. */\n jitter: number;\n /** How fast the signs wander, in cycles per second. `0` = still. */\n jitterSpeed: number;\n /**\n * How fully the signs turn to face the pointer while it's over the background, from `0` (not at all)\n * to `1` (an arm of every sign points straight at the pointer).\n */\n pointerAlign: number;\n /**\n * How smoothly signs turn, in seconds: about how long a sign takes to cover two thirds of a turn.\n * `0` = they snap to their new angle at once.\n */\n turnTime: number;\n /** How fast a click wave travels outwards, in CSS pixels per second. */\n waveSpeed: number;\n /** How fully signs on a click wave's crest turn to face the click, from `0` to `1`. */\n waveAlign: number;\n /** How much heavier a click wave makes the signs it passes: `1` doubles the weight on the crest. */\n waveWeight: number;\n /** Width of a click wave's ring, in CSS pixels. */\n waveWidth: number;\n /** How long a click wave lasts before it has faded out, in seconds. */\n waveDuration: number;\n}\n\nexport const plusDefaults: Readonly<PlusOptions> = Object.freeze({\n color: '#8b95a5',\n opacity: 0.6,\n size: 4,\n weight: 1.2,\n spacing: 28,\n jitter: 1,\n jitterSpeed: 0.35,\n pointerAlign: 1,\n turnTime: 0.25,\n waveSpeed: 520,\n waveAlign: 1,\n waveWeight: 1.5,\n waveWidth: 60,\n waveDuration: 1.8,\n});\n\n/** Options after clamping: what the renderers consume. */\nexport type ResolvedPlusOptions = PlusOptions;\n\nconst unit = (value: number) => Math.min(1, Math.max(0, value));\n\nexport function resolvePlusOptions(options: PlusOptions): ResolvedPlusOptions {\n return {\n ...options,\n opacity: unit(options.opacity),\n size: Math.max(0.5, options.size),\n weight: Math.max(0.1, options.weight),\n spacing: Math.max(4, options.spacing),\n jitter: Math.max(0, options.jitter),\n jitterSpeed: Math.max(0, options.jitterSpeed),\n pointerAlign: unit(options.pointerAlign),\n turnTime: Math.max(0, options.turnTime),\n waveSpeed: Math.max(1, options.waveSpeed),\n waveAlign: unit(options.waveAlign),\n waveWeight: Math.max(0, options.waveWeight),\n waveWidth: Math.max(1, options.waveWidth),\n waveDuration: Math.max(0.05, options.waveDuration),\n };\n}\n\n/** Clicks start a wave only if it would change something. */\nexport function wavesEnabled(options: ResolvedPlusOptions): boolean {\n return options.waveAlign !== 0 || options.waveWeight !== 0;\n}\n","// The plus-specific part of the motion model; the rest is shared with other\n// grid styles in shared/grid.ts.\n\n/** atan(r) for r in [-1, 1], within 1e-5 rad: much cheaper than Math.atan2. */\nfunction atanUnit(r: number): number {\n const r2 = r * r;\n return r * (0.99997726 + r2 * (-0.33262347 + r2 * (0.19354346 + r2 * (-0.11643287 + r2 * (0.05265332 - 0.0117212 * r2)))));\n}\n\n/**\n * The smallest turn that points one of a sign's arms along (dx, dy). A \"+\"\n * looks the same every 90°, so this is always within ±45°.\n */\nexport function facingAngle(dx: number, dy: number): number {\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (ax >= ay) return ax === 0 ? 0 : atanUnit(dy / dx);\n // Steeper than 45°: the vertical arm is closer, a quarter turn away from the horizontal one.\n return -atanUnit(dx / dy);\n}\n","import type { Frame } from '../../core/style';\nimport { MAX_WAVES, waveEnvelope, waveRing, type Grid, type Wave } from '../../shared/grid';\nimport { facingAngle } from './motion';\nimport type { ResolvedPlusOptions } from './options';\n\nconst QUARTER = Math.PI / 2;\n/** A sign has finished turning once its arm tips are this close to where they're heading, in CSS pixels. */\nconst SETTLED_PX = 0.05;\n\n/** The same turn, expressed within ±45° (a \"+\" looks the same every 90°). */\nfunction wrap(angle: number): number {\n return angle - QUARTER * Math.round(angle / QUARTER);\n}\n\n/**\n * Each sign's angle and wave-crest height, kept between frames so signs ease\n * towards the angle they want instead of jumping to it. Both renderers use it.\n */\nexport interface SignTurns {\n /** Angle (radians) and wave-crest height of every sign, row-major, as pairs. */\n readonly data: Float32Array<ArrayBuffer>;\n /** Whether `data` changed in the last update. */\n readonly changed: boolean;\n /** Whether any sign is still turning towards its target. */\n readonly settling: boolean;\n update(frame: Frame, options: ResolvedPlusOptions, grid: Grid, waves: readonly Wave[]): void;\n}\n\nexport function createSignTurns(): SignTurns {\n let data = new Float32Array(0);\n const waveData = new Float32Array(MAX_WAVES * 4);\n\n /** Work out each wave's ring radius and envelope once per frame instead of once per sign. */\n function packWaves(waves: readonly Wave[], speed: number, duration: number): void {\n for (let k = 0; k < waves.length; k++) {\n const wave = waves[k];\n waveData[k * 4] = wave.x;\n waveData[k * 4 + 1] = wave.y;\n waveData[k * 4 + 2] = speed * wave.age;\n waveData[k * 4 + 3] = waveEnvelope(wave.age, duration);\n }\n }\n let changed = false;\n let settling = false;\n // What the last update computed from: if none of it changes, neither do the angles.\n let lastX = NaN;\n let lastY = NaN;\n let lastAlign = NaN;\n let lastOriginX = NaN;\n let lastOriginY = NaN;\n let lastOptions: ResolvedPlusOptions | null = null;\n let hadWaves = false;\n\n return {\n get data() {\n return data;\n },\n get changed() {\n return changed;\n },\n get settling() {\n return settling;\n },\n update(frame, options, grid, waves) {\n const { cols, rows, originX, originY } = grid;\n const { spacing, waveSpeed, waveWidth, waveDuration, waveAlign } = options;\n const resized = data.length !== cols * rows * 2;\n if (resized) data = new Float32Array(cols * rows * 2);\n\n const align = options.pointerAlign * frame.pointer.influence;\n const { x: px, y: py } = frame.pointer;\n // Nothing is turning and nothing it depends on has moved: the angles are already right.\n // With no pointer, every sign is upright whatever the grid or options.\n const unchanged =\n !resized &&\n !settling &&\n !hadWaves &&\n waves.length === 0 &&\n align === lastAlign &&\n (align === 0 ||\n (px === lastX && py === lastY && originX === lastOriginX && originY === lastOriginY && options === lastOptions));\n hadWaves = waves.length > 0;\n if (unchanged) {\n changed = false;\n return;\n }\n lastX = px;\n lastY = py;\n lastAlign = align;\n lastOriginX = originX;\n lastOriginY = originY;\n lastOptions = options;\n\n // Each wave as x, y, ring radius, envelope. Further than 3 widths from its ring a wave is below e⁻⁹: skipped.\n const waveCount = waves.length;\n packWaves(waves, waveSpeed, waveDuration);\n const waveReach = 3 * waveWidth;\n const settled = SETTLED_PX / options.size;\n const ease = options.turnTime > 0 ? 1 - Math.exp(-frame.dt / options.turnTime) : 1;\n settling = false;\n\n for (let j = 0; j < rows; j++) {\n const restY = originY + j * spacing;\n for (let i = 0; i < cols; i++) {\n const restX = originX + i * spacing;\n\n let target = 0;\n // While the pointer is over the background, every sign turns to face it.\n if (align !== 0) target = align * facingAngle(restX - px, restY - py);\n\n let ring = 0;\n for (let w = 0; w < waveCount * 4; w += 4) {\n const dx = restX - waveData[w];\n const dy = restY - waveData[w + 1];\n const outer = waveData[w + 2] + waveReach;\n if (Math.abs(dx) > outer || Math.abs(dy) > outer) continue;\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (Math.abs(distance - waveData[w + 2]) > waveReach) continue;\n const height = waveRing(distance, waveData[w + 2], waveWidth) * waveData[w + 3];\n ring += height;\n // On the crest, signs turn to face the click.\n target += waveAlign * Math.min(1, height) * facingAngle(dx, dy);\n }\n\n // Ease towards the target the short way round, so a sign never spins more than 45°.\n const k = (j * cols + i) * 2;\n const remaining = wrap(target - data[k]);\n if (Math.abs(remaining) < settled) {\n data[k] = wrap(target);\n } else {\n data[k] = wrap(data[k] + remaining * ease);\n settling = true;\n }\n data[k + 1] = ring;\n }\n }\n changed = true;\n },\n };\n}\n","import type { StyleRenderer } from '../../core/style';\nimport { createFloatBuffer, reserve, type FloatBuffer } from '../../shared/buffer';\nimport { createPhaseCache, createWaveList, gridLayout, TAU, wanderClock } from '../../shared/grid';\nimport { resolvePlusOptions, wavesEnabled, type PlusOptions } from './options';\nimport { createSignTurns } from './turns';\n\n/** Signs made heavier by waves are drawn in this many weight steps per unit of ring height. */\nconst WEIGHT_STEPS = 8;\n/** Ring heights beyond this are clamped (two overlapping wave crests). */\nconst MAX_WEIGHT_STEP = 2 * WEIGHT_STEPS;\n\n/**\n * Every sign's position computed on the CPU, with angles and weights from\n * SignTurns. All signs of one weight are a single path of round-capped lines,\n * stroked once.\n */\nexport function createPlusCanvas2D(ctx: CanvasRenderingContext2D, initial: PlusOptions): StyleRenderer<PlusOptions> {\n let options = resolvePlusOptions(initial);\n const waves = createWaveList();\n const phasesFor = createPhaseCache();\n const turns = createSignTurns();\n let clock = 0;\n\n // Signs as x, y, arm vector (dx, dy), one buffer per weight step; signs outside a wave all land in step 0.\n const weights = Array.from({ length: MAX_WEIGHT_STEP + 1 }, () => createFloatBuffer(512));\n\n function add(buffer: FloatBuffer, x: number, y: number, dx: number, dy: number): void {\n const data = reserve(buffer, 4);\n data[buffer.length++] = x;\n data[buffer.length++] = y;\n data[buffer.length++] = dx;\n data[buffer.length++] = dy;\n }\n\n function stroke(buffer: FloatBuffer, weight: number): void {\n const { data, length } = buffer;\n ctx.lineWidth = weight;\n ctx.beginPath();\n for (let k = 0; k < length; k += 4) {\n const x = data[k];\n const y = data[k + 1];\n const dx = data[k + 2];\n const dy = data[k + 3];\n // Two arms: along (dx, dy) and along its perpendicular (-dy, dx).\n ctx.moveTo(x - dx, y - dy);\n ctx.lineTo(x + dx, y + dy);\n ctx.moveTo(x + dy, y - dx);\n ctx.lineTo(x - dy, y + dx);\n }\n ctx.stroke();\n }\n\n return {\n update(next) {\n options = resolvePlusOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, wavesEnabled(options));\n\n const { spacing, size, jitter } = options;\n const grid = gridLayout(frame.width, frame.height, spacing);\n const { cols, rows, originX, originY } = grid;\n const wander = phasesFor(cols, rows);\n const { sx, cx, sy, cy } = wanderClock(clock);\n turns.update(frame, options, grid, waves.waves);\n const turn = turns.data;\n for (const buffer of weights) buffer.length = 0;\n\n for (let j = 0; j < rows; j++) {\n const restY = originY + j * spacing;\n for (let i = 0; i < cols; i++) {\n const k = j * cols + i;\n const w = k * 4;\n const x = originX + i * spacing + jitter * (sx * wander[w] + cx * wander[w + 1]);\n const y = restY + jitter * (cy * wander[w + 2] - sy * wander[w + 3]);\n const angle = turn[k * 2];\n const step = Math.min(MAX_WEIGHT_STEP, Math.round(turn[k * 2 + 1] * WEIGHT_STEPS));\n if (angle === 0) {\n add(weights[step], x, y, size, 0);\n } else {\n // Angles stay within ±45°, where these short series are exact to ~1e-6.\n const a2 = angle * angle;\n const cos = 1 - a2 * (0.5 - a2 * (1 / 24 - a2 * (1 / 720 - a2 / 40320)));\n const sin = angle * (1 - a2 * (1 / 6 - a2 * (1 / 120 - a2 / 5040)));\n add(weights[step], x, y, size * cos, size * sin);\n }\n }\n }\n\n ctx.globalAlpha = options.opacity;\n ctx.strokeStyle = options.color;\n ctx.lineCap = 'round';\n for (let step = 0; step <= MAX_WEIGHT_STEP; step++) {\n if (weights[step].length > 0) {\n stroke(weights[step], options.weight * (1 + (options.waveWeight * step) / WEIGHT_STEPS));\n }\n }\n return waves.waves.length > 0 || turns.settling;\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { wanderIdleFps } from '../../shared/grid';\nimport { plusDefaults, type PlusOptions } from './options';\n\n/**\n * A grid of \"+\" signs that wander gently around their places. While the\n * pointer is over the background, every sign turns smoothly so an arm points\n * at it. Clicks send out a wave that turns the signs on its crest to face the\n * click and makes them heavier as it passes.\n */\nexport const plusStyle: StyleBase<PlusOptions> = {\n name: 'plus',\n defaults: plusDefaults,\n animates: (options) => options.jitter > 0 && options.jitterSpeed > 0,\n // Same slow, sub-pixel wander as dots: it rarely needs the engine's full idle frame rate.\n idleFps: wanderIdleFps,\n};\n","import { parseColor } from '../../core/color';\nimport type { StyleRenderer } from '../../core/style';\nimport { createProgram, getUniforms } from '../../core/webgl';\nimport { createWaveList, gridLayout, TAU } from '../../shared/grid';\nimport { GRID_UNIFORMS, GRID_VERTEX_GLSL, setGridUniforms } from '../../shared/grid-webgl';\nimport { resolvePlusOptions, wavesEnabled, type PlusOptions } from './options';\nimport { createSignTurns } from './turns';\n\n// Wander mirrors canvas2d.ts; each sign's angle and wave height come from SignTurns (aTurn).\nconst VERTEX = `#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 aTurn; // angle (radians), wave-crest height\n\n${GRID_VERTEX_GLSL}\nuniform float uSize; // arm length, CSS px\nuniform float uWeight; // stroke weight, CSS px\nuniform float uWaveWeight;\n\nout vec2 vAxis; // cos, sin of the sign's angle\nout float vArm; // device px\nout float vHalfWeight; // device px\nout float vPointSize; // device px\n\nvoid main() {\n vec2 ij = markCell();\n vec2 p = restPosition(ij) + wander(ij);\n\n vAxis = vec2(cos(aTurn.x), sin(aTurn.x));\n vArm = uSize * uDpr;\n vHalfWeight = 0.5 * uWeight * (1.0 + uWaveWeight * min(aTurn.y, 2.0)) * uDpr;\n vPointSize = 2.0 * (vArm + vHalfWeight) + 2.0; // room for the antialiased edge\n gl_PointSize = vPointSize;\n gl_Position = toClip(p);\n}`;\n\nconst FRAGMENT = `#version 300 es\nprecision highp float;\n\nuniform vec4 uColor; // straight RGBA, opacity applied\nin vec2 vAxis;\nin float vArm;\nin float vHalfWeight;\nin float vPointSize;\nout vec4 outColor;\n\n// Distance to a round-capped arm of half-length vArm along x.\nfloat arm(vec2 q) {\n return length(vec2(max(abs(q.x) - vArm, 0.0), q.y)) - vHalfWeight;\n}\n\nvoid main() {\n vec2 p = (gl_PointCoord - 0.5) * vPointSize;\n vec2 q = vec2(dot(p, vAxis), dot(p, vec2(-vAxis.y, vAxis.x))); // into the sign's frame\n float d = min(arm(q), arm(q.yx));\n float a = uColor.a * clamp(0.5 - d, 0.0, 1.0);\n outColor = vec4(uColor.rgb * a, a); // premultiplied; the engine blends it over the background\n}`;\n\nconst UNIFORMS = [...GRID_UNIFORMS, 'uSize', 'uWeight', 'uWaveWeight', 'uColor'] as const;\n\n/**\n * Every sign is one GL point: the vertex shader places it and the fragment\n * shader draws the cross. Angles are eased on the CPU (SignTurns) and uploaded\n * only on frames where they changed.\n */\nexport function createPlusWebGL(gl: WebGL2RenderingContext, initial: PlusOptions): StyleRenderer<PlusOptions> {\n let options = resolvePlusOptions(initial);\n const waves = createWaveList();\n const turns = createSignTurns();\n let clock = 0;\n let uploaded = -1; // sign count the buffer was last sized for\n\n const program = createProgram(gl, VERTEX, FRAGMENT);\n const uniforms = program ? getUniforms(gl, program, UNIFORMS) : null;\n const vao = gl.createVertexArray();\n const buffer = gl.createBuffer();\n gl.bindVertexArray(vao);\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n gl.bindVertexArray(null);\n\n return {\n update(next) {\n options = resolvePlusOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, wavesEnabled(options));\n const grid = gridLayout(frame.width, frame.height, options.spacing);\n turns.update(frame, options, grid, waves.waves);\n const busy = waves.waves.length > 0 || turns.settling;\n if (!program || !uniforms) return busy; // context lost during setup\n\n const count = grid.cols * grid.rows;\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n if (uploaded !== count) {\n gl.bufferData(gl.ARRAY_BUFFER, turns.data, gl.DYNAMIC_DRAW);\n uploaded = count;\n } else if (turns.changed) {\n gl.bufferSubData(gl.ARRAY_BUFFER, 0, turns.data);\n }\n\n const color = parseColor(options.color);\n gl.useProgram(program);\n setGridUniforms(gl, uniforms, grid, frame, options.spacing, clock, options.jitter);\n gl.uniform1f(uniforms.uSize, options.size);\n gl.uniform1f(uniforms.uWeight, options.weight);\n gl.uniform1f(uniforms.uWaveWeight, options.waveWeight);\n gl.uniform4f(uniforms.uColor, color[0], color[1], color[2], color[3] * options.opacity);\n gl.bindVertexArray(vao);\n gl.drawArrays(gl.POINTS, 0, count);\n gl.bindVertexArray(null);\n return busy;\n },\n destroy() {\n gl.deleteProgram(program);\n gl.deleteBuffer(buffer);\n gl.deleteVertexArray(vao);\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createPlusCanvas2D } from '../styles/plus/canvas2d';\nimport { plusStyle } from '../styles/plus/definition';\nimport type { PlusOptions } from '../styles/plus/options';\nimport { createPlusWebGL } from '../styles/plus/webgl';\n\nexport type { PlusOptions };\n\n/** A grid of \"+\" signs, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const plus: StyleFactory<PlusOptions> = defineStyle({\n ...plusStyle,\n renderers: [webglRenderer(createPlusWebGL), canvas2dRenderer(createPlusCanvas2D)],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","names":["FRAGMENT","UNIFORMS","TAU","TAU","TAU","VERTEX","FRAGMENT","UNIFORMS","TAU","TAU","VERTEX","FRAGMENT","UNIFORMS","TAU","clamp","clamp","TAU","TAU","factory","global","exports","fades","fade","createSurface","ordered","preference","renderers","r","k","renderer","replaceCanvas","surface","canvas","options","invalidate","engineDefaults","createBackground","host","target","definition","style","engine","engineOptions","backgroundColor","resolveColor","resolveFade","ownsCanvas","hostPosition","mountCanvas","wake","fresh","blankSurface","width","height","dpr","pointerX","pointerY","targetX","targetY","influence","targetInfluence","clicks","frameClicks","pointer","frameState","styleBusy","lastFrame","rafId","timerId","paused","visible","intersecting","destroyed","needsDraw","reducedMotionQuery","reducedMotion","holdStill","animating","busy","pointerEasing","effectiveIdleFps","configured","needed","frameInterval","fps","canRun","resize","rect","nextWidth","nextHeight","nextDpr","frame","minInterval","now","schedule","dt","wasBusy","ease","moving","delay","onTimer","cancel","onPointerMove","x","event","y","inside","onPointerDown","onPointerLeave","onVisibilityChange","onReducedMotionChange","dprQuery","watchDpr","onDprChange","resizeObserver","intersectionObserver","entries","next","previous","needs","color","SIDES","canvas2dRenderer","ctx","createRenderer","gradients","fadeSide","size","side","cache","length","x0","y0","x1","y1","strip","fading","defineStyle","TRANSPARENT","probe","parseColor","cached","g","b","rgba","FULLSCREEN_VERTEX_SHADER","createProgram","program","gl","vertex","fragment","compile","vertexSource","fragmentSource","error","getUniforms","names","name","shader","type","source","log","WEBGL_ATTRIBUTES","FADE_FRAGMENT","webglRenderer","initial","fadePass","onLost","fadeEdges","uniforms","a","background","onRestored","createFloatBuffer","capacity","reserve","buffer","count","grown","traceContours","j","rows","cellSize","i","cols","idx","field","c","d","min","max","first","step","last","level","code","topX","frac","rightY","bottomX","leftY","emit","centreAbove","to","from","t","topoDefaults","resolveTopoOptions","F3","G3","GRAD3","mulberry32","seed","createNoise3D","random","p","tmp","perm","permMod12","s","z","z0","i1","j1","k1","i2","j2","k2","z1","x2","y2","z2","x3","y3","z3","ii","jj","kk","n","KEY_DT","createKeyframeField","params","noise","norm","keyA","keyB","keyNext","keyTime","keyNextRows","valid","version","allocate","nextCols","nextRows","sampleRows","fromRow","toRow","value","o","amp","freq","scale","octaves","prev","time","progress","wanted","createTerrain","speed","createTopoCanvas2D","terrain","minor","major","collectSegment","data","stroke","lineWidth","sampleField","blend","bump","radius2","pointerRadius","reach","i0","j0","dy","dx","topoStyle","FRAGMENT$3","UNIFORMS$3","createTopoWebGL","textures","texture","textureCols","textureRows","uploadedVersion","upload","resized","keys","unit","opacity","topo","TAU$3","gridLayout","spacing","cellPhase","salt","createPhaseCache","phases","phaseCols","px","py","wanderClock","clock","pointerFalloff","distance","radius","waveRing","ringRadius","waveEnvelope","age","duration","WANDER_STEP","wanderFps","maxSpeed","jitter","jitterSpeed","wanderIdleFps","createWaveList","waves","wave","enabled","click","out","WAVE_GROW","dotsDefaults","resolveDotsOptions","SIZE_STEPS","MAX_SIZE_STEP","createDotsCanvas2D","waveData","sizes","add","phasesFor","wander","push","waveCount","waveReach","waveWidth","restY","originY","restX","originX","sx","cx","cy","sy","amount","grow","w","outer","ring","waveStrength","dotsStyle","GRID_UNIFORMS","GRID_VERTEX_GLSL","setGridUniforms","grid","VERTEX$2","FRAGMENT$2","UNIFORMS$2","createDotsWebGL","dots","plusDefaults","resolvePlusOptions","wavesEnabled","atanUnit","r2","facingAngle","ax","QUARTER","SETTLED_PX","wrap","angle","createSignTurns","packWaves","changed","settling","lastX","lastY","lastAlign","lastOriginX","lastOriginY","lastOptions","hadWaves","align","unchanged","waveSpeed","waveDuration","settled","waveAlign","remaining","WEIGHT_STEPS","MAX_WEIGHT_STEP","createPlusCanvas2D","turns","weights","weight","turn","a2","cos","sin","plusStyle","VERTEX$1","FRAGMENT$1","UNIFORMS$1","createPlusWebGL","uploaded","vao","plus","hslToRgb","l","q","channel","h","splatColor","fluidDefaults","clamp$2","resolveFluidOptions","DYE_INTENSITY","VELOCITY_FADE","PRESSURE_RETENTION","BURST_FORCE","BURST_RADIUS","BURST_DYE","IDLE_DECAY","IDLE_CLEAR","MAX_DYE_RESOLUTION","clamp$1","createFluidSimulation","cells","u","v","uNext","vNext","dyeR","dyeG","dyeB","dyeRNext","dyeGNext","dyeBNext","divergence","curl","pressure","pressureNext","sample","gx","gy","fx","fy","top","bottom","walls","addCurl","forceX","forceY","strength","project","iteration","advectVelocity","decay","advectDye","aspect","viewWidth","viewHeight","sigma","reachX","reachY","velocityX","vx","velocityY","vy","sigma2","falloff","stepTime","simulationSize","long","resolution","TAU$2","createFluidCanvas2D","sim","image","targetCtx","builtWidth","builtHeight","builtResolution","active","idleTime","wasInside","burstPending","splatAt","colour","burst","dye","draw","density","moveX","moveY","clickPoint","effective","fluidStyle","TAU$1","VERTEX","SPLAT","ADVECTION","DIVERGENCE","CURL","VORTICITY","PRESSURE","GRADIENT","CLEAR","DISPLAY","createFluidWebGL","makePass","splatPass","advectionPass","divergencePass","curlPass","vorticityPass","pressurePass","gradientPass","clearPass","displayPass","createFBO","framebuffer","createDoubleFBO","pair","deleteFBO","simWidth","simHeight","dyeWidth","dyeHeight","velocity","dyeGrid","pass","splatVelocity","pointX","pointY","splatDye","radiusPx","idleBoost","mountSize","clearField","fbo","drawDye","fluid","TIME_RATE","COLOR_MIX","TAU","HALF_PI","LUT_SIZE","SIN_LUT","fastSin","f","fastCos","renderShimmer","frequency","colorScale","warp","chroma","distort","offset","su","sv","lens","pr","pg","pb","red","base","green","blue","shimmerDefaults","clamp","resolveShimmerOptions","fieldSize","CPU_FPS","createShimmerCanvas2D","accumulator","hasFrame","fieldWidth","fieldHeight","baseR","baseG","baseB","shimmerStyle","FRAGMENT","UNIFORMS","createShimmerWebGL","shimmer"],"sources":["../src/core/surface.ts","../src/core/engine.ts","../src/core/canvas2d-renderer.ts","../src/core/style.ts","../src/core/color.ts","../src/core/webgl.ts","../src/core/webgl-renderer.ts","../src/shared/buffer.ts","../src/styles/topo/contours.ts","../src/styles/topo/options.ts","../src/shared/noise.ts","../src/styles/topo/field.ts","../src/styles/topo/terrain.ts","../src/styles/topo/canvas2d.ts","../src/styles/topo/definition.ts","../src/styles/topo/webgl.ts","../src/topo/index.ts","../src/shared/grid.ts","../src/styles/dots/motion.ts","../src/styles/dots/options.ts","../src/styles/dots/canvas2d.ts","../src/styles/dots/definition.ts","../src/shared/grid-webgl.ts","../src/styles/dots/webgl.ts","../src/dots/index.ts","../src/styles/plus/options.ts","../src/styles/plus/motion.ts","../src/styles/plus/turns.ts","../src/styles/plus/canvas2d.ts","../src/styles/plus/definition.ts","../src/styles/plus/webgl.ts","../src/plus/index.ts","../src/styles/fluid/color.ts","../src/styles/fluid/options.ts","../src/styles/fluid/settings.ts","../src/styles/fluid/simulation.ts","../src/styles/fluid/size.ts","../src/styles/fluid/canvas2d.ts","../src/styles/fluid/definition.ts","../src/styles/fluid/webgl.ts","../src/fluid/index.ts","../src/styles/shimmer/field.ts","../src/styles/shimmer/options.ts","../src/styles/shimmer/canvas2d.ts","../src/styles/shimmer/definition.ts","../src/styles/shimmer/webgl.ts","../src/shimmer/index.ts"],"sourcesContent":["import type { Frame, RendererName } from './style';\n\n/** How far in from each edge the style's drawing fades out, in CSS pixels. `0` = no fade on that side. */\nexport interface Fade {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\n/** Whether any side fades. */\nexport function fades(fade: Fade): boolean {\n return fade.top > 0 || fade.right > 0 || fade.bottom > 0 || fade.left > 0;\n}\n\n/** A canvas context plus the style renderer drawing into it. */\nexport interface Surface<O> {\n readonly name: RendererName;\n update(options: O): void;\n /**\n * Clear to `backgroundColor` (`null` = transparent) and let the style draw, then fade the\n * style's drawing out towards the edges as `fade` says, keeping the background colour solid.\n * Fades on several sides multiply. Returns `true` while the style has a short-lived effect playing.\n */\n render(frame: Frame, backgroundColor: string | null, fade: Fade): boolean;\n /** Leave the canvas blank. */\n clear(): void;\n destroy(): void;\n}\n\n/**\n * One way to draw a style: a kind of canvas context plus the style's renderer\n * for it. Made with `webglRenderer()` or `canvas2dRenderer()`, each in its own\n * module, so a style only bundles the backends it lists.\n */\nexport interface Renderer<O> {\n readonly name: RendererName;\n /** Set up on `canvas`, or return `null` if this kind of context isn't available. */\n create(canvas: HTMLCanvasElement, options: O, invalidate: () => void): Surface<O> | null;\n}\n\n/**\n * Set up the first renderer that works here, trying them in the style's order,\n * with `preference` (if the style has it) first. `null` if none works.\n *\n * A canvas keeps the first kind of context it hands out, so after a renderer\n * fails, `replaceCanvas` (if given) swaps in a fresh canvas for the next one.\n */\nexport function createSurface<O>(\n canvas: () => HTMLCanvasElement,\n renderers: readonly Renderer<O>[],\n options: O,\n preference: 'auto' | RendererName,\n invalidate: () => void,\n replaceCanvas?: () => void,\n): Surface<O> | null {\n const ordered =\n preference === 'auto'\n ? renderers\n : [...renderers.filter((r) => r.name === preference), ...renderers.filter((r) => r.name !== preference)];\n for (const [k, renderer] of ordered.entries()) {\n if (k > 0) replaceCanvas?.();\n const surface = renderer.create(canvas(), options, invalidate);\n if (surface) return surface;\n }\n return null;\n}\n","import type { Frame, Point, RendererName, Style, StyleDefinition } from './style';\nimport { createSurface, type Fade, type Surface } from './surface';\n\n/** Options shared by every style: how and when the background is rendered. */\nexport interface EngineOptions {\n /**\n * Rendering backend, chosen when the background is created (changing it later has no effect).\n * `'auto'` uses the style's renderers in their own order (WebGL2 first for the built-in styles)\n * and falls back to the next when the browser lacks one. Naming one tries it first.\n */\n renderer: 'auto' | RendererName;\n /** Fill colour painted behind the style. `null` or `'transparent'` keeps the canvas transparent. */\n backgroundColor: string | null;\n /**\n * Fade the pattern out towards the top edge over this many CSS pixels: from its own opacity\n * this far in from the edge to fully transparent at the edge. The background colour isn't\n * faded. `0` = no fade. Fades on several sides multiply where they overlap.\n */\n fadeOutTop: number;\n /** Like `fadeOutTop`, towards the right edge. */\n fadeOutRight: number;\n /** Like `fadeOutTop`, towards the bottom edge. */\n fadeOutBottom: number;\n /** Like `fadeOutTop`, towards the left edge. */\n fadeOutLeft: number;\n /** React to the pointer and to clicks / taps. */\n interactive: boolean;\n /**\n * Upper limit for the canvas pixel density. Canvas memory grows with its square:\n * a 1920×1080 canvas takes 8 MB at 1, 18 MB at 1.5 and 32 MB at 2.\n */\n maxDpr: number;\n /** Frame-rate cap while the pointer is moving the background. `0` = uncapped. */\n maxFps: number;\n /** Frame-rate cap while only the style's own animation runs. Lower saves CPU and battery. `0` = same as `maxFps`. */\n idleFps: number;\n /** Hold the style's own animation still when the user prefers reduced motion. */\n respectReducedMotion: boolean;\n}\n\nexport const engineDefaults: Readonly<EngineOptions> = Object.freeze({\n renderer: 'auto',\n backgroundColor: null,\n fadeOutTop: 0,\n fadeOutRight: 0,\n fadeOutBottom: 0,\n fadeOutLeft: 0,\n interactive: true,\n maxDpr: 1.5,\n maxFps: 60,\n idleFps: 30,\n respectReducedMotion: true,\n});\n\nexport interface Background<O extends object> {\n readonly canvas: HTMLCanvasElement;\n /** Name of the style, e.g. `'topo'`. */\n readonly style: string;\n /**\n * The rendering backend actually in use, or `null` when none of the style's renderers works in\n * this browser (e.g. a WebGL-only style without WebGL2): the background then stays blank.\n */\n readonly renderer: RendererName | null;\n readonly options: Readonly<O>;\n readonly engineOptions: Readonly<EngineOptions>;\n /** Update any of the style's options on the fly. */\n setOptions(options: Partial<O>): void;\n /** Update any engine options on the fly (except `renderer`). */\n setEngineOptions(options: Partial<EngineOptions>): void;\n pause(): void;\n resume(): void;\n /** Stop rendering, remove listeners and (if it was created by us) the canvas. */\n destroy(): void;\n}\n\n/**\n * Mount an interactive background.\n *\n * - `target` `null`/omitted: a fixed, full-viewport canvas is placed behind the page.\n * - `target` is a `<canvas>`: it is drawn into directly and sized by your CSS.\n * - `target` is any other element (or a selector): a canvas is appended that\n * fills it. The element gets `position: relative` if it was `static`.\n *\n * @example createBackground('#hero', topo({ levels: 14 }), { maxFps: 30 })\n */\nexport function createBackground<O extends object>(\n target: HTMLElement | string | null | undefined,\n style: Style<O>,\n engineOptions: Partial<EngineOptions> = {},\n): Background<O> {\n const host = typeof target === 'string' ? document.querySelector<HTMLElement>(target) : target;\n if (typeof target === 'string' && !host) {\n throw new Error(`interactive-bg: no element matches \"${target}\"`);\n }\n\n const definition = style.definition;\n let options: O = { ...style.options };\n let engine: EngineOptions = { ...engineDefaults, ...engineOptions };\n let backgroundColor = resolveColor(engine.backgroundColor);\n let fade = resolveFade(engine);\n\n const ownsCanvas = !(host instanceof HTMLCanvasElement);\n // We may switch the host to `position: relative`; remember what to restore on destroy().\n const hostPosition = ownsCanvas && host ? host.style.position : null;\n let canvas = ownsCanvas ? mountCanvas(host ?? null) : (host as HTMLCanvasElement);\n const surface =\n createSurface(\n () => canvas,\n definition.renderers,\n options,\n engine.renderer,\n () => {\n needsDraw = true;\n wake();\n },\n // A renderer that failed may have claimed the canvas's context; the next one needs a fresh canvas.\n ownsCanvas\n ? () => {\n const fresh = mountCanvas(host ?? null);\n canvas.remove();\n canvas = fresh;\n }\n : undefined,\n ) ?? blankSurface(definition);\n\n // Canvas size in CSS pixels, and the pixel density it is rendered at.\n let width = 0;\n let height = 0;\n let dpr = 1;\n\n // Pointer state: `target*` is where the pointer is, the rest eases toward it.\n let pointerX = 0;\n let pointerY = 0;\n let targetX = 0;\n let targetY = 0;\n let influence = 0;\n let targetInfluence = 0;\n /** Clicks since the last rendered frame, and the array handed to the style for the current one (swapped each frame). */\n let clicks: Point[] = [];\n let frameClicks: Point[] = [];\n // Reused for every frame: styles only read them during render().\n const pointer = { x: 0, y: 0, influence: 0 };\n const frameState: Frame = { width: 0, height: 0, dpr: 1, dt: 0, reducedMotion: false, pointer, clicks: frameClicks };\n /** The style reported a short-lived effect still playing in its last frame. */\n let styleBusy = false;\n\n let lastFrame = 0;\n let rafId = 0;\n let timerId = 0;\n let paused = false;\n let visible = true;\n let intersecting = true;\n let destroyed = false;\n let needsDraw = true;\n\n const reducedMotionQuery = window.matchMedia?.('(prefers-reduced-motion: reduce)');\n let reducedMotion = reducedMotionQuery?.matches ?? false;\n\n function holdStill(): boolean {\n return engine.respectReducedMotion && reducedMotion;\n }\n\n /** Is the style's own ambient animation running (as opposed to only reacting to the pointer)? */\n function animating(): boolean {\n return surface.name !== null && definition.animates(options) && !holdStill();\n }\n\n /** Does something need the full frame rate: the pointer's effect easing, or a style effect playing? */\n function busy(): boolean {\n return styleBusy || clicks.length > 0 || pointerEasing();\n }\n\n /** Frame rate for the ambient animation; `0` means uncapped for the engine options. */\n function effectiveIdleFps(): number {\n const configured =\n engine.maxFps <= 0\n ? engine.idleFps\n : engine.idleFps <= 0\n ? engine.maxFps\n : Math.min(engine.maxFps, engine.idleFps);\n const needed = definition.idleFps?.(options) ?? 0;\n if (needed <= 0) return configured;\n return configured <= 0 ? needed : Math.min(configured, needed);\n }\n\n function frameInterval(fps: number): number {\n return fps > 0 ? 1000 / fps : 0;\n }\n\n function canRun(): boolean {\n return !destroyed && !paused && visible;\n }\n\n /** Is the pointer's effect still catching up with the pointer? */\n function pointerEasing(): boolean {\n if (influence !== targetInfluence) return true;\n return influence > 0 && (Math.abs(targetX - pointerX) > 0.5 || Math.abs(targetY - pointerY) > 0.5);\n }\n\n function resize(): void {\n const rect = canvas.getBoundingClientRect();\n const nextWidth = Math.max(1, Math.round(rect.width));\n const nextHeight = Math.max(1, Math.round(rect.height));\n const nextDpr = Math.min(window.devicePixelRatio || 1, Math.max(0.5, engine.maxDpr));\n if (nextWidth === width && nextHeight === height && nextDpr === dpr) return;\n width = nextWidth;\n height = nextHeight;\n dpr = nextDpr;\n canvas.width = Math.round(width * dpr);\n canvas.height = Math.round(height * dpr);\n needsDraw = true;\n }\n\n function frame(now: number): void {\n rafId = 0;\n if (!canRun()) return;\n\n // Full frame rate only while reacting to the pointer or playing an effect.\n const minInterval = frameInterval(busy() ? engine.maxFps : effectiveIdleFps());\n // 15% tolerance so a 60 fps cap doesn't drop frames on 60 Hz displays.\n if (lastFrame && now - lastFrame < minInterval * 0.85) {\n schedule(minInterval - (now - lastFrame));\n return;\n }\n const dt = lastFrame ? Math.min((now - lastFrame) / 1000, 0.1) : 0;\n lastFrame = now;\n\n const wasBusy = busy();\n // Frame-rate independent easing.\n const ease = 1 - Math.exp(-dt * 8);\n pointerX += (targetX - pointerX) * ease;\n pointerY += (targetY - pointerY) * ease;\n influence += (targetInfluence - influence) * ease;\n if (Math.abs(targetInfluence - influence) < 0.001) influence = targetInfluence;\n\n const moving = animating();\n if (moving || wasBusy || needsDraw) {\n needsDraw = false;\n [frameClicks, clicks] = [clicks, frameClicks];\n clicks.length = 0;\n pointer.x = pointerX;\n pointer.y = pointerY;\n pointer.influence = influence;\n frameState.width = width;\n frameState.height = height;\n frameState.dpr = dpr;\n frameState.dt = dt;\n frameState.reducedMotion = holdStill();\n frameState.clicks = frameClicks;\n styleBusy = surface.render(frameState, backgroundColor, fade);\n }\n\n // Nothing left to animate: stop until a pointer move, click, resize or option change wakes us.\n if (busy()) schedule();\n else if (moving) schedule(frameInterval(effectiveIdleFps()));\n else lastFrame = 0;\n }\n\n /** Request a frame `delay` ms from now. */\n function schedule(delay = 0): void {\n if (rafId || timerId || !canRun()) return;\n // requestAnimationFrame alone wakes up on every display refresh (up to 120–165 Hz),\n // so sleep through longer gaps with a timer and only then wait for the next frame.\n // The timer wakes slightly early so the next frame lands within frame()'s tolerance.\n if (delay > 8) {\n timerId = window.setTimeout(onTimer, delay * 0.8);\n } else {\n rafId = requestAnimationFrame(frame);\n }\n }\n\n function onTimer(): void {\n timerId = 0;\n schedule();\n }\n\n /** Render as soon as possible, cutting short any idle sleep. */\n function wake(): void {\n if (timerId) clearTimeout(timerId);\n timerId = 0;\n schedule();\n }\n\n function cancel(): void {\n if (rafId) cancelAnimationFrame(rafId);\n if (timerId) clearTimeout(timerId);\n rafId = timerId = 0;\n }\n\n function onPointerMove(event: PointerEvent): void {\n if (!engine.interactive || !canRun()) return;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const inside = x >= 0 && y >= 0 && x <= rect.width && y <= rect.height;\n if (inside && targetInfluence === 0) {\n // Entering: start where the pointer is instead of sliding in.\n pointerX = x;\n pointerY = y;\n }\n targetX = x;\n targetY = y;\n targetInfluence = inside ? 1 : 0;\n if (inside || influence > 0) wake();\n }\n\n function onPointerDown(event: PointerEvent): void {\n if (!engine.interactive || !canRun()) return;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n if (x < 0 || y < 0 || x > rect.width || y > rect.height) return;\n clicks.push({ x, y });\n wake();\n }\n\n function onPointerLeave(): void {\n targetInfluence = 0;\n wake();\n }\n\n function onVisibilityChange(): void {\n visible = document.visibilityState === 'visible' && intersecting;\n lastFrame = 0;\n if (visible) wake();\n else cancel();\n }\n\n function onReducedMotionChange(event: MediaQueryListEvent): void {\n reducedMotion = event.matches;\n needsDraw = true;\n wake();\n }\n\n // ResizeObserver doesn't fire when only the pixel density changes (e.g. the window moves to\n // another screen), so watch the current density with a media query, re-armed after each change.\n let dprQuery: MediaQueryList | null = null;\n function watchDpr(): void {\n dprQuery?.removeEventListener?.('change', onDprChange);\n dprQuery = window.matchMedia?.(`(resolution: ${window.devicePixelRatio || 1}dppx)`) ?? null;\n dprQuery?.addEventListener?.('change', onDprChange);\n }\n function onDprChange(): void {\n resize();\n wake();\n watchDpr();\n }\n watchDpr();\n\n const resizeObserver = new ResizeObserver(() => {\n resize();\n wake();\n });\n resizeObserver.observe(canvas);\n\n const intersectionObserver =\n typeof IntersectionObserver === 'function'\n ? new IntersectionObserver((entries) => {\n intersecting = entries[entries.length - 1].isIntersecting;\n onVisibilityChange();\n })\n : null;\n intersectionObserver?.observe(canvas);\n\n window.addEventListener('pointermove', onPointerMove, { passive: true });\n window.addEventListener('pointerdown', onPointerDown, { passive: true });\n document.documentElement.addEventListener('pointerleave', onPointerLeave);\n document.addEventListener('visibilitychange', onVisibilityChange);\n reducedMotionQuery?.addEventListener?.('change', onReducedMotionChange);\n\n resize();\n schedule();\n\n return {\n canvas,\n style: definition.name,\n renderer: surface.name,\n get options() {\n return options;\n },\n get engineOptions() {\n return engine;\n },\n setOptions(next) {\n options = { ...options, ...next };\n surface.update(options);\n needsDraw = true;\n wake();\n },\n setEngineOptions(next) {\n const previous = engine;\n engine = { ...engine, ...next };\n backgroundColor = resolveColor(engine.backgroundColor);\n fade = resolveFade(engine);\n if (engine.maxDpr !== previous.maxDpr) resize();\n if (!engine.interactive) {\n influence = targetInfluence = 0;\n clicks.length = 0;\n }\n needsDraw = true;\n wake();\n },\n pause() {\n paused = true;\n cancel();\n },\n resume() {\n paused = false;\n lastFrame = 0;\n wake();\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n cancel();\n resizeObserver.disconnect();\n intersectionObserver?.disconnect();\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerdown', onPointerDown);\n document.documentElement.removeEventListener('pointerleave', onPointerLeave);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n reducedMotionQuery?.removeEventListener?.('change', onReducedMotionChange);\n dprQuery?.removeEventListener?.('change', onDprChange);\n if (!ownsCanvas) surface.clear();\n surface.destroy();\n if (ownsCanvas) {\n // Free the GPU context now rather than at garbage collection: browsers cap live WebGL contexts.\n if (surface.name === 'webgl') canvas.getContext('webgl2')?.getExtension('WEBGL_lose_context')?.loseContext();\n canvas.remove();\n if (host && hostPosition !== null) host.style.position = hostPosition;\n }\n },\n };\n}\n\n/** Stands in when none of the style's renderers works here: draws nothing, and says so once. */\nfunction blankSurface<O extends object>(definition: StyleDefinition<O>): Omit<Surface<O>, 'name'> & { name: null } {\n const needs = definition.renderers.map((r) => (r.name === 'webgl' ? 'WebGL2' : 'Canvas 2D')).join(' or ');\n console.warn(`interactive-bg: style \"${definition.name}\" needs ${needs}, which this browser doesn't provide`);\n return { name: null, update() {}, render: () => false, clear() {}, destroy() {} };\n}\n\nfunction resolveFade(engine: EngineOptions): Fade {\n return {\n top: Math.max(0, engine.fadeOutTop),\n right: Math.max(0, engine.fadeOutRight),\n bottom: Math.max(0, engine.fadeOutBottom),\n left: Math.max(0, engine.fadeOutLeft),\n };\n}\n\nfunction resolveColor(color: string | null): string | null {\n return color && color !== 'transparent' ? color : null;\n}\n\n/** Create the background canvas inside `host`, or fixed behind the page when there is no host. */\nfunction mountCanvas(host: HTMLElement | null): HTMLCanvasElement {\n const canvas = document.createElement('canvas');\n canvas.setAttribute('aria-hidden', 'true');\n Object.assign(canvas.style, {\n position: host ? 'absolute' : 'fixed',\n inset: '0',\n width: '100%',\n height: '100%',\n display: 'block',\n pointerEvents: 'none',\n zIndex: host ? '0' : '-1',\n });\n if (host) {\n if (getComputedStyle(host).position === 'static') host.style.position = 'relative';\n host.prepend(canvas);\n } else {\n document.body.prepend(canvas);\n }\n return canvas;\n}\n","import type { StyleRenderer } from './style';\nimport { fades, type Fade, type Renderer } from './surface';\n\nconst SIDES: readonly (keyof Fade)[] = ['top', 'right', 'bottom', 'left'];\n\n/**\n * Draw a style with Canvas 2D. The engine clears to the background colour and\n * sets the transform so the style draws in CSS pixels.\n */\nexport function canvas2dRenderer<O>(\n createRenderer: (ctx: CanvasRenderingContext2D, options: O) => StyleRenderer<O>,\n): Renderer<O> {\n return {\n name: 'canvas2d',\n create(canvas, options) {\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n const renderer = createRenderer(ctx, options);\n\n // One gradient per side, kept while the canvas size and fade length stay the same.\n const gradients: { gradient: CanvasGradient | null; size: number; length: number }[] = SIDES.map(() => ({\n gradient: null,\n size: 0,\n length: 0,\n }));\n\n /**\n * Erase the style's drawing gradually along one side: nothing `length` px in from the edge,\n * all of it at the edge. Erasing multiplies, so overlapping sides combine.\n */\n const fadeSide = (side: number, length: number, width: number, height: number): void => {\n const horizontal = side === 1 || side === 3; // right, left\n const size = horizontal ? width : height;\n const cache = gradients[side];\n if (!cache.gradient || cache.size !== size || cache.length !== length) {\n // From the inner end of the strip to the edge.\n const [x0, y0, x1, y1] = [\n [0, length, 0, 0], // top\n [width - length, 0, width, 0], // right\n [0, height - length, 0, height], // bottom\n [length, 0, 0, 0], // left\n ][side];\n cache.gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n cache.gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');\n cache.gradient.addColorStop(1, 'rgba(0, 0, 0, 1)');\n cache.size = size;\n cache.length = length;\n }\n const strip = Math.min(length, size);\n ctx.fillStyle = cache.gradient;\n if (side === 0) ctx.fillRect(0, 0, width, strip);\n else if (side === 1) ctx.fillRect(width - strip, 0, strip, height);\n else if (side === 2) ctx.fillRect(0, height - strip, width, strip);\n else ctx.fillRect(0, 0, strip, height);\n };\n\n return {\n name: 'canvas2d',\n update(next) {\n renderer.update(next);\n },\n render(frame, backgroundColor, fade) {\n const { width, height, dpr } = frame;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.globalAlpha = 1;\n ctx.globalCompositeOperation = 'source-over';\n ctx.clearRect(0, 0, width, height);\n // With a fade, the background goes in last, behind the faded drawing, so it stays solid.\n const fading = fades(fade);\n if (backgroundColor && !fading) {\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, width, height);\n }\n const busy = renderer.render(frame) === true;\n if (fading) {\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.globalAlpha = 1;\n ctx.globalCompositeOperation = 'destination-out';\n for (let side = 0; side < SIDES.length; side++) {\n const length = fade[SIDES[side]];\n if (length > 0) fadeSide(side, length, width, height);\n }\n if (backgroundColor) {\n ctx.globalCompositeOperation = 'destination-over';\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, width, height);\n }\n ctx.globalCompositeOperation = 'source-over';\n }\n return busy;\n },\n clear() {\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n },\n destroy() {\n renderer.destroy?.();\n },\n };\n },\n };\n}\n","import type { Renderer } from './surface';\n\nexport type RendererName = 'webgl' | 'canvas2d';\n\n/** A position in CSS pixels relative to the canvas. */\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** The pointer as a style sees it. */\nexport interface Pointer extends Point {\n /** Eases from 0 to 1 while the pointer is over the canvas, and back when it leaves. Always 0 when not interactive. */\n influence: number;\n}\n\n/** What a style gets for each frame. The engine reuses this object: read it during `render()`, don't keep it. */\nexport interface Frame {\n /** Canvas size in CSS pixels. */\n width: number;\n height: number;\n /** Pixel density the canvas is rendered at. */\n dpr: number;\n /** Seconds since the previous frame (`0` on the first frame after a pause). */\n dt: number;\n /**\n * The user prefers reduced motion (and `respectReducedMotion` is on): hold the\n * style's own ambient animation still. Reactions to the pointer and clicks may still play.\n */\n reducedMotion: boolean;\n pointer: Pointer;\n /** Clicks / taps on the canvas since the previous frame. Empty when not interactive. */\n clicks: readonly Point[];\n}\n\n/**\n * Draws one style into a canvas. The engine has already cleared the canvas, and\n * takes care of the background colour and the edge fades, so just draw the pattern:\n * - Canvas 2D: the transform is set so you draw in CSS pixels.\n * - WebGL: the viewport covers the canvas, and blending is set up for premultiplied alpha\n * (`ONE, ONE_MINUS_SRC_ALPHA`), so output premultiplied colour.\n */\nexport interface StyleRenderer<O> {\n /** The style's options changed. */\n update(options: O): void;\n /**\n * Draw one frame. Return `true` while a short-lived effect (e.g. a click ripple)\n * is still playing: the engine then keeps rendering at the full frame rate.\n */\n render(frame: Frame): boolean | void;\n /** Free GPU resources and the like. */\n destroy?(): void;\n}\n\nexport interface StyleDefinition<O extends object> {\n /** Unique, lowercase name, e.g. `'topo'`. */\n name: string;\n defaults: Readonly<O>;\n /**\n * Whether the background moves on its own with these options. When it doesn't,\n * the engine only renders on pointer movement and option changes.\n */\n animates(options: O): boolean;\n /**\n * The lowest frame rate at which the ambient animation still looks smooth with\n * these options. The engine renders the ambient animation at the lower of this\n * and its `idleFps`. Omit to always use `idleFps`.\n */\n idleFps?(options: O): number;\n /**\n * How the style can be drawn, made with `webglRenderer()` and `canvas2dRenderer()`, in order of\n * preference: the engine uses the first one the browser supports. At least one.\n */\n renderers: readonly Renderer<O>[];\n}\n\n/** Everything about a style except how it's drawn: shared by its WebGL-only, Canvas 2D-only and auto builds. */\nexport type StyleBase<O extends object> = Omit<StyleDefinition<O>, 'renderers'>;\n\n/** A style with its options filled in, ready for `createBackground()`. */\nexport interface Style<O extends object> {\n readonly definition: StyleDefinition<O>;\n readonly options: Readonly<O>;\n}\n\nexport interface StyleFactory<O extends object> {\n (options?: Partial<O>): Style<O>;\n readonly styleName: string;\n readonly defaults: Readonly<O>;\n}\n\n/**\n * Turn a style definition into the function users call, e.g. `topo({ levels: 14 })`.\n */\nexport function defineStyle<O extends object>(definition: StyleDefinition<O>): StyleFactory<O> {\n if (definition.renderers.length === 0) {\n throw new Error(`interactive-bg: style \"${definition.name}\" has no renderer`);\n }\n const factory = (options: Partial<O> = {}): Style<O> => ({\n definition,\n options: { ...definition.defaults, ...options },\n });\n return Object.assign(factory, { styleName: definition.name, defaults: definition.defaults });\n}\n","export type RGBA = readonly [r: number, g: number, b: number, a: number];\n\nconst TRANSPARENT: RGBA = [0, 0, 0, 0];\n\nlet probe: CanvasRenderingContext2D | null = null;\nconst cache = new Map<string, RGBA>();\n\n/**\n * Resolve any CSS colour to straight (non-premultiplied) sRGB components in 0–1,\n * by letting the browser paint it into a 1×1 canvas. Results are cached.\n */\nexport function parseColor(color: string | null): RGBA {\n if (!color || color === 'transparent') return TRANSPARENT;\n const cached = cache.get(color);\n if (cached) return cached;\n\n if (!probe) {\n const canvas = document.createElement('canvas');\n canvas.width = canvas.height = 1;\n probe = canvas.getContext('2d', { willReadFrequently: true });\n if (!probe) return [0, 0, 0, 1];\n }\n probe.clearRect(0, 0, 1, 1);\n // An invalid colour leaves fillStyle unchanged, so it falls back to black.\n probe.fillStyle = '#000';\n probe.fillStyle = color;\n probe.fillRect(0, 0, 1, 1);\n const [r, g, b, a] = probe.getImageData(0, 0, 1, 1).data;\n const rgba: RGBA = [r / 255, g / 255, b / 255, a / 255];\n if (cache.size > 64) cache.clear();\n cache.set(color, rgba);\n return rgba;\n}\n","/**\n * Vertex shader for one triangle that covers the whole viewport, drawn with\n * `gl.drawArrays(gl.TRIANGLES, 0, 3)` and no vertex buffers. Pair it with a\n * fragment shader that works per pixel from `gl_FragCoord`.\n */\nexport const FULLSCREEN_VERTEX_SHADER = `#version 300 es\nvoid main() {\n vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));\n gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}`;\n\n/**\n * Compile and link a shader program. Returns `null` if the context is lost, and\n * throws with the driver's message if a shader doesn't compile or link (the\n * engine then falls back to the style's next renderer). Nothing is left behind\n * on failure.\n */\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n): WebGLProgram | null {\n const program = gl.createProgram();\n let vertex: WebGLShader | null = null;\n let fragment: WebGLShader | null = null;\n try {\n vertex = compile(gl, gl.VERTEX_SHADER, vertexSource);\n fragment = compile(gl, gl.FRAGMENT_SHADER, fragmentSource);\n if (!program || !vertex || !fragment) {\n gl.deleteProgram(program);\n return null;\n }\n gl.attachShader(program, vertex);\n gl.attachShader(program, fragment);\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS) && !gl.isContextLost()) {\n throw new Error(`interactive-bg: shader link error: ${gl.getProgramInfoLog(program)}`);\n }\n return program;\n } catch (error) {\n gl.deleteProgram(program);\n throw error;\n } finally {\n // Linked programs keep their own copy; the shader objects aren't needed either way.\n gl.deleteShader(vertex);\n gl.deleteShader(fragment);\n }\n}\n\n/** Look up uniform locations by name. */\nexport function getUniforms<N extends string>(\n gl: WebGL2RenderingContext,\n program: WebGLProgram,\n names: readonly N[],\n): Record<N, WebGLUniformLocation | null> {\n return Object.fromEntries(names.map((name) => [name, gl.getUniformLocation(program, name)])) as Record<\n N,\n WebGLUniformLocation | null\n >;\n}\n\nfunction compile(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS) && !gl.isContextLost()) {\n const log = gl.getShaderInfoLog(shader);\n gl.deleteShader(shader);\n throw new Error(`interactive-bg: shader error: ${log}`);\n }\n return shader;\n}\n","import { parseColor, type RGBA } from './color';\nimport type { StyleRenderer } from './style';\nimport { fades, type Fade, type Renderer } from './surface';\nimport { createProgram, FULLSCREEN_VERTEX_SHADER, getUniforms } from './webgl';\n\nconst WEBGL_ATTRIBUTES: WebGLContextAttributes = {\n alpha: true,\n premultipliedAlpha: true,\n antialias: false, // styles antialias in their shaders; MSAA would only cost memory\n depth: false,\n stencil: false,\n preserveDrawingBuffer: false,\n powerPreference: 'low-power',\n};\n\n// The edge fades, drawn after the style. Mode 0 scales what's there by how much of it each side\n// keeps (1 inside, down to 0 at a fading edge, multiplied over the sides) with blend\n// ZERO, ONE_MINUS_SRC_ALPHA. Mode 1 paints the premultiplied background colour behind it, where\n// the drawing is transparent (blend ONE_MINUS_DST_ALPHA, ONE).\nconst FADE_FRAGMENT = `#version 300 es\nprecision highp float;\nuniform float uMode;\nuniform vec4 uFade; // top, right, bottom, left, device px (0 = no fade)\nuniform vec2 uSize; // drawing buffer size, device px\nuniform vec4 uColor; // premultiplied background colour\nout vec4 outColor;\n\nfloat keep(float distance, float length) {\n return length > 0.0 ? clamp(distance / length, 0.0, 1.0) : 1.0;\n}\n\nvoid main() {\n if (uMode > 0.5) {\n outColor = uColor;\n return;\n }\n vec2 p = gl_FragCoord.xy; // origin at the bottom left\n float kept = keep(uSize.y - p.y, uFade.x) * keep(uSize.x - p.x, uFade.y) * keep(p.y, uFade.z) * keep(p.x, uFade.w);\n outColor = vec4(0.0, 0.0, 0.0, 1.0 - kept);\n}`;\n\n/**\n * Draw a style with WebGL2. The engine clears to the background colour, sets\n * the viewport and premultiplied-alpha blending, and recreates the renderer\n * after a lost context is restored.\n */\nexport function webglRenderer<O>(createRenderer: (gl: WebGL2RenderingContext, options: O) => StyleRenderer<O>): Renderer<O> {\n return {\n name: 'webgl',\n create(canvas, initial, invalidate) {\n const gl = canvas.getContext('webgl2', WEBGL_ATTRIBUTES);\n if (!gl) return null;\n\n let options = initial;\n // `null` while the context is lost: its GPU resources are gone.\n let renderer: StyleRenderer<O> | null;\n try {\n renderer = createRenderer(gl, options);\n } catch (error) {\n // E.g. a shader this GPU's driver rejects: let the engine try the next renderer.\n console.warn('interactive-bg: WebGL setup failed, trying the next renderer', error);\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n return null;\n }\n // Compiled the first time a fade is drawn, and again after a lost context.\n let fadePass: {\n program: WebGLProgram;\n uniforms: Record<'uMode' | 'uFade' | 'uSize' | 'uColor', WebGLUniformLocation | null>;\n } | null = null;\n\n const onLost = (event: Event): void => {\n event.preventDefault(); // allow the context to be restored\n renderer = null;\n fadePass = null;\n };\n\n /** Fade the drawing out towards the edges (`fade` in CSS px), then put `background` (RGBA) behind it. */\n const fadeEdges = (fade: Fade, dpr: number, background: RGBA): void => {\n if (!fadePass) {\n const program = createProgram(gl, FULLSCREEN_VERTEX_SHADER, FADE_FRAGMENT);\n if (!program) return; // context lost\n fadePass = { program, uniforms: getUniforms(gl, program, ['uMode', 'uFade', 'uSize', 'uColor'] as const) };\n }\n const { uniforms } = fadePass;\n gl.useProgram(fadePass.program);\n gl.uniform1f(uniforms.uMode, 0);\n gl.uniform4f(uniforms.uFade, fade.top * dpr, fade.right * dpr, fade.bottom * dpr, fade.left * dpr);\n gl.uniform2f(uniforms.uSize, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n const [r, g, b, a] = background;\n if (a > 0) {\n gl.uniform1f(uniforms.uMode, 1);\n gl.uniform4f(uniforms.uColor, r * a, g * a, b * a, a);\n gl.blendFunc(gl.ONE_MINUS_DST_ALPHA, gl.ONE);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n }\n };\n\n const onRestored = (): void => {\n renderer = createRenderer(gl, options);\n invalidate();\n };\n\n canvas.addEventListener('webglcontextlost', onLost);\n canvas.addEventListener('webglcontextrestored', onRestored);\n\n return {\n name: 'webgl',\n update(next) {\n options = next;\n renderer?.update(next);\n },\n render(frame, backgroundColor, fade) {\n if (!renderer) return false;\n const background = parseColor(backgroundColor);\n const [r, g, b, a] = background;\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n // With a fade, the background goes in last, behind the faded drawing, so it stays solid.\n const fading = fades(fade);\n if (fading) gl.clearColor(0, 0, 0, 0);\n else gl.clearColor(r * a, g * a, b * a, a);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n const busy = renderer.render(frame) === true;\n if (fading) fadeEdges(fade, frame.dpr, background);\n return busy;\n },\n clear() {\n if (!renderer) return;\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n },\n destroy() {\n canvas.removeEventListener('webglcontextlost', onLost);\n canvas.removeEventListener('webglcontextrestored', onRestored);\n renderer?.destroy?.();\n renderer = null;\n if (fadePass) gl.deleteProgram(fadePass.program);\n fadePass = null;\n },\n };\n },\n };\n}\n","/**\n * Numbers collected during a frame, in an array that's reused from frame to\n * frame and only ever grows, so drawing allocates nothing once it's warm.\n */\nexport interface FloatBuffer {\n data: Float32Array<ArrayBuffer>;\n length: number;\n}\n\nexport function createFloatBuffer(capacity: number): FloatBuffer {\n return { data: new Float32Array(capacity), length: 0 };\n}\n\n/** Make room for `count` more values (doubling the array if needed) and return the array to write into. */\nexport function reserve(buffer: FloatBuffer, count: number): Float32Array<ArrayBuffer> {\n if (buffer.length + count > buffer.data.length) {\n const grown = new Float32Array(Math.max(buffer.data.length * 2, buffer.length + count));\n grown.set(buffer.data);\n buffer.data = grown;\n }\n return buffer.data;\n}\n","export type SegmentSink = (\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n level: number,\n) => void;\n\n/**\n * Marching squares over a regular grid of samples.\n *\n * `field` holds `cols * rows` samples in row-major order, spaced `cellSize`\n * apart. Contour lines are traced at every multiple of `step`; each segment is\n * passed to `emit` together with its integer level index (threshold / step).\n */\nexport function traceContours(\n field: ArrayLike<number>,\n cols: number,\n rows: number,\n cellSize: number,\n step: number,\n emit: SegmentSink,\n): void {\n if (step <= 0) return;\n\n for (let j = 0; j < rows - 1; j++) {\n const y0 = j * cellSize;\n const y1 = y0 + cellSize;\n for (let i = 0; i < cols - 1; i++) {\n const idx = j * cols + i;\n // a ── b\n // │ │\n // d ── c\n const a = field[idx];\n const b = field[idx + 1];\n const c = field[idx + cols + 1];\n const d = field[idx + cols];\n\n const min = Math.min(a, b, c, d);\n const max = Math.max(a, b, c, d);\n const first = Math.ceil(min / step);\n const last = Math.floor(max / step);\n if (first > last) continue;\n\n const x0 = i * cellSize;\n const x1 = x0 + cellSize;\n\n for (let level = first; level <= last; level++) {\n const t = level * step;\n const code =\n (a >= t ? 8 : 0) | (b >= t ? 4 : 0) | (c >= t ? 2 : 0) | (d >= t ? 1 : 0);\n if (code === 0 || code === 15) continue;\n\n // Crossing points on each edge (only valid when that edge is crossed).\n const topX = x0 + cellSize * frac(t, a, b);\n const rightY = y0 + cellSize * frac(t, b, c);\n const bottomX = x0 + cellSize * frac(t, d, c);\n const leftY = y0 + cellSize * frac(t, a, d);\n\n switch (code) {\n case 1:\n case 14:\n emit(x0, leftY, bottomX, y1, level);\n break;\n case 2:\n case 13:\n emit(bottomX, y1, x1, rightY, level);\n break;\n case 3:\n case 12:\n emit(x0, leftY, x1, rightY, level);\n break;\n case 4:\n case 11:\n emit(topX, y0, x1, rightY, level);\n break;\n case 6:\n case 9:\n emit(topX, y0, bottomX, y1, level);\n break;\n case 7:\n case 8:\n emit(x0, leftY, topX, y0, level);\n break;\n case 5:\n case 10: {\n // Saddle: disambiguate with the cell centre.\n const centreAbove = (a + b + c + d) / 4 >= t;\n const isolateAC = (code === 5) === centreAbove;\n if (isolateAC) {\n emit(x0, leftY, topX, y0, level);\n emit(bottomX, y1, x1, rightY, level);\n } else {\n emit(topX, y0, x1, rightY, level);\n emit(x0, leftY, bottomX, y1, level);\n }\n break;\n }\n }\n }\n }\n }\n}\n\nfunction frac(t: number, from: number, to: number): number {\n const d = to - from;\n return d === 0 ? 0.5 : (t - from) / d;\n}\n","export interface TopoOptions {\n /** Stroke colour of regular contour lines. Any CSS colour. */\n lineColor: string;\n /** Stroke colour of every `majorEvery`-th (\"index\") line. Defaults to `lineColor`. */\n majorLineColor?: string;\n /** Opacity of all lines, from `0` (invisible) to `1` (opaque). Multiplies any alpha in the colours. */\n lineOpacity: number;\n /** Width of regular lines, in CSS pixels. */\n lineWidth: number;\n /** Width of index lines, in CSS pixels. */\n majorLineWidth: number;\n /** Every n-th contour is drawn as an index line. `0` disables index lines. */\n majorEvery: number;\n /** Number of contour levels across the full elevation range. More = denser lines. */\n levels: number;\n /** Noise frequency per CSS pixel. Smaller = larger, smoother landforms. */\n scale: number;\n /** Noise octaves. More = more detailed, rougher terrain (and more CPU). */\n octaves: number;\n /** How fast the terrain morphs, in noise units per second. `0` = static. */\n speed: number;\n /** Size of a sampling cell in CSS pixels. Smaller = smoother lines, more CPU. */\n resolution: number;\n /** Seed for the terrain. Same seed, same landscape. Pass a random number for a different one on every load. */\n seed: number;\n /** Radius of the pointer's influence, in CSS pixels. */\n pointerRadius: number;\n /** Height of the bump under the pointer. Negative values dig a crater. */\n pointerStrength: number;\n}\n\nexport const topoDefaults: Readonly<TopoOptions> = Object.freeze({\n lineColor: '#5b6576',\n majorLineColor: '#7dd3a8',\n lineOpacity: 0.5,\n lineWidth: 1,\n majorLineWidth: 1.75,\n majorEvery: 5,\n levels: 12,\n scale: 0.0025,\n octaves: 2,\n speed: 0.025,\n resolution: 6,\n seed: 1332056948,\n pointerRadius: 100,\n pointerStrength: 0.35,\n});\n\n/** Options after clamping and deriving: what the field and the renderers consume. */\nexport interface ResolvedTopoOptions {\n lineColor: string;\n majorLineColor: string;\n lineOpacity: number;\n lineWidth: number;\n majorLineWidth: number;\n /** Integer; `0` = no index lines. */\n majorEvery: number;\n /** Height difference between neighbouring contour levels. */\n levelStep: number;\n /** Grid spacing of the height field, in CSS pixels. */\n cellSize: number;\n octaves: number;\n scale: number;\n speed: number;\n seed: number;\n pointerRadius: number;\n pointerStrength: number;\n}\n\nexport function resolveTopoOptions(options: TopoOptions): ResolvedTopoOptions {\n return {\n lineColor: options.lineColor,\n majorLineColor: options.majorLineColor ?? options.lineColor,\n lineOpacity: Math.min(1, Math.max(0, options.lineOpacity)),\n lineWidth: Math.max(0.1, options.lineWidth),\n majorLineWidth: Math.max(0.1, options.majorLineWidth),\n majorEvery: Math.max(0, Math.round(options.majorEvery)),\n // The height field spans roughly [-1, 1], so the levels cover a range of 2.\n levelStep: 2 / Math.max(1, options.levels),\n cellSize: Math.max(2, options.resolution),\n octaves: Math.max(1, Math.round(options.octaves)),\n scale: options.scale,\n // The keyframes only step forwards in time; morphing backwards looks the same, so use the magnitude.\n speed: Math.abs(options.speed),\n seed: options.seed,\n pointerRadius: Math.max(1, options.pointerRadius),\n pointerStrength: options.pointerStrength,\n };\n}\n","/** Returns a value in roughly [-1, 1]. */\nexport type Noise3D = (x: number, y: number, z: number) => number;\n\nconst F3 = 1 / 3;\nconst G3 = 1 / 6;\n\n// prettier-ignore\nconst GRAD3 = new Float32Array([\n 1, 1, 0, -1, 1, 0, 1, -1, 0, -1, -1, 0,\n 1, 0, 1, -1, 0, 1, 1, 0, -1, -1, 0, -1,\n 0, 1, 1, 0, -1, 1, 0, 1, -1, 0, -1, -1,\n]);\n\n/** Small, fast seeded PRNG returning floats in [0, 1). */\nfunction mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/** Seeded 3D simplex noise (Gustavson). The third axis is used as time. */\nexport function createNoise3D(seed: number = Math.random() * 2 ** 32): Noise3D {\n const random = mulberry32(seed);\n const p = new Uint8Array(256);\n for (let i = 0; i < 256; i++) p[i] = i;\n for (let i = 255; i > 0; i--) {\n const j = Math.floor(random() * (i + 1));\n const tmp = p[i];\n p[i] = p[j];\n p[j] = tmp;\n }\n const perm = new Uint8Array(512);\n const permMod12 = new Uint8Array(512);\n for (let i = 0; i < 512; i++) {\n perm[i] = p[i & 255];\n permMod12[i] = perm[i] % 12;\n }\n\n return (x, y, z) => {\n const s = (x + y + z) * F3;\n const i = Math.floor(x + s);\n const j = Math.floor(y + s);\n const k = Math.floor(z + s);\n const t = (i + j + k) * G3;\n const x0 = x - (i - t);\n const y0 = y - (j - t);\n const z0 = z - (k - t);\n\n let i1: number, j1: number, k1: number, i2: number, j2: number, k2: number;\n if (x0 >= y0) {\n if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }\n else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; }\n else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; }\n } else {\n if (y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; }\n else if (x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; }\n else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }\n }\n\n const x1 = x0 - i1 + G3;\n const y1 = y0 - j1 + G3;\n const z1 = z0 - k1 + G3;\n const x2 = x0 - i2 + 2 * G3;\n const y2 = y0 - j2 + 2 * G3;\n const z2 = z0 - k2 + 2 * G3;\n const x3 = x0 - 1 + 3 * G3;\n const y3 = y0 - 1 + 3 * G3;\n const z3 = z0 - 1 + 3 * G3;\n\n const ii = i & 255;\n const jj = j & 255;\n const kk = k & 255;\n\n let n = 0;\n let c = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;\n if (c > 0) {\n const g = permMod12[ii + perm[jj + perm[kk]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x0 + GRAD3[g + 1] * y0 + GRAD3[g + 2] * z0);\n }\n c = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;\n if (c > 0) {\n const g = permMod12[ii + i1 + perm[jj + j1 + perm[kk + k1]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x1 + GRAD3[g + 1] * y1 + GRAD3[g + 2] * z1);\n }\n c = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;\n if (c > 0) {\n const g = permMod12[ii + i2 + perm[jj + j2 + perm[kk + k2]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x2 + GRAD3[g + 1] * y2 + GRAD3[g + 2] * z2);\n }\n c = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;\n if (c > 0) {\n const g = permMod12[ii + 1 + perm[jj + 1 + perm[kk + 1]]] * 3;\n c *= c;\n n += c * c * (GRAD3[g] * x3 + GRAD3[g + 1] * y3 + GRAD3[g + 2] * z3);\n }\n return 32 * n;\n };\n}\n","import { createNoise3D, type Noise3D } from '../../shared/noise';\nimport type { ResolvedTopoOptions } from './options';\n\n/** Noise-time distance between sampled keyframes; frames in between are blended. */\nconst KEY_DT = 0.02;\n\nexport type FieldParams = Pick<ResolvedTopoOptions, 'seed' | 'scale' | 'octaves' | 'cellSize'>;\n\nexport interface KeyframeField {\n readonly cols: number;\n readonly rows: number;\n /** The terrain at time `t` is `keyA + (keyB - keyA) * blend`, see `advance()`. */\n readonly keyA: Float32Array;\n readonly keyB: Float32Array;\n /** Changes whenever the contents of `keyA` / `keyB` change. */\n readonly version: number;\n /** Apply new parameters; resamples only if something actually changed. */\n configure(params: FieldParams): void;\n /** Size of the area to cover, in CSS pixels. */\n resize(width: number, height: number): void;\n /** Bring the keyframes up to `time` and return the blend factor between them. */\n advance(time: number): number;\n}\n\n/**\n * The terrain height field, sampled on a grid `cellSize` pixels apart.\n *\n * Sampling noise for every grid point is the most expensive step, but the\n * terrain changes slowly. So noise is only sampled at keyframes KEY_DT apart\n * (A at `keyTime`, B at `keyTime + KEY_DT`) and every frame blends between them.\n * The keyframe after B is built a few rows per frame to avoid spikes.\n */\nexport function createKeyframeField(initial: FieldParams): KeyframeField {\n let params = initial;\n let noise: Noise3D = createNoise3D(params.seed);\n // Sum of octave amplitudes (1 + 1/2 + 1/4 + …), to normalise the result to [-1, 1].\n let norm = 2 - 2 ** (1 - params.octaves);\n\n let width = 0;\n let height = 0;\n let cols = 0;\n let rows = 0;\n let keyA = new Float32Array(0);\n let keyB = new Float32Array(0);\n let keyNext = new Float32Array(0);\n let keyTime = 0;\n let keyNextRows = 0;\n let valid = false;\n let version = 0;\n\n function allocate(): void {\n const nextCols = Math.ceil(width / params.cellSize) + 1;\n const nextRows = Math.ceil(height / params.cellSize) + 1;\n if (nextCols === cols && nextRows === rows) return;\n cols = nextCols;\n rows = nextRows;\n keyA = new Float32Array(cols * rows);\n keyB = new Float32Array(cols * rows);\n keyNext = new Float32Array(cols * rows);\n valid = false;\n }\n\n function sampleRows(target: Float32Array, t: number, fromRow: number, toRow: number): void {\n const { cellSize, octaves, scale } = params;\n for (let j = fromRow; j < toRow; j++) {\n const y = j * cellSize;\n for (let i = 0; i < cols; i++) {\n const x = i * cellSize;\n let value = 0;\n for (let o = 0, amp = 1, freq = scale; o < octaves; o++, amp *= 0.5, freq *= 2) {\n value += amp * noise(x * freq, y * freq, t + o * 17.3);\n }\n target[j * cols + i] = value / norm;\n }\n }\n }\n\n return {\n get cols() {\n return cols;\n },\n get rows() {\n return rows;\n },\n get keyA() {\n return keyA;\n },\n get keyB() {\n return keyB;\n },\n get version() {\n return version;\n },\n\n configure(next) {\n const prev = params;\n if (\n next.seed === prev.seed &&\n next.scale === prev.scale &&\n next.octaves === prev.octaves &&\n next.cellSize === prev.cellSize\n ) {\n return;\n }\n params = { seed: next.seed, scale: next.scale, octaves: next.octaves, cellSize: next.cellSize };\n if (next.seed !== prev.seed) noise = createNoise3D(next.seed);\n norm = 2 - 2 ** (1 - next.octaves);\n allocate();\n valid = false;\n },\n\n resize(nextWidth, nextHeight) {\n width = nextWidth;\n height = nextHeight;\n allocate();\n },\n\n advance(time) {\n if (!valid || time < keyTime || time >= keyTime + 2 * KEY_DT) {\n keyTime = time;\n sampleRows(keyA, keyTime, 0, rows);\n sampleRows(keyB, keyTime + KEY_DT, 0, rows);\n keyNextRows = 0;\n valid = true;\n version++;\n }\n if (time >= keyTime + KEY_DT) {\n sampleRows(keyNext, keyTime + 2 * KEY_DT, keyNextRows, rows);\n [keyA, keyB, keyNext] = [keyB, keyNext, keyA];\n keyTime += KEY_DT;\n keyNextRows = 0;\n version++;\n }\n // Spread the next keyframe over the first 80% of the interval.\n const progress = (time - keyTime) / KEY_DT;\n const wanted = Math.min(rows, Math.ceil((rows * progress) / 0.8));\n if (wanted > keyNextRows) {\n sampleRows(keyNext, keyTime + 2 * KEY_DT, keyNextRows, wanted);\n keyNextRows = wanted;\n }\n return progress;\n },\n };\n}\n","import type { Frame } from '../../core/style';\nimport { createKeyframeField, type KeyframeField } from './field';\nimport type { ResolvedTopoOptions } from './options';\n\n/** The animated height field both topo renderers draw: keyframes plus the clock that drives them. */\nexport interface Terrain {\n readonly field: KeyframeField;\n configure(options: ResolvedTopoOptions): void;\n /** Move the terrain forward by one frame and return the blend factor between the keyframes. */\n advance(frame: Frame): number;\n}\n\nexport function createTerrain(initial: ResolvedTopoOptions): Terrain {\n const field = createKeyframeField(initial);\n let speed = initial.speed;\n let time = 0;\n return {\n field,\n configure(options) {\n field.configure(options);\n speed = options.speed;\n },\n advance(frame) {\n field.resize(frame.width, frame.height);\n if (!frame.reducedMotion) time += frame.dt * speed;\n return field.advance(time);\n },\n };\n}\n","import type { StyleRenderer } from '../../core/style';\nimport { createFloatBuffer, reserve, type FloatBuffer } from '../../shared/buffer';\nimport { traceContours } from './contours';\nimport { resolveTopoOptions, type TopoOptions } from './options';\nimport { createTerrain } from './terrain';\n\n/** Marching squares on the CPU, stroked with the Canvas 2D API. */\nexport function createTopoCanvas2D(ctx: CanvasRenderingContext2D, initial: TopoOptions): StyleRenderer<TopoOptions> {\n let options = resolveTopoOptions(initial);\n const terrain = createTerrain(options);\n let field = new Float32Array(0);\n\n // Segments are collected into reusable buffers and stroked from the context's\n // own path, so a frame allocates nothing. Path2D objects per frame pile up as\n // native garbage faster than the browser frees them.\n // Line segments as x1, y1, x2, y2.\n const minor = createFloatBuffer(4096);\n const major = createFloatBuffer(1024);\n\n function collectSegment(x1: number, y1: number, x2: number, y2: number, level: number): void {\n const buffer = options.majorEvery > 0 && level % options.majorEvery === 0 ? major : minor;\n const data = reserve(buffer, 4);\n data[buffer.length++] = x1;\n data[buffer.length++] = y1;\n data[buffer.length++] = x2;\n data[buffer.length++] = y2;\n }\n\n function stroke(buffer: FloatBuffer, color: string, lineWidth: number): void {\n const { data, length } = buffer;\n ctx.beginPath();\n for (let k = 0; k < length; k += 4) {\n ctx.moveTo(data[k], data[k + 1]);\n ctx.lineTo(data[k + 2], data[k + 3]);\n }\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.stroke();\n }\n\n /** Blend the keyframes and add the pointer bump into `field`. */\n function sampleField(blend: number, pointerX: number, pointerY: number, bump: number): void {\n const { cols, rows, keyA, keyB } = terrain.field;\n const size = cols * rows;\n if (field.length !== size) field = new Float32Array(size);\n for (let idx = 0; idx < size; idx++) {\n const a = keyA[idx];\n field[idx] = a + (keyB[idx] - a) * blend;\n }\n\n if (bump === 0) return;\n const { cellSize, pointerRadius } = options;\n const radius2 = pointerRadius * pointerRadius;\n // Beyond 3 radii the bump adds < 0.0001, so only touch the cells around the pointer.\n const reach = 3 * pointerRadius;\n const i0 = Math.max(0, Math.floor((pointerX - reach) / cellSize));\n const i1 = Math.min(cols - 1, Math.ceil((pointerX + reach) / cellSize));\n const j0 = Math.max(0, Math.floor((pointerY - reach) / cellSize));\n const j1 = Math.min(rows - 1, Math.ceil((pointerY + reach) / cellSize));\n for (let j = j0; j <= j1; j++) {\n const dy = j * cellSize - pointerY;\n for (let i = i0; i <= i1; i++) {\n const dx = i * cellSize - pointerX;\n field[j * cols + i] += bump * Math.exp(-(dx * dx + dy * dy) / radius2);\n }\n }\n }\n\n return {\n update(next) {\n options = resolveTopoOptions(next);\n terrain.configure(options);\n },\n render(frame) {\n const blend = terrain.advance(frame);\n const { pointer } = frame;\n sampleField(blend, pointer.x, pointer.y, options.pointerStrength * pointer.influence);\n\n minor.length = major.length = 0;\n const { cols, rows } = terrain.field;\n traceContours(field, cols, rows, options.cellSize, options.levelStep, collectSegment);\n\n ctx.globalAlpha = options.lineOpacity;\n stroke(minor, options.lineColor, options.lineWidth);\n if (options.majorEvery > 0) stroke(major, options.majorLineColor, options.majorLineWidth);\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { topoDefaults, type TopoOptions } from './options';\n\n/**\n * Animated topographic contour lines. The terrain drifts slowly and rises\n * (or, with a negative `pointerStrength`, sinks) under the pointer.\n */\nexport const topoStyle: StyleBase<TopoOptions> = {\n name: 'topo',\n defaults: topoDefaults,\n animates: (options) => options.speed !== 0,\n};\n","import { parseColor } from '../../core/color';\nimport type { StyleRenderer } from '../../core/style';\nimport { createProgram, FULLSCREEN_VERTEX_SHADER, getUniforms } from '../../core/webgl';\nimport { resolveTopoOptions, type TopoOptions } from './options';\nimport { createTerrain } from './terrain';\n\nconst FRAGMENT = `#version 300 es\nprecision highp float;\nprecision highp sampler2D;\n\nuniform sampler2D uKeyA;\nuniform sampler2D uKeyB;\nuniform float uBlend;\nuniform vec2 uGrid; // cols, rows\nuniform float uCellSize; // CSS px between grid samples\nuniform float uDpr;\nuniform float uHeight; // canvas height in device px\nuniform vec3 uPointer; // x, y (CSS px), bump height\nuniform float uRadius2;\nuniform float uStep; // height difference between contour levels\nuniform float uMajorEvery;\nuniform vec2 uHalfWidth; // half line widths (device px): minor, major\nuniform vec4 uMinor; // straight RGBA, opacity applied\nuniform vec4 uMajor;\n\nout vec4 outColor;\n\nfloat heightAt(ivec2 c) {\n return mix(texelFetch(uKeyA, c, 0).r, texelFetch(uKeyB, c, 0).r, uBlend);\n}\n\nvoid main() {\n vec2 p = vec2(gl_FragCoord.x, uHeight - gl_FragCoord.y) / uDpr;\n\n // Bilinear interpolation of the height field (same surface the CPU renderer traces).\n vec2 g = p / uCellSize;\n vec2 cell = clamp(floor(g), vec2(0.0), uGrid - 2.0);\n vec2 f = g - cell;\n ivec2 c = ivec2(cell);\n float h = mix(\n mix(heightAt(c), heightAt(c + ivec2(1, 0)), f.x),\n mix(heightAt(c + ivec2(0, 1)), heightAt(c + ivec2(1, 1)), f.x),\n f.y);\n\n vec2 d = p - uPointer.xy;\n h += uPointer.z * exp(-dot(d, d) / uRadius2);\n\n // Distance to the nearest contour, in device pixels, from the screen-space gradient.\n float v = h / uStep;\n float level = floor(v + 0.5);\n float dist = abs(v - level) / max(fwidth(v), 1e-5);\n\n bool major = uMajorEvery > 0.0 && mod(level, uMajorEvery) == 0.0;\n float halfWidth = major ? uHalfWidth.y : uHalfWidth.x;\n vec4 line = major ? uMajor : uMinor;\n // Analytic antialiasing: coverage ramps over one pixel at the line edge.\n float a = line.a * clamp(halfWidth + 0.5 - dist, 0.0, 1.0);\n outColor = vec4(line.rgb * a, a); // premultiplied; the engine blends it over the background\n}`;\n\nconst UNIFORMS = [\n 'uKeyA', 'uKeyB', 'uBlend', 'uGrid', 'uCellSize', 'uDpr', 'uHeight', 'uPointer', 'uRadius2',\n 'uStep', 'uMajorEvery', 'uHalfWidth', 'uMinor', 'uMajor',\n] as const;\n\n/**\n * Per-pixel contour lines in a fragment shader. The CPU only uploads the two noise\n * keyframes when they change (once per keyframe interval) and sets a few uniforms per frame.\n */\nexport function createTopoWebGL(gl: WebGL2RenderingContext, initial: TopoOptions): StyleRenderer<TopoOptions> {\n let options = resolveTopoOptions(initial);\n const terrain = createTerrain(options);\n\n const program = createProgram(gl, FULLSCREEN_VERTEX_SHADER, FRAGMENT);\n const uniforms = program ? getUniforms(gl, program, UNIFORMS) : null;\n const textures = [gl.createTexture(), gl.createTexture()] as const;\n for (const texture of textures) {\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n }\n let textureCols = 0;\n let textureRows = 0;\n let uploadedVersion = -1;\n\n /** Upload the keyframes when they changed since the last frame. */\n function upload(): void {\n const { field } = terrain;\n const resized = textureCols !== field.cols || textureRows !== field.rows;\n if (!resized && uploadedVersion === field.version) return;\n const keys = [field.keyA, field.keyB];\n for (let unit = 0; unit < 2; unit++) {\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, textures[unit]);\n if (resized) {\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, field.cols, field.rows, 0, gl.RED, gl.FLOAT, keys[unit]);\n } else {\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, field.cols, field.rows, gl.RED, gl.FLOAT, keys[unit]);\n }\n }\n textureCols = field.cols;\n textureRows = field.rows;\n uploadedVersion = field.version;\n }\n\n return {\n update(next) {\n options = resolveTopoOptions(next);\n terrain.configure(options);\n },\n render(frame) {\n const blend = terrain.advance(frame);\n if (!program || !uniforms) return; // context lost during setup; the engine recreates us\n upload();\n\n const minor = parseColor(options.lineColor);\n const major = parseColor(options.majorLineColor);\n const opacity = options.lineOpacity;\n const { field } = terrain;\n\n gl.useProgram(program);\n gl.uniform1i(uniforms.uKeyA, 0);\n gl.uniform1i(uniforms.uKeyB, 1);\n gl.uniform1f(uniforms.uBlend, blend);\n gl.uniform2f(uniforms.uGrid, field.cols, field.rows);\n gl.uniform1f(uniforms.uCellSize, options.cellSize);\n gl.uniform1f(uniforms.uDpr, frame.dpr);\n gl.uniform1f(uniforms.uHeight, gl.drawingBufferHeight);\n gl.uniform3f(uniforms.uPointer, frame.pointer.x, frame.pointer.y, options.pointerStrength * frame.pointer.influence);\n gl.uniform1f(uniforms.uRadius2, options.pointerRadius * options.pointerRadius);\n gl.uniform1f(uniforms.uStep, options.levelStep);\n gl.uniform1f(uniforms.uMajorEvery, options.majorEvery);\n gl.uniform2f(uniforms.uHalfWidth, (options.lineWidth * frame.dpr) / 2, (options.majorLineWidth * frame.dpr) / 2);\n gl.uniform4f(uniforms.uMinor, minor[0], minor[1], minor[2], minor[3] * opacity);\n gl.uniform4f(uniforms.uMajor, major[0], major[1], major[2], major[3] * opacity);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n },\n destroy() {\n gl.deleteTexture(textures[0]);\n gl.deleteTexture(textures[1]);\n gl.deleteProgram(program);\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createTopoCanvas2D } from '../styles/topo/canvas2d';\nimport { topoStyle } from '../styles/topo/definition';\nimport type { TopoOptions } from '../styles/topo/options';\nimport { createTopoWebGL } from '../styles/topo/webgl';\n\nexport type { TopoOptions };\n\n/** Animated topographic contour lines, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const topo: StyleFactory<TopoOptions> = defineStyle({\n ...topoStyle,\n renderers: [webglRenderer(createTopoWebGL), canvas2dRenderer(createTopoCanvas2D)],\n});\n","import type { Frame } from '../core/style';\n\n// The motion model shared by the grid styles (dots, plus): a grid of marks that\n// wander around their places, react to the pointer and to click waves. The\n// WebGL vertex shaders mirror parts of it in GLSL (grid-webgl.ts); keep them in step.\n\nexport const TAU = Math.PI * 2;\n\n/** At most this many waves play at once; a new click replaces the oldest. */\nexport const MAX_WAVES = 8;\n\nexport interface Grid {\n cols: number;\n rows: number;\n /** Position of mark (0, 0), in CSS pixels. */\n originX: number;\n originY: number;\n}\n\n/**\n * A grid that fits inside the canvas, centred, leaving at least half a\n * `spacing` of padding on every side so marks at the edges are never clipped.\n * Any space left over is shared equally between opposite sides. A canvas too\n * small for the padding still gets one mark, in its centre.\n */\nexport function gridLayout(width: number, height: number, spacing: number): Grid {\n const cols = Math.max(1, Math.floor(width / spacing));\n const rows = Math.max(1, Math.floor(height / spacing));\n return {\n cols,\n rows,\n originX: (width - (cols - 1) * spacing) / 2,\n originY: (height - (rows - 1) * spacing) / 2,\n };\n}\n\n/** A stable pseudo-random phase in [0, 2π) for mark (i, j). */\nexport function cellPhase(i: number, j: number, salt: number): number {\n const s = Math.sin(i * 12.9898 + j * 78.233 + salt) * 43758.5453;\n return (s - Math.floor(s)) * TAU;\n}\n\n/**\n * Each mark's wander phases (px, py) as cos px, sin px, cos py, sin py,\n * recomputed only when the grid changes size. The wander offset is\n * `jitter × (sin(clock + px), cos(clock × 1.3 + py))`; see wanderClock.\n */\nexport function createPhaseCache(): (cols: number, rows: number) => Float32Array {\n let phases = new Float32Array(0);\n let phaseCols = 0;\n return (cols, rows) => {\n if (phaseCols === cols && phases.length === cols * rows * 4) return phases;\n phases = new Float32Array(cols * rows * 4);\n for (let j = 0; j < rows; j++) {\n for (let i = 0; i < cols; i++) {\n const k = (j * cols + i) * 4;\n const px = cellPhase(i, j, 0);\n const py = cellPhase(i, j, 1);\n phases[k] = Math.cos(px);\n phases[k + 1] = Math.sin(px);\n phases[k + 2] = Math.cos(py);\n phases[k + 3] = Math.sin(py);\n }\n }\n phaseCols = cols;\n return phases;\n };\n}\n\n/**\n * The trig of the wander clock for one frame. With a mark's cached phases\n * (createPhaseCache), its offset is\n * x = jitter × (sx × cos px + cx × sin px) = jitter × sin(clock + px)\n * y = jitter × (cy × cos py − sy × sin py) = jitter × cos(clock × 1.3 + py)\n * so a frame needs four trig calls in all instead of two per mark.\n */\nexport function wanderClock(clock: number): { sx: number; cx: number; sy: number; cy: number } {\n return { sx: Math.sin(clock), cx: Math.cos(clock), sy: Math.sin(clock * 1.3), cy: Math.cos(clock * 1.3) };\n}\n\n/** How strongly the pointer affects a mark `distance` away: 1 at the pointer, easing to 0 at `radius`. */\nexport function pointerFalloff(distance: number, radius: number): number {\n const k = Math.max(0, 1 - distance / radius);\n return k * k;\n}\n\n/** Height of a wave's ring at `distance` from its centre: 1 on the ring, fading over `width` either side. */\nexport function waveRing(distance: number, ringRadius: number, width: number): number {\n const x = (distance - ringRadius) / width;\n return Math.exp(-x * x);\n}\n\n/** How much of a wave is left at `age`: 1 when it starts, easing out to 0 at `duration`. */\nexport function waveEnvelope(age: number, duration: number): number {\n const k = Math.max(0, 1 - age / duration);\n return k * k;\n}\n\n/** The wander moves each mark at most this far between frames, in CSS pixels; finer steps can't be seen. */\nconst WANDER_STEP = 0.25;\n\n/**\n * Frame rate that keeps every wander step below WANDER_STEP. The fastest a mark\n * wanders is along y: amplitude × angular speed × 1.3.\n */\nexport function wanderFps(jitter: number, jitterSpeed: number): number {\n const maxSpeed = jitter * jitterSpeed * TAU * 1.3;\n return Math.ceil(maxSpeed / WANDER_STEP);\n}\n\n/** Idle frame rate for a wandering grid: just enough for a smooth wander, at least 5 fps. */\nexport function wanderIdleFps(options: { jitter: number; jitterSpeed: number }): number {\n return Math.max(5, wanderFps(options.jitter, options.jitterSpeed));\n}\n\nexport interface Wave {\n x: number;\n y: number;\n age: number;\n}\n\n/** The click waves currently playing. */\nexport interface WaveList {\n readonly waves: readonly Wave[];\n /**\n * Start waves for this frame's clicks (unless `enabled` is false), age the\n * rest, and drop those older than `duration` seconds.\n */\n advance(frame: Frame, duration: number, enabled: boolean): void;\n /** Writes each wave as x, y, ring radius, envelope into `out` (MAX_WAVES × 4), zeroing unused slots. */\n pack(out: Float32Array, speed: number, duration: number): void;\n}\n\nexport function createWaveList(): WaveList {\n const waves: Wave[] = [];\n return {\n waves,\n advance(frame, duration, enabled) {\n for (const wave of waves) wave.age += frame.dt;\n for (let k = waves.length - 1; k >= 0; k--) {\n if (waves[k].age >= duration) waves.splice(k, 1);\n }\n if (!enabled) return;\n for (const click of frame.clicks) {\n if (waves.length === MAX_WAVES) waves.shift();\n waves.push({ x: click.x, y: click.y, age: 0 });\n }\n },\n pack(out, speed, duration) {\n out.fill(0);\n for (let k = 0; k < waves.length; k++) {\n const wave = waves[k];\n out[k * 4] = wave.x;\n out[k * 4 + 1] = wave.y;\n out[k * 4 + 2] = speed * wave.age;\n out[k * 4 + 3] = waveEnvelope(wave.age, duration);\n }\n },\n };\n}\n","// The dots-specific part of the motion model; the rest is shared with other\n// grid styles in shared/grid.ts.\n\n/** Size boost of a dot riding the crest of a wave (1 + WAVE_GROW × ring). */\nexport const WAVE_GROW = 0.6;\n","export interface DotsOptions {\n /** Dot colour. Any CSS colour. */\n color: string;\n /** Opacity of the dots, from `0` to `1`. Multiplies any alpha in the colour. */\n opacity: number;\n /** Dot radius in CSS pixels. */\n size: number;\n /**\n * Distance between neighbouring dots in CSS pixels. The grid also keeps at least half of\n * this as empty space along every edge, so dots at the edges aren't clipped.\n */\n spacing: number;\n /** How far each dot wanders around its place, in CSS pixels. `0` = still. */\n jitter: number;\n /** How fast the dots wander, in cycles per second. `0` = still. */\n jitterSpeed: number;\n /** Radius around the pointer within which dots are pushed away, in CSS pixels. */\n pointerRadius: number;\n /** How far the dots right next to the pointer are pushed, in CSS pixels. Negative values pull them in. */\n pointerStrength: number;\n /** How fast a click wave travels outwards, in CSS pixels per second. */\n waveSpeed: number;\n /** How far a click wave pushes dots, in CSS pixels. `0` disables waves. */\n waveStrength: number;\n /** Width of a click wave's ring, in CSS pixels. */\n waveWidth: number;\n /** How long a click wave lasts before it has faded out, in seconds. */\n waveDuration: number;\n}\n\nexport const dotsDefaults: Readonly<DotsOptions> = Object.freeze({\n color: '#8b95a5',\n opacity: 0.6,\n size: 1.6,\n spacing: 26,\n jitter: 1.2,\n jitterSpeed: 0.35,\n pointerRadius: 160,\n pointerStrength: 22,\n waveSpeed: 520,\n waveStrength: 10,\n waveWidth: 60,\n waveDuration: 1.8,\n});\n\n/** Options after clamping: what the renderers consume. */\nexport type ResolvedDotsOptions = DotsOptions;\n\nexport function resolveDotsOptions(options: DotsOptions): ResolvedDotsOptions {\n return {\n ...options,\n opacity: Math.min(1, Math.max(0, options.opacity)),\n size: Math.max(0.1, options.size),\n spacing: Math.max(4, options.spacing),\n jitter: Math.max(0, options.jitter),\n jitterSpeed: Math.max(0, options.jitterSpeed),\n pointerRadius: Math.max(1, options.pointerRadius),\n waveSpeed: Math.max(1, options.waveSpeed),\n waveWidth: Math.max(1, options.waveWidth),\n waveDuration: Math.max(0.05, options.waveDuration),\n };\n}\n","import type { StyleRenderer } from '../../core/style';\nimport { createFloatBuffer, reserve, type FloatBuffer } from '../../shared/buffer';\nimport {\n createPhaseCache,\n createWaveList,\n gridLayout,\n MAX_WAVES,\n pointerFalloff,\n TAU,\n wanderClock,\n waveRing,\n} from '../../shared/grid';\nimport { WAVE_GROW } from './motion';\nimport { resolveDotsOptions, type DotsOptions } from './options';\n\n/** Dots grown by waves are drawn in this many size steps per unit of growth (steps of ~0.25 px). */\nconst SIZE_STEPS = 4;\n/** Growth beyond this is clamped (two overlapping wave crests). */\nconst MAX_SIZE_STEP = 2 * SIZE_STEPS;\n\n/**\n * Every dot's position computed on the CPU. Dots are drawn as zero-length lines\n * with round caps: that renders the same round dots as `arc()`, about 4× faster.\n */\nexport function createDotsCanvas2D(ctx: CanvasRenderingContext2D, initial: DotsOptions): StyleRenderer<DotsOptions> {\n let options = resolveDotsOptions(initial);\n const waves = createWaveList();\n // Each wave as x, y, ring radius, envelope, worked out once per frame instead of once per dot.\n const waveData = new Float32Array(MAX_WAVES * 4);\n let clock = 0;\n\n // Dot centres as x, y pairs, one buffer per size step; dots outside a wave all land in step 0.\n const sizes = Array.from({ length: MAX_SIZE_STEP + 1 }, () => createFloatBuffer(256));\n\n function add(buffer: FloatBuffer, x: number, y: number): void {\n const data = reserve(buffer, 2);\n data[buffer.length++] = x;\n data[buffer.length++] = y;\n }\n\n function stroke(buffer: FloatBuffer, radius: number): void {\n const { data, length } = buffer;\n ctx.lineWidth = 2 * radius;\n ctx.beginPath();\n for (let k = 0; k < length; k += 2) {\n ctx.moveTo(data[k], data[k + 1]);\n // A tiny length: some browsers skip the caps of exactly zero-length lines.\n ctx.lineTo(data[k] + 0.01, data[k + 1]);\n }\n ctx.stroke();\n }\n\n const phasesFor = createPhaseCache();\n\n return {\n update(next) {\n options = resolveDotsOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, options.waveStrength !== 0);\n\n const { spacing, size, jitter, pointerRadius, waveWidth, waveStrength } = options;\n const { cols, rows, originX, originY } = gridLayout(frame.width, frame.height, spacing);\n const wander = phasesFor(cols, rows);\n const { sx, cx, sy, cy } = wanderClock(clock);\n const push = options.pointerStrength * frame.pointer.influence;\n const { x: px, y: py } = frame.pointer;\n const waveCount = waves.waves.length;\n waves.pack(waveData, options.waveSpeed, options.waveDuration);\n // Further than 3 widths from its ring a wave moves a dot by less than e⁻⁹ of its strength.\n const waveReach = 3 * waveWidth;\n for (const buffer of sizes) buffer.length = 0;\n\n for (let j = 0; j < rows; j++) {\n const restY = originY + j * spacing;\n for (let i = 0; i < cols; i++) {\n const restX = originX + i * spacing;\n const k = (j * cols + i) * 4;\n let x = restX + jitter * (sx * wander[k] + cx * wander[k + 1]);\n let y = restY + jitter * (cy * wander[k + 2] - sy * wander[k + 3]);\n\n if (push !== 0) {\n const dx = restX - px;\n const dy = restY - py;\n if (Math.abs(dx) < pointerRadius && Math.abs(dy) < pointerRadius) {\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (distance > 0 && distance < pointerRadius) {\n const amount = (push * pointerFalloff(distance, pointerRadius)) / distance;\n x += dx * amount;\n y += dy * amount;\n }\n }\n }\n\n let grow = 0;\n for (let w = 0; w < waveCount * 4; w += 4) {\n const dx = restX - waveData[w];\n const dy = restY - waveData[w + 1];\n const outer = waveData[w + 2] + waveReach;\n if (Math.abs(dx) > outer || Math.abs(dy) > outer) continue;\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (distance === 0 || Math.abs(distance - waveData[w + 2]) > waveReach) continue;\n const ring = waveRing(distance, waveData[w + 2], waveWidth) * waveData[w + 3];\n const amount = (waveStrength * ring) / distance;\n x += dx * amount;\n y += dy * amount;\n grow += ring;\n }\n\n add(sizes[Math.min(MAX_SIZE_STEP, Math.round(grow * SIZE_STEPS))], x, y);\n }\n }\n\n ctx.globalAlpha = options.opacity;\n ctx.strokeStyle = options.color;\n ctx.lineCap = 'round';\n for (let step = 0; step <= MAX_SIZE_STEP; step++) {\n if (sizes[step].length > 0) stroke(sizes[step], size * (1 + (WAVE_GROW * step) / SIZE_STEPS));\n }\n return waveCount > 0;\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { wanderIdleFps } from '../../shared/grid';\nimport { dotsDefaults, type DotsOptions } from './options';\n\n/**\n * A grid of dots that wander gently around their places. The pointer pushes\n * nearby dots away, more the closer they are, and clicks send out a wave.\n */\nexport const dotsStyle: StyleBase<DotsOptions> = {\n name: 'dots',\n defaults: dotsDefaults,\n animates: (options) => options.jitter > 0 && options.jitterSpeed > 0,\n // The wander is slow and sub-pixel, so it rarely needs the engine's full idle frame rate.\n idleFps: wanderIdleFps,\n};\n","import type { Frame } from '../core/style';\nimport { TAU, type Grid } from './grid';\n\n/** The uniforms GRID_VERTEX_GLSL declares; set them with setGridUniforms(). */\nexport const GRID_UNIFORMS = ['uCols', 'uOrigin', 'uSpacing', 'uViewport', 'uDpr', 'uClock', 'uJitter'] as const;\n\n/**\n * Vertex-shader preamble for the grid styles, which draw one GL point per mark.\n * Mirrors gridLayout, cellPhase and the wander in grid.ts; keep them in step.\n */\nexport const GRID_VERTEX_GLSL = `\nuniform int uCols;\nuniform vec2 uOrigin; // CSS px of mark (0, 0)\nuniform float uSpacing;\nuniform vec2 uViewport; // canvas size in CSS px\nuniform float uDpr;\nuniform float uClock; // wander phase, radians\nuniform float uJitter;\n\nfloat phase(vec2 ij, float salt) {\n return fract(sin(ij.x * 12.9898 + ij.y * 78.233 + salt) * 43758.5453) * ${TAU.toFixed(6)};\n}\n\n// This vertex's mark as (column, row). Integer maths: float division can put the first\n// mark of a row at the end of the previous one on some GPUs.\nvec2 markCell() {\n return vec2(float(gl_VertexID % uCols), float(gl_VertexID / uCols));\n}\n\nvec2 restPosition(vec2 ij) {\n return uOrigin + ij * uSpacing;\n}\n\nvec2 wander(vec2 ij) {\n return uJitter * vec2(sin(uClock + phase(ij, 0.0)), cos(uClock * 1.3 + phase(ij, 1.0)));\n}\n\n// CSS px (origin top left) to clip space.\nvec4 toClip(vec2 p) {\n vec2 clip = p / uViewport * 2.0 - 1.0;\n return vec4(clip.x, -clip.y, 0.0, 1.0);\n}\n`;\n\nexport function setGridUniforms(\n gl: WebGL2RenderingContext,\n uniforms: Record<(typeof GRID_UNIFORMS)[number], WebGLUniformLocation | null>,\n grid: Grid,\n frame: Frame,\n spacing: number,\n clock: number,\n jitter: number,\n): void {\n gl.uniform1i(uniforms.uCols, grid.cols);\n gl.uniform2f(uniforms.uOrigin, grid.originX, grid.originY);\n gl.uniform1f(uniforms.uSpacing, spacing);\n gl.uniform2f(uniforms.uViewport, frame.width, frame.height);\n gl.uniform1f(uniforms.uDpr, frame.dpr);\n gl.uniform1f(uniforms.uClock, clock);\n gl.uniform1f(uniforms.uJitter, jitter);\n}\n","import { parseColor } from '../../core/color';\nimport type { StyleRenderer } from '../../core/style';\nimport { createProgram, getUniforms } from '../../core/webgl';\nimport { createWaveList, gridLayout, MAX_WAVES, TAU } from '../../shared/grid';\nimport { GRID_UNIFORMS, GRID_VERTEX_GLSL, setGridUniforms } from '../../shared/grid-webgl';\nimport { WAVE_GROW } from './motion';\nimport { resolveDotsOptions, type DotsOptions } from './options';\n\n// Mirrors the motion model in shared/grid.ts: pointerFalloff, waveRing.\nconst VERTEX = `#version 300 es\nprecision highp float;\n\n${GRID_VERTEX_GLSL}\nuniform float uSize; // dot radius, CSS px\nuniform vec3 uPointer; // x, y, push distance (strength × influence)\nuniform float uPointerRadius;\nuniform vec4 uWaves[${MAX_WAVES}]; // x, y, ring radius, envelope (0 = inactive)\nuniform float uWaveStrength;\nuniform float uWaveWidth;\n\nout float vRadius; // device px\nout float vPointSize; // device px\n\nvoid main() {\n vec2 ij = markCell();\n vec2 rest = restPosition(ij);\n vec2 p = rest + wander(ij);\n\n vec2 d = rest - uPointer.xy;\n float dist = length(d);\n if (dist > 0.0 && dist < uPointerRadius) {\n float k = 1.0 - dist / uPointerRadius;\n p += d / dist * uPointer.z * k * k;\n }\n\n float grow = 0.0;\n for (int w = 0; w < ${MAX_WAVES}; w++) {\n vec4 wave = uWaves[w];\n if (wave.w <= 0.0) continue;\n vec2 dw = rest - wave.xy;\n float dd = length(dw);\n if (dd == 0.0) continue;\n float x = (dd - wave.z) / uWaveWidth;\n float ring = exp(-x * x) * wave.w;\n p += dw / dd * uWaveStrength * ring;\n grow += ring;\n }\n\n vRadius = uSize * (1.0 + ${WAVE_GROW.toFixed(3)} * grow) * uDpr;\n vPointSize = 2.0 * vRadius + 2.0; // room for the antialiased edge\n gl_PointSize = vPointSize;\n gl_Position = toClip(p);\n}`;\n\nconst FRAGMENT = `#version 300 es\nprecision highp float;\n\nuniform vec4 uColor; // straight RGBA, opacity applied\nin float vRadius;\nin float vPointSize;\nout vec4 outColor;\n\nvoid main() {\n float dist = length(gl_PointCoord - 0.5) * vPointSize;\n float a = uColor.a * clamp(vRadius + 0.5 - dist, 0.0, 1.0);\n outColor = vec4(uColor.rgb * a, a); // premultiplied; the engine blends it over the background\n}`;\n\nconst UNIFORMS = [\n ...GRID_UNIFORMS, 'uSize', 'uPointer', 'uPointerRadius', 'uWaves', 'uWaveStrength', 'uWaveWidth', 'uColor',\n] as const;\n\n/** Every dot is one GL point; the vertex shader places it, so the CPU only sets uniforms. */\nexport function createDotsWebGL(gl: WebGL2RenderingContext, initial: DotsOptions): StyleRenderer<DotsOptions> {\n let options = resolveDotsOptions(initial);\n const waves = createWaveList();\n const waveData = new Float32Array(MAX_WAVES * 4);\n let clock = 0;\n\n const program = createProgram(gl, VERTEX, FRAGMENT);\n const uniforms = program ? getUniforms(gl, program, UNIFORMS) : null;\n\n return {\n update(next) {\n options = resolveDotsOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, options.waveStrength !== 0);\n if (!program || !uniforms) return waves.waves.length > 0; // context lost during setup\n\n waves.pack(waveData, options.waveSpeed, options.waveDuration);\n\n const grid = gridLayout(frame.width, frame.height, options.spacing);\n const color = parseColor(options.color);\n\n gl.useProgram(program);\n setGridUniforms(gl, uniforms, grid, frame, options.spacing, clock, options.jitter);\n gl.uniform1f(uniforms.uSize, options.size);\n gl.uniform3f(uniforms.uPointer, frame.pointer.x, frame.pointer.y, options.pointerStrength * frame.pointer.influence);\n gl.uniform1f(uniforms.uPointerRadius, options.pointerRadius);\n gl.uniform4fv(uniforms.uWaves, waveData);\n gl.uniform1f(uniforms.uWaveStrength, options.waveStrength);\n gl.uniform1f(uniforms.uWaveWidth, options.waveWidth);\n gl.uniform4f(uniforms.uColor, color[0], color[1], color[2], color[3] * options.opacity);\n gl.drawArrays(gl.POINTS, 0, grid.cols * grid.rows);\n return waves.waves.length > 0;\n },\n destroy() {\n gl.deleteProgram(program);\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createDotsCanvas2D } from '../styles/dots/canvas2d';\nimport { dotsStyle } from '../styles/dots/definition';\nimport type { DotsOptions } from '../styles/dots/options';\nimport { createDotsWebGL } from '../styles/dots/webgl';\n\nexport type { DotsOptions };\n\n/** A grid of wandering dots, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const dots: StyleFactory<DotsOptions> = defineStyle({\n ...dotsStyle,\n renderers: [webglRenderer(createDotsWebGL), canvas2dRenderer(createDotsCanvas2D)],\n});\n","export interface PlusOptions {\n /** Colour of the signs. Any CSS colour. */\n color: string;\n /** Opacity of the signs, from `0` to `1`. Multiplies any alpha in the colour. */\n opacity: number;\n /** Length of each arm from the centre, in CSS pixels. */\n size: number;\n /** Stroke weight of the arms, in CSS pixels. */\n weight: number;\n /**\n * Distance between neighbouring signs in CSS pixels. The grid also keeps at least half of\n * this as empty space along every edge, so signs at the edges aren't clipped.\n */\n spacing: number;\n /** How far each sign wanders around its place, in CSS pixels. `0` = still. */\n jitter: number;\n /** How fast the signs wander, in cycles per second. `0` = still. */\n jitterSpeed: number;\n /**\n * How fully the signs turn to face the pointer while it's over the background, from `0` (not at all)\n * to `1` (an arm of every sign points straight at the pointer).\n */\n pointerAlign: number;\n /**\n * How smoothly signs turn, in seconds: about how long a sign takes to cover two thirds of a turn.\n * `0` = they snap to their new angle at once.\n */\n turnTime: number;\n /** How fast a click wave travels outwards, in CSS pixels per second. */\n waveSpeed: number;\n /** How fully signs on a click wave's crest turn to face the click, from `0` to `1`. */\n waveAlign: number;\n /** How much heavier a click wave makes the signs it passes: `1` doubles the weight on the crest. */\n waveWeight: number;\n /** Width of a click wave's ring, in CSS pixels. */\n waveWidth: number;\n /** How long a click wave lasts before it has faded out, in seconds. */\n waveDuration: number;\n}\n\nexport const plusDefaults: Readonly<PlusOptions> = Object.freeze({\n color: '#8b95a5',\n opacity: 0.6,\n size: 4,\n weight: 1.2,\n spacing: 28,\n jitter: 1,\n jitterSpeed: 0.35,\n pointerAlign: 1,\n turnTime: 0.25,\n waveSpeed: 520,\n waveAlign: 1,\n waveWeight: 1.5,\n waveWidth: 60,\n waveDuration: 1.8,\n});\n\n/** Options after clamping: what the renderers consume. */\nexport type ResolvedPlusOptions = PlusOptions;\n\nconst unit = (value: number) => Math.min(1, Math.max(0, value));\n\nexport function resolvePlusOptions(options: PlusOptions): ResolvedPlusOptions {\n return {\n ...options,\n opacity: unit(options.opacity),\n size: Math.max(0.5, options.size),\n weight: Math.max(0.1, options.weight),\n spacing: Math.max(4, options.spacing),\n jitter: Math.max(0, options.jitter),\n jitterSpeed: Math.max(0, options.jitterSpeed),\n pointerAlign: unit(options.pointerAlign),\n turnTime: Math.max(0, options.turnTime),\n waveSpeed: Math.max(1, options.waveSpeed),\n waveAlign: unit(options.waveAlign),\n waveWeight: Math.max(0, options.waveWeight),\n waveWidth: Math.max(1, options.waveWidth),\n waveDuration: Math.max(0.05, options.waveDuration),\n };\n}\n\n/** Clicks start a wave only if it would change something. */\nexport function wavesEnabled(options: ResolvedPlusOptions): boolean {\n return options.waveAlign !== 0 || options.waveWeight !== 0;\n}\n","// The plus-specific part of the motion model; the rest is shared with other\n// grid styles in shared/grid.ts.\n\n/** atan(r) for r in [-1, 1], within 1e-5 rad: much cheaper than Math.atan2. */\nfunction atanUnit(r: number): number {\n const r2 = r * r;\n return r * (0.99997726 + r2 * (-0.33262347 + r2 * (0.19354346 + r2 * (-0.11643287 + r2 * (0.05265332 - 0.0117212 * r2)))));\n}\n\n/**\n * The smallest turn that points one of a sign's arms along (dx, dy). A \"+\"\n * looks the same every 90°, so this is always within ±45°.\n */\nexport function facingAngle(dx: number, dy: number): number {\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (ax >= ay) return ax === 0 ? 0 : atanUnit(dy / dx);\n // Steeper than 45°: the vertical arm is closer, a quarter turn away from the horizontal one.\n return -atanUnit(dx / dy);\n}\n","import type { Frame } from '../../core/style';\nimport { MAX_WAVES, waveEnvelope, waveRing, type Grid, type Wave } from '../../shared/grid';\nimport { facingAngle } from './motion';\nimport type { ResolvedPlusOptions } from './options';\n\nconst QUARTER = Math.PI / 2;\n/** A sign has finished turning once its arm tips are this close to where they're heading, in CSS pixels. */\nconst SETTLED_PX = 0.05;\n\n/** The same turn, expressed within ±45° (a \"+\" looks the same every 90°). */\nfunction wrap(angle: number): number {\n return angle - QUARTER * Math.round(angle / QUARTER);\n}\n\n/**\n * Each sign's angle and wave-crest height, kept between frames so signs ease\n * towards the angle they want instead of jumping to it. Both renderers use it.\n */\nexport interface SignTurns {\n /** Angle (radians) and wave-crest height of every sign, row-major, as pairs. */\n readonly data: Float32Array<ArrayBuffer>;\n /** Whether `data` changed in the last update. */\n readonly changed: boolean;\n /** Whether any sign is still turning towards its target. */\n readonly settling: boolean;\n update(frame: Frame, options: ResolvedPlusOptions, grid: Grid, waves: readonly Wave[]): void;\n}\n\nexport function createSignTurns(): SignTurns {\n let data = new Float32Array(0);\n const waveData = new Float32Array(MAX_WAVES * 4);\n\n /** Work out each wave's ring radius and envelope once per frame instead of once per sign. */\n function packWaves(waves: readonly Wave[], speed: number, duration: number): void {\n for (let k = 0; k < waves.length; k++) {\n const wave = waves[k];\n waveData[k * 4] = wave.x;\n waveData[k * 4 + 1] = wave.y;\n waveData[k * 4 + 2] = speed * wave.age;\n waveData[k * 4 + 3] = waveEnvelope(wave.age, duration);\n }\n }\n let changed = false;\n let settling = false;\n // What the last update computed from: if none of it changes, neither do the angles.\n let lastX = NaN;\n let lastY = NaN;\n let lastAlign = NaN;\n let lastOriginX = NaN;\n let lastOriginY = NaN;\n let lastOptions: ResolvedPlusOptions | null = null;\n let hadWaves = false;\n\n return {\n get data() {\n return data;\n },\n get changed() {\n return changed;\n },\n get settling() {\n return settling;\n },\n update(frame, options, grid, waves) {\n const { cols, rows, originX, originY } = grid;\n const { spacing, waveSpeed, waveWidth, waveDuration, waveAlign } = options;\n const resized = data.length !== cols * rows * 2;\n if (resized) data = new Float32Array(cols * rows * 2);\n\n const align = options.pointerAlign * frame.pointer.influence;\n const { x: px, y: py } = frame.pointer;\n // Nothing is turning and nothing it depends on has moved: the angles are already right.\n // With no pointer, every sign is upright whatever the grid or options.\n const unchanged =\n !resized &&\n !settling &&\n !hadWaves &&\n waves.length === 0 &&\n align === lastAlign &&\n (align === 0 ||\n (px === lastX && py === lastY && originX === lastOriginX && originY === lastOriginY && options === lastOptions));\n hadWaves = waves.length > 0;\n if (unchanged) {\n changed = false;\n return;\n }\n lastX = px;\n lastY = py;\n lastAlign = align;\n lastOriginX = originX;\n lastOriginY = originY;\n lastOptions = options;\n\n // Each wave as x, y, ring radius, envelope. Further than 3 widths from its ring a wave is below e⁻⁹: skipped.\n const waveCount = waves.length;\n packWaves(waves, waveSpeed, waveDuration);\n const waveReach = 3 * waveWidth;\n const settled = SETTLED_PX / options.size;\n const ease = options.turnTime > 0 ? 1 - Math.exp(-frame.dt / options.turnTime) : 1;\n settling = false;\n\n for (let j = 0; j < rows; j++) {\n const restY = originY + j * spacing;\n for (let i = 0; i < cols; i++) {\n const restX = originX + i * spacing;\n\n let target = 0;\n // While the pointer is over the background, every sign turns to face it.\n if (align !== 0) target = align * facingAngle(restX - px, restY - py);\n\n let ring = 0;\n for (let w = 0; w < waveCount * 4; w += 4) {\n const dx = restX - waveData[w];\n const dy = restY - waveData[w + 1];\n const outer = waveData[w + 2] + waveReach;\n if (Math.abs(dx) > outer || Math.abs(dy) > outer) continue;\n const distance = Math.sqrt(dx * dx + dy * dy);\n if (Math.abs(distance - waveData[w + 2]) > waveReach) continue;\n const height = waveRing(distance, waveData[w + 2], waveWidth) * waveData[w + 3];\n ring += height;\n // On the crest, signs turn to face the click.\n target += waveAlign * Math.min(1, height) * facingAngle(dx, dy);\n }\n\n // Ease towards the target the short way round, so a sign never spins more than 45°.\n const k = (j * cols + i) * 2;\n const remaining = wrap(target - data[k]);\n if (Math.abs(remaining) < settled) {\n data[k] = wrap(target);\n } else {\n data[k] = wrap(data[k] + remaining * ease);\n settling = true;\n }\n data[k + 1] = ring;\n }\n }\n changed = true;\n },\n };\n}\n","import type { StyleRenderer } from '../../core/style';\nimport { createFloatBuffer, reserve, type FloatBuffer } from '../../shared/buffer';\nimport { createPhaseCache, createWaveList, gridLayout, TAU, wanderClock } from '../../shared/grid';\nimport { resolvePlusOptions, wavesEnabled, type PlusOptions } from './options';\nimport { createSignTurns } from './turns';\n\n/** Signs made heavier by waves are drawn in this many weight steps per unit of ring height. */\nconst WEIGHT_STEPS = 8;\n/** Ring heights beyond this are clamped (two overlapping wave crests). */\nconst MAX_WEIGHT_STEP = 2 * WEIGHT_STEPS;\n\n/**\n * Every sign's position computed on the CPU, with angles and weights from\n * SignTurns. All signs of one weight are a single path of round-capped lines,\n * stroked once.\n */\nexport function createPlusCanvas2D(ctx: CanvasRenderingContext2D, initial: PlusOptions): StyleRenderer<PlusOptions> {\n let options = resolvePlusOptions(initial);\n const waves = createWaveList();\n const phasesFor = createPhaseCache();\n const turns = createSignTurns();\n let clock = 0;\n\n // Signs as x, y, arm vector (dx, dy), one buffer per weight step; signs outside a wave all land in step 0.\n const weights = Array.from({ length: MAX_WEIGHT_STEP + 1 }, () => createFloatBuffer(512));\n\n function add(buffer: FloatBuffer, x: number, y: number, dx: number, dy: number): void {\n const data = reserve(buffer, 4);\n data[buffer.length++] = x;\n data[buffer.length++] = y;\n data[buffer.length++] = dx;\n data[buffer.length++] = dy;\n }\n\n function stroke(buffer: FloatBuffer, weight: number): void {\n const { data, length } = buffer;\n ctx.lineWidth = weight;\n ctx.beginPath();\n for (let k = 0; k < length; k += 4) {\n const x = data[k];\n const y = data[k + 1];\n const dx = data[k + 2];\n const dy = data[k + 3];\n // Two arms: along (dx, dy) and along its perpendicular (-dy, dx).\n ctx.moveTo(x - dx, y - dy);\n ctx.lineTo(x + dx, y + dy);\n ctx.moveTo(x + dy, y - dx);\n ctx.lineTo(x - dy, y + dx);\n }\n ctx.stroke();\n }\n\n return {\n update(next) {\n options = resolvePlusOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, wavesEnabled(options));\n\n const { spacing, size, jitter } = options;\n const grid = gridLayout(frame.width, frame.height, spacing);\n const { cols, rows, originX, originY } = grid;\n const wander = phasesFor(cols, rows);\n const { sx, cx, sy, cy } = wanderClock(clock);\n turns.update(frame, options, grid, waves.waves);\n const turn = turns.data;\n for (const buffer of weights) buffer.length = 0;\n\n for (let j = 0; j < rows; j++) {\n const restY = originY + j * spacing;\n for (let i = 0; i < cols; i++) {\n const k = j * cols + i;\n const w = k * 4;\n const x = originX + i * spacing + jitter * (sx * wander[w] + cx * wander[w + 1]);\n const y = restY + jitter * (cy * wander[w + 2] - sy * wander[w + 3]);\n const angle = turn[k * 2];\n const step = Math.min(MAX_WEIGHT_STEP, Math.round(turn[k * 2 + 1] * WEIGHT_STEPS));\n if (angle === 0) {\n add(weights[step], x, y, size, 0);\n } else {\n // Angles stay within ±45°, where these short series are exact to ~1e-6.\n const a2 = angle * angle;\n const cos = 1 - a2 * (0.5 - a2 * (1 / 24 - a2 * (1 / 720 - a2 / 40320)));\n const sin = angle * (1 - a2 * (1 / 6 - a2 * (1 / 120 - a2 / 5040)));\n add(weights[step], x, y, size * cos, size * sin);\n }\n }\n }\n\n ctx.globalAlpha = options.opacity;\n ctx.strokeStyle = options.color;\n ctx.lineCap = 'round';\n for (let step = 0; step <= MAX_WEIGHT_STEP; step++) {\n if (weights[step].length > 0) {\n stroke(weights[step], options.weight * (1 + (options.waveWeight * step) / WEIGHT_STEPS));\n }\n }\n return waves.waves.length > 0 || turns.settling;\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { wanderIdleFps } from '../../shared/grid';\nimport { plusDefaults, type PlusOptions } from './options';\n\n/**\n * A grid of \"+\" signs that wander gently around their places. While the\n * pointer is over the background, every sign turns smoothly so an arm points\n * at it. Clicks send out a wave that turns the signs on its crest to face the\n * click and makes them heavier as it passes.\n */\nexport const plusStyle: StyleBase<PlusOptions> = {\n name: 'plus',\n defaults: plusDefaults,\n animates: (options) => options.jitter > 0 && options.jitterSpeed > 0,\n // Same slow, sub-pixel wander as dots: it rarely needs the engine's full idle frame rate.\n idleFps: wanderIdleFps,\n};\n","import { parseColor } from '../../core/color';\nimport type { StyleRenderer } from '../../core/style';\nimport { createProgram, getUniforms } from '../../core/webgl';\nimport { createWaveList, gridLayout, TAU } from '../../shared/grid';\nimport { GRID_UNIFORMS, GRID_VERTEX_GLSL, setGridUniforms } from '../../shared/grid-webgl';\nimport { resolvePlusOptions, wavesEnabled, type PlusOptions } from './options';\nimport { createSignTurns } from './turns';\n\n// Wander mirrors canvas2d.ts; each sign's angle and wave height come from SignTurns (aTurn).\nconst VERTEX = `#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec2 aTurn; // angle (radians), wave-crest height\n\n${GRID_VERTEX_GLSL}\nuniform float uSize; // arm length, CSS px\nuniform float uWeight; // stroke weight, CSS px\nuniform float uWaveWeight;\n\nout vec2 vAxis; // cos, sin of the sign's angle\nout float vArm; // device px\nout float vHalfWeight; // device px\nout float vPointSize; // device px\n\nvoid main() {\n vec2 ij = markCell();\n vec2 p = restPosition(ij) + wander(ij);\n\n vAxis = vec2(cos(aTurn.x), sin(aTurn.x));\n vArm = uSize * uDpr;\n vHalfWeight = 0.5 * uWeight * (1.0 + uWaveWeight * min(aTurn.y, 2.0)) * uDpr;\n vPointSize = 2.0 * (vArm + vHalfWeight) + 2.0; // room for the antialiased edge\n gl_PointSize = vPointSize;\n gl_Position = toClip(p);\n}`;\n\nconst FRAGMENT = `#version 300 es\nprecision highp float;\n\nuniform vec4 uColor; // straight RGBA, opacity applied\nin vec2 vAxis;\nin float vArm;\nin float vHalfWeight;\nin float vPointSize;\nout vec4 outColor;\n\n// Distance to a round-capped arm of half-length vArm along x.\nfloat arm(vec2 q) {\n return length(vec2(max(abs(q.x) - vArm, 0.0), q.y)) - vHalfWeight;\n}\n\nvoid main() {\n vec2 p = (gl_PointCoord - 0.5) * vPointSize;\n vec2 q = vec2(dot(p, vAxis), dot(p, vec2(-vAxis.y, vAxis.x))); // into the sign's frame\n float d = min(arm(q), arm(q.yx));\n float a = uColor.a * clamp(0.5 - d, 0.0, 1.0);\n outColor = vec4(uColor.rgb * a, a); // premultiplied; the engine blends it over the background\n}`;\n\nconst UNIFORMS = [...GRID_UNIFORMS, 'uSize', 'uWeight', 'uWaveWeight', 'uColor'] as const;\n\n/**\n * Every sign is one GL point: the vertex shader places it and the fragment\n * shader draws the cross. Angles are eased on the CPU (SignTurns) and uploaded\n * only on frames where they changed.\n */\nexport function createPlusWebGL(gl: WebGL2RenderingContext, initial: PlusOptions): StyleRenderer<PlusOptions> {\n let options = resolvePlusOptions(initial);\n const waves = createWaveList();\n const turns = createSignTurns();\n let clock = 0;\n let uploaded = -1; // sign count the buffer was last sized for\n\n const program = createProgram(gl, VERTEX, FRAGMENT);\n const uniforms = program ? getUniforms(gl, program, UNIFORMS) : null;\n const vao = gl.createVertexArray();\n const buffer = gl.createBuffer();\n gl.bindVertexArray(vao);\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n gl.bindVertexArray(null);\n\n return {\n update(next) {\n options = resolvePlusOptions(next);\n },\n render(frame) {\n if (!frame.reducedMotion) clock += frame.dt * options.jitterSpeed * TAU;\n waves.advance(frame, options.waveDuration, wavesEnabled(options));\n const grid = gridLayout(frame.width, frame.height, options.spacing);\n turns.update(frame, options, grid, waves.waves);\n const busy = waves.waves.length > 0 || turns.settling;\n if (!program || !uniforms) return busy; // context lost during setup\n\n const count = grid.cols * grid.rows;\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n if (uploaded !== count) {\n gl.bufferData(gl.ARRAY_BUFFER, turns.data, gl.DYNAMIC_DRAW);\n uploaded = count;\n } else if (turns.changed) {\n gl.bufferSubData(gl.ARRAY_BUFFER, 0, turns.data);\n }\n\n const color = parseColor(options.color);\n gl.useProgram(program);\n setGridUniforms(gl, uniforms, grid, frame, options.spacing, clock, options.jitter);\n gl.uniform1f(uniforms.uSize, options.size);\n gl.uniform1f(uniforms.uWeight, options.weight);\n gl.uniform1f(uniforms.uWaveWeight, options.waveWeight);\n gl.uniform4f(uniforms.uColor, color[0], color[1], color[2], color[3] * options.opacity);\n gl.bindVertexArray(vao);\n gl.drawArrays(gl.POINTS, 0, count);\n gl.bindVertexArray(null);\n return busy;\n },\n destroy() {\n gl.deleteProgram(program);\n gl.deleteBuffer(buffer);\n gl.deleteVertexArray(vao);\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createPlusCanvas2D } from '../styles/plus/canvas2d';\nimport { plusStyle } from '../styles/plus/definition';\nimport type { PlusOptions } from '../styles/plus/options';\nimport { createPlusWebGL } from '../styles/plus/webgl';\n\nexport type { PlusOptions };\n\n/** A grid of \"+\" signs, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const plus: StyleFactory<PlusOptions> = defineStyle({\n ...plusStyle,\n renderers: [webglRenderer(createPlusWebGL), canvas2dRenderer(createPlusCanvas2D)],\n});\n","import { parseColor } from '../../core/color';\nimport type { ResolvedFluidOptions } from './options';\n\nexport type RGB = readonly [number, number, number];\n\n/** HSL (all in 0–1) to straight RGB. */\nfunction hslToRgb(h: number, s: number, l: number): RGB {\n if (s === 0) return [l, l, l];\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n const channel = (t: number) => {\n let k = t % 1;\n if (k < 0) k += 1;\n if (k < 1 / 6) return p + (q - p) * 6 * k;\n if (k < 1 / 2) return q;\n if (k < 2 / 3) return p + (q - p) * (2 / 3 - k) * 6;\n return p;\n };\n return [channel(h + 1 / 3), channel(h), channel(h - 1 / 3)];\n}\n\n/** The colour of a splash made at `clock` seconds: the fixed colour, or the cycling hue. */\nexport function splatColor(options: ResolvedFluidOptions, clock: number): RGB {\n if (options.color) {\n const [r, g, b, a] = parseColor(options.color);\n return [r * a, g * a, b * a];\n }\n const step = Math.floor(clock * options.colorSpeed);\n const hue = (((0.55 + step * 0.61803398875) % 1) + 1) % 1;\n return hslToRgb(hue, 1, 0.5);\n}\n","export interface FluidOptions {\n /**\n * Colour of the smoke, as any CSS colour. `null` (the default) cycles through\n * hues over time; set a colour to keep every splat that colour.\n */\n color: string | null;\n /** How many times per second the smoke picks a new hue while `color` is `null`. */\n colorSpeed: number;\n /** Opacity of the smoke, from `0` to `1`. Multiplies any alpha in `color`. */\n opacity: number;\n /** How strongly the fluid curls back on itself: vorticity confinement. `0` = no swirl. */\n curl: number;\n /** How hard pointer movement stirs the fluid. `0` = the pointer only adds dye. */\n force: number;\n /** Radius of each splash, in CSS pixels. */\n radius: number;\n /** Roughly how long the smoke takes to fade out, in seconds. */\n fade: number;\n /**\n * Simulation grid size: the longer side of the velocity/dye field, in cells.\n * Higher is smoother and more detailed, at more CPU or GPU cost. The Canvas 2D\n * fallback runs the whole simulation at this resolution.\n */\n resolution: number;\n /** Light the smoke from the dye's own gradients, for a sense of depth. */\n shading: boolean;\n}\n\nexport const fluidDefaults: Readonly<FluidOptions> = Object.freeze({\n color: null,\n colorSpeed: 10,\n opacity: 0.85,\n curl: 10,\n force: 6000,\n radius: 75,\n fade: 0.3,\n resolution: 128,\n shading: true,\n});\n\n/** Options after clamping: what the simulation and the renderers consume. */\nexport type ResolvedFluidOptions = FluidOptions;\n\nconst clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nexport function resolveFluidOptions(options: FluidOptions): ResolvedFluidOptions {\n return {\n ...options,\n colorSpeed: Math.max(0, options.colorSpeed),\n opacity: clamp(options.opacity, 0, 1),\n curl: clamp(options.curl, 0, 100),\n force: Math.max(0, options.force),\n radius: Math.max(2, options.radius),\n fade: Math.max(0.2, options.fade),\n resolution: Math.round(clamp(options.resolution, 48, 192)),\n };\n}\n","// Shared by the GPU and CPU simulations, so both produce the same kind of smoke.\n\n/** How much dye one splash adds at its centre. */\nexport const DYE_INTENSITY = 0.15;\n/** Seconds for the velocity field to lose about two thirds of its strength. */\nexport const VELOCITY_FADE = 0.5;\n/** How much of the previous pressure field is kept between frames, as in the reference. */\nexport const PRESSURE_RETENTION = 0.1;\n/** Pressure solve iterations (the CPU fallback uses fewer to stay cheap). */\nexport const PRESSURE_ITERATIONS = 20;\nexport const CPU_PRESSURE_ITERATIONS = 14;\n/** The initial burst is this fraction of the pointer force: just enough to set the smoke moving. */\nexport const BURST_FORCE = 0.003;\n/** The initial burst covers this many times the pointer splash radius. */\nexport const BURST_RADIUS = 2.2;\n/** The initial burst adds this many times the usual dye, so it reads on an otherwise empty canvas. */\nexport const BURST_DYE = 2.2;\n/** Seconds after the last splash before the extra idle fade begins. */\nexport const IDLE_DELAY = 0.5;\n/** Effective dye fade time while the pointer is idle, in seconds. */\nexport const IDLE_DECAY = 0.7;\n/** Seconds after the last splash when the field is cleared completely. */\nexport const IDLE_CLEAR = 3.5;\n\n/** The dye texture is this many times the simulation grid, up to a cap. */\nexport const DYE_SCALE = 8;\nexport const MAX_DYE_RESOLUTION = 1440;\n","import type { RGB } from './color';\nimport type { ResolvedFluidOptions } from './options';\nimport { CPU_PRESSURE_ITERATIONS, DYE_INTENSITY, VELOCITY_FADE } from './settings';\n\n/**\n * The CPU fluid field: a stable-fluids solver at `resolution` cells on its longer\n * side. The Canvas 2D renderer draws it upscaled; the WebGL renderer runs the\n * same steps in shaders instead. Velocities are in grid cells per second; dye\n * channels are straight colour densities.\n */\nexport interface FluidSimulation {\n readonly width: number;\n readonly height: number;\n readonly dyeR: Float32Array;\n readonly dyeG: Float32Array;\n readonly dyeB: Float32Array;\n /** Add a splash of colour and velocity at `(x, y)`, in CSS pixels of a view of `viewWidth` × `viewHeight`. */\n splat(\n x: number,\n y: number,\n vx: number,\n vy: number,\n color: RGB,\n radius: number,\n viewWidth: number,\n viewHeight: number,\n ): void;\n /** Advance the simulation by `dt` seconds. */\n step(dt: number, options: ResolvedFluidOptions): void;\n /** Clear the velocity and dye fields. */\n clear(): void;\n}\n\nconst clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nexport function createFluidSimulation(width: number, height: number): FluidSimulation {\n const w = width;\n const h = height;\n const cells = w * h;\n\n let u = new Float32Array(cells);\n let v = new Float32Array(cells);\n let uNext = new Float32Array(cells);\n let vNext = new Float32Array(cells);\n let dyeR = new Float32Array(cells);\n let dyeG = new Float32Array(cells);\n let dyeB = new Float32Array(cells);\n let dyeRNext = new Float32Array(cells);\n let dyeGNext = new Float32Array(cells);\n let dyeBNext = new Float32Array(cells);\n const divergence = new Float32Array(cells);\n const curl = new Float32Array(cells);\n let pressure = new Float32Array(cells);\n let pressureNext = new Float32Array(cells);\n\n /** Bilinear sample of a field at grid coordinates, clamped at the edges. */\n function sample(field: Float32Array, x: number, y: number): number {\n const gx = clamp(x, 0, w - 1);\n const gy = clamp(y, 0, h - 1);\n const i0 = Math.floor(gx);\n const j0 = Math.floor(gy);\n const i1 = Math.min(i0 + 1, w - 1);\n const j1 = Math.min(j0 + 1, h - 1);\n const fx = gx - i0;\n const fy = gy - j0;\n const top = field[j0 * w + i0] * (1 - fx) + field[j0 * w + i1] * fx;\n const bottom = field[j1 * w + i0] * (1 - fx) + field[j1 * w + i1] * fx;\n return top * (1 - fy) + bottom * fy;\n }\n\n /** Zero the velocity along the walls, so the field doesn't leak. */\n function walls(): void {\n for (let i = 0; i < w; i++) {\n u[i] = 0;\n u[(h - 1) * w + i] = 0;\n v[i] = 0;\n v[(h - 1) * w + i] = 0;\n }\n for (let j = 0; j < h; j++) {\n u[j * w] = 0;\n u[j * w + w - 1] = 0;\n v[j * w] = 0;\n v[j * w + w - 1] = 0;\n }\n }\n\n function addCurl(dt: number, amount: number): void {\n for (let j = 1; j < h - 1; j++) {\n for (let i = 1; i < w - 1; i++) {\n const k = j * w + i;\n curl[k] = 0.5 * (v[k + 1] - v[k - 1] - (u[k + w] - u[k - w]));\n }\n }\n for (let j = 1; j < h - 1; j++) {\n for (let i = 1; i < w - 1; i++) {\n const k = j * w + i;\n const forceX = 0.5 * (Math.abs(curl[k + 1]) - Math.abs(curl[k - 1]));\n const forceY = 0.5 * (Math.abs(curl[k - w]) - Math.abs(curl[k + w]));\n const length = Math.hypot(forceX, forceY) + 1e-4;\n const strength = (amount * curl[k] * dt) / length;\n u[k] = clamp(u[k] + forceX * strength, -1000, 1000);\n v[k] = clamp(v[k] + forceY * strength, -1000, 1000);\n }\n }\n }\n\n function project(dt: number, options: ResolvedFluidOptions): void {\n if (options.curl > 0) addCurl(dt, options.curl);\n for (let j = 1; j < h - 1; j++) {\n for (let i = 1; i < w - 1; i++) {\n const k = j * w + i;\n divergence[k] = 0.5 * (u[k + 1] - u[k - 1] + v[k + w] - v[k - w]);\n }\n }\n pressure.fill(0);\n for (let iteration = 0; iteration < CPU_PRESSURE_ITERATIONS; iteration++) {\n for (let j = 1; j < h - 1; j++) {\n for (let i = 1; i < w - 1; i++) {\n const k = j * w + i;\n pressureNext[k] =\n (pressure[k - 1] + pressure[k + 1] + pressure[k - w] + pressure[k + w] - divergence[k]) * 0.25;\n }\n }\n [pressure, pressureNext] = [pressureNext, pressure];\n }\n for (let j = 1; j < h - 1; j++) {\n for (let i = 1; i < w - 1; i++) {\n const k = j * w + i;\n u[k] -= 0.5 * (pressure[k + 1] - pressure[k - 1]);\n v[k] -= 0.5 * (pressure[k + w] - pressure[k - w]);\n }\n }\n walls();\n }\n\n function advectVelocity(dt: number, decay: number): void {\n for (let j = 0; j < h; j++) {\n for (let i = 0; i < w; i++) {\n const k = j * w + i;\n const sx = i - u[k] * dt;\n const sy = j - v[k] * dt;\n uNext[k] = sample(u, sx, sy) * decay;\n vNext[k] = sample(v, sx, sy) * decay;\n }\n }\n [u, uNext] = [uNext, u];\n [v, vNext] = [vNext, v];\n walls();\n }\n\n function advectDye(dt: number, decay: number): void {\n for (let j = 0; j < h; j++) {\n for (let i = 0; i < w; i++) {\n const k = j * w + i;\n const sx = i - u[k] * dt;\n const sy = j - v[k] * dt;\n dyeRNext[k] = sample(dyeR, sx, sy) * decay;\n dyeGNext[k] = sample(dyeG, sx, sy) * decay;\n dyeBNext[k] = sample(dyeB, sx, sy) * decay;\n }\n }\n [dyeR, dyeRNext] = [dyeRNext, dyeR];\n [dyeG, dyeGNext] = [dyeGNext, dyeG];\n [dyeB, dyeBNext] = [dyeBNext, dyeB];\n }\n\n return {\n width: w,\n height: h,\n get dyeR() {\n return dyeR;\n },\n get dyeG() {\n return dyeG;\n },\n get dyeB() {\n return dyeB;\n },\n splat(x, y, vx, vy, color, radius, viewWidth, viewHeight) {\n const aspect = Math.max(1, viewWidth) / Math.max(1, viewHeight);\n const sigma = Math.max(0.0005, radius / viewHeight);\n const cx = x / Math.max(1, viewWidth);\n const cy = y / Math.max(1, viewHeight);\n const reachX = (sigma / aspect) * w * 3;\n const reachY = sigma * h * 3;\n const x0 = Math.max(0, Math.floor(cx * w - reachX));\n const x1 = Math.min(w - 1, Math.ceil(cx * w + reachX));\n const y0 = Math.max(0, Math.floor(cy * h - reachY));\n const y1 = Math.min(h - 1, Math.ceil(cy * h + reachY));\n // Velocities are in simulation texels per second, which is cells per second here.\n const velocityX = clamp(vx, -1000, 1000);\n const velocityY = clamp(vy, -1000, 1000);\n const sigma2 = sigma * sigma;\n for (let j = y0; j <= y1; j++) {\n const ny = (j + 0.5) / h;\n const dy = ny - cy;\n for (let i = x0; i <= x1; i++) {\n const nx = (i + 0.5) / w;\n const dx = (nx - cx) * aspect;\n const distance = dx * dx + dy * dy;\n if (distance > sigma2 * 9) continue;\n const falloff = Math.exp(-distance / sigma2);\n const k = j * w + i;\n u[k] = clamp(u[k] + velocityX * falloff, -1000, 1000);\n v[k] = clamp(v[k] + velocityY * falloff, -1000, 1000);\n dyeR[k] += color[0] * DYE_INTENSITY * falloff;\n dyeG[k] += color[1] * DYE_INTENSITY * falloff;\n dyeB[k] += color[2] * DYE_INTENSITY * falloff;\n }\n }\n },\n step(dt, options) {\n const stepTime = Math.min(dt, 1 / 30);\n if (stepTime <= 0) return;\n project(stepTime, options);\n advectVelocity(stepTime, 1 / (1 + stepTime / VELOCITY_FADE));\n advectDye(stepTime, 1 / (1 + stepTime / options.fade));\n },\n clear() {\n for (const field of [u, v, uNext, vNext, dyeR, dyeG, dyeB, dyeRNext, dyeGNext, dyeBNext, pressure, pressureNext, divergence, curl]) {\n field.fill(0);\n }\n },\n };\n}\n","/** Grid size for a view: the longer side gets `resolution` cells. */\nexport function simulationSize(\n resolution: number,\n width: number,\n height: number,\n): { width: number; height: number } {\n const aspect = Math.max(1, width) / Math.max(1, height);\n const long = Math.max(16, Math.round(resolution));\n if (aspect >= 1) return { width: long, height: Math.max(12, Math.round(long / aspect)) };\n return { width: Math.max(12, Math.round(long * aspect)), height: long };\n}\n","import type { Frame, StyleRenderer } from '../../core/style';\nimport { splatColor, type RGB } from './color';\nimport { resolveFluidOptions, type FluidOptions } from './options';\nimport { BURST_DYE, BURST_FORCE, BURST_RADIUS, IDLE_CLEAR, IDLE_DECAY, IDLE_DELAY } from './settings';\nimport { createFluidSimulation, type FluidSimulation } from './simulation';\nimport { simulationSize } from './size';\n\nconst TAU = Math.PI * 2;\n\n/**\n * The CPU fallback: the same stable-fluids simulation as the WebGL renderer,\n * on a small grid, upscaled as one image. It is softer than the GPU version but\n * keeps the style working without WebGL2 (or the float render-target extension).\n */\nexport function createFluidCanvas2D(ctx: CanvasRenderingContext2D, initial: FluidOptions): StyleRenderer<FluidOptions> {\n let options = resolveFluidOptions(initial);\n let sim: FluidSimulation | null = null;\n let image: ImageData | null = null;\n let target: HTMLCanvasElement | null = null;\n let targetCtx: CanvasRenderingContext2D | null = null;\n let builtWidth = 0;\n let builtHeight = 0;\n let builtResolution = -1;\n\n let clock = 0;\n let active = 0;\n let idleTime = 0;\n let lastX = 0;\n let lastY = 0;\n let wasInside = false;\n let burstPending = true;\n\n function allocate(width: number, height: number): void {\n const grid = simulationSize(options.resolution, width, height);\n sim = createFluidSimulation(grid.width, grid.height);\n target = document.createElement('canvas');\n target.width = grid.width;\n target.height = grid.height;\n targetCtx = target.getContext('2d');\n image = targetCtx?.createImageData(grid.width, grid.height) ?? null;\n builtWidth = width;\n builtHeight = height;\n builtResolution = options.resolution;\n burstPending = true;\n }\n\n function wake(): void {\n active = Math.max(active, IDLE_CLEAR + 0.5);\n idleTime = 0;\n }\n\n function splatAt(\n frame: Frame,\n x: number,\n y: number,\n vx: number,\n vy: number,\n colour: RGB,\n radius: number,\n ): void {\n sim?.splat(x, y, vx, vy, colour, radius, frame.width, frame.height);\n }\n\n function burst(frame: Frame): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * BURST_DYE, colour[1] * BURST_DYE, colour[2] * BURST_DYE];\n const angle = Math.random() * TAU;\n const speed = options.force * BURST_FORCE;\n splatAt(\n frame,\n frame.width * (0.34 + Math.random() * 0.18),\n frame.height * (0.4 + Math.random() * 0.2),\n Math.cos(angle) * speed,\n Math.sin(angle) * speed,\n dye,\n options.radius * BURST_RADIUS,\n );\n wake();\n }\n\n function click(frame: Frame, x: number, y: number): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * 10, colour[1] * 10, colour[2] * 10];\n const dx = 10 * (Math.random() - 0.5);\n const dy = 30 * (Math.random() - 0.5);\n splatAt(frame, x, y, dx, dy, dye, options.radius);\n wake();\n }\n\n function draw(frame: Frame): void {\n if (!sim || !image || !target || !targetCtx) return;\n const { dyeR, dyeG, dyeB } = sim;\n const data = image.data;\n for (let k = 0; k < dyeR.length; k++) {\n const r = Math.min(1, Math.max(0, dyeR[k]));\n const g = Math.min(1, Math.max(0, dyeG[k]));\n const b = Math.min(1, Math.max(0, dyeB[k]));\n const density = Math.max(r, Math.max(g, b));\n const scale = density > 0.0001 ? 255 / density : 0;\n const o = k * 4;\n data[o] = Math.round(r * scale);\n data[o + 1] = Math.round(g * scale);\n data[o + 2] = Math.round(b * scale);\n data[o + 3] = Math.round(density * 255);\n }\n targetCtx.putImageData(image, 0, 0);\n ctx.globalAlpha = options.opacity;\n ctx.imageSmoothingEnabled = true;\n ctx.drawImage(target, 0, 0, frame.width, frame.height);\n ctx.globalAlpha = 1;\n }\n\n return {\n update(next) {\n options = resolveFluidOptions(next);\n },\n render(frame) {\n if (\n !sim ||\n frame.width !== builtWidth ||\n frame.height !== builtHeight ||\n options.resolution !== builtResolution\n ) {\n allocate(frame.width, frame.height);\n }\n\n if (frame.reducedMotion) {\n // One static splash, then hold it: no simulation steps and no pointer splats.\n if (burstPending) {\n burstPending = false;\n burst(frame);\n }\n draw(frame);\n return false;\n }\n\n const dt = Math.min(frame.dt, 1 / 60);\n const { pointer } = frame;\n\n if (burstPending) {\n burstPending = false;\n burst(frame);\n }\n\n if (pointer.influence > 0) {\n if (wasInside) {\n const moveX = pointer.x - lastX;\n const moveY = pointer.y - lastY;\n const dx = moveX / Math.max(1, frame.width);\n const dy = moveY / Math.max(1, frame.height);\n // Like a real mousemove stream: don't keep adding dye to a resting pointer.\n if (Math.hypot(moveX, moveY) > 0.5) {\n const colour = splatColor(options, clock);\n const strength = options.force * pointer.influence;\n splatAt(frame, pointer.x, pointer.y, dx * strength, dy * strength, colour, options.radius);\n wake();\n }\n }\n lastX = pointer.x;\n lastY = pointer.y;\n wasInside = true;\n } else {\n wasInside = false;\n }\n\n for (const clickPoint of frame.clicks) click(frame, clickPoint.x, clickPoint.y);\n\n if (dt > 0) {\n idleTime += dt;\n if (idleTime >= IDLE_CLEAR) {\n sim?.clear();\n idleTime = 0;\n active = 0;\n draw(frame);\n return false;\n }\n const effective =\n idleTime > IDLE_DELAY ? { ...options, fade: Math.min(options.fade, IDLE_DECAY) } : options;\n sim?.step(dt, effective);\n clock += dt;\n active = Math.max(0, active - dt);\n }\n\n draw(frame);\n return active > 0;\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { fluidDefaults, type FluidOptions } from './options';\n\n/**\n * A GPU fluid simulation: pointer movement injects velocity and dye, the dye is\n * advected into curling plumes, and clicks send out a burst. A gentle splash\n * plays when the background appears; otherwise it is still until stirred.\n */\nexport const fluidStyle: StyleBase<FluidOptions> = {\n name: 'fluid',\n defaults: fluidDefaults,\n // Nothing animates on its own: the initial burst and every reaction keep the\n // engine awake by returning true from render() until the smoke has settled.\n animates: () => false,\n};\n","import type { Frame, StyleRenderer } from '../../core/style';\nimport { createProgram, getUniforms } from '../../core/webgl';\nimport { splatColor, type RGB } from './color';\nimport { resolveFluidOptions, type FluidOptions } from './options';\nimport {\n BURST_DYE,\n BURST_FORCE,\n BURST_RADIUS,\n DYE_INTENSITY,\n DYE_SCALE,\n IDLE_CLEAR,\n IDLE_DECAY,\n IDLE_DELAY,\n MAX_DYE_RESOLUTION,\n PRESSURE_ITERATIONS,\n PRESSURE_RETENTION,\n VELOCITY_FADE,\n} from './settings';\nimport { simulationSize } from './size';\n\nconst TAU = Math.PI * 2;\n\n// All passes are one full-screen triangle. Neighbouring texel coordinates are\n// worked out once in the vertex shader and interpolated.\nconst VERTEX = `#version 300 es\nprecision highp float;\n\nuniform vec2 uTexelSize;\n\nout vec2 vUv;\nout vec2 vL;\nout vec2 vR;\nout vec2 vT;\nout vec2 vB;\n\nvoid main() {\n vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));\n vUv = p;\n vL = vUv - vec2(uTexelSize.x, 0.0);\n vR = vUv + vec2(uTexelSize.x, 0.0);\n vT = vUv + vec2(0.0, uTexelSize.y);\n vB = vUv - vec2(0.0, uTexelSize.y);\n gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}`;\n\nconst SPLAT = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uTarget;\nuniform vec2 uPoint;\nuniform vec3 uColor;\nuniform float uRadius; // squared radius, in screens-heights\nuniform float uAspect;\n\nin vec2 vUv;\nout vec4 outColor;\n\nvoid main() {\n vec2 p = vUv - uPoint;\n p.x *= uAspect;\n vec3 splat = exp(-dot(p, p) / uRadius) * uColor;\n outColor = vec4(texture(uTarget, vUv).rgb + splat, 1.0);\n}`;\n\nconst ADVECTION = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uVelocity;\nuniform sampler2D uSource;\nuniform vec2 uTexelSize;\nuniform float uDt;\nuniform float uDissipation;\n\nin vec2 vUv;\nout vec4 outColor;\n\nvoid main() {\n vec2 coord = vUv - uDt * texture(uVelocity, vUv).xy * uTexelSize;\n outColor = texture(uSource, coord) / (1.0 + uDissipation * uDt);\n}`;\n\nconst DIVERGENCE = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uVelocity;\nuniform vec2 uTexelSize;\n\nin vec2 vUv;\nin vec2 vL;\nin vec2 vR;\nin vec2 vT;\nin vec2 vB;\nout vec4 outColor;\n\nvoid main() {\n float L = texture(uVelocity, vL).x;\n float R = texture(uVelocity, vR).x;\n float T = texture(uVelocity, vT).y;\n float B = texture(uVelocity, vB).y;\n vec2 C = texture(uVelocity, vUv).xy;\n if (vL.x < 0.0) L = -C.x;\n if (vR.x > 1.0) R = -C.x;\n if (vT.y > 1.0) T = -C.y;\n if (vB.y < 0.0) B = -C.y;\n outColor = vec4(0.5 * (R - L + T - B), 0.0, 0.0, 1.0);\n}`;\n\nconst CURL = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uVelocity;\nuniform vec2 uTexelSize;\n\nin vec2 vL;\nin vec2 vR;\nin vec2 vT;\nin vec2 vB;\nout vec4 outColor;\n\nvoid main() {\n float L = texture(uVelocity, vL).y;\n float R = texture(uVelocity, vR).y;\n float T = texture(uVelocity, vT).x;\n float B = texture(uVelocity, vB).x;\n outColor = vec4(0.5 * (R - L - T + B), 0.0, 0.0, 1.0);\n}`;\n\nconst VORTICITY = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uVelocity;\nuniform sampler2D uCurl;\nuniform vec2 uTexelSize;\nuniform float uDt;\nuniform float uStrength;\n\nin vec2 vUv;\nin vec2 vL;\nin vec2 vR;\nin vec2 vT;\nin vec2 vB;\nout vec4 outColor;\n\nvoid main() {\n float L = texture(uCurl, vL).x;\n float R = texture(uCurl, vR).x;\n float T = texture(uCurl, vT).x;\n float B = texture(uCurl, vB).x;\n float C = texture(uCurl, vUv).x;\n vec2 force = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L));\n force /= length(force) + 1e-4;\n force *= uStrength * C;\n force.y *= -1.0;\n vec2 velocity = texture(uVelocity, vUv).xy + force * uDt;\n outColor = vec4(clamp(velocity, vec2(-1000.0), vec2(1000.0)), 0.0, 1.0);\n}`;\n\nconst PRESSURE = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uPressure;\nuniform sampler2D uDivergence;\nuniform vec2 uTexelSize;\n\nin vec2 vUv;\nin vec2 vL;\nin vec2 vR;\nin vec2 vT;\nin vec2 vB;\nout vec4 outColor;\n\nvoid main() {\n float L = texture(uPressure, vL).x;\n float R = texture(uPressure, vR).x;\n float T = texture(uPressure, vT).x;\n float B = texture(uPressure, vB).x;\n float divergence = texture(uDivergence, vUv).x;\n outColor = vec4((L + R + T + B - divergence) * 0.25, 0.0, 0.0, 1.0);\n}`;\n\nconst GRADIENT = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uPressure;\nuniform sampler2D uVelocity;\nuniform vec2 uTexelSize;\n\nin vec2 vUv;\nin vec2 vL;\nin vec2 vR;\nin vec2 vT;\nin vec2 vB;\nout vec4 outColor;\n\nvoid main() {\n float L = texture(uPressure, vL).x;\n float R = texture(uPressure, vR).x;\n float T = texture(uPressure, vT).x;\n float B = texture(uPressure, vB).x;\n vec2 velocity = texture(uVelocity, vUv).xy - vec2(R - L, T - B);\n outColor = vec4(velocity, 0.0, 1.0);\n}`;\n\nconst CLEAR = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uTexture;\nuniform float uValue;\n\nin vec2 vUv;\nout vec4 outColor;\n\nvoid main() {\n outColor = vec4(uValue * texture(uTexture, vUv).rgb, 1.0);\n}`;\n\nconst DISPLAY = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uDye;\nuniform vec2 uTexelSize;\nuniform float uOpacity;\nuniform bool uShading;\n\nin vec2 vUv;\nin vec2 vL;\nin vec2 vR;\nin vec2 vT;\nin vec2 vB;\nout vec4 outColor;\n\nvoid main() {\n vec3 c = texture(uDye, vUv).rgb;\n if (uShading) {\n vec3 lc = texture(uDye, vL).rgb;\n vec3 rc = texture(uDye, vR).rgb;\n vec3 tc = texture(uDye, vT).rgb;\n vec3 bc = texture(uDye, vB).rgb;\n float dx = length(rc) - length(lc);\n float dy = length(tc) - length(bc);\n vec3 normal = normalize(vec3(dx, dy, length(uTexelSize)));\n float diffuse = clamp(dot(normal, vec3(0.0, 0.0, 1.0)) + 0.7, 0.7, 1.0);\n c *= diffuse;\n }\n vec3 colour = clamp(c, 0.0, 1.0);\n float alpha = clamp(max(colour.r, max(colour.g, colour.b)) * uOpacity, 0.0, 1.0);\n outColor = vec4(colour * uOpacity, alpha);\n}`;\n\ninterface FBO {\n texture: WebGLTexture;\n framebuffer: WebGLFramebuffer;\n width: number;\n height: number;\n}\n\ninterface DoubleFBO {\n read: FBO;\n write: FBO;\n swap(): void;\n}\n\ninterface Pass {\n program: WebGLProgram;\n uniforms: Record<string, WebGLUniformLocation | null>;\n}\n\nexport function createFluidWebGL(gl: WebGL2RenderingContext, initial: FluidOptions): StyleRenderer<FluidOptions> {\n if (!gl.getExtension('EXT_color_buffer_float')) {\n throw new Error('interactive-bg: fluid needs EXT_color_buffer_float');\n }\n\n let options = resolveFluidOptions(initial);\n\n function makePass(fragment: string, names: readonly string[]): Pass {\n const program = createProgram(gl, VERTEX, fragment);\n if (!program) throw new Error('interactive-bg: fluid could not create a shader program');\n return { program, uniforms: getUniforms(gl, program, names) };\n }\n\n const splatPass = makePass(SPLAT, ['uTarget', 'uPoint', 'uColor', 'uRadius', 'uAspect']);\n const advectionPass = makePass(ADVECTION, ['uVelocity', 'uSource', 'uDt', 'uDissipation', 'uTexelSize']);\n const divergencePass = makePass(DIVERGENCE, ['uVelocity', 'uTexelSize']);\n const curlPass = makePass(CURL, ['uVelocity', 'uTexelSize']);\n const vorticityPass = makePass(VORTICITY, ['uVelocity', 'uCurl', 'uDt', 'uStrength', 'uTexelSize']);\n const pressurePass = makePass(PRESSURE, ['uPressure', 'uDivergence', 'uTexelSize']);\n const gradientPass = makePass(GRADIENT, ['uPressure', 'uVelocity', 'uTexelSize']);\n const clearPass = makePass(CLEAR, ['uTexture', 'uValue']);\n const displayPass = makePass(DISPLAY, ['uDye', 'uOpacity', 'uShading', 'uTexelSize']);\n\n function createFBO(width: number, height: number): FBO {\n const texture = gl.createTexture();\n const framebuffer = gl.createFramebuffer();\n if (!texture || !framebuffer) throw new Error('interactive-bg: fluid could not allocate a render target');\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, width, height, 0, gl.RGBA, gl.HALF_FLOAT, null);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {\n throw new Error('interactive-bg: fluid render target is incomplete');\n }\n gl.viewport(0, 0, width, height);\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n return { texture, framebuffer, width, height };\n }\n\n function createDoubleFBO(width: number, height: number): DoubleFBO {\n const a = createFBO(width, height);\n const b = createFBO(width, height);\n const pair = {\n read: a,\n write: b,\n swap() {\n [pair.read, pair.write] = [pair.write, pair.read];\n },\n };\n return pair;\n }\n\n function deleteFBO(target: FBO): void {\n gl.deleteTexture(target.texture);\n gl.deleteFramebuffer(target.framebuffer);\n }\n\n let simWidth = 0;\n let simHeight = 0;\n let dyeWidth = 0;\n let dyeHeight = 0;\n let builtWidth = 0;\n let builtHeight = 0;\n let builtResolution = -1;\n let velocity: DoubleFBO;\n let dye: DoubleFBO;\n let pressure: DoubleFBO;\n let divergence: FBO;\n let curl: FBO;\n\n // Initialised below by allocate().\n velocity = createDoubleFBO(1, 1);\n dye = createDoubleFBO(1, 1);\n pressure = createDoubleFBO(1, 1);\n divergence = createFBO(1, 1);\n curl = createFBO(1, 1);\n\n function allocate(width: number, height: number): void {\n for (const target of [velocity.read, velocity.write, dye.read, dye.write, pressure.read, pressure.write, divergence, curl]) {\n deleteFBO(target);\n }\n const grid = simulationSize(options.resolution, width, height);\n const dyeGrid = simulationSize(\n Math.min(MAX_DYE_RESOLUTION, Math.max(256, options.resolution * DYE_SCALE)),\n width,\n height,\n );\n simWidth = grid.width;\n simHeight = grid.height;\n dyeWidth = dyeGrid.width;\n dyeHeight = dyeGrid.height;\n velocity = createDoubleFBO(simWidth, simHeight);\n dye = createDoubleFBO(dyeWidth, dyeHeight);\n pressure = createDoubleFBO(simWidth, simHeight);\n divergence = createFBO(simWidth, simHeight);\n curl = createFBO(simWidth, simHeight);\n burstPending = true;\n }\n\n function draw(pass: Pass, target: FBO): void {\n gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);\n gl.viewport(0, 0, target.width, target.height);\n gl.useProgram(pass.program);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n }\n\n function texture(unit: number, source: WebGLTexture): void {\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, source);\n }\n\n function splatVelocity(pointX: number, pointY: number, vx: number, vy: number, radius: number, aspect: number): void {\n const { uniforms, program } = splatPass;\n texture(0, velocity.read.texture);\n gl.useProgram(program);\n gl.uniform1i(uniforms.uTarget, 0);\n gl.uniform2f(uniforms.uPoint, pointX, pointY);\n gl.uniform3f(uniforms.uColor, vx, vy, 0);\n gl.uniform1f(uniforms.uRadius, radius * radius);\n gl.uniform1f(uniforms.uAspect, aspect);\n draw(splatPass, velocity.write);\n velocity.swap();\n }\n\n function splatDye(pointX: number, pointY: number, colour: RGB, radius: number, aspect: number): void {\n const { uniforms, program } = splatPass;\n texture(0, dye.read.texture);\n gl.useProgram(program);\n gl.uniform1i(uniforms.uTarget, 0);\n gl.uniform2f(uniforms.uPoint, pointX, pointY);\n gl.uniform3f(uniforms.uColor, colour[0] * DYE_INTENSITY, colour[1] * DYE_INTENSITY, colour[2] * DYE_INTENSITY);\n gl.uniform1f(uniforms.uRadius, radius * radius);\n gl.uniform1f(uniforms.uAspect, aspect);\n draw(splatPass, dye.write);\n dye.swap();\n }\n\n function splatAt(\n x: number,\n y: number,\n vx: number,\n vy: number,\n colour: RGB,\n radiusPx: number,\n aspect: number,\n height: number,\n ): void {\n const pointX = x / (height * aspect);\n // Texture v points up; pointer y points down. Flip both the splash position\n // and the vertical velocity so the smoke follows the pointer's direction.\n const pointY = 1 - y / height;\n const radius = Math.max(0.0005, radiusPx / height);\n splatVelocity(pointX, pointY, vx, -vy, radius, aspect);\n splatDye(pointX, pointY, colour, radius, aspect);\n }\n\n function step(dt: number): void {\n gl.disable(gl.BLEND);\n const idleBoost = idleTime > IDLE_DELAY ? 1 / IDLE_DECAY : 0;\n // Vorticity confinement: the curl of the velocity becomes a force.\n gl.useProgram(curlPass.program);\n texture(0, velocity.read.texture);\n gl.uniform1i(curlPass.uniforms.uVelocity, 0);\n gl.uniform2f(curlPass.uniforms.uTexelSize, 1 / simWidth, 1 / simHeight);\n draw(curlPass, curl);\n\n gl.useProgram(vorticityPass.program);\n texture(0, velocity.read.texture);\n texture(1, curl.texture);\n gl.uniform1i(vorticityPass.uniforms.uVelocity, 0);\n gl.uniform1i(vorticityPass.uniforms.uCurl, 1);\n gl.uniform2f(vorticityPass.uniforms.uTexelSize, 1 / simWidth, 1 / simHeight);\n gl.uniform1f(vorticityPass.uniforms.uDt, dt);\n gl.uniform1f(vorticityPass.uniforms.uStrength, options.curl);\n draw(vorticityPass, velocity.write);\n velocity.swap();\n\n gl.useProgram(divergencePass.program);\n texture(0, velocity.read.texture);\n gl.uniform1i(divergencePass.uniforms.uVelocity, 0);\n gl.uniform2f(divergencePass.uniforms.uTexelSize, 1 / simWidth, 1 / simHeight);\n draw(divergencePass, divergence);\n\n gl.useProgram(clearPass.program);\n texture(0, pressure.read.texture);\n gl.uniform1i(clearPass.uniforms.uTexture, 0);\n gl.uniform1f(clearPass.uniforms.uValue, PRESSURE_RETENTION);\n draw(clearPass, pressure.write);\n pressure.swap();\n for (let iteration = 0; iteration < PRESSURE_ITERATIONS; iteration++) {\n gl.useProgram(pressurePass.program);\n texture(0, pressure.read.texture);\n texture(1, divergence.texture);\n gl.uniform1i(pressurePass.uniforms.uPressure, 0);\n gl.uniform1i(pressurePass.uniforms.uDivergence, 1);\n gl.uniform2f(pressurePass.uniforms.uTexelSize, 1 / simWidth, 1 / simHeight);\n draw(pressurePass, pressure.write);\n pressure.swap();\n }\n\n gl.useProgram(gradientPass.program);\n texture(0, pressure.read.texture);\n texture(1, velocity.read.texture);\n gl.uniform1i(gradientPass.uniforms.uPressure, 0);\n gl.uniform1i(gradientPass.uniforms.uVelocity, 1);\n gl.uniform2f(gradientPass.uniforms.uTexelSize, 1 / simWidth, 1 / simHeight);\n draw(gradientPass, velocity.write);\n velocity.swap();\n\n gl.useProgram(advectionPass.program);\n gl.uniform1i(advectionPass.uniforms.uVelocity, 0);\n gl.uniform1i(advectionPass.uniforms.uSource, 1);\n gl.uniform1f(advectionPass.uniforms.uDt, dt);\n gl.uniform2f(advectionPass.uniforms.uTexelSize, 1 / simWidth, 1 / simHeight);\n texture(0, velocity.read.texture);\n texture(1, velocity.read.texture);\n gl.uniform1f(advectionPass.uniforms.uDissipation, 1 / VELOCITY_FADE);\n draw(advectionPass, velocity.write);\n velocity.swap();\n\n gl.useProgram(advectionPass.program);\n gl.uniform1i(advectionPass.uniforms.uVelocity, 0);\n gl.uniform1i(advectionPass.uniforms.uSource, 1);\n gl.uniform1f(advectionPass.uniforms.uDt, dt);\n gl.uniform1f(advectionPass.uniforms.uDissipation, 1 / options.fade + idleBoost);\n gl.uniform2f(advectionPass.uniforms.uTexelSize, 1 / simWidth, 1 / simHeight);\n texture(0, velocity.read.texture);\n texture(1, dye.read.texture);\n draw(advectionPass, dye.write);\n dye.swap();\n }\n\n let clock = 0;\n let active = 0;\n let idleTime = 0;\n let lastX = 0;\n let lastY = 0;\n let wasInside = false;\n let burstPending = true;\n\n function wake(): void {\n active = Math.max(active, IDLE_CLEAR + 0.5);\n idleTime = 0;\n }\n\n function burst(x: number, y: number, radius: number, aspect: number, height: number): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * BURST_DYE, colour[1] * BURST_DYE, colour[2] * BURST_DYE];\n const angle = Math.random() * TAU;\n const speed = options.force * BURST_FORCE;\n splatAt(x, y, Math.cos(angle) * speed, Math.sin(angle) * speed, dye, radius, aspect, height);\n }\n\n function click(x: number, y: number, aspect: number, height: number): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * 10, colour[1] * 10, colour[2] * 10];\n const dx = 10 * (Math.random() - 0.5);\n const dy = 30 * (Math.random() - 0.5);\n splatAt(x, y, dx, dy, dye, options.radius, aspect, height);\n wake();\n }\n\n function mountSize(width: number, height: number): void {\n if (width === builtWidth && height === builtHeight && options.resolution === builtResolution) return;\n builtWidth = width;\n builtHeight = height;\n builtResolution = options.resolution;\n allocate(width, height);\n }\n\n /** Clear both sides of a double buffer. */\n function clearField(target: DoubleFBO): void {\n for (const fbo of [target.read, target.write]) {\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo.framebuffer);\n gl.viewport(0, 0, fbo.width, fbo.height);\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n }\n }\n\n function drawDye(frame: Frame): void {\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.useProgram(displayPass.program);\n texture(0, dye.read.texture);\n gl.uniform1i(displayPass.uniforms.uDye, 0);\n gl.uniform2f(displayPass.uniforms.uTexelSize, 1 / Math.max(1, frame.width * frame.dpr), 1 / Math.max(1, frame.height * frame.dpr));\n gl.uniform1f(displayPass.uniforms.uOpacity, options.opacity);\n gl.uniform1i(displayPass.uniforms.uShading, options.shading ? 1 : 0);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n }\n\n return {\n update(next) {\n options = resolveFluidOptions(next);\n },\n render(frame: Frame) {\n mountSize(frame.width, frame.height);\n if (frame.reducedMotion) {\n // Hold the smoke still: one static splash, no simulation. The engine then stops.\n if (burstPending) {\n burstPending = false;\n const aspect = frame.width / Math.max(1, frame.height);\n const bx = frame.width * (0.34 + Math.random() * 0.18);\n const by = frame.height * (0.4 + Math.random() * 0.2);\n burst(bx, by, options.radius * BURST_RADIUS, aspect, frame.height);\n }\n drawDye(frame);\n return false;\n }\n\n const dt = Math.min(frame.dt, 1 / 60);\n const aspect = frame.width / Math.max(1, frame.height);\n const { pointer } = frame;\n\n if (burstPending) {\n burstPending = false;\n const bx = frame.width * (0.34 + Math.random() * 0.18);\n const by = frame.height * (0.4 + Math.random() * 0.2);\n burst(bx, by, options.radius * BURST_RADIUS, aspect, frame.height);\n wake();\n }\n\n if (pointer.influence > 0) {\n if (wasInside) {\n const moveX = pointer.x - lastX;\n const moveY = pointer.y - lastY;\n const dx = moveX / Math.max(1, frame.width);\n const dy = moveY / Math.max(1, frame.height);\n // Like a real mousemove stream: don't keep adding dye to a resting pointer.\n if (Math.hypot(moveX, moveY) > 0.5) {\n const colour = splatColor(options, clock);\n const strength = options.force * pointer.influence;\n splatAt(\n pointer.x,\n pointer.y,\n dx * strength,\n dy * strength,\n colour,\n options.radius,\n aspect,\n frame.height,\n );\n wake();\n }\n }\n lastX = pointer.x;\n lastY = pointer.y;\n wasInside = true;\n } else {\n wasInside = false;\n }\n\n for (const clickPoint of frame.clicks) click(clickPoint.x, clickPoint.y, aspect, frame.height);\n\n if (dt > 0) {\n idleTime += dt;\n if (idleTime >= IDLE_CLEAR) {\n clearField(dye);\n clearField(velocity);\n idleTime = 0;\n active = 0;\n drawDye(frame);\n return false;\n }\n step(dt);\n clock += dt;\n active = Math.max(0, active - dt);\n }\n\n drawDye(frame);\n return active > 0;\n },\n destroy() {\n for (const target of [\n velocity.read,\n velocity.write,\n dye.read,\n dye.write,\n pressure.read,\n pressure.write,\n divergence,\n curl,\n ]) {\n deleteFBO(target);\n }\n for (const pass of [\n splatPass,\n advectionPass,\n divergencePass,\n curlPass,\n vorticityPass,\n pressurePass,\n gradientPass,\n clearPass,\n displayPass,\n ]) {\n gl.deleteProgram(pass.program);\n }\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createFluidCanvas2D } from '../styles/fluid/canvas2d';\nimport { fluidStyle } from '../styles/fluid/definition';\nimport type { FluidOptions } from '../styles/fluid/options';\nimport { createFluidWebGL } from '../styles/fluid/webgl';\n\nexport type { FluidOptions };\n\n/** An interactive fluid simulation, drawn with WebGL2 where available and a CPU simulation otherwise. */\nexport const fluid: StyleFactory<FluidOptions> = defineStyle({\n ...fluidStyle,\n renderers: [webglRenderer(createFluidWebGL), canvas2dRenderer(createFluidCanvas2D)],\n});\n","import type { ResolvedShimmerOptions } from './options';\n\n/** Long side of the CPU fallback's field. The reference field is very soft. */\nexport const CPU_RESOLUTION = 128;\n/** The reference's clock runs at this many time units per second. */\nexport const TIME_RATE = 0.22;\n/** How much of the warped colour replaces the base colour. */\nconst COLOR_MIX = 0.8;\nconst TAU = Math.PI * 2;\nconst HALF_PI = Math.PI / 2;\nconst LUT_SIZE = 2048;\nconst SIN_LUT = new Float32Array(LUT_SIZE + 1);\nfor (let i = 0; i <= LUT_SIZE; i++) SIN_LUT[i] = Math.sin((i / LUT_SIZE) * TAU);\n\n/** Interpolated sine lookup: the CPU field is trig-heavy and runs every frame. */\nfunction fastSin(x: number): number {\n let t = (x * LUT_SIZE) / TAU;\n t -= Math.floor(t / LUT_SIZE) * LUT_SIZE;\n const i = t | 0;\n const f = t - i;\n return SIN_LUT[i] + (SIN_LUT[i + 1] - SIN_LUT[i]) * f;\n}\n\nfunction fastCos(x: number): number {\n return fastSin(x + HALF_PI);\n}\n\n/**\n * The CPU mirror of the reference shader. `time` is the style clock in seconds;\n * the field is evaluated at `width` × `height` and written into `image`.\n * Coordinates are top-left based; the shader flips its UVs to match.\n */\nexport function renderShimmer(\n image: ImageData,\n width: number,\n height: number,\n time: number,\n pointerX: number,\n pointerY: number,\n influence: number,\n options: ResolvedShimmerOptions,\n base: readonly [number, number, number],\n): void {\n const data = image.data;\n const t = time * TIME_RATE * options.speed;\n const frequency = options.frequency;\n const colorScale = options.colorScale;\n const warp = options.warp;\n const chroma = options.chroma;\n const opacity = options.opacity;\n const pointer = options.pointerStrength * influence;\n const aspect = Math.max(1, width) / Math.max(1, height);\n\n const distort = (x: number, y: number, offset: number): number => {\n let px = x + offset;\n let py = y + offset;\n for (let i = 1; i < 7; i++) {\n px += (warp * 0.3 * fastSin(i * 5 * py + t)) / i;\n py += (warp * 0.1 * fastCos(i * 3 * px + t)) / i;\n }\n return px;\n };\n\n for (let y = 0; y < height; y++) {\n const v = (y + 0.5) / height;\n for (let x = 0; x < width; x++) {\n const u = (x + 0.5) / width;\n\n // Optional pointer lens, in screen-height units like the shader.\n let su = u;\n let sv = v;\n if (pointer > 0) {\n const dx = (u - pointerX) * aspect;\n const dy = v - pointerY;\n const lens = Math.exp(-(dx * dx + dy * dy) / 0.03) * pointer;\n su += (dx / aspect) * lens;\n sv += dy * lens;\n }\n\n const r = fastSin(distort(su, sv, 0) * frequency) * 0.5 + 0.5;\n const g = fastSin(distort(su, sv, chroma) * frequency) * 0.5 + 0.5;\n const b = fastSin(distort(su, sv, 2 * chroma) * frequency) * 0.5 + 0.5;\n const pr = Math.pow(r, colorScale);\n const pg = Math.pow(g, colorScale);\n const pb = Math.pow(b, colorScale);\n\n const red = base[0] * (1 - COLOR_MIX) + pr * COLOR_MIX;\n const green = base[1] * (1 - COLOR_MIX) + pg * COLOR_MIX;\n const blue = base[2] * (1 - COLOR_MIX) + pb * COLOR_MIX;\n\n const o = (y * width + x) * 4;\n data[o] = Math.round(Math.min(1, Math.max(0, red)) * 255);\n data[o + 1] = Math.round(Math.min(1, Math.max(0, green)) * 255);\n data[o + 2] = Math.round(Math.min(1, Math.max(0, blue)) * 255);\n data[o + 3] = Math.round(opacity * 255);\n }\n }\n}\n","export interface ShimmerOptions {\n /** Opacity of the finished field, from `0` to `1`. `1` is the opaque reference canvas. */\n opacity: number;\n /** How fast the field flows. `1` matches the reference's slow drift. `0` = still. */\n speed: number;\n /** Sine frequency of the bands. Higher = more, narrower bands. The reference uses `7`. */\n frequency: number;\n /** Gamma applied to the bands. Higher = darker gaps and brighter crests. The reference uses `10`. */\n colorScale: number;\n /** Colour mixed into the 20% base of the field. The reference uses white. */\n baseColor: string;\n /** Separation between the red, green and blue channel warps: chromatic dispersion. The reference uses `0.02`. */\n chroma: number;\n /** Multiplier for the sine/cosine distortion. `1` is the reference; `0` = straight bands. */\n warp: number;\n /** Optional pointer lens that bends the bands locally. `0` keeps the reference's ambient field. */\n pointerStrength: number;\n}\n\nexport const shimmerDefaults: Readonly<ShimmerOptions> = Object.freeze({\n opacity: 1,\n speed: 1,\n frequency: 7,\n colorScale: 10,\n baseColor: '#5735ff',\n chroma: 0.02,\n warp: 1,\n pointerStrength: 0.35,\n});\n\n/** Options after clamping: what the shader and the CPU field consume. */\nexport type ResolvedShimmerOptions = ShimmerOptions;\n\nconst clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nexport function resolveShimmerOptions(options: ShimmerOptions): ResolvedShimmerOptions {\n return {\n ...options,\n opacity: clamp(options.opacity, 0, 1),\n speed: Math.max(0, options.speed),\n frequency: clamp(options.frequency, 0.5, 40),\n colorScale: clamp(options.colorScale, 0.5, 40),\n chroma: clamp(options.chroma, 0, 0.2),\n warp: clamp(options.warp, 0, 4),\n pointerStrength: clamp(options.pointerStrength, 0, 1.5),\n };\n}\n","import { parseColor } from '../../core/color';\nimport type { Frame, StyleRenderer } from '../../core/style';\nimport { CPU_RESOLUTION, renderShimmer } from './field';\nimport { resolveShimmerOptions, type ShimmerOptions } from './options';\n\nfunction fieldSize(width: number, height: number): { width: number; height: number } {\n const aspect = Math.max(1, width) / Math.max(1, height);\n if (aspect >= 1) return { width: CPU_RESOLUTION, height: Math.max(1, Math.round(CPU_RESOLUTION / aspect)) };\n return { width: Math.max(1, Math.round(CPU_RESOLUTION * aspect)), height: CPU_RESOLUTION };\n}\n\n/** CPU mirror of the analytic band field, at low resolution and upscaled. */\nconst CPU_FPS = 12;\n\nexport function createShimmerCanvas2D(\n ctx: CanvasRenderingContext2D,\n initial: ShimmerOptions,\n): StyleRenderer<ShimmerOptions> {\n let options = resolveShimmerOptions(initial);\n let clock = 0;\n let accumulator = 0;\n let hasFrame = false;\n\n let target: HTMLCanvasElement | null = null;\n let targetCtx: CanvasRenderingContext2D | null = null;\n let image: ImageData | null = null;\n let fieldWidth = 0;\n let fieldHeight = 0;\n let builtWidth = 0;\n let builtHeight = 0;\n\n function allocate(width: number, height: number): void {\n const size = fieldSize(width, height);\n fieldWidth = size.width;\n fieldHeight = size.height;\n target = document.createElement('canvas');\n target.width = fieldWidth;\n target.height = fieldHeight;\n targetCtx = target.getContext('2d');\n image = targetCtx?.createImageData(fieldWidth, fieldHeight) ?? null;\n builtWidth = width;\n builtHeight = height;\n accumulator = 0;\n hasFrame = false;\n }\n\n return {\n update(next) {\n options = resolveShimmerOptions(next);\n },\n render(frame: Frame) {\n if (!image || frame.width !== builtWidth || frame.height !== builtHeight) {\n allocate(frame.width, frame.height);\n }\n if (!image || !target || !targetCtx) return;\n\n // Recompute the field at 20 fps; the engine may call us at 60 fps while\n // the pointer moves, but this field is slow and soft.\n if (frame.reducedMotion) {\n if (!hasFrame) {\n const [baseR, baseG, baseB] = parseColor(options.baseColor);\n renderShimmer(\n image,\n fieldWidth,\n fieldHeight,\n clock,\n 0.5,\n 0.5,\n 0,\n options,\n [baseR, baseG, baseB],\n );\n targetCtx.putImageData(image, 0, 0);\n hasFrame = true;\n }\n } else {\n accumulator += frame.dt;\n if (!hasFrame || accumulator >= 1 / CPU_FPS) {\n clock += accumulator;\n accumulator = 0;\n const [baseR, baseG, baseB] = parseColor(options.baseColor);\n renderShimmer(\n image,\n fieldWidth,\n fieldHeight,\n clock,\n frame.pointer.x / Math.max(1, frame.width),\n frame.pointer.y / Math.max(1, frame.height),\n frame.pointer.influence,\n options,\n [baseR, baseG, baseB],\n );\n targetCtx.putImageData(image, 0, 0);\n hasFrame = true;\n }\n }\n ctx.imageSmoothingEnabled = true;\n ctx.drawImage(target, 0, 0, frame.width, frame.height);\n },\n };\n}\n","import type { StyleBase } from '../../core/style';\nimport { shimmerDefaults, type ShimmerOptions } from './options';\n\n/**\n * Iridescent light bands, reproduced from the reference's `sr-ground-canvas`:\n * six coupled sine/cosine warps, per-channel offsets and a high-power sine\n * field, mixed 80% with a base colour.\n */\nexport const shimmerStyle: StyleBase<ShimmerOptions> = {\n name: 'shimmer',\n defaults: shimmerDefaults,\n animates: (options) => options.speed > 0,\n // The field drifts slowly; 24 fps is plenty and keeps the CPU fallback cheap.\n idleFps: () => 16,\n};\n","import { parseColor } from '../../core/color';\nimport type { Frame, StyleRenderer } from '../../core/style';\nimport { createProgram, FULLSCREEN_VERTEX_SHADER, getUniforms } from '../../core/webgl';\nimport { TIME_RATE } from './field';\nimport { resolveShimmerOptions, type ShimmerOptions } from './options';\n\n// A faithful port of the reference's `sr-ground-canvas` shader: a pair of\n// coupled sine waves warp the UVs six times, the three channels are offset\n// slightly, and the resulting sine bands are raised to a high power.\nconst FRAGMENT = `#version 300 es\nprecision highp float;\n\nuniform vec2 uRes;\nuniform float uTime;\nuniform float uFrequency;\nuniform float uColorScale;\nuniform vec3 uBaseColor;\nuniform float uChroma;\nuniform float uWarp;\nuniform float uOpacity;\nuniform vec3 uPointer; // x, y, strength × influence\n\nout vec4 fragColor;\n\nvec2 distort(vec2 p, float offset) {\n p += offset;\n for (float i = 1.0; i < 7.0; i++) {\n p.x += uWarp * 0.3 / i * sin(i * 5.0 * p.y + uTime);\n p.y += uWarp * 0.1 / i * cos(i * 3.0 * p.x + uTime);\n }\n return p;\n}\n\nvoid main() {\n // gl_FragCoord is bottom-up; flip it so pointer coordinates are top-down.\n vec2 uv = vec2(gl_FragCoord.x / uRes.x, 1.0 - gl_FragCoord.y / uRes.y);\n\n float aspect = uRes.x / uRes.y;\n vec2 d = (uv - uPointer.xy) * vec2(aspect, 1.0);\n uv += vec2(d.x / aspect, d.y) * exp(-dot(d, d) / 0.03) * uPointer.z;\n\n float r = sin(distort(uv, 0.0).x * uFrequency) * 0.5 + 0.5;\n float g = sin(distort(uv, uChroma).x * uFrequency) * 0.5 + 0.5;\n float b = sin(distort(uv, 2.0 * uChroma).x * uFrequency) * 0.5 + 0.5;\n vec3 colour = pow(vec3(r, g, b), vec3(uColorScale));\n vec3 finalColour = mix(uBaseColor, colour, 0.8);\n fragColor = vec4(finalColour * uOpacity, uOpacity);\n}`;\n\nconst UNIFORMS = [\n 'uRes',\n 'uTime',\n 'uFrequency',\n 'uColorScale',\n 'uBaseColor',\n 'uChroma',\n 'uWarp',\n 'uOpacity',\n 'uPointer',\n] as const;\n\n/** The exact analytic band field from the reference, running in WebGL2. */\nexport function createShimmerWebGL(gl: WebGL2RenderingContext, initial: ShimmerOptions): StyleRenderer<ShimmerOptions> {\n let options = resolveShimmerOptions(initial);\n let clock = 0;\n\n const program = createProgram(gl, FULLSCREEN_VERTEX_SHADER, FRAGMENT);\n const uniforms = program ? getUniforms(gl, program, UNIFORMS) : null;\n\n return {\n update(next) {\n options = resolveShimmerOptions(next);\n },\n render(frame: Frame) {\n if (!program || !uniforms) return; // context lost during setup\n if (!frame.reducedMotion && options.speed > 0) clock += frame.dt;\n\n const [baseR, baseG, baseB] = parseColor(options.baseColor);\n gl.useProgram(program);\n gl.uniform2f(uniforms.uRes, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.uniform1f(uniforms.uTime, clock * TIME_RATE * options.speed);\n gl.uniform1f(uniforms.uFrequency, options.frequency);\n gl.uniform1f(uniforms.uColorScale, options.colorScale);\n gl.uniform3f(uniforms.uBaseColor, baseR, baseG, baseB);\n gl.uniform1f(uniforms.uChroma, options.chroma);\n gl.uniform1f(uniforms.uWarp, options.warp);\n gl.uniform1f(uniforms.uOpacity, options.opacity);\n gl.uniform3f(\n uniforms.uPointer,\n frame.pointer.x / Math.max(1, frame.width),\n frame.pointer.y / Math.max(1, frame.height),\n frame.reducedMotion ? 0 : options.pointerStrength * frame.pointer.influence,\n );\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n },\n destroy() {\n gl.deleteProgram(program);\n },\n };\n}\n","import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createShimmerCanvas2D } from '../styles/shimmer/canvas2d';\nimport { shimmerStyle } from '../styles/shimmer/definition';\nimport type { ShimmerOptions } from '../styles/shimmer/options';\nimport { createShimmerWebGL } from '../styles/shimmer/webgl';\n\nexport type { ShimmerOptions };\n\n/** Iridescent light bands, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const shimmer: StyleFactory<ShimmerOptions> = defineStyle({\n ...shimmerStyle,\n renderers: [webglRenderer(createShimmerWebGL), canvas2dRenderer(createShimmerCanvas2D)],\n});\n"],"mappings":"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"}
|