@vibecook/ice 0.10.0 → 0.14.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 (380) hide show
  1. package/README.md +79 -50
  2. package/dist/chunk-BA7XJC27.js +2429 -0
  3. package/dist/chunk-BA7XJC27.js.map +1 -0
  4. package/dist/chunk-BKV4ZEU3.js +1 -0
  5. package/dist/chunk-BKV4ZEU3.js.map +1 -0
  6. package/dist/{chunk-5FQS7V2C.js → chunk-DYK6KNLG.js} +13303 -7485
  7. package/dist/chunk-DYK6KNLG.js.map +1 -0
  8. package/dist/chunk-ENIFIUEP.js +155 -0
  9. package/dist/chunk-ENIFIUEP.js.map +1 -0
  10. package/dist/chunk-IBWWLA6D.js +634 -0
  11. package/dist/chunk-IBWWLA6D.js.map +1 -0
  12. package/dist/{chunk-OR5FNVUE.js → chunk-JS6PG6YD.js} +398 -167
  13. package/dist/chunk-JS6PG6YD.js.map +1 -0
  14. package/dist/chunk-QXOCF56A.js +148 -0
  15. package/dist/chunk-QXOCF56A.js.map +1 -0
  16. package/dist/chunk-ZPUPBULB.js +7399 -0
  17. package/dist/chunk-ZPUPBULB.js.map +1 -0
  18. package/dist/desk-engine.js +36 -0
  19. package/dist/desk-engine.js.map +1 -0
  20. package/dist/desk-kit.js +244 -0
  21. package/dist/desk-kit.js.map +1 -0
  22. package/dist/desk-objects.js +12728 -0
  23. package/dist/desk-objects.js.map +1 -0
  24. package/dist/desk.js +469 -0
  25. package/dist/desk.js.map +1 -0
  26. package/dist/devtools.js +233 -189
  27. package/dist/devtools.js.map +1 -1
  28. package/dist/dom.js +7 -19
  29. package/dist/index.js +232 -20
  30. package/dist/kernel.js +53 -25
  31. package/dist/react.js +1045 -38
  32. package/dist/react.js.map +1 -1
  33. package/dist/types/packages/core/src/behavior/define-behavior.d.ts +11 -0
  34. package/dist/types/packages/core/src/behavior/runtime.d.ts +4 -0
  35. package/dist/types/packages/core/src/canvas/define-canvas-type.d.ts +86 -0
  36. package/dist/types/packages/core/src/canvas/define-container.d.ts +17 -0
  37. package/dist/types/packages/core/src/canvas/diagnostics.d.ts +27 -0
  38. package/dist/types/packages/core/src/canvas/engine-catalog.d.ts +70 -0
  39. package/dist/types/packages/core/src/canvas/extensions.d.ts +125 -0
  40. package/dist/types/packages/core/src/canvas/frame-behavior-host.d.ts +16 -0
  41. package/dist/types/packages/core/src/canvas/frame-preview.d.ts +79 -0
  42. package/dist/types/packages/core/src/canvas/frame-projection.d.ts +38 -0
  43. package/dist/types/packages/core/src/canvas/frame-view.d.ts +36 -0
  44. package/dist/types/packages/core/src/canvas/migrate.d.ts +14 -0
  45. package/dist/types/packages/core/src/canvas/placement.d.ts +30 -0
  46. package/dist/types/packages/core/src/canvas/presentation-transition.d.ts +100 -0
  47. package/dist/types/packages/core/src/canvas/runtime-extension-host.d.ts +16 -0
  48. package/dist/types/packages/core/src/canvas/session.d.ts +47 -0
  49. package/dist/types/packages/core/src/catalog/camera-derived.d.ts +16 -27
  50. package/dist/types/packages/core/src/catalog/desk.d.ts +326 -0
  51. package/dist/types/packages/core/src/catalog/gesture.d.ts +51 -0
  52. package/dist/types/packages/core/src/catalog/graph.d.ts +2 -2
  53. package/dist/types/packages/core/src/catalog/index.d.ts +2 -0
  54. package/dist/types/packages/core/src/catalog/pointer.d.ts +42 -0
  55. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +7 -0
  56. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +28 -2
  57. package/dist/types/packages/core/src/catalog/surface.d.ts +1 -0
  58. package/dist/types/packages/core/src/doc/doc-commit-sink.d.ts +18 -2
  59. package/dist/types/packages/core/src/doc/doc-kit.d.ts +21 -2
  60. package/dist/types/packages/core/src/doc/envelope.d.ts +5 -2
  61. package/dist/types/packages/core/src/doc/schema-migrate.d.ts +1 -1
  62. package/dist/types/packages/core/src/doc/version-gate.d.ts +21 -3
  63. package/dist/types/packages/core/src/engine/commit-sink.d.ts +10 -1
  64. package/dist/types/packages/core/src/engine/engine.d.ts +6 -0
  65. package/dist/types/packages/core/src/engine/frame-control.d.ts +74 -0
  66. package/dist/types/packages/core/src/engine/guests.d.ts +4 -1
  67. package/dist/types/packages/core/src/engine/world-doors.d.ts +12 -0
  68. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +146 -13
  69. package/dist/types/packages/core/src/index.d.ts +34 -13
  70. package/dist/types/packages/core/src/input/queue.d.ts +3 -1
  71. package/dist/types/packages/core/src/interaction/install.d.ts +30 -0
  72. package/dist/types/packages/core/src/interaction/wakes.d.ts +24 -0
  73. package/dist/types/packages/core/src/nav/nav-geometry.d.ts +100 -0
  74. package/dist/types/packages/core/src/nav/nested-canvas.d.ts +47 -4
  75. package/dist/types/packages/core/src/ops/cascade.d.ts +2 -1
  76. package/dist/types/packages/core/src/ops/claims.d.ts +6 -0
  77. package/dist/types/packages/core/src/ops/insert.d.ts +4 -0
  78. package/dist/types/packages/core/src/ops/point-pick.d.ts +4 -1
  79. package/dist/types/packages/core/src/ops/sibling-order.d.ts +14 -4
  80. package/dist/types/packages/core/src/ops/tray.d.ts +48 -0
  81. package/dist/types/packages/core/src/presence/presence-kit.d.ts +5 -0
  82. package/dist/types/packages/core/src/schema/meta.d.ts +10 -0
  83. package/dist/types/packages/core/src/schema/prefab.d.ts +8 -0
  84. package/dist/types/packages/core/src/settings/defaults.d.ts +25 -6
  85. package/dist/types/packages/core/src/surface/gpu-device.d.ts +55 -0
  86. package/dist/types/packages/core/src/systems/camera-sim.d.ts +29 -0
  87. package/dist/types/packages/core/src/systems/chrome.d.ts +15 -23
  88. package/dist/types/packages/core/src/systems/drag-mods.d.ts +34 -0
  89. package/dist/types/packages/core/src/systems/held.d.ts +71 -0
  90. package/dist/types/packages/core/src/systems/insert-ghost.d.ts +2 -0
  91. package/dist/types/packages/core/src/systems/l0-input.d.ts +14 -0
  92. package/dist/types/packages/core/src/systems/l1-pick.d.ts +37 -1
  93. package/dist/types/packages/core/src/systems/l2-arbitrate.d.ts +18 -4
  94. package/dist/types/packages/core/src/systems/l3-behave.d.ts +4 -1
  95. package/dist/types/packages/core/src/systems/l3-claim.d.ts +7 -0
  96. package/dist/types/packages/core/src/systems/l3-connect.d.ts +1 -1
  97. package/dist/types/packages/core/src/systems/l3-drop.d.ts +30 -1
  98. package/dist/types/packages/core/src/systems/l3-marquee.d.ts +2 -1
  99. package/dist/types/packages/core/src/systems/l3-ports.d.ts +1 -1
  100. package/dist/types/packages/core/src/systems/l4-cursor.d.ts +5 -0
  101. package/dist/types/packages/core/src/systems/nav-flight.d.ts +85 -3
  102. package/dist/types/packages/core/src/systems/nav-tap.d.ts +44 -0
  103. package/dist/types/packages/core/src/systems/press-wheel.d.ts +11 -0
  104. package/dist/types/packages/core/src/systems/tray.d.ts +108 -0
  105. package/dist/types/packages/core/src/systems/zoom-through.d.ts +30 -0
  106. package/dist/types/packages/core/src/tools/define-tool.d.ts +10 -0
  107. package/dist/types/packages/core/src/widget/define-widget.d.ts +166 -63
  108. package/dist/types/packages/core/src/widget/equip.d.ts +14 -2
  109. package/dist/types/packages/core/src/widget/held-tools.d.ts +83 -0
  110. package/dist/types/packages/core/src/widget/menu-actions.d.ts +44 -0
  111. package/dist/types/packages/core/src/widget/mount-store.d.ts +21 -46
  112. package/dist/types/packages/core/src/widget/spawn.d.ts +1 -1
  113. package/dist/types/packages/desk/src/assets/blue-noise.gen.d.ts +10 -0
  114. package/dist/types/packages/desk/src/card/card.d.ts +103 -0
  115. package/dist/types/packages/desk/src/compose/ambient.d.ts +59 -0
  116. package/dist/types/packages/desk/src/compose/builder.d.ts +285 -0
  117. package/dist/types/packages/desk/src/compose/children.d.ts +3 -0
  118. package/dist/types/packages/desk/src/compose/index.d.ts +14 -0
  119. package/dist/types/packages/desk/src/compose/marks.d.ts +126 -0
  120. package/dist/types/packages/desk/src/compose/pick.d.ts +5 -0
  121. package/dist/types/packages/desk/src/compose/reflector.d.ts +111 -0
  122. package/dist/types/packages/desk/src/compose/tap.d.ts +5 -0
  123. package/dist/types/packages/desk/src/docs.d.ts +23 -0
  124. package/dist/types/packages/desk/src/engine/budget.d.ts +38 -0
  125. package/dist/types/packages/desk/src/engine/device.d.ts +54 -0
  126. package/dist/types/packages/desk/src/engine/index.d.ts +5 -0
  127. package/dist/types/packages/desk/src/engine/pipeline.d.ts +36 -0
  128. package/dist/types/packages/desk/src/engine/rasters.d.ts +66 -0
  129. package/dist/types/packages/desk/src/engine/records.d.ts +56 -0
  130. package/dist/types/packages/desk/src/engine/shader.d.ts +22 -0
  131. package/dist/types/packages/desk/src/engine/struct.d.ts +39 -0
  132. package/dist/types/packages/desk/src/engine/target.d.ts +26 -0
  133. package/dist/types/packages/desk/src/gpu-ablation.d.ts +61 -0
  134. package/dist/types/packages/desk/src/gpu-memory.d.ts +54 -0
  135. package/dist/types/packages/desk/src/gpu-profiler.d.ts +141 -0
  136. package/dist/types/packages/desk/src/gpu-wrap.d.ts +8 -0
  137. package/dist/types/packages/desk/src/ground.d.ts +388 -0
  138. package/dist/types/packages/desk/src/hold/focus.d.ts +53 -0
  139. package/dist/types/packages/desk/src/hold/pose.d.ts +132 -0
  140. package/dist/types/packages/desk/src/hold/shaders.d.ts +9 -0
  141. package/dist/types/packages/desk/src/host/editor.d.ts +18 -0
  142. package/dist/types/packages/desk/src/host/index.d.ts +9 -0
  143. package/dist/types/packages/desk/src/host/ink.d.ts +18 -0
  144. package/dist/types/packages/desk/src/host/layer.d.ts +430 -0
  145. package/dist/types/packages/desk/src/host/picture.d.ts +2 -0
  146. package/dist/types/packages/desk/src/host/surface.d.ts +5 -0
  147. package/dist/types/packages/desk/src/index.d.ts +13 -0
  148. package/dist/types/packages/desk/src/kind.d.ts +187 -0
  149. package/dist/types/packages/desk/src/kinds/world.d.ts +429 -0
  150. package/dist/types/packages/desk/src/kit/arrays.d.ts +88 -0
  151. package/dist/types/packages/desk/src/kit/blobs.d.ts +40 -0
  152. package/dist/types/packages/desk/src/kit/book.d.ts +2 -0
  153. package/dist/types/packages/desk/src/kit/editor.d.ts +103 -0
  154. package/dist/types/packages/desk/src/kit/eye.d.ts +37 -0
  155. package/dist/types/packages/desk/src/kit/hold.d.ts +1 -0
  156. package/dist/types/packages/desk/src/kit/index.d.ts +26 -0
  157. package/dist/types/packages/desk/src/kit/inside.d.ts +116 -0
  158. package/dist/types/packages/desk/src/kit/layer.d.ts +159 -0
  159. package/dist/types/packages/desk/src/kit/light.d.ts +3 -0
  160. package/dist/types/packages/desk/src/kit/mesh.d.ts +29 -0
  161. package/dist/types/packages/desk/src/kit/mips.d.ts +2 -0
  162. package/dist/types/packages/desk/src/kit/nav.d.ts +2 -0
  163. package/dist/types/packages/desk/src/kit/paper-tex.d.ts +5 -0
  164. package/dist/types/packages/desk/src/kit/physics.d.ts +44 -0
  165. package/dist/types/packages/desk/src/kit/place.d.ts +44 -0
  166. package/dist/types/packages/desk/src/kit/print.d.ts +30 -0
  167. package/dist/types/packages/desk/src/kit/raster.d.ts +34 -0
  168. package/dist/types/packages/desk/src/kit/sdf.d.ts +1 -0
  169. package/dist/types/packages/desk/src/kit/seeds.d.ts +11 -0
  170. package/dist/types/packages/desk/src/kit/services.d.ts +34 -0
  171. package/dist/types/packages/desk/src/kit/springs.d.ts +12 -0
  172. package/dist/types/packages/desk/src/kit/strokes.d.ts +93 -0
  173. package/dist/types/packages/desk/src/kit/text.d.ts +142 -0
  174. package/dist/types/packages/desk/src/kit/uniform.d.ts +8 -0
  175. package/dist/types/packages/desk/src/kit/view.d.ts +39 -0
  176. package/dist/types/packages/desk/src/kit/wgsl.d.ts +15 -0
  177. package/dist/types/packages/desk/src/lattice/line.d.ts +15 -0
  178. package/dist/types/packages/desk/src/lattice/lod.d.ts +52 -0
  179. package/dist/types/packages/desk/src/lattice/ruler.d.ts +88 -0
  180. package/dist/types/packages/desk/src/marks/assemble.d.ts +65 -0
  181. package/dist/types/packages/desk/src/marks/ease.d.ts +4 -0
  182. package/dist/types/packages/desk/src/marks/laser.d.ts +41 -0
  183. package/dist/types/packages/desk/src/marks/layout.d.ts +167 -0
  184. package/dist/types/packages/desk/src/marks/pass.d.ts +59 -0
  185. package/dist/types/packages/desk/src/marks/shaders.d.ts +12 -0
  186. package/dist/types/packages/desk/src/mat/grid.d.ts +50 -0
  187. package/dist/types/packages/desk/src/mat/lamp.d.ts +14 -0
  188. package/dist/types/packages/desk/src/mat/layout.d.ts +144 -0
  189. package/dist/types/packages/desk/src/mat/mat-pass.d.ts +83 -0
  190. package/dist/types/packages/desk/src/mat/night.d.ts +95 -0
  191. package/dist/types/packages/desk/src/mat/projector.d.ts +39 -0
  192. package/dist/types/packages/desk/src/mat/shaders.d.ts +17 -0
  193. package/dist/types/packages/desk/src/mat/tilt.d.ts +14 -0
  194. package/dist/types/packages/desk/src/nav/flight.d.ts +186 -0
  195. package/dist/types/packages/desk/src/nav/portal.d.ts +95 -0
  196. package/dist/types/packages/desk/src/object.d.ts +46 -0
  197. package/dist/types/packages/desk/src/pass-instrument.d.ts +89 -0
  198. package/dist/types/packages/desk/src/shaders.d.ts +12 -0
  199. package/dist/types/packages/desk/src/shaders.gen.d.ts +16 -0
  200. package/dist/types/packages/desk/src/submit-instrument.d.ts +36 -0
  201. package/dist/types/packages/desk/src/theme.d.ts +475 -0
  202. package/dist/types/packages/desk/src/tray/carry.d.ts +99 -0
  203. package/dist/types/packages/desk/src/tray/drawer.d.ts +113 -0
  204. package/dist/types/packages/desk/src/tray/flux.d.ts +46 -0
  205. package/dist/types/packages/desk/src/tray/index.d.ts +4 -0
  206. package/dist/types/packages/desk/src/tray/lattice.d.ts +71 -0
  207. package/dist/types/packages/desk/src/tray/layout.d.ts +7 -0
  208. package/dist/types/packages/desk/src/tray/look.d.ts +29 -0
  209. package/dist/types/packages/desk/src/tray/pass.d.ts +96 -0
  210. package/dist/types/packages/desk/src/tray/shaders.d.ts +10 -0
  211. package/dist/types/packages/desk/src/tray/specimens.d.ts +199 -0
  212. package/dist/types/packages/devtools/src/attach.d.ts +22 -8
  213. package/dist/types/packages/devtools/src/dock.d.ts +18 -14
  214. package/dist/types/packages/devtools/src/gpu-panel.d.ts +105 -0
  215. package/dist/types/packages/devtools/src/index.d.ts +5 -4
  216. package/dist/types/packages/dom/src/desk-host.d.ts +91 -0
  217. package/dist/types/packages/dom/src/host.d.ts +13 -14
  218. package/dist/types/packages/dom/src/index.d.ts +12 -10
  219. package/dist/types/packages/dom/src/loop.d.ts +18 -1
  220. package/dist/types/packages/dom/src/pointer-adapter.d.ts +5 -29
  221. package/dist/types/packages/dom/src/widget-focus.d.ts +17 -13
  222. package/dist/types/packages/ice/src/desk-engine.d.ts +2 -0
  223. package/dist/types/packages/ice/src/desk-kit.d.ts +6 -0
  224. package/dist/types/packages/ice/src/desk-objects.d.ts +5 -0
  225. package/dist/types/packages/ice/src/desk.d.ts +5 -0
  226. package/dist/types/packages/kernel/src/atlas-pack.d.ts +157 -0
  227. package/dist/types/packages/kernel/src/bezier.d.ts +0 -15
  228. package/dist/types/packages/kernel/src/coords.d.ts +0 -39
  229. package/dist/types/packages/kernel/src/index.d.ts +2 -2
  230. package/dist/types/packages/kernel/src/nav-flight.d.ts +6 -0
  231. package/dist/types/packages/kernel/src/tray.d.ts +155 -0
  232. package/dist/types/packages/objects/src/board/board-pass.d.ts +180 -0
  233. package/dist/types/packages/objects/src/board/board-pen.d.ts +36 -0
  234. package/dist/types/packages/objects/src/board/board.d.ts +104 -0
  235. package/dist/types/packages/objects/src/board/data.d.ts +31 -0
  236. package/dist/types/packages/objects/src/board/history.d.ts +33 -0
  237. package/dist/types/packages/objects/src/board/kind.d.ts +208 -0
  238. package/dist/types/packages/objects/src/board/layout.d.ts +102 -0
  239. package/dist/types/packages/objects/src/board/object.d.ts +7 -0
  240. package/dist/types/packages/objects/src/board/pen.d.ts +71 -0
  241. package/dist/types/packages/objects/src/board/shaders.d.ts +36 -0
  242. package/dist/types/packages/objects/src/board/stroke.d.ts +99 -0
  243. package/dist/types/packages/objects/src/board/theme.d.ts +150 -0
  244. package/dist/types/packages/objects/src/calendar/data.d.ts +97 -0
  245. package/dist/types/packages/objects/src/calendar/events.d.ts +58 -0
  246. package/dist/types/packages/objects/src/calendar/hand.d.ts +53 -0
  247. package/dist/types/packages/objects/src/calendar/host/input.d.ts +67 -0
  248. package/dist/types/packages/objects/src/calendar/host/print.d.ts +9 -0
  249. package/dist/types/packages/objects/src/calendar/kind.d.ts +297 -0
  250. package/dist/types/packages/objects/src/calendar/law.d.ts +151 -0
  251. package/dist/types/packages/objects/src/calendar/layout.d.ts +47 -0
  252. package/dist/types/packages/objects/src/calendar/month.d.ts +75 -0
  253. package/dist/types/packages/objects/src/calendar/object.d.ts +45 -0
  254. package/dist/types/packages/objects/src/calendar/pad.d.ts +42 -0
  255. package/dist/types/packages/objects/src/calendar/pass.d.ts +229 -0
  256. package/dist/types/packages/objects/src/calendar/print.d.ts +87 -0
  257. package/dist/types/packages/objects/src/calendar/printing.d.ts +80 -0
  258. package/dist/types/packages/objects/src/calendar/roll.d.ts +45 -0
  259. package/dist/types/packages/objects/src/calendar/shaders.d.ts +12 -0
  260. package/dist/types/packages/objects/src/calendar/sheet.d.ts +43 -0
  261. package/dist/types/packages/objects/src/calendar/tiles.d.ts +67 -0
  262. package/dist/types/packages/objects/src/calendar/turn.d.ts +73 -0
  263. package/dist/types/packages/objects/src/calendar/writing.d.ts +42 -0
  264. package/dist/types/packages/objects/src/index.d.ts +22 -0
  265. package/dist/types/packages/objects/src/kinds.d.ts +24 -0
  266. package/dist/types/packages/objects/src/minimat/inside.d.ts +17 -0
  267. package/dist/types/packages/objects/src/minimat/kind.d.ts +51 -0
  268. package/dist/types/packages/objects/src/minimat/layout.d.ts +83 -0
  269. package/dist/types/packages/objects/src/minimat/minimat.d.ts +179 -0
  270. package/dist/types/packages/objects/src/minimat/object.d.ts +8 -0
  271. package/dist/types/packages/objects/src/minimat/pass.d.ts +61 -0
  272. package/dist/types/packages/objects/src/minimat/shaders.d.ts +10 -0
  273. package/dist/types/packages/objects/src/minimat/theme.d.ts +98 -0
  274. package/dist/types/packages/objects/src/notebook/ink.d.ts +70 -0
  275. package/dist/types/packages/objects/src/notebook/kind.d.ts +236 -0
  276. package/dist/types/packages/objects/src/notebook/law.d.ts +129 -0
  277. package/dist/types/packages/objects/src/notebook/layout.d.ts +46 -0
  278. package/dist/types/packages/objects/src/notebook/leaf.d.ts +44 -0
  279. package/dist/types/packages/objects/src/notebook/mesh.d.ts +20 -0
  280. package/dist/types/packages/objects/src/notebook/motion.d.ts +107 -0
  281. package/dist/types/packages/objects/src/notebook/object.d.ts +8 -0
  282. package/dist/types/packages/objects/src/notebook/pages.d.ts +56 -0
  283. package/dist/types/packages/objects/src/notebook/pass.d.ts +197 -0
  284. package/dist/types/packages/objects/src/notebook/pick.d.ts +30 -0
  285. package/dist/types/packages/objects/src/notebook/raster.d.ts +28 -0
  286. package/dist/types/packages/objects/src/notebook/shaders.d.ts +11 -0
  287. package/dist/types/packages/objects/src/notebook/shape.d.ts +155 -0
  288. package/dist/types/packages/objects/src/notebook/theme.d.ts +76 -0
  289. package/dist/types/packages/objects/src/palette.d.ts +577 -0
  290. package/dist/types/packages/objects/src/paper/host/body.d.ts +30 -0
  291. package/dist/types/packages/objects/src/paper/kind.d.ts +81 -0
  292. package/dist/types/packages/objects/src/paper/layout.d.ts +73 -0
  293. package/dist/types/packages/objects/src/paper/object.d.ts +31 -0
  294. package/dist/types/packages/objects/src/paper/pages.d.ts +43 -0
  295. package/dist/types/packages/objects/src/paper/paper-pass.d.ts +86 -0
  296. package/dist/types/packages/objects/src/paper/paper.d.ts +117 -0
  297. package/dist/types/packages/objects/src/paper/shaders.d.ts +18 -0
  298. package/dist/types/packages/objects/src/paper/theme.d.ts +58 -0
  299. package/dist/types/packages/objects/src/paper/typing.d.ts +51 -0
  300. package/dist/types/packages/objects/src/paper/writing.d.ts +161 -0
  301. package/dist/types/packages/objects/src/photo/carry.d.ts +33 -0
  302. package/dist/types/packages/objects/src/photo/kind.d.ts +136 -0
  303. package/dist/types/packages/objects/src/photo/layout.d.ts +39 -0
  304. package/dist/types/packages/objects/src/photo/object.d.ts +5 -0
  305. package/dist/types/packages/objects/src/photo/photo-pass.d.ts +104 -0
  306. package/dist/types/packages/objects/src/photo/photo.d.ts +262 -0
  307. package/dist/types/packages/objects/src/photo/pictures.d.ts +152 -0
  308. package/dist/types/packages/objects/src/photo/sample.d.ts +9 -0
  309. package/dist/types/packages/objects/src/photo/shaders.d.ts +18 -0
  310. package/dist/types/packages/objects/src/preset.d.ts +44 -0
  311. package/dist/types/packages/objects/src/shaders.d.ts +3 -0
  312. package/dist/types/packages/objects/src/shaders.gen.d.ts +21 -0
  313. package/dist/types/packages/react/src/canvas-hooks.d.ts +12 -0
  314. package/dist/types/packages/react/src/desk.d.ts +56 -0
  315. package/dist/types/packages/react/src/engine-context.d.ts +2 -2
  316. package/dist/types/packages/react/src/frame-preview-boundary.d.ts +19 -0
  317. package/dist/types/packages/react/src/hooks.d.ts +9 -14
  318. package/dist/types/packages/react/src/index.d.ts +16 -9
  319. package/dist/types/packages/react/src/keymap.d.ts +21 -2
  320. package/dist/types/packages/react/src/selection-menu.d.ts +171 -0
  321. package/dist/types/packages/react/src/tray-bar.d.ts +124 -0
  322. package/package.json +64 -31
  323. package/dist/chunk-5FQS7V2C.js.map +0 -1
  324. package/dist/chunk-JWRHAM7L.js +0 -1163
  325. package/dist/chunk-JWRHAM7L.js.map +0 -1
  326. package/dist/chunk-MFTMPJUF.js +0 -681
  327. package/dist/chunk-MFTMPJUF.js.map +0 -1
  328. package/dist/chunk-OR5FNVUE.js.map +0 -1
  329. package/dist/ground.js +0 -1213
  330. package/dist/ground.js.map +0 -1
  331. package/dist/r3f.js +0 -1644
  332. package/dist/r3f.js.map +0 -1
  333. package/dist/types/packages/core/src/input/measure-queue.d.ts +0 -30
  334. package/dist/types/packages/core/src/settings/ground-config.d.ts +0 -103
  335. package/dist/types/packages/core/src/systems/measure-ingest.d.ts +0 -26
  336. package/dist/types/packages/devtools/src/gl-panel.d.ts +0 -69
  337. package/dist/types/packages/dom/src/measure-adapter.d.ts +0 -31
  338. package/dist/types/packages/dom/src/measure-wiring.d.ts +0 -49
  339. package/dist/types/packages/dom/src/planes.d.ts +0 -33
  340. package/dist/types/packages/dom/src/reflectors/chrome.d.ts +0 -33
  341. package/dist/types/packages/dom/src/reflectors/dom-widgets.d.ts +0 -59
  342. package/dist/types/packages/dom/src/reflectors/graybox.d.ts +0 -31
  343. package/dist/types/packages/dom/src/reflectors/plane-transform.d.ts +0 -38
  344. package/dist/types/packages/ground/src/index.d.ts +0 -69
  345. package/dist/types/packages/ground/src/layer.d.ts +0 -40
  346. package/dist/types/packages/ground/src/pass.d.ts +0 -41
  347. package/dist/types/packages/ground/src/passes/grid-classic.d.ts +0 -30
  348. package/dist/types/packages/ground/src/passes/grid-magnet.d.ts +0 -31
  349. package/dist/types/packages/ground/src/passes/grid.d.ts +0 -28
  350. package/dist/types/packages/ground/src/passes/guides-collect.d.ts +0 -14
  351. package/dist/types/packages/ground/src/passes/guides.d.ts +0 -3
  352. package/dist/types/packages/ground/src/passes/magnet-collect.d.ts +0 -63
  353. package/dist/types/packages/ground/src/passes/soup-collect.d.ts +0 -35
  354. package/dist/types/packages/ground/src/passes/soup-mesh.d.ts +0 -8
  355. package/dist/types/packages/ground/src/passes/wires-collect.d.ts +0 -35
  356. package/dist/types/packages/ground/src/passes/wires.d.ts +0 -10
  357. package/dist/types/packages/ground/src/poles.d.ts +0 -47
  358. package/dist/types/packages/ground/src/renderer.d.ts +0 -15
  359. package/dist/types/packages/ice/src/ground.d.ts +0 -1
  360. package/dist/types/packages/ice/src/r3f.d.ts +0 -1
  361. package/dist/types/packages/kernel/src/eviction.d.ts +0 -23
  362. package/dist/types/packages/kernel/src/zoom-bands.d.ts +0 -19
  363. package/dist/types/packages/r3f/src/bridge.d.ts +0 -129
  364. package/dist/types/packages/r3f/src/composite-material.d.ts +0 -26
  365. package/dist/types/packages/r3f/src/compositor-pass.d.ts +0 -105
  366. package/dist/types/packages/r3f/src/dev-write-trap.d.ts +0 -30
  367. package/dist/types/packages/r3f/src/gl-root.d.ts +0 -96
  368. package/dist/types/packages/r3f/src/gl-router.d.ts +0 -70
  369. package/dist/types/packages/r3f/src/index.d.ts +0 -17
  370. package/dist/types/packages/r3f/src/island-state.d.ts +0 -112
  371. package/dist/types/packages/r3f/src/island.d.ts +0 -13
  372. package/dist/types/packages/r3f/src/pool.d.ts +0 -56
  373. package/dist/types/packages/r3f/src/preview-capture.d.ts +0 -19
  374. package/dist/types/packages/r3f/src/resource-registry.d.ts +0 -30
  375. package/dist/types/packages/r3f/src/self-sustain.d.ts +0 -39
  376. package/dist/types/packages/r3f/src/use-island-frame.d.ts +0 -39
  377. package/dist/types/packages/react/src/infinite-canvas.d.ts +0 -140
  378. package/dist/types/packages/react/src/preview-snapshots.d.ts +0 -17
  379. package/dist/types/packages/react/src/widget-preview.d.ts +0 -14
  380. package/dist/types/packages/react/src/widget-root.d.ts +0 -33
