@mkbabb/glass-ui 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) hide show
  1. package/dist/{CardAction-8whJrLWt.js → CardAction-DlVP2evz.js} +58 -54
  2. package/dist/{CommandShortcut-D3yxgHNn.js → CommandShortcut-By-VQcLO.js} +3 -3
  3. package/dist/{ConfiguratorRow-CaP7U3ZA.js → ConfiguratorRow-YMXdINHx.js} +3 -3
  4. package/dist/{ContextMenuContent-B3ZsheLV.js → ContextMenuContent-CMWn6huB.js} +1 -1
  5. package/dist/{ContextMenuSubContent-DDRID3qC.js → ContextMenuSubContent-DvwWCUc0.js} +1 -1
  6. package/dist/{DataTable-Bc9kUtu_.js → DataTable-C4tG3eIJ.js} +4 -4
  7. package/dist/DialogContent-D8U9ZfWS.js +121 -0
  8. package/dist/{DialogScrollContent-TTuovQst.js → DialogScrollContent-BMekN7gq.js} +1 -1
  9. package/dist/{FadingScroll-DLRbH5Xr.js → FadingScroll-P8B30rAD.js} +1 -1
  10. package/dist/{HoverCardContent-Bel1gdLZ.js → HoverCardContent-DAmGYglo.js} +1 -1
  11. package/dist/{HoverPopover-BcIxvyqZ.js → HoverPopover-DYpBOzzF.js} +1 -1
  12. package/dist/{IconChip-DhbdGdFQ.js → IconChip-CQa7XZYc.js} +7 -5
  13. package/dist/{IconTooltip-B0zimd2H.js → IconTooltip-_df8M3xm.js} +1 -1
  14. package/dist/{Input-Cg9DF62r.js → Input-CyU4_hIC.js} +2 -2
  15. package/dist/{MetricBadge-RHdBP72w.js → MetricBadge-DQt_dGah.js} +1 -1
  16. package/dist/{Notification-CphK7AAm.js → Notification-BlSPJhtZ.js} +1 -1
  17. package/dist/{NumberFieldContent-D8cXeyO4.js → NumberFieldContent-Z3VxGu_6.js} +3 -3
  18. package/dist/PagerDots-CYlqVFd4.js +196 -0
  19. package/dist/PaperBackdrop-DYWgrnh8.js +42 -0
  20. package/dist/{PopoverContent-DL7E6vJP.js → PopoverContent-BuKyHZSz.js} +2 -2
  21. package/dist/{Progress-CnqB7gLm.js → Progress-C9SsdwIZ.js} +1 -1
  22. package/dist/{ScrollingText-CTZbA_cG.js → ScrollingText-DY3W1Jfh.js} +2 -2
  23. package/dist/{SelectScrollDownButton-DAKCBEdW.js → SelectScrollDownButton-3mFHX_R-.js} +15 -12
  24. package/dist/{Switch-B8RscmRu.js → Switch-uf-UKPA2.js} +1 -1
  25. package/dist/{Toaster-D9qIHjBI.js → Toaster-ozrsR4mP.js} +1 -1
  26. package/dist/{ToggleGroupItem-BLtr3TJq.js → ToggleGroupItem-BpzaVzNm.js} +4 -4
  27. package/dist/{TooltipProvider-BJ_Y5EGX.js → TooltipProvider-QQVM_80r.js} +1 -1
  28. package/dist/animated-digit.js +2 -2
  29. package/dist/api/index.d.ts +1 -0
  30. package/dist/api/types-extra.d.ts +3 -1
  31. package/dist/api.js +2 -2
  32. package/dist/aurora.js +163 -131
  33. package/dist/badge-Bt14yURi.js +72 -0
  34. package/dist/badge.js +1 -1
  35. package/dist/border-progress.js +1 -1
  36. package/dist/button-D1W9PrzI.js +130 -0
  37. package/dist/button.js +1 -1
  38. package/dist/canvas.js +1 -1
  39. package/dist/card.js +1 -1
  40. package/dist/carousel.js +227 -98
  41. package/dist/chipVariants-BJQ0I2kB.js +18 -0
  42. package/dist/collapsible.js +1 -1
  43. package/dist/color.js +1 -1
  44. package/dist/command.js +1 -1
  45. package/dist/components/custom/aurora/composables/glSetup.d.ts +1 -1
  46. package/dist/components/custom/aurora/composables/uniformBridgeWGPU.d.ts +1 -1
  47. package/dist/components/custom/aurora/constants/presets.d.ts +29 -0
  48. package/dist/components/custom/aurora/constants/shaders/aurora.wgsl.d.ts +1 -1
  49. package/dist/components/custom/aurora/index.d.ts +1 -1
  50. package/dist/components/custom/concentric/Concentric.vue.d.ts +15 -12
  51. package/dist/components/custom/concentric/composables/concentricGLSetup.d.ts +8 -3
  52. package/dist/components/custom/concentric/composables/concentricWGPUSetup.d.ts +8 -4
  53. package/dist/components/custom/concentric/composables/levelField.d.ts +50 -0
  54. package/dist/components/custom/concentric/composables/uniformBridgeWGPU.d.ts +7 -4
  55. package/dist/components/custom/concentric/composables/useConcentric.d.ts +3 -3
  56. package/dist/components/custom/concentric/constants.d.ts +62 -41
  57. package/dist/components/custom/concentric/index.d.ts +2 -2
  58. package/dist/components/custom/concentric/shaders/concentric.glsl.d.ts +2 -2
  59. package/dist/components/custom/concentric/shaders/concentric.wgsl.d.ts +1 -1
  60. package/dist/components/custom/configurator/Configurator.vue.d.ts +23 -2
  61. package/dist/components/custom/configurator/index.d.ts +1 -1
  62. package/dist/components/custom/dock/DockDropdownTrigger.vue.d.ts +4 -3
  63. package/dist/components/custom/dock/DockIconButton.vue.d.ts +10 -0
  64. package/dist/components/custom/dock/DockPopoverTrigger.vue.d.ts +19 -0
  65. package/dist/components/custom/dock/DockStack.vue.d.ts +35 -22
  66. package/dist/components/custom/dock/GlassDock.vue.d.ts +19 -3
  67. package/dist/components/custom/dock/composables/dockMorphContext.d.ts +18 -32
  68. package/dist/components/custom/dock/composables/dockMorphMeasure.d.ts +76 -145
  69. package/dist/components/custom/dock/composables/index.d.ts +1 -0
  70. package/dist/components/custom/dock/composables/railProjection.d.ts +45 -0
  71. package/dist/components/custom/dock/composables/useDockContextSilhouette.d.ts +192 -0
  72. package/dist/components/custom/dock/composables/useDockFission.d.ts +158 -0
  73. package/dist/components/custom/dock/composables/useDockItemDrag.d.ts +18 -0
  74. package/dist/components/custom/dock/composables/useDockShellProps.d.ts +38 -0
  75. package/dist/components/custom/dock/constants.d.ts +14 -3
  76. package/dist/components/custom/dock/index.d.ts +3 -0
  77. package/dist/components/custom/dot-flow-field/composables/flowField.d.ts +21 -0
  78. package/dist/components/custom/dot-flow-field/composables/flowGLProgram.d.ts +8 -0
  79. package/dist/components/custom/dot-flow-field/composables/flowSetupGL.d.ts +9 -0
  80. package/dist/components/custom/dot-flow-field/composables/flowSetupGLFlow.d.ts +12 -0
  81. package/dist/components/custom/dot-flow-field/composables/flowSetupWGPU.d.ts +7 -0
  82. package/dist/components/custom/dot-flow-field/composables/uniformBridgeWGPU.d.ts +28 -2
  83. package/dist/components/custom/dot-flow-field/composables/useFlowParticles.d.ts +18 -17
  84. package/dist/components/custom/dot-flow-field/constants.d.ts +51 -0
  85. package/dist/components/custom/dot-flow-field/index.d.ts +1 -1
  86. package/dist/components/custom/dot-flow-field/shaders/flow-field.compute.wgsl.d.ts +1 -1
  87. package/dist/components/custom/dot-flow-field/shaders/flow-field.glsl.d.ts +29 -0
  88. package/dist/components/custom/dot-flow-field/shaders/flow-field.render.wgsl.d.ts +2 -1
  89. package/dist/components/custom/dot-matrix/composables/uniformBridgeWGPU.d.ts +10 -1
  90. package/dist/components/custom/dot-matrix/composables/useDotSphere.d.ts +7 -0
  91. package/dist/components/custom/dot-matrix/constants.d.ts +14 -0
  92. package/dist/components/custom/dot-matrix/index.d.ts +1 -1
  93. package/dist/components/custom/dot-matrix/shaders/dot-matrix.glsl.d.ts +2 -2
  94. package/dist/components/custom/dot-matrix/shaders/dot-matrix.wgsl.d.ts +1 -1
  95. package/dist/components/custom/fourier-field/FourierField.vue.d.ts +4 -0
  96. package/dist/components/custom/fourier-field/composables/fourierFieldGLSetup.d.ts +9 -0
  97. package/dist/components/custom/fourier-field/composables/fourierFieldWGPUSetup.d.ts +11 -0
  98. package/dist/components/custom/fourier-field/composables/uniformBridgeWGPU.d.ts +16 -1
  99. package/dist/components/custom/fourier-field/composables/useFourierField.d.ts +22 -1
  100. package/dist/components/custom/fourier-field/constants.d.ts +53 -0
  101. package/dist/components/custom/fourier-field/shaders/fourier-field.glsl.d.ts +1 -1
  102. package/dist/components/custom/fourier-field/shaders/fourier-field.render.wgsl.d.ts +1 -1
  103. package/dist/components/custom/goo-blob/composables/easing.d.ts +1 -0
  104. package/dist/components/custom/goo-blob/composables/useBlobSatellites.d.ts +1 -0
  105. package/dist/components/custom/goo-blob/constants.d.ts +26 -1
  106. package/dist/components/custom/goo-blob/shaders/metaball-uniforms.glsl.d.ts +1 -1
  107. package/dist/components/custom/goo-blob/shaders/metaball.wgsl.d.ts +1 -1
  108. package/dist/components/custom/goo-blob/types.d.ts +50 -1
  109. package/dist/components/custom/goo-dot-matrix/composables/gooDotSetup.d.ts +32 -3
  110. package/dist/components/custom/goo-dot-matrix/composables/uniformBridgeWGPU.d.ts +14 -4
  111. package/dist/components/custom/goo-dot-matrix/constants.d.ts +55 -16
  112. package/dist/components/custom/goo-dot-matrix/index.d.ts +1 -1
  113. package/dist/components/custom/goo-dot-matrix/shaders/goo-dot.frag.d.ts +2 -0
  114. package/dist/components/custom/goo-dot-matrix/shaders/goo-dot.wgsl.d.ts +1 -0
  115. package/dist/components/custom/goo-filter/GooFilter.vue.d.ts +22 -0
  116. package/dist/components/custom/goo-filter/index.d.ts +1 -0
  117. package/dist/components/custom/handmark/brush.d.ts +17 -17
  118. package/dist/components/custom/handmark/constants.d.ts +28 -8
  119. package/dist/components/custom/handmark/geometry.d.ts +34 -1
  120. package/dist/components/custom/handmark/index.d.ts +1 -1
  121. package/dist/components/custom/icon-chip/types.d.ts +10 -0
  122. package/dist/components/custom/paper-backdrop/PaperBackdrop.vue.d.ts +18 -0
  123. package/dist/components/custom/paper-grid/composables/paperGrid.d.ts +44 -29
  124. package/dist/components/custom/paper-grid/composables/paperGridGLSetup.d.ts +2 -0
  125. package/dist/components/custom/paper-grid/composables/paperGridWGPUSetup.d.ts +3 -1
  126. package/dist/components/custom/paper-grid/composables/uniformBridgeWGPU.d.ts +2 -2
  127. package/dist/components/custom/paper-grid/constants.d.ts +44 -6
  128. package/dist/components/custom/paper-grid/index.d.ts +2 -2
  129. package/dist/components/custom/paper-grid/shaders/paper-grid.glsl.d.ts +1 -1
  130. package/dist/components/custom/paper-grid/shaders/paper-grid.wgsl.d.ts +1 -1
  131. package/dist/components/custom/selectable-chip/chipVariants.d.ts +39 -0
  132. package/dist/components/custom/selectable-chip/selectableChipVariants.d.ts +12 -20
  133. package/dist/components/custom/tabs/constants.d.ts +16 -8
  134. package/dist/components/custom/timeline/ScrubberTimeline.vue.d.ts +16 -0
  135. package/dist/components/custom/timeline/geometry.d.ts +0 -8
  136. package/dist/components/custom/toggle-chip/index.d.ts +15 -4
  137. package/dist/components/custom/watercolor-dot/WatercolorDot.vue.d.ts +12 -10
  138. package/dist/components/ui/_shared/useSurfaceAxis.d.ts +17 -3
  139. package/dist/components/ui/badge/Badge.vue.d.ts +14 -0
  140. package/dist/components/ui/badge/index.d.ts +1 -0
  141. package/dist/components/ui/button/Button.vue.d.ts +1 -0
  142. package/dist/components/ui/card/Card.vue.d.ts +1 -1
  143. package/dist/components/ui/card/ScrollCard.vue.d.ts +1 -1
  144. package/dist/components/ui/carousel/CarouselContent.vue.d.ts +2 -4
  145. package/dist/components/ui/dialog/DialogContent.vue.d.ts +9 -0
  146. package/dist/components/ui/drawer/Drawer.vue.d.ts +33 -14
  147. package/dist/components/ui/drawer/constants.d.ts +8 -6
  148. package/dist/components/ui/drawer/index.d.ts +12 -2
  149. package/dist/components/ui/select/SelectContent.vue.d.ts +9 -0
  150. package/dist/components/ui/slider/Slider.vue.d.ts +9 -0
  151. package/dist/composables/dom/index.d.ts +1 -0
  152. package/dist/composables/dom/useDragVelocity.d.ts +46 -0
  153. package/dist/composables/glass/wave/index.d.ts +4 -0
  154. package/dist/composables/glass/wave/waveField.d.ts +115 -0
  155. package/dist/composables/glass/wave/waveField.glsl.d.ts +1 -0
  156. package/dist/composables/glass/wave/waveField.wgsl.d.ts +1 -0
  157. package/dist/composables/glass/webgl/createCanvasLifecycle.d.ts +95 -2
  158. package/dist/composables/glass/webgl/useWebGLCanvas.d.ts +40 -2
  159. package/dist/composables/glass/webgpu/index.d.ts +1 -0
  160. package/dist/composables/glass/webgpu/useGpuSubstrate.d.ts +37 -0
  161. package/dist/composables/glass/webgpu/useWebGPUCanvas.d.ts +49 -2
  162. package/dist/composables/glass/webgpu/webgpuDevice.d.ts +1 -1
  163. package/dist/composables/motion/core/index.d.ts +4 -0
  164. package/dist/composables/motion/core/useHaptic.d.ts +48 -0
  165. package/dist/composables/motion/core/writeVelocityWeight.d.ts +31 -0
  166. package/dist/composables/motion/index.d.ts +2 -0
  167. package/dist/composables/motion/springPresets.d.ts +16 -17
  168. package/dist/composables/motion/suite.d.ts +2 -2
  169. package/dist/composables/motion/useBloomUp.d.ts +97 -0
  170. package/dist/composables/motion/useCelebrationBurst.d.ts +50 -0
  171. package/dist/composables/motion/useDockCtaReceive.d.ts +10 -28
  172. package/dist/composables/motion/useGooMorph.d.ts +72 -0
  173. package/dist/composables/motion/useLiquidFlex.d.ts +18 -0
  174. package/dist/composables/motion/useLiquidMorph.d.ts +108 -0
  175. package/dist/composables/motion/useLiquidPress.d.ts +12 -0
  176. package/dist/composables/motion/useLiquidReveal.d.ts +7 -4
  177. package/dist/composables/motion/useMorphField.d.ts +157 -0
  178. package/dist/composables/motion/useScrollPin.d.ts +49 -0
  179. package/dist/composables/motion/useScrollScene.d.ts +67 -0
  180. package/dist/concentric.js +532 -563
  181. package/dist/configurator.js +2 -2
  182. package/dist/confirm-dialog.js +3 -3
  183. package/dist/constellation.js +4 -4
  184. package/dist/context-menu.js +2 -2
  185. package/dist/controls.js +2 -2
  186. package/dist/createCanvasLifecycle-CuCrGRfq.js +173 -0
  187. package/dist/dark.js +1 -1
  188. package/dist/data-table.js +1 -1
  189. package/dist/deck.js +1 -1
  190. package/dist/dialog.js +3 -3
  191. package/dist/dock.js +1163 -618
  192. package/dist/dockContext-gFVS2gMg.js +18 -0
  193. package/dist/dom.js +7 -6
  194. package/dist/dot-flow-field.js +1114 -523
  195. package/dist/dot-matrix.js +348 -204
  196. package/dist/drawer.js +106 -96
  197. package/dist/{dropdown-menu-aJmV5SqE.js → dropdown-menu-CCfcCQ68.js} +3 -3
  198. package/dist/dropdown-menu.js +1 -1
  199. package/dist/easing.js +3 -3
  200. package/dist/expandable-container.js +2 -2
  201. package/dist/fading-scroll.js +1 -1
  202. package/dist/forms.js +6 -6
  203. package/dist/fourier-field.js +441 -197
  204. package/dist/fourier-math.js +1 -1
  205. package/dist/glass-panel.js +2 -2
  206. package/dist/glass-ui.css +1 -1
  207. package/dist/glass-ui.js +139 -135
  208. package/dist/goo-blob.js +11 -9
  209. package/dist/goo-dot-matrix.js +418 -198
  210. package/dist/handmark.js +137 -94
  211. package/dist/header-ribbon.js +1 -1
  212. package/dist/hover-card.js +1 -1
  213. package/dist/hover-popover.js +1 -1
  214. package/dist/icon-chip.js +1 -1
  215. package/dist/icon-tooltip.js +1 -1
  216. package/dist/index.d.ts +3 -0
  217. package/dist/instrument-chassis.js +1 -1
  218. package/dist/keyboard.js +1 -1
  219. package/dist/label.js +1 -1
  220. package/dist/labeled-field.js +7 -7
  221. package/dist/metric-badge.js +1 -1
  222. package/dist/metric-cell.js +1 -1
  223. package/dist/metric-stack.js +1 -1
  224. package/dist/motion-core.js +42 -39
  225. package/dist/motion-curves.js +20 -14
  226. package/dist/motion.js +226 -26
  227. package/dist/notification.js +1 -1
  228. package/dist/number-field.js +1 -1
  229. package/dist/pager-dots.js +1 -1
  230. package/dist/paper-backdrop.js +1 -1
  231. package/dist/paper-grid.js +315 -342
  232. package/dist/paperGrid-CXCSMbZ1.js +191 -0
  233. package/dist/popover.js +1 -1
  234. package/dist/{presets-CvOUqtdY.js → presets-QvYgnFIZ.js} +13 -12
  235. package/dist/progress.js +1 -1
  236. package/dist/pulse.js +1 -1
  237. package/dist/reactive.js +2 -2
  238. package/dist/{resolveCanvasColor-yPyIpJt9.js → resolveCanvasColor-DsSJk06I.js} +5 -5
  239. package/dist/scrolling-text.js +1 -1
  240. package/dist/search.js +7 -7
  241. package/dist/select.js +3 -3
  242. package/dist/selectable-chip.js +18 -35
  243. package/dist/separator.js +1 -1
  244. package/dist/{sheet-B2flBfLH.js → sheet-DUCIoOe0.js} +3 -3
  245. package/dist/sheet.js +1 -1
  246. package/dist/sidebar.js +1 -1
  247. package/dist/slider-CcICPe3u.js +149 -0
  248. package/dist/slider.js +1 -1
  249. package/dist/sortable-list.js +3 -3
  250. package/dist/{spectrum-walk-BVzA7Biz.js → spectrum-walk-cBNSx_zm.js} +1 -1
  251. package/dist/springPresets-DfoQ6XRY.js +64 -0
  252. package/dist/stacked-icons.js +54 -39
  253. package/dist/styles/cards.css +202 -2
  254. package/dist/styles/components.css +1 -3
  255. package/dist/styles/configurator.css +172 -7
  256. package/dist/styles/critical-partition.mjs +35 -2
  257. package/dist/styles/deferred.css +2 -0
  258. package/dist/styles/dock/adaptive-legibility.css +119 -0
  259. package/dist/styles/dock/density.css +18 -10
  260. package/dist/styles/dock/fission-bridge.css +552 -0
  261. package/dist/styles/dock/layers.css +88 -124
  262. package/dist/styles/dock/morph-bridge.css +15 -2
  263. package/dist/styles/dock/morph.css +45 -114
  264. package/dist/styles/dock/shape.css +137 -11
  265. package/dist/styles/dock/shell.css +1 -3
  266. package/dist/styles/dock/stack-rail.css +95 -7
  267. package/dist/styles/dock-controls/icon-button.css +34 -2
  268. package/dist/styles/dock-controls/triggers.css +23 -1
  269. package/dist/styles/dock-controls.css +18 -0
  270. package/dist/styles/dock.css +16 -1
  271. package/dist/styles/drawer.css +166 -0
  272. package/dist/styles/glass/glass-atom.css +244 -0
  273. package/dist/styles/glass/glass-capsule.css +143 -0
  274. package/dist/styles/glass/glass-chip.css +215 -0
  275. package/dist/styles/glass/liquid-enter.css +252 -0
  276. package/dist/styles/glass/liquid-morph.css +850 -0
  277. package/dist/styles/glass/material.css +70 -1
  278. package/dist/styles/glass/reveal.css +22 -2
  279. package/dist/styles/glass/rim.css +13 -1
  280. package/dist/styles/glass/surfaces.css +18 -8
  281. package/dist/styles/glass.css +11 -0
  282. package/dist/styles/icon-chip.css +45 -0
  283. package/dist/styles/index.css +11 -0
  284. package/dist/styles/jubilance.css +65 -0
  285. package/dist/styles/motion/morph-field.css +229 -0
  286. package/dist/styles/paper.css +230 -14
  287. package/dist/styles/scroll-choreography.css +135 -78
  288. package/dist/styles/segmented-tabs.css +85 -51
  289. package/dist/styles/select.css +151 -0
  290. package/dist/styles/tokens/color-radius.css +1 -1
  291. package/dist/styles/tokens/dark-arm.css +57 -8
  292. package/dist/styles/tokens/glass-deep.css +8 -4
  293. package/dist/styles/tokens/glass-fx.css +80 -2
  294. package/dist/styles/tokens/glass.css +140 -8
  295. package/dist/styles/tokens/light-dark.css +2 -2
  296. package/dist/styles/tokens/property-regs.css +144 -0
  297. package/dist/styles/tokens/scale-paper.css +20 -8
  298. package/dist/styles/tokens/scheme-motion.css +92 -157
  299. package/dist/styles/tokens/scheme-spring.css +239 -0
  300. package/dist/styles/tokens/scroll-tokens.css +15 -15
  301. package/dist/styles/tokens/shadow.css +73 -13
  302. package/dist/styles/tokens.css +9 -2
  303. package/dist/styles/utilities/btn.css +70 -0
  304. package/dist/switch.js +1 -1
  305. package/dist/tabs.js +198 -181
  306. package/dist/timeline.js +241 -206
  307. package/dist/toast.js +1 -1
  308. package/dist/toggle-chip.js +14 -41
  309. package/dist/toggle-group.js +1 -1
  310. package/dist/tooltip.js +1 -1
  311. package/dist/typewriter.js +1 -1
  312. package/dist/{uniformBridgeWGPU-CtAKl45L.js → uniformBridgeWGPU-BCse1SHU.js} +191 -127
  313. package/dist/{useAnimatedNumber-CLrxicG9.js → useAnimatedNumber-BntskVdQ.js} +1 -1
  314. package/dist/{useConfiguratorState-4xblKfwd.js → useConfiguratorState-22BcULzF.js} +37 -35
  315. package/dist/useDockCtaReceive-DX7RDb6_.js +88 -0
  316. package/dist/{useDragMorph-BUgAC-zK.js → useDragMorph-DGLSewwB.js} +2 -2
  317. package/dist/useDragVelocity-CjcfX3dA.js +57 -0
  318. package/dist/useGooMorph-Cs13NgYL.js +104 -0
  319. package/dist/useGpuSubstrate-Ceet70xq.js +347 -0
  320. package/dist/{useViewTransition-CUI1nAgn.js → useHaptic-CPz5BT9I.js} +40 -1
  321. package/dist/{useLiquidFlex-UmA6LMZu.js → useLiquidFlex-Cc6PjVJD.js} +8 -3
  322. package/dist/useLiquidPress-CtOQ8Z0_.js +43 -0
  323. package/dist/useMorphField-ogBM7ubT.js +141 -0
  324. package/dist/{useScrollChrome-D66AVP7C.js → useScrollChrome-JuImi1DM.js} +2 -2
  325. package/dist/{useSpringMount-BWDnKIwh.js → useSpringMount-DFxtzmkR.js} +1 -1
  326. package/dist/{useSpringPress-B1-Czp-V.js → useSpringPress-VM9RgVq3.js} +1 -1
  327. package/dist/{useSurfaceAxis-g0NloYEF.js → useSurfaceAxis-Ci7Dnaw2.js} +1 -1
  328. package/dist/{useTouchGate-CBZTD4SD.js → useTouchGate-B1Lf9XqN.js} +1 -1
  329. package/dist/virtual.js +1 -1
  330. package/dist/watercolor-dot.js +16 -26
  331. package/dist/writeVelocityWeight-Bh83xZfs.js +19 -0
  332. package/package.json +14 -3
  333. package/src/styles/cards.css +202 -2
  334. package/src/styles/configurator.css +172 -7
  335. package/src/styles/critical-partition.mjs +35 -2
  336. package/src/styles/dock/adaptive-legibility.css +119 -0
  337. package/src/styles/dock/density.css +18 -10
  338. package/src/styles/dock/fission-bridge.css +552 -0
  339. package/src/styles/dock/layers.css +88 -124
  340. package/src/styles/dock/morph-bridge.css +15 -2
  341. package/src/styles/dock/morph.css +45 -114
  342. package/src/styles/dock/shape.css +137 -11
  343. package/src/styles/dock/shell.css +1 -3
  344. package/src/styles/dock/stack-rail.css +95 -7
  345. package/src/styles/dock-controls/icon-button.css +34 -2
  346. package/src/styles/dock-controls/triggers.css +23 -1
  347. package/src/styles/dock-controls.css +18 -0
  348. package/src/styles/dock.css +16 -1
  349. package/src/styles/drawer.css +164 -0
  350. package/src/styles/glass/glass-atom.css +244 -0
  351. package/src/styles/glass/glass-capsule.css +143 -0
  352. package/src/styles/glass/glass-chip.css +215 -0
  353. package/src/styles/glass/liquid-enter.css +252 -0
  354. package/src/styles/glass/liquid-morph.css +850 -0
  355. package/src/styles/glass/material.css +70 -1
  356. package/src/styles/glass/reveal.css +22 -2
  357. package/src/styles/glass/rim.css +13 -1
  358. package/src/styles/glass/surfaces.css +18 -8
  359. package/src/styles/glass.css +11 -0
  360. package/src/styles/icon-chip.css +45 -0
  361. package/src/styles/index.css +11 -0
  362. package/src/styles/jubilance.css +65 -0
  363. package/src/styles/motion/morph-field.css +229 -0
  364. package/src/styles/paper.css +230 -14
  365. package/src/styles/scroll-choreography.css +135 -78
  366. package/src/styles/segmented-tabs.css +85 -47
  367. package/src/styles/select.css +151 -0
  368. package/src/styles/tokens/color-radius.css +1 -1
  369. package/src/styles/tokens/dark-arm.css +57 -8
  370. package/src/styles/tokens/glass-deep.css +8 -4
  371. package/src/styles/tokens/glass-fx.css +80 -2
  372. package/src/styles/tokens/glass.css +140 -8
  373. package/src/styles/tokens/light-dark.css +2 -2
  374. package/src/styles/tokens/property-regs.css +144 -0
  375. package/src/styles/tokens/scale-paper.css +20 -8
  376. package/src/styles/tokens/scheme-motion.css +92 -157
  377. package/src/styles/tokens/scheme-spring.css +239 -0
  378. package/src/styles/tokens/scroll-tokens.css +15 -15
  379. package/src/styles/tokens/shadow.css +73 -13
  380. package/src/styles/tokens.css +9 -2
  381. package/src/styles/utilities/btn.css +70 -0
  382. package/dist/DialogContent-6JtTB5x2.js +0 -106
  383. package/dist/PagerDots-Cjx96la-.js +0 -98
  384. package/dist/PaperBackdrop-CqwjnfLv.js +0 -31
  385. package/dist/badge-D9XWW4GT.js +0 -53
  386. package/dist/button-5dY1Dvhd.js +0 -125
  387. package/dist/components/custom/concentric/composables/ringField.d.ts +0 -85
  388. package/dist/createCanvasLifecycle-Gh45Ce-p.js +0 -93
  389. package/dist/dockContext-BNfyPLe9.js +0 -17
  390. package/dist/slider-2A0rPn79.js +0 -142
  391. package/dist/springPresets-Ce7OYCm9.js +0 -46
  392. package/dist/useDockCtaReceive-DfFkmgL1.js +0 -82
  393. package/dist/useGpuSubstrate-4pTcp6mX.js +0 -294
  394. package/dist/useLiquidPress-BooG97RY.js +0 -39
  395. /package/dist/{CollapsibleContent-68dEXIAl.js → CollapsibleContent-D7UNsXQr.js} +0 -0
  396. /package/dist/{DialogFooter-9phqcRIS.js → DialogFooter-DoLy0ewI.js} +0 -0
  397. /package/dist/{InstrumentChassis-CxsHSyMj.js → InstrumentChassis-UUJX0-mW.js} +0 -0
  398. /package/dist/{Label-C2ejNWeC.js → Label-B_HPqi_q.js} +0 -0
  399. /package/dist/{ModalOverlay-D1VrWyoi.js → ModalOverlay-DfAf7o15.js} +0 -0
  400. /package/dist/{SelectGroup-BFiod7X2.js → SelectGroup-Dcczq44n.js} +0 -0
  401. /package/dist/{SelectSeparator-C2UGOkXF.js → SelectSeparator-CNRGG7Ew.js} +0 -0
  402. /package/dist/{Separator-DQcwC2TR.js → Separator-Cf9-JFgi.js} +0 -0
  403. /package/dist/{_plugin-vue_export-helper-C1je1s0u.js → _plugin-vue_export-helper-gLzyemvl.js} +0 -0
  404. /package/dist/{color-Cs0-oxYL.js → color-B9jZdhJX.js} +0 -0
  405. /package/dist/{compile-nZ1xVYTp.js → compile-INR_tPk_.js} +0 -0
  406. /package/dist/{constants--C2DkLW8.js → constants-BWj7DkMn.js} +0 -0
  407. /package/dist/{createContext-CpBNTRMI.js → createContext-Cd23P9j0.js} +0 -0
  408. /package/dist/{dotMatrixField-D_x9_1qq.js → dotMatrixField-CRO0ZFk4.js} +0 -0
  409. /package/dist/{flow.glsl-B2P7e0MT.js → flow.glsl-DqEGRpl4.js} +0 -0
  410. /package/dist/{math-Eb0w3LqU.js → math-5RcIgCB4.js} +0 -0
  411. /package/dist/{menuItemVariants-D8VNHq22.js → menuItemVariants-DAXquKja.js} +0 -0
  412. /package/dist/{prng-B-d9eYX8.js → prng-B5tIXTtj.js} +0 -0
  413. /package/dist/{procedural-color.wgsl-m7Zgv35j.js → procedural-color.wgsl-C1Y5PkM6.js} +0 -0
  414. /package/dist/{scrollReader-DI1NWxUw.js → scrollReader-rc3Ns_NM.js} +0 -0
  415. /package/dist/{useControlSize-SH1UmJCi.js → useControlSize-DAZ062x7.js} +0 -0
  416. /package/dist/{useFuzzySearch-DIhcYtcw.js → useFuzzySearch-0fTYOhS4.js} +0 -0
  417. /package/dist/{useGlobalDark-CmjB9E32.js → useGlobalDark-B4HO9LXG.js} +0 -0
  418. /package/dist/{useIntersectionPause-Dbozzjgm.js → useIntersectionPause-DO8Vl4gs.js} +0 -0
  419. /package/dist/{useInterval-CNdua40W.js → useInterval-BVUI-sez.js} +0 -0
  420. /package/dist/{useKeyboardShortcuts-BPRp33Im.js → useKeyboardShortcuts-BEut54Tk.js} +0 -0
  421. /package/dist/{usePointerVelocityField-QLsy3_kv.js → usePointerVelocityField-BrkqZFhj.js} +0 -0
  422. /package/dist/{useResizeObserver-Bpoi7tRE.js → useResizeObserver-DdEn3v2f.js} +0 -0
  423. /package/dist/{useResolveTokenColor-vAylyR0x.js → useResolveTokenColor-ChOnCckA.js} +0 -0
  424. /package/dist/{useScrollProgress-c3yxmH6a.js → useScrollProgress-A0M6qRl7.js} +0 -0
  425. /package/dist/{useSortable-BVqlJRBR.js → useSortable-DQV_UNDw.js} +0 -0
  426. /package/dist/{useTextHighlight-NmBM5V_4.js → useTextHighlight-Bma3UlKA.js} +0 -0
  427. /package/dist/{useTimer-BHJOKr35.js → useTimer-BBLGPXR8.js} +0 -0
  428. /package/dist/{useUserInvalidAria-y5namzeE.js → useUserInvalidAria-EmmwWPOl.js} +0 -0
  429. /package/dist/{useViewportReady-anbac3m6.js → useViewportReady-C9pYnn7K.js} +0 -0
  430. /package/dist/{vReveal-D9k0jADx.js → vReveal-CT1KtwZA.js} +0 -0
