@vibecook/ice 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +10 -5
  2. package/dist/{chunk-ZTY2VRIS.js → chunk-6W2FPXR7.js} +13 -7
  3. package/dist/chunk-6W2FPXR7.js.map +1 -0
  4. package/dist/{chunk-Y7K6CHSF.js → chunk-LAZIY3J7.js} +286 -189
  5. package/dist/chunk-LAZIY3J7.js.map +1 -0
  6. package/dist/{chunk-REJTEK3V.js → chunk-M2HUDENL.js} +288 -318
  7. package/dist/chunk-M2HUDENL.js.map +1 -0
  8. package/dist/{chunk-BH5AFWJX.js → chunk-VZEZ7CYW.js} +9 -13
  9. package/dist/chunk-VZEZ7CYW.js.map +1 -0
  10. package/dist/desk-kit.js +2 -2
  11. package/dist/desk-objects.js +45 -14
  12. package/dist/desk-objects.js.map +1 -1
  13. package/dist/desk.js +3 -3
  14. package/dist/devtools.js +1 -1
  15. package/dist/dom.js +2 -2
  16. package/dist/index.js +7 -1
  17. package/dist/react.js +2 -2
  18. package/dist/types/packages/core/src/canvas/engine-catalog.d.ts +6 -0
  19. package/dist/types/packages/core/src/catalog/desk.d.ts +6 -6
  20. package/dist/types/packages/core/src/catalog/gesture.d.ts +2 -0
  21. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +2 -0
  22. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +8 -4
  23. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +11 -5
  24. package/dist/types/packages/core/src/index.d.ts +1 -1
  25. package/dist/types/packages/core/src/ops/selection-drag.d.ts +8 -0
  26. package/dist/types/packages/core/src/settings/defaults.d.ts +2 -0
  27. package/dist/types/packages/core/src/systems/camera-sim.d.ts +13 -0
  28. package/dist/types/packages/core/src/systems/tray.d.ts +5 -4
  29. package/dist/types/packages/core/src/tools/define-tool.d.ts +2 -2
  30. package/dist/types/packages/core/src/widget/define-widget.d.ts +2 -1
  31. package/dist/types/packages/desk/src/ground.d.ts +4 -3
  32. package/dist/types/packages/desk/src/host/layer.d.ts +1 -3
  33. package/dist/types/packages/desk/src/mat/layout.d.ts +45 -5
  34. package/dist/types/packages/desk/src/mat/mat-pass.d.ts +7 -0
  35. package/dist/types/packages/desk/src/mat/ruler-regions.d.ts +17 -0
  36. package/dist/types/packages/desk/src/shaders.gen.d.ts +4 -4
  37. package/dist/types/packages/desk/src/theme.d.ts +0 -15
  38. package/dist/types/packages/desk/src/tray/drawer.d.ts +10 -8
  39. package/dist/types/packages/desk/src/tray/flux.d.ts +2 -3
  40. package/dist/types/packages/desk/src/tray/layout.d.ts +1 -6
  41. package/dist/types/packages/desk/src/tray/look.d.ts +0 -9
  42. package/dist/types/packages/desk/src/tray/pass.d.ts +7 -18
  43. package/dist/types/packages/desk/src/tray/specimens.d.ts +2 -19
  44. package/dist/types/packages/dom/src/pointer-adapter.d.ts +1 -1
  45. package/dist/types/packages/objects/src/minimat/layout.d.ts +1 -1
  46. package/dist/types/packages/objects/src/photo/photo.d.ts +2 -2
  47. package/dist/types/packages/objects/src/preset.d.ts +5 -3
  48. package/package.json +15 -16
  49. package/dist/chunk-BH5AFWJX.js.map +0 -1
  50. package/dist/chunk-REJTEK3V.js.map +0 -1
  51. package/dist/chunk-Y7K6CHSF.js.map +0 -1
  52. package/dist/chunk-ZTY2VRIS.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../desk/src/lattice/lod.ts","../../desk/src/mat/night.ts","../../desk/src/theme.ts","../../desk/src/nav/portal.ts","../../desk/src/lattice/ruler.ts","../../desk/src/mat/projector.ts","../../desk/src/mat/layout.ts","../../desk/src/kit/book.ts","../../desk/src/shaders.gen.ts","../../desk/src/shaders.ts","../../desk/src/kit/wgsl.ts","../../desk/src/mat/grid.ts","../../desk/src/kit/layer.ts","../../desk/src/kit/springs.ts","../../desk/src/nav/flight.ts","../../desk/src/marks/ease.ts","../../desk/src/hold/pose.ts","../../desk/src/kit/inside.ts","../../desk/src/mat/lamp.ts","../../desk/src/kit/services.ts","../../desk/src/kit/blobs.ts","../../desk/src/kit/raster.ts","../../desk/src/kit/text.ts","../../desk/src/kit/arrays.ts","../../desk/src/kit/mips.ts","../../desk/src/kit/eye.ts","../../desk/src/kit/live.ts","../../desk/src/kit/mesh.ts","../../desk/src/kit/paper-tex.ts","../../desk/src/kit/physics.ts","../../desk/src/kit/place.ts","../../desk/src/kit/print.ts","../../desk/src/kit/sdf.ts","../../desk/src/kit/seeds.ts","../../desk/src/kit/strokes.ts","../../desk/src/kit/uniform.ts","../../desk/src/lattice/line.ts"],"sourcesContent":["// The decade lattice — pure maths, no GPU, no DOM. Everything the mat and its\n// rulers (and a mini mat's face) need to know about WHERE the lattice's sites\n// are comes from here, and this file is what the unit tests pin.\n//\n// One identity spacing (20 world units) whose screen size picks a decade:\n// logc = log10(20·zoom / 20px) k0 = −floor(logc) fade = fract(logc)\n// mid = 20·10^k0 fine = mid/10 (alpha·fade) coarse = mid·10\n// Zoom is unbounded; the host wraps the camera to the coarse period so\n// round(world/spacing) stays exact on the GPU. (The magnet field's atlas and\n// instance grids lived here too until the dot and the needle retired, 2026-09-25.)\n\nexport const BASE_SPACING = 20;\nexport const LOD_TARGET = 20;\nexport const ZOOM_MIN = 1e-8;\nexport const ZOOM_MAX = 1e8;\n\nexport interface View {\n readonly camX: number;\n readonly camY: number;\n readonly zoom: number;\n /** CSS px — the attachment. */\n readonly width: number;\n readonly height: number;\n /**\n * The slot's BOX on the attachment, CSS px (PORTAL.md §2.3): what is\n * culled — a mini mat's face for a nested slot.\n * Absent = the whole attachment. Positions never change with it: a site\n * lands where it lands under the camera; the box only decides which sites\n * exist. A root slot's box is the attachment and every number is what it\n * always was.\n */\n readonly box?: Box;\n}\n\nexport interface Box { readonly x: number; readonly y: number; readonly w: number; readonly h: number }\n\n/** The effective box: the view's own, or the attachment. */\nexport const boxOf = (v: View): Box => v.box ?? { x: 0, y: 0, w: v.width, h: v.height };\n/** The `box` record the uniform blocks carry: x, y, w, h. */\nexport const boxValues = (v: View): number[] => { const b = boxOf(v); return [b.x, b.y, b.w, b.h]; };\n\nexport interface Lod {\n readonly k0: number;\n readonly fade: number;\n readonly fine: number;\n readonly mid: number;\n readonly coarse: number;\n readonly wrapPeriod: number;\n}\n\nexport const wrap = (v: number, p: number): number => ((v % p) + p) % p;\n\n/**\n * How a rung presents itself: ONE size for every rung, and a rung's alpha is\n * `smoothstep(fadeIn, cellPx)` of its OWN cell — so a decade wrap (the fine rung\n * becoming the mid rung at the same cell) is continuous by construction, and\n * nothing is drawn below `fadeIn[0]` px of pitch: the product's classic-grid law\n * (`worldGrid.fadeIn`). The prototype's size LADDER (fine 0.55× · mid 0.85→1.25×\n * · coarse 1.55×, the fine rung's alpha the decade fade — every tenth site bigger,\n * a size pop at every wrap) was retired on 2026-09-04; nothing of it remains.\n */\nexport type FadeIn = readonly [number, number];\n\nexport const smoothstep = (a: number, b: number, x: number): number => {\n const t = Math.min(Math.max((x - a) / Math.max(b - a, 1e-3), 0), 1);\n return t * t * (3 - 2 * t);\n};\n\nexport function lod(v: View): Lod {\n const screenCell = BASE_SPACING * v.zoom;\n const logc = Math.log(Math.max(screenCell, 1e-20) / LOD_TARGET) / Math.LN10;\n const floorLog = Math.floor(logc);\n // `0 - floorLog`, not `-floorLog`: at zoom 1 the latter is -0, which is a\n // different value to Object.is and to anything keyed on it.\n const k0 = Math.min(12, Math.max(-12, 0 - floorLog));\n const fade = logc - floorLog;\n const mid = BASE_SPACING * 10 ** k0;\n return { k0, fade, fine: mid / 10, mid, coarse: mid * 10, wrapPeriod: mid * 10 };\n}\n","// The NIGHT — the cutting mat under the Moon (MAT.md). A PURE module, no GPU:\n// the physics that turns the theme's choices (a colour temperature, an\n// illuminance, a hue for the rods, Eigengrau, an exposure rule) into the\n// numbers the mat shader reads, and a CPU mirror of that shader for the tests\n// and the doc. No colour is CHOSEN here — theme.ts chooses, this file computes.\n//\n// The model, per pixel (mat.wgsl `night_mat` is the same arithmetic):\n// cone = albedo · moon · shade the mat under the Moon, as the partly adapted cones take it\n// rod = V'(cone) / V'(white) the rods' signal (Larson, Rushmeier & Piatko 1997)\n// L = lux · Y(cone) / π cd/m² on the desk\n// m = CIE 191:2010's mesopic weight at L\n// see = mix(rod · rodHue, cone, m) what the eye reports\n// disp = eigengrau + see · exposure the dark's own grey under it; the appearance's scale\n// out = sRGB(disp) + snow encoded, then the rods' own noise\n\nimport type { RGB } from \"../theme\";\n\n/** What the mat is lit by — a theme's light. `night` 0 is the reference's day chain, bit for bit. */\nexport interface MatLight {\n /** 0 = the day (the reference's chain, exactly) · 1 = the night · between: a cross-fade of the two on the display. */\n readonly night: number;\n /** The Moon's illuminance on the desk, lux — where on the mesopic ramp the eye sits. */\n readonly lux: number;\n /** Scene → display: the scale the adapted eye's report is drawn at. */\n readonly exposure: number;\n /** The rods' own noise, display units, peak to peak. */\n readonly snow: number;\n /** The Moon's colour as the (partly) adapted eye takes it — linear sRGB at Y = 1. */\n readonly moon: RGB;\n /** The sky's share of the light where the Moon is blocked. */\n readonly fill: number;\n /** The rods' signal drawn as a colour — linear sRGB at Y = 1. */\n readonly rod: RGB;\n /** The dark the eye adds to everything — linear sRGB. */\n readonly eigengrau: RGB;\n}\n\n/** The day: the reference's chain, untouched — every night number inert. */\nexport const DAY_LIGHT: MatLight = { night: 0, lux: 0, exposure: 0, snow: 0, moon: [1, 1, 1], fill: 0, rod: [1, 1, 1], eigengrau: [0, 0, 0] };\n\n/** The night as the theme states it (theme.ts `NIGHT`). */\nexport interface NightSpec {\n /** The Moon's colour temperature, K. */\n readonly kelvin: number;\n /** Its illuminance on the desk, lux. */\n readonly lux: number;\n /** The sky's share in the shadow. */\n readonly fill: number;\n /** The rods' hue: a spectral wavelength (470–500 nm) and how far from white toward it. */\n readonly rodHue: { readonly nm: number; readonly purity: number };\n /** Eigengrau, sRGB 0..1. */\n readonly eigengrau: RGB;\n /** The display luminance (linear, Eigengrau included) the moonlit ground is drawn at — the appearance's one scale. */\n readonly litLuminance: number;\n /** The rods' noise, display units peak to peak. */\n readonly snow: number;\n /** CIECAM02's surround factor F for the degree of adaptation: 1 average · 0.9 dim · 0.8 dark. */\n readonly surround: number;\n}\n\n// ---- colour science, the standard numbers\n/** sRGB (IEC 61966-2-1) ↔ CIE 1931 XYZ, D65 — rows. */\nconst RGB2XYZ = [[0.4124564, 0.3575761, 0.1804375], [0.2126729, 0.7151522, 0.072175], [0.0193339, 0.119192, 0.9503041]] as const;\nconst XYZ2RGB = [[3.2404542, -1.5371385, -0.4985314], [-0.969266, 1.8760108, 0.041556], [0.0556434, -0.2040259, 1.0572252]] as const;\nconst mul = (M: readonly [RGB, RGB, RGB], v: RGB): RGB => [M[0][0] * v[0] + M[0][1] * v[1] + M[0][2] * v[2], M[1][0] * v[0] + M[1][1] * v[1] + M[1][2] * v[2], M[2][0] * v[0] + M[2][1] * v[1] + M[2][2] * v[2]];\n/** A colour from its three channels by index — a tuple's literal index needs no guard. */\nconst tri = (f: (i: 0 | 1 | 2) => number): RGB => [f(0), f(1), f(2)];\nexport const srgbToLinear = (c: number): number => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);\nexport const linearToSrgb = (c: number): number => (c <= 0.0031308 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - 0.055);\nexport const linear = (c: RGB): RGB => [srgbToLinear(c[0]), srgbToLinear(c[1]), srgbToLinear(c[2])];\n/** Photopic luminance Y of a linear sRGB colour. */\nexport const luminance = (c: RGB): number => RGB2XYZ[1][0] * c[0] + RGB2XYZ[1][1] * c[1] + RGB2XYZ[1][2] * c[2];\n\n/**\n * Scotopic luminance V' from XYZ — Larson, Rushmeier & Piatko 1997's regression\n * (the one the night-rendering literature uses: Jensen et al. 2000, Kirk & O'Brien 2011).\n * The rods peak at 507 nm: greens and blues keep their brightness by night, reds die.\n */\nexport function scotopic(c: RGB): number {\n const [X, Y, Z] = mul(RGB2XYZ, c);\n return Y * (1.33 * (1 + (Y + Z) / Math.max(X, 1e-6)) - 1.68);\n}\nconst SCOTOPIC_WHITE = scotopic([1, 1, 1]);\n/** The rods' signal, white = 1 — what the shader calls `rod`. */\nexport const rodSignal = (c: RGB): number => Math.max(scotopic(c), 0) / SCOTOPIC_WHITE;\n\n/** CIE 191:2010's mesopic adaptation coefficient (first order, seeded by the photopic luminance): 0 at 0.005 cd/m² (the rods alone), 1 at 5 (the cones alone). */\nexport const mesopicWeight = (L: number): number => Math.min(Math.max(0.767 + 0.3334 * Math.log10(Math.max(L, 1e-9)), 0), 1);\n\n/** CIECAM02's degree of chromatic adaptation at an adapting luminance (cd/m²): how much of the illuminant's colour the eye discounts. */\nexport const degreeOfAdaptation = (LA: number, F: number): number => F * (1 - (1 / 3.6) * Math.exp((-LA - 42) / 92));\n\n/** The Planckian locus in CIE 1931 xy — Kang et al. 2002's fit, 1667–25000 K. */\nexport function planckianXY(T: number): readonly [number, number] {\n const t = 1 / T;\n const t2 = t * t;\n const t3 = t2 * t;\n const x = T <= 4000 ? -0.2661239e9 * t3 - 0.2343589e6 * t2 + 0.8776956e3 * t + 0.17991 : -3.0258469e9 * t3 + 2.1070379e6 * t2 + 0.2226347e3 * t + 0.24039;\n const x2 = x * x;\n const x3 = x2 * x;\n const y = T <= 2222 ? -1.1063814 * x3 - 1.3481102 * x2 + 2.18555832 * x - 0.20219683 : T <= 4000 ? -0.9549476 * x3 - 1.37418593 * x2 + 2.09137015 * x - 0.16748867 : 3.081758 * x3 - 5.8733867 * x2 + 3.75112997 * x - 0.37001483;\n return [x, y];\n}\n\n/** A chromaticity as linear sRGB at Y = 1. */\nexport const xyToLinear = (x: number, y: number): RGB => mul(XYZ2RGB, [x / y, 1, (1 - x - y) / y]);\n\n/** D65's chromaticity — sRGB's white. */\nexport const D65: readonly [number, number] = [0.3127, 0.329];\n/** The spectral locus, CIE 1931 2°, 470–500 nm at 5 nm — the blue-cyan reach where the rods' hue is placed. */\nconst LOCUS = [[470, 0.1241, 0.0578], [475, 0.1096, 0.0868], [480, 0.0913, 0.1327], [485, 0.0687, 0.2007], [490, 0.0454, 0.295], [495, 0.0235, 0.4127], [500, 0.0082, 0.5384]] as const;\ntype Knot = (typeof LOCUS)[number];\nexport function spectralXY(nm: number): readonly [number, number] {\n const w = Math.min(Math.max(nm, LOCUS[0][0]), LOCUS[6][0]);\n let i = 0;\n while (i < LOCUS.length - 2 && (LOCUS[i + 1] as Knot)[0] <= w) i++;\n const [w0, x0, y0] = LOCUS[i] as Knot;\n const [w1, x1, y1] = LOCUS[i + 1] as Knot;\n const t = (w - w0) / (w1 - w0);\n return [x0 + (x1 - x0) * t, y0 + (y1 - y0) * t];\n}\n/** White pulled `purity` of the way toward a spectral hue, as linear sRGB at Y = 1. */\nexport function hueTint(nm: number, purity: number): RGB {\n const [sx, sy] = spectralXY(nm);\n return xyToLinear(D65[0] + (sx - D65[0]) * purity, D65[1] + (sy - D65[1]) * purity);\n}\n\n/**\n * The reference's day chain writes the LINEARISED albedo to the swap chain as sRGB\n * (README §4e), so what the display shows for a lit pixel is that value decoded once\n * more: the day's displayed luminance of a ground colour.\n */\nexport const dayLuminance = (groundSrgb: RGB): number => luminance(linear(linear(groundSrgb)));\n\n/** The eye's report of a linear albedo under `light` at `shade` (1 lit · `fill` in full shadow) — linear, before Eigengrau and the exposure. */\nexport function nightReport(light: MatLight, albedoLinear: RGB, shade: number): RGB {\n const cone: RGB = [albedoLinear[0] * light.moon[0] * shade, albedoLinear[1] * light.moon[1] * shade, albedoLinear[2] * light.moon[2] * shade];\n const rod = rodSignal(cone);\n const m = mesopicWeight((light.lux * luminance(cone)) / Math.PI);\n return tri((i) => (1 - m) * rod * light.rod[i] + m * cone[i]);\n}\n\n/** The shader's `night_mat` on the CPU: what the display shows (sRGB 0..1), the snow left out. */\nexport function nightAppearance(light: MatLight, albedoLinear: RGB, shade: number): RGB {\n const see = nightReport(light, albedoLinear, shade);\n return tri((i) => linearToSrgb(light.eigengrau[i] + see[i] * light.exposure));\n}\n\n/** The theme's night, computed for a ground colour (sRGB 0..1): the light the mat pass reads. */\nexport function nightLight(spec: NightSpec, groundSrgb: RGB): MatLight {\n const ground = linear(groundSrgb);\n const [px, py] = planckianXY(spec.kelvin);\n const moonRaw = xyToLinear(px, py);\n // the eye adapts to the Moon's colour only as far as this little light lets it (CIECAM02's D at the moonlit ground's luminance)\n const D = degreeOfAdaptation((spec.lux * luminance(ground)) / Math.PI, spec.surround);\n const moon: RGB = [1 + (1 - D) * (moonRaw[0] - 1), 1 + (1 - D) * (moonRaw[1] - 1), 1 + (1 - D) * (moonRaw[2] - 1)];\n const eigengrau = linear(spec.eigengrau);\n const light: MatLight = { night: 1, lux: spec.lux, exposure: 1, snow: spec.snow, moon, fill: spec.fill, rod: hueTint(spec.rodHue.nm, spec.rodHue.purity), eigengrau };\n // the one scale: the lit ground's report, drawn so the display's luminance there (Eigengrau included) is the theme's number\n const above = Math.max(spec.litLuminance - luminance(eigengrau), 0);\n return { ...light, exposure: above / Math.max(luminance(nightReport(light, ground, 1)), 1e-9) };\n}\n\n/** The light's four vec4s, by name (MatUniforms). */\nexport function lightValues(l: MatLight): { night: number[]; moon: number[]; rod: number[]; eigengrau: number[] } {\n return {\n night: [l.night, l.lux, l.exposure, l.snow],\n moon: [l.moon[0], l.moon[1], l.moon[2], l.fill],\n rod: [l.rod[0], l.rod[1], l.rod[2], 0],\n eigengrau: [l.eigengrau[0], l.eigengrau[1], l.eigengrau[2], 0],\n };\n}\n\n/**\n * A light between two (design-015 §8, D4b — the reading light): the object in hand keeps its DAY light while the mat\n * stays moonlit, the change riding the carry (`t` 0 = `a`, 1 = `b`); every field lerped, the colours channel-wise.\n * `nightAppearance` is linear in each of them within a frame, so a lerp of the parameters is an honest in-between.\n */\nexport function mixLight(a: MatLight, b: MatLight, t: number): MatLight {\n if (t <= 0) return a;\n if (t >= 1) return b;\n const l = (x: number, y: number): number => x + (y - x) * t;\n const c = (x: RGB, y: RGB): RGB => [l(x[0], y[0]), l(x[1], y[1]), l(x[2], y[2])];\n return { night: l(a.night, b.night), lux: l(a.lux, b.lux), exposure: l(a.exposure, b.exposure), snow: l(a.snow, b.snow), moon: c(a.moon, b.moon), fill: l(a.fill, b.fill), rod: c(a.rod, b.rod), eigengrau: c(a.eigengrau, b.eigengrau) };\n}\n","// The ground's colours and material numbers — the ENGINE's half of the theme.\n//\n// Two homes, one law: a colour literal lives here or in the host's projection\n// (`lab/theme.ts` — VibeField's `--vf-*` tokens transcribed by name; at the fold,\n// field-app's `canvas-appearance.ts` reading them off the stamped root), and\n// nowhere else in src/, shaders/ or lab/ — `test/theme.test.ts` enforces it.\n// This file holds what the engine SHIPS: the types and the CSS-colour parser;\n// `themeFrom` (a palette → the numbers the passes read); the grid's fade-in\n// law; and the desk's materials, each with its lineage named — the cutting mat\n// with its two lights (the tree-shadow reference; MAT.md), the paper, the hand,\n// the notebook, the whiteboard and the mini mat. A product's palette is the\n// product's: it reaches the passes through `GroundTheme`, never from here.\n// Split from the one-file projection on 2026-09-07, before B1 (the move). The\n// card chrome's numbers (the §2.3 lines, the §5 shadow, the §7 lift and heat)\n// and the magnet field's (ICE's grid defaults) retired with the card frame and\n// the dot and needle grids on 2026-09-25 (MINIMAT.md §1).\n\nimport { DAY_LIGHT, dayLuminance, type MatLight, nightLight } from \"./mat/night\";\n\nexport type RGB = readonly [number, number, number];\nexport type RGBA = readonly [number, number, number, number];\nexport type ThemeName = \"light\" | \"dark\";\n\n/** How `cssColor` and `rgb` treat a string they cannot parse (petition I32). */\nexport interface ColourParse {\n /**\n * THROW (`theme: unparsed colour \"…\"`) instead of answering `MISSING_INK` — for a colour whose typo is a bug to fail on at the\n * call: the engine's own colours and a host's palette (`themeFrom`) are parsed so. A kind's colour from a prop never is.\n */\n readonly strict?: boolean;\n}\n\n/**\n * Parse the CSS colour syntaxes tokens.css uses — `#rrggbb`, `rgb(r g b / p%)`,\n * `rgba(r, g, b, a)` — into sRGB 0..1 + alpha. The swap chain is a plain\n * 8-bit format, so what CSS shows is what the shader writes.\n *\n * A string it cannot parse — another syntax (a name, `#rgb`, `hsl(…)`), a typo, or no string at all — answers `MISSING_INK` (the\n * desk's ink, opaque) and is SAID ONCE: a `console.warn` naming it, the first time a page meets that string — never a throw, so a\n * kind whose `record` or `resolve` feeds a user's colour through here draws in the missing ink instead of being struck for it\n * (petition I32; I24's ladder). `{ strict: true }` throws instead.\n */\nexport function cssColor(css: string, opts?: ColourParse): RGBA {\n const s = typeof css === \"string\" ? css.trim().toLowerCase() : \"\";\n let m = /^#([0-9a-f]{6})$/.exec(s);\n if (m) {\n const v = Number.parseInt(m[1] as string, 16);\n return [((v >> 16) & 255) / 255, ((v >> 8) & 255) / 255, (v & 255) / 255, 1];\n }\n m = /^rgba?\\(\\s*(\\d+)[\\s,]+(\\d+)[\\s,]+(\\d+)\\s*(?:[/,]\\s*([\\d.]+)(%?))?\\s*\\)$/.exec(s);\n if (m) {\n const a = m[4] === undefined ? 1 : m[5] === \"%\" ? Number(m[4]) / 100 : Number(m[4]);\n return [Number(m[1]) / 255, Number(m[2]) / 255, Number(m[3]) / 255, a];\n }\n if (opts?.strict === true) throw new Error(`theme: unparsed colour \"${String(css)}\"`);\n return unparsed(css);\n}\n/** `cssColor` without its alpha: sRGB 0..1. An unparsed string answers `MISSING_INK`'s three channels, said once (`{ strict: true }` throws). */\nexport const rgb = (css: string, opts?: ColourParse): RGB => cssColor(css, opts).slice(0, 3) as unknown as RGB;\n/** The engine's own colours parse strictly: a typo there is the engine's bug, thrown at import. */\nconst STRICT: ColourParse = { strict: true };\n\n/** The unparsed colours already said on this page (petition I32): each distinct one once, the first `UNPARSED_SAID` of them. */\nconst unparsedSaid = new Set<string>();\nconst UNPARSED_SAID = 32;\n/** An unparsed colour: said once a page — what it was, what it is drawn as, how to get the throw — and answered `MISSING_INK`. */\nfunction unparsed(css: unknown): RGBA {\n const key = typeof css === \"string\" ? css : `(${css === null ? \"null\" : typeof css})`;\n if (unparsedSaid.size < UNPARSED_SAID && !unparsedSaid.has(key)) {\n unparsedSaid.add(key);\n const shown = typeof css === \"string\" ? JSON.stringify(css.length > 64 ? `${css.slice(0, 64)}…` : css) : `(${key.slice(1, -1)} — not a string)`;\n const last = unparsedSaid.size === UNPARSED_SAID ? `; ${UNPARSED_SAID} have now been said, and the rest will not be` : \"\";\n console.warn(`[ice] desk: unparsed colour ${shown} — drawn in the missing ink. The parser reads #rrggbb, rgb(r g b / a) and rgba(r, g, b, a); \\`rgb(s, { strict: true })\\` throws instead (petition I32)${last}.`);\n }\n return [MISSING_INK[0], MISSING_INK[1], MISSING_INK[2], MISSING_INK[3]]; // a copy, as every parse answers one: a caller's write never reaches the constant\n}\n\n/** A colour as the design kit names it, with its CSS value verbatim. */\nexport interface TokenRef {\n /** `--vf-*` = a tokens.css token (checked by name); anything else names its DESIGN.md source. */\n readonly token: string;\n readonly css: string;\n}\n\n/** The roles the ground paints from a product's palette, one token each, per theme. */\nexport interface Palette {\n readonly canvasBg: TokenRef; // §2.1 the ground — the clear colour under the mat\n readonly select: TokenRef; // §2.5 selection ring only\n}\n\n/**\n * The GRID's fade-in window — the lattice's one law for every rung (lod.ts `FadeIn`,\n * line.ts): a rung fades in as its OWN cell grows from 10 to 20 CSS px, one octave\n * under the decade's 20 px bottom, so zoom 1 lands on a full lattice. The mat's\n * lines, the rulers' ticks and a mini mat's face all read it. (It was the magnet\n * field's `fadeIn` — ICE's `worldGrid.fadeIn` — and is the one number of that set\n * the mat kept.) And the DRESSING's floor (PORTAL.md §9, MINIMAT.md §5): a mini mat's inside is dressed\n * for its arrival — its lattice as it will look when entered, scaled — but the window is never scaled\n * below this share of itself, so a miniature's grid is never finer than half the desk's: a tiny mini\n * mat shows its inside's major lines, not a haze of its minor ones. The live inside, the face's far\n * LOD and a flight's two desks all take the same floor, so none of them can disagree.\n */\nexport const GRID = { fadeIn: [10, 20] as const, dressFloor: 0.5 } as const;\n\n/**\n * The CUTTING MAT — the ground's one grid: a hairline lattice on a green mat, ported\n * from research/tree-shadow/prototype (the oryzo \"hero desk\"). Its colours are\n * a material's, carried across both themes like an object's own colours;\n * the numbers are the reference's, transcribed with their names. DESIGN.md has\n * no cutting-mat row yet (it is a research port) — the token names below say\n * where each value came from, and adding the material to the doc is the step\n * before any of this leaves draft/.\n *\n * The reference draws its albedo through `srgbToLinear` and then `pow(2.2)`\n * again, grades in HSB, and writes `pow(1/2.2)` straight to the swap chain: the\n * mat on screen is the LINEARISED sage, a dark green. That chain is the look\n * and is kept verbatim (mat.wgsl), so `ground` and `line` below are the values\n * the chain STARTS from, not what a pixel measures.\n */\nexport const MAT = {\n ground: { token: \"hero cuttingMatAlbedo `sage`\", css: \"#86a078\" }, // 134 160 120\n line: { token: \"hero cuttingMatAlbedo `cream`\", css: \"#e8dcbe\" }, // 232 220 190\n /** The colour a desk object's shadow casts ON the mat — the tree-shadow design system's `--cast-rgb` (mat.css: \"the world's darkest value\"). */\n cast: { token: \"tree-shadow design mat.css `--cast-rgb`\", css: \"#0e1a0a\" }, // 14 26 10\n} as const;\n/** The same, parsed — what a pass reads (nothing outside this file parses a colour). */\nexport const MAT_COLORS: { readonly ground: RGB; readonly line: RGB; readonly cast: RGB } = { ground: rgb(MAT.ground.css, STRICT), line: rgb(MAT.line.css, STRICT), cast: rgb(MAT.cast.css, STRICT) };\n\n/**\n * THE PALETTE A KIND'S `theme` IS HANDED (petition I46): the host's roles — and its own extra ones, as it passed them — and beside\n * them the desk's OWN material role a kind needs to stand on the mat as the built-ins do: `cast`, the colour an object's shadow casts\n * ON the mat (the mat's own — `MAT.cast`, the same in both stock themes). A kind reads it in its `theme` (`rgb(palette.cast.css)`),\n * so its shadow falls in the mat's colour in every theme with no copy of the number. It is the DESK's word: a host's palette never\n * sets it (a `cast` there is replaced).\n */\nexport interface KindPalette extends Palette {\n readonly cast: TokenRef;\n}\n\n/** A host's palette as a kind's `theme` is handed it (I46 — `KindPalette`): every role the host passed, with the mat's `cast`. */\nexport function kindPalette<P extends Palette>(palette: P): P & KindPalette {\n return { ...palette, cast: MAT.cast };\n}\n\n/**\n * The mat's line law and the gobo's numbers (research/tree-shadow/prototype:\n * shaders.js `cuttingMatAlbedo` · `sampleGobo` · `heroFrag`, scenes.js `hero`).\n * Line widths are DEVICE px — the reference's hairlines are 0.5 / 0.75 of a\n * framebuffer pixel; the alphas ride the engine's `fadeIn` window (line.ts).\n */\nexport const MAT_GRID = {\n line: { thin: 0.5, thick: 0.75, alphaThin: 0.14, alphaThick: 0.28 },\n /** ±8/255 on the green channel (0.4× red, 0.35× blue): static hash + drifting value noise + blue noise. */\n grain: 8 / 255,\n gobo: {\n opacity: 1,\n /** `getGoboBlurRatio(z, params) * 2.0` — the blur radius in plate texels at full softness. */\n blurTexels: 2,\n /** heroFrag: `shade = mix(1, coaster·(0.5 + 0.5·gobo), 0.975)`; then HSB s += (1−shade)·0.1, v *= shade. */\n shadeMix: 0.975, darkFloor: 0.5, saturate: 0.1,\n /** scenes.js `hero.params` — the blur ramp's two linear depths (metres from the projector). */\n sharp: 0.372991, soft: 0.79059,\n /** The plates: R silhouette, G wind amp 1, B phase, A amps 2+3; each with its wind strength. */\n plates: { c: { strength: 0.38847005 }, b: { strength: 0.4630597 } },\n plate: \"c\" as \"c\" | \"b\",\n /** gobo.js: `time += dt·(speed + 1 + r)` at speed 4; the lab's 0 = frozen. */\n wind: 5,\n /** hero `mouseStrength` — radians of projector tilt per unit of smoothed pointer NDC. */\n tilt: 0.003,\n },\n /**\n * The RULERS printed along the mat's top and left edges (RULER.md — James's mockup of\n * 2026-09-23, measured at its 1.6×: a 41 px band under a 41 px margin, 12 px numerals,\n * ticks 9 · 15 · 24, 1–2 px lines): one MODULE for the unprinted margin and one for the\n * band; 1 px lines; the text 10 px mono (DESIGN.md §3's caption size, the product's\n * `--vf-font-mono`) 5 px in from the outer line and 3 px after its tick; the ink the\n * mat's own cream at these presences. The fine rung's ticks arrive over a 6 → 9 px pitch\n * (a ruler's mm under its cm; at 5 the comb read busy) and a level's labels over 50 → 70 px,\n * so labels sit 50–250 px apart at every zoom (lattice/ruler.ts).\n */\n ruler: {\n band: 26, margin: 26, tick: [6, 9, 15], line: 1,\n alpha: { frame: 0.55, tick: 0.85, label: 0.85 },\n ticksFrom: [6, 9], labelsFrom: [50, 70],\n text: { size: 10, top: 5, gap: 3 },\n maxChars: 9,\n },\n /**\n * World → desk: the hero's view at its default height is 0.2227 m over the\n * window's height (900 px in the reference shots), so one world unit (a CSS\n * px at zoom 1) is 0.2227 / 900 m and the dapple spans the same screen at\n * zoom 1. The mat's centre (the reference's coaster) is world (0, 0); the\n * desk plane is `y = 0.7471` in the projector's frame.\n */\n plane: { metresPerUnit: 0.2227 / 900, originX: -0.0105761, originZ: -0.0485146, deskY: 0.7471 },\n} as const;\n\n/**\n * The NIGHT — the cutting mat in the dark theme (MAT.md). The mat is a material and\n * keeps its sage and cream in both themes; what the theme changes is the LIGHT: the\n * Sun by day (the reference's chain, verbatim), the Moon by night — and the eye that\n * sees by it. Every number here is a choice with its source; `mat/night.ts` turns\n * them into the shader's numbers.\n */\nexport const NIGHT = {\n /** Full moonlight is REDDER than sunlight — ≈ 4100 K against the Sun's ≈ 5500 (Ciocca & Wang 2013); the blue of a moonlit scene is the eye's, not the light's. */\n kelvin: 4100,\n /** A full Moon high in a clear sky: 0.1–0.3 lux on the ground, a million times under the Sun's. Where on the mesopic ramp the eye sits. */\n lux: 0.2,\n /** The sky's share in the shadow — the same air scatters the same fraction of the Moon as of the Sun, ≈ 0.15–0.2 of the direct light at 45°. */\n fill: 0.18,\n /** The rods' signal drawn as a colour: white pulled 18 % toward 485 nm — the low-purity blue the night-rendering literature gives scotopic vision (Jensen et al. 2000; Khan & Pattanaik 2004). */\n rodHue: { nm: 485, purity: 0.18 },\n /** Eigengrau — the \"intrinsic grey\" the eye reports with no light at all (the rods' own dark noise); the value the term is given. */\n eigengrau: { token: \"Eigengrau (the dark's own grey)\", css: \"#16161d\" },\n /** The appearance's one scale: the moonlit sage is drawn at HALF the sunlit one's displayed luminance — the million can't be shown; the adapted eye's report is. */\n litOverDay: 0.5,\n /** The rods' own noise on the display: ±2/255, blue noise, achromatic. */\n snow: 4 / 255,\n /** CIECAM02's surround factor for the eye's adaptation to the Moon's colour: 0.8, a dark surround. */\n surround: 0.8,\n} as const;\n\n/** The night's model, for a host that rebuilds the Moon from its own numbers (the desk's dev panel — D5a; the prototype's lab/params.ts). */\nexport { dayLuminance, type MatLight, nightLight } from \"./mat/night\";\n\n/** Eigengrau, parsed — what a host hands `nightLight` (lab/params.ts rebuilds the night from its panel). */\nexport const EIGENGRAU: RGB = rgb(NIGHT.eigengrau.css, STRICT);\n\n/** The light the mat pass reads, per theme: the Sun (the reference's chain, bit for bit) by day, the Moon by night. */\nexport const MAT_LIGHT: Record<ThemeName, MatLight> = {\n light: DAY_LIGHT,\n dark: nightLight({\n kelvin: NIGHT.kelvin, lux: NIGHT.lux, fill: NIGHT.fill, rodHue: NIGHT.rodHue, eigengrau: EIGENGRAU,\n litLuminance: NIGHT.litOverDay * dayLuminance(MAT_COLORS.ground), snow: NIGHT.snow, surround: NIGHT.surround,\n }, MAT_COLORS.ground),\n};\n\n/**\n * The PORTAL's law (PORTAL.md §2.5, MINIMAT.md §5) — the live inside's GATE: a container's face shows its live inside\n * only when its short side on screen is at least `lo` CSS px, fading in fully by `hi` (the rung law applied to portals).\n * Under it the face is drawn by the container itself (the mini mat's lattice and chips); across it the nested desk fades\n * in over them; past it the face is the nested desk, the flight's first frame. The engine's (nav/portal.ts\n * `PORTAL_GATE`) since K4a — the mini mat's law (minimat/theme.ts) takes it by name, and the kinds' specs moved to their\n * own folders (paper/, notebook/, board/, minimat/ `theme.ts`; the hand's law to kit/text.ts; what they share to\n * kit/physics.ts).\n */\nexport const PORTAL = { gate: [140, 220] as const } as const;\n\n/**\n * The MARKS — the desk's chrome as the renderer draws it over every object (stratum 5; design-015 §7,\n * D4a): *Marks on the Mat* v2 (claude.ai artifact W9xB23bF9JkSoZhxqKpjaQ, sources\n * `vibe-field/draft/desk-chrome/`; Q-a…Q-k agreed 2026-09-25), its proposed DESIGN.md §14 \"the\n * desk's hands\". Every mark has one hand and every hand one ink: YOU draw in the PENCIL — the\n * selection's focus brackets, a several's union and its members' ticks, the knobs, the vellum\n * marquee, your extent on the rulers (`--vf-select`'s hue, OKLCH 252°, lifted to L .76: 3.62:1 on\n * the lit mat) — with a dark KEYLINE under every stroke so it holds on paper and on the whiteboard;\n * the DESK states facts about space in the LASER — the snap guides, the equal gaps and their numbers\n * — which is light, so it is ADDED; and the TAPE is masking tape across a taped object's top corners,\n * an attachment of the OBJECT (it zooms with it) and so moonlit by night, where the pencil and the\n * laser are light and the Moon does not dim them (Q-k). Lengths are SCREEN px (the chrome keeps its\n * size at every zoom) unless named; the numbers are chrome.js's `CHROME`/`INK` and its `drawSelection`\n * · `drawMember` · `drawUnion` · `drawMarquee` · `drawGuides` · `flare` · `pill` · `drawRulerBand`,\n * number for number, and desk.css's tape; the clocks are the page's §14 motion table (ms).\n */\nexport const MARKS = {\n /** The inks, each with its token (the page's §14; desk.css; chrome.js `INK`). */\n inks: {\n pencil: { token: \"--desk-pencil (Marks on the Mat §14, proposed)\", css: \"#79b5f8\" },\n /** The keyline under a pencil stroke: the mat's cast at 34 % (`--desk-keyline`). */\n keyline: { token: \"--desk-keyline — the tree-shadow design's `--cast-rgb`\", css: \"rgb(14 26 10 / .34)\" },\n /** A resize knob's face: chrome.js `INK.paper`. */\n paper: { token: \"chrome.js INK.paper\", css: \"#fffdf8\" },\n laser: { token: \"--desk-laser (the bloom, added)\", css: \"#ff2e93\" },\n laserLine: { token: \"--desk-laser-line\", css: \"#ff4fa3\" },\n laserCore: { token: \"--desk-laser-core (5.94:1 on the lit mat)\", css: \"#ffd6ea\" },\n /** The pencil pill's numerals: the tray's ink (`--desk-ink`, solid); the laser pill's: white. */\n tray: { token: \"--desk-ink, solid (the tree-shadow design's `--ink`)\", css: \"#100904\" },\n white: { token: \"chrome.js `pill` — the laser pill's numerals\", css: \"#ffffff\" },\n tape: { token: \"--desk-tape\", css: \"rgb(238 228 204 / .88)\" },\n /** The vellum's veil: cream by day, a cool milk by night (chrome.js `drawMarquee`). */\n vellumDay: { token: \"chrome.js vellum, day\", css: \"rgb(255 250 238 / .11)\" },\n vellumNight: { token: \"chrome.js vellum, night\", css: \"rgb(214 226 255 / .07)\" },\n },\n /** The keyline is this much wider than the stroke it lies under. */\n keyline: { grow: 2 },\n /** One object selected: the frame 6 out, brackets reaching 16 (≤ 30 % of a side, never under r + 2), 1.5 thick, the hairline between them one DEVICE px at 42 %, the corner r + 6 ≤ 10; the lock-on arrives from 8 further out, its presence full by 1/2.2 of the way; knobs (radius 3.5, a cast ring 1 wider at 28 %) where the object resizes; under 24 px on screen, one ring. */\n select: { gap: 6, reach: 16, share: 0.3, minOverR: 2, stroke: 1.5, hair: 0.42, radiusMax: 10, arrive: 8, rise: 2.2, knob: 3.5, knobShadow: 0.28, knobStroke: 1.5, collapse: 24 },\n /** A member of several: quiet ticks — 4 out, reaching 8, 1.25 thick, at 62 %; the union carries the weight. */\n member: { gap: 4, reach: 8, radiusMax: 8, stroke: 1.25, alpha: 0.62 },\n /** Several: one union, 10 out, square to the mat, its corner 4. */\n union: { gap: 10, radius: 4 },\n /** The vellum: its pencil edge at 80 % (one device px), brackets reaching 12 at its corners once both sides pass 14, the count riding the cursor at +14, +18. */\n marquee: { edge: 0.8, reach: 12, minSide: 14, count: [14, 18] as const },\n /** A number the desk states: 10 px mono, 8 wider than its text, 15 tall, corner 3.5. */\n pill: { size: 10, pad: 8, height: 15, radius: 3.5 },\n /** The tray's name tags as LABEL TAPE (K5b, D-K5b.7 — marks/layout.ts `tagMarks`): the embosser's near-black tape and the pale plastic of its raised capitals. */\n label: { tape: \"#17181b\", letters: \"#ecebe4\" },\n /**\n * The laser: a faint line wall to wall (3 px at 12 %, then 1 device px + 0.5 at 34 %, both added), and between the\n * objects it aligns, 14 past them, the bloom (9 · 5 · 2.6 px at 7 · 16 · 32 %, added) under a 1.25 px line at 95 %\n * with a 0.6 px core at 95 %; a centre is dotted (a dot every 4.51 px: the bloom 0.7 as wide, the line 2, the core 1);\n * a new alignment strikes at 1.8×; a flare (radius 7) at every aligned corner; a gap, a 4 px bloom at 18 % under a\n * 1.1 px line with 4 px ticks at its ends, its number in a laser pill on it (off it, under 26 px).\n */\n laser: {\n wall: [[3, 0.12], [0.5, 0.34]] as const, bloom: [[9, 0.07], [5, 0.16], [2.6, 0.32]] as const,\n line: 1.25, core: 0.6, alpha: 0.95, dotted: { period: 4.51, bloom: 0.7, line: 2, core: 1 }, past: 14, strike: 0.8,\n flare: { radius: 7, stop: 0.25, core: 0.9, mid: 0.55 },\n bar: { bloom: [4, 0.18] as const, line: 1.1, tick: 4, pillFrom: 26, off: [16, 14] as const },\n },\n /** Your extent on the rulers (the mat's RULER band): a pencil wash at 16 %, its edges at 95 %, the edge coordinates 4 off them, 7 up from the band's inner line, over a 3 px cast halo at 55 %; a guide ticks the band in laser (1.5 px at 90 %, added). */\n ruler: { wash: 0.16, edge: 0.95, label: { gap: 4, lift: 7, halo: 1.5, haloAlpha: 0.55 }, tick: { width: 1.5, alpha: 0.9, inset: 3 } },\n /** Masking tape (desk.css `.obj-tape`): two strips 60 × 17 (object units) crossing the top corners, 5 over the top edge and 20 past each side, turned 37°; fibres 1 in 3 at 10 % white, a light from above (18 % white → 4 % black); moonlit by night. */\n tape: { w: 60, h: 17, over: 5, past: 20, turn: 37, fibre: { every: 3, alpha: 0.1 }, sheen: [0.18, 0.04] as const, night: { saturate: 0.3, brightness: 0.46 }, press: 1.22 },\n /** The clocks, ms: the lock-on (on `--vf-ease-lift`) and the leave; several's union and its fade; the vellum's fold (`--vf-ease-island`); the strike; the tape pressed (the second strip 60 later) and lifted; the tape's GIVE — a drag that meets it shivers 2.2 px and settles. */\n clocks: { lockOn: 180, leave: 120, union: 220, unionFade: 120, fold: 240, strike: 160, tapePress: 240, tapeStagger: 60, tapeLift: 160, give: 360 },\n give: { px: 2.2, rate: 44 },\n} as const;\n\n/**\n * THE PEGBOARD TRAY (design-017 §6.5–§6.6; K3; design-018 §3) — the research board (research/sdf-pegboard, shader.js) under the desk's\n * light, lying ON the mat. The face is its own render's (preview.jpg): lit flat, a flat face is drawn at this byte (the paper's law — a\n * configured byte is the drawn byte). The punched edge keeps the research's edge/face albedo ratio. A hole shows the DESK as drawn under\n * it (design-018 §3 — the research's plaster wall retired): the cavity is the share of the room's light that reaches the mat through a\n * hole — at the hole's edge, at its heart, over what width (pitches) — kept near 1, so the densest hole is the mat's own shade under a\n * leaf (one shadow language). The LAMP is the research's HOME lamp (D-K3.4, decided): from the upper left at 48°, so its light lays a\n * patch through each slot on the mat, a shadow crescent along the lamp's side — its direction as the research states it (shader.js\n * `lightDir`: azimuth from the eye's axis toward +x, elevation up the board, degrees), its angular radius the research's too (D-K3.5);\n * the colour law and the room are the desk's.\n */\nexport const TRAY = {\n face: { token: \"research/sdf-pegboard preview.jpg — the face, lit flat\", css: \"#cdb491\" },\n /** shader.js FACE_ALB · EDGE_ALB, linear. */\n research: { face: [0.42, 0.26, 0.135], edge: [0.56, 0.41, 0.25] },\n cavity: { edge: 0.9, heart: 1, width: 0.1 },\n lamp: { azimuth: -36, elevation: 48 },\n lampSize: 0.06,\n /** K5a — a specimen under the mouse lifts this share of the hold's lift (its own kind's `lift`): its shadow grows. */\n hoverLift: 0.3,\n} as const;\n\n/**\n * THE MISSING FACE (petition I24 — missing/): what the desk draws for an object NOTHING can draw — its kind refused at create or\n * quarantined at three strikes (faults.ts), or its type without a kind on this desk. Faint and square to the mat, the size of the\n * object's box, and no text (the kind's name is said in the notice, never on the desk): a wash of the desk's ink, its hatching at 45°\n * and a hairline edge — the tray's ink by day, the night vellum's cool milk by night (`MARKS.inks`). The hatching's pitch and\n * weights are CSS px (it reads at every zoom); the corner is the object's units.\n */\nexport const MISSING = {\n ink: { light: MARKS.inks.tray.css, dark: \"rgb(214 226 255)\" },\n /** The wash under it all, the hatching's and the edge's alpha. */\n wash: 0.05,\n hatch: 0.2,\n edge: 0.36,\n /** The hatching's pitch and weight, the edge's weight, CSS px; the corner, world units (the box's half side at most). */\n pitch: 9,\n weight: 1,\n edgeWeight: 1,\n corner: 6,\n} as const;\n\n/**\n * THE MISSING INK (petition I32) — what `cssColor` answers for a colour it cannot parse, and `rgb` its three channels: the missing\n * face's ink by day (`MISSING.ink.light`, the tray's `--desk-ink`), opaque. One law with I24's face — what the desk cannot read is\n * drawn in the desk's own ink: the object stays visible and pickable, plainly not the colour that was asked for. Not transparent:\n * that would hide the very object whose colour is wrong (and `rgb` has no alpha to zero). Theme-blind: a kind's colour is an\n * albedo the desk's light grades, by day and by night alike.\n */\nexport const MISSING_INK: RGBA = cssColor(MISSING.ink.light, STRICT);\n\n/** Everything the passes read, as numbers. */\nexport interface GroundTheme {\n readonly name: ThemeName;\n /** The clear colour — what shows where nothing is drawn (the mat covers it at rest). */\n readonly canvasBg: RGB;\n /** §2.5 the selection ring. */\n readonly select: RGB;\n /** The cutting mat's light (mat/night.ts): the Sun by day, the Moon by night. */\n readonly matLight: MatLight;\n}\n\n/** A theme from a palette — the host's projection (lab/theme.ts builds VibeField's two). */\nexport function themeFrom(name: ThemeName, p: Palette): GroundTheme {\n // a host's palette is parsed strictly: a malformed colour throws at the call (petition I32 keeps the throw where the caller is the host)\n return { name, canvasBg: rgb(p.canvasBg.css, STRICT), select: rgb(p.select.css, STRICT), matLight: MAT_LIGHT[name] };\n}\n","// How a slot PRESENTS itself this frame: an opacity, and the rounded rects on\n// screen it is visible through — the FACE it is seen through (its portal: a\n// mini mat's cutting area, MINIMAT.md §3) and, for a nested slot, the faces of\n// every slot above it (`within`, nearest first): the CHAIN. During a flight the\n// arriving desk's ground is visible only through the mini mat's face (enter),\n// or the departing desk's only through the face it shrinks into (exit); a\n// nested slot's inside is visible only where its face lies inside its parent's,\n// and so on up; at rest the root presents everything. Every pass reads the chain by name (`portals`, `clips`)\n// and multiplies its coverage by `portal_cover` (shaders/portal.wgsl); the\n// ground also scissors the slot's draws to the chain's bounding box so nothing\n// outside it is shaded.\n\nimport type { Box } from \"../lattice/lod\";\nimport { PORTAL } from \"../theme\";\nimport type { CameraState, Rect, Viewport } from \"./flight\";\n\n/**\n * A rounded rect in screen CSS px: centre, half extents, corner radius — and a top FEATHER (design-018 §4): what the face shows\n * fades in over this many CSS px below its top edge, a smoothstep in every pass's `portal_cover` (absent or 0: a hard edge). The\n * pegboard tray's face carries one — its top the foot of the drawer's clear header (design-018 R4) — so its specimens dissolve into the\n * board under the header instead of being cut.\n */\nexport interface PortalClip { readonly cx: number; readonly cy: number; readonly hx: number; readonly hy: number; readonly r: number; readonly feather?: number }\n\n/**\n * The most faces a slot can be seen through, its own included — the length\n * of every uniform block's `portals`/`clips` arrays; portal.wgsl's\n * `PORTAL_CHAIN` is the same number (a mismatch fails to compile). Six holds\n * a host's depth belt of four plus the flight's face.\n */\nexport const PORTAL_CHAIN = 6;\n/** The struct field type of a chain record (gpu/struct.ts). */\nexport const PORTAL_CHAIN_TYPE = `array<vec4f, ${PORTAL_CHAIN}>` as const;\n\nexport interface Presentation {\n /** Multiplies the slot's every alpha; 1 at rest. */\n readonly opacity: number;\n /**\n * Multiplies its OBJECTS' alphas on top — not its mat (MINIMAT.md §5): a mini mat's live inside\n * comes in over the face's own drawing with its mat whole at once (the same lattice, lit by the\n * same lamp — nothing to see) and its objects fading in by the gate's answer, as the face's chips\n * fade out over them. Absent = 1.\n */\n readonly objects?: number;\n /** The face this slot is seen through; absent = visible everywhere (the root). */\n readonly portal?: PortalClip;\n /**\n * The faces the slot's PARENT is seen through, nearest first: a nested slot is\n * visible only inside all of them. The ground fills this in from the tree\n * (PORTAL.md §10); a host never needs to.\n */\n readonly within?: readonly PortalClip[];\n}\n\n/** The chain a presentation clips to: its own face first, then every face above it. Empty = everywhere. */\nexport function chainOf(p: Presentation | undefined): PortalClip[] {\n const out: PortalClip[] = [];\n if (p?.portal) out.push(p.portal);\n if (p?.within) out.push(...p.within);\n return out;\n}\n\n/** The `portals` and `clips` records every uniform block carries: the chain in order, a zero `clips[i].y` ending it; `clips[i].z` the feather. */\nexport function portalValues(p: Presentation | undefined): { portals: number[]; clips: number[] } {\n const portals = new Array<number>(4 * PORTAL_CHAIN).fill(0);\n const clips = new Array<number>(4 * PORTAL_CHAIN).fill(0);\n const chain = chainOf(p);\n if (chain.length > PORTAL_CHAIN) throw new Error(`nav/portal: a chain of ${chain.length} faces exceeds PORTAL_CHAIN ${PORTAL_CHAIN}`);\n chain.forEach((c, i) => { portals[4 * i] = c.cx; portals[4 * i + 1] = c.cy; portals[4 * i + 2] = c.hx; portals[4 * i + 3] = c.hy; clips[4 * i] = c.r; clips[4 * i + 1] = 1; clips[4 * i + 2] = c.feather ?? 0; });\n return { portals, clips };\n}\n\n/** A world rect (with a corner radius) as the portal it makes on screen under `cam`. */\nexport function clipOf(K: Rect, radius: number, cam: CameraState): PortalClip {\n const z = cam.zoom;\n return { cx: (K.x + K.width / 2 - cam.x) * z, cy: (K.y + K.height / 2 - cam.y) * z, hx: (K.width / 2) * z, hy: (K.height / 2) * z, r: radius * z };\n}\n\n/**\n * The slot's BOX for a portal (CSS px, inside the attachment; lod.ts `Box`):\n * the portal's bounding box plus a CSS px for the AA ramp. What a nested\n * slot instances, bakes and culls — its cost (PORTAL.md §2.3). The ground\n * intersects it with the parent's box (§10).\n */\nexport function boxOfPortal(c: PortalClip, attach: { readonly width: number; readonly height: number }): Box {\n const x0 = Math.max(0, c.cx - c.hx - 1);\n const y0 = Math.max(0, c.cy - c.hy - 1);\n const x1 = Math.min(attach.width, c.cx + c.hx + 1);\n const y1 = Math.min(attach.height, c.cy + c.hy + 1);\n return { x: x0, y: y0, w: Math.max(0, x1 - x0), h: Math.max(0, y1 - y0) };\n}\n\n/** The intersection of two boxes; empty (zero size) when they miss. */\nexport function intersectBox(a: Box, b: Box): Box {\n const x0 = Math.max(a.x, b.x);\n const y0 = Math.max(a.y, b.y);\n const x1 = Math.min(a.x + a.w, b.x + b.w);\n const y1 = Math.min(a.y + a.h, b.y + b.h);\n return { x: x0, y: y0, w: Math.max(0, x1 - x0), h: Math.max(0, y1 - y0) };\n}\n\n// ---------------------------------------------------------------- the live portal (PORTAL.md)\n\n/**\n * The GATE (PORTAL.md §2.5, MINIMAT.md §5): a container's face shows its LIVE\n * inside only when its short side on screen is at least `lo` CSS px, fading in\n * fully by `hi` — the rung law applied to portals. Below it no slot exists and\n * the mini mat draws its face itself (its far LOD); zoomed out, a desk of mini\n * mats costs one instanced draw. The engine holds the numbers (theme.ts\n * `PORTAL.gate`); the mini mat, the one container, takes them by name.\n */\nexport const PORTAL_GATE: readonly [number, number] = PORTAL.gate;\n/** The pool's cap: at most this many faces carry a slot per frame, largest first (PORTAL.md Q-f). */\nexport const PORTAL_CAP = 16;\n\nconst smoothstep = (a: number, b: number, x: number): number => { const t = Math.min(Math.max((x - a) / Math.max(b - a, 1e-3), 0), 1); return t * t * (3 - 2 * t); };\n/** The slot's presence for a face on screen — its opacity; 0 = no slot. */\nexport const portalPresence = (c: PortalClip, gate: readonly [number, number] = PORTAL_GATE): number => smoothstep(gate[0], gate[1], 2 * Math.min(c.hx, c.hy));\n\n// (`portalOf` — a container's live portal resolved under the gate, null below it — retired with the\n// folder card, 2026-09-25: a mini mat's face needs its embedding at every size, for the far LOD as for\n// the live inside, so the mini mat's `insideView` (minimat/inside.ts) resolves it always.)\n\n/**\n * ZOOM-THROUGH (PORTAL.md §8, §9): does a face COVER the viewport — every corner of the\n * viewport inside the face's rounded rect by at least `margin` CSS px (negative = may\n * poke out by that much)? Entering when it does is a cut nobody can see: the whole view\n * is already the inside; leaving when it no longer does shows the parent only where the\n * face has left the view. The two margins make the dead band.\n */\nexport function faceCovers(c: PortalClip, vp: Viewport, margin: number): boolean {\n const rr = Math.min(c.r, c.hx, c.hy);\n const sd = (x: number, y: number): number => {\n const qx = Math.abs(x - c.cx) - c.hx + rr;\n const qy = Math.abs(y - c.cy) - c.hy + rr;\n return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - rr;\n };\n return sd(0, 0) <= -margin && sd(vp.width, 0) <= -margin && sd(0, vp.height) <= -margin && sd(vp.width, vp.height) <= -margin;\n}\n/** The dead band: enter once the face covers the view by this much … */\nexport const THROUGH_IN = 2;\n/** … leave once it fails to cover by this much. */\nexport const THROUGH_OUT = 6;\n\n/** The scissor a presentation draws inside (device px): the chain's bounding boxes intersected, a device px of slack for the AA ramp; the attachment when there is no chain. */\nexport function scissorOf(p: Presentation | undefined, dpr: number, size: { readonly w: number; readonly h: number }): readonly [number, number, number, number] {\n let x0 = 0;\n let y0 = 0;\n let x1 = size.w;\n let y1 = size.h;\n for (const c of chainOf(p)) {\n x0 = Math.max(x0, Math.floor((c.cx - c.hx) * dpr) - 1); y0 = Math.max(y0, Math.floor((c.cy - c.hy) * dpr) - 1);\n x1 = Math.min(x1, Math.ceil((c.cx + c.hx) * dpr) + 1); y1 = Math.min(y1, Math.ceil((c.cy + c.hy) * dpr) + 1);\n }\n return [x0, y0, Math.max(0, x1 - x0), Math.max(0, y1 - y0)];\n}\n","// The ruler's law — pure maths beside lod.ts and line.ts. Two rulers are\n// PRINTED on the mat along the viewport's top and left edges (RULER.md): a\n// frame line one module in from the edge, a band one module wide inside it,\n// ticks standing on the band's inner line at the lattice's own sites, and a\n// label in the band's outer half at every site coarse enough to carry one.\n// The band is screen-fixed; what moves under it is the lattice, so the ticks\n// pan with the grid and the labels read the world coordinate (CSS px at\n// zoom 1 — what a card's position is) of the site they stand on.\n//\n// Five LEVELS of sites, a nested chain on the decade lattice: the fine rung\n// (f = 2·10^k), every fifth fine site (5f), the mid rung (m = 10f), every\n// fifth mid site (5m), the coarse rung (c = 100f). A site's level is the\n// coarsest one it lies on. Every presence is a smoothstep of a PITCH on\n// screen — the fine rung's ticks arrive as its pitch passes `ticksFrom`, a\n// level's labels as its pitch passes `labelsFrom` — so a decade wrap (the\n// fine rung becoming the mid rung at the same pitch) is continuous by\n// construction, as the mat's lines are (line.ts): level i at zoom 10·z has\n// the pitch level i+2 had at z, and takes its numbers.\n\nimport { type Lod, smoothstep } from \"./lod\";\n\nexport interface RulerLaw {\n /** CSS px: the band's width, and the mat's unprinted margin between the viewport's edge and the frame. */\n readonly band: number;\n readonly margin: number;\n /** CSS px: the ticks' lengths — minor · medium · major. */\n readonly tick: readonly [number, number, number];\n /** CSS px: the width of every printed line — the ticks and the frame. */\n readonly line: number;\n /** Ink presence of the frame's lines, the ticks and the labels (1 = the mat's cream, full). */\n readonly alpha: { readonly frame: number; readonly tick: number; readonly label: number };\n /** CSS px of pitch between which the fine rung's ticks (and its fifths) fade in. */\n readonly ticksFrom: readonly [number, number];\n /** CSS px of pitch between which a level's labels fade in. */\n readonly labelsFrom: readonly [number, number];\n /** The text: its size (CSS px — the atlas's em), its inset from the outer line, its gap after the tick. */\n readonly text: { readonly size: number; readonly top: number; readonly gap: number };\n /** The most characters a label may have; a level whose labels would be wider than its pitch carries none. */\n readonly maxChars: number;\n}\n\n/** One level of sites, with everything the pass draws for it this frame. */\nexport interface RulerLevel {\n /** World units between sites. */\n readonly spacing: number;\n /** CSS px between sites. */\n readonly pitch: number;\n /** A site's value is `index · mult · 10^exp` (index = its count from the world origin). */\n readonly mult: 1 | 2;\n readonly exp: number;\n /** CSS px; the label pulls a tick to the major length as it appears. */\n readonly tickLen: number;\n readonly tickAlpha: number;\n readonly labelAlpha: number;\n /** The lattice's wrap period over this spacing — an exact integer (100 · 20 · 10 · 2 · 1). */\n readonly perWrap: number;\n}\n\nexport type RulerLevels = readonly [RulerLevel, RulerLevel, RulerLevel, RulerLevel, RulerLevel];\n\nconst PER_WRAP = [100, 20, 10, 2, 1] as const;\nconst MULT = [2, 1, 2, 1, 2] as const;\nconst EXP_OFFSET = [0, 1, 1, 2, 2] as const;\n/** The exact ratio between level j's spacing and level i's (j ≥ i): spacings are 2 · [1, 5, 10, 50, 100] · 10^k. */\nconst UNITS = [1, 5, 10, 50, 100] as const;\n\nconst clamp01 = (x: number) => Math.min(Math.max(x, 0), 1);\nconst mix = (a: number, b: number, t: number) => a + (b - a) * t;\n\n/**\n * The five levels this frame. `maxAbs` is the largest |value| a label on\n * screen can carry (`labelReach`) — a level whose widest label would not fit\n * its pitch carries none, so labels never overlap whatever the coordinates.\n */\nexport function rulerLevels(l: Lod, zoom: number, law: RulerLaw, maxAbs = 0): RulerLevels {\n const af = smoothstep(law.ticksFrom[0], law.ticksFrom[1], l.fine * zoom);\n const [minor, medium, major] = law.tick;\n const base = [minor, medium, mix(minor, major, af), mix(medium, major, af), major];\n const tickAlpha = [af, af, 1, 1, 1];\n const out: RulerLevel[] = [];\n for (let i = 0; i < 5; i++) {\n const spacing = l.fine * (UNITS[i] as number);\n const pitch = spacing * zoom;\n const mult = MULT[i] as 1 | 2;\n const exp = l.k0 + (EXP_OFFSET[i] as number);\n let labelAlpha = smoothstep(law.labelsFrom[0], law.labelsFrom[1], pitch);\n // the widest label this level can show on screen, in characters — over the pitch, and the level is mute\n const chars = labelChars(maxAbs, mult, exp);\n if (chars > law.maxChars || chars * law.text.size * ADVANCE_EM + law.text.gap > pitch) labelAlpha = 0;\n out.push({ spacing, pitch, mult, exp, tickLen: mix(base[i] as number, major, labelAlpha), tickAlpha: tickAlpha[i] as number, labelAlpha, perWrap: PER_WRAP[i] as number });\n }\n return out as unknown as RulerLevels;\n}\n\n/** A mono glyph's advance as a fraction of its em — the layout's estimate (the atlas carries the measured one; SF Mono is 0.6). */\nexport const ADVANCE_EM = 0.6;\n\n/** The finest level that carries labels this frame, or -1 — the level the pass lays text out on. */\nexport function finestLabelled(levels: RulerLevels): number {\n for (let i = 0; i < 5; i++) if ((levels[i] as RulerLevel).labelAlpha > 0) return i;\n return -1;\n}\n\n/** The lattice's wrap count of a camera coordinate: `cam = wraps · period + phase`, exact in doubles (lod.ts wraps the phase). */\nexport const wrapsOf = (cam: number, period: number): number => Math.floor(cam / period);\n\n/**\n * The text of a site's label: `index · mult · 10^exp`, plain digits — no\n * suffixes (a \"1k\" that reads \"1000\" at the next zoom would change under the\n * eye), and no trailing zeros in a fraction (\"1.0\" is \"1\" at every level, so\n * a label's text never changes while it is visible). ruler.wgsl `ruler_char`\n * is the same arithmetic per character.\n */\nexport function formatLabel(index: number, mult: 1 | 2, exp: number): string {\n const M = index * mult;\n if (M === 0) return \"0\";\n const neg = M < 0;\n let digits = String(Math.abs(M));\n let text: string;\n if (exp >= 0) text = digits + \"0\".repeat(exp);\n else {\n const p = -exp;\n digits = digits.padStart(p + 1, \"0\");\n const int = digits.slice(0, digits.length - p);\n const frac = digits.slice(digits.length - p).replace(/0+$/, \"\");\n text = frac ? `${int}.${frac}` : int;\n }\n return neg ? `-${text}` : text;\n}\n\n/** How many characters the widest label of magnitude ≤ `maxAbs` takes at this level (the sign included). */\nexport function labelChars(maxAbs: number, mult: 1 | 2, exp: number): number {\n const index = Math.ceil(maxAbs / (mult * 10 ** exp));\n return Math.max(formatLabel(index, mult, exp).length, formatLabel(-index, mult, exp).length);\n}\n\n/** The largest |world coordinate| a label along an axis can show: the far edge of the band's reach. */\nexport function labelReach(cam: number, zoom: number, span: number): number {\n return Math.max(Math.abs(cam), Math.abs(cam + span / zoom));\n}\n\nexport interface RulerLabel {\n /** The site's world coordinate and its count from the origin at the finest labelled level. */\n readonly value: number;\n readonly index: number;\n /** CSS px along the axis where the site (its tick) stands. */\n readonly at: number;\n readonly text: string;\n readonly alpha: number;\n /** The site's level — the coarsest it lies on. */\n readonly level: number;\n}\n\n/**\n * The labels along one axis this frame, in order — the CPU mirror of what\n * ruler.wgsl lays out, site for site: the finest labelled level's sites from\n * the band's inner corner to the frame's far line, each with the alpha of the\n * coarsest level it lies on. `cam` is the camera's UNWRAPPED coordinate;\n * `span` the attachment's extent along the axis (CSS px).\n */\nexport function labelsAlong(cam: number, zoom: number, span: number, levels: RulerLevels, law: RulerLaw): RulerLabel[] {\n const lf = finestLabelled(levels);\n const out: RulerLabel[] = [];\n if (lf < 0) return out;\n const L = levels[lf] as RulerLevel;\n const period = (levels[4] as RulerLevel).spacing;\n const wraps = wrapsOf(cam, period);\n const phase = cam - wraps * period;\n const from = law.margin + law.band;\n const to = span - law.margin;\n // the shader's arithmetic exactly: a local count from the wrapped phase, the wrap count folded in as an exact integer\n // a hair of slack at the ends: a site on the corner itself is the shader's `site < lim.x` call, and a float either side of it lists the same sites\n const nLocal0 = Math.ceil((phase + from / zoom) / L.spacing - 1e-9);\n const nLocal1 = Math.floor((phase + to / zoom) / L.spacing + 1e-9);\n for (let n = nLocal0; n <= nLocal1; n++) {\n const index = wraps * L.perWrap + n;\n const at = (n * L.spacing - phase) * zoom;\n if (at < from || at > to) continue;\n let level = lf;\n for (let j = 4; j > lf; j--) { if (index % ((UNITS[j] as number) / (UNITS[lf] as number)) === 0) { level = j; break; } }\n out.push({ value: index * L.spacing, index, at, text: formatLabel(index, L.mult, L.exp), alpha: (levels[level] as RulerLevel).labelAlpha, level });\n }\n return out;\n}\n","// The gobo projector — pure 4×4 maths in three.js's conventions (column-major\n// elements, the WebGL clip range z ∈ [−1, 1]), because the reference's baked\n// projector camera and its depth linearisation are stated in them. A projector\n// is a perspective camera; a receiver maps its world position through\n// `projection · view` to clip space, divides, and reads the plate at the UV.\n// The mouse \"tilt\" is a small rotation applied AFTER the projection — the\n// reference's trick (it nudges the clip coordinates, which pans the shadow a\n// little and shifts its blur), reproduced exactly rather than rationalised.\n//\n// Nothing here knows about the GPU: the tests pin every function against\n// numbers three.js produced for the same inputs.\n\n/** 16 column-major floats — `Matrix4.elements`, and what WGSL's `mat4x4f` reads. */\nexport type Mat4 = Float32Array;\n/** The sixteen cells as a tuple: the length is the type, so a literal index needs no guard (ICE's kernel casts bounded reads the same way). */\nexport type Mat4Cells = readonly [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number];\nexport const cells = (m: Mat4): Mat4Cells => m as unknown as Mat4Cells;\nexport type Vec3 = readonly [number, number, number];\nexport type Quat = readonly [number, number, number, number]; // x y z w\n\nexport interface ProjectorSpec {\n /** World metres, y up — the desk scene's frame. */\n readonly position: Vec3;\n readonly quaternion: Quat;\n readonly fovDeg: number;\n readonly aspect: number;\n readonly near: number;\n readonly far: number;\n}\n\n/** three's `makePerspective`, WebGL coordinate system. */\nexport function perspective(fovDeg: number, aspect: number, near: number, far: number): Mat4 {\n const top = near * Math.tan((fovDeg * Math.PI) / 360);\n const height = 2 * top;\n const width = aspect * height;\n const left = -0.5 * width;\n const right = left + width;\n const bottom = top - height;\n const x = (2 * near) / (right - left);\n const y = (2 * near) / (top - bottom);\n const a = (right + left) / (right - left);\n const b = (top + bottom) / (top - bottom);\n const c = -(far + near) / (far - near);\n const d = (-2 * far * near) / (far - near);\n const m = new Float32Array(16);\n m[0] = x; m[5] = y; m[8] = a; m[9] = b; m[10] = c; m[11] = -1; m[14] = d;\n return m;\n}\n\n/** Rotation matrix of a unit quaternion (three's `makeRotationFromQuaternion`). */\nexport function fromQuat(q: Quat): Mat4 {\n const [x, y, z, w] = q;\n const x2 = x + x;\n const y2 = y + y;\n const z2 = z + z;\n const xx = x * x2;\n const xy = x * y2;\n const xz = x * z2;\n const yy = y * y2;\n const yz = y * z2;\n const zz = z * z2;\n const wx = w * x2;\n const wy = w * y2;\n const wz = w * z2;\n const m = new Float32Array(16);\n m[0] = 1 - (yy + zz); m[4] = xy - wz; m[8] = xz + wy;\n m[1] = xy + wz; m[5] = 1 - (xx + zz); m[9] = yz - wx;\n m[2] = xz - wy; m[6] = yz + wx; m[10] = 1 - (xx + yy);\n m[15] = 1;\n return m;\n}\n\n/** `a · b`, column-major. */\nexport function mul4(a: Mat4, b: Mat4): Mat4 {\n const m = new Float32Array(16);\n for (let col = 0; col < 4; col++) for (let row = 0; row < 4; row++) {\n let s = 0;\n for (let k = 0; k < 4; k++) s += (a[k * 4 + row] as number) * (b[col * 4 + k] as number);\n m[col * 4 + row] = s;\n }\n return m;\n}\n\n/** The inverse of `translate(p) · rotate(q)`: `Rᵀ · translate(−p)` — a camera's `matrixWorldInverse`. */\nexport function rigidInverse(position: Vec3, q: Quat): Mat4 {\n const r = fromQuat(q);\n const m = new Float32Array(16);\n for (let col = 0; col < 3; col++) for (let row = 0; row < 3; row++) m[col * 4 + row] = r[row * 4 + col] as number; // Rᵀ\n const [px, py, pz] = position;\n const e = cells(m);\n m[12] = -(e[0] * px + e[4] * py + e[8] * pz);\n m[13] = -(e[1] * px + e[5] * py + e[9] * pz);\n m[14] = -(e[2] * px + e[6] * py + e[10] * pz);\n m[15] = 1;\n return m;\n}\n\n/** `projection · view` for a projector — the matrix a receiver multiplies its world position by. */\nexport function projectorMatrix(spec: ProjectorSpec): Mat4 {\n return mul4(perspective(spec.fovDeg, spec.aspect, spec.near, spec.far), rigidInverse(spec.position, spec.quaternion));\n}\n\n/** three's `Quaternion.setFromEuler`, order XYZ. */\nexport function quatFromEuler(x: number, y: number, z: number): Quat {\n const c1 = Math.cos(x / 2);\n const c2 = Math.cos(y / 2);\n const c3 = Math.cos(z / 2);\n const s1 = Math.sin(x / 2);\n const s2 = Math.sin(y / 2);\n const s3 = Math.sin(z / 2);\n return [\n s1 * c2 * c3 + c1 * s2 * s3,\n c1 * s2 * c3 - s1 * c2 * s3,\n c1 * c2 * s3 + s1 * s2 * c3,\n c1 * c2 * c3 - s1 * s2 * s3,\n ];\n}\n\n/** The reference's mouse tilt: `rotate(euler) · base`, the rotation applied in clip space. */\nexport function tilted(base: Mat4, ex: number, ey: number, ez: number): Mat4 {\n return mul4(fromQuat(quatFromEuler(ex, ey, ez)), base);\n}\n\n/** A world point through the matrix: NDC xyz and clip w (the linear depth of a perspective projector). */\nexport function project(m: Mat4, p: Vec3): { ndc: [number, number, number]; w: number } {\n const [x, y, z] = p;\n const e = cells(m);\n const cx = e[0] * x + e[4] * y + e[8] * z + e[12];\n const cy = e[1] * x + e[5] * y + e[9] * z + e[13];\n const cz = e[2] * x + e[6] * y + e[10] * z + e[14];\n const cw = e[3] * x + e[7] * y + e[11] * z + e[15];\n return { ndc: [cx / cw, cy / cw, cz / cw], w: cw };\n}\n\n/** mat.wgsl `blur_ratio` — the reference's `getGoboBlurRatio`: linearise the WebGL NDC z, then a ramp between two depths. */\nexport function blurRatio(ndcZ: number, sharp: number, soft: number, near: number, far: number): number {\n const lin = (2 * near * far) / (far + near - ndcZ * (far - near));\n return Math.min(Math.max((lin - sharp) / (soft - sharp), 0), 1);\n}\n\n/** The hero desk's projector, as baked in the reference (research/tree-shadow/prototype/src/scenes.js). */\nexport const HERO_PROJECTOR: ProjectorSpec = {\n position: [0.466854, 0.992917, -0.252766],\n quaternion: [0.16182, -0.776664, -0.221667, -0.566984],\n fovDeg: 60, aspect: 1, near: 0.01, far: 20,\n};\n","// The cutting mat's GPU records, declared once. `MatUniforms` is what both mat\n// entries read — the wind pass (plate → animated silhouette) and the fullscreen\n// mat pass — and, since K4a (design-016 K-L3), the SLOT'S ONE VIEW BLOCK: the mat\n// writes it once a frame and every kind drawn in the slot binds the same buffer\n// (`MatPass.view`) at @group(0) @binding(0), never a copy of its own.\n// `matUniformValues()` fills it by name from the frame, the config and the\n// theme's numbers; nothing is hand-indexed.\n\nimport { defineStruct } from \"../engine/struct\";\nimport { boxValues, type FadeIn, lod, type View } from \"../lattice/lod\";\nimport type { LineLaw } from \"../lattice/line\";\nimport { finestLabelled, labelReach, type RulerLaw, rulerLevels, wrapsOf } from \"../lattice/ruler\";\nimport { MAT_COLORS, MAT_GRID, type RGB } from \"../theme\";\nimport { PORTAL_CHAIN_TYPE, portalValues, type Presentation } from \"../nav/portal\";\nimport type { CameraState } from \"../nav/flight\";\nimport { HERO_PROJECTOR, type Mat4, projectorMatrix } from \"./projector\";\nimport { DAY_LIGHT, lightValues, type MatLight } from \"./night\";\n\n/**\n * THE SLOT'S VIEW BLOCK — the kit's `view` piece (`kitWgsl([..., \"view\"])`): one per slot, written by the mat once a frame and\n * bound by every kind drawn in the slot at `@group(0) @binding(0)` as `u` (`MatPass.view`); a kind never writes it. Every field\n * is a vec4f but `goboMatrix` (mat4x4f) and the four arrays, so nothing is padded; its size is `MatUniforms.size`.\n *\n * THE CONVENTIONS (petition I31; mat.wgsl's header says them for the WGSL): WORLD units — one is one CSS px at zoom 1, x right\n * and y DOWN; CSS px — the attachment's layout px, origin its top-left, y down, `(world − cam.xy) · zoom`; DEVICE px — the\n * attachment's texels, `CSS px · dpr` (a fragment's `@builtin(position).xy`); colours sRGB-encoded 0..1 unless marked LINEAR.\n * The fields, x · y · z · w:\n *\n * - `cam` — the camera: the world point at the attachment's top-left (x, y — UNWRAPPED world units), the zoom (z — CSS px\n * per world unit, `mat_zoom`), the attachment's device px per CSS px (w — `mat_dpr`; below 1 for a capture's thumbnail or\n * the held desk copy, petition I29);\n * - `view` — the attachment's size (x, y — CSS px), the grain's clock (z — seconds), the OBJECTS' presentation opacity (w —\n * 0..1, the slot's × their own presence: what every kind multiplies its output by);\n * - `phase` — the camera wrapped to the lattice's coarse period (x, y — world units: the lattice's phase, which the lines are\n * drawn from); z, w unused;\n * - `rungs` — the fine, mid and coarse rungs' spacings (x, y, z — world units); w unused;\n * - `lod` — the grid's fade-in window (x, y — CSS px of a rung's cell; `GRID.fadeIn`); z, w unused;\n * - `line` — a line's half-width thin and thick (x, y — DEVICE px) and its alpha thin and thick (z, w — 0..1): `line_weight`;\n * - `grain` — the grain's amplitude (x — sRGB, ±); y, z, w unused;\n * - `ground` — the mat's green (xyz — sRGB 0..1); w unused;\n * - `ink` — the lines' cream (xyz — sRGB 0..1); w unused;\n * - `plane` — world → the desk: the desk origin's x and z (x, y — metres, the projector's frame), metres per world unit (z),\n * the desk's height (w — metres, y up): `desk_of`;\n * - `goboMatrix` — the projector: `projection · view` (· the pointer's tilt), column-major, desk metres → its clip space\n * (WebGL's z range);\n * - `goboParams` — the blur ramp's sharp and soft depths (x, y — metres from the projector), the projector's near and far (z,\n * w — metres): `blur_ratio`;\n * - `gobo` — the dapple's opacity (x — 0..1, 0 = no gobo), its blur at full softness (y — plate texels), the shade's mix (z —\n * 0..1) and its dark floor (w — 0..1): `sample_gobo`, `shade_mat`;\n * - `grade` — the saturation bump in shade (x); y, z, w unused;\n * - `noise` — the blue noise's offset (x, y — uv, re-rolled while the wind blows), one tile texel in uv (z — 1 / 128); w unused;\n * - `wind` — the gobo's clock (x — seconds), the plate's wind strength (y), and projection space (z — 0 = world,\n * 1 = viewport); w unused. Viewport shadows use CSS px at the original origin and scale, independent of the camera\n * and slot light handovers. The mode uses an existing spare lane so the shared view block does not grow;\n * - `night` — the NIGHT (mat/night.ts): its amount (x — 0..1, 0 = the day's chain exactly), the Moon's illuminance (y — lux),\n * the exposure (z — scene → display), the snow (w — display units, peak to peak): `night_mat`, `mat_colour`;\n * - `moon` — the Moon's colour as the adapted eye takes it (xyz — LINEAR sRGB, Y = 1) and the sky's share in the shadow (w —\n * 0..1);\n * - `rod` — the rods' signal drawn as a colour (xyz — LINEAR sRGB, Y = 1); w unused;\n * - `eigengrau` — the dark the eye adds to everything (xyz — LINEAR sRGB); w unused;\n * - `portals` — the portal CHAIN (nav/portal.ts; `PORTAL_CHAIN` records, nearest face first): each face's centre (xy) and half\n * extents (zw), CSS px of the attachment — `portal_cover`;\n * - `clips` — each face's corner radius (x — CSS px), on (y — 0/1: the first 0 ends the chain), top feather (z — CSS px; 0 =\n * a hard edge); w unused;\n * - `ruler` — the RULERS (lattice/ruler.ts): on (x — 0/1), the margin, the band and the line width (y, z, w — CSS px);\n * - `rulerText` — the text's inset from the outer line, its gap after the tick, the major tick's length (x, y, z — CSS px), the\n * atlas's texels per CSS px (w);\n * - `rulerAlpha` — the ink's presence on the frame's lines, the ticks and the labels (x, y, z — 0..1); w unused;\n * - `rulerOrigin` — the camera's wrap counts (x, y — exact integers), the finest labelled level (z — −1 = none); w unused;\n * - `rulerGlyph` — an atlas cell's width, height, advance and baseline (x, y, z, w — texels);\n * - `rulerAtlas` — the glyph atlas's width, height and cap height (x, y, z — texels) and its glyph count (w);\n * - `rulerSites` — per level (5): its spacing (x — world units), tick length (y — CSS px), tick presence and label presence\n * (z, w — 0..1);\n * - `rulerFormat` — per level (5): mult and exp (x, y — a site's value is index · mult · 10^exp), the wrap period over the\n * spacing (z); w unused;\n * - `box` — the slot's box on the attachment (x, y, w, h — CSS px): what is culled; the mat is fullscreen under the scissor;\n * - `light` — the camera the lamp's gobo is sampled under (`SlotLight`: x, y — world units at its top-left, z — its zoom) and\n * the cross-fade toward `light2` (w — 0..1): `lit_desk`, `lit_gobo`. Viewport mode fixes this camera at (0, 0, 1)\n * with no handover, so the mat uses the same shader path as a world-space lamp;\n * - `light2` — the second light a flight hands the slot to (x, y, z as `light`'s); w unused;\n * - `presence` — the SLOT's presentation opacity (x — 0..1: what the mat itself is drawn at; `view.w` is its objects'); y, z,\n * w unused.\n */\nexport const MatUniforms = defineStruct(\"MatUniforms\", [\n [\"cam\", \"vec4f\"],\n [\"view\", \"vec4f\"],\n [\"phase\", \"vec4f\"],\n [\"rungs\", \"vec4f\"],\n [\"lod\", \"vec4f\"],\n [\"line\", \"vec4f\"],\n [\"grain\", \"vec4f\"],\n [\"ground\", \"vec4f\"],\n [\"ink\", \"vec4f\"],\n [\"plane\", \"vec4f\"],\n [\"goboMatrix\", \"mat4x4f\"],\n [\"goboParams\", \"vec4f\"],\n [\"gobo\", \"vec4f\"],\n [\"grade\", \"vec4f\"],\n [\"noise\", \"vec4f\"],\n [\"wind\", \"vec4f\"],\n [\"night\", \"vec4f\"],\n [\"moon\", \"vec4f\"],\n [\"rod\", \"vec4f\"],\n [\"eigengrau\", \"vec4f\"],\n [\"portals\", PORTAL_CHAIN_TYPE],\n [\"clips\", PORTAL_CHAIN_TYPE],\n [\"ruler\", \"vec4f\"],\n [\"rulerText\", \"vec4f\"],\n [\"rulerAlpha\", \"vec4f\"],\n [\"rulerOrigin\", \"vec4f\"],\n [\"rulerGlyph\", \"vec4f\"],\n [\"rulerAtlas\", \"vec4f\"],\n [\"rulerSites\", \"array<vec4f, 5>\"],\n [\"rulerFormat\", \"array<vec4f, 5>\"],\n [\"box\", \"vec4f\"],\n [\"light\", \"vec4f\"],\n [\"light2\", \"vec4f\"],\n [\"presence\", \"vec4f\"],\n] as const);\n\nexport type PlateName = \"c\" | \"b\";\n\n/** The rulers printed on the mat (RULER.md): the law's numbers, and whether this slot prints them at all — the ROOT does, a portal's inside never. */\nexport interface RulerConfig extends RulerLaw { readonly on: boolean }\n\n/**\n * What the pass knows about the glyph atlas it samples for the labels\n * (`MatPass.setGlyphs`): \"0123456789-.\" in that order, one cell each, drawn\n * `PAD` texels in from the cell's left edge with the baseline `baseline`\n * texels under the cell's top, at `scale` texels per CSS px of the ruler's\n * text size. The lab renders it from the product's mono stack at the device's\n * ratio; the oracle reads a committed one (lab/assets/glyphs-mono-2x.r8).\n */\nexport interface GlyphAtlasMeta {\n readonly scale: number;\n readonly cellW: number;\n readonly cellH: number;\n readonly advance: number;\n readonly baseline: number;\n readonly cap: number;\n readonly width: number;\n readonly height: number;\n readonly count: number;\n}\n/** Texels between a cell's left edge and its glyph's origin — room for a bearing either way. */\nexport const GLYPH_PAD = 2;\n/**\n * The glyphs the atlas holds, in cell order: the rulers' twelve first (ruler.wgsl indexes them by\n * this), then the capitals and the few marks a mini mat's printed NAME may use (MINIMAT.md §2) —\n * the design's print label is mono capitals. An atlas holds at least the rulers' twelve.\n */\nexport const GLYPHS = \"0123456789-.\" + \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" + \" &'/·#()+:\";\n/** The rulers' own glyphs — the first this many of `GLYPHS`, what every atlas must hold. */\nexport const RULER_GLYPHS = 12;\n/** No atlas uploaded: a 1×1 empty cell — labels sample nothing. */\nexport const NO_GLYPHS: GlyphAtlasMeta = { scale: 1, cellW: 1, cellH: 1, advance: 1, baseline: 1, cap: 1, width: 1, height: 1, count: 0 };\n\n/** The mat's tuning — theme.ts's numbers unless a host tweaks them. */\nexport interface MatConfig {\n readonly line: LineLaw;\n readonly grain: number;\n readonly ground: RGB;\n readonly ink: RGB;\n readonly gobo: {\n /** World by default. Viewport keeps the projection at its original origin and 100% scale in CSS px while the canvas moves. */\n readonly space?: \"world\" | \"viewport\";\n readonly opacity: number;\n readonly blurTexels: number;\n readonly shadeMix: number;\n readonly darkFloor: number;\n readonly saturate: number;\n readonly sharp: number;\n readonly soft: number;\n readonly plate: PlateName;\n };\n readonly plane: { readonly metresPerUnit: number; readonly originX: number; readonly originZ: number; readonly deskY: number };\n /** The rulers (RULER.md); off unless a host prints them on this slot. */\n readonly ruler: RulerConfig;\n}\n\n/**\n * The LIGHT a slot is lit by (MINIMAT.md §4) — the camera the lamp's gobo is sampled under, not the one\n * the slot draws under. The root at rest is lit by its own lamp (absent = that). A mini mat's inside is\n * lit by the lamp of the desk the mini mat lies on — `a` is the host's camera — so the dapple runs across\n * the mini mat as across any object on the desk. While a flight, or a zoom-through's re-dressing, hands\n * one desk's lamp to the other, the two are cross-faded: `t` of the way to `b`. Each camera is in the\n * frame it belongs to; none need share the slot's.\n */\nexport interface SlotLight { readonly a: CameraState; readonly b?: CameraState; readonly t?: number }\n\n/** What moves per frame — the host owns every clock and the tilt. */\nexport interface MatFrame {\n /** Seconds; drives the grain's drift. */\n readonly time: number;\n /** Seconds; drives the wind. Advanced by the host at its wind speed. */\n readonly goboTime: number;\n /** `projection · view` (· tilt), column-major — `projector.ts`. */\n readonly goboMatrix: Mat4;\n /** Blue-noise UV offset for this frame — random while animating, fixed for a still. */\n readonly noise: readonly [number, number];\n}\n\nexport const DEFAULT_MAT_CONFIG: MatConfig = {\n line: MAT_GRID.line,\n grain: MAT_GRID.grain,\n ground: MAT_COLORS.ground,\n ink: MAT_COLORS.line,\n gobo: {\n opacity: MAT_GRID.gobo.opacity, blurTexels: MAT_GRID.gobo.blurTexels,\n shadeMix: MAT_GRID.gobo.shadeMix, darkFloor: MAT_GRID.gobo.darkFloor, saturate: MAT_GRID.gobo.saturate,\n sharp: MAT_GRID.gobo.sharp, soft: MAT_GRID.gobo.soft, plate: MAT_GRID.gobo.plate,\n },\n plane: MAT_GRID.plane,\n ruler: { on: false, ...MAT_GRID.ruler },\n};\n\nexport const HERO_MATRIX: Mat4 = projectorMatrix(HERO_PROJECTOR);\nexport const STILL_MAT_FRAME: MatFrame = { time: 0, goboTime: 0, goboMatrix: HERO_MATRIX, noise: [0, 0] };\n\nexport const NOISE_SIZE = 128;\nexport const PLATE_SIZE = 512;\n\nexport function matUniformValues(view: View & { readonly dpr: number }, fadeIn: FadeIn, cfg: MatConfig, f: MatFrame, plateStrength: number, present?: Presentation, light: MatLight = DAY_LIGHT, glyphs: GlyphAtlasMeta = NO_GLYPHS, lit?: SlotLight) {\n const l = lod(view);\n const r = cfg.ruler;\n // one set of levels serves both rulers: the wider reach decides which levels can carry their labels\n const levels = rulerLevels(l, view.zoom, r, Math.max(labelReach(view.camX, view.zoom, view.width), labelReach(view.camY, view.zoom, view.height)));\n return {\n cam: [view.camX, view.camY, view.zoom, view.dpr],\n view: [view.width, view.height, f.time, present === undefined ? 1 : present.objects === undefined ? present.opacity : present.opacity * present.objects],\n phase: [((view.camX % l.wrapPeriod) + l.wrapPeriod) % l.wrapPeriod, ((view.camY % l.wrapPeriod) + l.wrapPeriod) % l.wrapPeriod, 0, 0],\n rungs: [l.fine, l.mid, l.coarse, 0],\n lod: [fadeIn[0], Math.max(fadeIn[1], fadeIn[0] + 1e-3), 0, 0],\n line: [cfg.line.thin, cfg.line.thick, cfg.line.alphaThin, cfg.line.alphaThick],\n grain: [cfg.grain, 0, 0, 0],\n ground: [cfg.ground[0], cfg.ground[1], cfg.ground[2], 0],\n ink: [cfg.ink[0], cfg.ink[1], cfg.ink[2], 0],\n plane: [cfg.plane.originX, cfg.plane.originZ, cfg.plane.metresPerUnit, cfg.plane.deskY],\n goboMatrix: f.goboMatrix,\n goboParams: [cfg.gobo.sharp, cfg.gobo.soft, HERO_PROJECTOR.near, HERO_PROJECTOR.far],\n gobo: [cfg.gobo.opacity, cfg.gobo.blurTexels, cfg.gobo.shadeMix, cfg.gobo.darkFloor],\n grade: [cfg.gobo.saturate, 0, 0, 0],\n noise: [f.noise[0], f.noise[1], 1 / NOISE_SIZE, 0],\n wind: [f.goboTime, plateStrength, cfg.gobo.space === \"viewport\" ? 1 : 0, 0],\n ...lightValues(light),\n ...portalValues(present),\n ruler: [r.on ? 1 : 0, r.margin, r.band, r.line],\n rulerText: [r.text.top, r.text.gap, r.tick[2], glyphs.scale],\n rulerAlpha: [r.alpha.frame, r.alpha.tick, r.alpha.label, 0],\n rulerOrigin: [wrapsOf(view.camX, l.wrapPeriod), wrapsOf(view.camY, l.wrapPeriod), finestLabelled(levels), 0],\n rulerGlyph: [glyphs.cellW, glyphs.cellH, glyphs.advance, glyphs.baseline],\n rulerAtlas: [glyphs.width, glyphs.height, glyphs.cap, glyphs.count],\n rulerSites: levels.flatMap((L) => [L.spacing, L.tickLen, L.tickAlpha, L.labelAlpha]),\n rulerFormat: levels.flatMap((L) => [L.mult, L.exp, L.perWrap, 0]),\n box: boxValues(view),\n ...(cfg.gobo.space === \"viewport\" ? VIEWPORT_LIGHT : slotLightValues(view, lit)),\n // the slot's own opacity, which the mat is drawn at; `view.w` above is the objects' (what the ground's `objectsOf` hands the kinds'\n // `SlotContext.present`). One view block per slot carries both (K4a, design-016 K-L3), so every kind reads it as it always read its copy\n presence: [present?.opacity ?? 1, 0, 0, 0],\n };\n}\n\n/**\n * A light with its ends collapsed: a handover at t ≤ 0 is `a` alone, at t ≥ 1 `b` alone — so a slot\n * at either end of one is lit through exactly the path a slot lit by that camera always takes.\n */\nexport function settleLight(lit: SlotLight | undefined): SlotLight | undefined {\n if (!lit?.b) return lit;\n const t = lit.t ?? 0;\n return t <= 0 ? { a: lit.a } : t >= 1 ? { a: lit.b } : lit;\n}\n/** Is a slot lit by its own camera — no light, or one that settles on the camera it draws under? */\nexport function litByOwn(view: View, lit: SlotLight | undefined): boolean {\n const s = settleLight(lit);\n return !s || (!s.b && s.a.x === view.camX && s.a.y === view.camY && s.a.zoom === view.zoom);\n}\n\n// A fixed viewport lamp is the existing light camera at the origin and 100% scale.\n// Reuse these records: no per-frame light arrays or extra per-fragment mode branch on the mat.\nconst VIEWPORT_LIGHT = { light: [0, 0, 1, 0], light2: [0, 0, 1, 0] } as const;\n\n/** The `light` / `light2` records: the slot's own camera unless it is lit from elsewhere (`SlotLight`). */\nfunction slotLightValues(view: View, lit: SlotLight | undefined): { light: number[]; light2: number[] } {\n const own = { x: view.camX, y: view.camY, zoom: view.zoom };\n const s = settleLight(lit);\n const a = s?.a ?? own;\n const b = s?.b ?? a;\n const t = s?.b ? (s.t ?? 0) : 0;\n return { light: [a.x, a.y, a.zoom, t], light2: [b.x, b.y, b.zoom, 0] };\n}\n","// The 3D KIT's records (design-016 §5; the notebook's, moved here at K4a): what kit/book.wgsl — the desk eye's\n// projection, the shadow (PCSS on a book's own shadow map, the penumbra growing with the gap by the desk's law), the\n// materials (bookcloth and its weave, the printed cover, the ivory page and its ruling, the board, the edge) — is written\n// against, declared once (`defineStruct`: the WGSL text and the packer from one list). `NbUniforms` is a 3D pass's knobs\n// and the desk eye; `NbBook` is one book-shaped object: its placement, its lamp and shadow map's frame, its dimensions\n// and pose, its palette. The notebook draws books with them, and the desk calendar's pad is the notebook's paper and cloth\n// under the same colour chain, so its program composes them too (`kitWgsl([..., \"book\"])`). The camera, the light and the\n// gobo arrive through the slot's view block (`MatUniforms`) — a book is lit like the mat beside it.\n\nimport { defineStruct } from \"../engine/struct\";\n\n/**\n * A 3D pass's KNOBS and the DESK EYE — the `book` piece's first record (`kitWgsl([..., \"book\"])`; bound as `k` beside the slot's\n * `u`). World units throughout (one is one CSS px at zoom 1; x right, y DOWN on the desk, z UP off it); colours sRGB 0..1. Every\n * field is a vec4f, so nothing is padded (petition I31). The fields, x · y · z · w:\n *\n * - `eye` — the desk eye (kit/eye.ts `eyeValues`): its foot, the view's centre (x, y — world units), its height (z — world\n * units), the zoom (w — CSS px per world unit): `nb_clip`;\n * - `view` — the viewport (x, y — CSS px), the depth range's near and far (z, w — world units from the eye);\n * - `light` — the sky's share where the lamp is blocked (x — 0..1), the lambert's cap (y — a flat face lit straight on reads 1),\n * the dapple's share on paper (z) and on cloth (w — 0..1);\n * - `shadow` — the penumbra law: σ at contact (x — world units) and σ per world unit of height (y), the shadow's alpha on the\n * mat (z) and the contact's (w — 0..1): `nb_shadow`;\n * - `shadow2` — the contact's σ (x — world units), the height it lets go by (y — world units), the shadow map's size (z —\n * texels), the dpr (w);\n * - `paper` — the paper's fibre, mottle, tooth and cockle (x, y, z, w — strengths, 0 = none): `nb_paper`;\n * - `rule` — the ruling's pitch, a dot's radius and the margin (x, y, z — world units); w unused: `nb_ruling`;\n * - `cloth` — the weave's pitch (x — world units) and relief (y), the sheen's exponent (z) and strength (w);\n * - `castCol` — what a shadow is made of on this ground (rgb — sRGB); a 1;\n * - `select` — the selection ring's colour (rgb — sRGB) and width (w — CSS px);\n * - `ruleInk` — the ruling's ink (rgb — sRGB) and alpha (a — 0..1);\n * - `ring` — the ring's offset from the footprint (x — CSS px), the pass's debug flags (y — & 1 no self-shadow, & 2 flat\n * albedo, & 4 no dapple), the layer box's origin on the attachment (z, w — device px: a fragment's attachment pixel is its\n * own plus these).\n */\nexport const NbUniforms = defineStruct(\"NbUniforms\", [\n [\"eye\", \"vec4f\"],\n [\"view\", \"vec4f\"],\n [\"light\", \"vec4f\"],\n [\"shadow\", \"vec4f\"],\n [\"shadow2\", \"vec4f\"],\n [\"paper\", \"vec4f\"],\n [\"rule\", \"vec4f\"],\n [\"cloth\", \"vec4f\"],\n [\"castCol\", \"vec4f\"],\n [\"select\", \"vec4f\"],\n [\"ruleInk\", \"vec4f\"],\n [\"ring\", \"vec4f\"],\n] as const);\n\n/**\n * ONE book-shaped object — the `book` piece's second record (a storage array of them, one per object). World units throughout\n * (x, y on the desk with y DOWN, z UP off it); colours sRGB 0..1. Every field is a vec4f, a mat4x4f or a vec4f array, so nothing\n * is padded (petition I31). The fields:\n *\n * - `model` — book → world: the book's placement (column-major);\n * - `inv` — world → book (`model`'s inverse);\n * - `light` — world → its shadow map's clip space (the lamp's view-projection): `nb_shadow`;\n * - `lamp` — the unit direction to the lamp (xyz — world) and the book's layer in the shadow maps (w);\n * - `sh` — a shadow-map texel (x — world units), the map's depth range (y — world units), mapped (z — 0/1), the book's tallest\n * point (w — world units);\n * - `size` — the cover's width and height (x, y), the board's thickness (z), the fore-edge corners' radius (w) — world units;\n * - `page` — unused (x), the page's height (y), its corner radius (z), the spine band's width (w) — world units;\n * - `open` — the cover's swing θ (x — radians, 0 shut … π open), the gutter's relax (y — 0..1), the spine's width (z — world\n * units), the squares — the boards' overhang past the pages (w — world units);\n * - `look` — the design (x — `nb_design`'s 0 … 4), the ruling (y — `nb_ruling`'s 0 none, 1 dots, 2 lines, else a grid), the\n * selection ring's presence (z — 0..1), a seed (w);\n * - `foot` — the front board lies on the desk (x — 0/1), the cover is paper (y — 0/1), a sheet's thickness (z — world units),\n * the book shades itself (w — 0/1);\n * - `recv` — the mat's rect this book darkens: x0, y0, x1, y1 (world units);\n * - `inkPage` — the pages with ink on the device, eight (−1 = none);\n * - `inkLayer` — the raster layer each of those is in;\n * - `col0` the cloth · `col1` the band · `col2`, `col3`, `col4` the accents · `col5` the endpaper · `col6` the paper · `col7` the\n * ink (rgb — sRGB; a 1).\n */\nexport const NbBook = defineStruct(\"NbBook\", [\n [\"model\", \"mat4x4f\"],\n [\"inv\", \"mat4x4f\"],\n [\"light\", \"mat4x4f\"],\n [\"lamp\", \"vec4f\"],\n [\"sh\", \"vec4f\"],\n [\"size\", \"vec4f\"],\n [\"page\", \"vec4f\"],\n [\"open\", \"vec4f\"],\n [\"look\", \"vec4f\"],\n [\"foot\", \"vec4f\"],\n [\"recv\", \"vec4f\"],\n [\"inkPage\", \"array<vec4f, 2>\"],\n [\"inkLayer\", \"array<vec4f, 2>\"],\n [\"col0\", \"vec4f\"], [\"col1\", \"vec4f\"], [\"col2\", \"vec4f\"], [\"col3\", \"vec4f\"],\n [\"col4\", \"vec4f\"], [\"col5\", \"vec4f\"], [\"col6\", \"vec4f\"], [\"col7\", \"vec4f\"],\n] as const);\n","// GENERATED by tools/wgsl-to-ts.mjs from shaders/**/*.wgsl — do not edit.\n// `pnpm --filter @ice/desk gen:shaders` regenerates it; `gen:check` fails the gate when it is stale.\n// The .wgsl files are the source: the Node oracle reads them from disk and composes byte-identical text.\nexport const WGSL = {\n \"hold/hold.wgsl\": \"// THE HAND'S FOCUS (design-015 §8; D4b) — the desk behind the object in hand goes out of focus, and the\\n// object is laid over it in its own light. Four fullscreen fragments over one triangle, one binding set:\\n// - `fs_down` / `fs_up`: the dual-Kawase blur (Bjørge, ARM 2015) — a down pass takes the centre ×4 and the\\n// four diagonals at ±offset half-texels; an up pass eight taps at ±offset (the axes once, the diagonals\\n// twice) — the desk's HALF-SIZE copy blurred through two levels and back, once per settled desk.\\n// - `fs_desk`: the frame's background — the sharp half-size copy mixed with the blurred one by the carry\\n// amount (half-way up, half the blur), dimmed by `dim` (8 % at the top).\\n// - `fs_hand`: the object in hand, drawn into a transparent target with the kinds' own straight-alpha\\n// \\\"source over\\\" — which, from a cleared target, accumulates PREMULTIPLIED colour — laid over the frame\\n// (one, one − src alpha), through the READING LIGHT (Q-n): saturate then brighten, both linear in the\\n// premultiplied colour, so the at-rest passes' bytes never move.\\n// Pure of everything but its bindings (engine/shader.ts's rule): the CPU decides every number.\\n\\n@group(0) @binding(0) var<uniform> u: HoldUniforms;\\n@group(0) @binding(1) var tex_a: texture_2d<f32>;\\n@group(0) @binding(2) var tex_b: texture_2d<f32>;\\n@group(0) @binding(3) var samp: sampler;\\n\\nstruct VSOut {\\n @builtin(position) clip: vec4f,\\n @location(0) uv: vec2f,\\n}\\n\\n/** One triangle over the whole attachment; uv (0, 0) at the top-left, as the texture's rows run. */\\n@vertex\\nfn vs(@builtin(vertex_index) vid: u32) -> VSOut {\\n var out: VSOut;\\n let x = f32((vid << 1u) & 2u);\\n let y = f32(vid & 2u);\\n out.clip = vec4f(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0);\\n out.uv = vec2f(x, y);\\n return out;\\n}\\n\\n/** Dual Kawase, down: `u.texel.xy` = one texel of the SOURCE, `u.texel.z` = the offset in half-texels. */\\n@fragment\\nfn fs_down(in: VSOut) -> @location(0) vec4f {\\n let o = u.texel.xy * 0.5 * u.texel.z;\\n var c = textureSample(tex_a, samp, in.uv) * 4.0;\\n c += textureSample(tex_a, samp, in.uv + vec2f(-o.x, -o.y));\\n c += textureSample(tex_a, samp, in.uv + vec2f(o.x, -o.y));\\n c += textureSample(tex_a, samp, in.uv + vec2f(-o.x, o.y));\\n c += textureSample(tex_a, samp, in.uv + vec2f(o.x, o.y));\\n return c / 8.0;\\n}\\n\\n/** Dual Kawase, up: the same offset, eight taps. */\\n@fragment\\nfn fs_up(in: VSOut) -> @location(0) vec4f {\\n let o = u.texel.xy * 0.5 * u.texel.z;\\n var c = textureSample(tex_a, samp, in.uv + vec2f(-o.x * 2.0, 0.0));\\n c += textureSample(tex_a, samp, in.uv + vec2f(-o.x, o.y)) * 2.0;\\n c += textureSample(tex_a, samp, in.uv + vec2f(0.0, o.y * 2.0));\\n c += textureSample(tex_a, samp, in.uv + vec2f(o.x, o.y)) * 2.0;\\n c += textureSample(tex_a, samp, in.uv + vec2f(o.x * 2.0, 0.0));\\n c += textureSample(tex_a, samp, in.uv + vec2f(o.x, -o.y)) * 2.0;\\n c += textureSample(tex_a, samp, in.uv + vec2f(0.0, -o.y * 2.0));\\n c += textureSample(tex_a, samp, in.uv + vec2f(-o.x, -o.y)) * 2.0;\\n return c / 12.0;\\n}\\n\\n/** The desk out of focus: the sharp copy (tex_a) mixed with the blurred one (tex_b) by the carry `u.mix.x`, dimmed by `u.mix.y`. Opaque. */\\n@fragment\\nfn fs_desk(in: VSOut) -> @location(0) vec4f {\\n let sharp = textureSample(tex_a, samp, in.uv).rgb;\\n let soft = textureSample(tex_b, samp, in.uv).rgb;\\n return vec4f(mix(sharp, soft, u.mix.x) * (1.0 - u.mix.y), 1.0);\\n}\\n\\n/** The hand over the frame: premultiplied (tex_a), through the reading light — saturate `u.mix.z`, brightness `u.mix.w`. Blend (one, one − src alpha). */\\n@fragment\\nfn fs_hand(in: VSOut) -> @location(0) vec4f {\\n let h = textureSample(tex_a, samp, in.uv);\\n let lum = dot(h.rgb, vec3f(0.2126, 0.7152, 0.0722));\\n let rgb = mix(vec3f(lum), h.rgb, u.mix.z) * u.mix.w;\\n return vec4f(rgb, h.a);\\n}\\n\",\n \"kit/book.wgsl\": \"// (The kit's since K4a, design-016 §5 — moved from notebook/notebook.wgsl: the desk calendar composes it too, `kitWgsl([..., \\\"book\\\"])`.)\\n//\\n// The NOTEBOOK — a real 3D book under the desk's one lamp (NOTEBOOK.md). A PURE module: the\\n// uniform blocks, the book records and the textures arrive as parameters, and it names no\\n// colour (a book's palette is its record's). mat.wgsl comes first: its noise, its colour chain\\n// (`shade_mat` by day, `night_mat` by night) and its gobo (`sample_gobo`) are the desk's, so a\\n// page under the palm is dappled and graded exactly as the mat beside it.\\n//\\n// The pieces: the desk eye's projection (`nb_clip`, eye.ts is the same arithmetic); the\\n// shadow — PCSS on the book's own shadow map, whose penumbra grows with the gap between caster\\n// and receiver by the desk's law (σ = σ0 + k·height, the note's and the photo's); the\\n// materials — bookcloth with a weave and a sheen, the cover's printed design, the ivory page\\n// with its fibre, tooth, cockle and dots, the stacked edges of the sheets, the endpaper framed\\n// by the cloth's turn-in; and the light — a lambert normalised so a flat face reads its own\\n// albedo, the sky's share where the lamp is blocked, the leaves' dapple.\\n//\\n// THE KIT'S `book` PIECE (`kitWgsl([..., \\\"book\\\"])`, after `light`; its records `NbUniforms` and `NbBook` are kit/book.ts's;\\n// petition I31 — every declaration's `///` block says what it takes and gives). Its world is the desk's with HEIGHT: a point\\n// is (x, y, z) — x, y world units on the desk (y DOWN, the desk's), z world units UP off it, toward the desk eye. A face's own\\n// point `q` is world units along its u and v (each function says from where). `px` is world units per device px at the\\n// fragment — under the eye's perspective it varies (the notebook takes `max(length(dpdx(P)), length(dpdy(P)))`).\\n\\n/// π, to f32's precision.\\nconst NB_PI = 3.14159265;\\n\\n/// Clamp to [0, 1].\\n/// `x` — any value.\\n/// → [0, 1].\\nfn nb_sat(x: f32) -> f32 { return clamp(x, 0.0, 1.0); }\\n\\n// ---- the desk eye: a world point → clip space (x, y 2·zoom·(p − E)/viewport; w = (H − z)/H; a perspective depth)\\n/// The DESK EYE's projection (kit/eye.ts `project` and `eyeValues` are the same arithmetic): an eye `k.eye.z` world units above\\n/// the view's centre, so a point with height is seen in perspective — and the desk itself (z = 0) exactly as the slot's camera\\n/// maps it.\\n/// `k` — the pass's knobs (`k.eye`: the eye's foot x, y — the view's centre, world units — its height H, world units, and the\\n/// zoom; `k.view`: the viewport w, h, CSS px, and the depth range's near and far, world units from the eye); `P` — the point:\\n/// x, y world units on the desk (y down), z its height above it, world units, below H.\\n/// → clip space: xy = 2 · zoom · (P.xy − the foot) / the viewport, y flipped to clip's up; w = (H − z) / H; z / w a depth,\\n/// 0 at `near` … 1 at `far` from the eye.\\nfn nb_clip(k: NbUniforms, P: vec3f) -> vec4f {\\n let H = k.eye.z;\\n let d = H - P.z;\\n let x = 2.0 * k.eye.w * (P.x - k.eye.x) / k.view.x;\\n let y = -2.0 * k.eye.w * (P.y - k.eye.y) / k.view.y;\\n let n = k.view.z;\\n let f = k.view.w;\\n let z = (d - n) * f / ((f - n) * H);\\n return vec4f(x, y, z, d / H);\\n}\\n\\n/// A point raised off the desk, in the projector's frame (mat.wgsl `desk_of` with a height).\\n/// `u` — the slot's view block (`u.plane`); `P` — x, y world units on the desk (y down), z its height above it, world units.\\n/// → metres, y up: `desk_of(u, P.xy)` raised by z · `u.plane.z`.\\nfn nb_desk_at(u: MatUniforms, P: vec3f) -> vec3f {\\n return vec3f(u.plane.x + P.x * u.plane.z, u.plane.w + P.z * u.plane.z, u.plane.y + P.y * u.plane.z);\\n}\\n\\n// ---- noise in a face's own world units: an integer hash (no sin — a page fragment reads a dozen of these),\\n// value noise with its analytic gradient (so a bump costs one evaluation, not three)\\n/// An integer hash — no `sin` (a page fragment reads a dozen of these).\\n/// `p` — an integer lattice point, any i32 (a negative one wraps through u32).\\n/// → [0, 1): one pseudo-random value per lattice point.\\nfn nb_hash(p: vec2i) -> f32 {\\n var h = (u32(p.x) * 668265261u) ^ (u32(p.y) * 374761393u);\\n h = (h ^ (h >> 15u)) * 2246822519u;\\n h = (h ^ (h >> 13u)) * 3266489917u;\\n h = h ^ (h >> 16u);\\n return f32(h) * 2.3283064e-10;\\n}\\n\\n/// Value noise with its analytic gradient: a bump costs one evaluation, not three.\\n/// `p` — the point, in the noise's cells (one per unit).\\n/// → x the value, centred on 0, [−0.5, 0.5); y, z its derivatives d/dx and d/dy, per unit of `p`.\\nfn nb_vn(p: vec2f) -> vec3f {\\n let fl = floor(p);\\n let i = vec2i(fl);\\n let f = p - fl;\\n let w = f * f * (3.0 - 2.0 * f);\\n let dw = 6.0 * f * (1.0 - f);\\n let a = nb_hash(i);\\n let b = nb_hash(i + vec2i(1, 0));\\n let c = nb_hash(i + vec2i(0, 1));\\n let d = nb_hash(i + vec2i(1, 1));\\n let k = a - b - c + d;\\n return vec3f(a + (b - a) * w.x + (c - a) * w.y + k * w.x * w.y - 0.5, dw.x * (b - a + k * w.y), dw.y * (c - a + k * w.x));\\n}\\n\\n/// Three octaves of `nb_vn` — frequencies 1, 2.03 and 4.11, amplitudes 1, 0.5 and 0.25 — the gradient carried through.\\n/// `p` — the point, in the first octave's cells.\\n/// → x the value, [−0.875, 0.875); y, z its derivatives, per unit of `p`.\\nfn nb_fbm(p: vec2f) -> vec3f {\\n let a = nb_vn(p);\\n let b = nb_vn(p * 2.03 + vec2f(17.1, 3.7));\\n let c = nb_vn(p * 4.11 + vec2f(-5.3, 11.9));\\n return vec3f(a.x + b.x * 0.5 + c.x * 0.25, a.yz + b.yz * 1.015 + c.yz * 1.0275);\\n}\\n\\n/// A pattern's detail, faded as its period falls under the pixel.\\n/// `period` — the pattern's period, world units; `px` — world units per device px, > 0.\\n/// → [0, 1]: 1 while the period spans ≥ 3 device px, 0 at ≤ 1.2, a smoothstep between.\\nfn nb_detail(period: f32, px: f32) -> f32 { return smoothstep(1.2, 3.0, period / max(px, 1e-5)); }\\n\\n/// The coverage of a signed distance at a pixel.\\n/// `d` — the signed distance, world units, negative inside; `px` — world units per device px, > 0.\\n/// → [0, 1]: `0.5 − d / px` clamped — a one-px linear ramp centred on the edge.\\nfn nb_cov(d: f32, px: f32) -> f32 { return nb_sat(0.5 - d / max(px, 1e-5)); }\\n\\n/// A rounded box centred on the origin. Unlike `sdf_round_box`, `r` is NOT clamped.\\n/// `p` — the point; `b` — the half extents, ≥ 0; `r` — the corner radius, 0 … min(b.x, b.y). All in one unit.\\n/// → the signed distance, in that unit: negative inside.\\nfn nb_sd_box(p: vec2f, b: vec2f, r: f32) -> f32 {\\n let q = abs(p) - b + vec2f(r);\\n return length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - r;\\n}\\n\\n/// A book's face, [0, w] × [0, h]: its two corners at u = w (the fore-edge) rounded by `r`, the spine side (u = 0) square.\\n/// `q` — the point, the face's world units (u from the spine side, v from the head); `w`, `h` — the face's size, world units;\\n/// `r` — the fore-edge corners' radius, world units, 0 … min(w, h / 2).\\n/// → the signed distance, world units: negative inside.\\nfn nb_sd_fore(q: vec2f, w: f32, h: f32, r: f32) -> f32 {\\n // mirror the square side out of reach: extend the box past u = 0 by r\\n let c = vec2f((w - r) * 0.5, h * 0.5);\\n let b = vec2f((w + r) * 0.5, h * 0.5);\\n return nb_sd_box(q - c, b, r);\\n}\\n\\n// ---- the shadow: PCSS on the book's own map (the blocker's gap → the desk's penumbra law)\\n/// The golden angle (≈ 2.39996 rad) as a rotation: a Vogel spiral's next direction is this times the last.\\nconst NB_GOLDEN = mat2x2f(-0.7373688, 0.6754903, -0.6754903, -0.7373688);\\n\\n/// The book's own shadow at a point — PCSS on its shadow map: a blocker search as wide as the widest penumbra the book can cast,\\n/// then a Gaussian-weighted filter whose width grows with the blocker's height over the receiver by the desk's law\\n/// (σ = `k.shadow.x` + `k.shadow.y` · the gap, world units).\\n/// `k` — the pass's knobs (`k.shadow`; `k.shadow2.z` the map's size, texels; `k.ring.y` & 1 turns self-shadowing off); `B` —\\n/// the book (`B.light` its map's matrix, `B.lamp.w` its layer, `B.sh` the map's texel and depth range, mapped, its tallest\\n/// point); `P` — the receiver: x, y world units on the desk, z its height, world units; `n` — the receiver's unit normal;\\n/// `rot` — the spirals' start angle, radians (blue noise × 2π); `tex` — the books' shadow maps (depth, a layer a book); `cmp`\\n/// — a comparison sampler.\\n/// → [0, 1]: 1 lit, 0 wholly shadowed — exactly 1 when the book has no map (`B.sh.z` < 0.5), with self-shadowing off, or where\\n/// `P` falls outside the map.\\nfn nb_shadow(k: NbUniforms, B: NbBook, P: vec3f, n: vec3f, rot: f32, tex: texture_depth_2d_array, cmp: sampler_comparison) -> f32 {\\n if (B.sh.z < 0.5 || (u32(k.ring.y) & 1u) != 0u) { return 1.0; }\\n let texel = B.sh.x;\\n let res = k.shadow2.z;\\n let layer = i32(B.lamp.w);\\n let Po = P + n * texel * 1.5;\\n let lc = B.light * vec4f(Po, 1.0);\\n let uv = vec2f(lc.x * 0.5 + 0.5, 0.5 - lc.y * 0.5);\\n if (uv.x <= 0.0 || uv.y <= 0.0 || uv.x >= 1.0 || uv.y >= 1.0) { return 1.0; }\\n // nothing was drawn at 1 (the clear): a receiver compares just inside it, so \\\"no caster here\\\" is lit wherever it lies\\n let depth = min(lc.z, 0.99995);\\n let bias = 0.35 / max(B.sh.y, 1.0);\\n // the blocker search: as far as the widest penumbra this book can cast\\n let widest = k.shadow.x + k.shadow.y * B.sh.w;\\n let search = clamp(2.2 * widest / texel, 2.0, 72.0);\\n var sum = 0.0;\\n var cnt = 0.0;\\n let base = uv * res;\\n var dir = vec2f(cos(rot), sin(rot));\\n for (var i = 0; i < 10; i++) {\\n let o = dir * sqrt((f32(i) + 0.5) / 10.0) * search;\\n dir = NB_GOLDEN * dir;\\n let t = clamp(vec2i(base + o), vec2i(0), vec2i(i32(res) - 1));\\n let d = textureLoad(tex, t, layer, 0);\\n if (d < depth - bias) { sum += d; cnt += 1.0; }\\n }\\n if (cnt < 0.5) { return 1.0; }\\n let gap = (depth - sum / cnt) * B.sh.y * B.lamp.z; // the blocker's height over the receiver, world units\\n let sigma = k.shadow.x + k.shadow.y * max(gap, 0.0);\\n let r = clamp(sigma / texel * 1.7, 0.75, 72.0);\\n var lit = 0.0;\\n var wsum = 0.0;\\n dir = vec2f(-dir.y, dir.x);\\n let inv2s2 = 1.0 / (2.0 * (r / 1.7) * (r / 1.7) + 1e-4);\\n for (var i = 0; i < 14; i++) {\\n let o = dir * sqrt((f32(i) + 0.5) / 14.0) * r;\\n dir = NB_GOLDEN * dir;\\n let w = exp(-dot(o, o) * inv2s2);\\n lit += w * textureSampleCompareLevel(tex, cmp, (base + o) / res, layer, depth - bias);\\n wsum += w;\\n }\\n return lit / max(wsum, 1e-5);\\n}\\n\\n// ---- the colour chain: the lamp's light on a face, then the desk's day or night\\n/// The book's colour chain: the lamp's light on a face, then the desk's day or night — the split a kind with an sRGB colour\\n/// makes (`mat_colour` hands one albedo to both chains).\\n/// `u` — the slot's view block; `albedo` — the face's sRGB colour, 0..1; `light` — the lamp's and the sky's share on it,\\n/// LINEAR, ≥ 0 (1 = a flat face lit straight on reads its own albedo); `gobo` — the dapple, 0..1; `noise` — blue noise 0..1.\\n/// → sRGB-encoded RGB: `shade_mat` of `albedo · light^(1/2.2)` by day, `night_mat` of `srgb_to_linear(albedo) · light` by\\n/// night, mixed by `u.night.x` between.\\nfn nb_colour(u: MatUniforms, albedo: vec3f, light: f32, gobo: f32, noise: f32) -> vec3f {\\n let day = shade_mat(u, clamp(albedo * pow(max(light, 0.0), 1.0 / 2.2), vec3f(0.0), vec3f(1.0)), gobo);\\n if (u.night.x <= 0.0) { return day; }\\n let night = night_mat(u, srgb_to_linear(clamp(albedo, vec3f(0.0), vec3f(1.0))) * max(light, 0.0), gobo, noise);\\n if (u.night.x >= 1.0) { return night; }\\n return mix(day, night, u.night.x);\\n}\\n\\n// ---- the cloth: a plain weave as a height, with its threads' own shades\\n/// A plain weave at a point: `h` — its height, unitless, ≈ −0.73 … 0.63 (the caller scales it); `g` — the height's slope,\\n/// d/du and d/dv per world unit; `shade` — the threads' own shade, ≈ −0.65 … 0.61 (a multiplier's offset). All three fade to 0\\n/// as the threads' pitch falls under the pixel.\\nstruct NbCloth { h: f32, g: vec2f, shade: f32 }\\n/// The bookcloth's plain weave: warp over weft on alternate cells, each thread a little thicker or lighter along its run.\\n/// `q` — the face's point, world units; `pitch` — the threads' pitch, world units, > 0; `px` — world units per device px.\\n/// → an `NbCloth`, faded to nothing as `px / pitch` rises from 0.35 to 0.9.\\nfn nb_cloth(q: vec2f, pitch: f32, px: f32) -> NbCloth {\\n let fade = 1.0 - smoothstep(0.35, 0.9, px / pitch);\\n let a = q / pitch;\\n let cell = floor(a);\\n let over = ((i32(cell.x) + i32(cell.y)) & 1) == 0;\\n let f = fract(a) - vec2f(0.5);\\n // warp (along v) over weft (along u) on alternate cells: a raised thread across each cell\\n let warp = 1.0 - 4.0 * f.x * f.x;\\n let weft = 1.0 - 4.0 * f.y * f.y;\\n let h = select(weft, warp, over) * 0.8 + 0.2 * (warp * weft);\\n let dwarp = -8.0 * f.x / pitch;\\n let dweft = -8.0 * f.y / pitch;\\n let g = select(vec2f(0.0, dweft), vec2f(dwarp, 0.0), over) * 0.8 + 0.2 * vec2f(dwarp * weft, warp * dweft);\\n // the threads' slubs: each thread a little thicker or lighter along its run\\n let slub = nb_vn(vec2f(select(cell.y, cell.x, over) * 1.7, select(a.x, a.y, over) * 0.21)).x;\\n var out: NbCloth;\\n out.h = (h - 0.55 + slub * 0.35) * fade;\\n out.g = g * fade;\\n out.shade = (slub * 0.9 + (h - 0.55) * 0.35) * fade;\\n return out;\\n}\\n\\n// ---- the cover's DESIGNS, printed on the cloth past the spine band (u, v in the face's world units from the band's edge and the head)\\n/// A ring's coverage.\\n/// `d` — the distance from the ring's centre; `r` — its radius; `w` — its line's width; `px` — world units per device px. All\\n/// world units.\\n/// → [0, 1]: 1 on the ring's line, a one-px ramp at its edges.\\nfn nb_ring(d: f32, r: f32, w: f32, px: f32) -> f32 { return nb_cov(abs(d - r) - w * 0.5, px); }\\n\\n/// A hash of a point: `hash12` on a scrambled copy (the designs' per-cell choices).\\n/// `p` — any point.\\n/// → [0, 1).\\nfn nb_hash2(p: vec2f) -> f32 { return hash12(p * vec2f(0.1031, 0.1030) + vec2f(19.19, 7.7)); }\\n\\n/// The cover's printed DESIGN, by `B.look.x`: 0 plain cloth · 1 orbit (rings round a brass sun) · 2 tiles (a grid of\\n/// quarter-rounds, halves and dots) · 3 label (a cream label on kraft) · 4 bordered (a blind-pressed frame).\\n/// `B` — the book (`B.look`: the design, and its seed in w; `B.col2` … `B.col4` and `B.col7` its inks, sRGB); `q` — the point\\n/// on the design's field, world units from the spine band's edge (u) and the head (v); `w`, `h` — the field's size, world\\n/// units; `px` — world units per device px; `base` — the cloth's sRGB colour under the design.\\n/// → rgb the colour there, sRGB 0..1; a a blind press's height, ≤ 0 (0 = none).\\nfn nb_design(B: NbBook, q: vec2f, w: f32, h: f32, px: f32, base: vec3f) -> vec4f {\\n let id = i32(B.look.x + 0.5);\\n var c = base;\\n var press = 0.0; // a blind line pressed into the cloth (a height)\\n if (id == 1) {\\n let o = vec2f(w * 0.5, h * 0.47);\\n let d = length(q - o);\\n let ringW = 0.9;\\n for (var i = 1; i <= 6; i++) {\\n let r = f32(i) * min(w, h) * 0.075 + 4.0;\\n c = mix(c, B.col3.rgb, nb_ring(d, r, ringW, px) * 0.8);\\n // a planet on each ring\\n let a = nb_hash2(vec2f(f32(i), 3.0)) * 6.2831 + B.look.w;\\n let pc = o + vec2f(cos(a), sin(a)) * r;\\n let pr = 1.6 + 2.4 * nb_hash2(vec2f(f32(i), 9.0));\\n let pcol = select(select(B.col4.rgb, B.col2.rgb, i % 3 == 1), B.col3.rgb, i % 3 == 2);\\n c = mix(c, pcol, nb_cov(length(q - pc) - pr, px));\\n }\\n c = mix(c, B.col2.rgb, nb_cov(d - 9.0, px));\\n } else if (id == 2) {\\n let n = vec2f(3.0, 4.0);\\n let cs = vec2f(w, h) / n;\\n let cell = clamp(floor(q / cs), vec2f(0.0), n - vec2f(1.0));\\n let f = (q - cell * cs) / cs; // 0..1 in the tile\\n let r = nb_hash2(cell + vec2f(B.look.w * 7.0, 1.0));\\n let r2 = nb_hash2(cell + vec2f(5.0, B.look.w * 3.0));\\n let bgI = i32(r2 * 4.0);\\n let fgI = (bgI + 1 + i32(r * 3.0)) % 4;\\n var bg = B.col2.rgb; var fg = B.col3.rgb;\\n if (bgI == 1) { bg = B.col3.rgb; } else if (bgI == 2) { bg = B.col4.rgb; } else if (bgI == 3) { bg = base; }\\n if (fgI == 0) { fg = B.col2.rgb; } else if (fgI == 2) { fg = B.col4.rgb; } else if (fgI == 3) { fg = base; }\\n let pxt = px / min(cs.x, cs.y);\\n var m = 0.0;\\n let kind = i32(r * 5.0);\\n if (kind == 0) { m = nb_cov(length(f) - 1.0, pxt); } // a quarter-round from a corner\\n else if (kind == 1) { m = nb_cov(length(f - vec2f(0.5, 1.0)) - 0.5, pxt); } // a half-round on the edge\\n else if (kind == 2) { m = nb_cov((f.x - f.y) * 0.7071, pxt); } // a diagonal half\\n else if (kind == 3) { m = nb_cov(length(f - vec2f(0.5)) - 0.3, pxt); } // a dot\\n else { m = nb_cov(max(abs(f.x - 0.5), abs(f.y - 0.5)) - 0.22, pxt); } // a square\\n c = mix(bg, fg, m);\\n } else if (id == 3) {\\n let lo = vec2f(w * 0.16, h * 0.16);\\n let hi = vec2f(w * 0.84, h * 0.33);\\n let d = nb_sd_box(q - (lo + hi) * 0.5, (hi - lo) * 0.5, 3.0);\\n let lab = nb_cov(d, px);\\n var lc = B.col3.rgb;\\n // two ruled lines on the label for a name\\n let ly = (q.y - lo.y) / (hi.y - lo.y);\\n let rule = max(nb_cov(abs(ly - 0.55) * (hi.y - lo.y) - 0.3, px), nb_cov(abs(ly - 0.8) * (hi.y - lo.y) - 0.3, px)) * step(lo.x + 6.0, q.x) * step(q.x, hi.x - 6.0);\\n lc = mix(lc, B.col7.rgb, rule * 0.35);\\n c = mix(c, lc, lab);\\n } else if (id == 4) {\\n let d = nb_sd_box(q - vec2f(w, h) * 0.5, vec2f(w, h) * 0.5 - vec2f(9.0), 2.5);\\n press = -exp(-(d * d) / 0.6) * 0.5;\\n c = c * (1.0 - exp(-(d * d) / 0.6) * 0.08);\\n }\\n return vec4f(c, press);\\n}\\n\\n// ---- the paper: its albedo (fibre, mottle) and its height (tooth, cockle), in the page's world units\\n/// A page's offset into the paper's tiles, so no two pages share their mottle.\\n/// `seed` — the page's number, any value.\\n/// → (0 … 97, 0 … 89), world units.\\nfn nb_paper_seed(seed: f32) -> vec2f { return vec2f(fract(seed * 0.618034) * 97.0, fract(seed * 0.381966) * 89.0); }\\n\\n// The paper from its baked texture (src/notebook/paper-tex.ts): the mottle and the fibres over a 64-unit\\n// tile, the tooth's slope over a 9.6-unit one, each page's tiles offset by its number; the cockle, slow\\n// enough for one noise. Explicit gradients, so it may be read anywhere and filters by its mips.\\n/// The paper at a point: `albedo` — its sRGB colour, the base with its mottle and fibres; `g` — its height's slope, the tooth\\n/// and the cockle, d/du and d/dv per world unit.\\nstruct NbPaperS { albedo: vec3f, g: vec2f }\\n/// The paper from its baked texture (kit/paper-tex.ts).\\n/// `k` — the pass's knobs (`k.paper`: fibre, mottle, tooth, cockle); `base` — the paper's sRGB colour; `q` — the page's point,\\n/// world units; `dqdx`, `dqdy` — `q`'s screen derivatives, world units per device px (the texture filters by them); `seed` —\\n/// the page's number; `tex` — the baked paper (rgba8, mipmapped: r the mottle, g the fibres, b and a the tooth's slope);\\n/// `samp` — a repeating trilinear sampler.\\n/// → an `NbPaperS`.\\nfn nb_paper(k: NbUniforms, base: vec3f, q: vec2f, dqdx: vec2f, dqdy: vec2f, seed: f32, tex: texture_2d<f32>, samp: sampler) -> NbPaperS {\\n let s = nb_paper_seed(seed);\\n let a = textureSampleGrad(tex, samp, q / 64.0 + s / 64.0, dqdx / 64.0, dqdy / 64.0);\\n let tt = 9.6;\\n let b = textureSampleGrad(tex, samp, q / tt + s.yx / 31.0, dqdx / tt, dqdy / tt);\\n let v = (a.r - 0.5) * k.paper.y * 2.0 + (a.g - 0.5) * k.paper.x * 3.0;\\n var out: NbPaperS;\\n out.albedo = base + vec3f(v * 1.05, v, v * 0.8);\\n let tooth = (b.ba - vec2f(0.5)) * (2.0 * 48.0 / tt) * (k.paper.z * 0.02);\\n let c = nb_vn(q / 55.0 + s * 0.5);\\n out.g = tooth + c.yz / 55.0 * (k.paper.w * 2.0);\\n return out;\\n}\\n\\n/// The ruling printed on a page, by `B.look.y`: 0 none · 1 dots · 2 lines · else a grid — on `k.rule.x`'s pitch, inside\\n/// `k.rule.z`'s margin, laid from the head and the fore-edge so it sits the same on every page.\\n/// `k` — the pass's knobs (`k.rule`: the pitch, a dot's radius, the margin — world units); `B` — the book; `q` — the page's\\n/// point, world units (u from the gutter, v from the head); `w`, `h` — the page's size, world units; `px` — world units per\\n/// device px.\\n/// → [0, 1]: the ruling's ink coverage, faded out as the pitch falls from 5 to 2 device px.\\nfn nb_ruling(k: NbUniforms, B: NbBook, q: vec2f, w: f32, h: f32, px: f32) -> f32 {\\n let kind = i32(B.look.y + 0.5);\\n if (kind == 0) { return 0.0; }\\n let pitch = k.rule.x;\\n let m = k.rule.z;\\n let inside = step(m, q.x) * step(q.x, w - m) * step(m, q.y) * step(q.y, h - m);\\n let vis = smoothstep(2.0, 5.0, pitch / px);\\n // the grid is laid from the page's head and fore-edge so it sits the same on every page\\n let g = (q - vec2f(w, 0.0)) / pitch;\\n let f = fract(g) - vec2f(0.5);\\n if (kind == 1) {\\n let d = length(f) * pitch - k.rule.y;\\n return nb_cov(d, max(px, 0.35)) * inside * vis;\\n }\\n if (kind == 2) {\\n let d = abs(f.y) * pitch - k.rule.y * 0.45;\\n return nb_cov(d, max(px, 0.3)) * inside * vis * 0.75;\\n }\\n let d = min(abs(f.x), abs(f.y)) * pitch - k.rule.y * 0.4;\\n return nb_cov(d, max(px, 0.3)) * inside * vis * 0.6;\\n}\\n\\n// ---- the case: the cover's face (u from the spine edge, v from the head, world units)\\n\\n/// The cover's height slope: the cloth rolling over the board's edge (the bevel), the groove where the band's edge lies under\\n/// the cover's cloth, the hinge's pressed groove, the weave (a paper cover's grain instead), a blind press.\\n/// `k` — the pass's knobs (`k.cloth`); `B` — the book (`B.size`, `B.page.w` the spine band's width, `B.foot.y` a paper cover,\\n/// `B.look.x` the design); `q` — the cover's point, world units (u from the spine edge, v from the head); `px` — world units\\n/// per device px.\\n/// → d/du and d/dv of the cover's height, per world unit (the caller tips the face's normal by it).\\nfn nb_cover_g(k: NbUniforms, B: NbBook, q: vec2f, px: f32) -> vec2f {\\n let w = B.size.x;\\n let h = B.size.y;\\n let e = 0.05;\\n let d = nb_sd_fore(q, w, h, B.size.w);\\n let dg = vec2f(nb_sd_fore(q + vec2f(e, 0.0), w, h, B.size.w) - d, nb_sd_fore(q + vec2f(0.0, e), w, h, B.size.w) - d) / e;\\n // bevel: z = −1.1·(1 + d/2.2)² over the last 2.2 units — its slope along the outline's normal\\n let t = nb_sat(1.0 + d / 2.2);\\n var g = dg * (-2.2 * t / 2.2) * select(0.0, 1.0, d > -2.2 && d < 0.0);\\n let band = B.page.w;\\n let xb = q.x - band;\\n g.x += 0.22 * exp(-(xb * xb) / 0.5) * (2.0 * xb / 0.5);\\n let xh = q.x - 7.0;\\n g.x += 0.55 * exp(-(xh * xh) / 2.2) * (2.0 * xh / 2.2);\\n if (B.foot.y < 0.5) { g += nb_cloth(q, k.cloth.x, px).g * k.cloth.y; }\\n else { g += nb_fbm(q * 1.1).yz * 1.1 * 0.05 * nb_detail(1.0, px); }\\n if (i32(B.look.x + 0.5) == 4 && q.x > band) {\\n // the blind-pressed frame\\n let p = q - vec2f(band, 0.0);\\n let hw = vec2f(w - band, h) * 0.5;\\n let db = nb_sd_box(p - hw, hw - vec2f(9.0), 2.5);\\n let dbg = vec2f(nb_sd_box(p + vec2f(e, 0.0) - hw, hw - vec2f(9.0), 2.5) - db, nb_sd_box(p + vec2f(0.0, e) - hw, hw - vec2f(9.0), 2.5) - db) / e;\\n g += dbg * (0.5 * exp(-(db * db) / 0.6) * (2.0 * db / 0.6));\\n }\\n return g;\\n}\\n\\n/// The cover's colour: the design on the cloth past the spine band, the band's cloth before it, the weave's shade (a paper\\n/// cover's grain instead).\\n/// `k` — the pass's knobs; `B` — the book (`B.col0` the cloth, `B.col1` the band, sRGB); `q` — the cover's point, world units\\n/// (u from the spine edge, v from the head); `px` — world units per device px.\\n/// → sRGB, ≈ 0..1.\\nfn nb_cover_albedo(k: NbUniforms, B: NbBook, q: vec2f, px: f32) -> vec3f {\\n let w = B.size.x;\\n let h = B.size.y;\\n let band = B.page.w;\\n let design = nb_design(B, q - vec2f(band, 0.0), w - band, h, px, B.col0.rgb).rgb;\\n var c = mix(design, B.col1.rgb, nb_cov(q.x - band, px));\\n if (B.foot.y < 0.5 || q.x < band) { c *= 1.0 + nb_cloth(q, k.cloth.x, px).shade * 0.16; }\\n else { c += vec3f(nb_fbm(q * 0.35).x * 0.035 + nb_fbm(q * 2.1).x * 0.02 * nb_detail(0.6, px)); }\\n return c;\\n}\\n\\n/// A board's inside at a point: `albedo` — sRGB 0..1; `ao` — its occlusion, a multiplier 0..1 (1 = none).\\nstruct NbEnd { albedo: vec3f, ao: f32 }\\n/// The inside of a board: the endpaper, framed by the cloth's turn-in along the head, the fore-edge and the tail.\\n/// `k` — the pass's knobs; `B` — the book (`B.col0` the cloth, `B.col5` the endpaper); `q` — the board's point, world units\\n/// (u from the spine side, v from the head); `px` — world units per device px; `stacked` — the text block stands on this board\\n/// (its foot occludes it); `dqdx`, `dqdy`, `tex`, `samp` — as `nb_paper`'s.\\n/// → an `NbEnd`.\\nfn nb_endpaper(k: NbUniforms, B: NbBook, q: vec2f, px: f32, stacked: bool, dqdx: vec2f, dqdy: vec2f, tex: texture_2d<f32>, samp: sampler) -> NbEnd {\\n let w = B.size.x;\\n let h = B.size.y;\\n let turn = 4.2;\\n let de = nb_sd_fore(q - vec2f(-2.0, turn), w - turn + 2.0, h - 2.0 * turn, max(B.size.w - turn * 0.6, 1.0));\\n let inside = nb_cov(de, px);\\n var cloth = B.col0.rgb;\\n if (B.foot.y < 0.5) { cloth *= 1.0 + nb_cloth(q, k.cloth.x, px).shade * 0.16; }\\n let paper = nb_paper(k, B.col5.rgb, q, dqdx, dqdy, 91.0 + B.look.w, tex, samp).albedo;\\n var out: NbEnd;\\n out.albedo = mix(cloth, paper, inside);\\n // the endpaper's edge: a hairline of shade where the paper lies over the cloth\\n out.ao = 1.0 - 0.3 * exp(-(de * de) / 0.35) * (1.0 - inside * 0.4);\\n if (stacked) {\\n // the text block standing on it: occlusion at its foot\\n let sq = B.open.w;\\n let ds = nb_sd_fore(q - vec2f(-4.0, sq), w - sq + 4.0, h - 2.0 * sq, B.page.z);\\n out.ao *= 1.0 - 0.34 * exp(-max(ds, 0.0) / 2.6);\\n }\\n return out;\\n}\\n\\n/// A board's edge: the cloth wrapped over it — the band's near the spine, the cover's beyond.\\n/// `k` — the pass's knobs (`k.cloth.x` the weave's pitch); `B` — the book (`B.size`, `B.page.w`, `B.col0`, `B.col1`); `q` —\\n/// the edge's point, world units (u along the board's edge from the spine, round the fore-edge and back; v across the board's\\n/// thickness); `px` — world units per device px.\\n/// → sRGB, ≈ 0..1.\\nfn nb_board(k: NbUniforms, B: NbBook, q: vec2f, px: f32) -> vec3f {\\n let w = B.size.x;\\n let h = B.size.y;\\n let r = B.size.w;\\n let total = 2.0 * (w - r) + NB_PI * r + h - 2.0 * r;\\n let band = B.page.w;\\n let inBand = max(1.0 - smoothstep(band - 0.5, band + 0.5, q.x), smoothstep(total - band - 0.5, total - band + 0.5, q.x));\\n var c = mix(B.col0.rgb, B.col1.rgb, inBand);\\n c *= 0.94 + nb_cloth(vec2f(q.x, q.y * 3.0), k.cloth.x, px).shade * 0.12;\\n return c;\\n}\\n\\n/// A stack's edge: the sheets' edges, one stripe each, each sheet a shade of its own; averaged as they fall under the pixel.\\n/// `k` — unread; `B` — the book (`B.foot.z` a sheet's thickness, world units; `B.col6` the paper); `q` — the edge's point,\\n/// world units (v across the sheets); `sheets` — unread (the face's own number, kept for the call's shape); `side` — which\\n/// edge, a seed (the head's, the tail's and the fore-edge's shades differ); `px` — world units per device px.\\n/// → sRGB: the paper's colour × ≈ 0.54 … 0.97.\\nfn nb_edge(k: NbUniforms, B: NbBook, q: vec2f, sheets: f32, side: f32, px: f32) -> vec3f {\\n let t = max(B.foot.z, 1e-3);\\n let f = q.y / t;\\n let i = floor(f);\\n let g = fract(f);\\n let vis = smoothstep(0.7, 2.2, t / px);\\n let own = hash12(vec2f(i + side * 131.0, 7.0)) - 0.5;\\n let gap = pow(1.0 - min(g, 1.0 - g) * 2.0, 6.0);\\n let rough = nb_vn(vec2f(q.x * 0.35, i * 1.7)).x * 0.05;\\n let shade = 0.9 + (own * 0.08 + rough) * vis - gap * 0.3 * vis;\\n return B.col6.rgb * shade;\\n}\\n\",\n \"kit/composite.wgsl\": \"// (The kit's since K4a — moved from notebook/notebook-composite.wgsl: every layered kind lays its layer with it, kit/layer.ts `layerComposite`.)\\n// A layered kind's layer onto the canvas: the resolved, premultiplied layer, over what the ground drew — through the slot's PORTAL CHAIN\\n// (design-018 §4 — the kit's contract, which the kind's own passes cannot keep: they draw into the layer, not onto the canvas). The\\n// whole layer is laid at the chain's cover, so its object fades as ONE (a book's cover never shows its pages through it — group\\n// opacity, the tray's feather); at the root the chain is empty, the cover exactly 1, and the layer is laid as it always was.\\n// K7a: the layer is its screen BOX's (kit/layer.ts `BoxTargets`) — the texel of a pixel is the pixel less the box's origin.\\n//\\n// THE KIT'S COMPOSITE ENTRY (`LAYER_COMPOSITE_FILE`; composed by `layerComposite` after the `view` and `portal` pieces; petition\\n// I31 — every declaration's `///` block says what it takes and gives). Drawn inside the slot's scissor; its output is\\n// premultiplied, laid \\\"one, one − src alpha\\\".\\n\\n/// The layer: the kind's resolved target, premultiplied RGBA, one texel a device px of its screen box.\\n@group(0) @binding(0) var layer: texture_2d<f32>;\\n/// The layer box's origin on the attachment, device px (xy; zw unused) — `BoxTargets.origin`.\\n@group(0) @binding(1) var<uniform> origin: vec4f;\\n/// The slot's view block (`MatPass.view`) — its portal chain and its ratio.\\n@group(0) @binding(2) var<uniform> u: MatUniforms;\\n\\n/// One triangle over the whole attachment.\\n/// `vid` — the vertex index, 0 … 2.\\n/// → its clip-space corner: (−1, −1), (3, −1), (−1, 3).\\n@vertex\\nfn vs(@builtin(vertex_index) vid: u32) -> @builtin(position) vec4f {\\n var p = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));\\n return vec4f(p[vid], 0.0, 1.0);\\n}\\n\\n/// The layer's texel at a pixel, through the slot's chain.\\n/// `pos` — the fragment's position, device px of the attachment.\\n/// → premultiplied RGBA: the layer's texel at `pos − origin`, times `portal_cover` at `pos` (exactly the texel at the root).\\n@fragment\\nfn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\\n let dpr = u.cam.w;\\n return textureLoad(layer, vec2i(pos.xy) - vec2i(origin.xy), 0) * portal_cover(pos.xy / dpr, u.portals, u.clips, dpr);\\n}\\n\",\n \"marks/marks-pass.wgsl\": \"// The marks pass — the desk's chrome over every stratum (design-015 §4.2 stratum 5, §7; D4a): one\\n// instanced draw, one quad per mark over the screen rect the CPU gave it (`quad`, CSS px — the marks do\\n// not zoom), one `marks_shade` per covered fragment, premultiplied out; a mark of light returns alpha 0,\\n// so the blend (one, one − src alpha) adds it. The glyphs are the rulers' mono atlas (RULER.md), the\\n// mat's own texture — the pills' and the rulers' numerals are one face.\\n\\n@group(0) @binding(0) var<uniform> u: MarksUniforms;\\n@group(0) @binding(1) var<storage, read> marks: array<Mark>;\\n@group(0) @binding(2) var glyph_tex: texture_2d<f32>;\\n@group(0) @binding(3) var glyph_samp: sampler;\\n\\nstruct VSOut {\\n @builtin(position) clip: vec4f,\\n @location(0) @interpolate(flat) idx: u32,\\n}\\n\\nconst CORNERS = array<vec2f, 6>(\\n vec2f(0.0, 0.0), vec2f(1.0, 0.0), vec2f(1.0, 1.0),\\n vec2f(0.0, 0.0), vec2f(1.0, 1.0), vec2f(0.0, 1.0),\\n);\\n\\n@vertex\\nfn vs(@builtin(vertex_index) vid: u32, @builtin(instance_index) iid: u32) -> VSOut {\\n var out: VSOut;\\n out.idx = iid;\\n let q = marks[iid].quad;\\n let pos = mix(q.xy, q.zw, CORNERS[vid]); // CSS px\\n out.clip = vec4f(pos.x / u.view.x * 2.0 - 1.0, 1.0 - pos.y / u.view.y * 2.0, 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fs(in: VSOut) -> @location(0) vec4f {\\n let dpr = max(u.view.z, 1e-6);\\n var c = marks_shade(marks[in.idx], in.clip.xy / dpr, dpr, u.atlas, glyph_tex, glyph_samp);\\n // the tray's name tags fade in under the drawer's header as its specimens do (design-018 §4, R4) — from the first tag's record on\\n if (u.fade.y > 0.0 && f32(in.idx) >= u.fade.z) { c *= smoothstep(u.fade.x, u.fade.x + u.fade.y, in.clip.y / dpr); }\\n if (c.a <= 0.0 && max(c.r, max(c.g, c.b)) <= 0.0) { discard; }\\n return c;\\n}\\n\",\n \"marks/marks.wgsl\": \"// The MARKS — the desk's chrome as SDF terms (design-015 §7, stratum 5; D4a): *Marks on the Mat*'s\\n// reference drawing code (vibe-field/draft/desk-chrome/chrome.js) as distances. Every mark is ONE\\n// record (a `Mark`, laid out on the CPU by src/marks/layout.ts in SCREEN px — the chrome keeps its size\\n// at every zoom), shaded here into a premultiplied colour: an outline or a fill of a turned rounded\\n// box (a frame, a ring, a knob, the vellum, a pill), the four brackets of a frame, a segment (solid or\\n// dotted, a laser's line), a gap's bar with its end ticks, a flare, a glyph of the rulers' mono atlas\\n// (with its halo), a strip of masking tape. Light is ADDED: a mark flagged so returns alpha 0 over its\\n// colour, which the pass's premultiplied blend turns into dst + src — Canvas2D's \\\"lighter\\\".\\n// Pure: every resource is a parameter (engine/shader.ts's rule).\\n\\nconst MARK_STROKE: f32 = 0.0;\\nconst MARK_FILL: f32 = 1.0;\\nconst MARK_BRACKETS: f32 = 2.0;\\nconst MARK_SEGMENT: f32 = 3.0;\\nconst MARK_BAR: f32 = 4.0;\\nconst MARK_FLARE: f32 = 5.0;\\nconst MARK_GLYPH: f32 = 6.0;\\nconst MARK_TAPE: f32 = 7.0;\\n\\n/** Coverage of a distance (CSS px) over one DEVICE px of ramp. */\\nfn marks_cov(sd: f32, dpr: f32) -> f32 { return clamp(0.5 - sd * dpr, 0.0, 1.0); }\\n\\n/** A screen point in a mark's own frame: about its centre, turned by −angle (positive turns clockwise on screen, y down). */\\nfn marks_local(p: vec2f, c: vec2f, angle: f32) -> vec2f {\\n let d = p - c;\\n let cs = cos(angle);\\n let sn = sin(angle);\\n return vec2f(cs * d.x + sn * d.y, -sn * d.x + cs * d.y);\\n}\\n\\n/**\\n * The distance to the four BRACKETS of a rounded frame (half extents X, Y, corner r), each reaching L from its\\n * corner along both sides (chrome.js `bracketsPath`): folded into one quadrant, the run along the top edge from\\n * its end to the arc, the arc, and the run down the side — round caps come from the distance itself.\\n */\\nfn marks_brackets(p: vec2f, X: f32, Y: f32, r: f32, L: f32) -> f32 {\\n let q = abs(p);\\n let top = length(q - vec2f(clamp(q.x, X - L, X - r), Y));\\n let side = length(q - vec2f(X, clamp(q.y, Y - L, Y - r)));\\n var d = min(top, side);\\n let v = q - vec2f(X - r, Y - r);\\n if (r > 0.0 && v.x >= 0.0 && v.y >= 0.0) { d = min(d, abs(length(v) - r)); }\\n return d;\\n}\\n\\n/** The distance to a dotted line A→B: a dot every `period` from A (Canvas2D's `[0.01, period − 0.01]` dash with round caps). */\\nfn marks_dotted(p: vec2f, a: vec2f, b: vec2f, period: f32) -> f32 {\\n let ab = b - a;\\n let len = length(ab);\\n let dir = ab / max(len, 1e-6);\\n let k = clamp(round(dot(p - a, dir) / period), 0.0, floor(len / period));\\n return length(p - (a + dir * (k * period)));\\n}\\n\\n/** A gap's bar: the segment A→B and a tick `tick` either side of it at each end, one stroke. */\\nfn marks_bar(p: vec2f, a: vec2f, b: vec2f, tick: f32) -> f32 {\\n let ab = b - a;\\n let n = vec2f(-ab.y, ab.x) / max(length(ab), 1e-6) * tick;\\n return min(sdf_segment(p, a, b), min(sdf_segment(p, a - n, a + n), sdf_segment(p, b - n, b + n)));\\n}\\n\\n/** Masking tape's torn outline (desk.css `.obj-tape i` clip-path), unit square, clockwise from the top-left. */\\nconst TAPE_EDGE = array<vec2f, 12>(\\n vec2f(0.03, 0.0), vec2f(0.97, 0.04), vec2f(1.0, 0.22), vec2f(0.96, 0.40), vec2f(1.0, 0.60), vec2f(0.97, 0.80),\\n vec2f(1.0, 1.0), vec2f(0.02, 0.96), vec2f(0.0, 0.78), vec2f(0.04, 0.58), vec2f(0.0, 0.40), vec2f(0.03, 0.20),\\n);\\n\\n/** The signed distance to the tape's outline, the strip `half` in its own frame (Quilez's polygon). */\\nfn marks_tape_sd(p: vec2f, half: vec2f) -> f32 {\\n let v0 = (TAPE_EDGE[0] - 0.5) * 2.0 * half;\\n var d = dot(p - v0, p - v0);\\n var s = 1.0;\\n for (var i = 0u; i < 12u; i++) {\\n let j = (i + 11u) % 12u;\\n let vi = (TAPE_EDGE[i] - 0.5) * 2.0 * half;\\n let vj = (TAPE_EDGE[j] - 0.5) * 2.0 * half;\\n let e = vj - vi;\\n let w = p - vi;\\n let b = w - e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0);\\n d = min(d, dot(b, b));\\n let c0 = p.y >= vi.y;\\n let c1 = p.y < vj.y;\\n let c2 = e.x * w.y > e.y * w.x;\\n if ((c0 && c1 && c2) || (!c0 && !c1 && !c2)) { s = -s; }\\n }\\n return s * sqrt(d);\\n}\\n\\n/** CSS `saturate(s) brightness(b)` on an sRGB colour (the Filter Effects matrix). */\\nfn marks_moonlit(c: vec3f, s: f32, b: f32) -> vec3f {\\n let r = vec3f(0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s);\\n let g = vec3f(0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s);\\n let bl = vec3f(0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s);\\n return clamp(vec3f(dot(r, c), dot(g, c), dot(bl, c)) * b, vec3f(0.0), vec3f(1.0));\\n}\\n\\n/** One texel sample of a cell (texels from its top-left, kept inside the cell: a neighbour's glyph never bleeds in). */\\nfn marks_glyph_at(t: vec2f, cell: f32, size: vec2f, atlas: vec4f, tex: texture_2d<f32>, samp: sampler) -> f32 {\\n let at = vec2f(cell * atlas.w, 0.0) + clamp(t, vec2f(0.5), size - 0.5);\\n return textureSampleLevel(tex, samp, at / atlas.xy, 0.0).r;\\n}\\n\\n/** The glyph atlas's coverage at a point of a cell's own frame (CSS px from its top-left; the cell `size` CSS px), `halo` > 0 = its coverage dilated that far. */\\nfn marks_glyph_cov(q: vec2f, cell: f32, size: vec2f, atlas: vec4f, halo: f32, tex: texture_2d<f32>, samp: sampler) -> f32 {\\n let scale = atlas.z;\\n let t = q * scale;\\n let s = size * scale;\\n var c = marks_glyph_at(t, cell, s, atlas, tex, samp);\\n if (halo > 0.0) {\\n for (var i = 0; i < 8; i++) {\\n let a = f32(i) * 0.785398163;\\n let o = vec2f(cos(a), sin(a)) * halo * scale;\\n c = max(c, marks_glyph_at(t + o, cell, s, atlas, tex, samp));\\n c = max(c, marks_glyph_at(t + o * 0.5, cell, s, atlas, tex, samp));\\n }\\n }\\n return c;\\n}\\n\\n/**\\n * One mark at screen point `p` (CSS px), premultiplied — alpha 0 when it is light (added). `atlas` = the glyph atlas's\\n * width, height (texels), texels per CSS px and cell width (texels).\\n */\\nfn marks_shade(M: Mark, p: vec2f, dpr: f32, atlas: vec4f, tex: texture_2d<f32>, samp: sampler) -> vec4f {\\n let kind = M.shape.x;\\n let width = M.shape.z;\\n var cov = 0.0;\\n var col = M.colour;\\n if (kind == MARK_STROKE || kind == MARK_FILL || kind == MARK_BRACKETS) {\\n let q = marks_local(p, M.centre.xy, M.centre.z);\\n let sd = sdf_round_box(q, M.half.xy, M.centre.w);\\n if (kind == MARK_STROKE) {\\n cov = marks_cov(abs(sd) - 0.5 * width, dpr);\\n } else if (kind == MARK_FILL) {\\n cov = marks_cov(sd, dpr);\\n } else {\\n cov = marks_cov(marks_brackets(q, M.half.x, M.half.y, M.centre.w, M.shape.w) - 0.5 * width, dpr);\\n }\\n } else if (kind == MARK_SEGMENT) {\\n let d = select(sdf_segment(p, M.centre.xy, M.half.xy), marks_dotted(p, M.centre.xy, M.half.xy, M.aux.x), M.aux.x > 0.0);\\n cov = marks_cov(d - 0.5 * width, dpr);\\n } else if (kind == MARK_BAR) {\\n cov = marks_cov(marks_bar(p, M.centre.xy, M.half.xy, M.aux.x) - 0.5 * width, dpr);\\n } else if (kind == MARK_FLARE) {\\n // a radial gradient: the core at the centre, the laser at `stop`, nothing at the rim — interpolated premultiplied\\n let t = length(p - M.centre.xy) / M.centre.w;\\n if (t >= 1.0) { return vec4f(0.0); }\\n let core = vec4f(M.aux.rgb * M.aux.a, M.aux.a);\\n let mid = vec4f(M.colour.rgb * M.colour.a, M.colour.a);\\n let stop = M.half.x;\\n let c = select(mix(mid, vec4f(0.0), (t - stop) / (1.0 - stop)), mix(core, mid, t / stop), t < stop);\\n return vec4f(c.rgb, select(c.a, 0.0, (u32(M.shape.y) & 1u) != 0u));\\n } else if (kind == MARK_GLYPH) {\\n // the cell turned about its centre (`centre.xy`), its own frame from its top-left; a halo reaches `aux.y` past it\\n let q = marks_local(p, M.centre.xy, M.centre.z) + 0.5 * M.half.xy;\\n let h = M.aux.y;\\n if (q.x < -h || q.y < -h || q.x > M.half.x + h || q.y > M.half.y + h) { return vec4f(0.0); }\\n cov = marks_glyph_cov(q, M.aux.x, M.half.xy, atlas, h, tex, samp);\\n } else if (kind == MARK_TAPE) {\\n // the strip in its own frame: its torn outline, its fibres (1 in `every` object units), a light from above, moonlit by night\\n let q = marks_local(p, M.centre.xy, M.centre.z);\\n let half = M.half.xy;\\n cov = marks_cov(marks_tape_sd(q, half), dpr);\\n let uv = (q + half) / (2.0 * half);\\n let units = M.aux.x; // CSS px per object unit\\n let sheen = mix(vec4f(1.0, 1.0, 1.0, M.half.z), vec4f(0.0, 0.0, 0.0, M.half.w), clamp(uv.y, 0.0, 1.0));\\n var c = vec4f(M.colour.rgb * M.colour.a, M.colour.a);\\n c = vec4f(sheen.rgb * sheen.a, sheen.a) + c * (1.0 - sheen.a);\\n let every = M.shape.w;\\n let x = (q.x + half.x) / max(units, 1e-6);\\n let seen = clamp(every * units * dpr / 3.0 - 0.5, 0.0, 1.0); // fibres under ~1.5 device px each fade to the mean\\n let fibre = select(0.0, 1.0, fract(x / every) < 1.0 / every) * seen + (1.0 - seen) / every;\\n let fa = M.aux.w * fibre;\\n c = vec4f(vec3f(fa), fa) + c * (1.0 - fa);\\n let rgb = marks_moonlit(c.rgb / max(c.a, 1e-6), M.aux.y, M.aux.z);\\n let a = c.a * cov * M.centre.w;\\n return vec4f(rgb * a, a);\\n }\\n let a = col.a * cov;\\n return vec4f(col.rgb * a, select(a, 0.0, (u32(M.shape.y) & 1u) != 0u));\\n}\\n\",\n \"mat/mat-pass.wgsl\": \"// PASS 2, the cutting mat — one fullscreen triangle: the lattice's lines as\\n// analytic coverage, the grain, the gobo projected onto the desk plane, the\\n// reference's grade by day or the night's eye by night (MAT.md). Alpha 1 at\\n// rest (a plain write); a flight fades it and clips it to the portal.\\n\\n@group(0) @binding(0) var<uniform> u: MatUniforms;\\n@group(0) @binding(1) var gobo_tex: texture_2d<f32>;\\n@group(0) @binding(2) var gobo_samp: sampler;\\n@group(0) @binding(3) var noise_tex: texture_2d<f32>;\\n@group(0) @binding(4) var noise_samp: sampler;\\n@group(0) @binding(5) var glyph_tex: texture_2d<f32>; // the rulers' glyph atlas (RULER.md); a 1×1 empty cell until a host uploads one\\n\\nstruct VSOut { @builtin(position) clip: vec4f }\\n\\n@vertex\\nfn vs(@builtin(vertex_index) vid: u32) -> VSOut {\\n var p = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));\\n var out: VSOut;\\n out.clip = vec4f(p[vid], 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fs(in: VSOut) -> @location(0) vec4f {\\n let zoom = mat_zoom(u);\\n let dpr = mat_dpr(u);\\n let frag = in.clip.xy; // device px\\n let screen = frag / dpr; // CSS px\\n let px = 1.0 / (zoom * dpr); // world per device px\\n let bn = textureSampleLevel(noise_tex, noise_samp, frag * u.noise.z + u.noise.xy, 0.0).rgb;\\n // the rulers' print — screen-space ink mixed into the albedo before the light, so it is lit and shadowed like the lines\\n let ruler = ruler_ink(u, screen, frag, glyph_tex, gobo_samp);\\n let albedo = mat_albedo(u, u.phase.xy + screen / zoom, px, frag, bn, ruler);\\n // the lamp's gobo where the LIGHT sees this pixel (MINIMAT.md §4): the slot's own camera at rest\\n // (`light` = `cam`, so this is the desk under the pixel), the host desk's through a mini mat's face.\\n // A viewport lamp uses (0, 0, 1): its projection stays in CSS pixels without an extra fragment branch.\\n var gobo = project_gobo(u, gobo_tex, gobo_samp, desk_of(u, u.light.xy + screen / max(u.light.z, 1e-12)), bn.z);\\n if (u.light.w > 0.0) { gobo = mix(gobo, project_gobo(u, gobo_tex, gobo_samp, desk_of(u, u.light2.xy + screen / max(u.light2.z, 1e-12)), bn.z), u.light.w); }\\n // Straight alpha: the presentation's opacity through the portal clip — both 1 at rest,\\n // when \\\"source over\\\" reduces to a plain write.\\n return vec4f(mat_colour(u, albedo, gobo, bn.y), u.presence.x * portal_cover(screen, u.portals, u.clips, dpr));\\n}\\n\",\n \"mat/mat.wgsl\": \"// The cutting mat's maths — a PURE module: no bindings. The uniform block and\\n// the textures arrive as parameters. Every function body is the reference's\\n// (research/tree-shadow/prototype/src/shaders.js), transcribed to the engine's\\n// units: world = CSS px at zoom 1, the lattice's decade rungs, `MatUniforms`\\n// from src/mat/layout.ts prepended by the engine.\\n//\\n// THE KIT'S `light` PIECE (`kitWgsl([..., \\\"light\\\"])` — `lamp`, `gobo`, `night` and `noise` name it too; petition I31: every\\n// declaration's `///` block says what it takes and gives). THE CONVENTIONS every kit piece is written in:\\n// - WORLD units: one is one CSS px at zoom 1. World x runs right and world y runs DOWN, as the screen's do. A slot's camera is\\n// unwrapped world (`u.cam.xy`, the world point at the attachment's top-left); the lattice's PHASE is the camera wrapped to\\n// the coarse rung's period (`u.phase.xy`), what the lines are drawn from so they stay exact at any distance.\\n// - CSS px: the attachment's layout px, origin its top-left, y down — `(world − u.cam.xy) · zoom`.\\n// - DEVICE px: the attachment's texels — a fragment's `@builtin(position).xy`, pixel centres at .5 — CSS px · dpr. So a\\n// fragment's world point is `frag / (zoom · dpr) + u.cam.xy`, and one device px is `1 / (zoom · dpr)` world units.\\n// - zoom = `mat_zoom(u)`: CSS px per world unit. dpr = `mat_dpr(u)`: device px per CSS px — the ATTACHMENT's own, below 1 for\\n// a capture's thumbnail or the held desk copy (petition I29). Both > 0.\\n// - the DESK: the plane the lamp lights, in the projector's frame — metres, y UP (three's): world x runs along its x, world y\\n// along its z, and a height above the desk along its y (`desk_of`, `lit_desk`; `u.plane`).\\n// - COLOUR: 0..1 per channel. sRGB-encoded unless a parameter says LINEAR; the swap chain is a plain 8-bit format, so what a\\n// pass writes is what CSS would show. The day's chain (`shade_mat`) keeps its input's encoding; the night's (`night_mat`)\\n// takes linear reflectance and returns encoded colour.\\n\\n/// The slot's zoom: CSS px per world unit.\\n/// `u` — the slot's view block (`MatUniforms`, bound as `u`).\\n/// → `u.cam.z`, floored at 1e-12 so it divides safely: > 0 (the desk's band is 1e-8 … 1e8).\\nfn mat_zoom(u: MatUniforms) -> f32 { return max(u.cam.z, 1e-12); }\\n// The ATTACHMENT's own device ratio — below 1 for a capture's thumbnail (dpr × scale), the held desk copy (dpr / 2) and a page\\n// zoomed out — guarded only against an unset block. Every fragment's CSS px is its device px over it: a floor at 1 put each one\\n// at the wrong point of the desk there, and the flat kinds shaded nothing (petition I29).\\n/// The attachment's device px per CSS px.\\n/// `u` — the slot's view block.\\n/// → `u.cam.w`, floored at 1e-6 against an unset block only: > 0, and below 1 for a thumbnail capture or the held desk copy.\\nfn mat_dpr(u: MatUniforms) -> f32 { return max(u.cam.w, 1e-6); }\\n\\n// ---- the reference's noise (hash12 · valueNoise), on framebuffer pixels\\n/// The reference's hash: one pseudo-random number per point (`sin`-based — cheap, not a quality RNG; best for |p| within a\\n/// few thousand, where f32 `sin` keeps its digits).\\n/// `p` — any point (the mat hands framebuffer device px, scaled).\\n/// → [0, 1): a different value at every distinct `p`, with no continuity between neighbours.\\nfn hash12(p: vec2f) -> f32 {\\n let n = sin(dot(p, vec2f(127.1, 311.7))) * 43758.5453;\\n return n - floor(n);\\n}\\n\\n/// Value noise: `hash12` at the four corners of `p`'s lattice cell, blended by a smoothstep weight.\\n/// `p` — the point in the noise's own cells (one cell per unit of `p`; the mat's grain hands device px × 0.45, a cell ≈ 2.2\\n/// device px).\\n/// → [0, 1): continuous, with a continuous gradient across cells, mean ≈ 0.5 — centre it with `value_noise(p) − 0.5`\\n/// ([−0.5, 0.5)).\\nfn value_noise(p: vec2f) -> f32 {\\n let i = floor(p);\\n var f = fract(p);\\n f = f * f * (3.0 - 2.0 * f);\\n return mix(\\n mix(hash12(i), hash12(i + vec2f(1.0, 0.0)), f.x),\\n mix(hash12(i + vec2f(0.0, 1.0)), hash12(i + vec2f(1.0, 1.0)), f.x),\\n f.y);\\n}\\n\\n/// The sRGB transfer curve, decoded (IEC 61966-2-1).\\n/// `c` — sRGB-encoded, 0..1 per channel. Clamp first: below −0.055 the curve's unused branch is NaN, and NaN survives the mix.\\n/// → LINEAR, 0..1 per channel.\\nfn srgb_to_linear(c: vec3f) -> vec3f {\\n return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3f(2.4)), step(vec3f(0.04045), c));\\n}\\n\\n/// RGB → HSB (hue, saturation, brightness).\\n/// `c` — RGB, 0..1 per channel (either encoding — the result is in the same one).\\n/// → x the hue in TURNS, [0, 1) (0 red, 1/3 green, 2/3 blue); y the saturation, [0, 1]; z the brightness `max(r, g, b)`, [0, 1].\\nfn rgb2hsb(c: vec3f) -> vec3f {\\n let K = vec4f(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\\n let p = mix(vec4f(c.bg, K.wz), vec4f(c.gb, K.xy), step(c.b, c.g));\\n let q = mix(vec4f(p.xyw, c.r), vec4f(c.r, p.yzx), step(p.x, c.r));\\n let d = q.x - min(q.w, q.y);\\n let e = 1.0e-10;\\n return vec3f(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\\n}\\n\\n/// HSB → RGB, `rgb2hsb`'s inverse.\\n/// `c` — x the hue in turns (any value: only its fraction counts), y the saturation 0..1, z the brightness 0..1.\\n/// → RGB, 0..1 per channel.\\nfn hsb2rgb(c: vec3f) -> vec3f {\\n let K = vec4f(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\\n let p = abs(fract(K.xyz + c.x) * 6.0 - K.w);\\n return c.z * mix(K.xxx, clamp(p - K.x, vec3f(0.0), vec3f(1.0)), c.y);\\n}\\n\\n// ---- the lines. `px` is world units per DEVICE pixel; half-widths are in device px.\\n/// One family of parallel lines — one every `spacing` along an axis, a line at every multiple of it.\\n/// `x` — the coordinate across the lines, world units (the lattice's phase); `spacing` — their pitch, world units, > 0;\\n/// `half_width` — a line's half width, WORLD units (`line_weight`'s device px × `px`); `px` — world units per device px, > 0.\\n/// → [0, 1]: 1 within `half_width − px` of a line, 0 beyond `half_width + px`, a smoothstep between (the AA).\\nfn line_coverage(x: f32, spacing: f32, half_width: f32, px: f32) -> f32 {\\n let d = abs(fract(x / spacing - 0.5) - 0.5) * spacing;\\n return 1.0 - smoothstep(max(half_width - px, 0.0), half_width + px, d);\\n}\\n\\n/// A square grid: `line_coverage` along both axes, the larger.\\n/// `p` — the point, world units (the lattice's phase); `spacing`, `half_width`, `px` — as `line_coverage`'s, world units.\\n/// → [0, 1]: the grid's coverage at `p`.\\nfn grid2(p: vec2f, spacing: f32, half_width: f32, px: f32) -> f32 {\\n return max(line_coverage(p.x, spacing, half_width, px), line_coverage(p.y, spacing, half_width, px));\\n}\\n\\n// One law for every rung (src/lattice/line.ts `lineWeight`): fade in over the\\n// engine's window by the rung's OWN cell, then thicken and darken over the\\n// next decade. x = half-width (device px), y = alpha.\\n/// The lattice's line law for one rung — src/lattice/line.ts `lineWeight`, number for number.\\n/// `u` — the slot's view block (`u.lod`: the fade-in window, CSS px; `u.line`: the half-widths and alphas); `cell_px` — the\\n/// rung's cell on screen, CSS px (its spacing × zoom).\\n/// → x the line's half-width, DEVICE px, from `u.line.x` (at the window's top) to `u.line.y` (a decade above it); y its\\n/// alpha: 0 at or below `u.lod.x`, `u.line.z` at `u.lod.y`, rising to `u.line.w` a decade above.\\nfn line_weight(u: MatUniforms, cell_px: f32) -> vec2f {\\n let s = smoothstep(u.lod.x, u.lod.y, cell_px);\\n let t = saturate(log(max(cell_px, 1e-9) / u.lod.y) / 2.302585093);\\n return vec2f(mix(u.line.x, u.line.y, t), u.line.z * s + (u.line.w - u.line.z) * t);\\n}\\n\\n// The mat's albedo at a point: the reference's `cuttingMatAlbedo` with the\\n// three lattice rungs in place of its own decade, and the line law above in\\n// place of its fade ladder. `world` is lattice-phase world (wrapped); `px` is\\n// world per device pixel; `frag` is the framebuffer pixel; `ruler` the rulers'\\n// print at it (ruler.wgsl) — ink over the lines, and at 0 exactly the mix below\\n// returns the lined mat untouched, bit for bit.\\n/// The cutting mat's albedo at a point: the sage with its grain, the three rungs' cream lines, the rulers' ink over them.\\n/// `u` — the slot's view block; `world` — the point in LATTICE-PHASE world units (`u.phase.xy + css / zoom` — wrapped, not\\n/// the camera's world); `px` — world units per device px, > 0; `frag` — the fragment's device px (the grain's hash runs on\\n/// it); `bn` — the blue-noise texel at the fragment, 0..1 per channel; `ruler` — the rulers' ink coverage there, 0..1\\n/// (`ruler_ink`; 0 = the lined mat bit for bit).\\n/// → LINEAR RGB, 0..1 per channel — the reference's quirk: the chain after it (`mat_colour`) takes it as is.\\nfn mat_albedo(u: MatUniforms, world: vec2f, px: f32, frag: vec2f, bn: vec3f, ruler: f32) -> vec3f {\\n var sage = u.ground.xyz;\\n let amp = u.grain.x;\\n var g = (hash12(frag * vec2f(0.73, 0.91)) - 0.5) * amp;\\n g += (value_noise(frag * 0.45 + vec2f(u.view.z * 0.9, -u.view.z * 0.6)) - 0.5) * amp;\\n g += (bn.x - 0.5) * amp * 0.5;\\n sage += vec3f(g * 0.4, g, g * 0.35);\\n\\n // A rung under the window has alpha 0 and no coverage to compute — the\\n // fine rung at most zooms. The branches are uniform across the frame.\\n let zoom = mat_zoom(u);\\n var cover = 0.0;\\n let wf = line_weight(u, u.rungs.x * zoom);\\n if (wf.y > 0.0) { cover = grid2(world, u.rungs.x, wf.x * px, px) * wf.y; }\\n let wm = line_weight(u, u.rungs.y * zoom);\\n if (wm.y > 0.0) { cover = max(cover, grid2(world, u.rungs.y, wm.x * px, px) * wm.y); }\\n let wc = line_weight(u, u.rungs.z * zoom);\\n if (wc.y > 0.0) { cover = max(cover, grid2(world, u.rungs.z, wc.x * px, px) * wc.y); }\\n return srgb_to_linear(clamp(mix(mix(sage, u.ink.xyz, cover), u.ink.xyz, ruler), vec3f(0.0), vec3f(1.0)));\\n}\\n\\n// ---- the gobo (the reference's sampleBlur · getGoboBlurRatio · sampleGobo)\\n/// A linear ramp.\\n/// `edge0`, `edge1` — where it starts and ends (`edge0` ≠ `edge1`); `x` — the input, in their units.\\n/// → [0, 1]: 0 at or before `edge0`, 1 at or past `edge1`, linear between.\\nfn linearstep(edge0: f32, edge1: f32, x: f32) -> f32 {\\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\\n}\\n\\n// Linearise the WebGL-range NDC z with the projector's near/far, then ramp\\n// between the two depths: sharp near the projector, soft far from it.\\n/// How soft the gobo's shadow is at a depth.\\n/// `ndc_z` — the point's depth in the projector's clip space, WebGL range [−1, 1]; `p` — `u.goboParams`: x the sharp depth\\n/// and y the soft one (linear, metres from the projector), z and w the projector's near and far planes (metres).\\n/// → [0, 1]: 0 (sharp) at or nearer than `p.x`, 1 (soft) at or beyond `p.y`.\\nfn blur_ratio(ndc_z: f32, p: vec4f) -> f32 {\\n return linearstep(p.x, p.y, (2.0 * p.z * p.w) / (p.w + p.z - ndc_z * (p.w - p.z)));\\n}\\n\\n// Six taps on a golden-angle spiral, the start angle from blue noise so the\\n// pattern differs per pixel (and per frame while the offset moves).\\n/// The gobo's silhouette blurred by six taps on a golden-angle spiral.\\n/// `tex` — the silhouette (r8: 1 = open, 0 = leaf); `samp` — a linear sampler; `uv` — the plate point, 0..1 (v runs down the\\n/// plate); `texel` — one plate texel in uv; `blur` — the spiral's reach in texels (≤ 0: one tap, sharp); `n` — a per-pixel\\n/// random 0..1 (blue noise) that turns the spiral.\\n/// → [0, 1]: the silhouette's mean over the taps.\\nfn sample_blur(tex: texture_2d<f32>, samp: sampler, uv: vec2f, texel: vec2f, blur: f32, n: f32) -> f32 {\\n // No blur: six taps at one point are one tap. The sharp end of the desk.\\n if (blur <= 0.0) { return textureSampleLevel(tex, samp, uv, 0.0).r; }\\n let G = 2.39996323;\\n let rot = mat2x2f(cos(G), sin(G), -sin(G), cos(G));\\n let a0 = n * 6.28318530718;\\n var d = vec2f(cos(a0), sin(a0));\\n let s = texel * blur * (1.0 / sqrt(6.0));\\n var c = 0.0;\\n for (var i = 0; i < 6; i++) {\\n c += textureSampleLevel(tex, samp, uv + d * sqrt(f32(i + 1)) * s, 0.0).r;\\n d = rot * d;\\n }\\n return c / 6.0;\\n}\\n\\n// The gobo term at a desk point (metres): 1 = lit. Outside the projector's\\n// frame the plate is not consulted at all — the cone is finite, as the\\n// reference's is.\\n/// The lamp's dapple at a point already in the chosen projection space.\\n/// `u` — the slot's view block (`u.goboMatrix` the projector, `u.gobo` its opacity and blur); `tex` — the slot's animated\\n/// silhouette (`MatPass.silhouette`, r8, 1 = open); `samp` — a linear sampler; `desk` — the point in the projector's frame,\\n/// metres, y up (`desk_of`, `lit_desk`, a kind's own desk point); `n` — blue noise 0..1 (the blur spiral's turn).\\n/// → [0, 1]: 1 = fully lit. Exactly 1 outside the projector's frame and when the gobo is off (`u.gobo.x` ≤ 0); else\\n/// `mix(1, the silhouette blurred by depth, u.gobo.x)`.\\nfn project_gobo(u: MatUniforms, tex: texture_2d<f32>, samp: sampler, desk: vec3f, n: f32) -> f32 {\\n if (u.gobo.x <= 0.0) { return 1.0; }\\n var clip = u.goboMatrix * vec4f(desk, 1.0);\\n let ndc = clip.xyz / clip.w;\\n // The wind target's row 0 is the plate's top row, so v runs downward.\\n let uv = vec2f(0.5 + 0.5 * ndc.x, 0.5 - 0.5 * ndc.y);\\n if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { return 1.0; }\\n let g = sample_blur(tex, samp, uv, vec2f(1.0 / 512.0), blur_ratio(ndc.z, u.goboParams) * u.gobo.y, n);\\n return mix(1.0, g, u.gobo.x);\\n}\\n\\n// A viewport gobo is a light over the visible desk, independent of canvas navigation. All kinds\\n// enter here with their own desk point, so their surfaces pass through the same light as the mat.\\n/// The lamp's dapple at a point of the slot's desk, respecting `u.wind.z` (0 = world, 1 = viewport).\\n/// `u`, `tex`, `samp`, `n` — as `project_gobo`'s; `desk` — metres in the slot's world frame, y up.\\n/// → [0, 1]: the projected light, with camera pan/zoom removed in viewport mode. Height scales with\\n/// the visible object; the shadow's ground footprint stays at its original CSS-pixel position and size.\\nfn sample_gobo(u: MatUniforms, tex: texture_2d<f32>, samp: sampler, desk: vec3f, n: f32) -> f32 {\\n if (u.gobo.x <= 0.0) { return 1.0; }\\n var receiver = desk;\\n if (u.wind.z > 0.0) {\\n let origin = vec3f(u.plane.x, u.plane.w, u.plane.y);\\n let camera = vec3f(u.cam.x, 0.0, u.cam.y) * u.plane.z;\\n receiver = origin + (desk - origin - camera) * mat_zoom(u);\\n }\\n return project_gobo(u, tex, samp, receiver, n);\\n}\\n\\n// World (CSS px at zoom 1, unwrapped) → the desk plane in the projector's frame.\\n/// A world point on the desk, in the projector's frame.\\n/// `u` — the slot's view block (`u.plane`: the origin's x and z, metres per world unit, the desk's height); `world` — the\\n/// point, UNWRAPPED world units (y down).\\n/// → metres, y up: `(plane.x + world.x · m, plane.w, plane.y + world.y · m)`, m = `u.plane.z` — world y runs along the\\n/// desk's z.\\nfn desk_of(u: MatUniforms, world: vec2f) -> vec3f {\\n return vec3f(u.plane.x + world.x * u.plane.z, u.plane.w, u.plane.y + world.y * u.plane.z);\\n}\\n\\n// ---- the LIGHT a slot is lit by (MINIMAT.md §4; src/mat/layout.ts `SlotLight`). The lamp's gobo is\\n// sampled where a light CAMERA sees a point, not where the slot's camera does: the same camera for the\\n// root at rest; the host desk's for a mini mat's inside — the dapple runs across the mini mat as across\\n// anything lying on the desk — and two of them cross-faded (`light.w`) while a flight hands one lamp to\\n// the other. An object's world point `p` raised `h` world units, as light camera `L` (x, y, zoom) sees it:\\n// the point on screen, back into L's world; a height scales as a length does.\\n/// A point of the slot's world, raised, as a LIGHT camera sees it — in the projector's frame.\\n/// `u` — the slot's view block; `L` — the light camera: x, y the world point at its top-left, z its zoom (`u.light` or\\n/// `u.light2`; w unread); `p` — the point, the slot's world units; `h` — its height above the desk, world units, ≥ 0.\\n/// → metres, y up: `p` carried through the screen into `L`'s world, its height scaled as a length is.\\nfn lit_desk(u: MatUniforms, L: vec4f, p: vec2f, h: f32) -> vec3f {\\n let s = max(u.cam.z, 1e-12) / max(L.z, 1e-12);\\n let w = L.xy + (p - u.cam.xy) * s;\\n return vec3f(u.plane.x + w.x * u.plane.z, u.plane.w + h * s * u.plane.z, u.plane.y + w.y * u.plane.z);\\n}\\n\\n// The gobo on an object's world point `p` raised `h`: under the slot's own lamp the desk point itself,\\n// `own` (the object's own `desk_at`, so a root's object reads exactly what it always read); else under\\n// the light camera — then, while a flight hands it over, cross-faded to the second.\\n/// The lamp's dapple on an object's point, under whichever lamp the slot is lit by.\\n/// `u` — the slot's view block; `tex`, `samp` — the silhouette and its sampler, as `sample_gobo`'s; `p` — the object's point,\\n/// the slot's world units; `h` — its height above the desk, world units, ≥ 0; `own` — the same point in the projector's frame\\n/// as the object computes it (metres, y up), read when the slot is lit by its own camera; `n` — blue noise 0..1.\\n/// → [0, 1]: 1 = fully lit (`sample_gobo` at the point the light sees; cross-faded by `u.light.w` toward `u.light2`'s).\\nfn lit_gobo(u: MatUniforms, tex: texture_2d<f32>, samp: sampler, p: vec2f, h: f32, own: vec3f, n: f32) -> f32 {\\n // The CPU selects the light camera, including a fixed (0, 0, 1) for viewport mode.\\n // lit_desk already maps into that projection space; no second camera transform is needed.\\n var g = 0.0;\\n if (all(u.light.xyz == u.cam.xyz)) { g = project_gobo(u, tex, samp, own, n); }\\n else { g = project_gobo(u, tex, samp, lit_desk(u, u.light, p, h), n); }\\n if (u.light.w > 0.0) { g = mix(g, project_gobo(u, tex, samp, lit_desk(u, u.light2, p, h), n), u.light.w); }\\n return g;\\n}\\n\\n// The reference's grade: `shade = mix(1, floor + (1 − floor)·gobo, mix)`, then\\n// HSB: saturation up by (1 − shade)·k, brightness × shade. The reference did\\n// this on pow(albedo, 2.2) and wrote pow(1/2.2) — kept verbatim: that chain is\\n// the mat's colour on screen.\\n/// The DAY's chain — the lamp's dapple graded onto a colour.\\n/// `u` — the slot's view block (`u.gobo.w` the dark floor, `u.gobo.z` the shade's mix, `u.grade.x` the saturation bump);\\n/// `albedo` — the colour as it is written where lit, 0..1 per channel: an object's sRGB colour (the mat hands its own linear\\n/// albedo — the reference's look); `gobo` — the dapple, 0..1 (1 = lit).\\n/// → RGB 0..1 in `albedo`'s encoding: exactly `albedo` where `gobo` ≥ 1; in shade, brightness × shade and saturation up by\\n/// (1 − shade) · `u.grade.x`, where shade = `mix(1, floor + (1 − floor) · gobo, u.gobo.z)` (≈ 0.51 … 1 by the theme's numbers).\\nfn shade_mat(u: MatUniforms, albedo: vec3f, gobo: f32) -> vec3f {\\n // Lit: shade is exactly 1, the saturation bump exactly 0, and the chain is\\n // pow(pow(albedo, 2.2), 1/2.2) — the identity. Every pixel outside the\\n // cone, and every lit one inside it, skips six pows and the HSB round trip.\\n if (gobo >= 1.0) { return albedo; }\\n let shade = mix(1.0, u.gobo.w + (1.0 - u.gobo.w) * gobo, u.gobo.z);\\n var hsb = rgb2hsb(pow(albedo, vec3f(2.2)));\\n hsb.y = min(hsb.y + (1.0 - shade) * u.grade.x, 1.0);\\n hsb.z = hsb.z * shade;\\n return pow(hsb2rgb(hsb), vec3f(1.0 / 2.2));\\n}\\n\\n// ---- the NIGHT (MAT.md; src/mat/night.ts is the same arithmetic on the CPU):\\n// the Moon in place of the Sun, and the eye that sees by it. The day's chain\\n// above is untouched — `mat_colour` returns it, alone, when `night.x` is 0.\\n/// Photopic luminance Y (the sRGB / Rec. 709 weights).\\n/// `c` — LINEAR RGB.\\n/// → Y, in `c`'s scale (0..1 for 0..1 channels; white is 1).\\nfn night_luminance(c: vec3f) -> f32 { return dot(c, vec3f(0.2126729, 0.7151522, 0.0721750)); }\\n\\n// Scotopic luminance V' from XYZ — Larson, Rushmeier & Piatko 1997's regression:\\n// the rods peak at 507 nm, so greens and blues keep their brightness by night and reds die.\\n/// Scotopic luminance V′ — what the rods see (Larson, Rushmeier & Piatko 1997).\\n/// `c` — LINEAR RGB.\\n/// → V′ in `c`'s scale: ≥ 0 over the sRGB gamut, white ≈ 2.57 (`night_mat` normalises by it).\\nfn night_scotopic(c: vec3f) -> f32 {\\n let X = dot(c, vec3f(0.4124564, 0.3575761, 0.1804375));\\n let Y = dot(c, vec3f(0.2126729, 0.7151522, 0.0721750));\\n let Z = dot(c, vec3f(0.0193339, 0.1191920, 0.9503041));\\n return Y * (1.33 * (1.0 + (Y + Z) / max(X, 1e-6)) - 1.68);\\n}\\n\\n// CIE 191:2010's mesopic weight — the cones' share of the seeing at L cd/m²:\\n// 0 at 0.005 (the rods alone), 1 at 5 (the cones alone).\\n/// The cones' share of the seeing at a luminance (CIE 191:2010's mesopic weight).\\n/// `L` — luminance, cd/m², > 0.\\n/// → [0, 1]: 0 at or below 0.005 cd/m² (the rods alone), 1 at or above 5 (the cones alone), linear in log10(L) between.\\nfn night_mesopic(L: f32) -> f32 { return saturate(0.767 + 0.3334 * log(max(L, 1e-9)) * 0.4342944819); }\\n\\n/// The sRGB transfer curve, encoded — `srgb_to_linear`'s inverse.\\n/// `c` — LINEAR RGB, ≥ 0 (0..1 for an on-screen colour).\\n/// → sRGB-encoded RGB (0..1 for 0..1).\\nfn night_encode(c: vec3f) -> vec3f {\\n return mix(c * 12.92, 1.055 * pow(max(c, vec3f(0.0)), vec3f(1.0 / 2.4)) - 0.055, step(vec3f(0.0031308), c));\\n}\\n\\n/// The NIGHT's chain — a reflectance under the Moon, as the dark-adapted eye reports it.\\n/// `u` — the slot's view block (`u.moon`, `u.night`, `u.rod`, `u.eigengrau`: the theme's night, mat/night.ts); `albedo` —\\n/// LINEAR reflectance, 0..1 per channel (unlike `shade_mat`'s: `srgb_to_linear` an sRGB colour first); `gobo` — the dapple,\\n/// 0..1 (1 = lit); `noise` — blue noise 0..1 (the rods' own snow).\\n/// → sRGB-ENCODED RGB, ≈ 0..1 — the Eigengrau's grey under everything, plus the snow (± `u.night.w` / 2).\\nfn night_mat(u: MatUniforms, albedo: vec3f, gobo: f32, noise: f32) -> vec3f {\\n let shade = u.moon.w + (1.0 - u.moon.w) * gobo; // the Moon, and the sky's share where it is blocked\\n let cone = albedo * u.moon.xyz * shade; // the mat under the Moon, as the partly adapted cones take it\\n let rod = max(night_scotopic(cone), 0.0) / night_scotopic(vec3f(1.0)); // the rods' signal, white = 1\\n let L = u.night.y * night_luminance(cone) * 0.3183098862; // cd/m² on the desk: E · ρ / π\\n let see = mix(rod * u.rod.xyz, cone, night_mesopic(L)); // what the eye reports\\n let disp = u.eigengrau.xyz + see * u.night.z; // the dark's own grey under it, at the appearance's scale\\n return night_encode(disp) + (noise - 0.5) * u.night.w; // encoded; then the rods' own noise\\n}\\n\\n// The mat's colour on screen: the day's chain, the night, or a cross-fade of the two.\\n/// The MAT's colour on screen: the day's chain, the night's, or between them by `u.night.x`.\\n/// `u` — the slot's view block; `albedo` — the colour handed to BOTH chains, as the mat's is (`mat_albedo`'s, linear — the\\n/// reference's look); `gobo` — the dapple, 0..1; `noise` — blue noise 0..1.\\n/// → the day's answer (`shade_mat`) while `u.night.x` ≤ 0, the night's (`night_mat`, encoded) from 1, a mix between. A kind\\n/// with an sRGB colour composes its own: the colour into `shade_mat`, `srgb_to_linear` of it into `night_mat` (the book's\\n/// `nb_colour`).\\nfn mat_colour(u: MatUniforms, albedo: vec3f, gobo: f32, noise: f32) -> vec3f {\\n if (u.night.x <= 0.0) { return shade_mat(u, albedo, gobo); }\\n let night = night_mat(u, albedo, gobo, noise);\\n if (u.night.x >= 1.0) { return night; }\\n return mix(shade_mat(u, albedo, gobo), night, u.night.x);\\n}\\n\",\n \"mat/ruler.wgsl\": \"// The RULERS printed on the mat (RULER.md) — a PURE module: no bindings. The\\n// ink coverage at a fragment from the frame's lines, the ticks and the labels,\\n// in screen space; the mat pass mixes it into the albedo before the light, so\\n// the print is lit and shadowed like the lines. Every number is a uniform\\n// `matUniformValues` fills from lattice/ruler.ts — the levels' spacings,\\n// presences and tick lengths per frame; the shader only lays them out.\\n//\\n// Layout: the frame's outer rect one `margin` in from the viewport; the top\\n// and left BANDS one `band` wide inside it, each closed by its inner line\\n// (the ticks' baseline). A tick stands on the baseline at every site of every\\n// level, its length the level's, its presence the level's. A label sits in\\n// the band's outer half after its tick, laid out on the finest labelled\\n// level's sites; the left ruler's labels are the top's rotated a quarter turn\\n// clockwise (reading down the band, their tops toward the field) — James's\\n// mockup. All distances are DEVICE px inside; positions arrive as CSS px.\\n//\\n// THE KIT'S `ruler` PIECE (`kitWgsl([..., \\\"ruler\\\"])`, after `light`, whose `mat_zoom` and `mat_dpr` it reads; petition I31 —\\n// every declaration's `///` block says what it takes and gives). A face that prints the mat's numerals composes it; the ink it\\n// answers is coverage 0..1, mixed into an albedo before the light (the mat's `mat_albedo` takes it as `ruler`).\\n\\n/// The ruler's levels: `u.rulerSites` and `u.rulerFormat` hold one record each (lattice/ruler.ts lays them out).\\nconst RULER_LEVELS = 5;\\n/// Texels between a glyph-atlas cell's left edge and its glyph's origin — mat/layout.ts `GLYPH_PAD`.\\nconst GLYPH_PAD = 2.0;\\n\\n/// A printed line's coverage.\\n/// `d` — the signed distance across the line, DEVICE px; `hw` — its half-width, device px, ≥ 0.\\n/// → [0, 1]: 1 within `hw − 0.5` of the line, 0 beyond `hw + 0.5`, a smoothstep between (a one-device-px AA ramp).\\nfn ruler_line(d: f32, hw: f32) -> f32 { return 1.0 - smoothstep(hw - 0.5, hw + 0.5, abs(d)); }\\n/// Inside [a, b] — the ends of a segment, the extents of a band.\\n/// `x` — the value; `a`, `b` — the closed interval's ends, in `x`'s units (`a` ≤ `b`).\\n/// → 1 when `a` ≤ `x` ≤ `b`, else 0.\\nfn ruler_in(x: f32, a: f32, b: f32) -> f32 { return step(a, x) * step(x, b); }\\n\\n/// The decimal digits a number is written with.\\n/// `a` — the number, ≥ 0.\\n/// → its digit count, ≥ 1 (0 is written with one).\\nfn ruler_digits(a: i32) -> i32 { var n = 1; var v = a; loop { if (v < 10) { break; } v = v / 10; n += 1; } return n; }\\n/// A power of ten, as an integer.\\n/// `p` — the exponent, 0 … 9 (past 9 the i32 overflows).\\n/// → 10^`p`.\\nfn ruler_pow10(p: i32) -> i32 { var r = 1; for (var i = 0; i < p; i++) { r = r * 10; } return r; }\\n/// One digit of a number written to a width.\\n/// `a` — the number, ≥ 0; `i` — the digit's place, 0 = the leftmost; `nd` — the width in digits (leading zeros where `a` is\\n/// shorter), ≥ `ruler_digits(a)`.\\n/// → the digit, 0 … 9.\\nfn ruler_digit_at(a: i32, i: i32, nd: i32) -> i32 { return (a / ruler_pow10(nd - 1 - i)) % 10; }\\n\\n/// A label's text, one character at a time — lattice/ruler.ts `formatLabel`: plain digits, no suffix; a fraction with its\\n/// trailing zeros stripped, so \\\"1.0\\\" is \\\"1\\\" at every level.\\n/// `index` — the site's index along the ruler (any sign); `mult`, `exp` — the level's format: the label is `index · mult ·\\n/// 10^exp`; `k` — the character slot, ≥ 0.\\n/// → the glyph at slot `k`: 0 … 9 a digit, 10 '-', 11 '.' (the atlas's first twelve cells, `GLYPHS`), −1 past the end.\\nfn ruler_label(index: i32, mult: i32, exp: i32, k: i32) -> i32 {\\n let M = index * mult;\\n if (M == 0) { return select(-1, 0, k == 0); }\\n let neg = M < 0;\\n let a = abs(M);\\n var i = k;\\n if (neg) { if (i == 0) { return 10; } i -= 1; }\\n if (exp >= 0) {\\n let nd = ruler_digits(a);\\n if (i < nd) { return ruler_digit_at(a, i, nd); }\\n if (i < nd + exp) { return 0; }\\n return -1;\\n }\\n let p = -exp;\\n let nd = max(ruler_digits(a), p + 1);\\n let intDigits = nd - p;\\n var fracLen = p;\\n loop { if (fracLen == 0) { break; } if ((a / ruler_pow10(p - fracLen)) % 10 != 0) { break; } fracLen -= 1; }\\n if (i < intDigits) { return ruler_digit_at(a, i, nd); }\\n if (i == intDigits) { return select(-1, 11, fracLen > 0); }\\n let j = i - intDigits - 1;\\n if (j < fracLen) { return ruler_digit_at(a, intDigits + j, nd); }\\n return -1;\\n}\\n/// A label's length.\\n/// `index`, `mult`, `exp` — as `ruler_label`'s.\\n/// → the number of characters `ruler_label` answers before −1, 0 … 16.\\nfn ruler_label_len(index: i32, mult: i32, exp: i32) -> i32 {\\n var n = 0;\\n loop { if (n >= 16) { break; } if (ruler_label(index, mult, exp, n) < 0) { break; } n += 1; }\\n return n;\\n}\\n\\n/// What one band prints at a fragment: `ink` — the ticks' coverage, 0..1 (times their alpha); `glyph` — where the fragment lies\\n/// in a label, the atlas point to sample (x, y — texels) and the label's presence (z, 0..1); z = 0 where no label is.\\nstruct RulerHit { ink: f32, glyph: vec3f }\\n\\n/// The ticks and the label along ONE band, at one fragment.\\n/// `u` — the slot's view block (the `ruler*` records); `along` — the fragment's CSS px along the band (x for the top band, y for\\n/// the left); `across` — its DEVICE px in from the band's outer line; `phase` — the lattice's wrapped camera coordinate along\\n/// the band (`u.phase.x` or `.y`, world units); `wraps` — that coordinate's wrap count (`u.rulerOrigin.x` or `.y`); `lim` —\\n/// the band's extent along, CSS px (the inner corner, the far frame line); `turned` — the left band (its glyphs turned a\\n/// quarter clockwise).\\n/// → a `RulerHit`: nothing (ink 0, glyph.z 0) outside the band's own pixels.\\nfn ruler_band(u: MatUniforms, along: f32, across: f32, phase: f32, wraps: f32, lim: vec2f, turned: bool) -> RulerHit {\\n var hit: RulerHit;\\n hit.ink = 0.0; hit.glyph = vec3f(0.0);\\n let dpr = mat_dpr(u); let zoom = mat_zoom(u);\\n let band_dev = u.ruler.z * dpr;\\n let hw = 0.5 * u.ruler.w * dpr;\\n // only the band's own pixels pay for the levels and the text — the rest of the mat returns here\\n if (across < -1.0 || across > band_dev + 1.0 || ruler_in(along, lim.x, lim.y) <= 0.0) { return hit; }\\n let w = phase + along / zoom; // lattice-phase world along the band\\n // the ticks: on the baseline (the band's inner edge), up the level's length; the coarsest level owning a site wins the max\\n var tick = 0.0;\\n for (var i = 0; i < RULER_LEVELS; i++) {\\n let s = u.rulerSites[i].x;\\n let len = u.rulerSites[i].y * dpr;\\n let a = u.rulerSites[i].z;\\n if (a <= 0.0 || len <= 0.0) { continue; }\\n let d = (abs(fract(w / s - 0.5) - 0.5) * s) * zoom * dpr;\\n tick = max(tick, ruler_line(d, hw) * ruler_in(across, band_dev - len - 0.5, band_dev + 0.5) * a);\\n }\\n hit.ink = tick * u.rulerAlpha.y;\\n // the label: laid out on the finest labelled level's sites, the site at or before the fragment\\n let lf = i32(u.rulerOrigin.z);\\n if (lf < 0 || u.rulerAtlas.w <= 0.0) { return hit; }\\n let s = u.rulerSites[lf].x;\\n let nLocal = floor(w / s);\\n let site = (nLocal * s - phase) * zoom; // CSS px along\\n if (site < lim.x) { return hit; } // a site inside the corner square prints nothing\\n let index = i32(wraps) * i32(u.rulerFormat[lf].z) + i32(nLocal);\\n // the site's presence: the coarsest level it lies on\\n var presence = u.rulerSites[lf].w;\\n for (var j = RULER_LEVELS - 1; j > lf; j--) {\\n let ratio = i32(u.rulerFormat[lf].z) / i32(u.rulerFormat[j].z);\\n if (index % ratio == 0) { presence = u.rulerSites[j].w; break; }\\n }\\n if (presence <= 0.0) { return hit; }\\n let mult = i32(u.rulerFormat[lf].x); let exp = i32(u.rulerFormat[lf].y);\\n let texel = u.rulerText.w / dpr; // atlas texels per device px\\n let adv = u.rulerGlyph.z / texel; // a glyph's advance, device px\\n let origin = floor((site + u.rulerText.y) * dpr + 0.5); // the text's start, on a whole device px\\n let t = along * dpr - origin;\\n if (t < 0.0) { return hit; }\\n let slot = i32(floor(t / adv));\\n let g = ruler_label(index, mult, exp, slot);\\n if (g < 0) { return hit; }\\n // the glyph cell. The top band: the cap's top `top` in from the outer line, the glyph read down the band. The left band: the\\n // glyph turned a quarter CLOCKWISE — read down the band still, but its baseline `top` in from the outer line and its top toward\\n // the field (the mockup's \\\"1\\\" above \\\"0\\\", the foot of the \\\"1\\\" at the outer side). Reading along +y with the cell's rows along −x\\n // keeps the hand: a rotation, not the mirror a transpose would be.\\n var v = 0.0;\\n if (turned) { v = u.rulerGlyph.w - (across - u.rulerText.x * dpr) * texel; }\\n else { v = (across - (u.rulerText.x * dpr - (u.rulerGlyph.w - u.rulerAtlas.z) / texel)) * texel; }\\n if (v < 0.0 || v >= u.rulerGlyph.y) { return hit; }\\n let uu = f32(g) * u.rulerGlyph.x + GLYPH_PAD + (t - f32(slot) * adv) * texel;\\n hit.glyph = vec3f(uu, v, presence);\\n return hit;\\n}\\n\\n// The whole print: the frame's lines, the two bands' ticks, the labels'\\n// texels sampled from the atlas. Returns ink coverage 0..1 at this fragment.\\n/// The rulers' whole print at a fragment: the frame's lines, both bands' ticks, the labels' texels.\\n/// `u` — the slot's view block (`u.ruler.x` on/off, the `ruler*` records, the view's size `u.view.xy`); `screen` — the\\n/// fragment's CSS px; `frag` — its device px (`@builtin(position).xy`); `glyph_tex` — the glyph atlas (r8; `MatPass\\n/// .glyphTexture`); `samp` — a sampler for it.\\n/// → ink coverage, 0..1 — exactly 0 when the rulers are off (`u.ruler.x` ≤ 0).\\nfn ruler_ink(u: MatUniforms, screen: vec2f, frag: vec2f, glyph_tex: texture_2d<f32>, samp: sampler) -> f32 {\\n if (u.ruler.x <= 0.0) { return 0.0; }\\n let dpr = mat_dpr(u);\\n let margin = u.ruler.y; let band = u.ruler.z;\\n let W = u.view.x; let H = u.view.y;\\n let hw = 0.5 * u.ruler.w * dpr;\\n let m = margin * dpr; let inner = (margin + band) * dpr;\\n let right = (W - margin) * dpr; let bottom = (H - margin) * dpr;\\n // the frame: the outer rect, and the two baselines closing the bands\\n var frame = 0.0;\\n frame = max(frame, ruler_line(frag.x - m, hw) * ruler_in(frag.y, m - hw, bottom + hw));\\n frame = max(frame, ruler_line(frag.x - right, hw) * ruler_in(frag.y, m - hw, bottom + hw));\\n frame = max(frame, ruler_line(frag.y - m, hw) * ruler_in(frag.x, m - hw, right + hw));\\n frame = max(frame, ruler_line(frag.y - bottom, hw) * ruler_in(frag.x, m - hw, right + hw));\\n frame = max(frame, ruler_line(frag.x - inner, hw) * ruler_in(frag.y, m, bottom));\\n frame = max(frame, ruler_line(frag.y - inner, hw) * ruler_in(frag.x, m, right));\\n var ink = frame * u.rulerAlpha.x;\\n // the top band (across = down from the outer line) and the left band (across = right from it); a pixel in neither pays nothing more.\\n // The labels: the top band's cell read along x, the left band's along y and turned — the same atlas texels either way.\\n if (ruler_in(frag.y, m - 1.0, inner + 1.0) * ruler_in(frag.x, inner - 1.0, right + 1.0) > 0.0) {\\n let top = ruler_band(u, screen.x, frag.y - m, u.phase.x, u.rulerOrigin.x, vec2f(margin + band, W - margin), false);\\n ink = max(ink, top.ink);\\n if (top.glyph.z > 0.0) { ink = max(ink, textureSampleLevel(glyph_tex, samp, top.glyph.xy / u.rulerAtlas.xy, 0.0).r * top.glyph.z * u.rulerAlpha.z); }\\n }\\n if (ruler_in(frag.x, m - 1.0, inner + 1.0) * ruler_in(frag.y, inner - 1.0, bottom + 1.0) > 0.0) {\\n let left = ruler_band(u, screen.y, frag.x - m, u.phase.y, u.rulerOrigin.y, vec2f(margin + band, H - margin), true);\\n ink = max(ink, left.ink);\\n if (left.glyph.z > 0.0) { ink = max(ink, textureSampleLevel(glyph_tex, samp, left.glyph.xy / u.rulerAtlas.xy, 0.0).r * left.glyph.z * u.rulerAlpha.z); }\\n }\\n return ink;\\n}\\n\",\n \"mat/wind.wgsl\": \"// The wind pass — the reference's `goboWind`: one fragment per plate texel,\\n// R silhouette + three sines whose amplitudes and phase the plate's other\\n// channels carry, written to an r8 target the mat pass samples. Runs only when\\n// the gobo time moved; the target is 512² like the plate.\\n\\n@group(0) @binding(0) var<uniform> u: MatUniforms;\\n@group(0) @binding(1) var plate: texture_2d<f32>;\\n\\nstruct VSOut { @builtin(position) clip: vec4f }\\n\\n@vertex\\nfn vs(@builtin(vertex_index) vid: u32) -> VSOut {\\n var p = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));\\n var out: VSOut;\\n out.clip = vec4f(p[vid], 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fs(in: VSOut) -> @location(0) vec4f {\\n let params = textureLoad(plate, vec2i(in.clip.xy), 0);\\n let time = u.wind.x;\\n let strength = u.wind.y;\\n let s = params.r;\\n let amp1 = params.g * strength;\\n let phase1 = (params.b - 0.5) * 6.283185;\\n let amp23 = params.a * strength;\\n let waves = sin(time * vec3f(1.0, 2.0, 3.0) + phase1 * vec3f(1.0, 2.0, 0.5));\\n let motion = (amp1 * waves.x) + (amp23 * 0.5 * waves.y) + (amp23 * 0.3 * waves.z);\\n let v = clamp(s + motion, 0.0, 1.0);\\n return vec4f(v, 0.0, 0.0, 1.0);\\n}\\n\",\n \"missing/missing-pass.wgsl\": \"// THE MISSING FACE (petition I24; desk src/missing/) — what the desk draws where NOTHING can draw an object: its kind refused at\\n// create or quarantined at three strikes (src/faults.ts), or its type without a kind on this desk. A faint card the size of the\\n// object's box, square to the mat: a wash of the ink, the ink's hatching at 45° (a pitch and a weight in CSS px, anchored to the\\n// box's corner, so it reads at every zoom and moves with the object) and a hairline edge inside the box — no text: the kind's name\\n// is said in the notice, never on the desk. Premultiplied, through the slot's objects' presence (`u.view.w`) and its portal chain,\\n// as every kind's face. The record (`MissingFace`, src/missing/layout.ts): `rect` — the centre and half extents, world units;\\n// `ink` — the colour, and the object's fade in w; `mix` — the wash's, the hatching's and the edge's alpha; `shape` — the corner\\n// (world units), the hatching's pitch and weight and the edge's weight (CSS px).\\n\\n@group(0) @binding(0) var<uniform> u: MatUniforms;\\n@group(0) @binding(1) var<storage, read> faces: array<MissingFace>;\\n@group(0) @binding(2) var<storage, read> order: array<u32>; // the draw list: paint index → the record's slot\\n\\nstruct VSOut {\\n @builtin(position) clip: vec4f,\\n @location(0) @interpolate(flat) idx: u32,\\n}\\n\\nconst CORNERS = array<vec2f, 6>(\\n vec2f(-1.0, -1.0), vec2f(1.0, -1.0), vec2f(1.0, 1.0),\\n vec2f(-1.0, -1.0), vec2f(1.0, 1.0), vec2f(-1.0, 1.0),\\n);\\n\\n@vertex\\nfn vs(@builtin(vertex_index) vid: u32, @builtin(instance_index) iid: u32) -> VSOut {\\n var out: VSOut;\\n out.clip = vec4f(2.0, 2.0, 2.0, 1.0); // degenerate: a culled face (or a gone one, fade 0) collapses\\n let slot = order[iid];\\n out.idx = slot;\\n let F = faces[slot];\\n if (F.ink.w <= 0.0) { return out; }\\n let zoom = max(u.cam.z, 1e-12);\\n let dpr = max(u.cam.w, 1e-6); // the attachment's own ratio, below 1 too (mat.wgsl `mat_dpr`, petition I29)\\n let pad = 2.0 / (zoom * dpr); // two device px of the edge's ramp\\n let lo = (F.rect.xy - F.rect.zw - vec2f(pad) - u.cam.xy) * zoom; // CSS px\\n let hi = (F.rect.xy + F.rect.zw + vec2f(pad) - u.cam.xy) * zoom;\\n if (hi.x < u.box.x || hi.y < u.box.y || lo.x > u.box.x + u.box.z || lo.y > u.box.y + u.box.w) { return out; }\\n let pos = mix(lo, hi, CORNERS[vid] * 0.5 + 0.5);\\n out.clip = vec4f(pos.x / u.view.x * 2.0 - 1.0, 1.0 - pos.y / u.view.y * 2.0, 0.0, 1.0);\\n return out;\\n}\\n\\n@fragment\\nfn fs(in: VSOut) -> @location(0) vec4f {\\n let F = faces[in.idx];\\n let zoom = max(u.cam.z, 1e-12);\\n let dpr = max(u.cam.w, 1e-6);\\n let px = 1.0 / (zoom * dpr); // one device px, world units\\n let p = in.clip.xy * px + u.cam.xy; // device px → world\\n let r = min(F.shape.x, min(F.rect.z, F.rect.w));\\n let d = sdf_round_box(p - F.rect.xy, F.rect.zw, r) / px; // device px; < 0 inside the box\\n let inside = clamp(0.5 - d, 0.0, 1.0);\\n if (inside <= 0.0) { discard; }\\n // the hatching: lines at 45°, `pitch` CSS px apart and `weight` wide, from the box's top-left corner\\n let corner = (F.rect.xy - F.rect.zw - u.cam.xy) * zoom * dpr; // device px\\n let s = in.clip.xy - corner;\\n let pitch = F.shape.y * dpr;\\n let t = (s.x + s.y) * 0.70710678;\\n let k = abs(fract(t / pitch + 0.5) - 0.5) * pitch; // device px to the nearest line\\n let hatch = clamp(0.5 * F.shape.z * dpr - k + 0.5, 0.0, 1.0);\\n // the edge: a hairline just inside the box\\n let ew = F.shape.w * dpr;\\n let edge = clamp(0.5 * ew - abs(d + 0.5 * ew) + 0.5, 0.0, 1.0);\\n var a = F.mix.x;\\n a = a + (1.0 - a) * F.mix.y * hatch;\\n a = a + (1.0 - a) * F.mix.z * edge;\\n let cov = a * inside * F.ink.w;\\n return vec4f(F.ink.xyz * cov, cov) * (u.view.w * portal_cover(in.clip.xy / dpr, u.portals, u.clips, dpr));\\n}\\n\",\n \"portal.wgsl\": \"// The portal clip — a slot's ground and frames are visible only through a\\n// rounded rect on screen (CSS px): its FACE and, for a nested slot, every face\\n// above it — the CHAIN (src/nav/portal.ts `Presentation`, `within`). A PURE\\n// module every pass includes: the records arrive as parameters. `clips[i].y`\\n// < 0.5 ends the chain (an empty chain is no clip at all, and the loop is one\\n// compare); `clips[i].x` is a face's corner radius; `clips[i].z` its top\\n// FEATHER (CSS px; 0 = a hard edge — design-018 §4, the tray's face: what it\\n// shows fades in over that band below its top edge, with no code of its own).\\n//\\n// THE KIT'S `portal` PIECE (`kitWgsl([..., \\\"portal\\\"])`; petition I31). Its points are CSS px of the ATTACHMENT — origin the\\n// top-left, y down: a fragment's `@builtin(position).xy` (device px) over `mat_dpr(u)` — and the chain is the slot's view\\n// block's (`u.portals`, `u.clips`). A kind multiplies what it writes by `portal_cover` (premultiplied: rgb and alpha; straight\\n// alpha: alpha), so it shows only through its slot's faces; at the root the chain is empty and the cover is exactly 1.\\n\\n/// The portal chain's length: the faces `u.portals` and `u.clips` hold, nearest first (6 — a host's depth belt of four and a\\n/// flight's face). = nav/portal.ts `PORTAL_CHAIN`, the uniform arrays' length; a mismatch fails to compile.\\nconst PORTAL_CHAIN = 6u;\\n\\n/// A face's outline: a rounded rect centred on the origin.\\n/// `p` — the point relative to the face's centre, CSS px; `half` — the face's half extents, CSS px, ≥ 0; `r` — its corner\\n/// radius, CSS px, ≥ 0 (clamped to the shorter half extent).\\n/// → the signed distance to the outline, CSS px: negative inside, 0 on the edge, positive outside.\\nfn portal_sd(p: vec2f, half: vec2f, r: f32) -> f32 {\\n let rr = min(r, min(half.x, half.y));\\n let q = abs(p) - half + vec2f(rr, rr);\\n return length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - rr;\\n}\\n\\n/// The cover through ONE face.\\n/// `p_css` — the fragment's point, CSS px of the attachment; `portal` — the face: its centre (xy) and half extents (zw), CSS px;\\n/// `clip` — its corner radius (x, CSS px), on (y — read by the chain's loop, not here), top feather (z, CSS px; ≤ 0 = a hard\\n/// edge), w unused; `dpr` — the attachment's device px per CSS px, > 0 (below 1 too — petition I29); `grow` — device px the\\n/// face is grown by, ≥ 0 (0 = the face as it is).\\n/// → [0, 1]: 1 inside, 0 outside, a linear ramp one DEVICE px wide centred on the grown edge; times, with a feather, a\\n/// smoothstep from 0 at the face's top edge to 1 `clip.z` CSS px below it.\\nfn portal_cover_one(p_css: vec2f, portal: vec4f, clip: vec4f, dpr: f32, grow: f32) -> f32 {\\n let px = 1.0 / max(dpr, 1e-6); // CSS px a device px — the attachment's own ratio, below 1 too (petition I29)\\n let d = portal_sd(p_css - portal.xy, portal.zw, clip.x) - grow * px;\\n let c = clamp(0.5 - d / px, 0.0, 1.0);\\n if (clip.z <= 0.0) { return c; }\\n let top = portal.y - portal.w;\\n return c * smoothstep(top, top + clip.z, p_css.y);\\n}\\n\\n/// The cover through the whole chain, its first face grown.\\n/// `p_css` — the fragment's point, CSS px of the attachment; `portals`, `clips` — the chain (`u.portals`, `u.clips`): face `i`\\n/// as `portal_cover_one` reads it, nearest first, the first `clips[i].y` < 0.5 ending it; `dpr` — device px per CSS px, > 0;\\n/// `grow` — device px the FIRST face (the slot's own) is grown by, ≥ 0 — every face above it is taken as it is (the fill's one\\n/// px, so the hole's edge partitions with the plate — PORTAL.md §10).\\n/// → [0, 1]: the product of the faces' covers — a nested slot shows only where every face agrees; exactly 1 for an empty chain.\\nfn portal_cover_grown(p_css: vec2f, portals: array<vec4f, PORTAL_CHAIN>, clips: array<vec4f, PORTAL_CHAIN>, dpr: f32, grow: f32) -> f32 {\\n var c = 1.0;\\n for (var i = 0u; i < PORTAL_CHAIN; i++) {\\n if (clips[i].y < 0.5) { break; }\\n c *= portal_cover_one(p_css, portals[i], clips[i], dpr, select(0.0, grow, i == 0u));\\n }\\n return c;\\n}\\n\\n/// The cover a kind multiplies its output by: the slot's chain, no face grown.\\n/// `p_css` — the fragment's point, CSS px of the attachment (`@builtin(position).xy / mat_dpr(u)`); `portals`, `clips` — the\\n/// slot's chain, `u.portals` and `u.clips`; `dpr` — the attachment's device px per CSS px, `mat_dpr(u)`.\\n/// → [0, 1]: 1 where the slot is wholly visible (everywhere, at the root), 0 outside its faces, a one-device-px ramp on each\\n/// edge and a face's top feather where it has one.\\nfn portal_cover(p_css: vec2f, portals: array<vec4f, PORTAL_CHAIN>, clips: array<vec4f, PORTAL_CHAIN>, dpr: f32) -> f32 {\\n return portal_cover_grown(p_css, portals, clips, dpr, 0.0);\\n}\\n\",\n \"primitives.wgsl\": \"// 2D primitives for the desk's objects — the note, the whiteboard, the photo,\\n// the mini mat. Pure functions, exact Euclidean distances — which is what\\n// everything downstream (1-px AA, the analytic shadows, the hit-test mirrors,\\n// src/sdf.ts) relies on. Prefixed `sdf_` so this module can share a program\\n// with the mat's module without a name clash. Moved out of shaders/card/ when\\n// the card frame retired (2026-09-25).\\n// (Lineage: research/sdf-card/src/sdf/primitives.wgsl.)\\n//\\n// THE KIT'S `sdf` PIECE (`kitWgsl([..., \\\"sdf\\\"])`; petition I31 — every declaration's `///` block says what it takes and gives).\\n// A distance here is SIGNED — negative inside, 0 on the edge, positive outside — and in the units its point is given in: a kind\\n// hands world units (one world unit is one CSS px at zoom 1), so a one-device-px AA band is `1 / (mat_zoom(u) · mat_dpr(u))`\\n// world units wide. A shape is centred on its frame's origin unless it takes its own points; y runs down, as everywhere on\\n// the desk, and no shape here cares (each is symmetric under the flip).\\n\\n/// An axis-aligned box centred on the origin.\\n/// `p` — the point, in the box's own units (world units for a kind); `b` — the half extents, ≥ 0, in the same units.\\n/// → the exact Euclidean signed distance in those units: negative inside (−min(b.x, b.y) at the centre), 0 on the edge,\\n/// positive outside.\\nfn sdf_box(p: vec2f, b: vec2f) -> f32 {\\n let q = abs(p) - b;\\n return length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0);\\n}\\n\\n/// A box centred on the origin with its four corners rounded — the card's outline; src/sdf.ts `sdRoundBox` is its CPU mirror,\\n/// number for number.\\n/// `p` — the point, in the box's units; `b` — the half extents, ≥ 0; `r` — the corner radius, clamped to [0, min(b.x, b.y)]\\n/// (an oversized radius makes a stadium, never a dent).\\n/// → the exact Euclidean signed distance, in `p`'s units: negative inside, 0 on the rounded edge, positive outside.\\nfn sdf_round_box(p: vec2f, b: vec2f, r: f32) -> f32 {\\n let rr = clamp(r, 0.0, min(b.x, b.y));\\n let q = abs(p) - b + rr;\\n return length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - rr;\\n}\\n\\n/// A circle centred on the origin.\\n/// `p` — the point; `r` — the radius, ≥ 0, in `p`'s units.\\n/// → `length(p) − r`: exact, negative inside (−r at the centre), positive outside.\\nfn sdf_circle(p: vec2f, r: f32) -> f32 { return length(p) - r; }\\n\\n/// The segment from `a` to `b` — a line of zero width (subtract a half-width for a stroke with round caps).\\n/// `p` — the point; `a`, `b` — the segment's ends, in `p`'s units; `a` ≠ `b` (a zero-length segment divides by zero).\\n/// → the exact UNSIGNED distance to the nearest point of the segment, ≥ 0, in `p`'s units.\\nfn sdf_segment(p: vec2f, a: vec2f, b: vec2f) -> f32 {\\n let pa = p - a;\\n let ba = b - a;\\n let h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\\n return length(pa - ba * h);\\n}\\n\\n/// An X centred on the origin (Quilez's rounded X): two bars along the diagonals, crossing at the origin.\\n/// `p` — the point; `w` — the X's span: each arm runs from the origin to (±w/2, ±w/2), ≥ 0; `r` — the bars' half thickness,\\n/// ≥ 0, their ends round. All in `p`'s units.\\n/// → the exact signed distance: negative inside the bars, positive outside.\\nfn sdf_rounded_x(p: vec2f, w: f32, r: f32) -> f32 {\\n let q = abs(p);\\n return length(q - min(q.x + q.y, w) * 0.5) - r;\\n}\\n\\n// Exact circular fillet CSG (Quilez). Unlike smin/smax these put a TRUE circle\\n// of radius r on the seam. Exact when the operands are perpendicular\\n// half-planes (the retired card frame's corner was built to satisfy it).\\n//\\n// The union form clamps its operands to >= -r so the fillet stays local: the\\n// unclamped hg_sdf form keeps growing once both surfaces are more than r\\n// inside, and the field goes badly wrong in the interior.\\n\\n/// The UNION of two shapes with a circular fillet of radius `r` on their seam.\\n/// `a`, `b` — the two shapes' signed distances at one point, in one unit; `r` — the fillet's radius, ≥ 0, in that unit\\n/// (0 = the plain `min(a, b)`).\\n/// → the union's signed distance: exact where the operands are perpendicular half-planes, a bound elsewhere; the fillet stays\\n/// local to the seam (each operand is clamped at −r), and away from it the answer is `min(a, b)`.\\nfn op_union_round(a: f32, b: f32, r: f32) -> f32 {\\n let m = min(a, b);\\n let A = max(a, -r);\\n let B = max(b, -r);\\n let u = max(vec2f(r - A, r - B), vec2f(0.0));\\n return min(m, max(r, min(A, B)) - length(u));\\n}\\n\\n/// The INTERSECTION of two shapes with a circular round of radius `r` on their crease.\\n/// `a`, `b` — the two shapes' signed distances at one point, in one unit; `r` — the round's radius, ≥ 0, in that unit\\n/// (0 = the plain `max(a, b)`).\\n/// → the intersection's signed distance: exact where the operands are perpendicular half-planes, a bound elsewhere.\\nfn op_isect_round(a: f32, b: f32, r: f32) -> f32 {\\n let u = max(vec2f(r + a, r + b), vec2f(0.0));\\n return min(-r, max(a, b)) + length(u);\\n}\\n\",\n \"tray/tray-pass.wgsl\": \"// The pegboard drawer and its edge veil share one layout. The board is drawn under the specimens; the veil is drawn over them.\\n\\n@group(0) @binding(0) var<uniform> u: MatUniforms;\\n@group(0) @binding(1) var<uniform> t: TrayUniforms;\\n@group(0) @binding(2) var noise_tex: texture_2d<f32>;\\n@group(0) @binding(3) var noise_samp: sampler;\\n@group(0) @binding(4) var hash_tex: texture_2d<f32>;\\n\\n@vertex\\nfn vs(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {\\n var corners = array<vec2f, 6>(vec2f(0.0, 0.0), vec2f(1.0, 0.0), vec2f(0.0, 1.0), vec2f(0.0, 1.0), vec2f(1.0, 0.0), vec2f(1.0, 1.0));\\n let k = corners[vi % 6u];\\n let vw = t.view.x;\\n let vh = t.view.y;\\n var lo = vec2f(0.0, 0.0);\\n var hi = vec2f(vw, vh);\\n // Dimming covers the view; otherwise cover only the drawer and its shadows.\\n if (t.dim <= 0.0) {\\n let reach = 3.0 * max(t.shadow.x, t.room.x) + length(t.shadow.zw);\\n lo = vec2f(max(t.rect.x - reach, 0.0), max(t.rect.y - reach, 0.0));\\n hi = vec2f(min(t.rect.x + t.rect.z + reach, vw), vh);\\n }\\n let css = mix(lo, hi, k);\\n return vec4f(css.x / vw * 2.0 - 1.0, 1.0 - css.y / vh * 2.0, 0.0, 1.0);\\n}\\n\\n@fragment\\nfn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\\n return tray_drawer(u, t, pos.xy, noise_tex, noise_samp, hash_tex);\\n}\\n\\n// THE VEIL (design-018 rev 5): one quad over the drawer's top — from its edge down through the header and its ramp — laid LAST, over\\n// everything the drawer holds (tray.wgsl `tray_veil`: the plain board, whole in the header, fading out over the ramp). With a host's\\n// FOOT inset (petition I21, `fade.z`) a second quad in the same draw, vertices 6–11: from the foot's ramp down to the board's bottom\\n// edge (never above the first's foot), the plain board whole in the foot and fading out over the ramp above its line.\\n@vertex\\nfn vs_veil(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {\\n var corners = array<vec2f, 6>(vec2f(0.0, 0.0), vec2f(1.0, 0.0), vec2f(0.0, 1.0), vec2f(0.0, 1.0), vec2f(1.0, 0.0), vec2f(1.0, 1.0));\\n let k = corners[vi % 6u];\\n let vw = t.view.x;\\n let vh = t.view.y;\\n let head = t.rect.y + t.shape.y + t.fade.y + t.fade.x + 1.0;\\n var lo = clamp(vec2f(t.rect.x, t.rect.y), vec2f(0.0), vec2f(vw, vh));\\n var hi = clamp(vec2f(t.rect.x + t.rect.z, head), vec2f(0.0), vec2f(vw, vh));\\n if (vi >= 6u) {\\n lo = clamp(vec2f(t.rect.x, max(t.rect.y + t.rect.w - t.fade.z - t.fade.w - 1.0, head)), vec2f(0.0), vec2f(vw, vh));\\n hi = clamp(vec2f(t.rect.x + t.rect.z, t.rect.y + t.rect.w), vec2f(0.0), vec2f(vw, vh));\\n }\\n let css = mix(lo, hi, k);\\n return vec4f(css.x / vw * 2.0 - 1.0, 1.0 - css.y / vh * 2.0, 0.0, 1.0);\\n}\\n\\n@fragment\\nfn fs_veil(@builtin(position) pos: vec4f) -> @location(0) vec4f {\\n return tray_veil(u, t, pos.xy, noise_tex, noise_samp, hash_tex);\\n}\\n\",\n \"tray/tray.wgsl\": \"// THE PEGBOARD TRAY (design-017 §5–§6; design-018 §2–§4) — the drawer, and the research board in it (research/sdf-pegboard, shader.js)\\n// lying on the mat, shaded in CLOSED FORM for a head-on view: no march, no history, no jitter — every frame is final, so a scrolling\\n// drawer is clean on every frame. Its edge is an arris in the face's material; its holes show the desk as drawn under it, black at the\\n// board's shadow; under its top edge a clear HEADER (design-018 R4) where nothing hangs and no hole opens, then what hangs on it fades in\\n// through the face's portal feather (every kind's `portal_cover`) and here, the holes. A PURE module: the uniform blocks arrive as parameters — `u` the mat's struct carrying the DESK's light (the colour law\\n// is mat.wgsl's own), `t` the tray's (src/tray/pass.ts) — and so does the blue noise.\\n//\\n// Board units are PITCHES (the research's 1). A board point is x from the drawer's left edge and Y down the board, Y split into a\\n// whole row R (i32: the scroll's whole rows carried on the CPU plus the rows on screen) and fy ∈ [0,1): nothing large ever enters\\n// an f32, so the pattern is exact at any scroll (src/tray/lattice.ts is this arithmetic on the CPU, rounding half up as here).\\n\\n// ---- hashing: the research's pcg, on integer lattice points only (wrapping u32)\\nfn peg_pcg(v: u32) -> u32 {\\n let s = v * 747796405u + 2891336453u;\\n let w = ((s >> ((s >> 28u) + 4u)) ^ s) * 277803737u;\\n return (w >> 22u) ^ w;\\n}\\n\\n// Four independent uniforms for a lattice cell (the research's hash2i4).\\nfn peg_hash4(x: u32, y: u32, seed: u32) -> vec4f {\\n let h0 = peg_pcg(x ^ peg_pcg(y + seed));\\n let h1 = peg_pcg(h0);\\n let h2 = peg_pcg(h1);\\n let h3 = peg_pcg(h2);\\n return vec4f(f32(h0), f32(h1), f32(h2), f32(h3)) * 2.3283064365386963e-10;\\n}\\n\\n// ---- the board point\\nstruct PegPoint { x: f32, R: i32, fy: f32 }\\n\\n// The same point moved by `d` pitches — the move's rows re-carried into R, so R stays exact.\\nfn peg_move(p: PegPoint, d: vec2f) -> PegPoint {\\n let y = p.fy + d.y;\\n let fl = floor(y);\\n return PegPoint(p.x + d.x, p.R + i32(fl), y - fl);\\n}\\n\\n// ---- value noise on the board (the research's noise2, its quintic fade): the value and its gradient in lattice units. The corners'\\n// hashes come PRE-GATHERED (src/tray/pass.ts `hashTexels`: texel (i, j) holds the research's pcg hash of lattice points (i, j),\\n// (i+1, j), (i, j+1), (i+1, j+1), 8 bits each, tiled every 256 cells) — one load where the pcg took eight rounds. Each band reads\\n// it at its own offset (its seed); the lattice point is an integer, so the noise stays exact at any row.\\nfn peg_vnoise(ht: texture_2d<f32>, x: u32, y: u32, f: vec2f, seed: u32) -> vec3f {\\n let u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\\n let du = 30.0 * f * f * (f * (f - 2.0) + 1.0);\\n let k = textureLoad(ht, vec2u((x + seed) & 255u, (y + ((seed * 2654435761u) >> 24u)) & 255u), 0);\\n let a = k.r;\\n let b = k.g;\\n let c = k.b;\\n let d = k.a;\\n let v = mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\\n return vec3f(v, du.x * mix(b - a, d - c, u.y), du.y * mix(c - a, d - b, u.x));\\n}\\n\\n// One band at (fx, fy) cells per pitch (integers): its lattice row is R·fy plus the cells within the row, in wrapping u32 — seamless\\n// and exact at any R. The value, and its gradient in pitches.\\nfn peg_band(ht: texture_2d<f32>, p: PegPoint, fx: u32, fy: u32, seed: u32) -> vec3f {\\n let X = p.x * f32(fx);\\n let ix = floor(X);\\n let Y = p.fy * f32(fy);\\n let iy = floor(Y);\\n let n = peg_vnoise(ht, u32(i32(ix)), u32(p.R) * fy + u32(i32(iy)), vec2f(X - ix, Y - iy), seed);\\n return vec3f(n.x, n.y * f32(fx), n.z * f32(fy));\\n}\\n\\n// ⌊a / b⌋ for b > 0 (WGSL's `/` truncates toward zero).\\nfn peg_floor_div(a: i32, b: i32) -> i32 {\\n let q = a / b;\\n return select(q, q - 1, (a % b != 0) && (a < 0));\\n}\\n\\n// Value noise on a TURNED lattice, exact at any row: lattice coordinates M·(x, Y)·num/den, M = [[a, −b], [b, a]] an INTEGER rotation\\n// and scale (cells turned atan(b/a), num·√(a² + b²)/den of them to a pitch), so no octave's cells line up with the board or with\\n// another octave's — value noise's square cells stop reading as squares. The carried row splits R = den·Q + r: Q's share is an\\n// exact integer (−b·num·Q, a·num·Q); only x, r and fy, all small, are ever a float. One pre-gathered load.\\nfn peg_rot(ht: texture_2d<f32>, p: PegPoint, a: i32, b: i32, num: i32, den: i32, seed: u32) -> f32 {\\n let q = peg_floor_div(p.R, den);\\n let r = f32(p.R - q * den) + p.fy;\\n let uv = vec2f(f32(a) * p.x - f32(b) * r, f32(b) * p.x + f32(a) * r) * (f32(num) / f32(den));\\n let cell = floor(uv);\\n let base = vec2i(i32(cell.x) - b * num * q, i32(cell.y) + a * num * q);\\n return peg_vnoise(ht, u32(base.x), u32(base.y), uv - cell, seed).x;\\n}\\n\\n// The research's \\\"fine detail fading with pixel footprint\\\", per band: F cycles per pitch are kept while a cycle spans ≥ 4 device\\n// px and gone at 2, so a scrolling board never shimmers (a fleck by its thin side, not its cell). The footprint is the frame's, so\\n// every band's share is a UNIFORM (pass.ts `keep` — `1 − smoothstep(¼, ½, fp·F)`): the face's grain (≈ 19) · 85 · 190, then\\n// 210 · 42 · 105, the punched fibre's 9 · 18 · 36.\\n\\n// Sparse fibre flecks (the research's `flecks`): one randomly turned ellipse per jittered cell at F per pitch, signed — dark\\n// negative, pale positive. A stroke's thin side is sub-pixel long before its cell is (≈ 0.3 of it): its edge is widened by the pixel's\\n// footprint in the ellipse's own measure and its peak lowered to keep its ink — analytic AA, the stroke a faint line, never a dash\\n// (the research averaged 1024 jittered samples to the same end). `fp` = pitches per device px.\\nfn peg_flecks(p: PegPoint, F: u32, density: f32, seed: u32, fp: f32) -> f32 {\\n let X = p.x * f32(F);\\n let ix = floor(X);\\n let Y = p.fy * f32(F);\\n let iy = floor(Y);\\n let cx = u32(i32(ix));\\n let cy = u32(p.R) * F + u32(i32(iy));\\n let q = vec2f(X - ix, Y - iy);\\n var acc = 0.0;\\n for (var j = -1; j <= 1; j++) {\\n for (var i = -1; i <= 1; i++) {\\n let r = peg_hash4(cx + u32(i), cy + u32(j), seed);\\n if (r.w > density) { continue; }\\n let d = q - (vec2f(f32(i), f32(j)) + r.xy);\\n let ang = r.z * 3.14159265;\\n let ca = cos(ang);\\n let sa = sin(ang);\\n let dl = vec2f(d.x * ca + d.y * sa, -d.x * sa + d.y * ca);\\n let wid = 0.10 + 0.10 * r.y;\\n let e = length(vec2f(dl.x / (0.35 + 0.65 * r.x), dl.y / wid));\\n let aa = fp * f32(F) / wid;\\n acc += (1.0 - smoothstep(0.6 - aa, 1.0 + aa, e)) / (1.0 + 2.0 * aa) * select(-1.0, 0.8, r.z > 0.62);\\n }\\n }\\n return clamp(acc, -1.0, 1.0);\\n}\\n\\n// ---- the lattice (the research's cellCoord · sdStadiumV)\\nstruct PegHole { q: vec2f, d: f32, g: vec2f }\\n\\n// The vertical stadium at an offset from its centre: the distance (negative inside) and its gradient, pointing out of the hole.\\nfn peg_stadium(t: TrayUniforms, q: vec2f) -> vec3f {\\n let e = vec2f(q.x, q.y - clamp(q.y, -t.hole.y, t.hole.y));\\n let len = max(length(e), 1.0e-6);\\n return vec3f(len - t.hole.x, e / len);\\n}\\n\\n// The hole of the nearest row (a hole's half-height, 0.33, is under half a pitch): rows at Y = r + ¾, odd rows shifted ½ — the\\n// stagger's parity from the exact row index. A hole whose centre lies within the solid border of a side is never punched.\\nfn peg_hole(t: TrayUniforms, p: PegPoint) -> PegHole {\\n let dr = floor(p.fy - t.depth.w + 0.5);\\n let row = p.R + i32(dr);\\n let shift = t.depth.z + select(0.0, 0.5, (row & 1) != 0);\\n let hx = p.x - shift;\\n let col = floor(hx + 0.5);\\n var h: PegHole;\\n h.q = vec2f(hx - col, p.fy - dr - t.depth.w);\\n let s = peg_stadium(t, h.q);\\n h.d = s.x;\\n h.g = s.yz;\\n let cx = col + shift;\\n if ((cx < t.hole.w) || (cx > t.rect.z / t.view.w - t.hole.w)) { h.d = 1.0e3; }\\n return h;\\n}\\n\\n// ---- the materials (the research's boardMat · wallMat), linear albedo\\n// The tempered face: the TONE drift — two smooth octaves on lattices turned against the board and each other (cells 2.24 and 0.89\\n// of a pitch), the research's big and mid fbm as a UI pitch shows them — and the fine fibre GRAIN on a third (cells 0.05 of a pitch,\\n// ≈ 19 a pitch: what survives of the research's fine grain where its footprint lets it), then at a reading pitch the research's fine\\n// height grain and its bump, the fibre flecks — every band faded by its own footprint. Out: the grain as one factor on the face's\\n// linear albedo (`g`: the albedo is face·(1 + g)), the height's gradient (the bump), and whether the face is FLAT (every bump faded).\\nstruct PegFace { g: f32, grad: vec2f, flat: bool }\\nfn peg_face(ht: texture_2d<f32>, t: TrayUniforms, p: PegPoint, fp: f32) -> PegFace {\\n let tone = 0.62 * (peg_rot(ht, p, 2, 1, 1, 5, 0x3a1u) - 0.5) + 0.38 * (peg_rot(ht, p, 1, -2, 1, 2, 0x5c7u) - 0.5);\\n var grain = 0.0;\\n let kg = t.keepFace.x;\\n if (kg > 0.0) { grain = kg * (peg_rot(ht, p, 3, 1, 6, 1, 0x2b1u) - 0.5); }\\n // the fine height (the research's faceHeight: 0.55 · 85, 0.30 · 190×70, 0.15 · 60×210) — at a UI pitch its footprint fades it\\n var h = 0.0;\\n var grad = vec2f(0.0);\\n let k85 = t.keepFace.z;\\n let k190 = t.keepFace.w;\\n let k210 = t.keepFine.x;\\n if (k85 > 0.0) { let n = peg_band(ht, p, 85u, 85u, 0x1f3u); h += 0.55 * k85 * (n.x - 0.5); grad += 0.55 * k85 * n.yz; }\\n if (k190 > 0.0) { let n = peg_band(ht, p, 190u, 70u, 0x4a7u); h += 0.30 * k190 * (n.x - 0.5); grad += 0.30 * k190 * n.yz; }\\n if (k210 > 0.0) { let n = peg_band(ht, p, 60u, 210u, 0x7c9u); h += 0.15 * k210 * (n.x - 0.5); grad += 0.15 * k210 * n.yz; }\\n let k42 = t.keepFine.y;\\n let k105 = t.keepFine.z;\\n var fl = 0.0;\\n if (k42 > 0.0) { fl += 0.30 * k42 * peg_flecks(p, 42u, 0.40, 0xa13u, fp); }\\n if (k105 > 0.0) { fl += 0.18 * k105 * peg_flecks(p, 105u, 0.35, 0xc35u, fp); }\\n var f: PegFace;\\n f.g = (1.0 + 0.12 * tone + 0.08 * grain + 0.40 * h) * (1.0 + fl) - 1.0;\\n f.grad = grad;\\n f.flat = (k85 <= 0.0) && (k190 <= 0.0) && (k210 <= 0.0);\\n return f;\\n}\\n\\n// The paler, fuzzier punched fibre (the research's edge): its clumps at 9 · 18 · 36 per pitch, faded by the footprint.\\nfn peg_edge(ht: texture_2d<f32>, t: TrayUniforms, p: PegPoint, fp: f32) -> vec3f {\\n var clump = 0.0;\\n let k9 = t.keepEdge.x;\\n let k18 = t.keepEdge.y;\\n let k36 = t.keepEdge.z;\\n if (k9 > 0.0) { clump += 0.5 * k9 * (peg_band(ht, p, 9u, 9u, 0x3e5u).x - 0.5); }\\n if (k18 > 0.0) { clump += 0.25 * k18 * (peg_band(ht, p, 18u, 18u, 0x5a9u).x - 0.5); }\\n if (k36 > 0.0) { clump += 0.125 * k36 * (peg_band(ht, p, 36u, 36u, 0x7bdu).x - 0.5); }\\n return t.edge.xyz * (1.0 + 0.30 * clump / 0.875);\\n}\\n\\n// ---- the light: the research's HOME lamp (D-K3.4), in the desk's colour law and room\\n// The desk's colour law on the tray (the paper's `paper_colour`, chain 0): by day the mat's grade on the sRGB albedo — lit (`gobo`\\n// 1) the identity, a configured byte is the drawn byte; in shadow the room's ½ and its touch of saturation — by night the Moon and\\n// the eye (mat.wgsl `night_mat`) on the linear albedo; between, the cross-fade.\\nfn tray_colour(u: MatUniforms, albedo: vec3f, gobo: f32, noise: f32) -> vec3f {\\n let day = shade_mat(u, albedo, gobo);\\n if (u.night.x <= 0.0) { return day; }\\n let night = night_mat(u, srgb_to_linear(albedo), gobo, noise);\\n if (u.night.x >= 1.0) { return night; }\\n return mix(day, night, u.night.x);\\n}\\n\\n// A surface under the lamp, its linear albedo and normal → the colour on screen. The relief is the paper's — `(N·L/L_z)^(1/2.2)`, the\\n// flat face exactly 1 — and only brightens; a normal turned from the lamp takes the room's grade instead (`gobo` = the Lambert term),\\n// so a face turned away reads as a shadow does, never black. `vis`: the lamp seen at all. The glint is the photo's.\\nfn tray_lit(u: MatUniforms, t: TrayUniforms, alb: vec3f, n: vec3f, vis: f32, noise: f32) -> vec3f {\\n let L = t.lamp.xyz;\\n let lam = clamp(dot(n, L) / max(L.z, 1.0e-3), 0.0, 1.6);\\n let srgb = clamp(night_encode(alb) * pow(max(lam, 1.0), 1.0 / 2.2), vec3f(0.0), vec3f(1.0));\\n var c = tray_colour(u, srgb, min(lam, 1.0) * vis, noise);\\n let H = normalize(L + vec3f(0.0, 0.0, 1.0));\\n let spec = pow(saturate(dot(n, H)), 48.0) * 0.08 * vis;\\n let glint = mix(vec3f(1.0, 0.985, 0.95), vec3f(0.78, 0.86, 1.0) * 0.5, saturate(u.night.x));\\n return c + glint * spec;\\n}\\n\\n// ---- the board: the face and the rim fillet, and the desk through a hole\\n// The front surface at a board point: the face, or — within k of a hole — the fillet. On smax(slab, −hole, k) = 0 seen head-on the\\n// surface's blend weight is h = √(d/k) for d ∈ [0,k], and its normal normalize(((h − 1)·∇d, h)) sweeps from the hole's wall to the\\n// face: the rim's lit edge and its shadowed one, in the paler punched fibre where the normal is steep (the research's faceness).\\nfn peg_surface(ht: texture_2d<f32>, u: MatUniforms, t: TrayUniforms, p: PegPoint, h: PegHole, fp: f32, noise: f32) -> vec3f {\\n let k = t.hole.z;\\n let face = peg_face(ht, t, p, fp);\\n // the PLAIN FACE — clear of every fillet, its bump faded: N·L is L_z exactly, the relief 1, the glint nothing; the grain's small\\n // linear factor rides the configured byte to first order ((1 + g)^(1/2.4) ≈ 1 + g/2.4 — the byte itself where the grain is 0)\\n if ((h.d >= k) && face.flat) {\\n return tray_colour(u, clamp(t.faceSrgb.xyz * (1.0 + face.g / 2.4), vec3f(0.0), vec3f(1.0)), 1.0, noise);\\n }\\n var n = normalize(vec3f(-face.grad * 0.003, 1.0)); // the research's bump: 0.0030 per unit of the height's slope\\n if (h.d < k) {\\n let s = sqrt(max(h.d, 0.0) / k);\\n n = normalize(vec3f((s - 1.0) * h.g, s));\\n }\\n let faceness = smoothstep(0.35, 0.75, n.z);\\n var alb = t.face.xyz * (1.0 + face.g);\\n if (faceness < 1.0) { alb = mix(peg_edge(ht, t, p, fp) * 0.86, alb, faceness); } // the punched rim, burnished at the front\\n return tray_lit(u, t, alb, n, 1.0, noise);\\n}\\n\\n// Through a hole: THE DESK AS DRAWN (design-018 §3). A hole is cut through the board, so it shows what lies under the drawer this\\n// frame — the mat's green, its grid lines, the leaf shadows, anything laid there — in the board's shadow: premultiplied BLACK over the\\n// frame, at the alpha that leaves `f` of the light. THE TWO PLANES (design-017 §6.4) give the lamp at the mat: the ray from the mat\\n// toward the lamp crosses the board's back face at A and its front face at B; the mat is lit iff both lie in the SAME hole — B's, with\\n// A tested against it (a convex prism holds the segment iff it holds both ends) — the penumbra from the SDF distance, widened by the\\n// lamp's size over each plane's height. The room's light reaches the mat through the hole, cut by the cavity. f = a·cav + (1 − a)·vis,\\n// `a` the room's share (the mat's own shade-in-shadow: shade_mat at gobo 0) — ENCODED as the mat's own chain encodes its shade (its\\n// grade lives in pow-2.2 space), so the densest hole is the mat's shade under a leaf — over the desk dimmed as the rest of it is.\\nfn peg_through(u: MatUniforms, t: TrayUniforms, p: PegPoint, h: PegHole, fp: f32) -> f32 {\\n let L = t.lamp.xyz;\\n let lz = max(L.z, 1.0e-3);\\n let off = L.xy / lz;\\n let thick = t.depth.x;\\n let gap = t.depth.y;\\n let hb = peg_hole(t, peg_move(p, off * (gap + thick)));\\n let da = peg_stadium(t, hb.q - off * thick).x;\\n // the penumbra: the lamp's angular radius over the ray's length to each plane's edge (height / L_z), and a pixel\\n let wa = t.lamp.w * gap / lz + fp;\\n let wb = t.lamp.w * (gap + thick) / lz + fp;\\n let vis = smoothstep(-wb, wb, -hb.d) * smoothstep(-wa, wa, -da);\\n let cav = mix(t.cavity.x, t.cavity.y, smoothstep(0.0, t.cavity.z, -h.d));\\n let a = 1.0 - u.gobo.z * (1.0 - u.gobo.w);\\n let f = a * cav + (1.0 - a) * vis;\\n return 1.0 - (1.0 - t.dim) * pow(f, 1.0 / 2.2);\\n}\\n\\n// ---- the drawer\\nfn tray_erf(x: f32) -> f32 {\\n let s = sign(x);\\n let a = abs(x);\\n let k = 1.0 / (1.0 + 0.3275911 * a);\\n let y = 1.0 - (((((1.061405429 * k - 1.453152027) * k) + 1.421413741) * k - 0.284496736) * k + 0.254829592) * k * exp(-a * a);\\n return s * y;\\n}\\n\\n// Gaussian-blurred coverage of an outline at distance d (the shadow, straight out of the field — the paper's).\\nfn tray_blur(d: f32, sigma: f32) -> f32 { return 0.5 - 0.5 * tray_erf(d / max(sigma * 1.4142136, 1.0e-4)); }\\n\\n// The drawer's outline (CSS px, negative inside): a box whose top corners round and whose bottom lies past the view — what is drawn\\n// and what casts the shadows (the finger notch retired — design-018 §2).\\nfn tray_outline(t: TrayUniforms, p: vec2f) -> f32 {\\n let r = t.shape.x;\\n let ext = vec2f(0.5 * t.rect.z, 0.5 * t.rect.w + r);\\n return sdf_round_box(p - vec2f(t.rect.x + ext.x, t.rect.y + ext.y), ext, r);\\n}\\n\\n// The board point under a pixel (CSS px) — the rows on screen added to the carried rows in i32.\\nfn tray_point(t: TrayUniforms, p: vec2f) -> PegPoint {\\n let ly = (p.y - t.rect.y) / t.view.w + t.frac;\\n let fl = floor(ly);\\n return PegPoint((p.x - t.rect.x) / t.view.w, t.rowBase + i32(fl), ly - fl);\\n}\\n\\n// The board's EDGE (design-018 §2): an ARRIS — a quarter-round `A` px wide where the face meets the outline, in the FACE's own\\n// material (its tone at the board point under it, so the grain runs on without a seam; not the paler punched fibre). Its normal turns\\n// from the eye (on the face's side) to the outline's outward direction (at the outline): it catches the lamp where the outline faces\\n// it — the top and the left — and falls to the room's shade on the far side. `o`: the outline's distance there (−A … 0).\\nfn tray_arris(ht: texture_2d<f32>, u: MatUniforms, t: TrayUniforms, p: vec2f, o: f32, noise: f32) -> vec3f {\\n let e = 0.5;\\n let gx = tray_outline(t, p + vec2f(e, 0.0)) - tray_outline(t, p - vec2f(e, 0.0));\\n let gy = tray_outline(t, p + vec2f(0.0, e)) - tray_outline(t, p - vec2f(0.0, e));\\n let g = vec2f(gx, gy) / max(length(vec2f(gx, gy)), 1.0e-6);\\n let s = clamp(1.0 + o / t.shape.y, 0.0, 1.0);\\n let n = vec3f(s * g, sqrt(max(1.0 - s * s, 0.0)));\\n let face = peg_face(ht, t, tray_point(t, p), t.fp);\\n return tray_lit(u, t, t.face.xyz * (1.0 + face.g), n, 1.0, noise);\\n}\\n\\n// The board to its edge, PREMULTIPLIED: the point under the carry, its hole — the front surface over it by its analytic coverage, and\\n// where the surface is not, the desk seen through (black at the hole's alpha). `holes` scales every hole's OPENING: 1 as punched (the\\n// board under the specimens), 0 CLOSED — the plain face, its fillets' relief flattened into it (the VEIL's board, `tray_veil`).\\nfn tray_board(ht: texture_2d<f32>, u: MatUniforms, t: TrayUniforms, p: vec2f, noise: f32, holes: f32) -> vec4f {\\n let pt = tray_point(t, p);\\n let h = peg_hole(t, pt);\\n let cg = clamp(0.5 + h.d / t.fp, 0.0, 1.0); // the surface's analytic coverage as punched\\n let open = (1.0 - cg) * holes; // what of the pixel the hole opens\\n var col = vec4f(0.0);\\n if (holes < 1.0) {\\n // closing: the plain face where the hole no longer opens, and the fillet (within `hole.z` of it) turning to the face\\n var plain = h;\\n plain.d = 1.0e3;\\n let face = peg_surface(ht, u, t, pt, plain, t.fp, noise);\\n var s = face;\\n if (cg > 0.0 && h.d < t.hole.z) { s = mix(face, peg_surface(ht, u, t, pt, h, t.fp, noise), holes); }\\n col = vec4f(s, 1.0) * cg + vec4f(face, 1.0) * ((1.0 - cg) * (1.0 - holes));\\n } else if (cg > 0.0) {\\n col = vec4f(peg_surface(ht, u, t, pt, h, t.fp, noise), 1.0) * cg;\\n }\\n if (open > 0.0) { col += vec4f(0.0, 0.0, 0.0, peg_through(u, t, pt, h, t.fp) * open); }\\n return col;\\n}\\n\\n// A pixel INSIDE the drawer's outline (`o` its distance there, `px` a device px in CSS px), premultiplied: the edge within `A` of the\\n// outline, the board inside it with its holes at `holes` — blended across the pixel where they meet — and the edge's INNER SHADOW over\\n// the board (D-R1.2): the window's lip on the lamp's side, black at up to `shape.z`, fading over `shape.w` px inside the edge, where the\\n// outline faces the lamp (the push of the drawer's lamp shadow points away from it).\\nfn tray_inside(ht: texture_2d<f32>, u: MatUniforms, t: TrayUniforms, p: vec2f, px: f32, o: f32, noise: f32, holes: f32) -> vec4f {\\n let k = clamp(0.5 + (o + t.shape.y) / px, 0.0, 1.0);\\n var col = vec4f(0.0);\\n if (k > 0.0) { col = vec4f(tray_arris(ht, u, t, p, o, noise), 1.0); }\\n if (k < 1.0) {\\n var b = tray_board(ht, u, t, p, noise, holes);\\n if (t.shape.z > 0.0 && -o - t.shape.y < t.shape.w) {\\n let e = 0.5;\\n let g = normalize(vec2f(tray_outline(t, p + vec2f(e, 0.0)) - tray_outline(t, p - vec2f(e, 0.0)), tray_outline(t, p + vec2f(0.0, e)) - tray_outline(t, p - vec2f(0.0, e))) + vec2f(1.0e-6, 0.0));\\n let facing = max(dot(g, -normalize(t.shadow.zw)), 0.0);\\n let sh = t.shape.z * facing * (1.0 - smoothstep(0.0, t.shape.w, -o - t.shape.y));\\n b = vec4f(b.rgb * (1.0 - sh), 1.0 - (1.0 - b.a) * (1.0 - sh));\\n }\\n col = mix(b, col, k);\\n }\\n return col;\\n}\\n\\n// One pixel of the tray UNDER its specimens (`frag` in device px), the view whole: the dim over the desk, the drawer's shadows on it,\\n// the board to the outline and its edge, every hole as punched — premultiplied, each pixel drawn once. The board scrolls under its edge\\n// (the drawer is a window onto it). The specimens hang over the board inside the edge and under the header (their face clip,\\n// tray/specimens.ts `faceClip`); the VEIL (`tray_veil`) is laid over them all at the top.\\nfn tray_drawer(u: MatUniforms, t: TrayUniforms, frag: vec2f, noise_tex: texture_2d<f32>, noise_samp: sampler, ht: texture_2d<f32>) -> vec4f {\\n let dpr = t.view.z;\\n let p = frag / dpr;\\n let px = 1.0 / dpr;\\n let dim = vec4f(0.0, 0.0, 0.0, t.dim);\\n // beyond the shadows' reach: the dim alone\\n let reach = 3.0 * max(t.shadow.x, t.room.x) + length(t.shadow.zw);\\n if ((p.x < t.rect.x - reach) || (p.x > t.rect.x + t.rect.z + reach) || (p.y < t.rect.y - reach)) { return dim; }\\n // the blue noise is the NIGHT's (the rods' snow, mat.wgsl `night_mat`): by day the board takes none — its own grain never bands,\\n // and a scrolled board is then the same pixels, moved\\n var bn = vec3f(0.5);\\n if (u.night.x > 0.0) { bn = textureSampleLevel(noise_tex, noise_samp, frag * u.noise.z + u.noise.xy, 0.0).rgb; }\\n // DEEP INSIDE — clear of the rounded corners, the edge, its inner shadow and two px more: no edge, no shadow, no outline to evaluate\\n // (premultiplied — a hole's alpha is its shadow over the desk, no longer 1)\\n let m = t.shape.y + t.shape.w + 2.0;\\n if ((p.x > t.rect.x + m) && (p.x < t.rect.x + t.rect.z - m) && (p.y > t.rect.y + t.shape.x + m)) {\\n return tray_board(ht, u, t, p, bn.y, 1.0);\\n }\\n let o = tray_outline(t, p);\\n let cover = clamp(0.5 - o / px, 0.0, 1.0);\\n // the shadows on the desk — the room's round the outline, the lamp's pushed along its ground direction, one over the other — where\\n // the drawer does not cover them\\n var under = dim;\\n if (cover < 1.0) {\\n let room = t.room.y * tray_blur(o, t.room.x);\\n let lamp = t.shadow.y * tray_blur(tray_outline(t, p - t.shadow.zw), t.shadow.x);\\n under = vec4f(0.0, 0.0, 0.0, 1.0 - (1.0 - room) * (1.0 - lamp) * (1.0 - t.dim));\\n }\\n if (cover <= 0.0) { return under; }\\n return tray_inside(ht, u, t, p, px, o, bn.y, 1.0) * cover + under * (1.0 - cover);\\n}\\n\\n// THE VEIL (design-018 rev 5 — James, 2026-09-28: \\\"at the edge fading, somehow the holes are displayed on top of objects\\\"): the PLAIN\\n// board — its face with every hole closed, its edge, the edge's inner shadow: `tray_drawer`'s own pixel, less its holes — laid OVER\\n// everything the drawer holds (the specimens and their tags), whole in the HEADER (`fade.y` under the edge's inside) and\\n// fading out over the ramp below it (`fade.x`): `1 − smoothstep(foot, foot + fade.x, y)`. What hangs there and the holes behind it fade\\n// INTO THE BOARD together — a specimen never turns see-through, so no hole shows through it (the specimens are opaque to the face\\n// clip's top; a hard clip at the header's foot lies under the veil's whole). Only pixels wholly inside the outline: its antialiased rim\\n// is `tray_drawer`'s, and the veil there would lay the edge twice. A host's FOOT inset (petition I21, `fade.z` — 0 none) is the same\\n// mirrored at the board's bottom edge: whole in the foot, fading out over the ramp above its line (`smoothstep(line − fade.w, line, y)`;\\n// the face's clip ends at the line, under the veil's whole) — the larger of the two ramps where a short drawer's meet.\\nfn tray_veil(u: MatUniforms, t: TrayUniforms, frag: vec2f, noise_tex: texture_2d<f32>, noise_samp: sampler, ht: texture_2d<f32>) -> vec4f {\\n let p = frag / t.view.z;\\n let px = 1.0 / t.view.z;\\n let foot = t.rect.y + t.shape.y + t.fade.y;\\n var a = 1.0 - smoothstep(foot, foot + t.fade.x, p.y);\\n if (t.fade.z > 0.0) {\\n let line = t.rect.y + t.rect.w - t.fade.z;\\n var bottom = step(line, p.y);\\n if (t.fade.w > 0.0) { bottom = smoothstep(line - t.fade.w, line, p.y); }\\n a = max(a, bottom);\\n }\\n if (a <= 0.0) { return vec4f(0.0); }\\n let o = tray_outline(t, p);\\n if (o > -0.5 * px) { return vec4f(0.0); }\\n var bn = vec3f(0.5);\\n if (u.night.x > 0.0) { bn = textureSampleLevel(noise_tex, noise_samp, frag * u.noise.z + u.noise.xy, 0.0).rgb; }\\n return tray_inside(ht, u, t, p, px, o, bn.y, 0.0) * a;\\n}\\n\",\n} as const;\nexport type WgslFile = keyof typeof WGSL;\n","// The desk's shader text from the generated module (shaders.gen.ts): what a\n// browser host composes its sets from — `matShaders(shaderText(MAT_SHADER_FILES))`,\n// and the same for every pass's `*_SHADER_FILES` map. The Node oracle composes the\n// same sets from the .wgsl files on disk (oracle/render.mjs), so the two hosts\n// compile byte-identical programs; `gen:check` keeps the module fresh.\n// (packages/ground/src/shaders.ts's helper, the B1 convention.)\nimport { WGSL, type WgslFile } from \"./shaders.gen\";\n\n/**\n * A host's shader text: a shader-file map (`MAT_SHADER_FILES`, …) → the text of every file it names, by the map's\n * keys — `shaderText` below (the generated module) in a browser, the .wgsl files read from disk in the Node oracle.\n * A kind's program is made for one (kinds/: `paperProgram(text)`, `deskKinds(text)`).\n */\nexport type ShaderText = <T extends Record<string, string>>(files: T) => { readonly [K in keyof T]: string };\n\n/** The text of every file a shader-file map names, by the map's keys. */\nexport function shaderText<T extends Record<string, string>>(files: T): { readonly [K in keyof T]: string } {\n const out: Record<string, string> = {};\n for (const [key, file] of Object.entries(files)) {\n const text = WGSL[file as WgslFile];\n if (text === undefined) throw new Error(`shaders: no generated text for \"${file}\" — run gen:shaders`);\n out[key] = text;\n }\n return out as { readonly [K in keyof T]: string };\n}\n","// The kit's SHARED WGSL, by name (design-016 §5, K4a). WebGPU has no #include, so a kind's program is COMPOSED\n// (engine/shader.ts: structs, then pure modules, then the entry that declares its bindings); what every kind composes\n// before its own text — the slot's view block, the portal chain's cover, the card's primitives, the mat's light — is\n// named here once, and a kind asks for it:\n//\n// paperShaders = (text) => kitWgsl([\"view\", \"portal\", \"sdf\", \"light\"], { structs: [...own], modules: [...own], entry }, text)\n//\n// instead of listing the mat's files in its own map. The text comes from the host's `ShaderText` (the generated module\n// in a browser, the .wgsl files on disk in the Node oracle), so both hosts compose byte-identical programs; the kit's\n// pieces always precede the kind's own, in the one order below, each once however many of its names are asked.\n\nimport type { ComposeOptions, ShaderPart } from \"../engine/shader\";\nimport type { StructDef } from \"../engine/struct\";\nimport { MatUniforms } from \"../mat/layout\";\nimport { NbBook, NbUniforms } from \"./book\";\nimport { type ShaderText, shaderText } from \"../shaders\";\n\nexport { type ShaderText, shaderText } from \"../shaders\";\n\n/**\n * The kit's pieces of WGSL, in compose order (petition I31: every function, struct and const in them carries a `///` block saying\n * what it takes — units and ranges — and what it gives; `shaderText(KIT_WGSL_FILES)` hands their text, comments and all):\n * - `view` — the slot's view block, `MatUniforms` (its JSDoc lists the fields), bound as `u` at `@group(0) @binding(0)`;\n * - `portal` — `portal_cover` and its parts: a fragment's cover through the slot's chain of faces, CSS px (portal.wgsl);\n * - `sdf` — exact signed distances: `sdf_box`, `sdf_round_box`, `sdf_circle`, `sdf_segment`, `sdf_rounded_x`, the fillets\n * `op_union_round` and `op_isect_round` (primitives.wgsl);\n * - `light` — the mat's light as an object reads it: `mat_zoom`, `mat_dpr`, the noise (`hash12`, `value_noise` — [0, 1)), the\n * gobo (`sample_gobo`, `lit_gobo`, `desk_of`, `lit_desk`), the day's chain (`shade_mat` — sRGB in, sRGB out) and the night's\n * (`night_mat` — LINEAR in, sRGB out), `mat_colour`, the lattice's lines (mat/mat.wgsl — its header states the conventions);\n * - `ruler` — the rulers' print: `ruler_ink`, `ruler_band` and their glyph arithmetic (mat/ruler.wgsl);\n * - `book` — the 3D kit: the desk eye (`nb_clip`), the PCSS shadow (`nb_shadow`), the colour chain (`nb_colour`), the cloth, the\n * paper, the cover's designs (kit/book.wgsl), over its records `NbUniforms` and `NbBook`.\n *\n * THE CONVENTIONS they share: world units (one is one CSS px at zoom 1), x right and y DOWN; CSS px = (world − `u.cam.xy`) ·\n * zoom, origin the attachment's top-left; device px = CSS px · dpr, a fragment's `@builtin(position).xy`; zoom = `mat_zoom(u)`\n * (CSS px per world unit), dpr = `mat_dpr(u)` (the attachment's device px per CSS px — below 1 for a thumbnail); the lamp's\n * desk in metres, y up (`desk_of`); colours 0..1, sRGB-encoded unless a parameter says LINEAR.\n */\nexport type KitWgslPiece = \"view\" | \"portal\" | \"sdf\" | \"light\" | \"ruler\" | \"book\";\n\n/**\n * A name of the kit's WGSL: a piece, or another name for one (`lamp`, `gobo`, `night`, `noise` and `mat` are `light` — `mat` since\n * M24 LT1: the mat's module IS the light piece, and a port that names the mat's module by its own name composes).\n */\nexport type KitWgslName = KitWgslPiece | \"lamp\" | \"gobo\" | \"night\" | \"noise\" | \"mat\";\n\n/** A piece of the kit's WGSL: generated structs, a pure module (a .wgsl file by the host's text), or both. */\ninterface KitPiece {\n readonly structs?: readonly StructDef<string>[];\n readonly file?: string;\n}\n\n/**\n * The kit's WGSL in its compose order:\n * - `view` — the slot's VIEW BLOCK (`MatUniforms`: the camera, the box, the clocks, the lamp's gobo, the night, the\n * portal chain), bound at `@group(0) @binding(0)` as `u` in every kind's entry;\n * - `portal` — `portal_cover`: a fragment's cover through the slot's chain of faces (portal.wgsl);\n * - `sdf` — the card's primitives: rounded boxes, their shadows and rims (primitives.wgsl);\n * - `light` — the mat's light as an object reads it: the desk point under a lamp, the gobo's dapple (`sample_gobo`,\n * `lit_gobo`), the night's appearance, the value noise and the colour chain (mat/mat.wgsl; its functions call each\n * other, so `lamp`, `gobo`, `night`, `noise` and `mat` are the same piece by other names);\n * - `ruler` — the rulers' glyph lattice (mat/ruler.wgsl: a face that prints the mat's numerals);\n * - `book` — the 3D kit (kit/book.wgsl and its records `NbUniforms`, `NbBook` — kit/book.ts): the desk eye's projection,\n * the PCSS shadow on an object's own shadow map, the materials of paper and cloth (after `light`, whose chain it grades by).\n */\nconst PIECES = {\n view: { structs: [MatUniforms] },\n portal: { file: \"portal.wgsl\" },\n sdf: { file: \"primitives.wgsl\" },\n light: { file: \"mat/mat.wgsl\" },\n ruler: { file: \"mat/ruler.wgsl\" },\n book: { structs: [NbUniforms, NbBook], file: \"kit/book.wgsl\" },\n} as const satisfies Record<KitWgslPiece, KitPiece>;\n\n/** The names a piece also answers to. */\nconst ALIASES: Readonly<Record<Exclude<KitWgslName, KitWgslPiece>, KitWgslPiece>> = { lamp: \"light\", gobo: \"light\", night: \"light\", noise: \"light\", mat: \"light\" };\n\n/**\n * The .wgsl file behind each of the kit's module pieces — what a host's `ShaderText` is asked for. `shaderText(KIT_WGSL_FILES)`\n * is the pieces' text, their `///` blocks with it: what a consumer's docs generator quotes (petition I31).\n */\nexport const KIT_WGSL_FILES: Readonly<Partial<Record<KitWgslPiece, string>>> = Object.fromEntries(\n Object.entries(PIECES).flatMap(([name, p]) => (\"file\" in p ? [[name, p.file]] : [])),\n);\n\n/**\n * A kind's program with the kit's named pieces before its own: the kit's structs, then its modules (each labelled by its\n * file, as a kind's own map labelled it), in the kit's order; then the kind's `own` structs, modules and entry. `text` is\n * the host's (default: the generated module). An unknown name throws — a misspelt piece never composes silently.\n */\nexport function kitWgsl(names: readonly KitWgslName[], own: ComposeOptions, text: ShaderText = shaderText): ComposeOptions {\n const want = new Set<string>();\n for (const n of names) {\n const piece = (ALIASES as Record<string, string>)[n] ?? n;\n if (!(piece in PIECES)) throw new Error(`kitWgsl: no piece \"${n}\" (the kit's: ${[...Object.keys(PIECES), ...Object.keys(ALIASES)].join(\", \")})`);\n want.add(piece);\n }\n const files: Record<string, string> = {};\n for (const [name, p] of Object.entries(PIECES) as [string, KitPiece][]) if (want.has(name) && p.file) files[name] = p.file;\n const read = text(files);\n const structs: StructDef<string>[] = [];\n const modules: ShaderPart[] = [];\n for (const [name, p] of Object.entries(PIECES) as [string, KitPiece][]) {\n if (!want.has(name)) continue;\n if (p.structs) structs.push(...p.structs);\n if (p.file) modules.push({ label: p.file, text: read[name] as string });\n }\n return { structs: [...structs, ...(own.structs ?? [])], modules: [...modules, ...(own.modules ?? [])], entry: own.entry };\n}\n","// A slot's GRID — the cutting mat, the one grid the ground draws since the dot\n// and the needle retired (2026-09-25; MINIMAT.md §1). What a slot says about its\n// ground each frame (`SlotFrame`: its view, the zoom its lattice is dressed for,\n// the mat's clocks, its presentation, its light) and the grid's config (the\n// fade-in window every rung reads, and the mat's own tuning).\n\nimport { type FadeIn, lod, type View } from \"../lattice/lod\";\nimport type { Presentation } from \"../nav/portal\";\nimport { GRID } from \"../theme\";\nimport { DEFAULT_MAT_CONFIG, type MatConfig, type MatFrame, type SlotLight } from \"./layout\";\n\nexport interface GridConfig {\n /** A rung fades in between these cell sizes, CSS px (lod.ts `FadeIn`) — the mat's lines, the rulers' ticks, a mini mat's face. */\n readonly fadeIn: FadeIn;\n /** The cutting mat's tuning (mat/layout.ts) — theme.ts's numbers unless a host tweaks them. */\n readonly mat: MatConfig;\n}\n\n/** The engine's grid: the fade-in law and the mat as theme.ts has them. */\nexport const DEFAULT_GRID: GridConfig = { fadeIn: GRID.fadeIn, mat: DEFAULT_MAT_CONFIG };\n\n/** One slot's frame: the root's, a flight's departed one, or a mini mat's inside. */\nexport interface SlotFrame {\n readonly view: View & { readonly dpr: number };\n /**\n * The zoom this slot's lattice is DRESSED for (PORTAL.md §9): its fade-in window scales by\n * `view.zoom / lodZoom`, so the grid looks like the grid at `lodZoom`, scaled — a mini mat's\n * face shows its inside as it will look at the arrival, an arriving slot lands on its own\n * dressing, a departed one keeps the cut's. Absent = the view's zoom: the root at rest.\n */\n readonly lodZoom?: number;\n /** The mat's clocks and tilt for this frame; absent = a still (STILL_MAT_FRAME). */\n readonly mat?: MatFrame;\n /** Opacity and the portal clip (nav/portal.ts); absent = everything, at full strength. */\n readonly present?: Presentation;\n /**\n * The lamp this slot is lit by (MINIMAT.md §4; mat/layout.ts `SlotLight`). Absent = the\n * host's: a mini mat's inside lies under the lamp of the desk the mini mat lies on, so the\n * ground hands every nested slot its parent's light, and the root its own camera.\n */\n readonly light?: SlotLight;\n}\n\n/**\n * The scale a lattice is dressed by for `lodZoom` (PORTAL.md §9): `σ = zoom / lodZoom` — the\n * lattice at `lodZoom` scaled whole — floored at `GRID.dressFloor` (a miniature's grid is never\n * finer than that share of the desk's). 1 = the identity: the object itself, not a copy.\n */\nexport function dressScale(zoom: number, lodZoom?: number): number {\n if (lodZoom === undefined || !(lodZoom > 0) || lodZoom === zoom) return 1;\n return Math.max(zoom / lodZoom, GRID.dressFloor);\n}\n\n/** The grid a slot renders with when dressed for `lodZoom`: its fade-in window scaled by `dressScale`. */\nexport function dressGrid(cfg: GridConfig, zoom: number, lodZoom?: number): GridConfig {\n const s = dressScale(zoom, lodZoom);\n if (s === 1) return cfg;\n return { ...cfg, fadeIn: [cfg.fadeIn[0] * s, cfg.fadeIn[1] * s] };\n}\n\n/** What a slot's grid did this frame: the lattice's decade and its fade, and whether the wind blew. */\nexport interface GridStats { readonly k0: number; readonly fade: number; readonly wind: boolean }\n\n/** The stats of a view's lattice (the wind the pass reports). */\nexport const gridStats = (view: View, wind: boolean): GridStats => { const l = lod(view); return { k0: l.k0, fade: l.fade, wind }; };\n","// What the two LAYERED kinds share — the notebook (kinds/notebook.ts) and the desk calendar (kinds/calendar.ts):\n// a kind whose pass renders every one of its objects into a target of its own (depth, 4× MSAA, the\n// notebook's shadow maps) and lays that target over the frame in ONE draw (design-015 §4.2: \"a kind whose\n// object needs depth, MSAA or shadow maps renders into its own target … its run in the main pass is a\n// composite draw\"). Both are ROOT-desk objects in this program (D-D18): only the root slot's pass draws.\n//\n// The layer is recorded in `prepare`, into the frame's command encoder — before the frame's render pass\n// begins and after the mat's wind (so it reads this frame's dapple) — and `drawRange` lays it, inside the\n// slot's scissor, then gives the slot its scissor back (the objects after it draw in the slot's, as the\n// ground restored it after a host's `underlays`).\n\nimport { bindLayout } from \"../engine/pipeline\";\nimport type { KindPass, RenderTarget, SlotContext } from \"../kind\";\nimport type { View } from \"../lattice/lod\";\nimport type { MatPass } from \"./view\";\nimport { scissorOf } from \"../nav/portal\";\nimport type { ComposeOptions } from \"../engine/shader\";\nimport type { ShaderText } from \"../shaders\";\nimport { kitWgsl } from \"./wgsl\";\n\n/** The composite's entry: a resolved, premultiplied layer laid over what the ground drew (the layered kinds share it). */\nexport const LAYER_COMPOSITE_FILE = \"kit/composite.wgsl\";\n\n/**\n * The program that lays a layer — its entry, from the host's shader text, after the kit's view block and portal chain: the layer is\n * laid through the slot's chain (design-018 §4), so a layered object keeps the kit's contract as one — the tray's feather included.\n */\nexport function layerComposite(text: ShaderText): ComposeOptions {\n return kitWgsl([\"view\", \"portal\"], { entry: { label: LAYER_COMPOSITE_FILE, text: text({ composite: LAYER_COMPOSITE_FILE }).composite } }, text);\n}\n\n/** The composite's bindings (every layered kind's): the resolved layer, its box's origin, and the slot's view block (its chain). */\nexport function layerCompositeLayout(device: GPUDevice, label: string): GPUBindGroupLayout {\n return bindLayout(device, [{ binding: 0, stages: [\"fragment\"], texture: \"float\" }, { binding: 1, stages: [\"fragment\"], buffer: \"uniform\" }, { binding: 2, stages: [\"fragment\"], buffer: \"uniform\" }], label);\n}\n\n/** A device-px rect: x, y, width, height. */\nexport type Rect4 = readonly [number, number, number, number];\n\n/**\n * The attachment a slot's view names, device px: what every host sizes its canvas to — `surface().fit`, the reflector's\n * `attach.resize`, the oracle's target — `max(1, round(css · dpr))`. A layer is made at this size, so its texel is the pixel.\n */\nexport const attachmentOf = (v: View & { readonly dpr: number }): { readonly w: number; readonly h: number } => ({\n w: Math.max(1, Math.round(v.width * v.dpr)),\n h: Math.max(1, Math.round(v.height * v.dpr)),\n});\n\n/** Two device-px rects intersected; a width or height of 0 when they do not meet. */\nexport function clip(a: Rect4, b: Rect4): Rect4 {\n const x0 = Math.max(a[0], b[0]);\n const y0 = Math.max(a[1], b[1]);\n const x1 = Math.min(a[0] + a[2], b[0] + b[2]);\n const y1 = Math.min(a[1] + a[3], b[1] + b[3]);\n return [x0, y0, Math.max(0, x1 - x0), Math.max(0, y1 - y0)];\n}\n\n/** What a layered kind asks of its pass: the layer recorded into an encoder, laid by one draw, its screen box. */\nexport interface LayerPass {\n layer(encoder: GPUCommandEncoder, size: { readonly w: number; readonly h: number }, dpr: number): boolean;\n composite(pass: GPURenderPassEncoder, scissor?: Rect4 | null): void;\n readonly screenBox: Rect4 | null;\n /** The render target the next prepare is for (D7 — `SlotContext.target`): a pass keeps the held desk copy's state apart. */\n use?(target: RenderTarget): void;\n /** The hold is over: the copy's state given back. */\n endHold?(): void;\n /** The records its last prepare turned away at its cap (D7). */\n readonly dropped?: number;\n /** K6a (D-K6a.3): its frame layer's targets are made (at the first object drawn)… */\n readonly layerMade?: boolean;\n /** …was one of its objects drawn within `ms` (and when last: `performance.now()`'s ms — the release's due, K7a)… */\n drawnWithin?(ms: number): boolean;\n readonly lastDrawn?: number;\n /** …and let them go (made again at the next object drawn). */\n releaseLayer?(): void;\n dispose(): void;\n}\n\n/**\n * The part of a layered kind that is the same for both: ROOT ONLY — a spawned slot's pass holds nothing and draws nothing (its\n * `pass` is null; D-D18: a notebook or a pad is never drawn in a mini mat's inside or a flight's departed desk) — the layer recorded\n * after its pass prepared, and laid ONCE over the whole range the ground hands it (a kind registered with `composite: true`: the\n * ground draws it as one run after the rest of its stratum).\n */\nexport abstract class LayeredKind<R, P extends LayerPass> implements KindPass<R> {\n /** The root slot's pass — the host's door to its own API (the ink, the tiles, the law); null in a spawned slot (root only). */\n readonly pass: P | null;\n /** The slot's scissor this frame, device px — the layer is laid inside it and it is given back after (null: nothing to lay). */\n private within: Rect4 | null = null;\n /** How many records `prepare` was handed: the whole range the layer lays. */\n private handed = 0;\n constructor(pass: P | null) { this.pass = pass; }\n\n abstract spawn(mat: MatPass): KindPass<R>;\n\n /** The pass's own prepare for this slot (its records, eye and look); returns the count that will draw. */\n protected abstract prepareOwn(pass: P, s: SlotContext, records: readonly R[]): number;\n\n prepare(encoder: GPUCommandEncoder, s: SlotContext, records: readonly R[]): number {\n this.within = null;\n this.handed = records.length;\n const p = this.pass;\n if (!p) return 0;\n p.use?.(s.target ?? \"frame\");\n const n = this.prepareOwn(p, s, records);\n if (n === 0) return 0;\n const size = attachmentOf(s.view);\n if (p.layer(encoder, size, s.view.dpr)) this.within = scissorOf(s.present, s.view.dpr, size);\n return n;\n }\n\n /** The layer over the frame: once, for the whole range [0, count) — one draw lays every object; a part of it cannot be drawn from one layer. */\n drawRange(pass: GPURenderPassEncoder, first: number, end: number): void {\n const p = this.pass;\n const within = this.within;\n if (!p || !within || first !== 0 || end < this.handed || end === 0) return;\n const box = p.screenBox;\n if (!box) return;\n const r = clip(box, within);\n if (r[2] <= 0 || r[3] <= 0) return;\n p.composite(pass, r);\n pass.setScissorRect(within[0], within[1], within[2], within[3]);\n }\n\n endHold(): void { this.pass?.endHold?.(); }\n\n /**\n * Let this slot's layer go when none of its objects was drawn within `ms` (D-K6a.3 for a slot the host keeps beyond the root — the\n * tray's specimen, K5a; the ROOT's layer goes by its kind's own tick). Made again at the next object drawn.\n */\n idle(ms: number): void {\n const p = this.pass;\n if (p !== null && p.layerMade === true && p.drawnWithin?.(ms) === false) p.releaseLayer?.();\n }\n\n /** When `idle(ms)` next lets the layer go — its last object drawn + `ms` (K7a: the host's registered TIME wake); ∞ with none. */\n idleAt(ms: number): number {\n const p = this.pass;\n return p !== null && p.layerMade === true && p.lastDrawn !== undefined ? p.lastDrawn + ms : Number.POSITIVE_INFINITY;\n }\n\n dropped(): number { return this.pass?.dropped ?? 0; }\n\n dispose(): void { this.pass?.dispose(); }\n}\n\n/** A box's targets grow and shrink by this many device px a side, so a pan's jitter never makes them again (K7a). */\nexport const BOX_STEP = 256;\n/** The numbers a layer's signature holds at most (`BoxTargets.holds`). */\nconst SIGNATURE = 8;\n\n/**\n * A layered kind's TARGETS AT ITS SCREEN BOX (K7a — design-016 §6): the 4× colour and depth and their resolve sized to the box\n * its objects cover on the attachment (rounded up to BOX_STEP, at most the attachment), never the canvas — a notebook's layer at\n * 2400 × 1600 was 136 MB for a book a tenth of the screen. The layer is drawn through a viewport shifted by the box's ORIGIN over\n * the whole attachment, so the pixel grid is the attachment's (a fragment lands on the pixel it always did, the target's texel\n * `pixel − origin`); the composite reads the texel at its pixel less the origin (its uniform, binding 1 beside the layer). What a\n * fragment samples BY its position adds `origin` back (the passes carry it in their knobs). The rasteriser is not exactly\n * translation-invariant in floating point: a handful of edge samples and 1-LSB interpolants move against a canvas-sized layer\n * (D-K7a.4 — 13 golden scenes re-blessed).\n */\nexport class BoxTargets {\n msaa: GPUTexture | null = null;\n depth: GPUTexture | null = null;\n resolve: GPUTexture | null = null;\n compGroup: GPUBindGroup | null = null;\n /** The box's top-left on the attachment, device px (the layer's texel 0, 0). */\n readonly origin: [number, number] = [0, 0];\n /** The targets' size as made, device px (0 × 0: none). */\n readonly size = { w: 0, h: 0 };\n private originBuf: GPUBuffer | null = null;\n private readonly sent = new Float32Array(4).fill(Number.NaN);\n private readonly next = new Float32Array(4);\n /** What the layer the targets hold was drawn from — its pass's signature at the draw (K7a); NaN: nothing drawn since made. */\n private readonly drawnFrom = new Float64Array(SIGNATURE).fill(Number.NaN);\n /** …and the content it read, by value (the knobs, the records, the view block), with each copy's length. */\n private readonly drawnBytes: Uint8Array[] = [];\n private readonly drawnLen: number[] = [];\n /** `view`: the slot's view block (`MatPass.view`) — the composite lays the layer through its portal chain (`layerCompositeLayout`). */\n constructor(private readonly device: GPUDevice, private readonly label: string, private readonly layoutComp: GPUBindGroupLayout, private readonly samples: number, private readonly view: GPUBuffer) {}\n\n /** The targets are made (a layer holds device memory). */\n get made(): boolean { return this.msaa !== null; }\n\n /**\n * Fit the targets to `box` [x0, y0, x1, y1] (device px) on an `attach` of its size: made when none are or the box outgrew them,\n * made smaller when they are more than four times its area — never larger than the attachment; the origin written for the\n * composite when it moved.\n */\n fit(box: readonly [number, number, number, number], attach: { readonly w: number; readonly h: number }): void {\n const [x0, y0, x1, y1] = box;\n const w = Math.min(Math.ceil(Math.max(1, x1 - x0) / BOX_STEP) * BOX_STEP, Math.max(1, attach.w));\n const h = Math.min(Math.ceil(Math.max(1, y1 - y0) / BOX_STEP) * BOX_STEP, Math.max(1, attach.h));\n const outgrown = this.size.w < x1 - x0 || this.size.h < y1 - y0;\n const loose = this.size.w * this.size.h > 4 * w * h;\n if (this.msaa === null || outgrown || loose) {\n this.release();\n const d = this.device;\n this.msaa = d.createTexture({ label: `${this.label}/layer ×4`, size: [w, h], format: \"rgba8unorm\", sampleCount: this.samples, usage: GPUTextureUsage.RENDER_ATTACHMENT });\n this.depth = d.createTexture({ label: `${this.label}/depth ×4`, size: [w, h], format: \"depth24plus\", sampleCount: this.samples, usage: GPUTextureUsage.RENDER_ATTACHMENT });\n this.resolve = d.createTexture({ label: `${this.label}/layer`, size: [w, h], format: \"rgba8unorm\", usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING });\n this.originBuf ??= d.createBuffer({ label: `${this.label}/layer origin`, size: 16, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });\n this.compGroup = d.createBindGroup({ label: `${this.label}/composite`, layout: this.layoutComp, entries: [{ binding: 0, resource: this.resolve.createView() }, { binding: 1, resource: { buffer: this.originBuf } }, { binding: 2, resource: { buffer: this.view } }] });\n this.size.w = w;\n this.size.h = h;\n this.sent.fill(Number.NaN);\n this.drawnFrom.fill(Number.NaN);\n }\n this.origin[0] = x0;\n this.origin[1] = y0;\n const n = this.next;\n n[0] = x0; n[1] = y0; n[2] = 0; n[3] = 0;\n if (n[0] !== this.sent[0] || n[1] !== this.sent[1]) {\n this.device.queue.writeBuffer(this.originBuf as GPUBuffer, 0, n);\n this.sent.set(n);\n }\n }\n\n /**\n * Begin the layer's pass into the fitted targets: cleared, the viewport the whole `attach` shifted by the origin, the scissor the\n * box — `box` [x0, y0, x1, y1] as fitted.\n */\n begin(encoder: GPUCommandEncoder, label: string, attach: { readonly w: number; readonly h: number }, box: readonly [number, number, number, number]): GPURenderPassEncoder {\n const pass = encoder.beginRenderPass({\n label,\n colorAttachments: [{ view: (this.msaa as GPUTexture).createView(), resolveTarget: (this.resolve as GPUTexture).createView(), clearValue: { r: 0, g: 0, b: 0, a: 0 }, loadOp: \"clear\", storeOp: \"discard\" }],\n depthStencilAttachment: { view: (this.depth as GPUTexture).createView(), depthClearValue: 1, depthLoadOp: \"clear\", depthStoreOp: \"discard\" },\n });\n pass.setViewport(-box[0], -box[1], attach.w, attach.h, 0, 1);\n pass.setScissorRect(0, 0, box[2] - box[0], box[3] - box[1]);\n return pass;\n }\n\n /**\n * The layer the targets hold was drawn from exactly `sig` and `bytes` (K7a — every input of its draw the same since: the pass's\n * numbers — its resources' generation, what it lists, the box — and the CONTENT the draw read, compared by value: this target's\n * knobs and records as prepared, the slot's view block. By content, not by version: a held frame's desk copy writes the shared\n * buffers between two of the hand's frames, and the hand's layer is still what they held): it may be laid again undrawn.\n */\n holds(sig: ArrayLike<number>, bytes: readonly Uint8Array[]): boolean {\n if (this.msaa === null) return false;\n for (let i = 0; i < SIGNATURE; i++) if (this.drawnFrom[i] !== (i < sig.length ? sig[i] : 0)) return false;\n if (bytes.length !== this.drawnBytes.length) return false;\n for (let i = 0; i < bytes.length; i++) {\n const a = bytes[i] as Uint8Array;\n const b = this.drawnBytes[i] as Uint8Array;\n if (this.drawnLen[i] !== a.byteLength) return false;\n for (let k = 0; k < a.byteLength; k++) if (a[k] !== b[k]) return false;\n }\n return true;\n }\n\n /** The layer was drawn from `sig` and `bytes` (copied; the copies grow once and are reused). */\n drew(sig: ArrayLike<number>, bytes: readonly Uint8Array[]): void {\n for (let i = 0; i < SIGNATURE; i++) this.drawnFrom[i] = i < sig.length ? (sig[i] as number) : 0;\n this.drawnBytes.length = bytes.length;\n this.drawnLen.length = bytes.length;\n for (let i = 0; i < bytes.length; i++) {\n const a = bytes[i] as Uint8Array;\n let b = this.drawnBytes[i];\n if (b === undefined || b.byteLength < a.byteLength) { b = new Uint8Array(Math.max(a.byteLength, 64)); this.drawnBytes[i] = b; }\n b.set(a);\n this.drawnLen[i] = a.byteLength;\n }\n }\n\n /** The targets let go, the origin's uniform with them (the next `fit` makes them again). */\n release(): void {\n this.drawnFrom.fill(Number.NaN);\n this.msaa?.destroy(); this.depth?.destroy(); this.resolve?.destroy(); this.originBuf?.destroy();\n this.msaa = null; this.depth = null; this.resolve = null; this.compGroup = null; this.originBuf = null;\n this.size.w = 0;\n this.size.h = 0;\n }\n\n dispose(): void { this.release(); }\n}\n\n/**\n * How long a layered kind's frame targets (its 4× layer, its resolve; the notebook's shadow maps) stand with none of its objects\n * drawn before the kind lets them go (K6a, design-016 §6 — made again at the next one drawn): render targets at the canvas's size,\n * never a cache the raster budget holds (D-K6a.3).\n */\nexport const LAYER_IDLE_MS = 5000;\n","// A critically-damped-by-default spring, integrated on the CPU with substeps.\n// Springs, not tweens: a target that flips mid-flight reverses from wherever\n// the value IS, with no snap and no restart.\n//\n// And the desk's ONE physics for its objects: every object lifts off the mat on\n// the same spring and brings its selection ring in on the same spring — the\n// note, the notebook, the whiteboard, the mini mat. The numbers are the §7\n// lift (`--vf-ease-lift`: 180 ms with a slight overshoot) and the old card's\n// reveal, kept when the cards retired (2026-09-25).\n\nexport function spring(\n x0: number, v0: number, target: number,\n hz: number, damping: number, dt: number, substeps = 8,\n): [number, number] {\n let x = x0;\n let v = v0;\n const w = 2 * Math.PI * hz;\n const h = Math.min(dt, 0.05) / substeps;\n for (let i = 0; i < substeps; i++) {\n v += (w * w * (target - x) - 2 * damping * w * v) * h;\n x += v * h;\n }\n return [x, v];\n}\n\nexport function settled(x: number, v: number, target: number, eps = 1e-3): boolean {\n return Math.abs(x - target) < eps && Math.abs(v) < eps * 10;\n}\n\n/**\n * The objects' springs: the hold's lift (the hover's rise rides the same numbers). The selection RING's spring is gone (D6): the\n * kinds' own ring retired at D4a — the marks draw the selection — and a spring that only ever fed a zero kept the desk live for\n * a second after every selection change (the D4a landing's owed item).\n */\nexport interface ObjectSprings {\n readonly liftHz: number; readonly liftDamp: number;\n}\n\nexport const SPRINGS: ObjectSprings = { liftHz: 4.5, liftDamp: 0.78 };\n","// The portal flight — the maths of ICE design-006 T1, ported VERBATIM from\n// `@ice/kernel` (nav-flight.ts, and coords.ts `fitCamera`), plus the opacity\n// ramps of `@ice/core` presentation-transition.ts and the NAV_TRANSITION\n// defaults. Pure: no GPU, no DOM, no ECS. test/nav.test.ts pins every function\n// here to numbers ICE's own kernel produced for the same inputs, so a drift\n// from the product's flight is a red test, not a feel.\n//\n// Conventions are coords.ts's (ICE Law 13), the same as lod.ts's `View`:\n// camera {x, y} = the world point at the viewport's top-left, zoom = screen px\n// per world unit, `screen = (world − cam)·zoom`.\n//\n// The portal embedding: a container's content coordinates are FRAME-LOCAL —\n// the transition DEFINES the embedding by mapping the arrival camera's visible\n// rect onto the container's body rect (`portalAffine`, aspect-fit, centres\n// aligned). With that affine fixed, both frames ride ONE camera: the\n// destination renders under `c(t)` directly; the departed frame renders under\n// `outgoingCamera(A, c(t))`, A mapping departed coords into destination coords.\n// Continuity at the cut is exact by construction (`solveFlightStart`), and no\n// drift is possible mid-flight — there is no second clock.\n//\n// Numerics locked by ICE's field testing (2026-07-15, three rounds):\n// - the progress spring is the CLOSED-FORM critically-damped solution —\n// semi-implicit Euler diverges once ω·dt nears 1 (one dropped frame at a\n// fast exit response sent a camera to zoom 1501);\n// - the path interpolates zoom in LOG space (constant perceived zoom\n// velocity — van Wijk & Nuij) with the view centre linear in 1/zoom, which\n// is exactly an anchored zoom whenever a fixed screen point exists;\n// - flights beyond `freezeOctaves` are depth-capped (`capFlightStart`): a DOM\n// plane's raster scale swept ~30× in one flight outruns the tile\n// re-raster; the capped flight is presented as a crossfade-through-zoom.\n// (A GPU ground has no such limit — the cap is kept so the ground's motion\n// matches the planes above it.)\n\nexport interface CameraState { readonly x: number; readonly y: number; readonly zoom: number }\nexport interface Rect { readonly x: number; readonly y: number; readonly width: number; readonly height: number }\nexport interface Viewport { readonly width: number; readonly height: number }\n\n/** Uniform scale + translate: `A(q) = o + q·s`. */\nexport interface PortalAffine { readonly s: number; readonly ox: number; readonly oy: number }\n\n/** The world rect a camera shows through a viewport. */\nexport function visibleRect(cam: CameraState, vpW: number, vpH: number): Rect {\n return { x: cam.x, y: cam.y, width: vpW / cam.zoom, height: vpH / cam.zoom };\n}\n\n/**\n * The portal embedding: map `arrival` (the world rect the arrival camera will\n * show, in the CHILD frame's coords) onto `portal` (the container's body rect,\n * in the PARENT frame's coords). Aspect-FIT with centres aligned (design-006\n * §8.3 — the container's chrome absorbs the letterbox; a mini mat's face shows\n * the inside past the arrival on its longer side, MINIMAT.md §3).\n */\nexport function portalAffine(arrival: Rect, portal: Rect): PortalAffine {\n const s = Math.min(portal.width / arrival.width, portal.height / arrival.height);\n return {\n s,\n ox: portal.x + portal.width / 2 - (arrival.x + arrival.width / 2) * s,\n oy: portal.y + portal.height / 2 - (arrival.y + arrival.height / 2) * s,\n };\n}\n\nexport function invertAffine(a: PortalAffine): PortalAffine {\n return { s: 1 / a.s, ox: -a.ox / a.s, oy: -a.oy / a.s };\n}\n\n/** `(outer ∘ inner)(q) = outer(inner(q))` — for multi-level exit portals. */\nexport function composeAffine(outer: PortalAffine, inner: PortalAffine): PortalAffine {\n return { s: outer.s * inner.s, ox: outer.ox + inner.ox * outer.s, oy: outer.oy + inner.oy * outer.s };\n}\n\n/**\n * Continuity solve: the camera `c0` (in the DESTINATION frame) under which\n * departed-frame content mapped through `A` (departed → destination coords)\n * renders EXACTLY as it did under `camPre` (in the departed frame) the instant\n * before the cut. Zoom limits deliberately do NOT apply here — flight paths\n * transit far outside the user-gesture band; only the ARRIVAL camera is\n * clamped by the caller.\n */\nexport function solveFlightStart(A: PortalAffine, camPre: CameraState): CameraState {\n return { x: A.ox + camPre.x * A.s, y: A.oy + camPre.y * A.s, zoom: camPre.zoom / A.s };\n}\n\n/**\n * Destination camera expressed in departed-frame coordinates. Rendering the\n * outgoing ground with this camera is pixel-equivalent to first mapping its\n * points through A and then rendering under `destination`.\n */\nexport function outgoingCamera(A: PortalAffine, destination: CameraState): CameraState {\n return { x: (destination.x - A.ox) / A.s, y: (destination.y - A.oy) / A.s, zoom: A.s * destination.zoom };\n}\n\n/** Zoom distance in octaves — the flight-length measure (design-006 §4/§5). */\nexport function flightOctaves(from: CameraState, to: CameraState): number {\n return Math.abs(Math.log2(to.zoom / from.zoom));\n}\n\n/**\n * Depth-cap a flight start (design-006 §5): beyond `maxOctaves`, clamp the\n * start zoom to `capFactor ×` the arrival zoom (dive direction preserved),\n * keeping the exact start's view CENTRE — the portal anchor — so the motion\n * still comes from/goes to the right place. `capped: true` means the caller\n * presents the flight as a crossfade (`flightOpacity` with `frozen`).\n */\nexport function capFlightStart(exact: CameraState, arrival: CameraState, vpW: number, vpH: number, maxOctaves: number, capFactor: number): { c0: CameraState; capped: boolean } {\n if (flightOctaves(exact, arrival) <= maxOctaves) return { c0: exact, capped: false };\n const zCap = exact.zoom > arrival.zoom ? arrival.zoom * capFactor : arrival.zoom / capFactor;\n return {\n c0: {\n x: exact.x + (vpW / 2) * (1 / exact.zoom - 1 / zCap),\n y: exact.y + (vpH / 2) * (1 / exact.zoom - 1 / zCap),\n zoom: zCap,\n },\n capped: true,\n };\n}\n\n/**\n * The flight path `c(p)`, p ∈ [0,1]: zoom log-lerped (constant perceived zoom\n * velocity); view CENTRE linear in 1/zoom — exactly an anchored zoom whenever\n * a fixed screen point exists between the endpoints, a graceful blend\n * otherwise. Endpoints are exact: c(0) = c0, c(1) = c1.\n */\nexport function flightCamera(c0: CameraState, c1: CameraState, p: number, vpW: number, vpH: number): CameraState {\n const zoom = Math.exp(Math.log(c0.zoom) + (Math.log(c1.zoom) - Math.log(c0.zoom)) * p);\n const inv0 = 1 / c0.zoom;\n const inv1 = 1 / c1.zoom;\n const inv = 1 / zoom;\n const w = Math.abs(inv1 - inv0) < 1e-12 ? p : (inv - inv0) / (inv1 - inv0);\n const cx = c0.x + vpW * inv0 * 0.5 + (c1.x + vpW * inv1 * 0.5 - (c0.x + vpW * inv0 * 0.5)) * w;\n const cy = c0.y + vpH * inv0 * 0.5 + (c1.y + vpH * inv1 * 0.5 - (c0.y + vpH * inv0 * 0.5)) * w;\n return { x: cx - vpW * inv * 0.5, y: cy - vpH * inv * 0.5, zoom };\n}\n\n/**\n * One step of the critically-damped progress spring toward 1, in CLOSED FORM:\n * with u = 1 − p, the exact solution is `u(t) = (u₀ + Bt)·e^(−ωt)`,\n * `B = −v₀ + ω·u₀`. Unconditionally stable at ANY dt. From rest (v = 0) the\n * approach is monotonic: p never overshoots 1.\n */\nexport function springStep(p: number, v: number, omega: number, dtSec: number): { p: number; v: number } {\n const u = 1 - p;\n const B = -v + omega * u;\n const decay = Math.exp(-omega * dtSec);\n const u2 = (u + B * dtSec) * decay;\n const du2 = (B - omega * (u + B * dtSec)) * decay;\n return { p: 1 - u2, v: -du2 };\n}\n\n/** Zoom-to-fit `content` with `pad` (world units), the zoom clamped into a band (kernel coords.ts). */\nexport function fitCamera(content: Rect, vpW: number, vpH: number, opts: { pad: number; minZoom: number; maxZoom: number }): CameraState {\n const fit = Math.min(vpW / (content.width + opts.pad * 2), vpH / (content.height + opts.pad * 2));\n const zoom = Math.min(opts.maxZoom, Math.max(opts.minZoom, fit));\n return { x: content.x + content.width / 2 - vpW / (2 * zoom), y: content.y + content.height / 2 - vpH / (2 * zoom), zoom };\n}\n\n// ---------------------------------------------------------------- the product's numbers\n\n/** `@ice/core` NAV_TRANSITION_DEFAULTS — the response the product flies at. */\nexport const NAV = {\n responseMs: 420,\n exitResponseFactor: 0.8,\n durationPerOctave: 0.12,\n baseOctaves: 3.5,\n freezeOctaves: 4.2,\n capFactor: 10,\n settleP: 0.999,\n settleV: 0.02,\n} as const;\nexport type FlightTuning = { readonly [K in keyof typeof NAV]: number };\n\n/** `@ice/core` FIT_DEFAULTS — the NATURAL band an arrival is framed into (design-006, amended 2026-07-18). */\nexport const FIT = { pad: 80, minZoom: 0.5, maxZoom: 1 } as const;\nexport type FitBand = { readonly [K in keyof typeof FIT]: number };\n\n// ---------------------------------------------------------------- the opacity story\n\nexport type NavKind = \"enter\" | \"exit\";\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst smooth = (v: number): number => { const x = clamp01(v); return x * x * (3 - 2 * x); };\nconst ramp = (v: number, from: number, to: number): number => (to <= from ? (v >= to ? 1 : 0) : smooth((v - from) / (to - from)));\n\n/**\n * The departing and arriving presentations' opacity at progress `p` — ICE\n * core `opacityAt`, verbatim. Enter: the parent holds until p ≈ 0.3 and is\n * gone by 0.75 (most of it has physically left the viewport by then). Exit:\n * the inner frame holds to 0.85 and fades as it lands on the card face. A\n * FROZEN (depth-capped) flight is a crossfade: out 0.05→0.45, in 0.3→0.7.\n */\nexport function flightOpacity(kind: NavKind, p: number, frozen: boolean): { readonly outgoing: number; readonly incoming: number } {\n if (frozen) return { outgoing: 1 - ramp(p, 0.05, 0.45), incoming: ramp(p, 0.3, 0.7) };\n return { outgoing: kind === \"enter\" ? 1 - ramp(p, 0.3, 0.75) : 1 - ramp(p, 0.85, 1), incoming: 1 };\n}\n\n// ---------------------------------------------------------------- a flight, as a host drives it\n\n/**\n * One in-flight transition — what ICE keeps in its `NavTransition` resource,\n * minus the ECS. The host owns the clock: `stepFlight` each frame until\n * `active` clears, `flightAt` for a pinned still.\n */\nexport interface Flight {\n readonly kind: NavKind;\n /** A: departed-frame coords → destination-frame coords. */\n readonly affine: PortalAffine;\n /** The departed frame's camera at the cut — what it renders under at p = 0, and throughout a frozen flight. */\n readonly camPre: CameraState;\n readonly c0: CameraState;\n readonly c1: CameraState;\n /** Depth-capped: present as a crossfade (`flightOpacity`). */\n readonly frozen: boolean;\n /** Response multiplier from octave distance, locked at start (§4). */\n readonly durMul: number;\n p: number;\n v: number;\n active: boolean;\n}\n\n/**\n * Arm a flight from the already-cut world: `camPre` the departed frame's\n * camera at the cut (the continuity solve gives c0 in destination coords),\n * `c1` the clamped arrival. Applies the depth cap and the octave response.\n * The host snaps its camera to `flight.c0`.\n */\nexport function startFlight(kind: NavKind, A: PortalAffine, camPre: CameraState, c1: CameraState, vp: Viewport, tune: FlightTuning = NAV, exact: CameraState = solveFlightStart(A, camPre)): Flight {\n // `exact`: the start the continuity solve gives — or, from a LIVE PORTAL (PORTAL.md §2.4), the camera the\n // inside was already rendering under (`outgoingCamera(M, camPre)`, the same number to within an ulp), so\n // the arriving slot's first frame is the portal's last frame bit for bit.\n const { c0, capped } = capFlightStart(exact, c1, vp.width, vp.height, tune.freezeOctaves, tune.capFactor);\n const octaves = flightOctaves(c0, c1);\n return { kind, affine: A, camPre, c0, c1, frozen: capped, durMul: 1 + tune.durationPerOctave * Math.max(0, octaves - tune.baseOctaves), p: 0, v: 0, active: true };\n}\n\n/**\n * The camera the DEPARTED frame renders under this frame. Riding the flight\n * through the affine (`outgoingCamera`) — except at the cut itself, where it\n * is the pre-cut camera bit for bit (the affine and its inverse round-trip to\n * within an ulp, and at zoom 1 an ulp is the other side of a decade), and\n * throughout a FROZEN flight, where the departed frame stays at its pre-cut\n * appearance and fades (design-006 §5: the cap broke the geometry, so the\n * story is a dissolve, not a portal).\n */\nexport function departedCamera(f: Flight, cam: CameraState): CameraState {\n if (f.frozen || (cam.x === f.c0.x && cam.y === f.c0.y && cam.zoom === f.c0.zoom)) return f.camPre;\n return outgoingCamera(f.affine, cam);\n}\n\n/** Advance the spring by `dtSec`; returns the camera for this frame. Lands EXACTLY on c1 and clears `active` at settle. */\nexport function stepFlight(f: Flight, dtSec: number, vp: Viewport, tune: FlightTuning = NAV): CameraState {\n if (!f.active) return f.c1;\n const responseMs = tune.responseMs * (f.kind === \"exit\" ? tune.exitResponseFactor : 1) * f.durMul;\n const omega = (2 * Math.PI) / (responseMs / 1000);\n const { p, v } = springStep(f.p, f.v, omega, dtSec);\n if (p > tune.settleP && Math.abs(v) < tune.settleV) { f.p = 1; f.v = 0; f.active = false; return f.c1; }\n f.p = p; f.v = v;\n return flightCamera(f.c0, f.c1, clamp01(p), vp.width, vp.height);\n}\n\n/** The camera at progress `p` — a pinned still (the oracle's scenes, the harness's shots). The endpoints are c0 and c1 themselves, bit for bit. */\nexport function flightAt(f: Flight, p: number, vp: Viewport): CameraState {\n if (p <= 0) return f.c0;\n if (p >= 1) return f.c1;\n return flightCamera(f.c0, f.c1, p, vp.width, vp.height);\n}\n\n// ---------------------------------------------------------------- the two nav ops, as geometry\n\n/** The bounds of some rects, or null when there are none. */\nexport function boundsOf(rects: readonly Rect[]): Rect | null {\n if (rects.length === 0) return null;\n let x0 = Number.POSITIVE_INFINITY;\n let y0 = Number.POSITIVE_INFINITY;\n let x1 = Number.NEGATIVE_INFINITY;\n let y1 = Number.NEGATIVE_INFINITY;\n for (const r of rects) { x0 = Math.min(x0, r.x); y0 = Math.min(y0, r.y); x1 = Math.max(x1, r.x + r.width); y1 = Math.max(y1, r.y + r.height); }\n return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };\n}\n\n/**\n * The DEFAULT framing for a frame (design-006 as amended): zoom-to-fit its\n * content capped into the natural band; an empty frame arrives centred on\n * its origin at zoom 1.\n */\nexport function arrivalCamera(content: Rect | null, vp: Viewport, fit: FitBand = FIT): CameraState {\n if (content === null) return { x: -vp.width / 2, y: -vp.height / 2, zoom: 1 };\n return fitCamera(content, vp.width, vp.height, fit);\n}\n\n/** A flight that is already over — what a degenerate portal (no area) gets: the host snaps to the arrival, as ICE's rect-less link \"degrades the whole jump to a snap — never half-fly\". */\nexport function cutFlight(kind: NavKind, camPre: CameraState, c1: CameraState): Flight {\n return { kind, affine: { s: 1, ox: 0, oy: 0 }, camPre, c0: c1, c1, frozen: false, durMul: 1, p: 1, v: 0, active: false };\n}\nconst hasArea = (K: Rect): boolean => K.width > 0 && K.height > 0;\n\n/**\n * ENTER a container whose body rect is `K` (parent coords) holding `content`\n * (child coords): the arrival is the child's default framing, the portal maps\n * that arrival onto K, and the flight starts where the parent was. The host\n * switches frames, snaps its camera to `flight.c0`, then steps.\n */\nexport function enterFlight(K: Rect, content: Rect | null, camPre: CameraState, vp: Viewport, tune: FlightTuning = NAV, fit: FitBand = FIT, exact?: CameraState): Flight {\n const c1 = arrivalCamera(content, vp, fit);\n if (!hasArea(K)) return cutFlight(\"enter\", camPre, c1);\n const A = invertAffine(portalAffine(visibleRect(c1, vp.width, vp.height), K));\n return startFlight(\"enter\", A, camPre, c1, vp, tune, exact ?? solveFlightStart(A, camPre));\n}\n\n/**\n * EXIT to the parent: the portal is rebuilt from the container's CURRENT rect\n * `K` and the inner frame's default framing (so arrival and preview agree),\n * and the landing is the camera saved at entry. `camPre` is the inner camera\n * at the cut.\n */\nexport function exitFlight(K: Rect, inner: Rect | null, camPre: CameraState, saved: CameraState, vp: Viewport, tune: FlightTuning = NAV, fit: FitBand = FIT): Flight {\n if (!hasArea(K)) return cutFlight(\"exit\", camPre, saved);\n const M = portalAffine(visibleRect(arrivalCamera(inner, vp, fit), vp.width, vp.height), K);\n return startFlight(\"exit\", M, camPre, saved, vp, tune);\n}\n","// The two easings the marks move on (DESIGN.md §6 by name; *Marks on the Mat*'s chrome.js `easeLift` /\n// `easeIsland`, number for number): `--vf-ease-lift` cubic-bezier(0.2, 0.9, 0.3, 1.2) — the lock-on's\n// arrival and the tape's press, with a slight overshoot — and `--vf-ease-island` cubic-bezier(0.25, 1,\n// 0.3, 1) — the vellum's fold. A CSS cubic-bezier solved for x by eight Newton steps, as the page does.\n\nconst clamp01 = (x: number): number => Math.min(Math.max(x, 0), 1);\n\nfunction bezier(x1: number, y1: number, x2: number, y2: number, x: number): number {\n if (x <= 0) return 0;\n if (x >= 1) return 1;\n let t = x;\n for (let i = 0; i < 8; i++) {\n const cx = 3 * x1 * t * (1 - t) ** 2 + 3 * x2 * t * t * (1 - t) + t ** 3 - x;\n const dx = 3 * x1 * (1 - t) ** 2 + 6 * (x2 - x1) * t * (1 - t) + 3 * (1 - x2) * t * t;\n if (Math.abs(dx) < 1e-6) break;\n t = clamp01(t - cx / dx);\n }\n return 3 * y1 * t * (1 - t) ** 2 + 3 * y2 * t * t * (1 - t) + t ** 3;\n}\n\n/** `--vf-ease-lift`: cubic-bezier(0.2, 0.9, 0.3, 1.2) — overshoots past 1 on the way. */\nexport const easeLift = (x: number): number => bezier(0.2, 0.9, 0.3, 1.2, x);\n/** `--vf-ease-island`: cubic-bezier(0.25, 1, 0.3, 1). */\nexport const easeIsland = (x: number): number => bezier(0.25, 1, 0.3, 1, x);\n","// THE HAND'S POSE (design-015 §8; D4b) — *Marks on the Mat* v2's Opening, desk.js `HOLD` · `heldTarget` ·\n// `heldPose`, number for number, as pure math the builder, the pose seam, the oracle and the units all read.\n//\n// An object is picked up INTO THE HAND: no camera move. Its OPEN EXTENT (the kind's `open.extent`: a\n// spread twice the case's width left of the spine, a board's face, a pad's month) comes to the middle of\n// the view at its READING SIZE — one rule for every object: the extent fits the view with `margin` clear at\n// the sides and top and the bar's `band` below, never past `max` — whatever the zoom you were at. Between\n// the desk and the hand the pose is ONE curve: the position on the island ease, the size in LOG scale (the\n// flight's zoom law: a book picked up from far out grows evenly), the tilt let go. The user's `zoom` (0.72 …\n// 3, about the pointer) and `pan` ride on the reading pose. On a portrait phone a spread opens one page at a\n// time (Q-p): the right page centred, the left waiting at the edge.\n//\n// THE POSE IS A CAMERA (the plan's D4b ruling): a flat kind is drawn by its own pass, at rest, under a\n// camera that maps its extent to the held rect — `heldCamera` — no per-kind pose code. A kind with height\n// (the notebook, `open.pose: \"eye\"`) keeps the desk's zoom under that camera and RISES toward the desk eye\n// by `grow` instead: a point `z` up projects by H/(H − z), so z = H·(1 − 1/grow) reads at `grow` times its\n// size (the page's engine plan: \"posed under the desk eye, rising to H·(1 − 1/s)\").\n\nimport { easeIsland } from \"../marks/ease\";\nimport type { ObjectRect } from \"../kinds/world\";\nimport { DAY_LIGHT, type MatLight, mixLight } from \"../mat/night\";\nimport type { CameraState } from \"../nav/flight\";\n\n/** The hand's numbers (desk.js `HOLD`). Times in ms; `margin`/`top`/`band` CSS px; `blur` CSS px; `narrow` = a phone's width. */\nexport const HOLD = {\n inMs: 560, outMs: 440, closeLead: 0.14, openAt: 0.42,\n blur: 14, blurPhone: 10, dim: 0.08,\n margin: 56, marginPhone: 16, top: 56, topPhone: 60, band: 72,\n max: 3, zoomMin: 0.72, zoomMax: 3,\n narrow: 640,\n /** The reading light by night (Q-n): the held object keeps its day light, filtered. */\n light: { saturate: 0.62, brightness: 0.82 },\n /** The cover's spring in hand (desk.js `COVER`): a palm, not a desk. */\n cover: { hz: 1.4, zeta: 0.78 },\n /** The held bar's travel (M1 morph) and its return after the landing — `travelMs` the default of a host's `hold.travelMs` (I20). */\n bar: { travelMs: 340, backMs: 200 },\n} as const;\n\n/**\n * THE HAND'S RESERVES (petition I20): how far the reading fit keeps from the view's top (`top`) and from its foot (`band` — the held\n * bar's band), CSS px. `HOLD`'s are the default; a host's chrome moves them (`deskLayer({ hold })`). A phone keeps its own top.\n */\nexport interface HoldReserves {\n readonly top: number;\n readonly band: number;\n}\n\n/**\n * The hand as a HOST sets it (petition I20 — `deskLayer({ hold })`, read at the mount): the reserves above and below the reading fit,\n * CSS px, and the held bar's travel (M1), ms — each `HOLD`'s when absent (`top` 56, `band` 72, `travelMs` 340). The bar is the host's:\n * the desk publishes the travel on the selection's anchor (`HeldAnchor.travelMs`) for whichever bar draws it.\n */\nexport interface HoldOptions {\n readonly top?: number;\n readonly band?: number;\n readonly travelMs?: number;\n}\n\nexport interface HeldViewport { readonly width: number; readonly height: number }\n\n/** The reading pose's target: where the open extent's centre goes on screen (CSS px), the scale there (CSS px per object unit), one page or the spread. */\nexport interface ReadingTarget {\n readonly cx: number;\n readonly cy: number;\n readonly s: number;\n readonly single: boolean;\n}\n\n/** A phone's width (desk.js `narrow`). */\nexport const isNarrow = (vp: HeldViewport): boolean => vp.width < HOLD.narrow;\n\n/**\n * The reading size (desk.js `heldTarget`): the extent fits the view inside the margins, `reserves.top` under its top and the bar's\n * band (`reserves.band`) above its foot, never past 3× — the host's reserves (I20), `HOLD`'s by default; a phone keeps its own top\n * and margins. `spread`: the extent is a two-page spread that may open one page at a time — on a portrait phone (W < 0.85·H) it\n * does when one page reads at least 1.3× larger than the whole spread would; then the RIGHT page is centred (the extent's centre sits\n * a quarter of its width left of the middle) — or, `face` → 1, the LEFT (D3t-b: the notebook reads page by page; between, the view\n * glides). That decision is the PHONE'S, on `HOLD`'s band whatever the host reserves, so a kind that asks it alone\n * (`readingTarget(extent, vp, true).single`) agrees with the hand; the reserves size the page it shows.\n */\nexport function readingTarget(extent: ObjectRect, vp: HeldViewport, spread = false, face = 0, reserves: HoldReserves = HOLD): ReadingTarget {\n const narrow = isNarrow(vp);\n const m = narrow ? HOLD.marginPhone : HOLD.margin;\n const top = narrow ? HOLD.topPhone : reserves.top;\n const boxW = Math.max(40, vp.width - 2 * m);\n const boxH = Math.max(40, vp.height - top - reserves.band);\n let s = Math.min(boxW / extent.w, boxH / extent.h, HOLD.max);\n let single = false;\n if (spread && narrow && vp.width < vp.height * 0.85) {\n const own = Math.max(40, vp.height - top - HOLD.band);\n const s0 = Math.min(boxW / extent.w, own / extent.h, HOLD.max);\n if (Math.min(boxW / (extent.w / 2), own / extent.h, HOLD.max) > s0 * 1.3) { s = Math.min(boxW / (extent.w / 2), boxH / extent.h, HOLD.max); single = true; }\n }\n return { cx: vp.width / 2 - (single ? (extent.w / 4) * s * (1 - 2 * face) : 0), cy: top + boxH / 2, s, single };\n}\n\n/** Where the extent lies on screen at rest, under the desk's camera: its centre (CSS px), the scale (the zoom) and the object's turn. */\nexport interface HomePose { readonly cx: number; readonly cy: number; readonly s: number; readonly angle: number }\n\nexport function homePose(extent: ObjectRect, angle: number, cam: CameraState): HomePose {\n return { cx: (extent.cx - cam.x) * cam.zoom, cy: (extent.cy - cam.y) * cam.zoom, s: cam.zoom, angle };\n}\n\n/** The user's facts on the held object (core's `HeldView`). */\nexport interface HeldUser { readonly zoom: number; readonly panX: number; readonly panY: number }\nexport const HELD_USER_REST: HeldUser = { zoom: 1, panX: 0, panY: 0 };\n\n/** The pose between the desk and the hand: the extent's centre on screen, CSS px per unit, the turn, the carry amount. */\nexport interface HeldPose { readonly cx: number; readonly cy: number; readonly s: number; readonly angle: number; readonly e: number }\n\n/** desk.js `heldPose`: position on the island curve (the caller eases `e`), size in log scale, the tilt let go. */\nexport function heldPose(home: HomePose, target: ReadingTarget, user: HeldUser, e: number): HeldPose {\n const s1 = target.s * user.zoom;\n const s = Math.exp(Math.log(Math.max(home.s, 1e-9)) + (Math.log(Math.max(s1, 1e-9)) - Math.log(Math.max(home.s, 1e-9))) * e);\n return { cx: home.cx + (target.cx + user.panX - home.cx) * e, cy: home.cy + (target.cy + user.panY - home.cy) * e, s, angle: home.angle * (1 - e), e };\n}\n\n/** The carry amount for the pickup's progress `p` (0 … 1) — the island ease; the put-down runs it backwards from where it was. */\nexport const carryOf = (p: number): number => easeIsland(Math.min(Math.max(p, 0), 1));\n\n/** The pickup's progress at a carry amount — the island ease inverted by bisection (a put-down caught mid-flight, a pinned still). */\nexport function progressOf(e: number): number {\n if (e <= 0) return 0;\n if (e >= 1) return 1;\n let lo = 0;\n let hi = 1;\n for (let i = 0; i < 40; i++) { const mid = (lo + hi) / 2; if (carryOf(mid) < e) lo = mid; else hi = mid; }\n return (lo + hi) / 2;\n}\n\n/** The focus behind the hand and the light on it at a carry amount (the builder's and the oracle's ONE reading of §8's numbers). */\nexport interface HeldFocus {\n /** The radius the ONE blur is made at, CSS px (14; a phone's 10). */\n readonly blur: number;\n /** The desk's dim behind, by the carry (8 % at the top). */\n readonly dim: number;\n /** The reading light on the hand (Q-n): 1, 1 by day; toward saturate .62 · brightness .82 by night as the carry rises. */\n readonly filter: { readonly saturate: number; readonly brightness: number };\n /** The hand's own light: the desk's by day; by night the day's mixed in by the carry. */\n readonly light: MatLight;\n}\n\nexport function heldFocus(e: number, vp: HeldViewport, theme: { readonly name: string; readonly matLight: MatLight }): HeldFocus {\n const night = theme.name === \"dark\";\n return {\n blur: isNarrow(vp) ? HOLD.blurPhone : HOLD.blur,\n dim: HOLD.dim * e,\n filter: night ? { saturate: 1 - (1 - HOLD.light.saturate) * e, brightness: 1 - (1 - HOLD.light.brightness) * e } : { saturate: 1, brightness: 1 },\n light: night ? mixLight(theme.matLight, DAY_LIGHT, e) : theme.matLight,\n };\n}\n\n/**\n * The held slot's CAMERA (the pose IS a camera) and the factor a kind with height must reach by rising. The object's rect centre\n * lies `offset` (its own units, unturned) from its extent's centre; the pose turns that offset by its angle and puts the extent's\n * centre at (pose.cx, pose.cy), so the rect's centre lands at P − R(angle)·offset·s. A flat kind's camera zooms to `pose.s` and\n * grows nothing; an `eye` kind keeps the desk's zoom when the pose is larger (grow = pose.s / zoom ≥ 1, the rise does the rest)\n * and zooms out with the camera when the pose is smaller (a book picked up from very close: grow 1).\n */\nexport function heldCamera(pose: HeldPose, rect: ObjectRect, extent: ObjectRect, deskZoom: number, eye: boolean, vp: HeldViewport): { readonly cam: CameraState; readonly grow: number } {\n const zoom = eye ? Math.min(deskZoom, pose.s) : pose.s;\n const grow = pose.s / zoom;\n const ox = rect.cx - extent.cx;\n const oy = rect.cy - extent.cy;\n const c = Math.cos(pose.angle);\n const sn = Math.sin(pose.angle);\n // the rect's centre on screen\n const sx = pose.cx + (c * ox - sn * oy) * pose.s;\n const sy = pose.cy + (sn * ox + c * oy) * pose.s;\n if (!eye || grow <= 1 + 1e-9) return { cam: { x: rect.cx - sx / zoom, y: rect.cy - sy / zoom, zoom }, grow: 1 };\n // the eye stands over the VIEW's centre: a point at the rising height lands at E + (p − E)·grow on the desk plane, so the eye's foot\n // must be E = c − (S − vw/2)/(grow·zoom), and the camera's corner is E − vw/(2·zoom)\n const ex = rect.cx - (sx - vp.width / 2) / (grow * zoom);\n const ey = rect.cy - (sy - vp.height / 2) / (grow * zoom);\n return { cam: { x: ex - vp.width / (2 * zoom), y: ey - vp.height / (2 * zoom), zoom }, grow };\n}\n\n/**\n * The held object's frame ON SCREEN (what the pose seam publishes, core's `HeldScreenFrame`): the shown extent's centre and half\n * extents, CSS px, its scale. `single`: one page alone — the right (`face` 0), the left (`face` 1), a glide between (D3t-b).\n */\nexport function heldFrame(pose: HeldPose, extent: ObjectRect, single: boolean, face = 0): { readonly cx: number; readonly cy: number; readonly hx: number; readonly hy: number; readonly s: number } {\n if (!single) return { cx: pose.cx, cy: pose.cy, hx: (extent.w / 2) * pose.s, hy: (extent.h / 2) * pose.s, s: pose.s };\n // one page: a half of the spread, centred a quarter-width right (the right page) or left (the left) of the extent's centre, turned with the pose\n const half = (extent.w / 4) * pose.s;\n const q = half * (1 - 2 * face);\n return { cx: pose.cx + q * Math.cos(pose.angle), cy: pose.cy + q * Math.sin(pose.angle), hx: half, hy: (extent.h / 2) * pose.s, s: pose.s };\n}\n\n/** The focus behind the hand: the blur radius (CSS px) and the dim at a carry amount. */\nexport const focusOf = (e: number, vp: HeldViewport): { readonly blur: number; readonly dim: number } => ({ blur: (isNarrow(vp) ? HOLD.blurPhone : HOLD.blur) * e, dim: HOLD.dim * e });\n","// A CONTAINER's inside, as the contract names it (design-015 §5.2 `chip` · `InsideContext`; moved here from minimat/ at\n// K4a, design-016 §5): the view a host has of the desk a container holds — its embedding, the camera it renders under,\n// its face on screen, the gate's answer — and a child as that face's far LOD draws it (a CHIP). The mini mat is the\n// container that makes them (minimat/inside.ts, `chipOf`); the builder hands them to a kind's `record` and `chip`. Pure\n// types: the contract (kinds/world.ts) names them, so they live where no kind folder is imported to reach them.\n//\n// And the ONE LAW every container's inside is built by (moved here from minimat/inside.ts at K4b, design-016 §5 — the builder\n// nests every container by it, so it cannot be the mini mat's alone): the view through a face (`insideViewOfFace`), the live\n// inside's presentation at rest, a flight's presentations and the lamps it hands between the two desks, the face's clip radius\n// and its chip cap.\n\nimport type { Box } from \"../lattice/lod\";\nimport type { SlotLight } from \"../mat/layout\";\nimport { arrivalCamera, type CameraState, FIT, type FitBand, type Flight, flightOpacity, outgoingCamera, type PortalAffine, portalAffine, type Rect, type Viewport, visibleRect } from \"../nav/flight\";\nimport { boxOfPortal, clipOf, PORTAL_GATE, type PortalClip, portalPresence, type Presentation } from \"../nav/portal\";\nimport type { RGB } from \"../theme\";\n\n/** A container's inside under the host camera (MINIMAT.md §3–§5): what `insideView` answers — ALWAYS, past the gate or not. */\nexport interface InsideView {\n /** The embedding: inside → host (`host = o + inside · s`) — the flight's own. */\n readonly M: PortalAffine;\n /** The inside's arrival camera — what its lattice is DRESSED for (PORTAL.md §9). */\n readonly arrival: CameraState;\n /** The camera the inside renders under at the host's camera: the enter flight's c0 at the cut. */\n readonly cam: CameraState;\n /** The face on screen: the live inside's clip. */\n readonly clip: PortalClip;\n /** The gate's answer (0..1): the live inside's presence — 0 = the face is the far LOD alone. */\n readonly presence: number;\n /** The live inside's box on the attachment. */\n readonly box: Box;\n}\n\n/**\n * The FINISH a container's face draws a child's chip in (K8a — open: until K8a a chip was a `ChipKind`, `\"paper\" | \"mat\"`, the two\n * built-ins' own names, so no plugin kind could have one): a name among the container's `FaceLaw.finishes` — the mini mat draws\n * `\"paper\"` (a sheet in the chip's colour, its writing greeked) and `\"vinyl\"` (grained, its frame line at `margin`) — and a plugin\n * container draws its own. A chip names one, or several in preference order; the first the container draws wins, and a chip the\n * container draws none of is not drawn (the builder counts it: `BuildWork.unchipped`) — never a finish it did not ask for.\n */\nexport type ChipFinish = string;\n/** The two finishes the kit names — a chip's shared vocabulary (a note's `paper`, a mini mat's `vinyl`); a container may draw more. */\nexport const PAPER_FINISH: ChipFinish = \"paper\";\nexport const VINYL_FINISH: ChipFinish = \"vinyl\";\n\n/** One child as the face's far LOD draws it, in the CHILD's frame (the inside's world). */\nexport interface ChildShape {\n /** Its finish (`ChipFinish`) — or finishes, in preference order; the builder hands the container the one it draws. */\n readonly finish: ChipFinish | readonly ChipFinish[];\n readonly cx: number; readonly cy: number;\n /** Half extents, the tilt (radians), the corner radius — the child's own. */\n readonly hx: number; readonly hy: number;\n readonly angle: number;\n readonly radius: number;\n /** Its colour: the paper's, or the vinyl's. */\n readonly colour: RGB;\n /** How far it stands off the face, child units — what its contact shadow is cast from. */\n readonly height: number;\n /** A note's writing, GREEKED: the pen's colour, the text's left edge and em (note units from the sheet's top-left), and each line's baseline and width. */\n readonly writing?: { readonly ink: RGB; readonly x0: number; readonly em: number; readonly lines: readonly { readonly y: number; readonly width: number }[] } | undefined;\n /** A mini mat's printed border, child units. */\n readonly margin?: number | undefined;\n}\n\n/**\n * A CONTAINER kind's FACE LAW (K8a — the container's own, declared on its kind as `ObjectKind.faceLaw`; until K8a `FACE_RADIUS` and\n * `FACE_CHIPS_MAX` were the kit's, the mini mat's numbers imposed on every container): the corner its face clips its inside by (the\n * live inside, the far LOD, a flight through it — `clipOf(face, radius, cam)`), the most chips its face draws, and the chip finishes\n * it draws them in. Absent on a kind with a `face`: square, and no chips.\n */\nexport interface FaceLaw {\n readonly radius: number;\n readonly chips: number;\n readonly finishes: readonly ChipFinish[];\n}\n\n/** The finish a container draws a chip in: the chip's first that the container draws, or undefined — none (the chip is not drawn). */\nexport function finishOf(finish: ChipFinish | readonly ChipFinish[], drawn: readonly ChipFinish[]): ChipFinish | undefined {\n if (typeof finish === \"string\") return drawn.includes(finish) ? finish : undefined;\n return (finish as readonly ChipFinish[]).find((f) => drawn.includes(f));\n}\n\n/**\n * The same view from a FACE rect and its corner alone (D2b; the corner the container's own since K8a — `FaceLaw.radius`): what a\n * kind's `face(geometry)` hands the builder, so any container kind's inside is built by the one law — the mini mat's `faceClip` is\n * `clipOf(faceOf(G), its radius, cam)`, so the numbers are its `insideView`'s to the bit.\n */\nexport function insideViewOfFace(K: Rect, radius: number, content: Rect | null, cam: CameraState, vp: Viewport, fit: FitBand = FIT, gate: readonly [number, number] = PORTAL_GATE): InsideView | null {\n if (!(K.width > 0) || !(K.height > 0)) return null;\n const clip = clipOf(K, radius, cam);\n const arrival = arrivalCamera(content, vp, fit);\n const M = portalAffine(visibleRect(arrival, vp.width, vp.height), K);\n return { M, arrival, cam: outgoingCamera(M, cam), clip, presence: portalPresence(clip, gate), box: boxOfPortal(clip, vp) };\n}\n\n/** The live inside's presentation at rest: through its face, its mat whole, its objects at the gate's answer (MINIMAT.md §5). */\nexport const insidePresent = (view: InsideView): Presentation => ({ opacity: 1, objects: view.presence, portal: view.clip });\n\n/**\n * The presentations of a flight through a mini mat's face: `flightOpacity` as ever, and — on an\n * ENTER — the arriving desk's objects at the gate's answer for the face as it is this frame, so\n * a mini mat entered from its far LOD grows through the gate on the way in and its chips give way\n * to its objects as it does (the arriving desk's mat is whole from the cut: the same lattice as\n * the face's, by the same lamp). An exit keeps its objects whole and lands on whatever the face\n * shows at the landing (the old landing fade). A frozen flight is a dissolve.\n */\n/** What the flight helpers read of a flight: its kind, its progress, whether it is frozen — the prototype's `Flight` or core's `NavTransition` alike. */\nexport type FlightState = Pick<Flight, \"kind\" | \"p\" | \"frozen\">;\n\nexport function flightPresent(f: FlightState, clip: PortalClip | undefined, gate: readonly [number, number] = PORTAL_GATE): { readonly incoming: Presentation; readonly outgoing: Presentation } {\n const op = flightOpacity(f.kind, f.p, f.frozen);\n if (f.frozen || !clip) return { incoming: { opacity: op.incoming }, outgoing: { opacity: op.outgoing } };\n if (f.kind === \"enter\") return { incoming: { opacity: op.incoming, objects: portalPresence(clip, gate), portal: clip }, outgoing: { opacity: op.outgoing } };\n return { incoming: { opacity: op.incoming }, outgoing: { opacity: op.outgoing, portal: clip } };\n}\n\n/**\n * When a flight hands the lamp over, as progress windows. ENTER hands it over once the departed\n * desk starts to go (flightOpacity: it holds to 0.3) — until then the frame IS the rest frame\n * under the departed camera; an EXIT hands it back in its first half — from then on the frame IS\n * the rest frame under the flying camera, the inside lit as a mini mat's inside is.\n */\nexport const HANDOVER = { enter: [0.3, 1], exit: [0, 0.5] } as const;\n/** Smooth at both ends; exactly 0 before the window and 1 after it. */\nconst ease = (p: number, [a, b]: readonly [number, number]): number => { const x = (p - a) / (b - a); return x <= 0 ? 0 : x >= 1 ? 1 : x * x * (3 - 2 * x); };\n\n/**\n * The LAMPS a flight hands between the two desks (MINIMAT.md §4). At rest a mini mat's inside is\n * lit by the desk the mini mat lies on; a desk the camera is on, by its own lamp. ENTER: the\n * arriving desk starts under the departed desk's lamp (`outCam` — at the cut, the portal's own\n * light, bit for bit) and ends under its own. EXIT: the departed desk starts under its own and\n * ends under the arriving desk's — the lamp its mini mat's inside is lit by at rest. A frozen\n * flight is two whole desks under their own lamps.\n */\nexport function flightLights(f: FlightState, cam: CameraState, outCam: CameraState): { readonly incoming?: SlotLight; readonly outgoing?: SlotLight } {\n if (f.frozen) return {};\n return f.kind === \"enter\" ? { incoming: { a: outCam, b: cam, t: ease(f.p, HANDOVER.enter) } } : { outgoing: { a: outCam, b: cam, t: ease(f.p, HANDOVER.exit) } };\n}\n","// THE LAMP over the desk (design-015 §2 — the gobo projector as a light every kind's shadow falls from). It lived in\n// paper/paper.ts as the note's first light; every kind's geometry takes it (the builder hands it to each resolve), so it is the\n// MAT's — moved here at D7 #5 (D-D7-A.3): the builder may not import a kind's module for what belongs to the desk.\n\nimport { HERO_PROJECTOR, type ProjectorSpec } from \"./projector\";\n\n/** The lamp over the desk in WORLD units: where it stands on the plane, and how high above it. */\nexport interface Lamp { readonly x: number; readonly y: number; readonly h: number }\n\n/** The gobo projector as a lamp on the world plane (mat.wgsl `desk_of` inverted: world = (desk − origin) / metresPerUnit). */\nexport function lampOf(plane: { readonly originX: number; readonly originZ: number; readonly metresPerUnit: number; readonly deskY: number }, p: ProjectorSpec = HERO_PROJECTOR): Lamp {\n const m = plane.metresPerUnit;\n return { x: (p.position[0] - plane.originX) / m, y: (p.position[2] - plane.originZ) / m, h: (p.position[1] - plane.deskY) / m };\n}\n","// THE SERVICES (design-016 §5 · K-L2, K8a): what a desk LENDS its kinds, as an OPEN registry by name. Until K8a `KindHost`\n// carried a fixed list — the text raster, the picture decoder, the byte store, and `print`, which WAS the desk calendar's raster\n// (lent to the calendar alone) — so a plugin kind could neither lend a service of its own nor use one another kind lent. Now a\n// service is an ENTRY under a typed KEY: the host lends its own (the text raster, the decoder, the byte store — `deskLayer`'s\n// options), an object's DOM half lends what only a browser can make (`defineObject({ host: { lend } })` — the calendar's print\n// raster), and every kind's world half `use`s any of them by key (`KindHost.use`).\n//\n// A key is a VALUE carrying its type (D-K8a.1): `serviceKey<T>(name)` — never a declaration-merged interface, which would have\n// to be augmented through the module a plugin imports (`@ice/desk` here, `@vibecook/ice/desk` published) and breaks when the\n// d.ts is bundled. Keys match by NAME, not identity: a kind may declare a key for a service another package lends without\n// importing that package (K-L1 — a kind names another only by a registry name), and two copies of one module agree. A name is\n// lent once per desk: a second lender is a mount error, never a silent winner.\n\n/** A service's KEY (K8a): its name — the registry's identity — and, as a phantom, the type of what is lent under it. */\nexport interface ServiceKey<T> {\n readonly name: string;\n /** Never set: carries `T` so `use(key)` answers the lent thing's own type. */\n readonly __service?: T;\n}\n\n/** A key for a service of type `T` under `name` — namespace a plugin's own (`\"clock.face\"`); the desk's are bare words. */\nexport const serviceKey = <T>(name: string): ServiceKey<T> => ({ name });\n\n/** One service as it is LENT: its key and the thing. Made by `service(key, value)`, which checks the pair's type. */\nexport interface Lent<T = unknown> {\n readonly key: ServiceKey<T>;\n readonly value: T;\n}\n\n/** An entry to lend: `service(PRINT_RASTER, printRaster({ text }))`. */\nexport const service = <T>(key: ServiceKey<T>, value: T): Lent<T> => ({ key, value });\n\n/** Where a service is found: `use(key)` answers what is lent under the key's name, or undefined — none on this desk. */\nexport interface Services {\n use<T>(key: ServiceKey<T>): T | undefined;\n}\n\n/**\n * What an object's DOM half is handed to LEND (K8a): what is lent so far, and the desk's WAKE — a service whose work LANDS later (a\n * face loaded, a picture decoded, a feed arrived) calls it when it does, so a sleeping loop steps and every kind is asked again (K7a's\n * law: nothing is polled at rest; what arrives outside a step says so). The kinds that read the service see the landing in their tick.\n */\nexport interface LendHost extends Services {\n wake(): void;\n}\n\n/** A registry of what has been lent so far (the desk layer's): `lend` adds entries — a name lent twice throws, naming both lenders. */\nexport interface ServiceRegistry extends Services {\n lend(entries: readonly Lent[], by: string): void;\n /** The names lent, in lending order (a rig's and a test's witness). */\n names(): readonly string[];\n}\n\nexport function createServices(entries: readonly Lent[] = [], by = \"the host\"): ServiceRegistry {\n const lent = new Map<string, { readonly value: unknown; readonly by: string }>();\n const registry: ServiceRegistry = {\n use: <T>(key: ServiceKey<T>): T | undefined => lent.get(key.name)?.value as T | undefined,\n lend(more, lender) {\n for (const { key, value } of more) {\n const had = lent.get(key.name);\n if (had !== undefined) throw new Error(`desk: the service \"${key.name}\" is lent twice — by ${had.by} and by ${lender} (a name is lent once per desk)`);\n if (value !== undefined) lent.set(key.name, { value, by: lender });\n }\n },\n names: () => [...lent.keys()],\n };\n registry.lend(entries, by);\n return registry;\n}\n","// (The kit's since K4a, design-016 §5 — moved from photo/blobs.ts: host services a kind `use`s — `BLOB_STORE`, `PICTURE_DECODER`, K8a.)\n//\n// A print's BYTES (design-015 D-D12; D3w): a picture is not a durable cell — strata has no bytes field,\n// and a photo is megabytes — so a print's durable props name its picture by the HASH of its bytes\n// (`blob`), and the bytes live in a store the APP provides: content-addressed, `put` answering the\n// hash, `get` the bytes and their media type. The desk never keeps bytes itself: the photo kind's\n// world half (kinds/photo.ts) asks the store for a print's blob the first time it meets the print,\n// decodes it — raw RGBA (the committed fixture, `RGBA_TYPE`) by itself, anything else through the\n// host's decoder (desk/host: `createImageBitmap`, the one DOM touch) — and makes the pass's\n// `Picture` (D-D3r-a.2: the picture handle is the pass's; its lifetime is the world half's).\n//\n// `createMemoryBlobStore` is the reference store — a Map in memory, what apps/desk hands the layer —\n// and `hashBytes` the name every store must give: SHA-256, lowercase hex, over the bytes alone.\n\nimport { type ServiceKey, serviceKey } from \"./services\";\n\n/** A blob as the store holds it: its bytes and its media type (`image/png`, `RGBA_TYPE`, …). */\nexport interface StoredBlob {\n readonly bytes: Uint8Array<ArrayBuffer>;\n readonly type: string;\n}\n\n/** The app's content-addressed byte store (D-D12): the desk names a blob by its hash; keeping the bytes is the app's. */\nexport interface BlobStore {\n /** Keep `bytes` (idempotent by content); resolves to their hash — the name a print's `blob` prop carries. */\n put(bytes: Uint8Array<ArrayBuffer>, type: string): Promise<string>;\n /** The blob under a hash, or undefined when the store has none (a peer's picture not arrived yet, a hash from another desk). */\n get(hash: string): Promise<StoredBlob | undefined>;\n}\n\n/** A picture ready for the pass: raw RGBA rows, or a source the device copies from (a browser's `ImageBitmap`) — closed once uploaded. */\nexport type DecodedPicture =\n | { readonly kind: \"rgba\"; readonly bytes: Uint8Array<ArrayBuffer>; readonly width: number; readonly height: number }\n | { readonly kind: \"source\"; readonly source: unknown; readonly width: number; readonly height: number; close?(): void };\n\n/** The host's decoder for an encoded blob, scaled so its long side is at most `max` texels; undefined when it cannot. */\nexport type PictureDecoder = (blob: StoredBlob, max: number) => Promise<DecodedPicture | undefined>;\n\n/** The app's byte store as a desk SERVICE (K8a, kit/services.ts — `deskLayer({ blobs })` lends it): `host.use?.(BLOB_STORE)`. */\nexport const BLOB_STORE: ServiceKey<BlobStore> = serviceKey<BlobStore>(\"blobs\");\n/** The host's picture decoder as a desk SERVICE (K8a — the layer lends `decodePicture` in a browser): `host.use?.(PICTURE_DECODER)`. */\nexport const PICTURE_DECODER: ServiceKey<PictureDecoder> = serviceKey<PictureDecoder>(\"decode\");\n\n/** Raw RGBA8 rows, row-major, no header — the one media type the desk decodes itself (its size is the print's `width` × `height`). */\nexport const RGBA_TYPE = \"image/x-ice-rgba\";\n\n/** The name a blob goes by: SHA-256 over its bytes, lowercase hex. */\nexport async function hashBytes(bytes: Uint8Array<ArrayBuffer>): Promise<string> {\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** The reference store: every blob in a Map, for the life of the page. */\nexport function createMemoryBlobStore(): BlobStore & { size(): number } {\n const blobs = new Map<string, StoredBlob>();\n return {\n async put(bytes, type) {\n const hash = await hashBytes(bytes);\n if (!blobs.has(hash)) blobs.set(hash, { bytes: bytes.slice(), type });\n return hash;\n },\n async get(hash) { return blobs.get(hash); },\n size: () => blobs.size,\n };\n}\n","// (The kit's since K4a, design-016 §5 — moved from paper/raster.ts: a host service a kind `use`s — `TEXT_RASTER`, K8a.)\n//\n// The TEXT RASTER seam (design-015 §6.1; D2c) — what the paper kind calls to turn a hand's layout\n// (text.ts, pure) into ink: the face's metrics for the layout, and the glyph boxes drawn as r8\n// coverage for the ink pages. DOM-free as a contract: the browser's implementation is\n// `desk/host/ink.ts` (Canvas2D on an OffscreenCanvas, the faces the app hands in — the prototype's\n// lab/ink.ts); the Node oracle has none and keeps its COMMITTED raster (a still pinned on its note),\n// so a desk without a text raster draws every sheet blank but the pinned ones, honestly.\n\nimport { type ServiceKey, serviceKey } from \"./services\";\nimport type { HandLayout, HandMetrics } from \"./text\";\n\n/** r8 coverage rows, row 0 at the top — what the ink pages take (`PaperPass.write`). */\nexport interface InkBitmap {\n readonly bytes: Uint8Array<ArrayBuffer>;\n readonly w: number;\n readonly h: number;\n}\n\nexport interface TextRaster {\n /**\n * The face's metrics in em (advances and kerning measured at 100 px, the box from the font's own\n * ascent and descent) — `undefined` while the face loads: a sheet waits, blank, rather than write\n * in a stand-in hand and re-write itself a moment later.\n */\n metrics(face: string): HandMetrics | undefined;\n /** Bumped whenever a face lands: every layout keyed by it is laid again (the prototype's `fontVersion`). */\n version(): number;\n /**\n * Tell `fn` whenever `version` moves — a face landed between frames (K7a: the desk wakes for it; a loop at rest polls no\n * version). Returns an unsubscribe. Absent (a fake, a raster with fixed faces): the version never moves on its own.\n */\n onVersion?(fn: () => void): () => void;\n /**\n * Draw a layout's glyphs for a `box` (note units) at `band` texels per note unit: each glyph in its\n * own frame — turned, scaled, at its pressure — over a faint stroke `bleed` note units wide (the pen's\n * spread), the canvas's alpha read back as coverage.\n */\n raster(layout: HandLayout, face: string, box: { readonly w: number; readonly h: number }, band: number, bleed: number): InkBitmap;\n}\n\n/** The app's text raster as a desk SERVICE (K8a, kit/services.ts — `deskLayer({ text })` lends it): `host.use?.(TEXT_RASTER)`. */\nexport const TEXT_RASTER: ServiceKey<TextRaster> = serviceKey<TextRaster>(\"text\");\n","// (The kit's since K4a, design-016 §5 — moved from paper/text.ts with the HAND's law it lays by, theme.ts's until\n// then: the note writes with it and the desk calendar prints with it, so it is shared, never borrowed.)\n//\n// The handwriting's LAYOUT — pure: no canvas, no font file. A host supplies\n// the face's metrics (advances and kerning in em, the ascent and descent) and\n// this lays a note's text into its writable box — wrapped at words, broken at\n// newlines — and gives every glyph its own hand: a small rotation, a rise off\n// the baseline, a size, a pressure, and the line's slow wander, all from a hash\n// of the glyph's own seed. So a note re-rastered at another zoom is the same\n// handwriting to the pixel, and a glyph typed before the next keeps its hand\n// when the host carries the seeds through an edit (lab/main.ts does). The\n// raster (lab/ink.ts) draws exactly these boxes; the caret sits at\n// `positions`; the tests pin the wrap and the determinism.\n\nexport interface HandMetrics {\n /** em above the baseline, em below — the face's own box. */\n readonly ascent: number;\n readonly descent: number;\n /** A glyph's advance, em. */\n advance(ch: string): number;\n /** Optional pair kerning, em (negative tightens). */\n kern?(a: string, b: string): number;\n}\n\n/** The hand's law (theme.ts `HAND`): the size in world units, and how far each glyph may stray. */\nexport interface HandLaw {\n /** The pen's size, world units (CSS px at zoom 1). */\n readonly size: number;\n /** Line pitch, × size. */\n readonly lineHeight: number;\n /** The margin the writing keeps from the paper's edge, world units. */\n readonly pad: number;\n readonly jitter: {\n /** Each glyph's tilt, ± radians. */\n readonly rot: number;\n /** Each glyph's rise off the baseline, ± em. */\n readonly rise: number;\n /** Each glyph's size, ± fraction. */\n readonly scale: number;\n /** The pen's pressure — the ink's presence — between these. */\n readonly press: readonly [number, number];\n };\n readonly wander: {\n /** The line's slow drift, ± em. */\n readonly amp: number;\n /** …over this many em along the line. */\n readonly period: number;\n };\n}\n\nexport interface HandGlyph {\n readonly ch: string;\n /** Its index in the text. */\n readonly index: number;\n /** The glyph's origin on its baseline, note units from the paper's top-left. */\n readonly x: number;\n readonly y: number;\n /** The advance it takes, note units. */\n readonly advance: number;\n readonly rot: number;\n readonly scale: number;\n readonly press: number;\n readonly line: number;\n}\n\nexport interface HandLine {\n /** Text indices [start, end). */\n readonly start: number;\n readonly end: number;\n /** The baseline, note units. */\n readonly y: number;\n readonly width: number;\n}\n\nexport interface HandLayout {\n readonly glyphs: readonly HandGlyph[];\n readonly lines: readonly HandLine[];\n /** The caret's place BEFORE each index (and after the last): x, baseline y — `2 × (text.length + 1)`. */\n readonly positions: Float32Array;\n /** The writing ran past the bottom margin. */\n readonly overflow: boolean;\n /** The em, and the caret's height above and below the baseline. */\n readonly em: number;\n readonly ascent: number;\n readonly descent: number;\n}\n\n/**\n * Four floats in [0, 1) from a glyph's seed and its character — a 32-bit mix\n * (Wang's hash twice, xorshift between) that changes wholly for a change of\n * one bit in either. Deterministic across hosts: only integer arithmetic.\n */\nexport function hashHand(seed: number, code: number): readonly [number, number, number, number] {\n let h = (Math.imul(seed | 0, 0x9e3779b1) ^ Math.imul(code | 0, 0x85ebca77)) >>> 0;\n const out: number[] = [];\n for (let i = 0; i < 4; i++) {\n h = (h ^ (h >>> 16)) >>> 0; h = Math.imul(h, 0x7feb352d) >>> 0;\n h = (h ^ (h >>> 15)) >>> 0; h = Math.imul(h, 0x846ca68b) >>> 0;\n h = (h ^ (h >>> 16)) >>> 0;\n out.push(h / 4294967296);\n h = (h + 0x6d2b79f5) >>> 0;\n }\n return out as unknown as readonly [number, number, number, number];\n}\n\n/** A glyph's seed when the host carries none: the note's seed and the glyph's place. */\nexport const glyphSeed = (noteSeed: number, index: number): number => (Math.imul(noteSeed | 0, 0x27d4eb2f) + Math.imul(index + 1, 0x165667b1)) | 0;\n\n/**\n * Lay `text` into a `box` (note units) under `law` with the face's `metrics`.\n * `seeds[i]` is glyph i's own seed (the host's, carried through edits) — absent,\n * it is derived from `noteSeed` and the index.\n */\nexport function layoutText(text: string, box: { readonly w: number; readonly h: number }, law: HandLaw, metrics: HandMetrics, noteSeed = 1, seeds?: ArrayLike<number>): HandLayout {\n const em = law.size;\n const lineH = law.lineHeight * em;\n const x0 = law.pad;\n const xMax = Math.max(box.w - law.pad, x0 + 1);\n const yMax = box.h - law.pad;\n const glyphs: HandGlyph[] = [];\n const lines: { start: number; end: number; y: number; width: number }[] = [];\n const positions = new Float32Array(2 * (text.length + 1));\n const phase = hashHand(noteSeed, 7)[0] * Math.PI * 2;\n let x = x0;\n let y = law.pad + metrics.ascent * em;\n let line = 0;\n let lineStart = 0;\n let prev = \"\";\n let overflow = false;\n const adv = (ch: string) => metrics.advance(ch) * em;\n const newline = (i: number) => {\n lines.push({ start: lineStart, end: i, y, width: x - x0 });\n lineStart = i; line += 1; x = x0; y += lineH; prev = \"\";\n };\n // the width a word (to the next space or newline) takes, with its kerning\n const wordWidth = (i: number): number => {\n let w = 0;\n let p = \"\";\n for (let j = i; j < text.length; j++) {\n const c = text[j] as string;\n if (c === \" \" || c === \"\\n\") break;\n if (p && metrics.kern) w += metrics.kern(p, c) * em;\n w += adv(c); p = c;\n }\n return w;\n };\n for (let i = 0; i < text.length; i++) {\n const ch = text[i] as string;\n if (ch === \"\\n\") { positions[2 * i] = x; positions[2 * i + 1] = y; newline(i + 1); continue; }\n const wordStart = i === 0 || text[i - 1] === \" \" || text[i - 1] === \"\\n\";\n // a word that does not fit the rest of the line wraps before it — unless it starts the line, when it breaks by glyph below\n if (ch !== \" \" && wordStart && x > x0 && x + wordWidth(i) > xMax) newline(i);\n if (ch !== \" \" && !wordStart && prev && metrics.kern) x += metrics.kern(prev, ch) * em;\n // a glyph that runs past the edge mid-word (a word longer than the line) wraps by itself\n if (ch !== \" \" && x > x0 && x + adv(ch) > xMax) newline(i);\n positions[2 * i] = x; positions[2 * i + 1] = y;\n if (ch === \" \") { x += adv(ch); prev = ch; continue; }\n const seed = seeds && i < seeds.length ? (seeds[i] as number) : glyphSeed(noteSeed, i);\n const [r0, r1, r2, r3] = hashHand(seed, ch.codePointAt(0) ?? 0);\n const scale = 1 + (r2 - 0.5) * 2 * law.jitter.scale;\n const a = adv(ch) * scale;\n const wander = law.wander.amp * em * Math.sin((2 * Math.PI * (x - x0)) / Math.max(law.wander.period * em, 1e-6) + phase);\n glyphs.push({\n ch, index: i, x, y: y + wander + (r1 - 0.5) * 2 * law.jitter.rise * em, advance: a,\n rot: (r0 - 0.5) * 2 * law.jitter.rot, scale, press: law.jitter.press[0] + (law.jitter.press[1] - law.jitter.press[0]) * r3, line,\n });\n if (y + metrics.descent * em > yMax) overflow = true;\n x += a; prev = ch;\n }\n positions[2 * text.length] = x; positions[2 * text.length + 1] = y;\n lines.push({ start: lineStart, end: text.length, y, width: x - x0 });\n if (y + metrics.descent * em > yMax && text.length > 0) overflow = true;\n return { glyphs, lines, positions, overflow, em, ascent: metrics.ascent * em, descent: metrics.descent * em };\n}\n\n/** The caret before `index`: its left edge on the baseline, and its extent above and below. */\nexport function caretAt(L: HandLayout, index: number): { readonly x: number; readonly y: number; readonly above: number; readonly below: number } {\n const i = Math.min(Math.max(index, 0), L.positions.length / 2 - 1);\n return { x: L.positions[2 * i] as number, y: L.positions[2 * i + 1] as number, above: L.ascent, below: L.descent };\n}\n\n/** The box a glyph's ink can reach (its advance wide, the face's box tall, grown by the hand's jitter), note units — what the wipe reveals. */\nexport function glyphBox(L: HandLayout, g: HandGlyph): { readonly x0: number; readonly y0: number; readonly x1: number; readonly y1: number } {\n const grow = L.em * 0.12;\n return { x0: g.x - grow, y0: g.y - L.ascent * g.scale - grow, x1: g.x + g.advance + grow, y1: g.y + L.descent * g.scale + grow };\n}\n\n/**\n * The hand's seeds carried through an edit: the common prefix and suffix of\n * the old and new text keep their seeds, the inserted run gets fresh ones from\n * `fresh()`. Returns the new seeds and the inserted range [from, to).\n */\nexport function carrySeeds(oldText: string, oldSeeds: ArrayLike<number>, newText: string, fresh: () => number): { seeds: number[]; from: number; to: number } {\n let pre = 0;\n const maxPre = Math.min(oldText.length, newText.length);\n while (pre < maxPre && oldText[pre] === newText[pre]) pre += 1;\n let suf = 0;\n const maxSuf = Math.min(oldText.length, newText.length) - pre;\n while (suf < maxSuf && oldText[oldText.length - 1 - suf] === newText[newText.length - 1 - suf]) suf += 1;\n const seeds: number[] = [];\n for (let i = 0; i < pre; i++) seeds.push(i < oldSeeds.length ? (oldSeeds[i] as number) : fresh());\n const inserted = newText.length - pre - suf;\n for (let i = 0; i < inserted; i++) seeds.push(fresh());\n for (let i = 0; i < suf; i++) { const j = oldText.length - suf + i; seeds.push(j < oldSeeds.length ? (oldSeeds[j] as number) : fresh()); }\n return { seeds, from: pre, to: pre + inserted };\n}\n\n/**\n * The HAND — how the pen writes on the paper (STICKY.md §3; `paper/text.ts`). The face is\n * the host's (the lab's Caveat, an OFL hand); its size is in world units; the jitter is\n * each glyph's own — a tilt, a rise, a size, a pressure — and the line wanders slowly.\n * The wipe is how a typed glyph arrives: revealed left to right in `wipeMs`, the pen's stroke.\n */\nexport const HAND = {\n size: 24, lineHeight: 1.16, pad: 16,\n jitter: { rot: 0.028, rise: 0.03, scale: 0.05, press: [0.8, 0.97] as readonly [number, number] },\n wander: { amp: 0.022, period: 9 },\n wipeMs: 110,\n} as const;\n\n/** The pens a hand writes with (STICKY.md §3) — names; the inks are the host's (the note's, and the desk calendar's lines). */\nexport const PENS = [\"felt\", \"ball\", \"fountain\", \"red\"] as const;\nexport type PenName = (typeof PENS)[number];\n\n/** A face: its family and weight, and the file it loads from (absent = the platform's own). */\nexport interface FaceSpec {\n readonly family: string;\n readonly weight: number;\n readonly url?: string;\n}\n\n/** The hand's faces by name (STICKY.md §3) — the families and weights; the app supplies the files (desk/host/ink.ts `penFaces`). */\nexport const PEN_FACES: Readonly<Record<string, Omit<FaceSpec, \"url\">>> = {\n caveat: { family: \"Caveat\", weight: 500 },\n \"caveat-bold\": { family: \"Caveat\", weight: 600 },\n kalam: { family: \"Kalam\", weight: 400 },\n marker: { family: \"Marker Felt\", weight: 400 },\n noteworthy: { family: \"Noteworthy\", weight: 400 },\n};\n","// SHARED TEXTURE ARRAYS (design-016 §6, K-L4; K6a) — what a kind keeps per object as pixels, kept as LAYERS of one array so\n// a run of its objects binds one texture and draws as one instanced draw: a picture's thumbnail (the print), a board's far\n// ink (the whiteboard). An object's layer holds the TAIL of its own mip chain — the levels from the first whose sides fit the\n// layer — copied texel for texel at the layer's origin, its last row and column carried to the layer's edge at every level\n// (so a clamped sampler reads it exactly as it read the object's own texture); the array grows by doubling (the old layers\n// copied); a layer given back is taken again first. The copy passes through the plain view of an `-srgb` format, so the\n// bytes pass unchanged. A kind's record carries the layer and the chain level it starts at; its WGSL samples\n// `uv · size_k / side` at `lod − k` (photo-pass.wgsl `photo_texel`, board-pass.wgsl `board_ink`).\n\n/** The level of a `w × h` chain whose both sides first fit `side` (0 when the whole chain does). */\nexport function tailBase(w: number, h: number, side: number): number {\n let k = 0;\n while (Math.max(w >> k, 1) > side || Math.max(h >> k, 1) > side) k += 1;\n return k;\n}\n\n/** Bytes of `levels` of a chain from `w × h` at `texel` bytes a texel. */\nexport function chainBytes(w: number, h: number, levels: number, texel = 4): number {\n let b = 0;\n for (let l = 0; l < levels; l++) b += Math.max(w >> l, 1) * Math.max(h >> l, 1) * texel;\n return b;\n}\n\n/**\n * THE LAYER ALLOCATOR: an array's layers handed out lowest first and taken back; `take` says the capacity the array must hold\n * for the layer it hands out (doubling, from `first`, to the device's `max`) — null when it holds no more. K9 R2: `shrunk` says\n * the capacity the layers in use let the array fall back to — halves, and nothing at all when none is in use.\n */\nexport class Layers {\n private free: number[] = [];\n private next = 0;\n capacity = 0;\n constructor(readonly first = 4, readonly max = 256) {}\n take(): { readonly layer: number; readonly capacity: number } | null {\n if (this.free.length > 0) { this.free.sort((a, b) => a - b); return { layer: this.free.shift() as number, capacity: this.capacity }; }\n if (this.next >= this.max) return null;\n const layer = this.next++;\n if (layer >= this.capacity) this.capacity = Math.min(Math.max(this.first, this.capacity * 2), this.max);\n return { layer, capacity: this.capacity };\n }\n give(layer: number): void { if (layer >= 0 && layer < this.next && !this.free.includes(layer)) this.free.push(layer); }\n get used(): number { return this.next - this.free.length; }\n /** The highest layer in use (−1 when none): what a smaller array must still hold. */\n get highest(): number {\n let h = this.next - 1;\n while (h >= 0 && this.free.includes(h)) h -= 1;\n return h;\n }\n /**\n * The capacity an array holding these layers may shrink to (K9 R2): halved while fewer than a QUARTER of it is in use and the\n * highest layer in use fits the half — down to `first`; 0 when none is in use; the current capacity when it cannot shrink.\n */\n shrunk(): number {\n if (this.used === 0) return 0;\n let c = this.capacity;\n while (c > this.first && this.used * 4 < c && this.highest < c / 2) c /= 2;\n return c;\n }\n /** The allocator's word after the array was remade at `capacity` (from `shrunk()`): the layers past it are forgotten. */\n shrinkTo(capacity: number): void {\n if (capacity === 0) { this.free = []; this.next = 0; this.capacity = 0; return; }\n this.next = Math.min(this.next, capacity);\n this.free = this.free.filter((l) => l < this.next);\n this.capacity = capacity;\n }\n}\n\nconst FILL = /* wgsl */ `\n@group(0) @binding(0) var src: texture_2d<f32>;\n@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {\n let p = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0))[i];\n return vec4f(p, 0.0, 1.0);\n}\n@fragment fn fs(@builtin(position) pos: vec4f) -> @location(0) vec4f {\n let last = vec2i(textureDimensions(src)) - vec2i(1);\n return textureLoad(src, min(vec2i(pos.xy), last), 0);\n}\n`;\n\n/** The plain format an `-srgb` one is viewed as for a copy (the bytes pass unchanged); a plain format is its own. */\nexport const plainFormat = (f: GPUTextureFormat): GPUTextureFormat => (f.endsWith(\"-srgb\") ? (f.slice(0, -5) as GPUTextureFormat) : f);\n\nexport interface LayerArrayOptions {\n /** The label every array is made with (`photo/thumbnails`) — the memory ledger's row. */\n readonly label: string;\n readonly format: GPUTextureFormat;\n /** The layers' side, texels (square); every layer holds its full mip chain. */\n readonly side: number;\n /** Layers at the first growth (then doubling). */\n readonly first?: number;\n}\n\n/** One kind's array of layers on one device: its texture (null before the first layer), the allocator, the fill. */\nexport class LayerArray {\n readonly side: number;\n readonly mips: number;\n readonly format: GPUTextureFormat;\n private readonly device: GPUDevice;\n private readonly label: string;\n private readonly layers: Layers;\n private tex: GPUTexture | null = null;\n /** The texture's layers (kept here: a fake device's texture has no count of its own). */\n private cap = 0;\n /** Bumped whenever the texture is remade (a bind group holding its view must be made again). */\n version = 0;\n /** The fill's pipeline, made on the first fill — labelled with the array's own name, so the profiler counts its passes as the kind's. */\n private fillPipe: GPURenderPipeline | null = null;\n\n constructor(device: GPUDevice, opts: LayerArrayOptions) {\n this.device = device;\n this.label = opts.label;\n this.format = opts.format;\n this.side = opts.side;\n this.mips = Math.floor(Math.log2(opts.side)) + 1;\n const max = (device as { limits?: { maxTextureArrayLayers?: number } }).limits?.maxTextureArrayLayers ?? 256;\n this.layers = new Layers(opts.first ?? 4, max);\n }\n\n /** The array (null before its first layer). */\n get texture(): GPUTexture | null { return this.tex; }\n /** Layers in use; the array's capacity. */\n get used(): number { return this.layers.used; }\n get capacity(): number { return this.tex === null ? 0 : this.layers.capacity; }\n /** What the array weighs on the device, every layer of its capacity with its chain (the GPU ledger's row). */\n get bytes(): number { return this.capacity * chainBytes(this.side, this.side, this.mips); }\n /** What the layers IN USE weigh (K9 R2: the budget's resident charge — the capacity's slack is the ledger's to show, bounded by `give`'s shrink). */\n get usedBytes(): number { return this.used * chainBytes(this.side, this.side, this.mips); }\n\n /** A layer for a new object (the array grown — its old layers copied — when it must be); null when the device holds no more. */\n take(): number | null {\n const t = this.layers.take();\n if (t === null) return null;\n if (this.tex === null || t.capacity > this.cap) this.remake(t.capacity);\n return t.layer;\n }\n\n /**\n * A layer given back — and the array SHRUNK when fewer than a quarter of its layers are in use and the ones in use fit the\n * half (K9 R2: an array never shrank before, so its charge survived a document switch): remade at half, its low layers copied;\n * let go entirely when none is in use. The version moves as on a growth — a holder rebinds its view.\n */\n give(layer: number): void {\n this.layers.give(layer);\n if (this.tex === null) return;\n const to = this.layers.shrunk();\n if (to >= this.cap) return;\n if (to === 0) { this.tex.destroy(); this.tex = null; this.cap = 0; this.layers.shrinkTo(0); this.version += 1; return; }\n this.layers.shrinkTo(to);\n this.remake(to);\n }\n\n /**\n * Layer `layer`'s every level from `src`'s chain: level `base + m` at the origin, its edge carried to the layer's; a level past\n * the chain's end takes its last. `src` must allow the plain view of its format (`viewFormats`) when that format is `-srgb`.\n */\n fill(src: GPUTexture, srcMips: number, layer: number, base: number, encoder?: GPUCommandEncoder): void {\n const tex = this.tex;\n if (tex === null) return;\n const plain = plainFormat(this.format);\n const pipe = this.pipeline(plain);\n const enc = encoder ?? this.device.createCommandEncoder({ label: `${this.label} fill` });\n for (let m = 0; m < this.mips; m++) {\n const from = src.createView({ format: plainFormat(src.format ?? this.format), dimension: \"2d\", baseMipLevel: Math.min(base + m, srcMips - 1), mipLevelCount: 1 });\n const to = tex.createView({ format: plain, dimension: \"2d\", baseArrayLayer: layer, arrayLayerCount: 1, baseMipLevel: m, mipLevelCount: 1 });\n const group = this.device.createBindGroup({ label: `${this.label} fill`, layout: pipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: from }] });\n const pass = enc.beginRenderPass({ label: `${this.label} fill`, colorAttachments: [{ view: to, loadOp: \"clear\", storeOp: \"store\", clearValue: { r: 0, g: 0, b: 0, a: 0 } }] });\n pass.setPipeline(pipe);\n pass.setBindGroup(0, group);\n pass.draw(3);\n pass.end();\n }\n if (encoder === undefined) this.device.queue.submit([enc.finish()]);\n }\n\n /** A `2d-array` view of the whole array — or of `blank` (a 1 × 1 × 1 stand-in the caller keeps) before its first layer. */\n view(blank: GPUTexture): GPUTextureView { return (this.tex ?? blank).createView({ dimension: \"2d-array\" }); }\n\n destroy(): void { this.tex?.destroy(); this.tex = null; this.cap = 0; }\n\n /** The array made again at `capacity` layers — the old one's layers copied, as many as both hold — and the old destroyed. */\n private remake(capacity: number): void {\n const next = this.device.createTexture({\n label: this.label, size: [this.side, this.side, capacity], format: this.format, mipLevelCount: this.mips,\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,\n ...(plainFormat(this.format) !== this.format ? { viewFormats: [plainFormat(this.format)] } : {}),\n });\n const old = this.tex;\n if (old !== null) {\n const enc = this.device.createCommandEncoder({ label: `${this.label} ${capacity > this.cap ? \"grow\" : \"shrink\"}` });\n const layers = Math.min(this.cap, capacity);\n for (let m = 0; m < this.mips; m++) {\n const s = Math.max(this.side >> m, 1);\n enc.copyTextureToTexture({ texture: old, mipLevel: m }, { texture: next, mipLevel: m }, [s, s, layers]);\n }\n this.device.queue.submit([enc.finish()]);\n old.destroy();\n }\n this.tex = next;\n this.cap = capacity;\n this.version += 1;\n }\n\n private pipeline(format: GPUTextureFormat): GPURenderPipeline {\n if (this.fillPipe === null) {\n const module = this.device.createShaderModule({ label: `${this.label} fill`, code: FILL });\n this.fillPipe = this.device.createRenderPipeline({ label: `${this.label} fill`, layout: \"auto\", vertex: { module, entryPoint: \"vs\" }, fragment: { module, entryPoint: \"fs\", targets: [{ format }] } });\n }\n return this.fillPipe;\n }\n}\n","// A picture's mip chain, made on the device: each level drawn from the one\n// above it through a linear sampler (a 2×2 box at exactly half size). Sampled\n// from an `-srgb` view the filtering happens in linear light, so a zoomed-out\n// print keeps its brightness. One pipeline per format, made on first use.\n// Two forms: `generateMips` makes a whole chain in a submit of its own (the\n// photo's one-shot pictures); `mipsInto` makes some of its levels into the\n// caller's encoder (a live face's chain, as deep as it is read — M24 LT1).\n\nconst WGSL = /* wgsl */ `\n@group(0) @binding(0) var src: texture_2d<f32>;\n@group(0) @binding(1) var samp: sampler;\nstruct VO { @builtin(position) pos: vec4f, @location(0) uv: vec2f }\n@vertex fn vs(@builtin(vertex_index) i: u32) -> VO {\n let p = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0))[i];\n var o: VO; o.pos = vec4f(p, 0.0, 1.0); o.uv = vec2f(0.5 * p.x + 0.5, 0.5 - 0.5 * p.y); return o;\n}\n@fragment fn fs(v: VO) -> @location(0) vec4f { return textureSampleLevel(src, samp, v.uv, 0.0); }\n`;\n\nconst cache = new WeakMap<GPUDevice, { module: GPUShaderModule; sampler: GPUSampler; pipes: Map<GPUTextureFormat, GPURenderPipeline> }>();\n\nexport const mipCount = (w: number, h: number): number => Math.floor(Math.log2(Math.max(w, h, 1))) + 1;\n\n/** The device's mip sampler and its pipeline for `format`, made on first use — one per device and format, both forms'. */\nfunction pipeOf(device: GPUDevice, format: GPUTextureFormat): { readonly pipe: GPURenderPipeline; readonly sampler: GPUSampler } {\n let c = cache.get(device);\n if (!c) {\n c = { module: device.createShaderModule({ label: \"photo/mips\", code: WGSL }), sampler: device.createSampler({ minFilter: \"linear\", magFilter: \"linear\" }), pipes: new Map() };\n cache.set(device, c);\n }\n let pipe = c.pipes.get(format);\n if (!pipe) {\n pipe = device.createRenderPipeline({\n label: `photo/mips ${format}`, layout: \"auto\",\n vertex: { module: c.module, entryPoint: \"vs\" },\n fragment: { module: c.module, entryPoint: \"fs\", targets: [{ format }] },\n });\n c.pipes.set(format, pipe);\n }\n return { pipe, sampler: c.sampler };\n}\n\nexport function generateMips(device: GPUDevice, texture: GPUTexture): void {\n const { pipe, sampler } = pipeOf(device, texture.format);\n const encoder = device.createCommandEncoder({ label: \"photo/mips\" });\n for (let level = 1; level < texture.mipLevelCount; level++) {\n const src = texture.createView({ baseMipLevel: level - 1, mipLevelCount: 1 });\n const dst = texture.createView({ baseMipLevel: level, mipLevelCount: 1 });\n const group = device.createBindGroup({ layout: pipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: src }, { binding: 1, resource: sampler }] });\n const pass = encoder.beginRenderPass({ colorAttachments: [{ view: dst, loadOp: \"clear\", storeOp: \"store\", clearValue: { r: 0, g: 0, b: 0, a: 0 } }] });\n pass.setPipeline(pipe);\n pass.setBindGroup(0, group);\n pass.draw(3);\n pass.end();\n }\n device.queue.submit([encoder.finish()]);\n}\n\n/** What `mipsInto` keeps per texture: its format's pipeline, each level's own view, and the group that reads level l − 1 for level l. */\ninterface Chain {\n readonly pipe: GPURenderPipeline;\n readonly sampler: GPUSampler;\n readonly views: GPUTextureView[];\n readonly groups: GPUBindGroup[];\n}\nconst chains = new WeakMap<GPUTexture, Chain>();\n\n/**\n * A chain's levels `from` … `to` made INTO `encoder` (design-019 §3.1, M24 LT1 — a live face's chain, made only as deep as it is read,\n * in the frame's own encoder: no submit of its own), each level drawn from the one above it as `generateMips` draws it (a 2×2 box\n * through a linear sampler; from an `-srgb` texture, in linear light). The pipeline is the device's per format (`generateMips`' own);\n * each level's view and the bind group that reads the level above it are kept per TEXTURE, made the first time that level is asked —\n * a face made again at a producer's 60 a second makes no view or group per call. `from` is at least 1; `to` is clamped to the chain's\n * last level; `to` below `from` records nothing. The texture needs RENDER_ATTACHMENT (a level is drawn) and TEXTURE_BINDING (the one\n * above is read). The DEVICE comes first, as `generateMips`' does: a WebGPU encoder and texture carry none, and the views and groups\n * are made on it.\n */\nexport function mipsInto(device: GPUDevice, encoder: GPUCommandEncoder, texture: GPUTexture, from: number, to: number): void {\n const first = Math.max(1, Math.floor(from));\n const last = Math.min(Math.floor(to), texture.mipLevelCount - 1);\n if (last < first) return;\n let chain = chains.get(texture);\n if (chain === undefined) {\n const { pipe, sampler } = pipeOf(device, texture.format);\n chain = { pipe, sampler, views: [], groups: [] };\n chains.set(texture, chain);\n }\n const c = chain;\n const view = (level: number): GPUTextureView => {\n let v = c.views[level];\n if (v === undefined) { v = texture.createView({ baseMipLevel: level, mipLevelCount: 1 }); c.views[level] = v; }\n return v;\n };\n for (let level = first; level <= last; level++) {\n let group = c.groups[level];\n if (group === undefined) {\n group = device.createBindGroup({ layout: c.pipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: view(level - 1) }, { binding: 1, resource: c.sampler }] });\n c.groups[level] = group;\n }\n const pass = encoder.beginRenderPass({ colorAttachments: [{ view: view(level), loadOp: \"clear\", storeOp: \"store\", clearValue: { r: 0, g: 0, b: 0, a: 0 } }] });\n pass.setPipeline(c.pipe);\n pass.setBindGroup(0, group);\n pass.draw(3);\n pass.end();\n }\n}\n","// (The kit's since K4a, design-016 §5 — moved from notebook/eye.ts: the desk calendar projects through the same eye.)\n//\n// The DESK EYE — how a thing with height is seen from the top-down camera (NOTEBOOK.md §2).\n//\n// The camera is still the desk's: top-down, pan and zoom only. But a notebook is not flat, so\n// what rises off the mat is seen from an eye standing above the VIEW's centre: a point h up\n// lands at E + (p − E) · H / (H − h) on the desk plane. At h = 0 that is the identity — the mat,\n// the cards and every flat thing map exactly as the ortho camera maps them — so the only\n// things that move are the ones with height: a lifted book grows, a standing cover keystones,\n// a closed book off to the side shows the edge of its pages. Pure: no GPU. `notebook.wgsl`'s\n// `nb_clip` is the same arithmetic; `unproject` is its inverse for the hit test.\n\nimport type { CameraState, Viewport } from \"./nav\";\n\nexport interface DeskEye {\n /** The eye's foot on the desk: the view's centre, world units. */\n readonly ex: number;\n readonly ey: number;\n /** How far up it stands, world units. */\n readonly h: number;\n readonly zoom: number;\n /** The viewport, CSS px. */\n readonly vw: number;\n readonly vh: number;\n}\n\n/** The eye for a camera: over the view's centre, `k` view-diagonals up, never nearer than `min`. */\nexport function eyeOf(cam: CameraState, vp: Viewport, law: { readonly k: number; readonly min: number }): DeskEye {\n const zoom = Math.max(cam.zoom, 1e-9);\n const diag = Math.hypot(vp.width, vp.height) / zoom;\n return { ex: cam.x + vp.width / (2 * zoom), ey: cam.y + vp.height / (2 * zoom), h: Math.max(law.min, law.k * diag), zoom, vw: vp.width, vh: vp.height };\n}\n\n/** A world point (z up) → CSS px on the screen. */\nexport function project(e: DeskEye, x: number, y: number, z: number): readonly [number, number] {\n const k = e.h / Math.max(e.h - z, 1e-6);\n return [e.vw / 2 + (x - e.ex) * k * e.zoom, e.vh / 2 + (y - e.ey) * k * e.zoom];\n}\n\n/** CSS px → the desk point under it (z = 0): the ortho camera's own inverse. */\nexport function deskAt(e: DeskEye, sx: number, sy: number): readonly [number, number] {\n return [e.ex + (sx - e.vw / 2) / e.zoom, e.ey + (sy - e.vh / 2) / e.zoom];\n}\n\n/** The world point at height z that lands on the desk point (dx, dy) — along the eye's ray. */\nexport function unproject(e: DeskEye, dx: number, dy: number, z: number): readonly [number, number] {\n const f = (e.h - z) / e.h;\n return [e.ex + (dx - e.ex) * f, e.ey + (dy - e.ey) * f];\n}\n\n/** The eye's ray through a desk point: origin (the eye) and direction (toward the desk point, unnormalised). */\nexport function rayThrough(e: DeskEye, dx: number, dy: number): { readonly o: readonly [number, number, number]; readonly d: readonly [number, number, number] } {\n return { o: [e.ex, e.ey, e.h], d: [dx - e.ex, dy - e.ey, -e.h] };\n}\n\n/**\n * The clip-space numbers the shader's `nb_clip` reads: x, y are 2·zoom·(p − E)/viewport (y up),\n * w = (H − z)/H, and z is a perspective depth over distances from the eye in [near, far] —\n * `near` above the tallest thing a book can reach, `far` just under the desk.\n */\nexport function eyeValues(e: DeskEye, reach = 900): { eye: [number, number, number, number]; view: [number, number, number, number] } {\n const near = Math.max(e.h - reach, 1);\n const far = e.h + 40;\n return { eye: [e.ex, e.ey, e.h, e.zoom], view: [e.vw, e.vh, near, far] };\n}\n","// THE LIVE FACE (design-019 §3, §9 — PORTALS' seam; M24 LT1): a kind's face may show a surface that lives OUTSIDE the world — a web\n// page, a captured window, a simulator's screen, later a terminal — as a texture on the desk's device that the HOST fills and the\n// kind samples. Nothing about a source enters the desk: the host LENDS a `LiveSources` under the `LIVE` key (`deskLayer({ services })`,\n// as it lends its text raster and its byte store); a kind's world half opens a FACE on it per object, by the object's durable key\n// (`KindHost.keyOf`), takes what arrived in its tick and draws the face's `LiveTexture` — a view, never a frame (VibeField's PA-22:\n// a plugin never touches a frame). THIS MODULE IS THE KIND'S HALF (petition I51) — what a kind reads and is lent:\n// - `LiveTexture` — the READER of a face's texture: its size, the counters that say when to rebind or make its mips again, `view()`,\n// `prepare(encoder, upTo)` (its mips, only as deep as they are read, into the frame's encoder) — and `liveDepth`;\n// - the contract a host lends (`LIVE`, `LiveSources`, `LiveFace` and its words: `LiveState`, `LiveInfo`, `LiveDemand`, `LiveInput`);\n// - `createSight` — where a kind's faces were drawn, folded into one fact per entity per frame (seen, the largest device px, held):\n// what the kind's demand law reads.\n// The HOST's half — `createLiveTexture` (the writer that takes frames) and `stillLive` (a still host's source of committed bytes) — is\n// host/live-texture.ts, on `@vibecook/ice/desk` beside `deskLayer` and off this kit: a kind never makes a face's texture, and the kit's\n// module graph cannot reach the writer (`desk-dom-free`: nothing outside host/ imports host/).\n// THE WAKE (§3.3): `arrived` → the kind's `KindHost.wake()` → its tick `take()`s each woken face → a face that answers true asks\n// `KindHost.redraw()` and the tick answers FALSE: the frame is drawn again and no record is remade. A quiet source sends nothing, so a\n// desk of live faces at rest submits nothing.\n\nimport type { Entity } from \"@ice/core\";\nimport type { SlotContext } from \"../kind\";\nimport type { ObjectRect } from \"../kinds/world\";\nimport { boxOf } from \"../lattice/lod\";\nimport { type ServiceKey, serviceKey } from \"./services\";\n\n// ---------------------------------------------------------------- the texture\n\n/** The formats a live texture is made in: `rgba8unorm-srgb` (the default — filtered in linear light, as the photo's chain is) or `rgba8unorm`. */\nexport type LiveFormat = \"rgba8unorm-srgb\" | \"rgba8unorm\";\n\n/** What a kind reads (design-019 §3.1): a stable texture, its size, and the counters that say when to rebind or make its mips again. */\nexport interface LiveTexture {\n /** Texels of level 0 — the source's size as last presented (or as made, before the first). */\n readonly width: number;\n readonly height: number;\n readonly format: LiveFormat;\n /** Moves on every present: the content changed, so the mips are owed again (0 — nothing presented yet). */\n readonly revision: number;\n /** Moves when the GPU texture itself is replaced (a resize): a kind rebinds every group that holds `view()`. */\n readonly epoch: number;\n /**\n * The whole chain's view — sampled through a trilinear sampler. Levels past `prepare`'s reach hold the mips last made there (a\n * texture of a new epoch: nothing until they are made).\n */\n view(): GPUTextureView;\n /**\n * Make the mips down to level `upTo` into `encoder` — the frame's, from the kind's `prepare`: never a submit of its own. Once per\n * revision: a second call at the same revision and depth records nothing, a deeper one only the levels still missing. `upTo` is\n * clamped to the chain's last level; nothing is made before the first present, nor for a texture made without mips.\n */\n prepare(encoder: GPUCommandEncoder, upTo: number): void;\n /** Bytes held on the device, every level counted (the kit's `chainBytes`) — what a kind charges its budget. */\n readonly bytes: number;\n /**\n * The LOGICAL size of the frame last presented (design-019 §5, M24 LT2 — a page's CSS viewport, as its host said with the present):\n * `[width, height]`, the texel size when the present gave none (and after a resize, before the next). Texels are not a source's\n * coordinates: a kind maps the hand's point into the frame it DISPLAYED through this, and the host stamps that frame's geometry.\n */\n readonly logical: readonly [number, number];\n}\n\n/**\n * How deep a face is READ (design-019 §3.1 — \"a mip chain made only as deep as it is read\"): drawn at `px` device px, a texture of\n * `face`'s size is minified by its larger ratio, and a trilinear sampler reads the two levels about log2 of it — so the levels down\n * to ⌈log2 ratio⌉ are what `prepare` must make; 0 when the face is drawn at its size or larger. A kind passes it to `prepare`.\n */\nexport function liveDepth(face: Pick<LiveTexture, \"width\" | \"height\">, px: readonly [number, number]): number {\n const ratio = Math.max(face.width / Math.max(px[0], 1e-6), face.height / Math.max(px[1], 1e-6));\n return ratio <= 1 ? 0 : Math.ceil(Math.log2(ratio) - 1e-9);\n}\n\n// ---------------------------------------------------------------- the source a host lends\n\n/**\n * The source's state (design-019 §3.2): `starting` (no frame yet — the kind draws its still or its film), `live`, `paused` (the last\n * frame holds), `closed`; `failed` with its reason in words and, when the host can, a way to try again.\n */\nexport type LiveState =\n | { readonly is: \"starting\" | \"live\" | \"paused\" | \"closed\" }\n | { readonly is: \"failed\"; readonly reason: string; readonly retry?: () => void };\n\n/** The source's words for the face — all optional; `extra` carries a host's own (the kind knows its host's contract). */\nexport interface LiveInfo {\n readonly title?: string;\n readonly address?: string;\n /** 0 … 1 while loading; undefined when not. */\n readonly loading?: number;\n readonly back?: boolean;\n readonly forward?: boolean;\n /** The CSS cursor the source shows at the last point it was told of. */\n readonly cursor?: string;\n /** The source runs degraded — `\"cpu-bitmap\"` (LSF's fallback): the kind may badge it. */\n readonly degraded?: string;\n readonly extra?: Readonly<Record<string, unknown>>;\n}\n\n/**\n * What the desk asks of a face, in the KIND's law over what it is seen (design-019 §4) — handed to `LiveFace.demand` change-only; the\n * host maps it to its producer and folds several holders of one key. `mode`: live or paused (a face unseen, behind the hand, evicted);\n * `fps`: the rate it wants (the host buckets it — VibeField's 0/2/5/10/15/30/60); `raster`: the device px it wants delivered (a rung,\n * held through a wobbling zoom); `viewport`: the source's logical layout size (a page's CSS viewport — absent: unchanged);\n * `interactive`: in use, at the native rate and urgent.\n */\nexport interface LiveDemand {\n readonly mode: \"live\" | \"paused\";\n readonly fps: number;\n readonly raster: readonly [number, number];\n readonly viewport?: readonly [number, number];\n readonly interactive: boolean;\n}\n\n/**\n * Input to a face, in the coordinates of the frame it DISPLAYED — its LOGICAL size (`LiveTexture.logical`, design-019 §5; M24 LT2): a\n * pointer (`button` the one pressed or released — −1 on a move, `buttons` the mask held, `count` the click count the hand told the kind:\n * 1, 2, 3… — `HeldEvent`'s), a wheel (CSS px of the hand — the DOM wheel event's deltas as they are, never multiplied by a density: a\n * host forwards them to its source unchanged), a key (`mods` Chrome DevTools' modifier mask — Alt 1, Ctrl 2, Meta 4,\n * Shift 8), committed text, an IME composition (its text and its caret within it — `EditorLease.compose`). A kind maps what the hand\n * told it (`KindLocal.held`, the editor's lease) and sends it; it carries no geometry revision: the host stamps the frame it displayed.\n */\nexport type LiveInput =\n | { readonly kind: \"pointer\"; readonly x: number; readonly y: number; readonly button: number; readonly buttons: number; readonly count: number; readonly phase: \"down\" | \"move\" | \"up\" }\n | { readonly kind: \"wheel\"; readonly x: number; readonly y: number; readonly dx: number; readonly dy: number }\n | { readonly kind: \"key\"; readonly key: string; readonly code: string; readonly phase: \"down\" | \"up\"; readonly mods: number; readonly repeat: boolean }\n | { readonly kind: \"text\"; readonly text: string }\n | { readonly kind: \"compose\"; readonly text: string; readonly caret: number };\n\n/**\n * ONE FACE a host opened for an object (design-019 §3.2). The kind holds it — a view and words, never a frame. A kind TAKES once right\n * after it opens a face (what the host already holds — a page re-attached, a still's committed frame — lands in the frame that opens\n * it), and then whenever `arrived` woke it.\n */\nexport interface LiveFace {\n readonly key: string;\n /** The face's texture, or undefined before the first frame and after an eviction — the kind draws its still or its film. */\n texture(): LiveTexture | undefined;\n /**\n * In the kind's tick (and once at its open): the host copies the NEWEST arrival once into the texture and closes it — older ones\n * were closed on arrival. True when the look changed: a frame landed, the state or the info moved.\n */\n take(): boolean;\n state(): LiveState;\n info(): LiveInfo;\n /** What the desk sees of the face, in the kind's law — change-only; the host maps it to its producer. */\n demand(d: LiveDemand): void;\n /** Input in the displayed frame's logical coordinates (§5 — a kind sends what the hand told it, M24 LT2). Absent: a view-only source (a captured window, a simulator without a control lane). */\n readonly input?: ((e: LiveInput) => void) | undefined;\n close(): void;\n}\n\n/** What a HOST lends (design-019 §3.2) under `LIVE`: its sources, as faces by key. */\nexport interface LiveSources {\n /**\n * Open a face for `key` — the object's DURABLE key (`KindHost.keyOf`) — on a source the HOST understands: `spec` is the host's\n * contract (a page's address, a window's id), the desk never reads it. `arrived` is called — outside a frame, any number of times —\n * when something new is ready: a frame, a state, an info change. One face per key per desk: a key opened twice is a host error.\n * Open on the kind's first `record` of the object; `close` on its `forget`, the kind's `dispose`, or its eviction.\n */\n open(key: string, spec: Readonly<Record<string, unknown>>, arrived: () => void): LiveFace;\n}\n\n/** The host's live sources as a desk SERVICE (design-019 §3.2 — `deskLayer({ services: [service(LIVE, sources)] })`): `host.use?.(LIVE)`. */\nexport const LIVE: ServiceKey<LiveSources> = serviceKey<LiveSources>(\"live\");\n\n// ---------------------------------------------------------------- the sight\n\n/**\n * What a kind is told of one face (design-019 §3.4): `seen` — drawn in the last frame, in any slot but the desk copy behind the hand;\n * `px` — the LARGEST device-px extent it was drawn at there (`[0, 0]` unseen); `held` — drawn in the hand.\n */\nexport interface Seen {\n readonly seen: boolean;\n readonly px: readonly [number, number];\n readonly held: boolean;\n}\n\n/** A face not drawn in the last frame. */\nconst UNSEEN: Seen = { seen: false, px: [0, 0], held: false };\n\n/**\n * THE SIGHT (design-019 §3.4): where a kind's faces are drawn, folded into one fact per entity per frame. The kind's pass tells it what\n * each slot drew (`saw`, in `prepare`); its tick asks what moved (`step`) and hands its demand law the facts.\n *\n * WHICH RENDERS COUNT: the frame's (`target` absent or `frame`) and the hand's (`held`). Not the desk COPY behind a carried object —\n * prepared once per stamp, it is what the eye sees out of focus: a face behind the hand reads `seen: false` and rests on its last\n * frame (§6, a policy) — and not a CAPTURE, which draws the last frame's inputs once more, outside any frame. So the photo's\n * `keepSlotted` re-ask (K9 R4 — the hand's prepare the only prepare of a carried frame) is not needed here: under a carry the hand's\n * prepare tells the held face, and every other face reads unseen BY THE POLICY, not by the gap.\n *\n * THE FRAME BOUNDARY: a kind with no records in a slot is never prepared, so \"not asked\" means \"not drawn\" only when a frame WAS drawn —\n * and a kind is ticked on steps that draw nothing (any input step: a pointer moving over the bare mat ticks every kind and draws no\n * frame). `frames` — the desk's count of frames drawn (`KindHost.frames`) — is that boundary: a step after no new frame says nothing\n * moved; one after a frame folds what THAT frame's prepares saw, and an entity they did not see reads `seen: false`; prepares made\n * outside the count (an instrument's render — the cost rig's batches, the profiler's ablation) are no frame's, dropped at the next\n * step. Absent (a bare host, a still): every step is taken as a frame.\n *\n * WHAT MEETS THE SLOT'S BOX (petition I50): a slot's records are prepared within their kind's REACH — beyond the view, for a shadow or\n * a glow — so a pass may tell every record it PREPARED: `saw` itself believes only a face whose rect meets the slot's box (`view.box`\n * — a mini mat's face for its inside — or the whole view), under the slot's camera. One wholly outside reads `seen: false` (its\n * source may rest); one straddling the edge is seen at its FULL px — a face half on screen is still asked at its size.\n */\nexport interface Sight {\n /**\n * In `prepare`, per slot, per record: the face's rect (the slot's world units, axis-aligned — a turned face passes the rect that\n * covers it) → device px through the slot's view, when it meets the slot's box (I50); its `w`, `h` are the px folded, whole.\n */\n saw(e: Entity, slot: SlotContext, face: ObjectRect): void;\n /** In the tick: the entities whose fact moved since the last step, each with its fact now. Empty when no frame was drawn since. */\n step(): ReadonlyMap<Entity, Seen>;\n /** `e`'s fact as of the last step; undefined before its first. */\n of(e: Entity): Seen | undefined;\n /** A frame was drawn since the last step — the kind is due NOW (its `KindLocal.due`), or a face culled by it reads seen until a later tick. */\n owed(): boolean;\n /** The entity left the desk: nothing of it is kept. */\n forget(e: Entity): void;\n}\n\n/** A face's extent in one render — device px — and whether that render was the hand. */\ninterface Glimpse { w: number; h: number; held: boolean }\n\n/** Does `face` (world units, under the slot's camera) meet the slot's box (CSS px of the attachment — petition I50)? Touching is not meeting. */\nfunction meetsBox(view: SlotContext[\"view\"], face: ObjectRect): boolean {\n const b = boxOf(view);\n const x0 = (face.cx - face.w / 2 - view.camX) * view.zoom;\n const y0 = (face.cy - face.h / 2 - view.camY) * view.zoom;\n return x0 + face.w * view.zoom > b.x && x0 < b.x + b.w && y0 + face.h * view.zoom > b.y && y0 < b.y + b.h;\n}\n\nconst sameSeen = (a: Seen, b: Seen): boolean => a.seen === b.seen && a.held === b.held && a.px[0] === b.px[0] && a.px[1] === b.px[1];\n\n/** A kind's SIGHT over its faces (design-019 §3.4) — `frames` the desk's count of frames drawn (`KindHost.frames`); see `Sight`. */\nexport function createSight(frames?: () => number): Sight {\n const facts = new Map<Entity, Seen>();\n /** What the frame being drawn (or the last drawn) saw — stamped with the count its prepares read. */\n const fold = new Map<Entity, Glimpse>();\n let foldAt = -1;\n /** The count the last step read (−1 before the first: never read at creation — a host's count may not exist yet). */\n let stepped = -1;\n return {\n saw(e, slot, face) {\n if (slot.target === \"copy\" || slot.target === \"capture\") return;\n if (frames !== undefined) {\n const n = frames();\n if (n !== foldAt) { fold.clear(); foldAt = n; } // a new frame's first prepare: what the last frame saw is gone\n }\n if (!meetsBox(slot.view, face)) return; // prepared within the kind's reach, drawn nowhere the eye sees (I50)\n const k = slot.view.zoom * slot.view.dpr;\n const glimpse: Glimpse = { w: Math.round(face.w * k), h: Math.round(face.h * k), held: slot.target === \"hand\" };\n const had = fold.get(e);\n if (had === undefined) { fold.set(e, glimpse); return; }\n // drawn in more than one slot this frame (a departed desk and the arriving one, an inside): the largest extent, held if any was\n if (glimpse.w * glimpse.h > had.w * had.h) { had.w = glimpse.w; had.h = glimpse.h; }\n had.held ||= glimpse.held;\n },\n step() {\n const moved = new Map<Entity, Seen>();\n if (frames !== undefined) {\n const n = frames();\n // prepares made while the count already reads n came after the last frame counted — no frame's (an instrument's render: the\n // cost rig's batches, the profiler's ablation, which prepare the passes and count nothing): dropped, so the next frame's\n // fold starts clean\n if (foldAt === n) { fold.clear(); foldAt = -1; }\n if (n === stepped) return moved;\n stepped = n;\n // the last frame drawn — the n-th — was prepared while the count read n − 1: what it saw is the fold, or (never asked) nothing\n if (foldAt !== n - 1) fold.clear();\n }\n for (const [e, g] of fold) {\n const now: Seen = { seen: true, px: [g.w, g.h], held: g.held };\n const was = facts.get(e);\n if (was === undefined || !sameSeen(was, now)) { facts.set(e, now); moved.set(e, now); }\n }\n for (const [e, was] of facts) {\n if (fold.has(e) || !was.seen) continue;\n facts.set(e, UNSEEN);\n moved.set(e, UNSEEN);\n }\n if (frames === undefined) fold.clear();\n return moved;\n },\n of: (e) => facts.get(e),\n owed: () => frames !== undefined && frames() !== stepped,\n forget(e) { facts.delete(e); fold.delete(e); },\n };\n}\n","// A MESH WRITER for a kind that draws real 3D (design-016 §5; the notebook's, moved here at K4a so the desk calendar's\n// pad builds with it without importing the notebook): a growable vertex + index writer and the mesh it builds. A vertex\n// is 16 floats — position · normal · uv · (material, page, flags, ao) · the face's size in world units (what uv is a\n// fraction of) · two extras — and the kind's shader reads a material by the number the kind gives it. Pure: typed\n// arrays out, no GPU.\n\nexport const VERTEX_FLOATS = 16;\nexport const VERTEX_BYTES = VERTEX_FLOATS * 4;\n\n/** Flags: a face seen from both sides (a sheet in the air, the spine). */\nexport const FLAG_TWO_SIDED = 1;\n\n/** A growable vertex + index writer. */\nexport class MeshWriter {\n v: Float32Array;\n ix: Uint32Array;\n nv = 0;\n ni = 0;\n readonly min: [number, number, number] = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];\n readonly max: [number, number, number] = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];\n constructor(vcap = 8192, icap = 24576) { this.v = new Float32Array(vcap * VERTEX_FLOATS); this.ix = new Uint32Array(icap); }\n reset(): void { this.nv = 0; this.ni = 0; this.min.fill(Number.POSITIVE_INFINITY); this.max.fill(Number.NEGATIVE_INFINITY); }\n vert(px: number, py: number, pz: number, nx: number, ny: number, nz: number, u: number, v: number, mat: number, page: number, flags: number, ao: number, sx: number, sy: number, e0 = 0, e1 = 0): number {\n if ((this.nv + 1) * VERTEX_FLOATS > this.v.length) { const g = new Float32Array(this.v.length * 2); g.set(this.v); this.v = g; }\n const o = this.nv * VERTEX_FLOATS;\n const a = this.v;\n const nl = Math.hypot(nx, ny, nz) || 1;\n a[o] = px; a[o + 1] = py; a[o + 2] = pz; a[o + 3] = nx / nl; a[o + 4] = ny / nl; a[o + 5] = nz / nl;\n a[o + 6] = u; a[o + 7] = v; a[o + 8] = mat; a[o + 9] = page; a[o + 10] = flags; a[o + 11] = ao;\n a[o + 12] = sx; a[o + 13] = sy; a[o + 14] = e0; a[o + 15] = e1;\n if (px < this.min[0]) this.min[0] = px; if (py < this.min[1]) this.min[1] = py; if (pz < this.min[2]) this.min[2] = pz;\n if (px > this.max[0]) this.max[0] = px; if (py > this.max[1]) this.max[1] = py; if (pz > this.max[2]) this.max[2] = pz;\n return this.nv++;\n }\n tri(a: number, b: number, c: number): void {\n if (this.ni + 3 > this.ix.length) { const g = new Uint32Array(this.ix.length * 2); g.set(this.ix); this.ix = g; }\n this.ix[this.ni++] = a; this.ix[this.ni++] = b; this.ix[this.ni++] = c;\n }\n quad(a: number, b: number, c: number, d: number): void { this.tri(a, b, c); this.tri(a, c, d); }\n /** A grid's quads: `cols` × `rows` vertices laid out row-major from `first`. */\n gridQuads(first: number, cols: number, rows: number): void {\n for (let j = 0; j + 1 < rows; j++) for (let i = 0; i + 1 < cols; i++) {\n const a = first + j * cols + i;\n this.quad(a, a + 1, a + cols + 1, a + cols);\n }\n }\n}\n\n/** A built mesh: views onto the writer's arrays (copy before the next build) and the local bounds. */\nexport interface BuiltMesh {\n readonly vertices: Float32Array;\n readonly indices: Uint32Array;\n readonly vcount: number;\n readonly icount: number;\n readonly min: readonly [number, number, number];\n readonly max: readonly [number, number, number];\n}\n\n","// (The kit's since K4a, design-016 §5 — moved from notebook/paper-tex.ts: the desk calendar's sheets are the same paper.)\n//\n// The PAPER's texture — baked once, sampled everywhere a page is (NOTEBOOK.md §4). Pure: bytes\n// out, no GPU. A tileable 256² rgba8:\n// R the mottle — the pulp's slow clouds (periodic value noise, 4 and 8 cells to the tile)\n// G the fibres — a few hundred short curved strokes, lighter and darker, laid at random with a\n// bias along the machine direction, wrapping at the tile's edges (0.5 = none)\n// B A the tooth's slope — the gradient of a fine periodic height (32 cells to the tile),\n// signed about 0.5\n// Sampled with mipmaps and explicit gradients, the tooth and the fibres fade into the pixel as a\n// page is zoomed out — filtered, not cut — and a page costs two fetches, not a dozen noises.\n\nexport const PAPER_TEX = 256;\n/** How much of the tooth's slope one step of B/A encodes (the decode multiplies back). */\nexport const TOOTH_SCALE = 48;\n\nconst fract = (x: number): number => x - Math.floor(x);\nfunction hash(i: number, j: number, seed: number): number {\n let h = (Math.imul(i, 668265261) ^ Math.imul(j, 374761393) ^ Math.imul(seed, 1274126177)) >>> 0;\n h = Math.imul(h ^ (h >>> 15), 2246822519) >>> 0;\n h = Math.imul(h ^ (h >>> 13), 3266489917) >>> 0;\n return ((h ^ (h >>> 16)) >>> 0) / 4294967296;\n}\n\n/** Periodic value noise on a lattice of `cells` to the unit square (smoothstep between corners), and its gradient. */\nfunction vnoise(u: number, v: number, cells: number, seed: number): [number, number, number] {\n const x = u * cells;\n const y = v * cells;\n const i = Math.floor(x);\n const j = Math.floor(y);\n const fx = x - i;\n const fy = y - j;\n const w = (t: number) => t * t * (3 - 2 * t);\n const dw = (t: number) => 6 * t * (1 - t);\n const at = (a: number, b: number) => hash(((a % cells) + cells) % cells, ((b % cells) + cells) % cells, seed);\n const a = at(i, j);\n const b = at(i + 1, j);\n const c = at(i, j + 1);\n const d = at(i + 1, j + 1);\n const k = a - b - c + d;\n const wx = w(fx);\n const wy = w(fy);\n return [a + (b - a) * wx + (c - a) * wy + k * wx * wy - 0.5, dw(fx) * (b - a + k * wy) * cells, dw(fy) * (c - a + k * wx) * cells];\n}\n\n/** The texture's bytes (deterministic: the same page everywhere, every run). */\nexport function paperTexture(seed = 7): Uint8Array<ArrayBuffer> {\n const N = PAPER_TEX;\n const out = new Uint8Array(N * N * 4);\n const fib = new Float32Array(N * N);\n // the fibres: strokes of a few texels, a gaussian stamp stepped along each, wrapping\n let r = seed * 9973;\n const rnd = () => { r = (Math.imul(r, 1664525) + 1013904223) >>> 0; return r / 4294967296; };\n for (let f = 0; f < 420; f++) {\n const x0 = rnd() * N;\n const y0 = rnd() * N;\n // most fibres run near the machine direction (along the page's height), some anywhere\n const a = rnd() < 0.65 ? Math.PI / 2 + (rnd() - 0.5) * 0.9 : rnd() * Math.PI;\n const len = 5 + rnd() * 16;\n const bend = (rnd() - 0.5) * 0.12;\n const tone = (rnd() < 0.55 ? 1 : -1) * (0.35 + rnd() * 0.65);\n const wid = 0.45 + rnd() * 0.5;\n let x = x0;\n let y = y0;\n let ang = a;\n for (let s = 0; s < len; s += 0.5) {\n x += Math.cos(ang) * 0.5; y += Math.sin(ang) * 0.5; ang += bend;\n const fade = Math.sin((s / len) * Math.PI);\n for (let dy = -2; dy <= 2; dy++) for (let dx = -2; dx <= 2; dx++) {\n const px = Math.floor(x) + dx;\n const py = Math.floor(y) + dy;\n const ddx = px + 0.5 - x;\n const ddy = py + 0.5 - y;\n const g = Math.exp(-(ddx * ddx + ddy * ddy) / (2 * wid * wid));\n const ix = ((px % N) + N) % N;\n const iy = ((py % N) + N) % N;\n fib[iy * N + ix] = (fib[iy * N + ix] as number) + tone * g * fade * 0.18;\n }\n }\n }\n for (let j = 0; j < N; j++) for (let i = 0; i < N; i++) {\n const u = (i + 0.5) / N;\n const v = (j + 0.5) / N;\n const m = vnoise(u, v, 4, seed)[0] + 0.5 * vnoise(u, v, 8, seed + 1)[0];\n const t1 = vnoise(u, v, 32, seed + 2);\n const t2 = vnoise(u, v, 64, seed + 3);\n const gx = t1[1] + 0.5 * t2[1];\n const gy = t1[2] + 0.5 * t2[2];\n const o = (j * N + i) * 4;\n out[o] = Math.round(Math.min(Math.max(0.5 + m * 0.9, 0), 1) * 255);\n out[o + 1] = Math.round(Math.min(Math.max(0.5 + (fib[j * N + i] as number), 0), 1) * 255);\n out[o + 2] = Math.round(Math.min(Math.max(0.5 + gx / TOOTH_SCALE / 2, 0), 1) * 255);\n out[o + 3] = Math.round(Math.min(Math.max(0.5 + gy / TOOTH_SCALE / 2, 0), 1) * 255);\n }\n void fract;\n return out;\n}\n","// ONE PHYSICS (design-015 §6; BOOK.md, BOARD.md, MINIMAT.md): every desk object under the mat's one lamp lifts, casts and\n// reads its face by the same law — the note's lift and penumbra, the slab's contact term at its base, the face's fill, the\n// selection ring — so the note, the notebook, the whiteboard, the mini mat and the print agree by NAME, never by copy. The\n// numbers stood in the engine's theme inside the note's and the notebook's specs until K4a (design-016 §5); each kind's\n// own spec (paper/theme.ts, notebook/theme.ts, board/theme.ts, minimat/theme.ts) now takes them from here, and no kind\n// reads another's. Lengths are world units (CSS px at zoom 1).\n\n/** The shadow's penumbra, as the note casts it (theme.ts `PAPER.shadow` until K4a). */\nconst SHADOW = { sigma: 2.2, alpha: 0.36, sigmaPerUnit: 0.9, alphaHeld: 0.4, slopeMax: 2.2 } as const;\n\nexport const PHYSICS = {\n /** How far a HELD note rises (§7's lift, as a height), and the scale it reads at (§7's 1.05, kept). */\n lift: { height: 12, scale: 1.03 },\n /**\n * The contact shadow on the mat: Gaussian-blurred coverage of the sheet cast along the lamp's\n * ground direction by its height — σ and alpha at contact, σ growing per unit of height, the\n * alpha a held note casts, and the slope's cap (a note far from the lamp keeps a finite shadow).\n */\n shadow: SHADOW,\n /**\n * A SLAB's shadow (a notebook, a whiteboard, a mini mat): the note's penumbra swept down its height, with a contact\n * term at its base (the tree-shadow design system's paper elevation, mat.css `--lift-1`) — theme.ts `BOOK.shadow` until K4a.\n */\n slab: {\n penumbra: { sigma0: SHADOW.sigma, sigmaPerHeight: SHADOW.sigmaPerUnit, alpha: SHADOW.alpha },\n /** The contact term: σ, alpha, and the gap (world units) it has faded over once the object floats. */\n contact: { sigma: 1.1, alpha: 0.3, reach: 2.5 },\n slopeMax: SHADOW.slopeMax,\n },\n /** The lamp's fill on a face turned away from it; how far past a flat face one turned toward it may brighten. */\n light: { ambient: 0.5, cap: 1.35 },\n /** The sole-selection ring (DESIGN.md §7), CSS px, in `--vf-select`. */\n ring: 1.5,\n} as const;\n","// (The kit's since K4a, design-016 §5 — moved from notebook/place.ts: the desk calendar places its pad by the same rigid maths.)\n//\n// Where a notebook IS on the desk, and the light on it (NOTEBOOK.md §5). Pure.\n//\n// A book's mesh is built in its own coordinates; this places it: a centre on the mat, a turn\n// in the mat's plane, a lift off it and a tilt about its own middle while held. One rigid\n// matrix does it on the GPU (`model`), and its inverse brings the pointer's ray back into the\n// book for the hit test. The lamp is the desk's one light (paper.ts `lampOf`): per book, the\n// unit direction toward it with the shadow's ground slope capped — the note's, the photo's\n// and the notebook's shadows fall the same way from the same lamp — and the orthographic\n// frame its shadow map is drawn in, fitted to the book's bounds as it stands this frame.\n\nimport type { Lamp } from \"./light\";\n\nexport interface Placement {\n readonly cx: number; readonly cy: number;\n /** Radians in the mat's plane; positive turns clockwise on screen. */\n readonly angle: number;\n /** Units off the mat. */\n readonly lift: number;\n /** Radians about the book's own x (its head dips for +) and y (its fore-edge dips for +) axes, through its middle `zc` up. */\n readonly tiltX: number; readonly tiltY: number;\n readonly zc: number;\n}\n\n/** A rigid transform: 3×3 rotation (row-major) and a translation. */\nexport interface Rigid { readonly r: readonly number[]; readonly t: readonly [number, number, number] }\n\nexport function rigidOf(p: Placement): Rigid {\n const cz = Math.cos(p.angle);\n const sz = Math.sin(p.angle);\n const cx = Math.cos(p.tiltX);\n const sx = Math.sin(p.tiltX);\n const cy = Math.cos(p.tiltY);\n const sy = Math.sin(p.tiltY);\n // Rz · Rx · Ry\n const rx = [1, 0, 0, 0, cx, -sx, 0, sx, cx];\n const ry = [cy, 0, sy, 0, 1, 0, -sy, 0, cy];\n const rz = [cz, -sz, 0, sz, cz, 0, 0, 0, 1];\n const mul = (a: readonly number[], b: readonly number[]) => { const o: number[] = []; for (let i = 0; i < 3; i++) for (let j = 0; j < 3; j++) o.push((a[i * 3] as number) * (b[j] as number) + (a[i * 3 + 1] as number) * (b[3 + j] as number) + (a[i * 3 + 2] as number) * (b[6 + j] as number)); return o; };\n const r = mul(rz, mul(rx, ry));\n // pivot the tilt about the book's middle: t = (cx, cy, lift + zc) − R·(0, 0, zc)\n const t: [number, number, number] = [p.cx - (r[2] as number) * p.zc, p.cy - (r[5] as number) * p.zc, p.lift + p.zc - (r[8] as number) * p.zc];\n return { r, t };\n}\n\nexport function toWorld(g: Rigid, x: number, y: number, z: number): [number, number, number] {\n const r = g.r;\n return [(r[0] as number) * x + (r[1] as number) * y + (r[2] as number) * z + g.t[0], (r[3] as number) * x + (r[4] as number) * y + (r[5] as number) * z + g.t[1], (r[6] as number) * x + (r[7] as number) * y + (r[8] as number) * z + g.t[2]];\n}\nexport function dirToWorld(g: Rigid, x: number, y: number, z: number): [number, number, number] {\n const r = g.r;\n return [(r[0] as number) * x + (r[1] as number) * y + (r[2] as number) * z, (r[3] as number) * x + (r[4] as number) * y + (r[5] as number) * z, (r[6] as number) * x + (r[7] as number) * y + (r[8] as number) * z];\n}\nexport function toLocal(g: Rigid, x: number, y: number, z: number): [number, number, number] {\n const r = g.r;\n const dx = x - g.t[0];\n const dy = y - g.t[1];\n const dz = z - g.t[2];\n return [(r[0] as number) * dx + (r[3] as number) * dy + (r[6] as number) * dz, (r[1] as number) * dx + (r[4] as number) * dy + (r[7] as number) * dz, (r[2] as number) * dx + (r[5] as number) * dy + (r[8] as number) * dz];\n}\nexport function dirToLocal(g: Rigid, x: number, y: number, z: number): [number, number, number] {\n const r = g.r;\n return [(r[0] as number) * x + (r[3] as number) * y + (r[6] as number) * z, (r[1] as number) * x + (r[4] as number) * y + (r[7] as number) * z, (r[2] as number) * x + (r[5] as number) * y + (r[8] as number) * z];\n}\n\n/** Column-major 4×4 (WGSL's mat4x4f) of a rigid transform. */\nexport function matrixOf(g: Rigid): Float32Array {\n const r = g.r;\n const m = new Float32Array(16);\n m[0] = r[0] as number; m[1] = r[3] as number; m[2] = r[6] as number;\n m[4] = r[1] as number; m[5] = r[4] as number; m[6] = r[7] as number;\n m[8] = r[2] as number; m[9] = r[5] as number; m[10] = r[8] as number;\n m[12] = g.t[0]; m[13] = g.t[1]; m[14] = g.t[2]; m[15] = 1;\n return m;\n}\n\n/** The unit direction toward the lamp from a desk point, the ground slope capped (a book far from the lamp keeps a finite shadow). */\nexport function lampDir(lamp: Lamp, x: number, y: number, slopeMax: number): [number, number, number] {\n let dx = lamp.x - x;\n let dy = lamp.y - y;\n const h = Math.max(lamp.h, 1e-6);\n const s = Math.hypot(dx, dy) / h;\n if (s > slopeMax) { dx *= slopeMax / s; dy *= slopeMax / s; }\n const l = Math.hypot(dx, dy, h);\n return [dx / l, dy / l, h / l];\n}\n\n/**\n * The shadow map's frame for a book: an orthographic view along the light, square, fitted to\n * the book's world-space box (grown by `pad`). Out: the world → clip matrix (x, y in −1…1, z\n * 0 nearest the lamp … 1), the world size of one texel at `res`, and the depth range (world).\n */\nexport function lightFrame(L: readonly [number, number, number], lo: readonly [number, number, number], hi: readonly [number, number, number], res: number, pad = 6, receivers: readonly (readonly [number, number, number])[] = []): { matrix: Float32Array; texel: number; depth: number } {\n const f: [number, number, number] = [-L[0], -L[1], -L[2]];\n let r: [number, number, number] = Math.abs(f[2]) > 0.999 ? [1, 0, 0] : [f[1] * 1 - f[2] * 0, f[2] * 0 - f[0] * 1, 0];\n const rl = Math.hypot(r[0], r[1], r[2]) || 1; r = [r[0] / rl, r[1] / rl, r[2] / rl];\n const u: [number, number, number] = [r[1] * f[2] - r[2] * f[1], r[2] * f[0] - r[0] * f[2], r[0] * f[1] - r[1] * f[0]];\n let x0 = Number.POSITIVE_INFINITY;\n let x1 = Number.NEGATIVE_INFINITY;\n let y0 = Number.POSITIVE_INFINITY;\n let y1 = Number.NEGATIVE_INFINITY;\n let d0 = Number.POSITIVE_INFINITY;\n let d1 = Number.NEGATIVE_INFINITY;\n for (let i = 0; i < 8; i++) {\n const P = [i & 1 ? hi[0] : lo[0], i & 2 ? hi[1] : lo[1], i & 4 ? hi[2] : lo[2]] as const;\n const lx = P[0] * r[0] + P[1] * r[1] + P[2] * r[2];\n const ly = P[0] * u[0] + P[1] * u[1] + P[2] * u[2];\n const d = P[0] * f[0] + P[1] * f[1] + P[2] * f[2];\n x0 = Math.min(x0, lx); x1 = Math.max(x1, lx); y0 = Math.min(y0, ly); y1 = Math.max(y1, ly); d0 = Math.min(d0, d); d1 = Math.max(d1, d);\n }\n // the receivers only reach the depth range: a desk point behind the book must compare INSIDE it, or it reads as occluded by nothing at all\n for (const P of receivers) d1 = Math.max(d1, P[0] * f[0] + P[1] * f[1] + P[2] * f[2]);\n const half = Math.max(x1 - x0, y1 - y0) / 2 + pad;\n const mx = (x0 + x1) / 2;\n const my = (y0 + y1) / 2;\n x0 = mx - half; x1 = mx + half; y0 = my - half; y1 = my + half; d0 -= pad; d1 += pad;\n const sx = 2 / (x1 - x0);\n const sy = 2 / (y1 - y0);\n const sd = 1 / (d1 - d0);\n const m = new Float32Array(16);\n // rows: clip.x = sx·(P·r) − sx·x0 − 1 ; clip.y = sy·(P·u) − sy·y0 − 1 ; clip.z = sd·(P·f) − sd·d0 ; w = 1\n m[0] = sx * r[0]; m[4] = sx * r[1]; m[8] = sx * r[2]; m[12] = -sx * x0 - 1;\n m[1] = sy * u[0]; m[5] = sy * u[1]; m[9] = sy * u[2]; m[13] = -sy * y0 - 1;\n m[2] = sd * f[0]; m[6] = sd * f[1]; m[10] = sd * f[2]; m[14] = -sd * d0;\n m[15] = 1;\n return { matrix: m, texel: (x1 - x0) / res, depth: d1 - d0 };\n}\n\n/** A local box through the rigid transform → its world-space bounds. */\nexport function worldBounds(g: Rigid, lo: readonly [number, number, number], hi: readonly [number, number, number]): { lo: [number, number, number]; hi: [number, number, number] } {\n const a: [number, number, number] = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];\n const b: [number, number, number] = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];\n for (let i = 0; i < 8; i++) {\n const p = toWorld(g, i & 1 ? hi[0] : lo[0], i & 2 ? hi[1] : lo[1], i & 4 ? hi[2] : lo[2]);\n for (let k = 0; k < 3; k++) { a[k] = Math.min(a[k] as number, p[k] as number); b[k] = Math.max(b[k] as number, p[k] as number); }\n }\n return { lo: a, hi: b };\n}\n\n/** The inverse of a rigid transform. */\nexport function inverseOf(g: Rigid): Rigid {\n const r = g.r;\n const rt = [r[0], r[3], r[6], r[1], r[4], r[7], r[2], r[5], r[8]] as number[];\n const t = g.t;\n return { r: rt, t: [-((rt[0] as number) * t[0] + (rt[1] as number) * t[1] + (rt[2] as number) * t[2]), -((rt[3] as number) * t[0] + (rt[4] as number) * t[1] + (rt[5] as number) * t[2]), -((rt[6] as number) * t[0] + (rt[7] as number) * t[1] + (rt[8] as number) * t[2])] };\n}\n","// THE PRINT'S RASTER — a service a kind is lent (`PRINT_RASTER`, K8a — the desk calendar's DOM half lends it; moved here from calendar/printing.ts at K4a,\n// design-016 §5, so the contract names no kind's folder): the host's hand face and its metrics, a version that turns\n// over when a face lands, the type's widths, and a rectangle of a PRINT drawn into a tile. What a print is belongs to\n// the kind that prints (the desk calendar's `SheetPrint`), so the service is generic over it — `P` is opaque here and\n// the kind's own type in the kind; the host half that draws it (desk/host/print.ts) names the same `P`.\n\nimport { type ServiceKey, serviceKey } from \"./services\";\nimport type { HandMetrics } from \"./text\";\n\n/** The hand's face as a print sets it: a family and a weight (the host loads it — desk/host/ink.ts `PEN_FACES`). */\nexport interface PrintFace {\n readonly family: string;\n readonly weight: number;\n}\n\n/** What a pass takes a tile as: the host's canvas (TILE_TEX², straight alpha) — a type only. */\nexport type TileSource = HTMLCanvasElement | OffscreenCanvas;\n\n/**\n * THE PRINT'S RASTER (the host's seam, as `TextRaster` is the note's): the hand's face and its metrics (undefined while the\n * face loads — the print waits rather than set the hand in a stand-in face), a version that turns over when a face lands,\n * the type's widths, and a rectangle of a print drawn into a tile at `band` texels a unit.\n */\nexport interface PrintRaster<P = unknown> {\n hand(): { readonly face: PrintFace; readonly metrics: HandMetrics } | undefined;\n version(): number;\n measure(font: string, text: string): number;\n tile(print: P, x: number, y: number, w: number, h: number, band: number): TileSource;\n /** The same rectangle as RGBA bytes, TILE_TEX² × 4, row 0 at the top — a fixture's (a rig reads the live print through it). */\n bytes(print: P, x: number, y: number, w: number, h: number, band: number): Uint8Array<ArrayBuffer>;\n}\n\n/**\n * The print raster as a desk SERVICE (K8a, kit/services.ts): lent by the object whose DOM half makes it (the desk calendar's,\n * over the host's text raster) and `use`d by any kind that prints — `host.use?.(PRINT_RASTER)`.\n */\nexport const PRINT_RASTER: ServiceKey<PrintRaster> = serviceKey<PrintRaster>(\"print\");\n","// The desk's shared 2D distance — pure, no GPU: the CPU mirror of\n// shaders/primitives.wgsl `sdf_round_box`, exact Euclidean, which every object's\n// hit test and CPU mirror reads (the note, the whiteboard, the mini mat). It\n// lived beside the card frame's mirror until the cards retired (2026-09-25).\n// (Lineage: research/sdf-card/src/sdf.js.)\n\nexport const sdRoundBox = (px: number, py: number, bx: number, by: number, r: number): number => {\n const rr = Math.min(Math.max(r, 0), Math.min(bx, by));\n const qx = Math.abs(px) - bx + rr;\n const qy = Math.abs(py) - by + rr;\n return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - rr;\n};\n","// The hand's SEEDS as a durable cell (design-015 D-D13; D2c). Every glyph of a note carries its own\n// seed — its tilt, rise, size and pressure are a hash of it (text.ts `hashHand`) — and `carrySeeds`\n// keeps them through an edit, so a letter typed before the next keeps its hand. The prototype kept\n// them in memory; here they are DOCUMENT truth beside the text (the note's `ink` group: `text` and\n// `seeds`, one cell, written in the same transaction), or a reload would re-draw the hand.\n//\n// The encoding: one little-endian u32 per UTF-16 unit of the text (the layout's own indexing),\n// base64 without padding — 4 bytes a glyph, deterministic on every host (integer arithmetic, no\n// `btoa`). A TOLERANT reader: a malformed string decodes to what it can (whole seeds only), and a\n// glyph with no stored seed falls back to `glyphSeed(noteSeed, i)` — which is also what a NEW note's\n// seeds are, so a note spawned with text and no seeds writes exactly the hand it would have written.\n\nimport { glyphSeed } from \"./text\";\n\nconst ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nconst INDEX: Readonly<Record<string, number>> = Object.fromEntries([...ALPHABET].map((c, i) => [c, i]));\n\n/** The seeds as the cell stores them: base64 (no padding) of little-endian u32s. */\nexport function encodeSeeds(seeds: ArrayLike<number>): string {\n const n = seeds.length;\n const bytes = new Uint8Array(n * 4);\n for (let i = 0; i < n; i++) {\n const v = (seeds[i] as number) >>> 0;\n bytes[4 * i] = v & 255;\n bytes[4 * i + 1] = (v >>> 8) & 255;\n bytes[4 * i + 2] = (v >>> 16) & 255;\n bytes[4 * i + 3] = (v >>> 24) & 255;\n }\n let out = \"\";\n for (let i = 0; i < bytes.length; i += 3) {\n const a = bytes[i] as number;\n const b = i + 1 < bytes.length ? (bytes[i + 1] as number) : 0;\n const c = i + 2 < bytes.length ? (bytes[i + 2] as number) : 0;\n const t = (a << 16) | (b << 8) | c;\n out += ALPHABET[(t >>> 18) & 63];\n out += ALPHABET[(t >>> 12) & 63];\n if (i + 1 < bytes.length) out += ALPHABET[(t >>> 6) & 63];\n if (i + 2 < bytes.length) out += ALPHABET[t & 63];\n }\n return out;\n}\n\n/** The seeds a cell holds, as i32s (the layout's `seeds`) — whole seeds only; anything unreadable ends the run. */\nexport function decodeSeeds(s: string): number[] {\n const bytes: number[] = [];\n let acc = 0;\n let bits = 0;\n for (const ch of s) {\n const v = INDEX[ch];\n if (v === undefined) break;\n acc = ((acc << 6) | v) & 0xffffff;\n bits += 6;\n if (bits >= 8) {\n bits -= 8;\n bytes.push((acc >>> bits) & 255);\n }\n }\n const out: number[] = [];\n for (let i = 0; i + 3 < bytes.length; i += 4) {\n out.push(((bytes[i] as number) | ((bytes[i + 1] as number) << 8) | ((bytes[i + 2] as number) << 16) | ((bytes[i + 3] as number) << 24)) | 0);\n }\n return out;\n}\n\n/**\n * The seeds a note's text is written with: the stored ones, index for index, and for every glyph\n * past them the note's own `glyphSeed(noteSeed, i)` — exactly `text.length` of them.\n */\nexport function seedsFor(text: string, stored: string, noteSeed: number): number[] {\n const got = decodeSeeds(stored);\n const out = new Array<number>(text.length);\n for (let i = 0; i < text.length; i++) out[i] = i < got.length ? (got[i] as number) : glyphSeed(noteSeed, i);\n return out;\n}\n\n/** A fresh seed for a glyph just written — the host's randomness (`Math.random` in a browser). */\nexport const freshSeed = (): number => (Math.random() * 0x7fffffff) | 0;\n","// A STROKE — the data child of an object that takes ink (design-015 §5.1: a stroke is one transaction, so undo, sync,\n// persistence and presence come from strata): the whiteboard's marker strokes and wipes, the notebook's pen strokes on a\n// page. Its component and prefab, its row as a tolerant reader takes it, the spec a pen lays, the cell codecs (paths and\n// times as base64 f32), and the fibre seed a replay walks. The whiteboard's until K4a (board/data.ts); the notebook\n// borrowed it whole, so it is the kit's (design-016 §5), and both keep their doors. And `inking`: a stroke is in hand.\n\nimport { ChildOf, defineComponent, definePrefab, defineQuery, type Entity, field, type GuardedTx, HeldPress, init, LocalPointer, Pointer, type World } from \"@ice/core\";\nimport { decodeSeeds, encodeSeeds } from \"./seeds\";\n\n/** A board's data child: a stroke (`marker`, with `erase` for the eraser) or a wipe. */\nexport const BoardStroke = defineComponent(\"desk.stroke\", {\n tool: field(\"string\", { default: \"marker\" }),\n ink: field(\"string\", { default: \"black\" }),\n tip: field(\"string\", { default: \"bullet\" }),\n erase: field(\"bool\", { default: false }),\n points: field(\"string\", { default: \"\" }),\n speed: field(\"f64\", { default: 400 }),\n times: field(\"string\", { default: \"\" }),\n page: field(\"u32\", { default: 0 }),\n seed: field(\"f64\", { default: -1 }),\n});\n\n/** A stroke's cell as the board reads it (a tolerant reader: a string field strata hands back as null reads as its default). */\nexport interface StrokeRow {\n readonly tool: string | null;\n readonly ink: string | null;\n readonly tip: string | null;\n readonly erase: boolean | null;\n readonly points: string | null;\n readonly speed: number | null;\n readonly times?: string | null;\n /** The notebook page it is on (D3t-b — v3): 2i + 1 a sheet's recto, 2i + 2 its verso; 0 (or absent, a v2 reader's) = none. */\n readonly page?: number | null;\n /** Its fibre seed (D7 #13 — v4): the one the live pen laid with; −1 (or absent, a v3 reader's) = the seed its position gives it. */\n readonly seed?: number | null;\n}\n\n/** The durable id a stroke entity carries (`PrefabId`) — a data child, never a widget. */\nexport const STROKE_TYPE = \"desk.stroke\";\n\n/**\n * A stroke's durable prefab: its one cell and its `ChildOf` edge to the board (or the book) it is on. Version 2 (D3t-a) added\n * `times`; a v1 stroke migrates to an empty one — it keeps its `speed` (the replay spaces it as before). Version 3 (D3t-b) added\n * `page`; a v2 stroke — a board's — migrates to page 0. The Board and the Notebook declare it as their `data`, so the engine's\n * catalog stamps, gates and migrates it with them.\n */\nexport const StrokePrefab = definePrefab(STROKE_TYPE, {\n store: \"durable\",\n version: 4,\n components: [init(BoardStroke, { tool: \"marker\", ink: \"black\", tip: \"bullet\", erase: false, points: \"\", speed: 400, times: \"\", page: 0, seed: -1 })],\n relations: [ChildOf],\n // v4 (D7 #13): `seed` — the fibre seed the pen laid with; a v3 stroke keeps the seed its position gives it (−1), so nothing it drew changes\n migrate: { 1: (v) => ({ ...v, times: \"\" }), 2: (v) => ({ ...v, page: 0 }), 3: (v) => ({ ...v, seed: -1 }) },\n});\n\n/** A row's fibre seed: its own (v4, the pen's) — or, for a row from before or without one, the `n`-th op's positional seed. */\nexport const seedOfRow = (s: Pick<StrokeRow, \"seed\">, n: number): number => (s.seed !== null && s.seed !== undefined && s.seed >= 0 ? s.seed : strokeSeed(n));\n\n/**\n * A stroke as an author states one: the path in melamine units (a notebook's: page units, on its `page`) and its pace — each\n * sample's time (ms from the first), or one speed; a wipe has no path.\n */\nexport interface StrokeSpec {\n readonly tool?: \"marker\" | \"wipe\" | \"pen\";\n readonly ink?: string;\n readonly tip?: string;\n readonly erase?: boolean;\n readonly points?: readonly (readonly [number, number])[];\n readonly times?: readonly number[];\n readonly speed?: number;\n /** The notebook page (D3t-b): 2i + 1 sheet i's recto, 2i + 2 its verso; absent = 0, a board's. */\n readonly page?: number;\n /** The fibre seed the pen laid with (D7 #13): stored, so the replay lays the same stamps whatever lands before it; absent = the position's. */\n readonly seed?: number;\n}\n\n/** A path as the cell stores it: base64 (no padding) of LE f32 (x, y) pairs. */\nexport function encodePoints(points: readonly (readonly [number, number])[]): string {\n const f = new Float32Array(points.length * 2);\n points.forEach(([x, y], i) => { f[2 * i] = x; f[2 * i + 1] = y; });\n return encodeSeeds(new Uint32Array(f.buffer));\n}\n\n/** A cell's path back: whole points only (a tolerant reader — anything unreadable ends the path). */\nexport function decodePoints(s: string): Array<readonly [number, number]> {\n const words = decodeSeeds(s);\n const f = new Float32Array(new Int32Array(words).buffer);\n const out: Array<readonly [number, number]> = [];\n for (let i = 0; i + 1 < f.length; i += 2) out.push([f[i] as number, f[i + 1] as number]);\n return out;\n}\n\n/** The samples' times as the cell stores them (D3t-a): base64 (no padding) of LE f32 milliseconds from the first sample. */\nexport function encodeTimes(times: readonly number[]): string {\n return encodeSeeds(new Uint32Array(Float32Array.from(times).buffer));\n}\n\n/** A cell's times back (a tolerant reader: \"\" — an old stroke — is none). */\nexport function decodeTimes(s: string): number[] {\n return Array.from(new Float32Array(new Int32Array(decodeSeeds(s)).buffer));\n}\n\n/** A path's mean pace, world units/s — what a v2 stroke leaves in `speed` for a reader that knows no `times`; the default for a dot. */\nexport function meanSpeed(points: readonly (readonly [number, number])[], times: readonly number[]): number {\n let length = 0;\n for (let i = 1; i < points.length; i++) { const a = points[i - 1] as readonly [number, number]; const b = points[i] as readonly [number, number]; length += Math.hypot(b[0] - a[0], b[1] - a[1]); }\n const ms = (times[times.length - 1] ?? 0) - (times[0] ?? 0);\n return length > 0 && ms > 0 ? (length / ms) * 1000 : 400;\n}\n\n/** The row a spec is — defaults as the prefab has them; timed, its `speed` is the path's mean pace unless the spec names one. */\nexport function strokeRow(s: StrokeSpec): { tool: string; ink: string; tip: string; erase: boolean; points: string; speed: number; times: string; page: number; seed: number } {\n const points = s.points ?? [];\n const timed = s.times !== undefined && s.times.length === points.length && points.length > 0;\n return {\n tool: s.tool ?? \"marker\", ink: s.ink ?? \"black\", tip: s.tip ?? \"bullet\", erase: s.erase === true,\n points: encodePoints(points), speed: s.speed ?? (timed ? meanSpeed(points, s.times ?? []) : 400),\n times: timed ? encodeTimes(s.times ?? []) : \"\",\n page: Math.max(0, Math.floor(s.page ?? 0)),\n seed: s.seed !== undefined && Number.isFinite(s.seed) && s.seed >= 0 ? s.seed : -1,\n };\n}\n\n/** Lay a stroke on a board (or a book's page) — one entity, the object's newest child — inside the caller's transaction (one stroke, one undo step). */\nexport function addStroke(tx: GuardedTx, board: Entity, s: StrokeSpec): Entity {\n const e = tx.spawnPrefab(StrokePrefab, [init(BoardStroke, strokeRow(s))]);\n tx.setRelation(e, ChildOf, board); // placeless on the ordered ChildOf: appended last — the newest stroke\n return e;\n}\n\n/** The fibre seed of the `n`-th op a replay walks — the bench's `97.13 ×` the ops before it; the live pen seeds its stroke with the next. */\nexport const strokeSeed = (n: number): number => (n * 97.13) % 1000;\n\nconst heldPressesQ = defineQuery([Pointer, LocalPointer, HeldPress]);\n/** A stroke is in hand (a local pointer's press is a tool's): a history waits for it to land (BOARD.md §5 — the bench's `!this.open?.stroke`). */\nexport function inking(world: World): boolean {\n let yes = false;\n world.query(heldPressesQ).each((b) => { for (const r of b) if (world.read(b.entity(r), HeldPress).kind === \"tool\") yes = true; });\n return yes;\n}\n","// A UNIFORM WRITTEN ONLY WHEN IT CHANGED (design-016 K-L3 — a standing value costs a frame nothing). A kind's knobs — its\n// law, its colours, the ring — stand still frame after frame while the camera moves, and the slot's view block carries\n// what moves; so a pass keeps the bytes the GPU holds and writes a block only when they differ. The shader reads the same\n// values either way: WebGPU zero-fills a new buffer, and `sent` starts as those zeros.\n\nimport type { StructBuffer } from \"../engine/struct\";\n\n/** What a pass keeps beside a buffer it writes change-only: the bytes the GPU holds (sized to the buffer). */\nexport const sentBytes = (size: number): Uint8Array => new Uint8Array(size);\n\n/**\n * Write `block` (its first `elements`, or all) into `buffer` at 0 only when its bytes differ from `sent` — which then holds\n * them. Returns whether it wrote.\n */\nexport function writeChanged(queue: GPUQueue, buffer: GPUBuffer, block: StructBuffer<string>, sent: Uint8Array, elements?: number): boolean {\n const bytes = block.view(elements);\n if (bytes.byteLength > sent.byteLength) throw new Error(`writeChanged: ${bytes.byteLength} bytes into a ${sent.byteLength}-byte record of what was sent`);\n let same = true;\n for (let i = 0; i < bytes.byteLength; i++) if (bytes[i] !== sent[i]) { same = false; break; }\n if (same) return false;\n queue.writeBuffer(buffer, 0, bytes);\n sent.set(bytes);\n return true;\n}\n","// The cutting mat's line law — pure maths beside lod.ts. A rung's LINES fade in\n// over the same `fadeIn` window every glyph uses (by the rung's OWN cell, so a\n// decade wrap is continuous by construction), and then thicken and darken over\n// the NEXT decade: thin/faint at the window's top, thick/strong ten times\n// coarser. That is the reference's ladder (research/tree-shadow hero:\n// fine 0.14·fade · mid 0.14→0.28, 0.5→0.75 px · coarse 0.28, 0.75 px) written\n// as one function of the cell, anchored on the engine's window instead of its\n// own 6 px. At a wrap the old fine rung IS the new mid rung at the same cell,\n// so it draws the same line; the old coarse rung's lines are every tenth of the\n// new coarse rung's and already carry the saturated weight — nothing pops.\n\nimport { type FadeIn, smoothstep } from \"./lod\";\n\nexport interface LineLaw {\n /** Half-widths at the window's top and a decade above it, DEVICE px (the reference's hairlines). */\n readonly thin: number;\n readonly thick: number;\n /** Coverage alphas at the same two points. */\n readonly alphaThin: number;\n readonly alphaThick: number;\n}\n\nexport interface LineWeight {\n readonly halfWidth: number; // device px\n readonly alpha: number;\n}\n\nconst clamp01 = (x: number) => Math.min(Math.max(x, 0), 1);\n\n/** mat.wgsl `line_weight`, for a rung whose on-screen cell is `cellPx` (CSS px). */\nexport function lineWeight(cellPx: number, fadeIn: FadeIn, law: LineLaw): LineWeight {\n const s = smoothstep(fadeIn[0], fadeIn[1], cellPx);\n const t = clamp01(Math.log10(Math.max(cellPx, 1e-9) / Math.max(fadeIn[1], 1e-9)));\n return {\n halfWidth: law.thin + (law.thick - law.thin) * t,\n alpha: law.alphaThin * s + (law.alphaThick - law.alphaThin) * t,\n };\n}\n"],"mappings":"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","names":["smoothstep","clamp01","clip","hash","WGSL","cells","a","b","mul","clamp01"]}