@@ -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/mat/grid.ts","../../desk/src/kit/book.ts","../../desk/src/shaders.gen.ts","../../desk/src/shaders.ts","../../desk/src/kit/wgsl.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/eye.ts","../../desk/src/kit/mesh.ts","../../desk/src/kit/mips.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/**\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 */\nexport function cssColor(css: string): RGBA {\n const s = 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 throw new Error(`theme: unparsed colour \"${css}\"`);\n}\nexport const rgb = (css: string): RGB => cssColor(css).slice(0, 3) as unknown as RGB;\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), line: rgb(MAT.line.css), cast: rgb(MAT.cast.css) };\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);\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 /**\n * K5a — the ACCESSORIES the specimens hang on (hooks, shelves, clips, rails): SKÅDIS's white powder coat warmed to sit on the\n * hardboard; how far each stands off the board (pitches — its shadow's reach on the board under the lamp); the shadow's strength.\n */\n accessory: { token: \"SKÅDIS white, warmed\", css: \"#e8e3d9\", height: { hook: 0.45, shelf: 0.6, clip: 0.3, rail: 0.4 }, shadow: 0.38 },\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/** 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 return { name, canvasBg: rgb(p.canvasBg.css), select: rgb(p.select.css), 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\nexport const MatUniforms = defineStruct(\"MatUniforms\", [\n [\"cam\", \"vec4f\"], // camX, camY (world, UNwrapped — the projector is fixed in world), zoom, dpr\n [\"view\", \"vec4f\"], // cssW, cssH, grain time (s), the OBJECTS' presentation opacity (the slot's × their own presence — what every kind multiplies by)\n [\"phase\", \"vec4f\"], // wrapped camX, camY (the lattice's phase), unused ×2\n [\"rungs\", \"vec4f\"], // fine, mid, coarse spacing (world), unused\n [\"lod\", \"vec4f\"], // fadeIn lo, hi (CSS px), unused ×2\n [\"line\", \"vec4f\"], // half-width thin, thick (DEVICE px), alpha thin, thick\n [\"grain\", \"vec4f\"], // amplitude, unused ×3\n [\"ground\", \"vec4f\"], // the mat's green (sRGB), unused\n [\"ink\", \"vec4f\"], // the line cream (sRGB), unused\n [\"plane\", \"vec4f\"], // desk origin x, z (m), metres per world unit, desk y (m)\n [\"goboMatrix\", \"mat4x4f\"],\n [\"goboParams\", \"vec4f\"], // sharp, soft, near, far — the blur ramp's depths and the projector's clip range\n [\"gobo\", \"vec4f\"], // opacity, blur radius (plate texels), shade mix, dark floor\n [\"grade\", \"vec4f\"], // saturation bump, unused ×3\n [\"noise\", \"vec4f\"], // blue-noise offset x, y, texel size, unused\n [\"wind\", \"vec4f\"], // gobo time (s), plate strength, unused ×2\n [\"night\", \"vec4f\"], // the NIGHT (mat/night.ts): amount (0 = the day's chain, exactly), the Moon's lux, exposure, snow\n [\"moon\", \"vec4f\"], // the Moon's colour as the adapted eye takes it (linear sRGB, Y = 1), the sky's share in the shadow\n [\"rod\", \"vec4f\"], // the rods' signal drawn as a colour (linear sRGB, Y = 1), unused\n [\"eigengrau\", \"vec4f\"], // the dark the eye adds (linear sRGB), unused\n [\"portals\", PORTAL_CHAIN_TYPE], // the portal CHAIN (nav/portal.ts): each face's centre xy, half extents xy (CSS px)\n [\"clips\", PORTAL_CHAIN_TYPE], // each face's corner radius, on (0/1 — a 0 ends the chain), unused ×2\n [\"ruler\", \"vec4f\"], // the RULERS (RULER.md; lattice/ruler.ts): on (0/1), margin, band, line width (CSS px)\n [\"rulerText\", \"vec4f\"], // the text's inset from the outer line, its gap after the tick, the major tick's length (CSS px), the atlas's texels per CSS px\n [\"rulerAlpha\", \"vec4f\"], // ink presence: the frame's lines, the ticks, the labels, unused\n [\"rulerOrigin\", \"vec4f\"], // the lattice's wrap count of camX, camY (exact integers), the finest labelled level (−1 = none), unused\n [\"rulerGlyph\", \"vec4f\"], // the glyph atlas: cell width, cell height, advance, baseline (texels)\n [\"rulerAtlas\", \"vec4f\"], // the glyph atlas: width, height, cap height (texels), glyph count\n [\"rulerSites\", \"array<vec4f, 5>\"], // per level: spacing (world), tick length (CSS px), tick presence, label presence\n [\"rulerFormat\", \"array<vec4f, 5>\"], // per level: mult, exp (a site's value = index · mult · 10^exp), wrap period over spacing, unused\n [\"box\", \"vec4f\"], // the slot's box on the attachment: x, y, w, h (CSS px) — stats only; the mat is fullscreen under the scissor\n [\"light\", \"vec4f\"], // the LIGHT (MINIMAT.md §4): the camera the lamp's gobo is sampled under — x, y, zoom — and the cross-fade toward `light2`\n [\"light2\", \"vec4f\"], // the second light a flight hands the slot to: x, y, zoom, unused\n [\"presence\", \"vec4f\"], // the SLOT's presentation opacity — what the mat itself is drawn at (K4a, K-L3: the one view block carries both), unused ×3\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 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, 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 ...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/** 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","// 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","// 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\nexport const NbUniforms = defineStruct(\"NbUniforms\", [\n [\"eye\", \"vec4f\"], // the desk eye: foot x, y (world), height (world), zoom\n [\"view\", \"vec4f\"], // viewport w, h (CSS px), the depth range's near and far (distance from the eye)\n [\"light\", \"vec4f\"], // the sky's share, the lambert's cap, the dapple's share on paper, on cloth\n [\"shadow\", \"vec4f\"], // σ at contact, σ per unit of height, the shadow's alpha on the mat, the contact's alpha\n [\"shadow2\", \"vec4f\"], // the contact's σ, the height it lets go by, the shadow map's size (texels), dpr\n [\"paper\", \"vec4f\"], // fibre, mottle, tooth, cockle\n [\"rule\", \"vec4f\"], // pitch, dot radius, margin, unused\n [\"cloth\", \"vec4f\"], // the weave's pitch, its relief, the sheen's exponent and strength\n [\"castCol\", \"vec4f\"], // what a shadow is made of on this ground\n [\"select\", \"vec4f\"], // the ring's colour, its width (CSS px)\n [\"ruleInk\", \"vec4f\"], // the ruling's ink, alpha\n [\"ring\", \"vec4f\"], // the ring's offset from the footprint (CSS px), unused ×3\n] as const);\n\nexport const NbBook = defineStruct(\"NbBook\", [\n [\"model\", \"mat4x4f\"], // book → world\n [\"inv\", \"mat4x4f\"], // world → book\n [\"light\", \"mat4x4f\"], // world → the shadow map's clip space\n [\"lamp\", \"vec4f\"], // the unit direction to the lamp (world), the shadow map's layer\n [\"sh\", \"vec4f\"], // a shadow texel (world), the map's depth range (world), mapped (0/1), the book's tallest point\n [\"size\", \"vec4f\"], // cover width, height, board, fore-edge radius\n [\"page\", \"vec4f\"], // unused, page height, page corner radius, the spine band's width\n [\"open\", \"vec4f\"], // the swing θ, the gutter's relax, the spine's width, the squares\n [\"look\", \"vec4f\"], // design, ruling, the ring's presence, a seed\n [\"foot\", \"vec4f\"], // the front board lies on the desk (0/1), the cover is paper (0/1), a sheet's thickness, the book shades itself (0/1)\n [\"recv\", \"vec4f\"], // the mat's rect this book darkens: x0, y0, x1, y1 (world)\n [\"inkPage\", \"array<vec4f, 2>\"], // the pages with ink on the device (−1 = none), eight\n [\"inkLayer\", \"array<vec4f, 2>\"], // … and the raster layer each is in\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\\nconst NB_PI = 3.14159265;\\n\\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)\\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 world point raised off the desk, in the projector's frame (mat.wgsl `desk_of` with a height).\\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)\\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 (centred on 0), d/dx, d/dy\\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, the gradient carried through\\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: 1 while `period` spans ≥ 3 px of `px` world, 0 under 1.\\nfn nb_detail(period: f32, px: f32) -> f32 { return smoothstep(1.2, 3.0, period / max(px, 1e-5)); }\\n\\n// Coverage of a signed distance (negative inside) at a pixel of `px` world units.\\nfn nb_cov(d: f32, px: f32) -> f32 { return nb_sat(0.5 - d / max(px, 1e-5)); }\\n\\n// A rounded box, centred, half extents `b`, radius `r`.\\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 face [0, w] × [0, h] whose corners at u = w are rounded by r (the spine side square): signed distance.\\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 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\\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\\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\\nstruct NbCloth { h: f32, g: vec2f, shade: f32 }\\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)\\nfn nb_ring(d: f32, r: f32, w: f32, px: f32) -> f32 { return nb_cov(abs(d - r) - w * 0.5, px); }\\n\\nfn nb_hash2(p: vec2f) -> f32 { return hash12(p * vec2f(0.1031, 0.1030) + vec2f(19.19, 7.7)); }\\n\\n// 0 plain cloth · 1 orbit (rings round a brass sun) · 2 tiles (a grid of quarter-rounds, halves and dots) · 3 label (a cream label on kraft) · 4 bordered (a blind-pressed frame)\\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\\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.\\nstruct NbPaperS { albedo: vec3f, g: vec2f }\\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: dots on a pitch, inside a margin, faded as they fall under the pixel.\\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// Its height's slope (d/du, d/dv): the cloth rolling over the board's edge (the bevel), the groove\\n// where the band's edge lies under the cover's cloth, the hinge's pressed groove, the weave, a blind press.\\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\\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// The inside of a board: the endpaper, framed by the cloth's turn-in along the head, the fore-edge and the tail.\\nstruct NbEnd { albedo: vec3f, ao: f32 }\\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.\\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.\\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@group(0) @binding(0) var layer: texture_2d<f32>;\\n@group(0) @binding(1) var<uniform> origin: vec4f;\\n@group(0) @binding(2) var<uniform> u: MatUniforms;\\n\\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@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 var gobo = sample_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, sample_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\\nfn mat_zoom(u: MatUniforms) -> f32 { return max(u.cam.z, 1e-12); }\\nfn mat_dpr(u: MatUniforms) -> f32 { return max(u.cam.w, 1.0); }\\n\\n// ---- the reference's noise (hash12 · valueNoise), on framebuffer pixels\\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\\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\\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\\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\\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.\\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\\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.\\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.\\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)\\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.\\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).\\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.\\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 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// World (CSS px at zoom 1, unwrapped) → the desk plane in the projector's frame.\\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.\\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.\\nfn lit_gobo(u: MatUniforms, tex: texture_2d<f32>, samp: sampler, p: vec2f, h: f32, own: vec3f, n: f32) -> f32 {\\n var g = 0.0;\\n if (all(u.light.xyz == u.cam.xyz)) { g = sample_gobo(u, tex, samp, own, n); }\\n else { g = sample_gobo(u, tex, samp, lit_desk(u, u.light, p, h), n); }\\n if (u.light.w > 0.0) { g = mix(g, sample_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.\\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.\\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.\\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).\\nfn night_mesopic(L: f32) -> f32 { return saturate(0.767 + 0.3334 * log(max(L, 1e-9)) * 0.4342944819); }\\n\\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\\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.\\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\\nconst RULER_LEVELS = 5;\\nconst GLYPH_PAD = 2.0;\\n\\n// A printed line's coverage across `d` device px at half-width `hw`: a 1 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 and the extents of a band.\\nfn ruler_in(x: f32, a: f32, b: f32) -> f32 { return step(a, x) * step(x, b); }\\n\\nfn ruler_digits(a: i32) -> i32 { var n = 1; var v = a; loop { if (v < 10) { break; } v = v / 10; n += 1; } return n; }\\nfn ruler_pow10(p: i32) -> i32 { var r = 1; for (var i = 0; i < p; i++) { r = r * 10; } return r; }\\n// The i-th digit (0 = leftmost) of `a` written with `nd` digits — leading zeros where `a` is short.\\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 — lattice/ruler.ts `formatLabel`, per character: the glyph\\n// index at slot `k` of `index · mult · 10^exp` (0–9, 10 '-', 11 '.', -1 past\\n// the end), and (x < 0) the character count. Plain digits, no suffix; a\\n// fraction with its trailing zeros stripped, so \\\"1.0\\\" is \\\"1\\\" at every level.\\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}\\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// The ticks and the label along ONE band. `along` is the fragment's CSS px\\n// along the band (x for the top, y for the left), `across` its device px in\\n// from the outer line; `phase` the lattice's wrapped camera coordinate along\\n// it, `wraps` the wrap count, `lim` the band's extent along (CSS px: the inner\\n// corner, the far frame line), `turned` the left band. `glyph` receives the\\n// atlas texel to sample when the fragment lies in a label (its .z the label's\\n// presence), else .z 0.\\nstruct RulerHit { ink: f32, glyph: vec3f }\\n\\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.\\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 \"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// = nav/portal.ts PORTAL_CHAIN, the uniform arrays' length; a mismatch fails to compile.\\nconst PORTAL_CHAIN = 6u;\\n\\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// Coverage at a CSS-px point through ONE face grown by `grow` device px: 1 inside, 0 outside, a one-device-px ramp across the edge —\\n// times, where the face has a feather, a smoothstep from 0 at its top edge to 1 the feather 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, 1.0);\\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// Coverage through the chain: the slot's own face grown by `grow` device px (the fill's one\\n// px, so the hole's edge partitions with the plate — PORTAL.md §10) times every face above\\n// it as it is. The product: a nested slot shows only where all of them agree.\\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\\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\\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\\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\\nfn sdf_circle(p: vec2f, r: f32) -> f32 { return length(p) - r; }\\n\\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\\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.\\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\\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 tray's pass (design-017 §5; K5a; design-018 §2): drawn in the ROOT's render pass after the marks, premultiplied, two kinds\\n// of quad — one vertex entry that lays each by its instance, two fragment entries (two pipelines on one layout: a branch over both in one\\n// entry cost the board a third of its time, the register budget of the largest path paid by every pixel): instance 0 the drawer UNDER\\n// its specimens, its edge included (`fs` → tray.wgsl `tray_drawer` — the view whole while the slide shows the dim, the drawer's box grown\\n// by its shadows' reach while nothing dims; shut, nothing is drawn at all); from instance 1, one quad per specimen's ACCESSORY with its\\n// shadow (`fs_accessory`, the records in `acc`). The rim's strips over it all retired with the rim (design-018 §2).\\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@group(0) @binding(5) var<storage, read> acc: array<TrayAccessory>;\\n\\nstruct TrayOut {\\n @builtin(position) pos: vec4f,\\n @location(0) @interpolate(flat) mode: u32,\\n @location(1) @interpolate(flat) item: u32,\\n}\\n\\n@vertex\\nfn vs(@builtin(vertex_index) vi: u32, @builtin(instance_index) ii: u32) -> TrayOut {\\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 var o: TrayOut;\\n o.mode = 0u;\\n o.item = 0u;\\n if (ii == 0u) {\\n // dimming: the view whole; undimmed: the drawer's box from its shadows' reach above and beside it down to the view's bottom edge\\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 } else {\\n o.mode = 1u;\\n o.item = ii - 1u;\\n let b = acc[o.item].box;\\n lo = clamp(b.xy, vec2f(0.0), vec2f(vw, vh));\\n hi = clamp(b.zw, vec2f(0.0), vec2f(vw, vh));\\n }\\n let css = mix(lo, hi, k);\\n o.pos = vec4f(css.x / vw * 2.0 - 1.0, 1.0 - css.y / vh * 2.0, 0.0, 1.0);\\n return o;\\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@fragment\\nfn fs_accessory(@builtin(position) pos: vec4f, @location(1) @interpolate(flat) item: u32) -> @location(0) vec4f {\\n return tray_accessory(u, t, acc[item], 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).\\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 lo = clamp(vec2f(t.rect.x, t.rect.y), vec2f(0.0), vec2f(vw, vh));\\n let hi = clamp(vec2f(t.rect.x + t.rect.z, t.rect.y + t.shape.y + t.fade.y + t.fade.x + 1.0), vec2f(0.0), vec2f(vw, vh));\\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 accessories and 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 accessories, the specimens, 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.\\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 let a = 1.0 - smoothstep(foot, foot + t.fade.x, p.y);\\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// ---- the accessories (K5a): what the specimens hang on, plugged into real holes — SKÅDIS's hook, shelf, clip and rail seen head-on, in\\n// their powder coat under the lamp, each casting its shadow on the board. One instance per specimen (tray-pass.wgsl), its quad the\\n// accessory and its shadow's reach; CSS px, the pitch `P` the unit of every length (kernel/tray.ts TRAY_ACCESSORY's numbers).\\nfn acc_peg(a: TrayAccessory, i: u32) -> vec2f {\\n if (i == 0u) { return a.pegs0.xy; }\\n if (i == 1u) { return a.pegs0.zw; }\\n if (i == 2u) { return a.pegs1.xy; }\\n return a.pegs1.zw;\\n}\\n\\n// The accessory's silhouette: its signed distance at `p` (negative inside) — every peg's PLUG in its hole, and the accessory's body.\\nfn acc_sdf(a: TrayAccessory, p: vec2f, P: f32) -> f32 {\\n let kind = u32(a.kind.x + 0.5);\\n let n = min(u32(a.kind.y + 0.5), 4u);\\n let r = a.rect;\\n var d = 1.0e4;\\n var lo = 1.0e9;\\n var hi = -1.0e9;\\n for (var i = 0u; i < n; i++) {\\n let g = acc_peg(a, i);\\n lo = min(lo, g.x);\\n hi = max(hi, g.x);\\n d = min(d, sdf_round_box(p - g, vec2f(0.1, 0.28) * P, 0.09 * P)); // the plug, in its hole\\n if (kind == 0u) { d = min(d, sdf_segment(p, g, g + vec2f(0.0, 0.58 * P)) - 0.07 * P); } // a hook: down to its tip\\n if (kind == 1u) { d = min(d, sdf_segment(p, g, vec2f(g.x, r.w + 0.1 * P)) - 0.06 * P); } // a shelf's bracket, up to the plank\\n if (kind == 2u) { // a clip: its spring from the hole down over the specimen's top edge\\n let top = g.y - 0.22 * P;\\n let foot = max(g.y, r.y) + 0.5 * P;\\n d = min(d, sdf_round_box(p - vec2f(g.x, 0.5 * (top + foot)), vec2f(0.24 * P, 0.5 * (foot - top)), 0.08 * P));\\n }\\n }\\n if (kind == 1u) { // the shelf's plank, under the specimen and past its sides\\n let hw = 0.5 * (r.z - r.x) + 0.3 * P;\\n d = min(d, sdf_round_box(p - vec2f(0.5 * (r.x + r.z), r.w + 0.12 * P), vec2f(hw, 0.12 * P), 0.05 * P));\\n }\\n if (kind == 3u && n > 0u) { // the rail: a bar through its holes, past the outer two\\n let y = acc_peg(a, 0u).y;\\n d = min(d, sdf_round_box(p - vec2f(0.5 * (lo + hi), y), vec2f(0.5 * (hi - lo) + 0.4 * P, 0.11 * P), 0.11 * P));\\n }\\n return d;\\n}\\n\\n// One pixel of an accessory's quad: its shadow on the board (the silhouette seen from the lamp, pushed off by how far it stands off the\\n// board, softened by the lamp's size over that), then the accessory over it — its rounded relief from the silhouette's gradient, lit as\\n// the board's edge is; both kept inside that edge. Premultiplied.\\nfn tray_accessory(u: MatUniforms, t: TrayUniforms, a: TrayAccessory, 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 P = t.view.w;\\n // inside the board's edge — whole: in the header and its ramp the VEIL lays the plain board over it, as over the specimens (design-018\\n // rev 5, `tray_veil`)\\n let inside = clamp(0.5 - (tray_outline(t, p) + t.shape.y) / px, 0.0, 1.0);\\n if (inside <= 0.0) { return vec4f(0.0); }\\n let L = t.lamp.xyz;\\n let lz = max(L.z, 1.0e-3);\\n let off = L.xy / lz * a.kind.z;\\n let sig = t.lamp.w * a.kind.z / lz + px;\\n let ds = acc_sdf(a, p + off, P);\\n let shadow = t.accessory.w * (1.0 - smoothstep(-sig, sig, ds));\\n let d = acc_sdf(a, p, P);\\n let c = clamp(0.5 - d / px, 0.0, 1.0);\\n if ((c <= 0.0) && (shadow <= 1.0e-4)) { return vec4f(0.0); }\\n var col = vec3f(0.0);\\n if (c > 0.0) {\\n let e = 0.5;\\n let gx = acc_sdf(a, p + vec2f(e, 0.0), P) - acc_sdf(a, p - vec2f(e, 0.0), P);\\n let gy = acc_sdf(a, p + vec2f(0.0, e), P) - acc_sdf(a, p - vec2f(0.0, e), P);\\n let g = vec2f(gx, gy) / max(length(vec2f(gx, gy)), 1.0e-6);\\n let s = clamp(-d / (0.07 * P), 0.0, 1.0);\\n let n = normalize(vec3f(g * (1.0 - s) * 1.2, max(s, 0.2)));\\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 col = tray_lit(u, t, t.accessory.xyz, n, 1.0, bn.y);\\n }\\n let body = c * inside;\\n let under = shadow * inside;\\n return vec4f(col * body, body + under * (1.0 - body));\\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/** The kit's pieces of WGSL (below, in compose order). */\nexport type KitWgslPiece = \"view\" | \"portal\" | \"sdf\" | \"light\" | \"ruler\" | \"book\";\n\n/** A name of the kit's WGSL: a piece, or another name for one (`lamp`, `gobo`, `night` and `noise` are `light`). */\nexport type KitWgslName = KitWgslPiece | \"lamp\" | \"gobo\" | \"night\" | \"noise\";\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` and `noise` 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\" };\n\n/** The .wgsl file behind each of the kit's module pieces — what a host's `ShaderText` is asked for. */\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","// 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. */\n bar: { travelMs: 340, backMs: 200 },\n} as const;\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 and above the bar's band, never past 3×.\n * `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 does when\n * one page reads at least 1.3× larger than the whole spread would; then the RIGHT page is centred (the extent's centre sits a\n * 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).\n */\nexport function readingTarget(extent: ObjectRect, vp: HeldViewport, spread = false, face = 0): ReadingTarget {\n const narrow = isNarrow(vp);\n const m = narrow ? HOLD.marginPhone : HOLD.margin;\n const top = narrow ? HOLD.topPhone : HOLD.top;\n const boxW = Math.max(40, vp.width - 2 * m);\n const boxH = Math.max(40, vp.height - top - HOLD.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 s1 = Math.min(boxW / (extent.w / 2), boxH / extent.h, HOLD.max);\n if (s1 > s * 1.3) { s = s1; 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","// (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","// 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","// 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\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\nexport function generateMips(device: GPUDevice, texture: GPUTexture): void {\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(texture.format);\n if (!pipe) {\n pipe = device.createRenderPipeline({\n label: `photo/mips ${texture.format}`, layout: \"auto\",\n vertex: { module: c.module, entryPoint: \"vs\" },\n fragment: { module: c.module, entryPoint: \"fs\", targets: [{ format: texture.format }] },\n });\n c.pipes.set(texture.format, pipe);\n }\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: c.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","// (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"]}