@@ -0,0 +1,18 @@
1
+ import { type Ref } from "vue";
2
+ export interface UseDockItemDragParams {
3
+ /** The dock root element (the items live in its active layer). */
4
+ rootEl: Ref<HTMLElement | null>;
5
+ /** Whether the axis is armed (the `:draggable-items` prop). May be a getter. */
6
+ enabled: () => boolean;
7
+ /** The morph axis (`"x"` horizontal · `"y"` vertical). A getter (orientation flips). */
8
+ axis: () => "x" | "y";
9
+ /** Fired once on settle with the committed (from, to) item indices. */
10
+ onReorder?: (from: number, to: number) => void;
11
+ }
12
+ export interface UseDockItemDragReturn {
13
+ /** True while a dock item is being dragged. */
14
+ dragging: Readonly<Ref<boolean>>;
15
+ /** Tear down the gesture + listeners. */
16
+ detach: () => void;
17
+ }
18
+ export declare function useDockItemDrag(params: UseDockItemDragParams): UseDockItemDragReturn;
@@ -154,6 +154,44 @@ export interface DockProps {
154
154
  * byte-identical to HEAD (the slot + the data-attr are present only when authored).
155
155
  */
156
156
  search?: boolean;
157
+ /**
158
+ * BD.W-DOCK-CORE (A13 / II.2) — arm the SHIPPED fission seam (additive, default
159
+ * `false`). When true the dock composes `useDockFission` (the n-ary detach
160
+ * orchestrator on the SAME `DOCK_SPRING` clock, BESIDE the morph engine — box-
161
+ * INVIOLATE, never editing `dockMorphContext`), auto-registers every child marked
162
+ * `data-dock-splittable` as a fission PIECE (its detach vector derived from its
163
+ * FLIP-measured center relative to the dock center), feeds the seam-tension on
164
+ * `@pointermove`, and exposes `split()`/`merge()`/`toggle()` via `defineExpose`. A
165
+ * non-splittable dock is byte-identical to HEAD. The ONE `<GooFilter>` mount must be mounted
166
+ * once at the app root (the goo `<filter>` the necks reference).
167
+ */
168
+ splittable?: boolean;
169
+ /**
170
+ * BD.W-DOCK-CORE (A13) — the fission CONTEXT (the `DOCK_SPLIT_SIGNATURES` row): the
171
+ * detach-vector family + neck stagger. `"nav"` (default) is inward-merge; `"search"`
172
+ * is a radial bloom; `"media"` is a lateral peel.
173
+ */
174
+ splitContext?: "search" | "media" | "nav";
175
+ /**
176
+ * BD.W-DOCK-CORE (A13) — where the detached sibling dock lands (reads the split
177
+ * vector). `"beside"` (default) is the radial/lateral lateral landing; `"above"`/
178
+ * `"below"` are the V-axis landings.
179
+ */
180
+ splitPlacement?: "beside" | "above" | "below";
181
+ /**
182
+ * BD.W-DOCK-CORE (A12) — arm the draggable-ITEMS axis (additive, default `false`).
183
+ * When true every child marked `data-dock-draggable` (or, lacking marks, every
184
+ * `.dock-icon-button` in the active layer) becomes GRABBABLE: a pointer-capture grab
185
+ * lets the user pull a dock item and the gesture follows ~1:1 with a volume-preserving
186
+ * gel-squish (the SHIPPED `useDragMorph` composing kf `Draggable` + `useLiquidFlex`
187
+ * "tanh" velocity-squish — NO second drag engine), then flings velocity-continuously to
188
+ * the nearest slot, committing a REORDER via `update:order`. Compositor-only
189
+ * (`transform: translate` — never a layout property); PRM-safe (the gesture still
190
+ * functions, the squish off, the release an instant nearest-snap); the roving-tabindex
191
+ * keyboard contract on the dock controls is preserved (a draggable strip that is
192
+ * keyboard-dead is the worse failure). A non-draggable dock is byte-identical to HEAD.
193
+ */
194
+ draggableItems?: boolean;
157
195
  }
158
196
  /** The resolved shell-prop computeds the GlassDock SFC binds. */
159
197
  export interface DockShellProps {
@@ -17,6 +17,17 @@ export interface DockStackItem {
17
17
  icon?: Component;
18
18
  /** Optional per-member select handler (fired alongside the model write). */
19
19
  onSelect?: () => void;
20
+ /**
21
+ * BE.W-DOCK-RAIL-REALIZE — the per-FACET accent hue (the `mode="facets"` context
22
+ * carousel only — IGNORED by the macOS `mode="stack"` glyph fan). A complete
23
+ * `<color>` (a consumer DATA/context hue) written to the chip's `--glass-accent`
24
+ * (the BB.W-GLASS-ACCENT per-instance chromatic-rim axis, `rim.css`/`material.css`),
25
+ * so each context facet carries its OWN rim+glint hue — the AZ context-carousel
26
+ * identity. Unset ⇒ the neutral warm-cream rim (the `--glass-accent: transparent`
27
+ * no-op floor). NOT a plate-background fill (the accent rides the THIN rim/glint;
28
+ * presets-in-consumers — no consumer hue enters a library token).
29
+ */
30
+ accent?: string;
20
31
  }
21
32
  /**
22
33
  * BA.W-DOCK-SECTIONS — the three named zone kinds the declarative `<DockSection>`
@@ -61,8 +72,8 @@ export interface DockSectionDescriptor {
61
72
  * prior copies were a DRY hazard — a re-tune had to touch both).
62
73
  */
63
74
  export declare const DOCK_SPRING: {
64
- readonly response: 0.32;
65
- readonly dampingFraction: 0.7;
75
+ readonly response: number;
76
+ readonly dampingFraction: number;
66
77
  };
67
78
  /**
68
79
  * The CSS properties whose `transitionend` the dock-morph window watches to know a
@@ -84,4 +95,4 @@ export declare const DOCK_MORPH_LABEL = "glass-ui:dock-morph-context";
84
95
  * edge sweeping past the cursor, not a real exit. */
85
96
  export declare const HOVER_INTENT_MS = 60;
86
97
  export declare const EDGE_BAND_PX = 24;
87
- export declare const MORPH_SETTLE_MS = 320;
98
+ export declare const MORPH_SETTLE_MS = 840;
@@ -6,6 +6,7 @@ export { default as DockBackgroundToggle } from "./DockBackgroundToggle.vue";
6
6
  export { default as DockTabButton } from "./DockTabButton.vue";
7
7
  export { default as DockSelectTrigger } from "./DockSelectTrigger.vue";
8
8
  export { default as DockDropdownTrigger } from "./DockDropdownTrigger.vue";
9
+ export { default as DockPopoverTrigger } from "./DockPopoverTrigger.vue";
9
10
  export { default as DockSeparator } from "./DockSeparator.vue";
10
11
  export { default as DockStack } from "./DockStack.vue";
11
12
  export type { DockStackItem } from "./constants";
@@ -19,3 +20,5 @@ export { useDockOrientationMorph, type DockMorphOrientation, type UseDockOrienta
19
20
  export { useDockCtaReceive, type UseDockCtaReceiveOptions, type UseDockCtaReceiveReturn, type DockCtaReceivePreset, } from "../../../composables/motion/useDockCtaReceive";
20
21
  export { useDockSearch } from "./composables";
21
22
  export type { UseDockSearchOptions, UseDockSearchReturn } from "./composables";
23
+ export { GooFilter } from "../goo-filter";
24
+ export { useDockFission, DOCK_SPLIT_SIGNATURES, type DockSplitContext, type DockSplitVector, type DockSplitSquishPeak, type DockSplitSignature, type DockFissionPieceRegistration, type DockFissionPieceHandle, type UseDockFissionOptions, type UseDockFissionReturn, } from "./composables/useDockFission";
@@ -38,6 +38,27 @@ export declare function curlFBM(p: Vec2): Vec2;
38
38
  * the round-trip anchor + the analytic ∇⊥h the displacement reads.
39
39
  */
40
40
  export declare function sampleVelocity(p: Vec2, timeSec: number, waves: readonly WaveComponent[], windSpeed: number, curlStrength: number): Vec2;
41
+ /** The cursor-vortex lever set (the √φ-laddered radius + the spin/drag/burst gains). */
42
+ export interface VortexParams {
43
+ cursor: Vec2;
44
+ /** Pointer velocity (domain units / sec). */
45
+ pointerVel: Vec2;
46
+ /** Flick-burst impulse 0..1. */
47
+ burst: number;
48
+ /** Pointer active? (inert when false — the vortex is off). */
49
+ active: boolean;
50
+ radius: number;
51
+ spin: number;
52
+ dragGain: number;
53
+ burstShove: number;
54
+ }
55
+ /**
56
+ * The velocity the cursor injects at `p` — the perturbation `cs_flow` adds to the curl
57
+ * current. A true tangential vortex (∇⊥ of the radial), plus a drag-along (the streamlines
58
+ * follow the gesture) and a radial flick shove (the shockwave), all gaussian-falling off the
59
+ * vortex radius. Returns the un-normalized perturbation in domain/sec.
60
+ */
61
+ export declare function pointerVortex(p: Vec2, v: VortexParams): Vec2;
41
62
  /** The shipped domain half-extent (the lattice is laid out over [-half, half]²). */
42
63
  export declare const FLOW_DOMAIN_HALF = 0.85;
43
64
  /**
@@ -0,0 +1,8 @@
1
+ export declare function compileGL(gl: WebGL2RenderingContext, type: number, src: string): WebGLShader;
2
+ export declare function linkGL(gl: WebGL2RenderingContext, vsSrc: string, fsSrc: string): WebGLProgram;
3
+ /** Probe whether an internal format is color-renderable as a float FBO target (R-A). */
4
+ export declare function probeRenderable(gl: WebGL2RenderingContext, internal: number, type: number): boolean;
5
+ /** Pack a Float32Array to half-float (RGBA16F upload) — the RGBA32F-absent fallback (R-A). */
6
+ export declare function float32ToHalf(src: Float32Array): Uint16Array;
7
+ /** IEEE-754 float32 → float16 bits (the standard round-to-nearest packing). */
8
+ export declare function f32ToF16(val: number): number;
@@ -0,0 +1,9 @@
1
+ import type { WebGLCanvasFrame } from "../../../../composables/glass/webgl/useWebGLCanvas";
2
+ import { type FlowSetupDeps } from "./useFlowParticles";
3
+ /**
4
+ * Build the `setupGL(gl)` callback the picker invokes on the WebGL2 path (the LIVE path).
5
+ * `field` is the kept fullscreen-fragment dot-lattice; `flow` routes to the state-texture
6
+ * GPGPU + two-FBO trail + point-sprite motes + present composite (flowSetupGLFlow) — the SAME
7
+ * advected-population gestalt as the WGPU compute path (the ONE math source via the GLSL chunk).
8
+ */
9
+ export declare function createFlowGLSetup(deps: FlowSetupDeps): (gl: WebGL2RenderingContext) => WebGLCanvasFrame;
@@ -0,0 +1,12 @@
1
+ import type { WebGLCanvasFrame } from "../../../../composables/glass/webgl/useWebGLCanvas";
2
+ import { type FlowSetupDeps } from "./useFlowParticles";
3
+ /**
4
+ * The `flow` WebGL2 channel — the AURORA CURRENT, made real + measurable + equal-gestalt:
5
+ * 1. STATE-TEXTURE GPGPU advect pass (one texel per mote; pos/speed/life ping-pong),
6
+ * 2. TRAIL decay-blit (prev → cur at the derived α) on a two-FBO RGBA16F ping-pong,
7
+ * 3. MOTE point-sprite draw (additive into the trail; speed→hue/brightness),
8
+ * 4. PRESENT composite (trail over the warm floor + corner-bloom → the swapchain).
9
+ * The float state/trail RTs fall RGBA32F→RGBA16F where the render extension is absent (R-A);
10
+ * the trail is pinned NEAREST (no half-float-linear extension dependency).
11
+ */
12
+ export declare function createFlowGLFlow(deps: FlowSetupDeps): (gl: WebGL2RenderingContext) => WebGLCanvasFrame;
@@ -0,0 +1,7 @@
1
+ import type { WebGPUCanvasFrame } from "../../../../composables/glass/webgpu/useWebGPUCanvas";
2
+ import { type FlowSetupDeps } from "./useFlowParticles";
3
+ /**
4
+ * Build the dot-flow-field `setupWGPU(device, context, format)` callback. Closes over the
5
+ * config/palette getters + the renderer's demand gate + the pointer `onFrame`/`getPointer`.
6
+ */
7
+ export declare function createFlowWGPUSetup(deps: FlowSetupDeps): (device: GPUDevice, context: GPUCanvasContext, format: GPUTextureFormat) => WebGPUCanvasFrame;
@@ -12,15 +12,34 @@ export interface FlowGridGeometry {
12
12
  export declare const FLOW_MAX_LATTICE = 16384;
13
13
  export declare function flowGridGeometry(gridPitchPx: number, canvasCssMin: number): FlowGridGeometry;
14
14
  export declare const FLOW_COMPUTE_UNIFORM_BYTES: number;
15
+ /** The live pointer/vortex state the renderer feeds the compute kernel each frame. */
16
+ export interface FlowPointerState {
17
+ /** Cursor in domain space ([-half,half]²). */
18
+ cursorX: number;
19
+ cursorY: number;
20
+ /** Pointer velocity in domain units / sec. */
21
+ velX: number;
22
+ velY: number;
23
+ /** Flick-burst impulse (0..1). */
24
+ burst: number;
25
+ /** Pointer active (1) / inert (0). */
26
+ active: number;
27
+ }
28
+ /** A rest (pointer-inert) state — the vortex is off. */
29
+ export declare const FLOW_POINTER_REST: FlowPointerState;
15
30
  export interface FlowUniformScratch {
16
31
  buffer: ArrayBuffer;
17
32
  f32: Float32Array;
18
33
  i32: Int32Array;
19
34
  }
20
35
  export declare function createFlowComputeScratch(): FlowUniformScratch;
21
- /** Pack the compute uniforms in place. */
22
- export declare function packFlowComputeUniforms(scratch: FlowUniformScratch, config: FlowFieldConfig, timeSec: number, dt: number, geometry: FlowGridGeometry): FlowUniformScratch;
36
+ /** Pack the compute uniforms in place. `count` is the live mote/lattice count (flow mode
37
+ * uses particleCount; field mode uses the lattice geometry count). */
38
+ export declare function packFlowComputeUniforms(scratch: FlowUniformScratch, config: FlowFieldConfig, timeSec: number, dt: number, geometry: FlowGridGeometry, count: number, pointer?: FlowPointerState): FlowUniformScratch;
23
39
  export declare const FLOW_RENDER_UNIFORM_BYTES: number;
40
+ /** The speed normalizer (the modal mote speed maps to the ramp MIDDLE — H2: so the full
41
+ * ember→gold→white spread paints, not a unimodal-amber blowout). */
42
+ export declare const FLOW_SPEED_NORM = 0.022;
24
43
  export declare function createFlowRenderScratch(): FlowUniformScratch;
25
44
  /** The base resting brightness (the calm-lattice floor before the band lights a dot). */
26
45
  export declare const FLOW_BASE_BRIGHT = 0.22;
@@ -37,3 +56,10 @@ export declare const FLOW_PARTICLE_BYTES = 16;
37
56
  * so the seed only needs the starting position (the lattice settles on the first frames).
38
57
  */
39
58
  export declare function seedLatticeBuffer(geometry: FlowGridGeometry): Float32Array;
59
+ /**
60
+ * BD.W-DOTFLOW-AURORA-CURRENT — seed the FLOW mote buffer: each mote scattered across the
61
+ * domain, life STAGGERED across [0, lifetimeSec) so deaths/respawns don't synchronize (the
62
+ * field never blinks). `(pos.x, pos.y, speed=0, life)` per index. A deterministic hash so
63
+ * the capture path reproduces.
64
+ */
65
+ export declare function seedFlowBuffer(count: number, lifetimeSec: number): Float32Array;
@@ -1,7 +1,12 @@
1
- import type { WebGPUCanvasFrame } from "../../../../composables/glass/webgpu/useWebGPUCanvas";
2
- import type { WebGLCanvasFrame } from "../../../../composables/glass/webgl/useWebGLCanvas";
3
1
  import type { OklchStop } from "../../../../composables/color";
4
2
  import type { FlowFieldConfig } from "../constants";
3
+ import { type FlowPointerState } from "./uniformBridgeWGPU";
4
+ export { flowGridGeometry } from "./uniformBridgeWGPU";
5
+ /** The deep warm-near-black floor + the warm rose corner-bloom (linear-sRGB), the §3 ground.
6
+ * Resolved off a warm-fire-adjacent OKLCh ground (NOT teal). The demo preset overrides via
7
+ * `config.background`; this is the fallback ground for the flow present-composite. */
8
+ export declare const FLOW_FLOOR_OKLCH: OklchStop;
9
+ export declare const FLOW_BLOOM_OKLCH: OklchStop;
5
10
  export interface FlowSetupDeps {
6
11
  canvas: HTMLCanvasElement;
7
12
  config: FlowFieldConfig;
@@ -11,21 +16,17 @@ export interface FlowSetupDeps {
11
16
  shouldContinue: () => boolean;
12
17
  /**
13
18
  * The per-frame pointer hook — useDotFlowField advances the shared
14
- * `usePointerVelocityField` here (the no-own-rAF discipline; the renderer's loop feeds
15
- * the push-API tick). ZERO own rAF.
19
+ * `usePointerVelocityField` here (the no-own-rAF discipline). ZERO own rAF.
16
20
  */
17
21
  onFrame?: (timeSec: number) => void;
22
+ /** The live pointer/vortex state the renderer feeds the flow kernel (rest = inert). */
23
+ getPointer?: () => FlowPointerState;
18
24
  }
19
- /**
20
- * Build the dot-flow-field `setupWGPU(device, context, format)` callback. Closes over the
21
- * config/palette getters + the renderer's demand gate + the pointer `onFrame` hook.
22
- */
23
- export declare function createFlowWGPUSetup(deps: FlowSetupDeps): (device: GPUDevice, context: GPUCanvasContext, format: GPUTextureFormat) => WebGPUCanvasFrame;
24
- /**
25
- * Build the `setupGL(gl)` callback the `createGpuSubstrate` WebGL2 path invokes — a clean
26
- * aurora-class fullscreen fragment pass (the retopology made the dot-lattice + brightness
27
- * model fragment-friendly; the Canvas2D point-cloud is GONE, clean break). It evaluates
28
- * the SAME `flowField.ts` height/displacement field the WGSL primary does, splicing the
29
- * SHARED GLSL color chunk (the ONE color source → no drift between the two backends).
30
- */
31
- export declare function createFlowGLSetup(deps: FlowSetupDeps): (gl: WebGL2RenderingContext) => WebGLCanvasFrame;
25
+ /** A px-min reader (the lattice density rides the min CSS dimension). */
26
+ export declare function cssMin(canvas: HTMLCanvasElement): number;
27
+ /** The flow mote count, clamped to the storage/state cap. */
28
+ export declare function flowCount(config: FlowFieldConfig): number;
29
+ /** The square state-texture side that holds `count` motes (one texel each). */
30
+ export declare function stateCols(count: number): number;
31
+ export { createFlowWGPUSetup } from "./flowSetupWGPU";
32
+ export { createFlowGLSetup } from "./flowSetupGL";
@@ -6,6 +6,14 @@ export declare const MAX_PARTICLES = 16384;
6
6
  export declare const MAX_WAVE_COMPONENTS = 8;
7
7
  /** Compile-time palette cap — mirrors the WGSL `MAX_FLOW_STOPS` #define. */
8
8
  export declare const MAX_FLOW_STOPS = 4;
9
+ export declare const PHI = 1.618033988749895;
10
+ export declare const SQRT_PHI: number;
11
+ /**
12
+ * The per-frame trail decay α DERIVED from a half-life in seconds (DRY — `trailDecay` is
13
+ * NOT a free knob; the streak persistence is a proportion of `trailHalfLife`). At a 60fps
14
+ * reference cadence, α = 2^(−dtRef / halfLife) so the trail fades to ½ over `halfLife`.
15
+ */
16
+ export declare function flowTrailDecay(halfLifeSec: number, dtRef?: number): number;
9
17
  /**
10
18
  * The full author schema — the studio's `useConfiguratorState` model. Every field is a
11
19
  * tunable the demo configurator drives; the SFC resolves it into the uniform table.
@@ -16,6 +24,49 @@ export declare const MAX_FLOW_STOPS = 4;
16
24
  * `displaceAmp`/`springK`; `coherence` maps the octave count + persistence.
17
25
  */
18
26
  export interface FlowFieldConfig {
27
+ /**
28
+ * BD.W-DOTFLOW-AURORA-CURRENT — the topology discriminator (the dock `dim`-idiom
29
+ * discipline: ONE schema, two orthogonal lever sets, no fork). `"flow"` (default) is
30
+ * the AURORA CURRENT — a dense population ADVECTED along the curl current, trailing
31
+ * fading ribbons of warm-fire light, the cursor a live vortex. `"field"` is the calm
32
+ * anchored halftone (the rebuild's content-deferential backdrop — the kept register).
33
+ */
34
+ mode: "flow" | "field";
35
+ /** Mote population (flow mode) — re-introduced, mode-scoped (field keeps gridPitch). */
36
+ particleCount: number;
37
+ /** Trail streak half-life in seconds (the √φ τ₀ anchor); `trailDecay` derives from it. */
38
+ trailHalfLife: number;
39
+ /** Half-res trail buffer scale (R-D — quarters the float fillrate at 0.5). */
40
+ trailScale: number;
41
+ /** Inertia 0..1: the velocity lerp rate (LOW = weighty arcs, eases into the field). */
42
+ turnRate: number;
43
+ /** Advection speed gain (|V| → displacement-per-frame). */
44
+ speedScale: number;
45
+ /** Brightness-from-speed gain (the velocity-map glow). */
46
+ speedGlow: number;
47
+ /** Mote lifetime in seconds before respawn (the √φ τ₀·φ rung). */
48
+ lifetimeSec: number;
49
+ /** Density-vignette strength (shared with field; thins spawns behind the content rect). */
50
+ edgeBias: number;
51
+ /** The clear content region (the v4 content-deferential vignette; shared with field). */
52
+ contentMask: {
53
+ cx: number;
54
+ cy: number;
55
+ rx: number;
56
+ ry: number;
57
+ } | null;
58
+ /** Cursor-vortex fall-off radius (the √φ r₀ anchor). */
59
+ vortexRadius: number;
60
+ /** Cursor-vortex tangential spin gain (the swirl). */
61
+ vortexSpin: number;
62
+ /** Cursor-drag advection gain (the streamlines follow the gesture). */
63
+ dragGain: number;
64
+ /** Flick-burst radial shove gain (the shockwave). */
65
+ burstShove: number;
66
+ /** WebGPU cartoon-cast shadow offset (drops on WebGL2/PRM/PRT). */
67
+ shadowOffset: number;
68
+ /** WebGPU velocity-anisotropic squash-stretch amount (drops on WebGL2/PRM/PRT). */
69
+ stretchAmp: number;
19
70
  /** The Gerstner sum-of-sines table (1..MAX_WAVE_COMPONENTS) — the LARGE-wave ladder. */
20
71
  waveComponents: WaveComponent[];
21
72
  /** The dispersion-driven sweep speed (scales ω). LOW = slow sweep (default 0.3). */
@@ -1,5 +1,5 @@
1
1
  export { default as DotFlowField } from "./DotFlowField.vue";
2
2
  export { useDotFlowField, type DotFlowFieldHandle, type UseDotFlowFieldOptions, } from "./composables/useDotFlowField";
3
3
  export { type FlowFieldConfig, DEFAULT_FLOW_CONFIG, DEFAULT_WAVE_COMPONENTS, WARM_IDENTITY_PALETTE, MAX_PARTICLES, MAX_WAVE_COMPONENTS, MAX_FLOW_STOPS, } from "./constants";
4
- export { type WaveComponent, type Vec2, sampleVelocity, gerstnerVelocity, curlFBM, buildWaveLadder, gridOrigin, sampleHeight, sampleDisplacement, waveBand, FLOW_GRAVITY, FLOW_DOMAIN_HALF, } from "./composables/flowField";
4
+ export { type WaveComponent, type Vec2, sampleVelocity, gerstnerVelocity, curlFBM, pointerVortex, type VortexParams, buildWaveLadder, gridOrigin, sampleHeight, sampleDisplacement, waveBand, FLOW_GRAVITY, FLOW_DOMAIN_HALF, } from "./composables/flowField";
5
5
  export type { OklchStop } from "../../../composables/color";
@@ -1 +1 @@
1
- export declare const FLOW_FIELD_COMPUTE_WGSL = "\nconst MAX_WAVE_COMPONENTS: i32 = 8;\nconst PI: f32 = 3.141592653589793;\nconst TAU: f32 = 6.283185307179586;\nconst FLOW_GRAVITY: f32 = 9.81;\nconst CURL_EPS: f32 = 0.012;\nconst FBM_ROT: mat2x2<f32> = mat2x2<f32>(0.8, 0.6, -0.6, 0.8);\n\nstruct Particle {\n // (pos.x, pos.y, height, |disp|) \u2014 the anchored-lattice live state\n data: vec4<f32>,\n};\n\n// \u2500\u2500 Uniforms (the typed-struct source-of-truth \u2014 see uniformBridgeWGPU.ts) \u2500\u2500\nstruct FlowUniforms {\n // p0: (uTime, uDt, uWindSpeed, uCurlStrength)\n p0: vec4<f32>,\n // p1: (uGridPitch, uDisplaceAmp, uSpringK, uGridCols) \u2014 the lattice geometry\n p1: vec4<f32>,\n // ints: (uWaveCount, uParticleCount, uGridColsI, _pad)\n ints: vec4<i32>,\n // each wave row: (amplitude, wavelength, directionDeg, phase)\n waves: array<vec4<f32>, 8>,\n};\n\n@group(0) @binding(0) var<uniform> u: FlowUniforms;\n@group(0) @binding(1) var<storage, read_write> particles: array<Particle>;\n\n// \u2500\u2500 The deterministic lattice origin (transcribes flowField.ts gridOrigin) \u2500\u2500\nfn gridOrigin(index: u32, cols: i32, pitch: f32) -> vec2<f32> {\n let c = max(cols, 1);\n let col = i32(index) % c;\n let row = i32(index) / c;\n let half = f32(c - 1) * pitch * 0.5;\n return vec2<f32>(f32(col) * pitch - half, f32(row) * pitch - half);\n}\n\n// \u2500\u2500 The Gerstner-sum analytic \u2207\u22A5h velocity (transcribes flowField.ts gerstnerVelocity) \u2500\u2500\nfn gerstnerVelocity(p: vec2<f32>, t: f32) -> vec2<f32> {\n var dhdx = 0.0;\n var dhdy = 0.0;\n let windSpeed = u.p0.z;\n let waveCount = u.ints.x;\n for (var i = 0; i < MAX_WAVE_COMPONENTS; i = i + 1) {\n if (i >= waveCount) { break; }\n let w = u.waves[i];\n let amplitude = w.x;\n let wavelength = max(w.y, 1e-4);\n let dirRad = w.z * PI / 180.0;\n let phase = w.w;\n let k = TAU / wavelength;\n let d = vec2<f32>(cos(dirRad), sin(dirRad));\n let omega = sqrt(FLOW_GRAVITY * k) * windSpeed;\n let theta = k * (d.x * p.x + d.y * p.y) - omega * t + phase;\n let akc = amplitude * k * cos(theta);\n dhdx = dhdx + akc * d.x;\n dhdy = dhdy + akc * d.y;\n }\n // v = \u2207\u22A5h = (\u2202h/\u2202y, \u2212\u2202h/\u2202x).\n return vec2<f32>(dhdy, -dhdx);\n}\n\n// \u2500\u2500 The scalar Gerstner HEIGHT (transcribes flowField.ts sampleHeight \u2014 the brightness\n// driver, normalized to \u2248[-1,1] by the total amplitude so the band thresholds are\n// wave-table-independent). \u2500\u2500\nfn sampleHeight(o: vec2<f32>, t: f32) -> f32 {\n var h = 0.0;\n var ampSum = 0.0;\n let windSpeed = u.p0.z;\n let waveCount = u.ints.x;\n for (var i = 0; i < MAX_WAVE_COMPONENTS; i = i + 1) {\n if (i >= waveCount) { break; }\n let w = u.waves[i];\n let k = TAU / max(w.y, 1e-4);\n let dirRad = w.z * PI / 180.0;\n let d = vec2<f32>(cos(dirRad), sin(dirRad));\n let omega = sqrt(FLOW_GRAVITY * k) * windSpeed;\n let theta = k * (d.x * o.x + d.y * o.y) - omega * t + w.w;\n h = h + w.x * sin(theta);\n ampSum = ampSum + abs(w.x);\n }\n return h / max(ampSum, 1e-4);\n}\n\n// \u2500\u2500 Shared curl-noise basis (the WGSL twin of flow.glsl.ts curlFBM) \u2500\u2500\nfn hash21(p: vec2<f32>) -> f32 {\n var p3 = fract(vec3<f32>(p.x, p.y, p.x) * 0.1031);\n p3 = p3 + dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\n\nfn valueNoise(p: vec2<f32>) -> f32 {\n let i = floor(p);\n let f = fract(p);\n let u2 = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n let a = hash21(i + vec2<f32>(0.0, 0.0));\n let b = hash21(i + vec2<f32>(1.0, 0.0));\n let c = hash21(i + vec2<f32>(0.0, 1.0));\n let d = hash21(i + vec2<f32>(1.0, 1.0));\n return mix(mix(a, b, u2.x), mix(c, d, u2.x), u2.y);\n}\n\nfn potentialFBM(p0: vec2<f32>) -> f32 {\n var v = 0.0;\n var amp = 0.5;\n var freq = 1.0;\n var p = p0;\n for (var i = 0; i < 3; i = i + 1) {\n v = v + amp * valueNoise(p * freq);\n p = FBM_ROT * p;\n freq = freq * 2.0;\n amp = amp * 0.5;\n }\n return v;\n}\n\nfn curlFBM(p: vec2<f32>) -> vec2<f32> {\n let dx = potentialFBM(p + vec2<f32>(CURL_EPS, 0.0)) - potentialFBM(p - vec2<f32>(CURL_EPS, 0.0));\n let dy = potentialFBM(p + vec2<f32>(0.0, CURL_EPS)) - potentialFBM(p - vec2<f32>(0.0, CURL_EPS));\n let g = vec2<f32>(dx, dy) / (2.0 * CURL_EPS);\n return vec2<f32>(g.y, -g.x);\n}\n\n// The composite flow velocity (transcribes flowField.ts sampleVelocity EXACTLY \u2014 the\n// coarse \u00D70.55 curl domain-scale, the \u00A73.2 inversion).\nfn sampleVelocity(p: vec2<f32>, t: f32) -> vec2<f32> {\n let curlStrength = u.p0.w;\n var v = gerstnerVelocity(p, t);\n if (curlStrength > 0.0) {\n let c = curlFBM(vec2<f32>(p.x * 0.55 + t * 0.15, p.y * 0.55));\n v = v + c * curlStrength;\n }\n return v;\n}\n\n// The sub-cell DISPLACEMENT (transcribes flowField.ts sampleDisplacement \u2014 \u2207\u22A5h + the\n// coarse curl break, soft-clamped through tanh so the magnitude rides into [0,1)).\nfn sampleDisplacement(o: vec2<f32>, t: f32) -> vec2<f32> {\n let v = sampleVelocity(o, t);\n let mag = length(v);\n if (mag < 1e-5) { return vec2<f32>(0.0, 0.0); }\n let bounded = tanh(mag);\n return v * (bounded / mag);\n}\n\n@compute @workgroup_size(64)\nfn cs_main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let idx = gid.x;\n let count = u32(u.ints.y);\n if (idx >= count) { return; } // bounds-guard the dispatch tail\n\n let t = u.p0.x;\n let dt = u.p0.y;\n let pitch = u.p1.x;\n let displaceAmp = u.p1.y;\n let springK = u.p1.z;\n let cols = u.ints.z;\n\n // The PERMANENT anchor \u2014 no wrap, no re-seed (the coherence fix).\n let o = gridOrigin(idx, cols, pitch);\n let disp = sampleDisplacement(o, t);\n let anchorTarget = o + disp * (displaceAmp * pitch);\n\n var pr = particles[idx];\n var pos = pr.data.xy;\n // Framerate-independent critically-damped pull-to-anchor:\n // p \u2190 mix(p, anchorTarget, 1 - exp(-springK\u00B7dt)) (the GPGPU influence-pull pattern).\n let k = 1.0 - exp(-springK * dt);\n pos = mix(pos, anchorTarget, k);\n\n let h = sampleHeight(o, t);\n particles[idx] = Particle(vec4<f32>(pos, h, length(disp)));\n}\n";
1
+ export declare const FLOW_FIELD_COMPUTE_WGSL = "\nconst MAX_WAVE_COMPONENTS: i32 = 8;\nconst PI: f32 = 3.141592653589793;\nconst TAU: f32 = 6.283185307179586;\nconst FLOW_GRAVITY: f32 = 9.81;\nconst CURL_EPS: f32 = 0.012;\nconst FBM_ROT: mat2x2<f32> = mat2x2<f32>(0.8, 0.6, -0.6, 0.8);\n\nstruct Particle {\n // field: (pos.x, pos.y, height, |disp|) \u2014 the anchored-lattice live state\n // flow: (pos.x, pos.y, speed, life) \u2014 the advected-mote live state\n data: vec4<f32>,\n};\n\n// \u2500\u2500 Uniforms (the typed-struct source-of-truth \u2014 see uniformBridgeWGPU.ts) \u2500\u2500\nstruct FlowUniforms {\n // p0: (uTime, uDt, uWindSpeed, uCurlStrength)\n p0: vec4<f32>,\n // p1: (uGridPitch, uDisplaceAmp, uSpringK, uGridCols) \u2014 the lattice geometry (field)\n p1: vec4<f32>,\n // ints: (uWaveCount, uParticleCount, uGridColsI, uMode) \u2014 uMode: 0=field, 1=flow\n ints: vec4<i32>,\n // f0: (uTurnRate, uSpeedScale, uLifetimeSec, uDomainHalf) \u2014 the flow advection levers\n f0: vec4<f32>,\n // f1: (uVortexRadius, uVortexSpin, uDragGain, uBurstShove) \u2014 the cursor vortex\n f1: vec4<f32>,\n // ptr: (cursor.x, cursor.y, vel.x, vel.y) \u2014 the pointer in domain space + its velocity\n ptr: vec4<f32>,\n // ptr2: (burst, pointerActive, edgeBias, _pad)\n ptr2: vec4<f32>,\n // each wave row: (amplitude, wavelength, directionDeg, phase)\n waves: array<vec4<f32>, 8>,\n};\n\n@group(0) @binding(0) var<uniform> u: FlowUniforms;\n@group(0) @binding(1) var<storage, read_write> particles: array<Particle>;\n\n// \u2500\u2500 The deterministic lattice origin (transcribes flowField.ts gridOrigin) \u2500\u2500\nfn gridOrigin(index: u32, cols: i32, pitch: f32) -> vec2<f32> {\n let c = max(cols, 1);\n let col = i32(index) % c;\n let row = i32(index) / c;\n let half = f32(c - 1) * pitch * 0.5;\n return vec2<f32>(f32(col) * pitch - half, f32(row) * pitch - half);\n}\n\n// \u2500\u2500 The Gerstner-sum analytic \u2207\u22A5h velocity (transcribes flowField.ts gerstnerVelocity) \u2500\u2500\nfn gerstnerVelocity(p: vec2<f32>, t: f32) -> vec2<f32> {\n var dhdx = 0.0;\n var dhdy = 0.0;\n let windSpeed = u.p0.z;\n let waveCount = u.ints.x;\n for (var i = 0; i < MAX_WAVE_COMPONENTS; i = i + 1) {\n if (i >= waveCount) { break; }\n let w = u.waves[i];\n let amplitude = w.x;\n let wavelength = max(w.y, 1e-4);\n let dirRad = w.z * PI / 180.0;\n let phase = w.w;\n let k = TAU / wavelength;\n let d = vec2<f32>(cos(dirRad), sin(dirRad));\n let omega = sqrt(FLOW_GRAVITY * k) * windSpeed;\n let theta = k * (d.x * p.x + d.y * p.y) - omega * t + phase;\n let akc = amplitude * k * cos(theta);\n dhdx = dhdx + akc * d.x;\n dhdy = dhdy + akc * d.y;\n }\n // v = \u2207\u22A5h = (\u2202h/\u2202y, \u2212\u2202h/\u2202x).\n return vec2<f32>(dhdy, -dhdx);\n}\n\n// \u2500\u2500 The scalar Gerstner HEIGHT (transcribes flowField.ts sampleHeight \u2014 the brightness\n// driver, normalized to \u2248[-1,1] by the total amplitude so the band thresholds are\n// wave-table-independent). \u2500\u2500\nfn sampleHeight(o: vec2<f32>, t: f32) -> f32 {\n var h = 0.0;\n var ampSum = 0.0;\n let windSpeed = u.p0.z;\n let waveCount = u.ints.x;\n for (var i = 0; i < MAX_WAVE_COMPONENTS; i = i + 1) {\n if (i >= waveCount) { break; }\n let w = u.waves[i];\n let k = TAU / max(w.y, 1e-4);\n let dirRad = w.z * PI / 180.0;\n let d = vec2<f32>(cos(dirRad), sin(dirRad));\n let omega = sqrt(FLOW_GRAVITY * k) * windSpeed;\n let theta = k * (d.x * o.x + d.y * o.y) - omega * t + w.w;\n h = h + w.x * sin(theta);\n ampSum = ampSum + abs(w.x);\n }\n return h / max(ampSum, 1e-4);\n}\n\n// \u2500\u2500 Shared curl-noise basis (the WGSL twin of flow.glsl.ts curlFBM) \u2500\u2500\nfn hash21(p: vec2<f32>) -> f32 {\n var p3 = fract(vec3<f32>(p.x, p.y, p.x) * 0.1031);\n p3 = p3 + dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\n\nfn valueNoise(p: vec2<f32>) -> f32 {\n let i = floor(p);\n let f = fract(p);\n let u2 = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n let a = hash21(i + vec2<f32>(0.0, 0.0));\n let b = hash21(i + vec2<f32>(1.0, 0.0));\n let c = hash21(i + vec2<f32>(0.0, 1.0));\n let d = hash21(i + vec2<f32>(1.0, 1.0));\n return mix(mix(a, b, u2.x), mix(c, d, u2.x), u2.y);\n}\n\nfn potentialFBM(p0: vec2<f32>) -> f32 {\n var v = 0.0;\n var amp = 0.5;\n var freq = 1.0;\n var p = p0;\n for (var i = 0; i < 3; i = i + 1) {\n v = v + amp * valueNoise(p * freq);\n p = FBM_ROT * p;\n freq = freq * 2.0;\n amp = amp * 0.5;\n }\n return v;\n}\n\nfn curlFBM(p: vec2<f32>) -> vec2<f32> {\n let dx = potentialFBM(p + vec2<f32>(CURL_EPS, 0.0)) - potentialFBM(p - vec2<f32>(CURL_EPS, 0.0));\n let dy = potentialFBM(p + vec2<f32>(0.0, CURL_EPS)) - potentialFBM(p - vec2<f32>(0.0, CURL_EPS));\n let g = vec2<f32>(dx, dy) / (2.0 * CURL_EPS);\n return vec2<f32>(g.y, -g.x);\n}\n\n// The composite flow velocity (transcribes flowField.ts sampleVelocity EXACTLY \u2014 the\n// coarse \u00D70.55 curl domain-scale, the \u00A73.2 inversion).\nfn sampleVelocity(p: vec2<f32>, t: f32) -> vec2<f32> {\n let curlStrength = u.p0.w;\n var v = gerstnerVelocity(p, t);\n if (curlStrength > 0.0) {\n let c = curlFBM(vec2<f32>(p.x * 0.55 + t * 0.15, p.y * 0.55));\n v = v + c * curlStrength;\n }\n return v;\n}\n\n// The sub-cell DISPLACEMENT (transcribes flowField.ts sampleDisplacement \u2014 \u2207\u22A5h + the\n// coarse curl break, soft-clamped through tanh so the magnitude rides into [0,1)).\nfn sampleDisplacement(o: vec2<f32>, t: f32) -> vec2<f32> {\n let v = sampleVelocity(o, t);\n let mag = length(v);\n if (mag < 1e-5) { return vec2<f32>(0.0, 0.0); }\n let bounded = tanh(mag);\n return v * (bounded / mag);\n}\n\n// \u2500\u2500 The cursor VORTEX injected into the velocity field (transcribes flowField.ts\n// pointerVortex). r = p \u2212 cursor; a gaussian fall-off; a TRUE tangential \u2207\u22A5 swirl +\n// a drag-along term + a radial burst shove. Inert when the pointer is inactive. \u2500\u2500\nfn pointerVortex(p: vec2<f32>) -> vec2<f32> {\n if (u.ptr2.y < 0.5) { return vec2<f32>(0.0, 0.0); } // pointer inactive \u2192 no vortex\n let cursor = u.ptr.xy;\n let vel = u.ptr.zw;\n let burst = u.ptr2.x;\n let radius = max(u.f1.x, 1e-3);\n let r = p - cursor;\n let d = length(r);\n let fall = exp(-(d * d) / (radius * radius));\n let swirl = normalize(vec2<f32>(-r.y, r.x) + vec2<f32>(1e-6, 0.0)); // tangential \u2207\u22A5\n let radial = r / max(d, 1e-4);\n let v = swirl * u.f1.y // the spin\n + vel * u.f1.z // the drag (streamlines follow the gesture)\n + radial * burst * u.f1.w; // the flick shockwave\n return v * fall;\n}\n\n// \u2500\u2500 density-weighted respawn: a hash-stratified seed inside the domain, biased toward the\n// edges by edgeBias (a faint vignette \u2014 the field never thins to a hole). \u2500\u2500\nfn respawn(idx: u32, t: f32) -> vec2<f32> {\n let half = u.f0.w;\n let s = f32(idx) * 0.013 + t * 0.37;\n let rx = hash21(vec2<f32>(s, 1.7)) * 2.0 - 1.0;\n let ry = hash21(vec2<f32>(3.1, s)) * 2.0 - 1.0;\n // edgeBias>0 pushes the seed toward the perimeter (a power-curve on |coord|).\n let bias = clamp(u.ptr2.z, 0.0, 1.0);\n let bx = sign(rx) * pow(abs(rx), mix(1.0, 0.5, bias));\n let by = sign(ry) * pow(abs(ry), mix(1.0, 0.5, bias));\n return vec2<f32>(bx, by) * half;\n}\n\n// \u2500\u2500 cs_field \u2014 the ANCHORED-LATTICE evaluator (BYTE-MOVED from cs_main; the field-mode\n// fence-scoped unit; F1 greps the no-advection/no-reseed witness WITHIN this brace-span).\nfn cs_field(idx: u32, t: f32, dt: f32) {\n let pitch = u.p1.x;\n let displaceAmp = u.p1.y;\n let springK = u.p1.z;\n let cols = u.ints.z;\n\n // The PERMANENT anchor \u2014 no wrap, no re-seed (the coherence fix).\n let o = gridOrigin(idx, cols, pitch);\n let disp = sampleDisplacement(o, t);\n let anchorTarget = o + disp * (displaceAmp * pitch);\n\n var pr = particles[idx];\n var pos = pr.data.xy;\n // Framerate-independent critically-damped pull-to-anchor:\n // p \u2190 mix(p, anchorTarget, 1 - exp(-springK\u00B7dt)) (the GPGPU influence-pull pattern).\n let k = 1.0 - exp(-springK * dt);\n pos = mix(pos, anchorTarget, k);\n\n let h = sampleHeight(o, t);\n particles[idx] = Particle(vec4<f32>(pos, h, length(disp)));\n}\n\n// \u2500\u2500 cs_flow \u2014 the AURORA CURRENT (the RE-INVENT register). Momentum-integrated advection\n// along the curl current + the live cursor vortex, with lifetime decay + density-weighted\n// respawn. F1b greps the pos+=v*dt + respawn( + pointerVortex( witness in THIS function.\nfn cs_flow(idx: u32, t: f32, dt: f32) {\n let half = u.f0.w;\n let turnRate = u.f0.x;\n let speedScale = u.f0.y;\n let lifetimeSec = max(u.f0.z, 1e-3);\n\n var pr = particles[idx];\n var pos = pr.data.xy;\n var life = pr.data.w;\n\n // First-frame / dead / out-of-domain seed (the density-weighted respawn).\n let outOfDomain = max(abs(pos.x), abs(pos.y)) > half * 1.05;\n if (life <= 0.0 || outOfDomain) {\n pos = respawn(idx, t);\n // stratify the initial life across [0,lifetime] so deaths don't synchronize.\n life = lifetimeSec * hash21(vec2<f32>(f32(idx) * 0.027, t * 0.11));\n }\n\n // The target velocity: the divergence-free curl current + the cursor vortex.\n let vField = sampleVelocity(pos, t) + pointerVortex(pos);\n // Momentum/inertia: the low turnRate scales how hard the mote commits to the field\n // each step \u2014 a weighty ease into the current's turns (arcs, not snaps), the\n // overlapping-action/follow-through on a particle (R4-motion).\n let v = vField * turnRate * speedScale;\n // Forward-Euler advection step (the integrator \u2014 F1b's witness pos = pos + v*dt).\n pos = pos + v * dt * 60.0;\n\n life = life - dt;\n let speed = length(v);\n particles[idx] = Particle(vec4<f32>(pos, speed, life));\n}\n\n@compute @workgroup_size(64)\nfn cs_main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let idx = gid.x;\n let count = u32(u.ints.y);\n if (idx >= count) { return; } // bounds-guard the dispatch tail\n\n let t = u.p0.x;\n let dt = u.p0.y;\n let mode = u.ints.w;\n\n if (mode == 1) {\n cs_flow(idx, t, dt);\n } else {\n cs_field(idx, t, dt);\n }\n}\n";
@@ -2,3 +2,32 @@
2
2
  export declare const FLOW_FIELD_VERT_GLSL = "#version 300 es\nprecision highp float;\nin vec2 aPosition;\nout vec2 vUv;\nvoid main() {\n vUv = aPosition; // [-1,1]\u00B2 domain\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}";
3
3
  /** The dot-lattice + sweeping-brightness fragment source (the anchored-grid model). */
4
4
  export declare const FLOW_FIELD_FRAG_GLSL = "#version 300 es\nprecision highp float;\n\n#define PI 3.141592653589793\n#define TAU 6.283185307179586\n#define FLOW_GRAVITY 9.81\n#define CURL_EPS 0.012\n#define MAX_WAVE_COMPONENTS 8\n#define MAX_FLOW_STOPS 4\n\nin vec2 vUv;\nout vec4 fragColor;\n\nuniform float uTime;\nuniform float uWindSpeed;\nuniform float uCurlStrength;\nuniform float uDomainHalf;\nuniform float uAspect;\nuniform float uGridPitchDomain; // lattice pitch in DOMAIN units\nuniform float uDotRadiusDomain; // dot radius in DOMAIN units\nuniform float uDisplaceAmp; // sub-cell drift in pitch fractions\nuniform float uContrast;\nuniform float uBaseBright;\nuniform float uWaveBandCenter;\nuniform float uWaveBandWidth;\nuniform float uGlobeMask;\nuniform int uWaveCount;\nuniform int uStopCount;\nuniform float uHasBackground;\nuniform vec3 uBg;\nuniform vec4 uWaves[MAX_WAVE_COMPONENTS]; // (amplitude, wavelength, directionDeg, phase)\nuniform vec3 uPalette[MAX_FLOW_STOPS]; // linear-sRGB stops\n\nconst mat2 FBM_ROT = mat2(0.8, 0.6, -0.6, 0.8);\n\n\nfloat srgbToLinearCh(float c) {\n return c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);\n}\nvec3 srgbToLinear(vec3 c) {\n return vec3(srgbToLinearCh(c.r), srgbToLinearCh(c.g), srgbToLinearCh(c.b));\n}\n\nfloat linearToSrgbCh(float c) {\n return c <= 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055;\n}\nvec3 linearToSrgb(vec3 c) {\n return vec3(linearToSrgbCh(c.r), linearToSrgbCh(c.g), linearToSrgbCh(c.b));\n}\n\n// value.js LINEAR_SRGB_TO_LMS (constants.ts), row-major; written here as GLSL\n// columns (= the transpose) so mat3 * vec3 evaluates the row-major M\u00B7v.\nconst mat3 LINEAR_SRGB_TO_LMS = mat3(\n 0.4122214708, 0.2119034982, 0.0883024619,\n 0.5363325363, 0.6806995451, 0.2817188376,\n 0.0514459929, 0.1073969566, 0.6299787005\n);\n\n// value.js srgbToOKLab's INLINE LMS\u2192OKLab coefficients (gamut.ts lines 295-297 \u2014\n// these differ at the ~1e-9 digit from LMS_TO_OKLAB_MATRIX; use the inline ones to\n// mirror the exact value.js path), row-major \u2192 GLSL columns.\nconst mat3 LMS_TO_OKLAB = mat3(\n 0.2104542553, 1.9779984951, 0.0259040371,\n 0.7936177850, -2.4285922050, 0.7827717662,\n -0.0040720468, 0.4505937099, -0.8086757660\n);\n\n// value.js OKLAB_TO_LMS_COEFF (constants.ts), row-major \u2192 GLSL columns. Rows:\n// l = [1, 0.3963377774, 0.2158037573], m = [1, -0.1055613458, -0.0638541728],\n// s = [1, -0.0894841775, -1.2914855480].\nconst mat3 OKLAB_TO_LMS = mat3(\n 1.0, 1.0, 1.0,\n 0.3963377774, -0.1055613458, -0.0894841775,\n 0.2158037573, -0.0638541728, -1.2914855480\n);\n\n// value.js LMS_TO_LINEAR_SRGB (constants.ts), row-major \u2192 GLSL columns.\nconst mat3 LMS_TO_LINEAR_SRGB = mat3(\n 4.0767416621, -1.2684380046, -0.0041960863,\n -3.3077115913, 2.6097574011, -0.7034186147,\n 0.2309699292, -0.3413193965, 1.7076147010\n);\n\n// Gamma sRGB \u2192 raw OKLab (L, a, b). Mirrors value.js srgbToOKLab.\nvec3 srgbToOklab(vec3 c) {\n vec3 lin = srgbToLinear(c);\n vec3 lms = LINEAR_SRGB_TO_LMS * lin;\n vec3 lmsCbrt = sign(lms) * pow(abs(lms), vec3(1.0 / 3.0));\n return LMS_TO_OKLAB * lmsCbrt;\n}\n\n// Raw OKLab (L, a, b) \u2192 linear sRGB. Mirrors value.js oklabToLinearSRGB.\nvec3 oklabToLinearSrgb(vec3 lab) {\n vec3 lms_ = OKLAB_TO_LMS * lab;\n vec3 lms = lms_ * lms_ * lms_;\n return LMS_TO_LINEAR_SRGB * lms;\n}\n\n// OKLab \u2192 OKLCh: H in RADIANS. Mirrors value.js rawOklabToOklch (which returns\n// degrees; we stay in radians and only fold to [0, 2pi)).\nvec3 oklabToOklch(vec3 lab) {\n float C = length(lab.yz);\n float H = atan(lab.z, lab.y);\n if (H < 0.0) H += 2.0 * PI;\n return vec3(lab.x, C, H);\n}\n\n// OKLCh (H radians) \u2192 OKLab. Mirrors value.js rawOklchToOklab.\nvec3 oklchToOklab(vec3 lch) {\n return vec3(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));\n}\n\n// \u2500\u2500 The Gerstner-sum analytic \u2207\u22A5h velocity (transcribes flowField.ts gerstnerVelocity) \u2500\u2500\nvec2 gerstnerVelocity(vec2 p, float t) {\n float dhdx = 0.0;\n float dhdy = 0.0;\n for (int i = 0; i < MAX_WAVE_COMPONENTS; i++) {\n if (i >= uWaveCount) break;\n vec4 w = uWaves[i];\n float k = TAU / max(w.y, 1e-4);\n float dirRad = w.z * PI / 180.0;\n vec2 d = vec2(cos(dirRad), sin(dirRad));\n float omega = sqrt(FLOW_GRAVITY * k) * uWindSpeed;\n float theta = k * (d.x * p.x + d.y * p.y) - omega * t + w.w;\n float akc = w.x * k * cos(theta);\n dhdx += akc * d.x;\n dhdy += akc * d.y;\n }\n return vec2(dhdy, -dhdx);\n}\n\n// \u2500\u2500 The scalar Gerstner HEIGHT (transcribes flowField.ts sampleHeight) \u2500\u2500\nfloat sampleHeight(vec2 o, float t) {\n float h = 0.0;\n float ampSum = 0.0;\n for (int i = 0; i < MAX_WAVE_COMPONENTS; i++) {\n if (i >= uWaveCount) break;\n vec4 w = uWaves[i];\n float k = TAU / max(w.y, 1e-4);\n float dirRad = w.z * PI / 180.0;\n vec2 d = vec2(cos(dirRad), sin(dirRad));\n float omega = sqrt(FLOW_GRAVITY * k) * uWindSpeed;\n float theta = k * (d.x * o.x + d.y * o.y) - omega * t + w.w;\n h += w.x * sin(theta);\n ampSum += abs(w.x);\n }\n return h / max(ampSum, 1e-4);\n}\n\n// \u2500\u2500 Shared curl-noise basis (the GLSL twin of flow.glsl.ts curlFBM) \u2500\u2500\nfloat hash21(vec2 p) {\n vec3 p3 = fract(vec3(p.x, p.y, p.x) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\nfloat valueNoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u2 = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n float a = hash21(i + vec2(0.0, 0.0));\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u2.x), mix(c, d, u2.x), u2.y);\n}\nfloat potentialFBM(vec2 p0) {\n float v = 0.0;\n float amp = 0.5;\n float freq = 1.0;\n vec2 p = p0;\n for (int i = 0; i < 3; i++) {\n v += amp * valueNoise(p * freq);\n p = FBM_ROT * p;\n freq *= 2.0;\n amp *= 0.5;\n }\n return v;\n}\nvec2 curlFBM(vec2 p) {\n float dx = potentialFBM(p + vec2(CURL_EPS, 0.0)) - potentialFBM(p - vec2(CURL_EPS, 0.0));\n float dy = potentialFBM(p + vec2(0.0, CURL_EPS)) - potentialFBM(p - vec2(0.0, CURL_EPS));\n vec2 g = vec2(dx, dy) / (2.0 * CURL_EPS);\n return vec2(g.y, -g.x);\n}\nvec2 sampleVelocity(vec2 p, float t) {\n vec2 v = gerstnerVelocity(p, t);\n if (uCurlStrength > 0.0) {\n vec2 c = curlFBM(vec2(p.x * 0.55 + t * 0.15, p.y * 0.55));\n v += c * uCurlStrength;\n }\n return v;\n}\n// sub-cell displacement (transcribes flowField.ts sampleDisplacement \u2014 tanh soft-clamp).\nvec2 sampleDisplacement(vec2 o, float t) {\n vec2 v = sampleVelocity(o, t);\n float mag = length(v);\n if (mag < 1e-5) return vec2(0.0);\n return v * (tanh(mag) / mag);\n}\n\n// The sweeping bright-stripe band (transcribes flowField.ts waveBand).\nfloat waveBand(float h, float center, float width) {\n float w = max(width, 1e-3);\n float d = abs(h - center);\n return 1.0 - smoothstep(0.0, w, d);\n}\n\n// The optional soft-disc globe mask (the reference's two-sphere composition).\nfloat globeMask(vec2 o, float t, float on) {\n if (on <= 0.5) return 1.0;\n float cx = 0.35 * sin(t * 0.13);\n float cy = 0.28 * cos(t * 0.11);\n float d = length(o - vec2(cx, cy));\n return 1.0 - smoothstep(0.45, 0.75, d);\n}\n\nvec3 samplePaletteLin(float t) {\n if (uStopCount <= 1) return uPalette[0];\n float n = float(uStopCount);\n float ft = clamp(t, 0.0, 1.0) * (n - 1.0);\n int i0 = int(floor(ft));\n int i1 = min(i0 + 1, uStopCount - 1);\n float f = ft - float(i0);\n vec3 lmsA = LINEAR_SRGB_TO_LMS * uPalette[i0];\n vec3 lmsB = LINEAR_SRGB_TO_LMS * uPalette[i1];\n vec3 labA = LMS_TO_OKLAB * (sign(lmsA) * pow(abs(lmsA), vec3(1.0 / 3.0)));\n vec3 labB = LMS_TO_OKLAB * (sign(lmsB) * pow(abs(lmsB), vec3(1.0 / 3.0)));\n return oklabToLinearSrgb(mix(labA, labB, f));\n}\n\nvoid main() {\n float aspect = max(uAspect, 1e-4);\n // Domain-space pixel (aspect-corrected x so the lattice stays square).\n vec2 p = vec2(vUv.x * aspect, vUv.y);\n float pitch = max(uGridPitchDomain, 1e-3);\n\n // The nearest lattice cell ORIGIN (the anchored grid \u2014 the deterministic gridOrigin\n // mapping, evaluated per-pixel: round p/pitch to the nearest cell center).\n vec2 cell = floor(p / pitch + 0.5);\n vec2 o = cell * pitch;\n\n // The dot DRIFTS toward o + disp\u00B7displaceAmp\u00B7pitch (the same sub-cell offset the\n // compute kernel writes \u2014 here evaluated analytically per pixel).\n vec2 disp = sampleDisplacement(o, uTime);\n vec2 dotCenter = o + disp * (uDisplaceAmp * pitch);\n\n // The soft circle around the (drifted) dot center.\n float dist = length(p - dotCenter);\n float radius = max(uDotRadiusDomain, 1e-4);\n float mask = 1.0 - smoothstep(radius * 0.6, radius, dist);\n if (mask < 0.002) {\n if (uHasBackground > 0.5) {\n fragColor = vec4(clamp(linearToSrgb(uBg), vec3(0.0), vec3(1.0)), 1.0);\n } else {\n fragColor = vec4(0.0);\n }\n return;\n }\n\n // The brightness lights the dot \u2014 the SWEEPING band over the height at the anchor.\n float h = sampleHeight(o, uTime);\n float band = waveBand(h, uWaveBandCenter, uWaveBandWidth);\n float bright = (uBaseBright + band * uContrast) * globeMask(o, uTime, uGlobeMask);\n bright = clamp(bright, 0.0, 1.6);\n\n float tone = clamp(bright, 0.0, 1.0);\n vec3 lin = samplePaletteLin(tone) * bright;\n vec3 rgb = clamp(linearToSrgb(lin), vec3(0.0), vec3(1.0));\n float alpha = mask * clamp(bright * 0.8 + 0.12, 0.0, 1.0);\n\n if (uHasBackground > 0.5) {\n vec3 bg = clamp(linearToSrgb(uBg), vec3(0.0), vec3(1.0));\n fragColor = vec4(mix(bg, rgb, alpha), 1.0);\n return;\n }\n fragColor = vec4(rgb * alpha, alpha);\n}";
5
+ /** The fullscreen-quad vertex pass for the GPGPU/trail passes (a [-1,1] clip quad). */
6
+ export declare const FLOW_FIELD_QUAD_VERT_GLSL = "#version 300 es\nprecision highp float;\nin vec2 aPosition;\nout vec2 vUv;\nvoid main() {\n vUv = aPosition * 0.5 + 0.5; // [0,1] texel space\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}";
7
+ /**
8
+ * The STATE-TEXTURE GPGPU advect pass (proof:dotflow-fence F4 — the GPGPU export replacing
9
+ * the FLOW_FIELD_FRAG_GLSL mandate). One texel per mote, RGBA = (pos.x, pos.y, speed, life).
10
+ * Each frame: read prev state, advect along the curl current + the cursor VORTEX with
11
+ * momentum (turnRate), decrement life, density-weighted respawn on death/out-of-domain.
12
+ * The math twin of cs_flow (WGSL) — F3 round-trips the SAME sampleVelocity.
13
+ */
14
+ export declare const FLOW_FIELD_STATE_GLSL = "#version 300 es\nprecision highp float;\nin vec2 vUv;\nout vec4 fragColor;\n\nuniform sampler2D uState; // prev particle state (RGBA = pos.xy, speed, life)\nuniform float uDt;\nuniform float uDomainHalf;\nuniform float uTurnRate;\nuniform float uSpeedScale;\nuniform float uLifetimeSec;\nuniform float uEdgeBias;\nuniform vec2 uCursor; // pointer in domain space\nuniform vec2 uPointerVel; // pointer velocity (domain/s)\nuniform float uBurst; // flick-burst impulse\nuniform float uPointerActive; // 0/1\nuniform float uVortexRadius;\nuniform float uVortexSpin;\nuniform float uDragGain;\nuniform float uBurstShove;\n\n\n#define PI 3.141592653589793\n#define TAU 6.283185307179586\n#define FLOW_GRAVITY 9.81\n#define CURL_EPS 0.012\n#define MAX_WAVE_COMPONENTS 8\nconst mat2 FBM_ROT = mat2(0.8, 0.6, -0.6, 0.8);\n\nuniform float uTime;\nuniform float uWindSpeed;\nuniform float uCurlStrength;\nuniform int uWaveCount;\nuniform vec4 uWaves[MAX_WAVE_COMPONENTS]; // (amplitude, wavelength, directionDeg, phase)\n\nvec2 gerstnerVelocity(vec2 p, float t) {\n float dhdx = 0.0; float dhdy = 0.0;\n for (int i = 0; i < MAX_WAVE_COMPONENTS; i++) {\n if (i >= uWaveCount) break;\n vec4 w = uWaves[i];\n float k = TAU / max(w.y, 1e-4);\n float dirRad = w.z * PI / 180.0;\n vec2 d = vec2(cos(dirRad), sin(dirRad));\n float omega = sqrt(FLOW_GRAVITY * k) * uWindSpeed;\n float theta = k * (d.x * p.x + d.y * p.y) - omega * t + w.w;\n float akc = w.x * k * cos(theta);\n dhdx += akc * d.x; dhdy += akc * d.y;\n }\n return vec2(dhdy, -dhdx);\n}\nfloat hash21f(vec2 p) {\n vec3 p3 = fract(vec3(p.x, p.y, p.x) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\nfloat valueNoiseF(vec2 p) {\n vec2 i = floor(p); vec2 f = fract(p);\n vec2 u2 = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n float a = hash21f(i + vec2(0.0, 0.0));\n float b = hash21f(i + vec2(1.0, 0.0));\n float c = hash21f(i + vec2(0.0, 1.0));\n float d = hash21f(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u2.x), mix(c, d, u2.x), u2.y);\n}\nfloat potentialFBMf(vec2 p0) {\n float v = 0.0; float amp = 0.5; float freq = 1.0; vec2 p = p0;\n for (int i = 0; i < 3; i++) { v += amp * valueNoiseF(p * freq); p = FBM_ROT * p; freq *= 2.0; amp *= 0.5; }\n return v;\n}\nvec2 curlFBMf(vec2 p) {\n float dx = potentialFBMf(p + vec2(CURL_EPS, 0.0)) - potentialFBMf(p - vec2(CURL_EPS, 0.0));\n float dy = potentialFBMf(p + vec2(0.0, CURL_EPS)) - potentialFBMf(p - vec2(0.0, CURL_EPS));\n vec2 g = vec2(dx, dy) / (2.0 * CURL_EPS);\n return vec2(g.y, -g.x);\n}\nvec2 sampleVelocityF(vec2 p, float t) {\n vec2 v = gerstnerVelocity(p, t);\n if (uCurlStrength > 0.0) { v += curlFBMf(vec2(p.x * 0.55 + t * 0.15, p.y * 0.55)) * uCurlStrength; }\n return v;\n}\n\n\nvec2 pointerVortex(vec2 p) {\n if (uPointerActive < 0.5) return vec2(0.0);\n vec2 r = p - uCursor;\n float d = length(r);\n float radius = max(uVortexRadius, 1e-3);\n float fall = exp(-(d * d) / (radius * radius));\n vec2 swirl = normalize(vec2(-r.y, r.x) + vec2(1e-6, 0.0));\n vec2 radial = r / max(d, 1e-4);\n vec2 v = swirl * uVortexSpin + uPointerVel * uDragGain + radial * uBurst * uBurstShove;\n return v * fall;\n}\n\nvec2 respawn(vec2 seed, float t) {\n float rx = hash21f(seed + vec2(t * 0.37, 1.7)) * 2.0 - 1.0;\n float ry = hash21f(seed.yx + vec2(3.1, t * 0.37)) * 2.0 - 1.0;\n float bias = clamp(uEdgeBias, 0.0, 1.0);\n float bx = sign(rx) * pow(abs(rx), mix(1.0, 0.5, bias));\n float by = sign(ry) * pow(abs(ry), mix(1.0, 0.5, bias));\n return vec2(bx, by) * uDomainHalf;\n}\n\nvoid main() {\n vec4 st = texture(uState, vUv);\n vec2 pos = st.xy;\n float life = st.w;\n float half = uDomainHalf;\n\n bool dead = life <= 0.0;\n bool outOfDomain = max(abs(pos.x), abs(pos.y)) > half * 1.05;\n if (dead || outOfDomain) {\n pos = respawn(vUv, uTime);\n life = max(uLifetimeSec, 1e-3) * hash21f(vUv * 7.0 + uTime * 0.11);\n }\n\n vec2 vField = sampleVelocityF(pos, uTime) + pointerVortex(pos);\n // momentum: low turnRate = weighty arcs (eases into the current's turns).\n vec2 v = vField * uTurnRate * uSpeedScale;\n // forward-Euler advection (pos = pos + v*dt \u2014 the integrand twin of cs_flow).\n pos = pos + v * uDt * 60.0;\n life = life - uDt;\n\n fragColor = vec4(pos, length(v), life);\n}";
15
+ /**
16
+ * The MOTE point-sprite pass — reads the advected state texture by gl_VertexID, places a
17
+ * point sprite at the mote, sizes/brightens/hues it by SPEED·life (the velocity-map). Drawn
18
+ * additively into the trail FBO. The warm-fire palette is spliced via the shared color seam.
19
+ */
20
+ export declare const FLOW_FIELD_POINT_VERT_GLSL = "#version 300 es\nprecision highp float;\nuniform sampler2D uState;\nuniform int uStateCols;\nuniform float uDomainHalf;\nuniform float uPointSize;\nuniform float uSpeedNorm; // the speed\u2192[0,1] normalizer (modal-speed at ramp middle)\nuniform float uStretchAmp;\nout float vSpeedNorm;\nout float vFade;\nvoid main() {\n int id = gl_VertexID;\n int col = id % uStateCols;\n int row = id / uStateCols;\n vec2 uv = (vec2(float(col), float(row)) + 0.5) / float(uStateCols);\n vec4 st = texture(uState, uv);\n vec2 pos = st.xy;\n float speed = st.z;\n float life = st.w;\n float sn = clamp(speed / max(uSpeedNorm, 1e-4), 0.0, 1.0);\n vSpeedNorm = sn;\n vFade = clamp(life * 3.0, 0.0, 1.0);\n // NDC: domain [-half,half] \u2192 [-1,1].\n gl_Position = vec4(pos / uDomainHalf, 0.0, 1.0);\n // faster motes read as larger hot speed-cores (the cartoon \"more\" as point size).\n gl_PointSize = max(uPointSize * (1.0 + sn * (uStretchAmp + 1.0)), 1.0);\n}";
21
+ export declare const FLOW_FIELD_POINT_FRAG_GLSL = "#version 300 es\nprecision highp float;\n#define MAX_FLOW_STOPS 4\nin float vSpeedNorm;\nin float vFade;\nout vec4 fragColor;\nuniform int uStopCount;\nuniform vec3 uPalette[MAX_FLOW_STOPS];\nuniform float uSpeedGlow;\n\n\nfloat srgbToLinearCh(float c) {\n return c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);\n}\nvec3 srgbToLinear(vec3 c) {\n return vec3(srgbToLinearCh(c.r), srgbToLinearCh(c.g), srgbToLinearCh(c.b));\n}\n\nfloat linearToSrgbCh(float c) {\n return c <= 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055;\n}\nvec3 linearToSrgb(vec3 c) {\n return vec3(linearToSrgbCh(c.r), linearToSrgbCh(c.g), linearToSrgbCh(c.b));\n}\n\n// value.js LINEAR_SRGB_TO_LMS (constants.ts), row-major; written here as GLSL\n// columns (= the transpose) so mat3 * vec3 evaluates the row-major M\u00B7v.\nconst mat3 LINEAR_SRGB_TO_LMS = mat3(\n 0.4122214708, 0.2119034982, 0.0883024619,\n 0.5363325363, 0.6806995451, 0.2817188376,\n 0.0514459929, 0.1073969566, 0.6299787005\n);\n\n// value.js srgbToOKLab's INLINE LMS\u2192OKLab coefficients (gamut.ts lines 295-297 \u2014\n// these differ at the ~1e-9 digit from LMS_TO_OKLAB_MATRIX; use the inline ones to\n// mirror the exact value.js path), row-major \u2192 GLSL columns.\nconst mat3 LMS_TO_OKLAB = mat3(\n 0.2104542553, 1.9779984951, 0.0259040371,\n 0.7936177850, -2.4285922050, 0.7827717662,\n -0.0040720468, 0.4505937099, -0.8086757660\n);\n\n// value.js OKLAB_TO_LMS_COEFF (constants.ts), row-major \u2192 GLSL columns. Rows:\n// l = [1, 0.3963377774, 0.2158037573], m = [1, -0.1055613458, -0.0638541728],\n// s = [1, -0.0894841775, -1.2914855480].\nconst mat3 OKLAB_TO_LMS = mat3(\n 1.0, 1.0, 1.0,\n 0.3963377774, -0.1055613458, -0.0894841775,\n 0.2158037573, -0.0638541728, -1.2914855480\n);\n\n// value.js LMS_TO_LINEAR_SRGB (constants.ts), row-major \u2192 GLSL columns.\nconst mat3 LMS_TO_LINEAR_SRGB = mat3(\n 4.0767416621, -1.2684380046, -0.0041960863,\n -3.3077115913, 2.6097574011, -0.7034186147,\n 0.2309699292, -0.3413193965, 1.7076147010\n);\n\n// Gamma sRGB \u2192 raw OKLab (L, a, b). Mirrors value.js srgbToOKLab.\nvec3 srgbToOklab(vec3 c) {\n vec3 lin = srgbToLinear(c);\n vec3 lms = LINEAR_SRGB_TO_LMS * lin;\n vec3 lmsCbrt = sign(lms) * pow(abs(lms), vec3(1.0 / 3.0));\n return LMS_TO_OKLAB * lmsCbrt;\n}\n\n// Raw OKLab (L, a, b) \u2192 linear sRGB. Mirrors value.js oklabToLinearSRGB.\nvec3 oklabToLinearSrgb(vec3 lab) {\n vec3 lms_ = OKLAB_TO_LMS * lab;\n vec3 lms = lms_ * lms_ * lms_;\n return LMS_TO_LINEAR_SRGB * lms;\n}\n\n// OKLab \u2192 OKLCh: H in RADIANS. Mirrors value.js rawOklabToOklch (which returns\n// degrees; we stay in radians and only fold to [0, 2pi)).\nvec3 oklabToOklch(vec3 lab) {\n float C = length(lab.yz);\n float H = atan(lab.z, lab.y);\n if (H < 0.0) H += 2.0 * PI;\n return vec3(lab.x, C, H);\n}\n\n// OKLCh (H radians) \u2192 OKLab. Mirrors value.js rawOklchToOklab.\nvec3 oklchToOklab(vec3 lch) {\n return vec3(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));\n}\n\nvec3 samplePaletteLin(float t) {\n if (uStopCount <= 1) return uPalette[0];\n float n = float(uStopCount);\n float ft = clamp(t, 0.0, 1.0) * (n - 1.0);\n int i0 = int(floor(ft));\n int i1 = min(i0 + 1, uStopCount - 1);\n float f = ft - float(i0);\n vec3 lmsA = LINEAR_SRGB_TO_LMS * uPalette[i0];\n vec3 lmsB = LINEAR_SRGB_TO_LMS * uPalette[i1];\n vec3 labA = LMS_TO_OKLAB * (sign(lmsA) * pow(abs(lmsA), vec3(1.0 / 3.0)));\n vec3 labB = LMS_TO_OKLAB * (sign(lmsB) * pow(abs(lmsB), vec3(1.0 / 3.0)));\n return oklabToLinearSrgb(mix(labA, labB, f));\n}\n\nvoid main() {\n // soft round sprite \u2014 a tight hot core (mask\u00B2 caps the white wash, H2).\n vec2 pc = gl_PointCoord * 2.0 - 1.0;\n float r = length(pc);\n float mask = 1.0 - smoothstep(0.55, 1.0, r);\n if (mask < 0.002) discard;\n float core = mask * mask;\n float bright = (0.35 + vSpeedNorm * uSpeedGlow) * vFade;\n vec3 lin = samplePaletteLin(vSpeedNorm) * bright;\n vec3 rgb = clamp(linearToSrgb(lin), vec3(0.0), vec3(1.0));\n float a = core * clamp(bright, 0.0, 1.0);\n fragColor = vec4(rgb * a, a); // additive premultiplied (the trail braids the ribbons)\n}";
22
+ /**
23
+ * The TRAIL decay-blit — draws the PREVIOUS trail frame back at the derived decay α (toward
24
+ * the warm floor), so the motes drawn additively after it leave fading ribbons of light.
25
+ * The headline gestalt lever. Pinned NEAREST (no half-float-linear extension dependency).
26
+ */
27
+ export declare const FLOW_FIELD_TRAIL_FRAG_GLSL = "#version 300 es\nprecision highp float;\nin vec2 vUv;\nout vec4 fragColor;\nuniform sampler2D uPrev;\nuniform float uDecay; // per-frame trail persistence (DERIVED from trailHalfLife)\nvoid main() {\n vec4 prev = texture(uPrev, vUv);\n fragColor = prev * uDecay; // fade toward black; the warm floor is the present-blit's\n}";
28
+ /**
29
+ * The PRESENT blit — composites the trail buffer over the warm-near-black floor + the
30
+ * colorful corner-bloom (the §3 colorful-field-behind-glass ground), tone-mapped so the hot
31
+ * cores read without a white wash. The full-bleed ground is HERE, not a parallel plane.
32
+ */
33
+ export declare const FLOW_FIELD_PRESENT_FRAG_GLSL = "#version 300 es\nprecision highp float;\nin vec2 vUv;\nout vec4 fragColor;\nuniform sampler2D uTrail;\nuniform vec3 uFloor; // the deep warm-near-black floor (linear-sRGB)\nuniform vec3 uBloomColor; // the warm rose/magenta corner-bloom (linear-sRGB)\nuniform float uHasGround; // 0 \u2192 transparent (compose over the page field); 1 \u2192 opaque floor\n\n\nfloat srgbToLinearCh(float c) {\n return c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);\n}\nvec3 srgbToLinear(vec3 c) {\n return vec3(srgbToLinearCh(c.r), srgbToLinearCh(c.g), srgbToLinearCh(c.b));\n}\n\nfloat linearToSrgbCh(float c) {\n return c <= 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055;\n}\nvec3 linearToSrgb(vec3 c) {\n return vec3(linearToSrgbCh(c.r), linearToSrgbCh(c.g), linearToSrgbCh(c.b));\n}\n\nvoid main() {\n vec3 trail = texture(uTrail, vUv).rgb;\n // soft tone-map the accumulated additive trail (Reinhard \u2014 hot cores, not white wash).\n vec3 mapped = trail / (trail + vec3(0.85));\n if (uHasGround < 0.5) {\n // compose OVER the page's warm field: emit the lit ribbons premultiplied, no floor.\n vec3 rgb = clamp(linearToSrgb(mapped), vec3(0.0), vec3(1.0));\n float a = clamp(max(mapped.r, max(mapped.g, mapped.b)), 0.0, 1.0);\n fragColor = vec4(rgb * a, a);\n return;\n }\n // the corner-bloom: a faint warm rose radial in one corner (NOT teal).\n float bloom = smoothstep(1.3, 0.0, distance(vUv, vec2(0.12, 0.88)));\n vec3 floorLin = uFloor + uBloomColor * bloom * 0.5;\n vec3 lin = floorLin + mapped; // the ribbons sit OVER the warm floor\n vec3 rgb = clamp(linearToSrgb(lin), vec3(0.0), vec3(1.0));\n fragColor = vec4(rgb, 1.0);\n}";
@@ -1 +1,2 @@
1
- export declare const FLOW_FIELD_RENDER_WGSL = "\nconst PI: f32 = 3.141592653589793;\nconst TAU: f32 = 6.283185307179586;\nconst MAX_FLOW_STOPS: i32 = 4;\n\nstruct Particle {\n // (pos.x, pos.y, height, |disp|)\n data: vec4<f32>,\n};\n\n// \u2500\u2500 Render uniforms (the typed-struct source-of-truth \u2014 see uniformBridgeWGPU.ts) \u2500\u2500\nstruct RenderUniforms {\n // r0: (uTime, uContrast, uBaseBright, uDomainHalf)\n r0: vec4<f32>,\n // r1: (uDotSize, uSizePulse, uAspect, uGridPitch)\n r1: vec4<f32>,\n // r2: (uWaveBandCenter, uWaveBandWidth, uGlobeMask, _pad)\n r2: vec4<f32>,\n // ints: (uStopCount, uParticleCount, _pad, _pad)\n ints: vec4<i32>,\n // bg: (background.rgb, hasBackground)\n bg: vec4<f32>,\n // each palette stop: linear-sRGB rgb + _pad\n palette: array<vec4<f32>, 4>,\n};\n\n@group(0) @binding(0) var<uniform> u: RenderUniforms;\n@group(0) @binding(1) var<storage, read> particles: array<Particle>;\n\n\nfn srgbToLinearCh(c: f32) -> f32 {\n if (c <= 0.04045) { return c / 12.92; }\n return pow((c + 0.055) / 1.055, 2.4);\n}\nfn srgbToLinear(c: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(srgbToLinearCh(c.r), srgbToLinearCh(c.g), srgbToLinearCh(c.b));\n}\n\nfn linearToSrgbCh(c: f32) -> f32 {\n if (c <= 0.0031308) { return c * 12.92; }\n return 1.055 * pow(c, 1.0 / 2.4) - 0.055;\n}\nfn linearToSrgb(c: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(linearToSrgbCh(c.r), linearToSrgbCh(c.g), linearToSrgbCh(c.b));\n}\n\n// value.js LINEAR_SRGB_TO_LMS, row-major \u2192 WGSL columns (= the transpose).\nconst LINEAR_SRGB_TO_LMS: mat3x3<f32> = mat3x3<f32>(\n 0.4122214708, 0.2119034982, 0.0883024619,\n 0.5363325363, 0.6806995451, 0.2817188376,\n 0.0514459929, 0.1073969566, 0.6299787005\n);\n\n// value.js srgbToOKLab's INLINE LMS\u2192OKLab coefficients, row-major \u2192 WGSL columns.\nconst LMS_TO_OKLAB: mat3x3<f32> = mat3x3<f32>(\n 0.2104542553, 1.9779984951, 0.0259040371,\n 0.7936177850, -2.4285922050, 0.7827717662,\n -0.0040720468, 0.4505937099, -0.8086757660\n);\n\n// value.js OKLAB_TO_LMS_COEFF, row-major \u2192 WGSL columns.\nconst OKLAB_TO_LMS: mat3x3<f32> = mat3x3<f32>(\n 1.0, 1.0, 1.0,\n 0.3963377774, -0.1055613458, -0.0894841775,\n 0.2158037573, -0.0638541728, -1.2914855480\n);\n\n// value.js LMS_TO_LINEAR_SRGB, row-major \u2192 WGSL columns.\nconst LMS_TO_LINEAR_SRGB: mat3x3<f32> = mat3x3<f32>(\n 4.0767416621, -1.2684380046, -0.0041960863,\n -3.3077115913, 2.6097574011, -0.7034186147,\n 0.2309699292, -0.3413193965, 1.7076147010\n);\n\nfn cbrt3(v: vec3<f32>) -> vec3<f32> {\n return sign(v) * pow(abs(v), vec3<f32>(1.0 / 3.0));\n}\n\n// Gamma sRGB \u2192 raw OKLab (L, a, b). Mirrors value.js srgbToOKLab.\nfn srgbToOklab(c: vec3<f32>) -> vec3<f32> {\n let lin = srgbToLinear(c);\n let lms = LINEAR_SRGB_TO_LMS * lin;\n return LMS_TO_OKLAB * cbrt3(lms);\n}\n\n// Raw OKLab (L, a, b) \u2192 linear sRGB. Mirrors value.js oklabToLinearSRGB.\nfn oklabToLinearSrgb(lab: vec3<f32>) -> vec3<f32> {\n let lms_ = OKLAB_TO_LMS * lab;\n let lms = lms_ * lms_ * lms_;\n return LMS_TO_LINEAR_SRGB * lms;\n}\n\n// OKLab \u2192 OKLCh: H in RADIANS, folded to [0, 2pi). Mirrors value.js rawOklabToOklch.\nfn oklabToOklch(lab: vec3<f32>) -> vec3<f32> {\n let C = length(lab.yz);\n var H = atan2(lab.z, lab.y);\n if (H < 0.0) { H = H + 2.0 * PI; }\n return vec3<f32>(lab.x, C, H);\n}\n\n// OKLCh (H radians) \u2192 OKLab. Mirrors value.js rawOklchToOklab.\nfn oklchToOklab(lch: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));\n}\n\n// The sweeping bright-stripe band (transcribes flowField.ts waveBand): a soft two-sided\n// ridge over the normalized height \u2014 1 at the band center, falling to 0 at \u00B1width.\nfn waveBand(h: f32, center: f32, width: f32) -> f32 {\n let w = max(width, 1e-3);\n let d = abs(h - center);\n return 1.0 - smoothstep(0.0, w, d);\n}\n\n// The optional soft-disc globe mask \u2014 a slow Lissajous-drifting radial field (the\n// reference's two-sphere composition). OFF when uGlobeMask <= 0.5 (returns 1).\nfn globeMask(o: vec2<f32>, t: f32, on: f32) -> f32 {\n if (on <= 0.5) { return 1.0; }\n // a slow Lissajous center drift within the domain\n let cx = 0.35 * sin(t * 0.13);\n let cy = 0.28 * cos(t * 0.11);\n let d = length(o - vec2<f32>(cx, cy));\n // a soft disc of radius ~0.6 with a feathered edge\n return 1.0 - smoothstep(0.45, 0.75, d);\n}\n\n// Sample the multi-stop palette (linear-sRGB stops, OKLab mix). t in [0,1].\nfn samplePaletteLin(t: f32) -> vec3<f32> {\n let stopCount = u.ints.x;\n if (stopCount <= 1) { return u.palette[0].rgb; }\n let n = f32(stopCount);\n let ft = clamp(t, 0.0, 1.0) * (n - 1.0);\n let i0 = i32(floor(ft));\n let i1 = min(i0 + 1, stopCount - 1);\n let f = ft - f32(i0);\n let labA = LMS_TO_OKLAB * cbrt3(LINEAR_SRGB_TO_LMS * u.palette[i0].rgb);\n let labB = LMS_TO_OKLAB * cbrt3(LINEAR_SRGB_TO_LMS * u.palette[i1].rgb);\n return oklabToLinearSrgb(mix(labA, labB, f));\n}\n\nstruct VSOut {\n @builtin(position) pos: vec4<f32>,\n @location(0) local: vec2<f32>, // [-1,1] billboard-local coords for the soft circle\n @location(1) bright: f32, // band-driven brightness [0, ~1.6]\n};\n\n@vertex\nfn vs_main(\n @builtin(vertex_index) vi: u32,\n @builtin(instance_index) ii: u32,\n) -> VSOut {\n // Two-triangle quad corners in billboard-local space.\n var corners = array<vec2<f32>, 6>(\n vec2<f32>(-1.0, -1.0), vec2<f32>(1.0, -1.0), vec2<f32>(-1.0, 1.0),\n vec2<f32>(-1.0, 1.0), vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),\n );\n let local = corners[vi];\n\n let pr = particles[ii].data;\n let p = pr.xy;\n let h = pr.z;\n let dispMag = pr.w;\n let half = u.r0.w;\n\n // Brightness = base + band\u00B7contrast, masked by the optional globe (read at the live\n // position \u2014 close enough to the anchor at the sub-cell cap). The band SWEEPS as h\n // translates across the lattice.\n let band = waveBand(h, u.r2.x, u.r2.y);\n var bright = u.r0.z + band * u.r0.y;\n bright = bright * globeMask(p, u.r0.x, u.r2.z);\n\n // A subtle drift-driven size pulse (never a re-seed \u2014 the dot only breathes).\n let sizePulse = u.r1.y;\n let sizeWorld = u.r1.x * (1.0 + dispMag * sizePulse);\n\n // Position the quad at the dot in clip space. Domain [-half,half] \u2192 NDC [-1,1];\n // the quad half-extent rides sizeWorld (in domain units, aspect-corrected x).\n let aspect = u.r1.z;\n let ndc = p / half;\n let off = local * sizeWorld / half;\n let offX = off.x / max(aspect, 1e-4);\n\n var out: VSOut;\n out.pos = vec4<f32>(ndc.x + offX, ndc.y + off.y, 0.0, 1.0);\n out.local = local;\n out.bright = bright;\n return out;\n}\n\n@fragment\nfn fs_main(in: VSOut) -> @location(0) vec4<f32> {\n // Soft circle \u2014 radial smoothstep over the billboard-local radius.\n let r = length(in.local);\n let feather = 0.4;\n let mask = 1.0 - smoothstep(1.0 - feather, 1.0, r);\n if (mask < 0.002) { return vec4<f32>(0.0); }\n\n // The brightness lights the dot core; the palette tints it (the warm-cream identity).\n let bright = clamp(in.bright, 0.0, 1.6);\n let tone = clamp(bright, 0.0, 1.0);\n let lin = samplePaletteLin(tone) * bright;\n // A floor alpha so even an off-band dot stays a faint lattice point (the calm grid).\n let alpha = mask * clamp(bright * 0.8 + 0.12, 0.0, 1.0);\n let rgb = clamp(linearToSrgb(lin), vec3<f32>(0.0), vec3<f32>(1.0));\n // Premultiplied-alpha output.\n return vec4<f32>(rgb * alpha, alpha);\n}\n";
1
+ export declare const FLOW_FIELD_RENDER_WGSL = "\nconst PI: f32 = 3.141592653589793;\nconst TAU: f32 = 6.283185307179586;\nconst MAX_FLOW_STOPS: i32 = 4;\n\nstruct Particle {\n // field: (pos.x, pos.y, height, |disp|) flow: (pos.x, pos.y, speed, life)\n data: vec4<f32>,\n};\n\n// \u2500\u2500 Render uniforms (the typed-struct source-of-truth \u2014 see uniformBridgeWGPU.ts) \u2500\u2500\nstruct RenderUniforms {\n // r0: (uTime, uContrast, uBaseBright, uDomainHalf)\n r0: vec4<f32>,\n // r1: (uDotSize, uSizePulse, uAspect, uGridPitch)\n r1: vec4<f32>,\n // r2: (uWaveBandCenter, uWaveBandWidth, uGlobeMask, uMode) \u2014 uMode: 0=field, 1=flow\n r2: vec4<f32>,\n // ints: (uStopCount, uParticleCount, _pad, _pad)\n ints: vec4<i32>,\n // bg: (background.rgb, hasBackground)\n bg: vec4<f32>,\n // f0: (uSpeedGlow, uSpeedNorm, uShadowOffset, uStretchAmp) \u2014 the flow velocity-map levers\n f0: vec4<f32>,\n // each palette stop: linear-sRGB rgb + _pad\n palette: array<vec4<f32>, 4>,\n};\n\n@group(0) @binding(0) var<uniform> u: RenderUniforms;\n@group(0) @binding(1) var<storage, read> particles: array<Particle>;\n\n\nfn srgbToLinearCh(c: f32) -> f32 {\n if (c <= 0.04045) { return c / 12.92; }\n return pow((c + 0.055) / 1.055, 2.4);\n}\nfn srgbToLinear(c: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(srgbToLinearCh(c.r), srgbToLinearCh(c.g), srgbToLinearCh(c.b));\n}\n\nfn linearToSrgbCh(c: f32) -> f32 {\n if (c <= 0.0031308) { return c * 12.92; }\n return 1.055 * pow(c, 1.0 / 2.4) - 0.055;\n}\nfn linearToSrgb(c: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(linearToSrgbCh(c.r), linearToSrgbCh(c.g), linearToSrgbCh(c.b));\n}\n\n// value.js LINEAR_SRGB_TO_LMS, row-major \u2192 WGSL columns (= the transpose).\nconst LINEAR_SRGB_TO_LMS: mat3x3<f32> = mat3x3<f32>(\n 0.4122214708, 0.2119034982, 0.0883024619,\n 0.5363325363, 0.6806995451, 0.2817188376,\n 0.0514459929, 0.1073969566, 0.6299787005\n);\n\n// value.js srgbToOKLab's INLINE LMS\u2192OKLab coefficients, row-major \u2192 WGSL columns.\nconst LMS_TO_OKLAB: mat3x3<f32> = mat3x3<f32>(\n 0.2104542553, 1.9779984951, 0.0259040371,\n 0.7936177850, -2.4285922050, 0.7827717662,\n -0.0040720468, 0.4505937099, -0.8086757660\n);\n\n// value.js OKLAB_TO_LMS_COEFF, row-major \u2192 WGSL columns.\nconst OKLAB_TO_LMS: mat3x3<f32> = mat3x3<f32>(\n 1.0, 1.0, 1.0,\n 0.3963377774, -0.1055613458, -0.0894841775,\n 0.2158037573, -0.0638541728, -1.2914855480\n);\n\n// value.js LMS_TO_LINEAR_SRGB, row-major \u2192 WGSL columns.\nconst LMS_TO_LINEAR_SRGB: mat3x3<f32> = mat3x3<f32>(\n 4.0767416621, -1.2684380046, -0.0041960863,\n -3.3077115913, 2.6097574011, -0.7034186147,\n 0.2309699292, -0.3413193965, 1.7076147010\n);\n\nfn cbrt3(v: vec3<f32>) -> vec3<f32> {\n return sign(v) * pow(abs(v), vec3<f32>(1.0 / 3.0));\n}\n\n// Gamma sRGB \u2192 raw OKLab (L, a, b). Mirrors value.js srgbToOKLab.\nfn srgbToOklab(c: vec3<f32>) -> vec3<f32> {\n let lin = srgbToLinear(c);\n let lms = LINEAR_SRGB_TO_LMS * lin;\n return LMS_TO_OKLAB * cbrt3(lms);\n}\n\n// Raw OKLab (L, a, b) \u2192 linear sRGB. Mirrors value.js oklabToLinearSRGB.\nfn oklabToLinearSrgb(lab: vec3<f32>) -> vec3<f32> {\n let lms_ = OKLAB_TO_LMS * lab;\n let lms = lms_ * lms_ * lms_;\n return LMS_TO_LINEAR_SRGB * lms;\n}\n\n// OKLab \u2192 OKLCh: H in RADIANS, folded to [0, 2pi). Mirrors value.js rawOklabToOklch.\nfn oklabToOklch(lab: vec3<f32>) -> vec3<f32> {\n let C = length(lab.yz);\n var H = atan2(lab.z, lab.y);\n if (H < 0.0) { H = H + 2.0 * PI; }\n return vec3<f32>(lab.x, C, H);\n}\n\n// OKLCh (H radians) \u2192 OKLab. Mirrors value.js rawOklchToOklab.\nfn oklchToOklab(lch: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(lch.x, lch.y * cos(lch.z), lch.y * sin(lch.z));\n}\n\n// The sweeping bright-stripe band (transcribes flowField.ts waveBand): a soft two-sided\n// ridge over the normalized height \u2014 1 at the band center, falling to 0 at \u00B1width.\nfn waveBand(h: f32, center: f32, width: f32) -> f32 {\n let w = max(width, 1e-3);\n let d = abs(h - center);\n return 1.0 - smoothstep(0.0, w, d);\n}\n\n// The optional soft-disc globe mask \u2014 a slow Lissajous-drifting radial field (the\n// reference's two-sphere composition). OFF when uGlobeMask <= 0.5 (returns 1).\nfn globeMask(o: vec2<f32>, t: f32, on: f32) -> f32 {\n if (on <= 0.5) { return 1.0; }\n // a slow Lissajous center drift within the domain\n let cx = 0.35 * sin(t * 0.13);\n let cy = 0.28 * cos(t * 0.11);\n let d = length(o - vec2<f32>(cx, cy));\n // a soft disc of radius ~0.6 with a feathered edge\n return 1.0 - smoothstep(0.45, 0.75, d);\n}\n\n// Sample the multi-stop palette (linear-sRGB stops, OKLab mix). t in [0,1].\nfn samplePaletteLin(t: f32) -> vec3<f32> {\n let stopCount = u.ints.x;\n if (stopCount <= 1) { return u.palette[0].rgb; }\n let n = f32(stopCount);\n let ft = clamp(t, 0.0, 1.0) * (n - 1.0);\n let i0 = i32(floor(ft));\n let i1 = min(i0 + 1, stopCount - 1);\n let f = ft - f32(i0);\n let labA = LMS_TO_OKLAB * cbrt3(LINEAR_SRGB_TO_LMS * u.palette[i0].rgb);\n let labB = LMS_TO_OKLAB * cbrt3(LINEAR_SRGB_TO_LMS * u.palette[i1].rgb);\n return oklabToLinearSrgb(mix(labA, labB, f));\n}\n\nstruct VSOut {\n @builtin(position) pos: vec4<f32>,\n @location(0) local: vec2<f32>, // [-1,1] billboard-local coords for the soft circle\n @location(1) bright: f32, // brightness [0, ~1.6]\n @location(2) ramp: f32, // palette-ramp coord (field: tone, flow: speedNorm)\n @location(3) flowFade: f32, // flow life-fade [0,1] (field: 1)\n};\n\n@vertex\nfn vs_main(\n @builtin(vertex_index) vi: u32,\n @builtin(instance_index) ii: u32,\n) -> VSOut {\n // Two-triangle quad corners in billboard-local space.\n var corners = array<vec2<f32>, 6>(\n vec2<f32>(-1.0, -1.0), vec2<f32>(1.0, -1.0), vec2<f32>(-1.0, 1.0),\n vec2<f32>(-1.0, 1.0), vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),\n );\n let local = corners[vi];\n\n let pr = particles[ii].data;\n let p = pr.xy;\n let half = u.r0.w;\n let aspect = u.r1.z;\n let mode = i32(u.r2.w + 0.5);\n\n var bright: f32;\n var ramp: f32;\n var sizeWorld: f32;\n var flowFade: f32 = 1.0;\n\n if (mode == 1) {\n // \u2500\u2500 flow (AURORA CURRENT): speed\u2192hue, speed\u00B7life\u2192brightness, speed\u2192size bloom \u2500\u2500\n let speed = pr.z;\n let life = pr.w;\n let speedNorm = clamp(speed / max(u.f0.y, 1e-4), 0.0, 1.0);\n // life fades the mote over its last third (the trail's tail / overlapping-action).\n flowFade = clamp(life * 3.0, 0.0, 1.0);\n ramp = speedNorm;\n bright = (0.35 + speedNorm * u.f0.x) * flowFade;\n // a speed bloom (the cartoon \"more\" on WGPU \u2014 faster motes read as hot speed-cores) +\n // the \u221A\u03C6 stretch lever scales the bloom (the squash-stretch as an isotropic core here).\n sizeWorld = u.r1.x * (1.0 + speedNorm * (u.f0.w + 1.0));\n } else {\n // \u2500\u2500 field: the sweeping bright band over the anchored lattice (BC.W-VIZ-DOTFLOW) \u2500\u2500\n let h = pr.z;\n let dispMag = pr.w;\n let band = waveBand(h, u.r2.x, u.r2.y);\n bright = (u.r0.z + band * u.r0.y) * globeMask(p, u.r0.x, u.r2.z);\n ramp = clamp(bright, 0.0, 1.0);\n sizeWorld = u.r1.x * (1.0 + dispMag * u.r1.y);\n }\n\n // Position the quad at the dot in clip space. Domain [-half,half] \u2192 NDC [-1,1];\n // the quad half-extent rides sizeWorld (in domain units, aspect-corrected x).\n let ndc = p / half;\n let off = local * sizeWorld / half;\n let offX = off.x / max(aspect, 1e-4);\n\n var out: VSOut;\n out.pos = vec4<f32>(ndc.x + offX, ndc.y + off.y, 0.0, 1.0);\n out.local = local;\n out.bright = bright;\n out.ramp = ramp;\n out.flowFade = flowFade;\n return out;\n}\n\n@fragment\nfn fs_main(in: VSOut) -> @location(0) vec4<f32> {\n // Soft circle \u2014 radial smoothstep over the billboard-local radius.\n let r = length(in.local);\n let feather = 0.4;\n let mask = 1.0 - smoothstep(1.0 - feather, 1.0, r);\n if (mask < 0.002) { return vec4<f32>(0.0); }\n\n let mode = i32(u.r2.w + 0.5);\n let bright = clamp(in.bright, 0.0, 1.6);\n let lin = samplePaletteLin(in.ramp) * bright;\n let rgb = clamp(linearToSrgb(lin), vec3<f32>(0.0), vec3<f32>(1.0));\n\n if (mode == 1) {\n // flow: additive premultiplied \u2014 a soft glowing core, alpha rides speed\u00B7life.\n let coreAlpha = mask * mask; // a tighter hot core (less white wash \u2014 H2 cap)\n let a = coreAlpha * clamp(bright, 0.0, 1.0);\n return vec4<f32>(rgb * a, a);\n }\n // field: a floor alpha so even an off-band dot stays a faint lattice point.\n let alpha = mask * clamp(bright * 0.8 + 0.12, 0.0, 1.0);\n return vec4<f32>(rgb * alpha, alpha);\n}\n";
2
+ export declare const FLOW_FIELD_TRAIL_WGSL = "\nstruct TrailUniforms {\n // (decay, hasGround, time, _pad)\n p: vec4<f32>,\n // floor.rgb (linear-sRGB) + _pad\n floorC: vec4<f32>,\n // bloom.rgb (linear-sRGB) + _pad\n bloomC: vec4<f32>,\n};\n@group(0) @binding(0) var<uniform> u: TrailUniforms;\n@group(0) @binding(1) var samp: sampler;\n@group(0) @binding(2) var tex: texture_2d<f32>;\n\n\nfn srgbToLinearCh(c: f32) -> f32 {\n if (c <= 0.04045) { return c / 12.92; }\n return pow((c + 0.055) / 1.055, 2.4);\n}\nfn srgbToLinear(c: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(srgbToLinearCh(c.r), srgbToLinearCh(c.g), srgbToLinearCh(c.b));\n}\n\nfn linearToSrgbCh(c: f32) -> f32 {\n if (c <= 0.0031308) { return c * 12.92; }\n return 1.055 * pow(c, 1.0 / 2.4) - 0.055;\n}\nfn linearToSrgb(c: vec3<f32>) -> vec3<f32> {\n return vec3<f32>(linearToSrgbCh(c.r), linearToSrgbCh(c.g), linearToSrgbCh(c.b));\n}\n\nstruct FSQ { @builtin(position) pos: vec4<f32>, @location(0) uv: vec2<f32> };\n\n@vertex\nfn vs_fsq(@builtin(vertex_index) vi: u32) -> FSQ {\n var c = array<vec2<f32>, 3>(\n vec2<f32>(-1.0, -1.0), vec2<f32>(3.0, -1.0), vec2<f32>(-1.0, 3.0),\n );\n let p = c[vi];\n var out: FSQ;\n out.pos = vec4<f32>(p, 0.0, 1.0);\n out.uv = p * 0.5 + 0.5;\n return out;\n}\n\n@fragment\nfn fs_decay(in: FSQ) -> @location(0) vec4<f32> {\n let prev = textureSample(tex, samp, in.uv);\n return prev * u.p.x; // fade toward black\n}\n\n@fragment\nfn fs_present(in: FSQ) -> @location(0) vec4<f32> {\n let trail = textureSample(tex, samp, in.uv).rgb;\n let mapped = trail / (trail + vec3<f32>(0.85)); // Reinhard \u2014 hot cores, not white wash\n if (u.p.y < 0.5) {\n let rgb = clamp(linearToSrgb(mapped), vec3<f32>(0.0), vec3<f32>(1.0));\n let a = clamp(max(mapped.r, max(mapped.g, mapped.b)), 0.0, 1.0);\n return vec4<f32>(rgb * a, a);\n }\n let bloom = smoothstep(1.3, 0.0, distance(in.uv, vec2<f32>(0.12, 0.88)));\n let floorLin = u.floorC.rgb + u.bloomC.rgb * bloom * 0.5;\n let lin = floorLin + mapped;\n let rgb = clamp(linearToSrgb(lin), vec3<f32>(0.0), vec3<f32>(1.0));\n return vec4<f32>(rgb, 1.0);\n}\n";
@@ -20,6 +20,15 @@ export interface DotPointerState {
20
20
  push: number;
21
21
  /** The accel-burst brightness/scale bloom 0..1 (the flick term). */
22
22
  bloom: number;
23
+ /**
24
+ * The travel VELOCITY (normalized-host units/sec, the shared field's already-computed
25
+ * `pointer.velocity` — the dead-lever reclaim). Drives the anisotropic squash/stretch +
26
+ * the comet-tail wake direction. Mapped to NDC/frame deltas in the shader.
27
+ */
28
+ velX: number;
29
+ velY: number;
30
+ /** The flick-take ACCEL magnitude (`hypot(pointer.acceleration)`, also unused today). */
31
+ accelMag: number;
23
32
  }
24
33
  /** A fresh resting pointer state. */
25
34
  export declare function restingPointer(): DotPointerState;
@@ -39,7 +48,7 @@ export declare function createDotRenderScratch(): DotUniformScratch;
39
48
  * phyllotaxis on the GPU — the JS+GPU agree by construction).
40
49
  */
41
50
  export declare function buildDotsBuffer(config: DotMatrixConfig): Float32Array;
42
- /** The total dot instance count for a config (per-sphere × spheres). */
51
+ /** The total dot instance count for a config (per-sphere × spheres; plane is single). */
43
52
  export declare function dotInstanceCount(config: DotMatrixConfig): number;
44
53
  /**
45
54
  * Pack the per-frame render uniforms in place. `timeSec` drives the spin matrix + the
@@ -14,6 +14,13 @@ export interface DotSetupDeps {
14
14
  shouldContinue: () => boolean;
15
15
  /** The per-frame pointer hook — advances the shared field (the no-own-rAF discipline). */
16
16
  onFrame?: (timeSec: number) => void;
17
+ /**
18
+ * The live `prefers-reduced-motion` state (read lazily — the handle resolves AFTER the
19
+ * setup closure is built). When true the frame PINS uTime to a fixed √φ rung so the spin
20
+ * AND the per-dot twinkle `sin` are bit-identical across runs (the deterministic static
21
+ * frame — G9). Capture mode is already deterministic via `renderAt(fixedT)`.
22
+ */
23
+ getReducedMotion?: () => boolean;
17
24
  }
18
25
  /** Build the dot-matrix `setupWGPU(device, context, format)` callback. */
19
26
  export declare function createDotWGPUSetup(deps: DotSetupDeps): (device: GPUDevice, context: GPUCanvasContext, format: GPUTextureFormat) => WebGPUCanvasFrame;
@@ -5,6 +5,8 @@ export declare const MAX_DOTS = 4000;
5
5
  export declare const MAX_DOT_STOPS = 4;
6
6
  /** Pointer interaction mode — a repel pushes dots off the surface, attract pulls them in. */
7
7
  export type DotPointerMode = "repel" | "attract";
8
+ /** The dot layout register — a 3D phyllotaxis SPHERE (kept) or a flat 2D background PLANE. */
9
+ export type DotLayout = "sphere" | "plane";
8
10
  /**
9
11
  * The full author schema — the studio's `useConfiguratorState` model. Every field is a
10
12
  * tunable the demo configurator drives; the composable resolves it into the uniform table.
@@ -33,12 +35,24 @@ export interface DotMatrixConfig {
33
35
  palette: OklchStop[];
34
36
  /** The ground color (the demo sets near-black; default transparent). */
35
37
  background: OklchStop | "transparent";
38
+ /** The layout register — 3D sphere (kept preset) or a flat 2D background plane (the default). */
39
+ layout: DotLayout;
36
40
  /** Pointer parallax + repel + accel-burst (the §T7 interaction). */
37
41
  interactive: boolean;
38
42
  /** repel ↔ attract (the dimple direction). */
39
43
  pointerMode: DotPointerMode;
40
44
  /** The pointer-parallax depth (0–0.3; the screen-center tracks the cursor). */
41
45
  parallax: number;
46
+ /** The cursor-gravity well depth — how far a near dot is pulled toward the cursor (NDC). */
47
+ gravityStrength: number;
48
+ /** The cursor-gravity well radius — the falloff width (NDC; WIDE → many dots feel it). */
49
+ gravityRadius: number;
50
+ /**
51
+ * The resting per-dot TWINKLE rate (the living-constellation floor): each dot's opacity
52
+ * breathes on an `instance_index`-hashed phase at this rate (0 = a dead-still field; the
53
+ * demo lifts it). Frozen under PRM (the `sin` reads the pinned capture time).
54
+ */
55
+ twinkle: number;
42
56
  /** ONE static frame then park under `prefers-reduced-motion: reduce`. */
43
57
  respectReducedMotion: boolean;
44
58
  }