@mkbabb/glass-ui 4.2.0 → 5.0.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 (1377) hide show
  1. package/README.md +73 -159
  2. package/dist/CardAction-2uUvjMQK.js +285 -0
  3. package/dist/CollapsibleContent-DiHcB_HH.js +63 -0
  4. package/dist/CommandShortcut-fmdbsEJL.js +302 -0
  5. package/dist/ConfiguratorRow-BV6zPjTM.js +151 -0
  6. package/dist/DataTable-Bxya8nBn.js +518 -0
  7. package/dist/DialogContent-Bl4v10AC.js +192 -0
  8. package/dist/DialogFooter-C0v4Hz2F.js +168 -0
  9. package/dist/FadingScroll-BSRLqQCx.js +76 -0
  10. package/dist/FocusScope-BzKwhsBn.js +23 -0
  11. package/dist/IconChip-CwLmBJ_K.js +57 -0
  12. package/dist/IconTooltip-D9sbK-Mk.js +25 -0
  13. package/dist/Input-DKf-XwUM.js +57 -0
  14. package/dist/InstrumentChassis-Dss5Tjcm.js +65 -0
  15. package/dist/Label-C84TaQiw.js +36 -0
  16. package/dist/Notification-DQv2cOh9.js +43 -0
  17. package/dist/NumberFieldContent-BkE7xPS9.js +140 -0
  18. package/dist/PagerDots-BP6jh7z4.js +279 -0
  19. package/dist/PaperBackdrop-BYwE8_kg.js +31 -0
  20. package/dist/PopoverContent-DOtszFWK.js +251 -0
  21. package/dist/Progress-uWLyXE7J.js +308 -0
  22. package/dist/SelectGroup-BuEptUsa.js +31 -0
  23. package/dist/SelectScrollDownButton-CDtwaWkZ.js +261 -0
  24. package/dist/SelectSeparator-4QGephvr.js +49 -0
  25. package/dist/Separator-DqJ6PfOd.js +44 -0
  26. package/dist/Surface-BWRfwyn8.js +59 -0
  27. package/dist/Switch-BPBfhMU3.js +49 -0
  28. package/dist/Toaster-C_-WeU9W.js +281 -0
  29. package/dist/ToggleGroupItem-DNWx2aSW.js +175 -0
  30. package/dist/TooltipProvider-GtfYdSVf.js +110 -0
  31. package/dist/accent-tone-solve-CBw3L0cy.js +20 -0
  32. package/dist/animated-digit.d.ts +1 -1
  33. package/dist/animated-digit.js +5 -5
  34. package/dist/aurora.d.ts +1 -1
  35. package/dist/aurora.js +1395 -398
  36. package/dist/axes.d.ts +1 -0
  37. package/dist/axes.js +50 -0
  38. package/dist/badge-C0C-rTBu.js +80 -0
  39. package/dist/badge.d.ts +1 -1
  40. package/dist/badge.js +1 -1
  41. package/dist/blob-config.d.ts +5 -0
  42. package/dist/blob-config.js +2 -0
  43. package/dist/blob.d.ts +1 -0
  44. package/dist/blob.js +1582 -0
  45. package/dist/button-BXzhydVB.js +187 -0
  46. package/dist/button.d.ts +1 -1
  47. package/dist/button.js +1 -1
  48. package/dist/canvas.js +1 -1
  49. package/dist/card.d.ts +1 -1
  50. package/dist/card.js +1 -1
  51. package/dist/carousel.d.ts +2 -2
  52. package/dist/carousel.js +165 -248
  53. package/dist/chip.d.ts +10 -0
  54. package/dist/chip.js +81 -0
  55. package/dist/class-names-5jotTFzp.js +97 -0
  56. package/dist/coalesce-metric-B8o7zT9u.js +13 -0
  57. package/dist/collapsible.d.ts +1 -1
  58. package/dist/collapsible.js +1 -1
  59. package/dist/color-Bp5jmv4Z.js +86 -0
  60. package/dist/color-swatch.d.ts +1 -1
  61. package/dist/color-swatch.js +2 -2
  62. package/dist/color.js +3 -2
  63. package/dist/command.d.ts +1 -1
  64. package/dist/command.js +1 -1
  65. package/dist/completion-seal.d.ts +1 -1
  66. package/dist/completion-seal.js +76 -42
  67. package/dist/components/_shared/axes.d.ts +21 -0
  68. package/dist/components/_shared/class-names.d.ts +27 -0
  69. package/dist/components/_shared/index.d.ts +6 -0
  70. package/dist/components/_shared/menuItemVariants.d.ts +51 -0
  71. package/dist/components/_shared/useControlSize.d.ts +46 -0
  72. package/dist/components/_shared/useMotionAxis.d.ts +41 -0
  73. package/dist/components/_shared/useSurfaceAxis.d.ts +64 -0
  74. package/dist/components/alert/Alert.vue.d.ts +19 -0
  75. package/dist/components/alert/index.d.ts +8 -0
  76. package/dist/components/aurora/Aurora.vue.d.ts +104 -0
  77. package/dist/components/aurora/composables/atoms-fields.d.ts +43 -0
  78. package/dist/components/aurora/composables/atoms.d.ts +198 -0
  79. package/dist/components/aurora/composables/auroraImageSource.d.ts +44 -0
  80. package/dist/components/aurora/composables/color.d.ts +111 -0
  81. package/dist/components/aurora/composables/frameLoop.d.ts +66 -0
  82. package/dist/components/aurora/composables/glSetup.d.ts +29 -0
  83. package/dist/components/aurora/composables/runtime.d.ts +140 -0
  84. package/dist/components/aurora/composables/uniformBridge.d.ts +120 -0
  85. package/dist/components/aurora/composables/uniformBridgeWGPU.d.ts +60 -0
  86. package/dist/components/aurora/composables/uniformBridgeWGPUImage.d.ts +39 -0
  87. package/dist/components/aurora/composables/useAurora.d.ts +80 -0
  88. package/dist/components/aurora/composables/useCursorInteraction.d.ts +25 -0
  89. package/dist/components/aurora/composables/wgpuSetup.d.ts +50 -0
  90. package/dist/components/aurora/constants/presets.d.ts +326 -0
  91. package/dist/components/aurora/constants/shaders/aurora-image.frag.d.ts +3 -0
  92. package/dist/components/aurora/constants/shaders/aurora-image.wgsl.d.ts +3 -0
  93. package/dist/components/aurora/constants/shaders/aurora-mediums.wgsl.d.ts +1 -0
  94. package/dist/components/aurora/constants/shaders/aurora.wgsl.d.ts +1 -0
  95. package/dist/components/aurora/constants/shaders/brush.glsl.d.ts +1 -0
  96. package/dist/components/aurora/constants/shaders/flow.glsl.d.ts +1 -0
  97. package/dist/components/aurora/constants/shaders/mediums.glsl.d.ts +2 -0
  98. package/dist/components/aurora/constants/shaders/metal-medium.glsl.d.ts +2 -0
  99. package/dist/components/aurora/index.d.ts +13 -0
  100. package/dist/components/avatar/Avatar.vue.d.ts +23 -0
  101. package/dist/components/avatar/index.d.ts +9 -0
  102. package/dist/components/badge/Badge.vue.d.ts +41 -0
  103. package/dist/components/badge/index.d.ts +9 -0
  104. package/dist/components/blob/Blob.vue.d.ts +72 -0
  105. package/dist/components/blob/composables/satelliteKinematics.d.ts +20 -0
  106. package/dist/components/blob/composables/uploadBlobUniforms.d.ts +51 -0
  107. package/dist/components/blob/composables/useBlobPointer.d.ts +88 -0
  108. package/dist/components/blob/composables/useMetaballRenderer.d.ts +100 -0
  109. package/dist/components/blob/composables/wgpuSetup.d.ts +23 -0
  110. package/dist/components/blob/config.d.ts +3 -0
  111. package/dist/components/blob/constants.d.ts +82 -0
  112. package/dist/components/blob/index.d.ts +8 -0
  113. package/dist/components/blob/presets.d.ts +14 -0
  114. package/dist/components/blob/shaders/metaball-uniforms.glsl.d.ts +1 -0
  115. package/dist/components/blob/types.d.ts +256 -0
  116. package/dist/components/button/Button.vue.d.ts +31 -0
  117. package/dist/components/button/index.d.ts +9 -0
  118. package/dist/components/card/Card.vue.d.ts +180 -0
  119. package/dist/components/card/CardHeader.vue.d.ts +58 -0
  120. package/dist/components/card/ScrollCard.vue.d.ts +33 -0
  121. package/dist/components/carousel/Carousel.vue.d.ts +44 -0
  122. package/dist/components/carousel/CarouselContent.vue.d.ts +24 -0
  123. package/dist/components/carousel/CarouselNext.vue.d.ts +21 -0
  124. package/dist/components/carousel/CarouselPrevious.vue.d.ts +21 -0
  125. package/dist/components/carousel/GlassCarouselPager.vue.d.ts +50 -0
  126. package/dist/components/carousel/useCarousel.d.ts +21 -0
  127. package/dist/components/chip/Chip.vue.d.ts +20 -0
  128. package/dist/components/chip/chipVariants.d.ts +43 -0
  129. package/dist/components/chip/index.d.ts +3 -0
  130. package/dist/components/chip/types.d.ts +38 -0
  131. package/dist/components/combobox/Combobox.vue.d.ts +32 -0
  132. package/dist/components/combobox/ComboboxList.vue.d.ts +32 -0
  133. package/dist/components/command/index.d.ts +10 -0
  134. package/dist/components/completion-seal/CompletionSeal.vue.d.ts +28 -0
  135. package/dist/components/completion-seal/constants.d.ts +66 -0
  136. package/dist/components/configurator/Configurator.vue.d.ts +160 -0
  137. package/dist/components/configurator/ConfiguratorRow.vue.d.ts +96 -0
  138. package/dist/components/configurator/index.d.ts +6 -0
  139. package/dist/components/configurator/size.d.ts +26 -0
  140. package/dist/components/constellation/Constellation.vue.d.ts +34 -0
  141. package/dist/components/constellation/composables/constellationGLSetup.d.ts +10 -0
  142. package/dist/components/constellation/composables/constellationWGPUSetup.d.ts +19 -0
  143. package/dist/components/constellation/composables/useConstellation.d.ts +39 -0
  144. package/dist/components/constellation/constants.d.ts +97 -0
  145. package/dist/components/constellation/constellationTypes.d.ts +420 -0
  146. package/dist/components/dialog/DialogContent.vue.d.ts +115 -0
  147. package/dist/components/dock/DockBackgroundToggle.vue.d.ts +46 -0
  148. package/dist/components/dock/DockControl.vue.d.ts +73 -0
  149. package/dist/components/dock/DockCrossfade.vue.d.ts +50 -0
  150. package/dist/components/dock/DockLayer.vue.d.ts +33 -0
  151. package/dist/components/dock/DockLayerGroup.vue.d.ts +65 -0
  152. package/dist/components/dock/DockStack.vue.d.ts +73 -0
  153. package/dist/components/dock/DockTrigger.vue.d.ts +27 -0
  154. package/dist/components/dock/GlassDock.vue.d.ts +33 -0
  155. package/dist/components/dock/composables/dockContext.d.ts +48 -0
  156. package/dist/components/dock/composables/dockCrossfadeContext.d.ts +57 -0
  157. package/dist/components/dock/composables/dockMorphContext.d.ts +89 -0
  158. package/dist/components/dock/composables/index.d.ts +10 -0
  159. package/dist/components/dock/composables/useDockFisheye.d.ts +24 -0
  160. package/dist/components/dock/composables/useDockOverflowFit.d.ts +22 -0
  161. package/dist/components/dock/composables/useDockPopover.d.ts +68 -0
  162. package/dist/components/dock/composables/useDockSearch.d.ts +85 -0
  163. package/dist/components/dock/composables/useDockShellProps.d.ts +178 -0
  164. package/dist/components/dock/composables/useDockSpring.d.ts +71 -0
  165. package/dist/components/dock/composables/useDockTouchGate.d.ts +51 -0
  166. package/dist/components/dock/constants.d.ts +107 -0
  167. package/dist/components/dock/index.d.ts +19 -0
  168. package/dist/components/drawer/Drawer.vue.d.ts +85 -0
  169. package/dist/components/drawer/DrawerContent.vue.d.ts +40 -0
  170. package/dist/components/drawer/composables/useDrawerSnap.d.ts +24 -0
  171. package/dist/components/drawer/constants.d.ts +50 -0
  172. package/dist/components/drawer/index.d.ts +35 -0
  173. package/dist/components/dropdown-menu/DropdownMenu.vue.d.ts +24 -0
  174. package/dist/components/dropdown-menu/DropdownMenuContent.vue.d.ts +36 -0
  175. package/dist/components/dropdown-menu/index.d.ts +16 -0
  176. package/dist/components/dropdown-menu/useMenuTrigger.d.ts +14 -0
  177. package/dist/components/expandable-container/ExpandableContainer.vue.d.ts +71 -0
  178. package/dist/components/fourier-field/FourierField.vue.d.ts +54 -0
  179. package/dist/components/fourier-field/composables/fourierFieldGLSetup.d.ts +24 -0
  180. package/dist/components/fourier-field/composables/fourierFieldWGPUSetup.d.ts +31 -0
  181. package/dist/components/fourier-field/composables/uniformBridgeWGPU.d.ts +41 -0
  182. package/dist/components/fourier-field/composables/useFourierField.d.ts +55 -0
  183. package/dist/components/fourier-field/constants.d.ts +134 -0
  184. package/dist/components/fourier-field/index.d.ts +31 -0
  185. package/dist/components/fourier-field/math.d.ts +111 -0
  186. package/dist/components/fourier-field/shaders/fourier-field.glsl.d.ts +4 -0
  187. package/dist/components/fourier-field/shaders/fourier-field.render.wgsl.d.ts +1 -0
  188. package/dist/components/fourier-field/shaders/fourier-field.ribbon.d.ts +51 -0
  189. package/dist/components/handmark/composables/useHandMark.d.ts +99 -0
  190. package/dist/components/handmark/constants.d.ts +69 -0
  191. package/dist/components/handmark/geometry.d.ts +65 -0
  192. package/dist/components/handmark/noise.d.ts +30 -0
  193. package/dist/components/handmark/types.d.ts +70 -0
  194. package/dist/components/header-ribbon/HeaderRibbon.vue.d.ts +31 -0
  195. package/dist/components/header-ribbon/index.d.ts +2 -0
  196. package/dist/components/header-ribbon/types.d.ts +7 -0
  197. package/dist/components/index.d.ts +36 -0
  198. package/dist/components/liquid-grid/LiquidGrid.vue.d.ts +42 -0
  199. package/dist/components/liquid-grid/composables/liquidGrid.d.ts +113 -0
  200. package/dist/components/liquid-grid/composables/liquidGridGLSetup.d.ts +18 -0
  201. package/dist/components/liquid-grid/composables/liquidGridWGPUSetup.d.ts +21 -0
  202. package/dist/components/liquid-grid/composables/uniformBridgeWGPU.d.ts +16 -0
  203. package/dist/components/liquid-grid/composables/useLiquidGrid.d.ts +31 -0
  204. package/dist/components/liquid-grid/constants.d.ts +93 -0
  205. package/dist/components/liquid-grid/index.d.ts +5 -0
  206. package/dist/components/liquid-grid/shaders/liquid-grid.glsl.d.ts +4 -0
  207. package/dist/components/liquid-grid/shaders/liquid-grid.wgsl.d.ts +1 -0
  208. package/dist/components/metric-badge/MetricBadge.vue.d.ts +40 -0
  209. package/dist/components/metric-cell/MetricCell.vue.d.ts +108 -0
  210. package/dist/components/metric-stack/MetricRow.vue.d.ts +120 -0
  211. package/dist/components/notification/Notification.vue.d.ts +16 -0
  212. package/dist/components/pager-dots/composables/usePagerWorm.d.ts +26 -0
  213. package/dist/components/pager-dots/constants.d.ts +15 -0
  214. package/dist/components/paper-backdrop/PaperBackdrop.vue.d.ts +21 -0
  215. package/dist/components/popover/Popover.vue.d.ts +54 -0
  216. package/dist/components/popover/PopoverContent.vue.d.ts +53 -0
  217. package/dist/components/popover/PopoverTrigger.vue.d.ts +16 -0
  218. package/dist/components/popover/popoverContext.d.ts +17 -0
  219. package/dist/components/progress/Progress.vue.d.ts +54 -0
  220. package/dist/components/progress/ProgressLiquid.vue.d.ts +21 -0
  221. package/dist/components/progress/index.d.ts +6 -0
  222. package/dist/components/scroll-progress-rim/ScrollProgressRim.vue.d.ts +19 -0
  223. package/dist/components/scroll-progress-rim/index.d.ts +3 -0
  224. package/dist/components/scroll-progress-rim/types.d.ts +2 -0
  225. package/dist/components/search/FuzzySearch.vue.d.ts +22 -0
  226. package/dist/components/search/SearchBar.vue.d.ts +38 -0
  227. package/dist/components/search/searchVariants.d.ts +19 -0
  228. package/dist/components/select/SelectContent.vue.d.ts +42 -0
  229. package/dist/components/slider/Slider.vue.d.ts +40 -0
  230. package/dist/components/slider/index.d.ts +46 -0
  231. package/dist/components/sortable-list/SortableHandle.vue.d.ts +19 -0
  232. package/dist/components/sortable-list/SortableItem.vue.d.ts +22 -0
  233. package/dist/components/sortable-list/SortableList.vue.d.ts +39 -0
  234. package/dist/components/sortable-list/composables/dragController.d.ts +29 -0
  235. package/dist/components/sortable-list/composables/types.d.ts +50 -0
  236. package/dist/components/sortable-list/composables/useSortable.d.ts +5 -0
  237. package/dist/components/sortable-list/context.d.ts +11 -0
  238. package/dist/components/sortable-list/index.d.ts +4 -0
  239. package/dist/components/split-chars/SplitChars.vue.d.ts +53 -0
  240. package/dist/components/stacked-icons/types.d.ts +19 -0
  241. package/dist/components/surface/Surface.vue.d.ts +45 -0
  242. package/dist/components/surface/index.d.ts +2 -0
  243. package/dist/components/tabs/SegmentedTabs.vue.d.ts +101 -0
  244. package/dist/components/tabs/composables/useEyeglassLive.d.ts +17 -0
  245. package/dist/components/tabs/composables/useTabDragMorph.d.ts +42 -0
  246. package/dist/components/tabs/composables/useTabResponsive.d.ts +43 -0
  247. package/dist/components/tabs/composables/useTabRovingFocus.d.ts +51 -0
  248. package/dist/components/tabs/constants.d.ts +1 -0
  249. package/dist/components/timeline/ContinuousMarkers.vue.d.ts +49 -0
  250. package/dist/components/timeline/GlassTimeline.vue.d.ts +114 -0
  251. package/dist/components/toast/Toast.vue.d.ts +107 -0
  252. package/dist/components/toast/index.d.ts +9 -0
  253. package/dist/components/toast/use-toast.d.ts +182 -0
  254. package/dist/components/toggle/Toggle.vue.d.ts +29 -0
  255. package/dist/components/toggle/index.d.ts +26 -0
  256. package/dist/components/watercolor-dot/prng.d.ts +5 -0
  257. package/dist/components/watercolor-dot/useWatercolorBlob.d.ts +31 -0
  258. package/dist/composables/color/accent-tone-solve.d.ts +11 -0
  259. package/dist/composables/color/index.d.ts +18 -1
  260. package/dist/composables/color/useAccentTone.d.ts +6 -8
  261. package/dist/composables/dom/useUserInvalidAria.d.ts +7 -11
  262. package/dist/composables/glass/ambientHueHistogram.d.ts +27 -0
  263. package/dist/composables/glass/backdropLuminanceSample.d.ts +56 -0
  264. package/dist/composables/glass/backdropSampleMath.d.ts +5 -0
  265. package/dist/composables/glass/textureUpload.d.ts +91 -0
  266. package/dist/composables/glass/useGlassBackdropLuminance.d.ts +27 -1
  267. package/dist/composables/glass/useSpecularPointer.d.ts +23 -4
  268. package/dist/composables/glass/useSpecularTracking.d.ts +1 -1
  269. package/dist/composables/glass/wave/waveField.d.ts +22 -1
  270. package/dist/composables/glass/wave/waveField.glsl.d.ts +1 -1
  271. package/dist/composables/glass/wave/waveField.wgsl.d.ts +1 -1
  272. package/dist/composables/glass/webgl/backingSize.d.ts +44 -0
  273. package/dist/composables/glass/webgl/createCanvasLifecycle.d.ts +36 -55
  274. package/dist/composables/glass/webgl/shaders/glass-refract.glsl.d.ts +36 -0
  275. package/dist/composables/glass/webgl/useWebGLCanvas.d.ts +1 -1
  276. package/dist/composables/glass/webgl/visibility.d.ts +42 -0
  277. package/dist/composables/glass/webgpu/useGpuSubstrate.d.ts +5 -4
  278. package/dist/composables/glass/webgpu/useWebGPUCanvas.d.ts +3 -111
  279. package/dist/composables/glass/webgpu/webgpuCanvasTypes.d.ts +96 -0
  280. package/dist/composables/glass/webgpu/webgpuDevice.d.ts +30 -0
  281. package/dist/composables/index.d.ts +1 -2
  282. package/dist/composables/motion/bloomUpField.d.ts +29 -0
  283. package/dist/composables/motion/core/index.d.ts +6 -2
  284. package/dist/composables/motion/gooBarbellGeometry.d.ts +79 -0
  285. package/dist/composables/motion/index.d.ts +1 -1
  286. package/dist/composables/motion/morphSignatures.d.ts +88 -0
  287. package/dist/composables/motion/motionTempo.d.ts +9 -0
  288. package/dist/composables/motion/pointerFieldMappings.d.ts +161 -0
  289. package/dist/composables/motion/springPresets.d.ts +17 -23
  290. package/dist/composables/motion/useDockCtaReceive.d.ts +32 -39
  291. package/dist/composables/motion/useElementMorph.d.ts +99 -0
  292. package/dist/composables/motion/useLeadTrail.d.ts +69 -0
  293. package/dist/composables/motion/useLiquidPress.d.ts +9 -0
  294. package/dist/composables/motion/useLiquidReveal.d.ts +15 -29
  295. package/dist/composables/motion/usePointerVelocityField.d.ts +59 -0
  296. package/dist/composables/motion/useRoutePointer.d.ts +41 -0
  297. package/dist/composables/motion/useSelectionGroup.d.ts +83 -0
  298. package/dist/composables/motion/useSelectionIndicator.d.ts +90 -0
  299. package/dist/composables/motion/useSpringPress.d.ts +5 -5
  300. package/dist/configurator.d.ts +1 -1
  301. package/dist/configurator.js +3 -3
  302. package/dist/constellation.d.ts +1 -1
  303. package/dist/constellation.js +292 -255
  304. package/dist/controls.d.ts +1 -1
  305. package/dist/controls.js +5 -5
  306. package/dist/createCanvasLifecycle-DlrcvWbb.js +209 -0
  307. package/dist/dark.js +1 -1
  308. package/dist/data-table.d.ts +1 -1
  309. package/dist/data-table.js +1 -1
  310. package/dist/deck.d.ts +1 -1
  311. package/dist/deck.js +6 -6
  312. package/dist/dialog.d.ts +1 -1
  313. package/dist/dialog.js +3 -4
  314. package/dist/dock.d.ts +1 -1
  315. package/dist/dock.js +1038 -1591
  316. package/dist/dockContext-d-WpJN2Z.js +13 -0
  317. package/dist/dom.js +6 -6
  318. package/dist/drawer.d.ts +1 -1
  319. package/dist/drawer.js +169 -161
  320. package/dist/dropdown-menu-DaGlVdp9.js +421 -0
  321. package/dist/dropdown-menu.d.ts +1 -1
  322. package/dist/dropdown-menu.js +1 -1
  323. package/dist/easing.d.ts +10 -1
  324. package/dist/easing.js +148 -148
  325. package/dist/expandable-container.d.ts +1 -1
  326. package/dist/expandable-container.js +85 -66
  327. package/dist/fading-scroll.d.ts +1 -1
  328. package/dist/fading-scroll.js +1 -1
  329. package/dist/focus-scope.d.ts +1 -1
  330. package/dist/focus-scope.js +2 -23
  331. package/dist/forms.d.ts +4 -3
  332. package/dist/forms.js +75 -66
  333. package/dist/fourier-field.d.ts +1 -1
  334. package/dist/fourier-field.js +608 -554
  335. package/dist/fourier-math.d.ts +7 -1
  336. package/dist/fourier-math.js +2 -2
  337. package/dist/glass-ui.css +1 -1
  338. package/dist/glass-ui.js +192 -340
  339. package/dist/handmark.d.ts +3 -1
  340. package/dist/handmark.js +179 -161
  341. package/dist/header-ribbon.d.ts +1 -1
  342. package/dist/header-ribbon.js +7 -7
  343. package/dist/icon-chip.d.ts +1 -1
  344. package/dist/icon-chip.js +1 -1
  345. package/dist/icon-tooltip.d.ts +1 -1
  346. package/dist/icon-tooltip.js +1 -1
  347. package/dist/index.d.ts +42 -45
  348. package/dist/infinite-scroll.d.ts +2 -2
  349. package/dist/infinite-scroll.js +2 -2
  350. package/dist/instrument-chassis.d.ts +1 -1
  351. package/dist/instrument-chassis.js +1 -1
  352. package/dist/keyboard.js +1 -1
  353. package/dist/label.d.ts +1 -1
  354. package/dist/label.js +1 -1
  355. package/dist/labeled-field.d.ts +1 -1
  356. package/dist/labeled-field.js +13 -13
  357. package/dist/liquid-grid.d.ts +1 -0
  358. package/dist/liquid-grid.js +1064 -0
  359. package/dist/math-CIEcwsYi.js +112 -0
  360. package/dist/menuItemVariants-DbO-Fr74.js +36 -0
  361. package/dist/metric-badge.d.ts +1 -1
  362. package/dist/metric-badge.js +79 -2
  363. package/dist/metric-cell.d.ts +1 -1
  364. package/dist/metric-cell.js +9 -9
  365. package/dist/metric-stack.d.ts +1 -1
  366. package/dist/metric-stack.js +23 -23
  367. package/dist/motion-core.js +48 -42
  368. package/dist/motion-curves.d.ts +20 -0
  369. package/dist/motion-curves.js +2 -2
  370. package/dist/motion.js +94 -210
  371. package/dist/motionTempo-CMS5b0Vu.js +7 -0
  372. package/dist/notification.d.ts +1 -1
  373. package/dist/notification.js +1 -1
  374. package/dist/number-field.d.ts +1 -1
  375. package/dist/number-field.js +1 -1
  376. package/dist/pager-dots.d.ts +1 -1
  377. package/dist/pager-dots.js +1 -1
  378. package/dist/paper-backdrop.d.ts +1 -1
  379. package/dist/paper-backdrop.js +1 -1
  380. package/dist/pointerFieldMappings-4VtmkOWv.js +65 -0
  381. package/dist/popover.d.ts +1 -1
  382. package/dist/popover.js +1 -1
  383. package/dist/presets-B07HzyKd.js +95 -0
  384. package/dist/prng-B0PLRmR6.js +15 -0
  385. package/dist/progress.d.ts +1 -1
  386. package/dist/progress.js +2 -2
  387. package/dist/pulse.d.ts +1 -1
  388. package/dist/pulse.js +4 -4
  389. package/dist/reactive.js +2 -2
  390. package/dist/resolveCanvasColor-B3L-akX0.js +93 -0
  391. package/dist/scroll-progress-rim.d.ts +1 -0
  392. package/dist/scroll-progress-rim.js +61 -0
  393. package/dist/search.d.ts +1 -1
  394. package/dist/search.js +123 -123
  395. package/dist/select.d.ts +1 -1
  396. package/dist/select.js +3 -3
  397. package/dist/separator.d.ts +1 -1
  398. package/dist/separator.js +1 -1
  399. package/dist/sidebar.js +1 -1
  400. package/dist/slider-Cxuj_W_H.js +151 -0
  401. package/dist/slider.d.ts +1 -1
  402. package/dist/slider.js +1 -1
  403. package/dist/sortable-list.d.ts +1 -1
  404. package/dist/sortable-list.js +384 -59
  405. package/dist/spa-view.d.ts +1 -1
  406. package/dist/spa-view.js +1 -1
  407. package/dist/springPresets-h5VKJQqG.js +58 -0
  408. package/dist/stacked-icons.d.ts +1 -1
  409. package/dist/stacked-icons.js +6 -6
  410. package/dist/status-dot.d.ts +1 -1
  411. package/dist/status-dot.js +2 -2
  412. package/dist/styles/animations.css +1 -409
  413. package/dist/styles/card-scroll.css +1 -0
  414. package/dist/styles/cards.css +1 -448
  415. package/dist/styles/completion-seal.css +1 -131
  416. package/dist/styles/components.css +1 -45
  417. package/dist/styles/configurator.css +1 -297
  418. package/dist/styles/dialog-placement.css +1 -0
  419. package/dist/styles/dock/adaptive-legibility.css +1 -119
  420. package/dist/styles/dock/crossfade.css +1 -0
  421. package/dist/styles/dock/cta-seat.css +1 -87
  422. package/dist/styles/dock/density.css +1 -455
  423. package/dist/styles/dock/dock.css +1 -0
  424. package/dist/styles/dock/fisheye.css +1 -0
  425. package/dist/styles/dock/layer-group.css +1 -333
  426. package/dist/styles/dock/layers.css +1 -413
  427. package/dist/styles/dock/morph.css +1 -430
  428. package/dist/styles/dock/overflow.css +1 -292
  429. package/dist/styles/dock/popover.css +1 -0
  430. package/dist/styles/dock/search.css +1 -68
  431. package/dist/styles/dock/section.css +1 -59
  432. package/dist/styles/dock/shape.css +1 -250
  433. package/dist/styles/dock/shell-regions.css +1 -0
  434. package/dist/styles/dock/shell.css +1 -498
  435. package/dist/styles/dock-controls/dark-mode-toggle.css +1 -122
  436. package/dist/styles/dock-controls/icon-button.css +1 -189
  437. package/dist/styles/dock-controls/tab-button.css +1 -143
  438. package/dist/styles/dock-controls/touch-floor.css +1 -94
  439. package/dist/styles/dock-controls/triggers.css +1 -157
  440. package/dist/styles/dock-controls.css +1 -92
  441. package/dist/styles/dock.css +1 -173
  442. package/dist/styles/draw-in.css +1 -0
  443. package/dist/styles/drawer.css +1 -406
  444. package/dist/styles/feedback-tone.css +1 -104
  445. package/dist/styles/fonts.css +1 -143
  446. package/dist/styles/glass/a11y-fallback.css +1 -245
  447. package/dist/styles/glass/accent-tone.css +1 -66
  448. package/dist/styles/glass/control-surfaces.css +1 -167
  449. package/dist/styles/glass/deep.css +1 -44
  450. package/dist/styles/glass/defined.css +1 -0
  451. package/dist/styles/glass/glass-atom.css +1 -244
  452. package/dist/styles/glass/glass-capsule.css +1 -143
  453. package/dist/styles/glass/glass-chip.css +1 -215
  454. package/dist/styles/glass/grain-overlay.css +1 -0
  455. package/dist/styles/glass/ladder-undershadow.css +1 -0
  456. package/dist/styles/glass/ladder.css +1 -489
  457. package/dist/styles/glass/liquid-enter.css +1 -252
  458. package/dist/styles/glass/liquid-fill.css +1 -0
  459. package/dist/styles/glass/material.css +1 -370
  460. package/dist/styles/glass/progress-rail.css +1 -78
  461. package/dist/styles/glass/reveal.css +1 -156
  462. package/dist/styles/glass/rim.css +1 -122
  463. package/dist/styles/glass/squircle.css +1 -66
  464. package/dist/styles/glass/surface-axis.css +1 -113
  465. package/dist/styles/glass/surfaces-pager.css +1 -0
  466. package/dist/styles/glass/surfaces.css +1 -411
  467. package/dist/styles/glass-refract.css +1 -114
  468. package/dist/styles/glass-specular-track.css +1 -74
  469. package/dist/styles/glass.css +1 -77
  470. package/dist/styles/icon-chip.css +1 -256
  471. package/dist/styles/index.css +1 -260
  472. package/dist/styles/instrument-chassis.css +1 -453
  473. package/dist/styles/menu.css +1 -127
  474. package/dist/styles/paper.css +1 -284
  475. package/dist/styles/scroll-choreography.css +1 -357
  476. package/dist/styles/scroll-chrome.css +1 -123
  477. package/dist/styles/scroll-driven.css +1 -110
  478. package/dist/styles/scroll-progress-rim.css +1 -0
  479. package/dist/styles/segmented-tabs.css +1 -447
  480. package/dist/styles/select.css +1 -201
  481. package/dist/styles/tabs/segmented-tabs-drag.css +1 -0
  482. package/dist/styles/theme/bridges.css +1 -380
  483. package/dist/styles/theme/dark.css +1 -7
  484. package/dist/styles/theme/literals.css +1 -103
  485. package/dist/styles/theme/radius.css +1 -117
  486. package/dist/styles/theme.css +1 -33
  487. package/dist/styles/tokens/color-radius.css +1 -297
  488. package/dist/styles/tokens/dark-arm-glass.css +1 -0
  489. package/dist/styles/tokens/dark-arm.css +1 -462
  490. package/dist/styles/tokens/glass-deep.css +1 -104
  491. package/dist/styles/tokens/glass-fx.css +1 -454
  492. package/dist/styles/tokens/glass.css +1 -412
  493. package/dist/styles/tokens/light-dark.css +1 -200
  494. package/dist/styles/tokens/motion-registers.css +1 -0
  495. package/dist/styles/tokens/offsets.css +1 -143
  496. package/dist/styles/tokens/on-glass-fg.css +1 -39
  497. package/dist/styles/tokens/property-regs-specular.css +1 -0
  498. package/dist/styles/tokens/property-regs.css +1 -566
  499. package/dist/styles/tokens/scale-paper.css +1 -493
  500. package/dist/styles/tokens/scheme-motion.css +1 -363
  501. package/dist/styles/tokens/scheme-spring.css +1 -239
  502. package/dist/styles/tokens/scroll-tokens.css +1 -123
  503. package/dist/styles/tokens/shadow.css +1 -226
  504. package/dist/styles/tokens/sizing-config.css +1 -110
  505. package/dist/styles/tokens/sizing.css +1 -450
  506. package/dist/styles/tokens.css +1 -52
  507. package/dist/styles/transitions.css +1 -263
  508. package/dist/styles/typography/scale.css +1 -153
  509. package/dist/styles/typography/semantic.css +1 -233
  510. package/dist/styles/typography/utilities.css +1 -174
  511. package/dist/styles/typography.css +1 -46
  512. package/dist/styles/utilities/a11y-overrides.css +1 -184
  513. package/dist/styles/utilities/animate.css +0 -29
  514. package/dist/styles/utilities/base-misc.css +1 -307
  515. package/dist/styles/utilities/base.css +1 -327
  516. package/dist/styles/utilities/btn.css +1 -301
  517. package/dist/styles/utilities/components.css +1 -342
  518. package/dist/styles/utilities/metal.css +1 -215
  519. package/dist/styles/utilities.css +1 -26
  520. package/dist/styles/view-transition.css +1 -67
  521. package/dist/styles/viz-reveal.css +1 -0
  522. package/dist/surface.d.ts +1 -0
  523. package/dist/surface.js +3 -0
  524. package/dist/switch.d.ts +1 -1
  525. package/dist/switch.js +1 -1
  526. package/dist/tabs.d.ts +1 -1
  527. package/dist/tabs.js +189 -249
  528. package/dist/timeline.d.ts +1 -1
  529. package/dist/timeline.js +199 -183
  530. package/dist/toast.d.ts +1 -1
  531. package/dist/toast.js +1 -1
  532. package/dist/toggle-group.d.ts +1 -1
  533. package/dist/toggle-group.js +1 -1
  534. package/dist/tooltip.d.ts +1 -1
  535. package/dist/tooltip.js +1 -1
  536. package/dist/typewriter.d.ts +1 -1
  537. package/dist/typewriter.js +8 -8
  538. package/dist/useAccentTone-D25DxviG.js +23 -0
  539. package/dist/useAnimatedNumber-2XC4aRB6.js +40 -0
  540. package/dist/useConfiguratorState-Dq35N_7t.js +167 -0
  541. package/dist/useControlSize-DJwe-7ZQ.js +9 -0
  542. package/dist/useDockCtaReceive-BgMmeINo.js +161 -0
  543. package/dist/useDocumentVisibility-CpJGUgcJ.js +17 -0
  544. package/dist/useDragMorph-65ihHePq.js +93 -0
  545. package/dist/useFuzzySearch-KslRxiJY.js +177 -0
  546. package/dist/useGooMorph-CU1pwuC6.js +268 -0
  547. package/dist/useGpuSubstrate-DcY584kE.js +347 -0
  548. package/dist/useIntersectionPause-Cmt5Tnv9.js +39 -0
  549. package/dist/useKeyboardShortcuts-ynVmNFo3.js +104 -0
  550. package/dist/useLeadTrail-DOH4XkL1.js +74 -0
  551. package/dist/useLiquidPress-BXNHydZh.js +40 -0
  552. package/dist/useMotionAxis-DCCXMC-i.js +20 -0
  553. package/dist/usePointerVelocityField-CwXyeW0Z.js +122 -0
  554. package/dist/useRAFLoop-CvOo_kgb.js +109 -0
  555. package/dist/useRoutePointer-DL7I0gY4.js +52 -0
  556. package/dist/useScrollProgress-C-yImzhU.js +35 -0
  557. package/dist/useSelectionGroup-Btpf24aY.js +215 -0
  558. package/dist/useSpring-BBSKFx_0.js +41 -0
  559. package/dist/useSpringMount-CNvvgGiC.js +71 -0
  560. package/dist/useSpringPress-BypV_KO-.js +36 -0
  561. package/dist/useSurfaceAxis-DudiZVOR.js +10 -0
  562. package/dist/useTabRovingFocus-CG1H1k1J.js +143 -0
  563. package/dist/useTouchGate-BlegwvwL.js +84 -0
  564. package/dist/useUserInvalidAria-Bkruei7M.js +25 -0
  565. package/dist/watercolor-dot.d.ts +1 -1
  566. package/dist/watercolor-dot.js +52 -50
  567. package/package.json +386 -827
  568. package/src/styles/animations.css +82 -23
  569. package/src/styles/card-scroll.css +189 -0
  570. package/src/styles/cards.css +45 -6
  571. package/src/styles/completion-seal.css +75 -1
  572. package/src/styles/configurator.css +63 -1
  573. package/src/styles/dialog-placement.css +68 -0
  574. package/src/styles/dock/adaptive-legibility.css +1 -1
  575. package/src/styles/dock/crossfade.css +139 -0
  576. package/src/styles/dock/density.css +16 -13
  577. package/src/styles/dock/dock.css +199 -0
  578. package/src/styles/dock/fisheye.css +81 -0
  579. package/src/styles/dock/layer-group.css +37 -41
  580. package/src/styles/dock/layers.css +46 -21
  581. package/src/styles/dock/morph.css +41 -16
  582. package/src/styles/dock/overflow.css +107 -67
  583. package/src/styles/dock/popover.css +249 -0
  584. package/src/styles/dock/shape.css +77 -139
  585. package/src/styles/dock/shell-regions.css +73 -0
  586. package/src/styles/dock/shell.css +159 -157
  587. package/src/styles/dock-controls/dark-mode-toggle.css +3 -2
  588. package/src/styles/dock-controls/icon-button.css +43 -11
  589. package/src/styles/dock-controls/tab-button.css +2 -2
  590. package/src/styles/dock-controls/touch-floor.css +25 -0
  591. package/src/styles/dock.css +60 -14
  592. package/src/styles/draw-in.css +89 -0
  593. package/src/styles/drawer.css +77 -41
  594. package/src/styles/glass/a11y-fallback.css +19 -76
  595. package/src/styles/glass/control-surfaces.css +20 -16
  596. package/src/styles/glass/deep.css +74 -4
  597. package/src/styles/glass/defined.css +88 -0
  598. package/src/styles/glass/glass-atom.css +23 -20
  599. package/src/styles/glass/glass-capsule.css +32 -0
  600. package/src/styles/glass/glass-chip.css +13 -17
  601. package/src/styles/glass/grain-overlay.css +79 -0
  602. package/src/styles/glass/ladder-undershadow.css +61 -0
  603. package/src/styles/glass/ladder.css +96 -133
  604. package/src/styles/glass/liquid-enter.css +12 -24
  605. package/src/styles/glass/liquid-fill.css +65 -0
  606. package/src/styles/glass/material.css +134 -10
  607. package/src/styles/glass/reveal.css +197 -20
  608. package/src/styles/glass/squircle.css +18 -26
  609. package/src/styles/glass/surface-axis.css +24 -1
  610. package/src/styles/glass/surfaces-pager.css +79 -0
  611. package/src/styles/glass/surfaces.css +121 -98
  612. package/src/styles/glass.css +34 -1
  613. package/src/styles/index.css +54 -26
  614. package/src/styles/menu.css +66 -6
  615. package/src/styles/paper.css +105 -202
  616. package/src/styles/scroll-choreography.css +29 -92
  617. package/src/styles/scroll-driven.css +18 -5
  618. package/src/styles/scroll-progress-rim.css +87 -0
  619. package/src/styles/segmented-tabs.css +67 -88
  620. package/src/styles/tabs/segmented-tabs-drag.css +200 -0
  621. package/src/styles/theme/bridges.css +8 -2
  622. package/src/styles/theme/literals.css +2 -1
  623. package/src/styles/theme/radius.css +43 -12
  624. package/src/styles/tokens/color-radius.css +15 -4
  625. package/src/styles/tokens/dark-arm-glass.css +55 -0
  626. package/src/styles/tokens/dark-arm.css +62 -69
  627. package/src/styles/tokens/glass-deep.css +102 -80
  628. package/src/styles/tokens/glass-fx.css +35 -5
  629. package/src/styles/tokens/glass.css +144 -78
  630. package/src/styles/tokens/light-dark.css +20 -4
  631. package/src/styles/tokens/motion-registers.css +93 -0
  632. package/src/styles/tokens/property-regs-specular.css +160 -0
  633. package/src/styles/tokens/property-regs.css +67 -186
  634. package/src/styles/tokens/scale-paper.css +6 -3
  635. package/src/styles/tokens/scheme-motion.css +59 -0
  636. package/src/styles/tokens/scheme-spring.css +146 -93
  637. package/src/styles/tokens/scroll-tokens.css +25 -11
  638. package/src/styles/tokens/shadow.css +28 -22
  639. package/src/styles/tokens/sizing.css +62 -7
  640. package/src/styles/tokens.css +16 -0
  641. package/src/styles/transitions.css +108 -143
  642. package/src/styles/typography/scale.css +10 -0
  643. package/src/styles/typography/semantic.css +5 -5
  644. package/src/styles/typography/utilities.css +25 -2
  645. package/src/styles/utilities/a11y-overrides.css +2 -2
  646. package/src/styles/utilities/base.css +13 -3
  647. package/src/styles/utilities/btn.css +29 -3
  648. package/src/styles/utilities/components.css +16 -21
  649. package/src/styles/utilities/metal.css +86 -29
  650. package/src/styles/viz-reveal.css +63 -0
  651. package/dist/CardAction-DlVP2evz.js +0 -272
  652. package/dist/CollapsibleContent-D7UNsXQr.js +0 -63
  653. package/dist/CommandShortcut-By-VQcLO.js +0 -302
  654. package/dist/ConfiguratorRow-YMXdINHx.js +0 -143
  655. package/dist/ContextMenuContent-CMWn6huB.js +0 -90
  656. package/dist/ContextMenuSubContent-DvwWCUc0.js +0 -245
  657. package/dist/DataTable-C4tG3eIJ.js +0 -512
  658. package/dist/DialogContent-D8U9ZfWS.js +0 -121
  659. package/dist/DialogFooter-DoLy0ewI.js +0 -80
  660. package/dist/DialogScrollContent-BMekN7gq.js +0 -93
  661. package/dist/FadingScroll-P8B30rAD.js +0 -76
  662. package/dist/HoverCardContent-DAmGYglo.js +0 -88
  663. package/dist/HoverPopover-DYpBOzzF.js +0 -96
  664. package/dist/IconChip-CQa7XZYc.js +0 -57
  665. package/dist/IconTooltip-_df8M3xm.js +0 -25
  666. package/dist/Input-CyU4_hIC.js +0 -57
  667. package/dist/InstrumentChassis-UUJX0-mW.js +0 -65
  668. package/dist/Label-B_HPqi_q.js +0 -36
  669. package/dist/MetricBadge-DQt_dGah.js +0 -79
  670. package/dist/ModalOverlay-DfAf7o15.js +0 -53
  671. package/dist/Notification-BlSPJhtZ.js +0 -43
  672. package/dist/NumberFieldContent-Z3VxGu_6.js +0 -140
  673. package/dist/PagerDots-CYlqVFd4.js +0 -196
  674. package/dist/PaperBackdrop-DYWgrnh8.js +0 -42
  675. package/dist/PopoverContent-BuKyHZSz.js +0 -127
  676. package/dist/Progress-C9SsdwIZ.js +0 -274
  677. package/dist/ScrollingText-DY3W1Jfh.js +0 -40
  678. package/dist/SelectGroup-Dcczq44n.js +0 -31
  679. package/dist/SelectScrollDownButton-3mFHX_R-.js +0 -260
  680. package/dist/SelectSeparator-CNRGG7Ew.js +0 -49
  681. package/dist/Separator-Cf9-JFgi.js +0 -44
  682. package/dist/Switch-uf-UKPA2.js +0 -49
  683. package/dist/Toaster-ozrsR4mP.js +0 -274
  684. package/dist/ToggleGroupItem-BpzaVzNm.js +0 -170
  685. package/dist/TooltipProvider-QQVM_80r.js +0 -109
  686. package/dist/api/index.d.ts +0 -34
  687. package/dist/api/types-extra.d.ts +0 -39
  688. package/dist/api.js +0 -2
  689. package/dist/badge-Bt14yURi.js +0 -72
  690. package/dist/border-progress.d.ts +0 -1
  691. package/dist/border-progress.js +0 -98
  692. package/dist/button-D1W9PrzI.js +0 -130
  693. package/dist/chipVariants-BJQ0I2kB.js +0 -18
  694. package/dist/cn-DJXf4yaB.js +0 -97
  695. package/dist/coalesceMetric-5qIeZnTx.js +0 -13
  696. package/dist/color-B9jZdhJX.js +0 -116
  697. package/dist/components/custom/aurora/Aurora.vue.d.ts +0 -101
  698. package/dist/components/custom/aurora/composables/atoms-fields.d.ts +0 -39
  699. package/dist/components/custom/aurora/composables/atoms.d.ts +0 -142
  700. package/dist/components/custom/aurora/composables/color.d.ts +0 -93
  701. package/dist/components/custom/aurora/composables/cursorModel.d.ts +0 -78
  702. package/dist/components/custom/aurora/composables/frameLoop.d.ts +0 -39
  703. package/dist/components/custom/aurora/composables/glSetup.d.ts +0 -29
  704. package/dist/components/custom/aurora/composables/runtime.d.ts +0 -127
  705. package/dist/components/custom/aurora/composables/uniformBridge.d.ts +0 -100
  706. package/dist/components/custom/aurora/composables/uniformBridgeWGPU.d.ts +0 -60
  707. package/dist/components/custom/aurora/composables/useAurora.d.ts +0 -86
  708. package/dist/components/custom/aurora/composables/useCursorInteraction.d.ts +0 -33
  709. package/dist/components/custom/aurora/composables/wgpuSetup.d.ts +0 -37
  710. package/dist/components/custom/aurora/constants/presets.d.ts +0 -258
  711. package/dist/components/custom/aurora/constants/shaders/aurora-mediums.wgsl.d.ts +0 -1
  712. package/dist/components/custom/aurora/constants/shaders/aurora.wgsl.d.ts +0 -1
  713. package/dist/components/custom/aurora/constants/shaders/brush.glsl.d.ts +0 -1
  714. package/dist/components/custom/aurora/constants/shaders/flow.glsl.d.ts +0 -1
  715. package/dist/components/custom/aurora/constants/shaders/mediums.glsl.d.ts +0 -2
  716. package/dist/components/custom/aurora/index.d.ts +0 -13
  717. package/dist/components/custom/border-progress/BorderProgress.vue.d.ts +0 -46
  718. package/dist/components/custom/border-progress/composables/spectrum-walk.d.ts +0 -25
  719. package/dist/components/custom/border-progress/composables/useBorderSpectrum.d.ts +0 -18
  720. package/dist/components/custom/border-progress/constants.d.ts +0 -59
  721. package/dist/components/custom/border-progress/index.d.ts +0 -4
  722. package/dist/components/custom/completion-seal/CompletionSeal.vue.d.ts +0 -21
  723. package/dist/components/custom/completion-seal/constants.d.ts +0 -46
  724. package/dist/components/custom/concentric/Concentric.vue.d.ts +0 -42
  725. package/dist/components/custom/concentric/composables/concentricGLSetup.d.ts +0 -23
  726. package/dist/components/custom/concentric/composables/concentricWGPUSetup.d.ts +0 -26
  727. package/dist/components/custom/concentric/composables/levelField.d.ts +0 -50
  728. package/dist/components/custom/concentric/composables/uniformBridgeWGPU.d.ts +0 -17
  729. package/dist/components/custom/concentric/composables/useConcentric.d.ts +0 -35
  730. package/dist/components/custom/concentric/constants.d.ts +0 -88
  731. package/dist/components/custom/concentric/index.d.ts +0 -5
  732. package/dist/components/custom/concentric/shaders/concentric.glsl.d.ts +0 -4
  733. package/dist/components/custom/concentric/shaders/concentric.wgsl.d.ts +0 -1
  734. package/dist/components/custom/configurator/Configurator.vue.d.ts +0 -160
  735. package/dist/components/custom/configurator/ConfiguratorRow.vue.d.ts +0 -79
  736. package/dist/components/custom/configurator/density.d.ts +0 -25
  737. package/dist/components/custom/configurator/index.d.ts +0 -6
  738. package/dist/components/custom/confirm-dialog/ConfirmDialog.vue.d.ts +0 -32
  739. package/dist/components/custom/confirm-dialog/index.d.ts +0 -1
  740. package/dist/components/custom/constellation/Constellation.vue.d.ts +0 -33
  741. package/dist/components/custom/constellation/composables/constellationGLSetup.d.ts +0 -10
  742. package/dist/components/custom/constellation/composables/constellationWGPUSetup.d.ts +0 -19
  743. package/dist/components/custom/constellation/composables/useConstellation.d.ts +0 -19
  744. package/dist/components/custom/constellation/constants.d.ts +0 -94
  745. package/dist/components/custom/constellation/constellationTypes.d.ts +0 -407
  746. package/dist/components/custom/dock/DockBackgroundToggle.vue.d.ts +0 -46
  747. package/dist/components/custom/dock/DockDropdownTrigger.vue.d.ts +0 -30
  748. package/dist/components/custom/dock/DockIconButton.vue.d.ts +0 -72
  749. package/dist/components/custom/dock/DockLayer.vue.d.ts +0 -34
  750. package/dist/components/custom/dock/DockLayerGroup.vue.d.ts +0 -51
  751. package/dist/components/custom/dock/DockPopoverTrigger.vue.d.ts +0 -19
  752. package/dist/components/custom/dock/DockSelectTrigger.vue.d.ts +0 -29
  753. package/dist/components/custom/dock/DockStack.vue.d.ts +0 -78
  754. package/dist/components/custom/dock/DockTabButton.vue.d.ts +0 -39
  755. package/dist/components/custom/dock/GlassDock.vue.d.ts +0 -47
  756. package/dist/components/custom/dock/composables/dockContext.d.ts +0 -47
  757. package/dist/components/custom/dock/composables/dockLayerContext.d.ts +0 -36
  758. package/dist/components/custom/dock/composables/dockMorphContext.d.ts +0 -79
  759. package/dist/components/custom/dock/composables/index.d.ts +0 -14
  760. package/dist/components/custom/dock/composables/railProjection.d.ts +0 -45
  761. package/dist/components/custom/dock/composables/useDockContextSilhouette.d.ts +0 -192
  762. package/dist/components/custom/dock/composables/useDockFission.d.ts +0 -158
  763. package/dist/components/custom/dock/composables/useDockItemDrag.d.ts +0 -18
  764. package/dist/components/custom/dock/composables/useDockMorphWindow.d.ts +0 -15
  765. package/dist/components/custom/dock/composables/useDockOrientationMorph.d.ts +0 -44
  766. package/dist/components/custom/dock/composables/useDockSearch.d.ts +0 -85
  767. package/dist/components/custom/dock/composables/useDockShellProps.d.ts +0 -214
  768. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +0 -90
  769. package/dist/components/custom/dock/constants.d.ts +0 -98
  770. package/dist/components/custom/dock/index.d.ts +0 -24
  771. package/dist/components/custom/dot-flow-field/DotFlowField.vue.d.ts +0 -42
  772. package/dist/components/custom/dot-flow-field/composables/flowField.d.ts +0 -104
  773. package/dist/components/custom/dot-flow-field/composables/flowGLProgram.d.ts +0 -8
  774. package/dist/components/custom/dot-flow-field/composables/flowSetupGL.d.ts +0 -9
  775. package/dist/components/custom/dot-flow-field/composables/flowSetupGLFlow.d.ts +0 -12
  776. package/dist/components/custom/dot-flow-field/composables/flowSetupWGPU.d.ts +0 -7
  777. package/dist/components/custom/dot-flow-field/composables/uniformBridgeWGPU.d.ts +0 -65
  778. package/dist/components/custom/dot-flow-field/composables/useDotFlowField.d.ts +0 -35
  779. package/dist/components/custom/dot-flow-field/composables/useFlowParticles.d.ts +0 -32
  780. package/dist/components/custom/dot-flow-field/constants.d.ts +0 -120
  781. package/dist/components/custom/dot-flow-field/index.d.ts +0 -5
  782. package/dist/components/custom/dot-flow-field/shaders/flow-field.compute.wgsl.d.ts +0 -1
  783. package/dist/components/custom/dot-flow-field/shaders/flow-field.glsl.d.ts +0 -33
  784. package/dist/components/custom/dot-flow-field/shaders/flow-field.render.wgsl.d.ts +0 -2
  785. package/dist/components/custom/dot-matrix/DotMatrix.vue.d.ts +0 -43
  786. package/dist/components/custom/dot-matrix/composables/dotMatrixField.d.ts +0 -89
  787. package/dist/components/custom/dot-matrix/composables/uniformBridgeWGPU.d.ts +0 -61
  788. package/dist/components/custom/dot-matrix/composables/useDotMatrix.d.ts +0 -34
  789. package/dist/components/custom/dot-matrix/composables/useDotSphere.d.ts +0 -34
  790. package/dist/components/custom/dot-matrix/constants.d.ts +0 -72
  791. package/dist/components/custom/dot-matrix/index.d.ts +0 -5
  792. package/dist/components/custom/dot-matrix/shaders/dot-matrix.glsl.d.ts +0 -4
  793. package/dist/components/custom/dot-matrix/shaders/dot-matrix.wgsl.d.ts +0 -1
  794. package/dist/components/custom/expandable-container/ExpandableContainer.vue.d.ts +0 -71
  795. package/dist/components/custom/fourier-field/FourierField.vue.d.ts +0 -58
  796. package/dist/components/custom/fourier-field/composables/fourierFieldGLSetup.d.ts +0 -24
  797. package/dist/components/custom/fourier-field/composables/fourierFieldWGPUSetup.d.ts +0 -31
  798. package/dist/components/custom/fourier-field/composables/uniformBridgeWGPU.d.ts +0 -56
  799. package/dist/components/custom/fourier-field/composables/useFourierField.d.ts +0 -63
  800. package/dist/components/custom/fourier-field/constants.d.ts +0 -117
  801. package/dist/components/custom/fourier-field/index.d.ts +0 -31
  802. package/dist/components/custom/fourier-field/math.d.ts +0 -86
  803. package/dist/components/custom/fourier-field/shaders/fourier-field.glsl.d.ts +0 -4
  804. package/dist/components/custom/fourier-field/shaders/fourier-field.render.wgsl.d.ts +0 -1
  805. package/dist/components/custom/glass-panel/GlassPanel.vue.d.ts +0 -49
  806. package/dist/components/custom/glass-panel/index.d.ts +0 -2
  807. package/dist/components/custom/goo-blob/GooBlob.vue.d.ts +0 -71
  808. package/dist/components/custom/goo-blob/composables/uploadBlobUniforms.d.ts +0 -41
  809. package/dist/components/custom/goo-blob/composables/useBlobPointer.d.ts +0 -62
  810. package/dist/components/custom/goo-blob/composables/useMetaballRenderer.d.ts +0 -69
  811. package/dist/components/custom/goo-blob/composables/wgpuSetup.d.ts +0 -23
  812. package/dist/components/custom/goo-blob/constants.d.ts +0 -82
  813. package/dist/components/custom/goo-blob/index.d.ts +0 -7
  814. package/dist/components/custom/goo-blob/shaders/metaball-uniforms.glsl.d.ts +0 -1
  815. package/dist/components/custom/goo-blob/types.d.ts +0 -244
  816. package/dist/components/custom/goo-dot-matrix/GooDotMatrix.vue.d.ts +0 -49
  817. package/dist/components/custom/goo-dot-matrix/composables/gooDotLattice.d.ts +0 -24
  818. package/dist/components/custom/goo-dot-matrix/composables/gooDotSetup.d.ts +0 -79
  819. package/dist/components/custom/goo-dot-matrix/composables/uniformBridgeWGPU.d.ts +0 -45
  820. package/dist/components/custom/goo-dot-matrix/composables/useGooDotMatrix.d.ts +0 -31
  821. package/dist/components/custom/goo-dot-matrix/constants.d.ts +0 -115
  822. package/dist/components/custom/goo-dot-matrix/index.d.ts +0 -5
  823. package/dist/components/custom/goo-dot-matrix/shaders/goo-dot.frag.d.ts +0 -13
  824. package/dist/components/custom/goo-dot-matrix/shaders/goo-dot.wgsl.d.ts +0 -4
  825. package/dist/components/custom/handmark/composables/useHandMark.d.ts +0 -89
  826. package/dist/components/custom/handmark/constants.d.ts +0 -59
  827. package/dist/components/custom/handmark/geometry.d.ts +0 -85
  828. package/dist/components/custom/handmark/types.d.ts +0 -62
  829. package/dist/components/custom/header-ribbon/HeaderRibbon.vue.d.ts +0 -31
  830. package/dist/components/custom/header-ribbon/index.d.ts +0 -2
  831. package/dist/components/custom/header-ribbon/types.d.ts +0 -7
  832. package/dist/components/custom/hover-popover/HoverPopover.vue.d.ts +0 -132
  833. package/dist/components/custom/hover-popover/index.d.ts +0 -1
  834. package/dist/components/custom/metric-badge/MetricBadge.vue.d.ts +0 -40
  835. package/dist/components/custom/metric-cell/MetricCell.vue.d.ts +0 -108
  836. package/dist/components/custom/metric-stack/MetricRow.vue.d.ts +0 -120
  837. package/dist/components/custom/paper-backdrop/PaperBackdrop.vue.d.ts +0 -39
  838. package/dist/components/custom/paper-grid/PaperGrid.vue.d.ts +0 -42
  839. package/dist/components/custom/paper-grid/composables/paperGrid.d.ts +0 -105
  840. package/dist/components/custom/paper-grid/composables/paperGridGLSetup.d.ts +0 -18
  841. package/dist/components/custom/paper-grid/composables/paperGridWGPUSetup.d.ts +0 -21
  842. package/dist/components/custom/paper-grid/composables/uniformBridgeWGPU.d.ts +0 -16
  843. package/dist/components/custom/paper-grid/composables/usePaperGrid.d.ts +0 -31
  844. package/dist/components/custom/paper-grid/constants.d.ts +0 -95
  845. package/dist/components/custom/paper-grid/index.d.ts +0 -5
  846. package/dist/components/custom/paper-grid/shaders/paper-grid.glsl.d.ts +0 -4
  847. package/dist/components/custom/paper-grid/shaders/paper-grid.wgsl.d.ts +0 -1
  848. package/dist/components/custom/scrolling-text/ScrollingText.vue.d.ts +0 -20
  849. package/dist/components/custom/scrolling-text/index.d.ts +0 -1
  850. package/dist/components/custom/search/FuzzySearch.vue.d.ts +0 -22
  851. package/dist/components/custom/search/SearchBar.vue.d.ts +0 -38
  852. package/dist/components/custom/search/searchVariants.d.ts +0 -19
  853. package/dist/components/custom/selectable-chip/SelectableChip.vue.d.ts +0 -50
  854. package/dist/components/custom/selectable-chip/chipVariants.d.ts +0 -39
  855. package/dist/components/custom/selectable-chip/index.d.ts +0 -2
  856. package/dist/components/custom/selectable-chip/selectableChipVariants.d.ts +0 -15
  857. package/dist/components/custom/sortable-list/SortableHandle.vue.d.ts +0 -38
  858. package/dist/components/custom/sortable-list/SortableItem.vue.d.ts +0 -38
  859. package/dist/components/custom/sortable-list/SortableList.vue.d.ts +0 -76
  860. package/dist/components/custom/sortable-list/context.d.ts +0 -25
  861. package/dist/components/custom/sortable-list/index.d.ts +0 -4
  862. package/dist/components/custom/split-chars/SplitChars.vue.d.ts +0 -39
  863. package/dist/components/custom/stacked-icons/types.d.ts +0 -18
  864. package/dist/components/custom/tabs/SegmentedTabs.vue.d.ts +0 -99
  865. package/dist/components/custom/tabs/composables/useTabDragMorph.d.ts +0 -42
  866. package/dist/components/custom/tabs/composables/useTabIndicator.d.ts +0 -58
  867. package/dist/components/custom/tabs/constants.d.ts +0 -44
  868. package/dist/components/custom/timeline/ContinuousMarkers.vue.d.ts +0 -49
  869. package/dist/components/custom/timeline/GlassTimeline.vue.d.ts +0 -114
  870. package/dist/components/custom/toggle-chip/ToggleChip.vue.d.ts +0 -41
  871. package/dist/components/custom/toggle-chip/index.d.ts +0 -28
  872. package/dist/components/custom/watercolor-dot/prng.d.ts +0 -5
  873. package/dist/components/custom/watercolor-dot/useWatercolorBlob.d.ts +0 -29
  874. package/dist/components/ui/_shared/index.d.ts +0 -6
  875. package/dist/components/ui/_shared/menuItemVariants.d.ts +0 -51
  876. package/dist/components/ui/_shared/useControlSize.d.ts +0 -46
  877. package/dist/components/ui/_shared/useSurfaceAxis.d.ts +0 -55
  878. package/dist/components/ui/alert/Alert.vue.d.ts +0 -19
  879. package/dist/components/ui/alert/index.d.ts +0 -8
  880. package/dist/components/ui/avatar/Avatar.vue.d.ts +0 -23
  881. package/dist/components/ui/avatar/index.d.ts +0 -9
  882. package/dist/components/ui/badge/Badge.vue.d.ts +0 -34
  883. package/dist/components/ui/badge/index.d.ts +0 -8
  884. package/dist/components/ui/button/Button.vue.d.ts +0 -29
  885. package/dist/components/ui/button/index.d.ts +0 -7
  886. package/dist/components/ui/card/Card.vue.d.ts +0 -168
  887. package/dist/components/ui/card/CardHeader.vue.d.ts +0 -81
  888. package/dist/components/ui/card/ScrollCard.vue.d.ts +0 -33
  889. package/dist/components/ui/carousel/Carousel.vue.d.ts +0 -37
  890. package/dist/components/ui/carousel/CarouselContent.vue.d.ts +0 -14
  891. package/dist/components/ui/carousel/CarouselNext.vue.d.ts +0 -22
  892. package/dist/components/ui/carousel/CarouselPrevious.vue.d.ts +0 -22
  893. package/dist/components/ui/carousel/GlassCarouselPager.vue.d.ts +0 -50
  894. package/dist/components/ui/carousel/useCarousel.d.ts +0 -20
  895. package/dist/components/ui/combobox/Combobox.vue.d.ts +0 -29
  896. package/dist/components/ui/combobox/ComboboxList.vue.d.ts +0 -32
  897. package/dist/components/ui/command/index.d.ts +0 -9
  898. package/dist/components/ui/context-menu/ContextMenu.vue.d.ts +0 -18
  899. package/dist/components/ui/context-menu/ContextMenuCheckboxItem.vue.d.ts +0 -24
  900. package/dist/components/ui/context-menu/ContextMenuContent.vue.d.ts +0 -34
  901. package/dist/components/ui/context-menu/ContextMenuItem.vue.d.ts +0 -23
  902. package/dist/components/ui/context-menu/ContextMenuLabel.vue.d.ts +0 -19
  903. package/dist/components/ui/context-menu/ContextMenuRadioGroup.vue.d.ts +0 -18
  904. package/dist/components/ui/context-menu/ContextMenuRadioItem.vue.d.ts +0 -22
  905. package/dist/components/ui/context-menu/ContextMenuSeparator.vue.d.ts +0 -8
  906. package/dist/components/ui/context-menu/ContextMenuShortcut.vue.d.ts +0 -17
  907. package/dist/components/ui/context-menu/ContextMenuSubContent.vue.d.ts +0 -34
  908. package/dist/components/ui/context-menu/ContextMenuSubTrigger.vue.d.ts +0 -19
  909. package/dist/components/ui/context-menu/ContextMenuTrigger.vue.d.ts +0 -14
  910. package/dist/components/ui/context-menu/index.d.ts +0 -12
  911. package/dist/components/ui/dialog/DialogContent.vue.d.ts +0 -93
  912. package/dist/components/ui/drawer/Drawer.vue.d.ts +0 -86
  913. package/dist/components/ui/drawer/DrawerContent.vue.d.ts +0 -47
  914. package/dist/components/ui/drawer/composables/useDrawerSnap.d.ts +0 -17
  915. package/dist/components/ui/drawer/constants.d.ts +0 -47
  916. package/dist/components/ui/drawer/index.d.ts +0 -35
  917. package/dist/components/ui/dropdown-menu/DropdownMenu.vue.d.ts +0 -18
  918. package/dist/components/ui/dropdown-menu/DropdownMenuContent.vue.d.ts +0 -36
  919. package/dist/components/ui/dropdown-menu/index.d.ts +0 -15
  920. package/dist/components/ui/hover-card/HoverCard.vue.d.ts +0 -18
  921. package/dist/components/ui/hover-card/HoverCardContent.vue.d.ts +0 -23
  922. package/dist/components/ui/hover-card/HoverCardTrigger.vue.d.ts +0 -14
  923. package/dist/components/ui/hover-card/index.d.ts +0 -3
  924. package/dist/components/ui/index.d.ts +0 -41
  925. package/dist/components/ui/metric-pill/MetricPill.vue.d.ts +0 -46
  926. package/dist/components/ui/metric-pill/index.d.ts +0 -1
  927. package/dist/components/ui/multi-select/MultiSelect.vue.d.ts +0 -28
  928. package/dist/components/ui/multi-select/index.d.ts +0 -7
  929. package/dist/components/ui/notification/Notification.vue.d.ts +0 -16
  930. package/dist/components/ui/popover/Popover.vue.d.ts +0 -18
  931. package/dist/components/ui/popover/PopoverContent.vue.d.ts +0 -42
  932. package/dist/components/ui/popover/PopoverTrigger.vue.d.ts +0 -14
  933. package/dist/components/ui/progress/Progress.vue.d.ts +0 -49
  934. package/dist/components/ui/progress/index.d.ts +0 -5
  935. package/dist/components/ui/select/SelectContent.vue.d.ts +0 -42
  936. package/dist/components/ui/sheet/Sheet.vue.d.ts +0 -18
  937. package/dist/components/ui/sheet/SheetClose.vue.d.ts +0 -14
  938. package/dist/components/ui/sheet/SheetContent.vue.d.ts +0 -59
  939. package/dist/components/ui/sheet/SheetDescription.vue.d.ts +0 -18
  940. package/dist/components/ui/sheet/SheetFooter.vue.d.ts +0 -17
  941. package/dist/components/ui/sheet/SheetHeader.vue.d.ts +0 -17
  942. package/dist/components/ui/sheet/SheetTitle.vue.d.ts +0 -18
  943. package/dist/components/ui/sheet/SheetTrigger.vue.d.ts +0 -14
  944. package/dist/components/ui/sheet/index.d.ts +0 -13
  945. package/dist/components/ui/slider/Slider.vue.d.ts +0 -37
  946. package/dist/components/ui/slider/index.d.ts +0 -46
  947. package/dist/components/ui/tabs/Tabs.vue.d.ts +0 -19
  948. package/dist/components/ui/tabs/TabsContent.vue.d.ts +0 -18
  949. package/dist/components/ui/tabs/TabsIndicator.vue.d.ts +0 -11
  950. package/dist/components/ui/tabs/TabsList.vue.d.ts +0 -28
  951. package/dist/components/ui/tabs/TabsTrigger.vue.d.ts +0 -18
  952. package/dist/components/ui/tabs/index.d.ts +0 -5
  953. package/dist/components/ui/toast/Toast.vue.d.ts +0 -107
  954. package/dist/components/ui/toast/index.d.ts +0 -9
  955. package/dist/components/ui/toast/use-toast.d.ts +0 -182
  956. package/dist/components/ui/toggle/Toggle.vue.d.ts +0 -29
  957. package/dist/components/ui/toggle/index.d.ts +0 -26
  958. package/dist/composables/glass/useGlassRenderer.d.ts +0 -44
  959. package/dist/composables/glass/useVizChoreography.d.ts +0 -123
  960. package/dist/composables/motion/core/useHaptic.d.ts +0 -48
  961. package/dist/composables/motion/useCelebrationBurst.d.ts +0 -50
  962. package/dist/composables/motion/useLiquidMorph.d.ts +0 -108
  963. package/dist/composables/motion/useMorphField.d.ts +0 -157
  964. package/dist/composables/sortable/dragController.d.ts +0 -44
  965. package/dist/composables/sortable/types.d.ts +0 -133
  966. package/dist/composables/sortable/useSortable.d.ts +0 -34
  967. package/dist/concentric.d.ts +0 -1
  968. package/dist/concentric.js +0 -805
  969. package/dist/confirm-dialog.d.ts +0 -1
  970. package/dist/confirm-dialog.js +0 -82
  971. package/dist/context-menu.d.ts +0 -1
  972. package/dist/context-menu.js +0 -3
  973. package/dist/createCanvasLifecycle-CuCrGRfq.js +0 -173
  974. package/dist/dockContext-gFVS2gMg.js +0 -18
  975. package/dist/dot-flow-field.d.ts +0 -1
  976. package/dist/dot-flow-field.js +0 -1485
  977. package/dist/dot-matrix.d.ts +0 -1
  978. package/dist/dot-matrix.js +0 -774
  979. package/dist/dotMatrixField-CRO0ZFk4.js +0 -48
  980. package/dist/dropdown-menu-CCfcCQ68.js +0 -369
  981. package/dist/glass-panel.d.ts +0 -1
  982. package/dist/glass-panel.js +0 -113
  983. package/dist/goo-blob.d.ts +0 -1
  984. package/dist/goo-blob.js +0 -348
  985. package/dist/goo-dot-matrix.d.ts +0 -1
  986. package/dist/goo-dot-matrix.js +0 -811
  987. package/dist/hover-card.d.ts +0 -1
  988. package/dist/hover-card.js +0 -2
  989. package/dist/hover-popover.d.ts +0 -1
  990. package/dist/hover-popover.js +0 -2
  991. package/dist/math-5RcIgCB4.js +0 -51
  992. package/dist/menuItemVariants-DAXquKja.js +0 -36
  993. package/dist/paper-grid.d.ts +0 -1
  994. package/dist/paper-grid.js +0 -761
  995. package/dist/paperGrid-CXCSMbZ1.js +0 -191
  996. package/dist/presets-QvYgnFIZ.js +0 -85
  997. package/dist/prng-B5tIXTtj.js +0 -15
  998. package/dist/resolveCanvasColor-DsSJk06I.js +0 -93
  999. package/dist/scrolling-text.d.ts +0 -1
  1000. package/dist/scrolling-text.js +0 -2
  1001. package/dist/selectable-chip.d.ts +0 -1
  1002. package/dist/selectable-chip.js +0 -48
  1003. package/dist/sheet-DUCIoOe0.js +0 -218
  1004. package/dist/sheet.d.ts +0 -1
  1005. package/dist/sheet.js +0 -2
  1006. package/dist/slider-CcICPe3u.js +0 -149
  1007. package/dist/spectrum-walk-cBNSx_zm.js +0 -33
  1008. package/dist/springPresets-DfoQ6XRY.js +0 -64
  1009. package/dist/styles/border-progress.css +0 -109
  1010. package/dist/styles/critical-partition.mjs +0 -195
  1011. package/dist/styles/critical.css +0 -12
  1012. package/dist/styles/deferred.css +0 -35
  1013. package/dist/styles/dock/fission-bridge.css +0 -552
  1014. package/dist/styles/dock/morph-bridge.css +0 -172
  1015. package/dist/styles/dock/stack-rail.css +0 -352
  1016. package/dist/styles/floating-panel.css +0 -51
  1017. package/dist/styles/glass/liquid-morph.css +0 -850
  1018. package/dist/styles/hover-popover.css +0 -47
  1019. package/dist/styles/jubilance.css +0 -65
  1020. package/dist/styles/motion/morph-field.css +0 -229
  1021. package/dist/toggle-chip.d.ts +0 -1
  1022. package/dist/toggle-chip.js +0 -46
  1023. package/dist/uniformBridgeWGPU-BCse1SHU.js +0 -1268
  1024. package/dist/useAnimatedNumber-BntskVdQ.js +0 -40
  1025. package/dist/useConfiguratorState-22BcULzF.js +0 -164
  1026. package/dist/useControlSize-DAZ062x7.js +0 -9
  1027. package/dist/useDockCtaReceive-DX7RDb6_.js +0 -88
  1028. package/dist/useDragMorph-DGLSewwB.js +0 -102
  1029. package/dist/useFuzzySearch-0fTYOhS4.js +0 -177
  1030. package/dist/useGooMorph-Cs13NgYL.js +0 -104
  1031. package/dist/useGpuSubstrate-Ceet70xq.js +0 -347
  1032. package/dist/useHaptic-CPz5BT9I.js +0 -134
  1033. package/dist/useIntersectionPause-DO8Vl4gs.js +0 -53
  1034. package/dist/useKeyboardShortcuts-BEut54Tk.js +0 -99
  1035. package/dist/useLiquidPress-CtOQ8Z0_.js +0 -43
  1036. package/dist/useMorphField-ogBM7ubT.js +0 -141
  1037. package/dist/usePointerVelocityField-BrkqZFhj.js +0 -91
  1038. package/dist/useScrollChrome-JuImi1DM.js +0 -258
  1039. package/dist/useScrollProgress-A0M6qRl7.js +0 -35
  1040. package/dist/useSortable-DQV_UNDw.js +0 -246
  1041. package/dist/useSpring-C0jyvEJB.js +0 -40
  1042. package/dist/useSpringMount-DFxtzmkR.js +0 -71
  1043. package/dist/useSpringPress-VM9RgVq3.js +0 -36
  1044. package/dist/useSurfaceAxis-Ci7Dnaw2.js +0 -7
  1045. package/dist/useTouchGate-B1Lf9XqN.js +0 -84
  1046. package/dist/useUserInvalidAria-EmmwWPOl.js +0 -29
  1047. package/dist/utils/cn.d.ts +0 -27
  1048. package/dist/utils/index.d.ts +0 -4
  1049. package/dist/utils/moveBefore.d.ts +0 -15
  1050. package/dist/utils/platformSupport.d.ts +0 -8
  1051. package/dist/vendor-B2qOlYY3.js +0 -239
  1052. package/dist/virtual.d.ts +0 -1
  1053. package/dist/virtual.js +0 -225
  1054. package/src/styles/border-progress.css +0 -109
  1055. package/src/styles/critical-partition.mjs +0 -195
  1056. package/src/styles/dock/fission-bridge.css +0 -552
  1057. package/src/styles/dock/morph-bridge.css +0 -172
  1058. package/src/styles/dock/stack-rail.css +0 -352
  1059. package/src/styles/floating-panel.css +0 -49
  1060. package/src/styles/glass/liquid-morph.css +0 -850
  1061. package/src/styles/hover-popover.css +0 -45
  1062. package/src/styles/jubilance.css +0 -65
  1063. package/src/styles/motion/morph-field.css +0 -229
  1064. /package/dist/{_plugin-vue_export-helper-gLzyemvl.js → _plugin-vue_export-helper-C1je1s0u.js} +0 -0
  1065. /package/dist/{compile-INR_tPk_.js → compile-C55K3P9g.js} +0 -0
  1066. /package/dist/components/{ui/_shared → _shared}/ModalOverlay.vue.d.ts +0 -0
  1067. /package/dist/components/{ui/_shared → _shared}/useStalePropWarning.d.ts +0 -0
  1068. /package/dist/components/{ui/accordion → accordion}/Accordion.vue.d.ts +0 -0
  1069. /package/dist/components/{ui/accordion → accordion}/AccordionContent.vue.d.ts +0 -0
  1070. /package/dist/components/{ui/accordion → accordion}/AccordionItem.vue.d.ts +0 -0
  1071. /package/dist/components/{ui/accordion → accordion}/AccordionTrigger.vue.d.ts +0 -0
  1072. /package/dist/components/{ui/accordion → accordion}/index.d.ts +0 -0
  1073. /package/dist/components/{ui/alert → alert}/AlertDescription.vue.d.ts +0 -0
  1074. /package/dist/components/{ui/alert → alert}/AlertTitle.vue.d.ts +0 -0
  1075. /package/dist/components/{custom/animated-digit → animated-digit}/AnimatedDigit.vue.d.ts +0 -0
  1076. /package/dist/components/{custom/animated-digit → animated-digit}/index.d.ts +0 -0
  1077. /package/dist/components/{custom/aurora → aurora}/composables/auroraFallbackGround.d.ts +0 -0
  1078. /package/dist/components/{custom/aurora → aurora}/composables/configSource.d.ts +0 -0
  1079. /package/dist/components/{custom/aurora → aurora}/constants/budget.d.ts +0 -0
  1080. /package/dist/components/{custom/aurora → aurora}/constants/renderMode.d.ts +0 -0
  1081. /package/dist/components/{custom/aurora → aurora}/constants/shaders/aurora.frag.d.ts +0 -0
  1082. /package/dist/components/{custom/aurora → aurora}/constants/shaders/aurora.vert.d.ts +0 -0
  1083. /package/dist/components/{custom/aurora → aurora}/constants/shaders/composition.glsl.d.ts +0 -0
  1084. /package/dist/components/{custom/aurora → aurora}/constants/shaders/oil-modes.glsl.d.ts +0 -0
  1085. /package/dist/components/{custom/aurora → aurora}/constants/shaders/procedural-color.wgsl.d.ts +0 -0
  1086. /package/dist/components/{custom/aurora → aurora}/constants/shaders/tonemap.glsl.d.ts +0 -0
  1087. /package/dist/components/{custom/aurora → aurora}/constants/shaders/vangogh-medium.glsl.d.ts +0 -0
  1088. /package/dist/components/{ui/avatar → avatar}/AvatarFallback.vue.d.ts +0 -0
  1089. /package/dist/components/{ui/avatar → avatar}/AvatarImage.vue.d.ts +0 -0
  1090. /package/dist/components/{custom/goo-blob → blob}/composables/buildMetaballProgram.d.ts +0 -0
  1091. /package/dist/components/{custom/goo-blob → blob}/composables/easing.d.ts +0 -0
  1092. /package/dist/components/{custom/goo-blob → blob}/composables/uniformBridgeWGPU.d.ts +0 -0
  1093. /package/dist/components/{custom/goo-blob → blob}/composables/useBlobMood.d.ts +0 -0
  1094. /package/dist/components/{custom/goo-blob → blob}/composables/useBlobSatellites.d.ts +0 -0
  1095. /package/dist/components/{custom/goo-blob → blob}/shaders/metaball-noise.wgsl.d.ts +0 -0
  1096. /package/dist/components/{custom/goo-blob → blob}/shaders/metaball-palette.wgsl.d.ts +0 -0
  1097. /package/dist/components/{custom/goo-blob → blob}/shaders/metaball.frag.d.ts +0 -0
  1098. /package/dist/components/{custom/goo-blob → blob}/shaders/metaball.vert.d.ts +0 -0
  1099. /package/dist/components/{custom/goo-blob → blob}/shaders/metaball.wgsl.d.ts +0 -0
  1100. /package/dist/components/{custom/goo-blob → blob}/shaders/oklch-perturb.glsl.d.ts +0 -0
  1101. /package/dist/components/{custom/goo-blob → blob}/shaders/sdf-body.glsl.d.ts +0 -0
  1102. /package/dist/components/{custom/goo-blob → blob}/shaders/watercolor-edges.glsl.d.ts +0 -0
  1103. /package/dist/components/{ui/card → card}/CardAction.vue.d.ts +0 -0
  1104. /package/dist/components/{ui/card → card}/CardContent.vue.d.ts +0 -0
  1105. /package/dist/components/{ui/card → card}/CardDescription.vue.d.ts +0 -0
  1106. /package/dist/components/{ui/card → card}/CardFooter.vue.d.ts +0 -0
  1107. /package/dist/components/{ui/card → card}/CardTitle.vue.d.ts +0 -0
  1108. /package/dist/components/{ui/card → card}/ScrollCardHeader.vue.d.ts +0 -0
  1109. /package/dist/components/{ui/card → card}/index.d.ts +0 -0
  1110. /package/dist/components/{ui/carousel → carousel}/CarouselItem.vue.d.ts +0 -0
  1111. /package/dist/components/{ui/carousel → carousel}/CarouselPager.vue.d.ts +0 -0
  1112. /package/dist/components/{ui/carousel → carousel}/index.d.ts +0 -0
  1113. /package/dist/components/{ui/carousel → carousel}/interface.d.ts +0 -0
  1114. /package/dist/components/{ui/checkbox → checkbox}/Checkbox.vue.d.ts +0 -0
  1115. /package/dist/components/{ui/checkbox → checkbox}/index.d.ts +0 -0
  1116. /package/dist/components/{ui/collapsible → collapsible}/Collapsible.vue.d.ts +0 -0
  1117. /package/dist/components/{ui/collapsible → collapsible}/CollapsibleContent.vue.d.ts +0 -0
  1118. /package/dist/components/{ui/collapsible → collapsible}/CollapsibleTrigger.vue.d.ts +0 -0
  1119. /package/dist/components/{ui/collapsible → collapsible}/index.d.ts +0 -0
  1120. /package/dist/components/{custom/color-swatch → color-swatch}/ColorSwatch.vue.d.ts +0 -0
  1121. /package/dist/components/{custom/color-swatch → color-swatch}/index.d.ts +0 -0
  1122. /package/dist/components/{ui/combobox → combobox}/ComboboxAnchor.vue.d.ts +0 -0
  1123. /package/dist/components/{ui/combobox → combobox}/ComboboxEmpty.vue.d.ts +0 -0
  1124. /package/dist/components/{ui/combobox → combobox}/ComboboxGroup.vue.d.ts +0 -0
  1125. /package/dist/components/{ui/combobox → combobox}/ComboboxInput.vue.d.ts +0 -0
  1126. /package/dist/components/{ui/combobox → combobox}/ComboboxItem.vue.d.ts +0 -0
  1127. /package/dist/components/{ui/combobox → combobox}/ComboboxItemIndicator.vue.d.ts +0 -0
  1128. /package/dist/components/{ui/combobox → combobox}/ComboboxSeparator.vue.d.ts +0 -0
  1129. /package/dist/components/{ui/combobox → combobox}/ComboboxViewport.vue.d.ts +0 -0
  1130. /package/dist/components/{ui/combobox → combobox}/index.d.ts +0 -0
  1131. /package/dist/components/{ui/command → command}/Command.vue.d.ts +0 -0
  1132. /package/dist/components/{ui/command → command}/CommandDialog.vue.d.ts +0 -0
  1133. /package/dist/components/{ui/command → command}/CommandEmpty.vue.d.ts +0 -0
  1134. /package/dist/components/{ui/command → command}/CommandGroup.vue.d.ts +0 -0
  1135. /package/dist/components/{ui/command → command}/CommandInput.vue.d.ts +0 -0
  1136. /package/dist/components/{ui/command → command}/CommandItem.vue.d.ts +0 -0
  1137. /package/dist/components/{ui/command → command}/CommandList.vue.d.ts +0 -0
  1138. /package/dist/components/{ui/command → command}/CommandSeparator.vue.d.ts +0 -0
  1139. /package/dist/components/{ui/command → command}/CommandShortcut.vue.d.ts +0 -0
  1140. /package/dist/components/{custom/completion-seal → completion-seal}/composables/useCompletionSeal.d.ts +0 -0
  1141. /package/dist/components/{custom/completion-seal → completion-seal}/index.d.ts +0 -0
  1142. /package/dist/components/{custom/configurator → configurator}/ConfiguratorLayer.vue.d.ts +0 -0
  1143. /package/dist/components/{custom/configurator → configurator}/useConfiguratorState.d.ts +0 -0
  1144. /package/dist/components/{custom/constellation → constellation}/composables/createConstellationField.d.ts +0 -0
  1145. /package/dist/components/{custom/constellation → constellation}/composables/uniformBridgeWGPU.d.ts +0 -0
  1146. /package/dist/components/{custom/constellation → constellation}/constellationField.d.ts +0 -0
  1147. /package/dist/components/{custom/constellation → constellation}/constellationInteraction.d.ts +0 -0
  1148. /package/dist/components/{custom/constellation → constellation}/constellationRender.d.ts +0 -0
  1149. /package/dist/components/{custom/constellation → constellation}/constellationWell.d.ts +0 -0
  1150. /package/dist/components/{custom/constellation → constellation}/index.d.ts +0 -0
  1151. /package/dist/components/{custom/constellation → constellation}/shaders/constellation-lines.glsl.d.ts +0 -0
  1152. /package/dist/components/{custom/constellation → constellation}/shaders/constellation-lines.wgsl.d.ts +0 -0
  1153. /package/dist/components/{custom/constellation → constellation}/shaders/constellation-points.glsl.d.ts +0 -0
  1154. /package/dist/components/{custom/constellation → constellation}/shaders/constellation-points.wgsl.d.ts +0 -0
  1155. /package/dist/components/{custom/controls → controls}/DarkModeToggle.vue.d.ts +0 -0
  1156. /package/dist/components/{custom/controls → controls}/index.d.ts +0 -0
  1157. /package/dist/components/{ui/data-table → data-table}/DataTable.vue.d.ts +0 -0
  1158. /package/dist/components/{ui/data-table → data-table}/DataTablePagination.vue.d.ts +0 -0
  1159. /package/dist/components/{ui/data-table → data-table}/composables/useDataTableResponsive.d.ts +0 -0
  1160. /package/dist/components/{ui/data-table → data-table}/composables/useDataTableRowIdentity.d.ts +0 -0
  1161. /package/dist/components/{ui/data-table → data-table}/index.d.ts +0 -0
  1162. /package/dist/components/{ui/data-table → data-table}/types.d.ts +0 -0
  1163. /package/dist/components/{custom/deck → deck}/DeckPager.vue.d.ts +0 -0
  1164. /package/dist/components/{custom/deck → deck}/composables/useDeck.d.ts +0 -0
  1165. /package/dist/components/{custom/deck → deck}/composables/useDeckKeyboard.d.ts +0 -0
  1166. /package/dist/components/{custom/deck → deck}/composables/useDeckSpring.d.ts +0 -0
  1167. /package/dist/components/{custom/deck → deck}/constants.d.ts +0 -0
  1168. /package/dist/components/{custom/deck → deck}/index.d.ts +0 -0
  1169. /package/dist/components/{ui/dialog → dialog}/Dialog.vue.d.ts +0 -0
  1170. /package/dist/components/{ui/dialog → dialog}/DialogClose.vue.d.ts +0 -0
  1171. /package/dist/components/{ui/dialog → dialog}/DialogDescription.vue.d.ts +0 -0
  1172. /package/dist/components/{ui/dialog → dialog}/DialogFooter.vue.d.ts +0 -0
  1173. /package/dist/components/{ui/dialog → dialog}/DialogHeader.vue.d.ts +0 -0
  1174. /package/dist/components/{ui/dialog → dialog}/DialogScrollContent.vue.d.ts +0 -0
  1175. /package/dist/components/{ui/dialog → dialog}/DialogTitle.vue.d.ts +0 -0
  1176. /package/dist/components/{ui/dialog → dialog}/DialogTrigger.vue.d.ts +0 -0
  1177. /package/dist/components/{ui/dialog → dialog}/index.d.ts +0 -0
  1178. /package/dist/components/{custom/dock → dock}/DockSection.vue.d.ts +0 -0
  1179. /package/dist/components/{custom/dock → dock}/DockSeparator.vue.d.ts +0 -0
  1180. /package/dist/components/{custom/dock → dock}/composables/dockMorphMeasure.d.ts +0 -0
  1181. /package/dist/components/{custom/dock → dock}/composables/isTeleportedTarget.d.ts +0 -0
  1182. /package/dist/components/{custom/dock → dock}/composables/useDockClickIntegrity.d.ts +0 -0
  1183. /package/dist/components/{custom/dock → dock}/composables/useDockHold.d.ts +0 -0
  1184. /package/dist/components/{custom/dock → dock}/composables/useDockState.d.ts +0 -0
  1185. /package/dist/components/{ui/drawer → drawer}/DrawerDescription.vue.d.ts +0 -0
  1186. /package/dist/components/{ui/drawer → drawer}/DrawerFooter.vue.d.ts +0 -0
  1187. /package/dist/components/{ui/drawer → drawer}/DrawerHeader.vue.d.ts +0 -0
  1188. /package/dist/components/{ui/drawer → drawer}/DrawerOverlay.vue.d.ts +0 -0
  1189. /package/dist/components/{ui/drawer → drawer}/DrawerTitle.vue.d.ts +0 -0
  1190. /package/dist/components/{ui/drawer → drawer}/composables/drawerSnapContext.d.ts +0 -0
  1191. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuCheckboxItem.vue.d.ts +0 -0
  1192. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuGroup.vue.d.ts +0 -0
  1193. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuItem.vue.d.ts +0 -0
  1194. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuLabel.vue.d.ts +0 -0
  1195. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuRadioGroup.vue.d.ts +0 -0
  1196. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuRadioItem.vue.d.ts +0 -0
  1197. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuSeparator.vue.d.ts +0 -0
  1198. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuShortcut.vue.d.ts +0 -0
  1199. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuSub.vue.d.ts +0 -0
  1200. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuSubContent.vue.d.ts +0 -0
  1201. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuSubTrigger.vue.d.ts +0 -0
  1202. /package/dist/components/{ui/dropdown-menu → dropdown-menu}/DropdownMenuTrigger.vue.d.ts +0 -0
  1203. /package/dist/components/{custom/easing → easing}/EasingConfigurator.vue.d.ts +0 -0
  1204. /package/dist/components/{custom/easing → easing}/EasingPicker.vue.d.ts +0 -0
  1205. /package/dist/components/{custom/easing → easing}/composables/useEasingPicker.d.ts +0 -0
  1206. /package/dist/components/{custom/easing → easing}/constants.d.ts +0 -0
  1207. /package/dist/components/{custom/easing → easing}/index.d.ts +0 -0
  1208. /package/dist/components/{custom/expandable-container → expandable-container}/index.d.ts +0 -0
  1209. /package/dist/components/{custom/fading-scroll → fading-scroll}/FadingScroll.vue.d.ts +0 -0
  1210. /package/dist/components/{custom/fading-scroll → fading-scroll}/composables/useFadingScroll.d.ts +0 -0
  1211. /package/dist/components/{custom/fading-scroll → fading-scroll}/constants.d.ts +0 -0
  1212. /package/dist/components/{custom/fading-scroll → fading-scroll}/index.d.ts +0 -0
  1213. /package/dist/components/{ui/focus-scope → focus-scope}/FocusScope.vue.d.ts +0 -0
  1214. /package/dist/components/{ui/focus-scope → focus-scope}/index.d.ts +0 -0
  1215. /package/dist/components/{custom/fourier-field → fourier-field}/presets.d.ts +0 -0
  1216. /package/dist/components/{custom/fourier-field → fourier-field}/shaders/fourier-field.compute.wgsl.d.ts +0 -0
  1217. /package/dist/components/{custom/goo-filter → goo-filter}/GooFilter.vue.d.ts +0 -0
  1218. /package/dist/components/{custom/goo-filter → goo-filter}/index.d.ts +0 -0
  1219. /package/dist/components/{custom/handmark → handmark}/HandMark.vue.d.ts +0 -0
  1220. /package/dist/components/{custom/handmark → handmark}/brush.d.ts +0 -0
  1221. /package/dist/components/{custom/handmark → handmark}/freehand.d.ts +0 -0
  1222. /package/dist/components/{custom/handmark → handmark}/index.d.ts +0 -0
  1223. /package/dist/components/{custom/handmark → handmark}/ink.d.ts +0 -0
  1224. /package/dist/components/{custom/handmark → handmark}/texture.d.ts +0 -0
  1225. /package/dist/components/{custom/icon-chip → icon-chip}/IconChip.vue.d.ts +0 -0
  1226. /package/dist/components/{custom/icon-chip → icon-chip}/index.d.ts +0 -0
  1227. /package/dist/components/{custom/icon-chip → icon-chip}/types.d.ts +0 -0
  1228. /package/dist/components/{custom/icon-tooltip → icon-tooltip}/IconTooltip.vue.d.ts +0 -0
  1229. /package/dist/components/{custom/icon-tooltip → icon-tooltip}/index.d.ts +0 -0
  1230. /package/dist/components/{custom/infinite-scroll → infinite-scroll}/InfiniteScroll.vue.d.ts +0 -0
  1231. /package/dist/components/{custom/infinite-scroll → infinite-scroll}/composables/index.d.ts +0 -0
  1232. /package/dist/components/{custom/infinite-scroll → infinite-scroll}/composables/types.d.ts +0 -0
  1233. /package/dist/components/{custom/infinite-scroll → infinite-scroll}/composables/useInfiniteScroll.d.ts +0 -0
  1234. /package/dist/components/{custom/infinite-scroll → infinite-scroll}/index.d.ts +0 -0
  1235. /package/dist/components/{ui/input → input}/Input.vue.d.ts +0 -0
  1236. /package/dist/components/{ui/input → input}/index.d.ts +0 -0
  1237. /package/dist/components/{custom/instrument-chassis → instrument-chassis}/ChassisDivider.vue.d.ts +0 -0
  1238. /package/dist/components/{custom/instrument-chassis → instrument-chassis}/InstrumentChassis.vue.d.ts +0 -0
  1239. /package/dist/components/{custom/instrument-chassis → instrument-chassis}/index.d.ts +0 -0
  1240. /package/dist/components/{ui/label → label}/Label.vue.d.ts +0 -0
  1241. /package/dist/components/{ui/label → label}/index.d.ts +0 -0
  1242. /package/dist/components/{custom/labeled-field → labeled-field}/LabeledField.vue.d.ts +0 -0
  1243. /package/dist/components/{custom/labeled-field → labeled-field}/LabeledInput.vue.d.ts +0 -0
  1244. /package/dist/components/{custom/labeled-field → labeled-field}/LabeledSelect.vue.d.ts +0 -0
  1245. /package/dist/components/{custom/labeled-field → labeled-field}/LabeledSlider.vue.d.ts +0 -0
  1246. /package/dist/components/{custom/labeled-field → labeled-field}/LabeledSwitch.vue.d.ts +0 -0
  1247. /package/dist/components/{custom/labeled-field → labeled-field}/index.d.ts +0 -0
  1248. /package/dist/{utils/coalesceMetric.d.ts → components/metric/coalesce-metric.d.ts} +0 -0
  1249. /package/dist/components/{custom/metric-badge → metric-badge}/index.d.ts +0 -0
  1250. /package/dist/components/{custom/metric-cell → metric-cell}/index.d.ts +0 -0
  1251. /package/dist/components/{custom/metric-stack → metric-stack}/MetricStack.vue.d.ts +0 -0
  1252. /package/dist/components/{custom/metric-stack → metric-stack}/index.d.ts +0 -0
  1253. /package/dist/components/{ui/notification → notification}/index.d.ts +0 -0
  1254. /package/dist/components/{ui/number-field → number-field}/NumberField.vue.d.ts +0 -0
  1255. /package/dist/components/{ui/number-field → number-field}/NumberFieldContent.vue.d.ts +0 -0
  1256. /package/dist/components/{ui/number-field → number-field}/NumberFieldDecrement.vue.d.ts +0 -0
  1257. /package/dist/components/{ui/number-field → number-field}/NumberFieldIncrement.vue.d.ts +0 -0
  1258. /package/dist/components/{ui/number-field → number-field}/NumberFieldInput.vue.d.ts +0 -0
  1259. /package/dist/components/{ui/number-field → number-field}/index.d.ts +0 -0
  1260. /package/dist/components/{custom/pager-dots → pager-dots}/PagerDots.vue.d.ts +0 -0
  1261. /package/dist/components/{custom/pager-dots → pager-dots}/index.d.ts +0 -0
  1262. /package/dist/components/{custom/pager-dots → pager-dots}/pagerWindow.d.ts +0 -0
  1263. /package/dist/components/{custom/paper-backdrop → paper-backdrop}/index.d.ts +0 -0
  1264. /package/dist/components/{ui/popover → popover}/index.d.ts +0 -0
  1265. /package/dist/components/{ui/progress → progress}/ProgressDefault.vue.d.ts +0 -0
  1266. /package/dist/components/{ui/progress → progress}/ProgressGradient.vue.d.ts +0 -0
  1267. /package/dist/components/{ui/progress → progress}/ProgressSectioned.vue.d.ts +0 -0
  1268. /package/dist/components/{ui/progress → progress}/useProgressGeometry.d.ts +0 -0
  1269. /package/dist/components/{custom/pulse → pulse}/Pulse.vue.d.ts +0 -0
  1270. /package/dist/components/{custom/pulse → pulse}/index.d.ts +0 -0
  1271. /package/dist/components/{ui/radio-group → radio-group}/RadioGroup.vue.d.ts +0 -0
  1272. /package/dist/components/{ui/radio-group → radio-group}/RadioGroupItem.vue.d.ts +0 -0
  1273. /package/dist/components/{ui/radio-group → radio-group}/index.d.ts +0 -0
  1274. /package/dist/components/{custom/search → search}/composables/fuzzySearchIndex.d.ts +0 -0
  1275. /package/dist/components/{custom/search → search}/composables/index.d.ts +0 -0
  1276. /package/dist/components/{custom/search → search}/composables/types.d.ts +0 -0
  1277. /package/dist/components/{custom/search → search}/composables/useFuzzySearch.d.ts +0 -0
  1278. /package/dist/components/{custom/search → search}/index.d.ts +0 -0
  1279. /package/dist/components/{ui/section → section}/Section.vue.d.ts +0 -0
  1280. /package/dist/components/{ui/section → section}/index.d.ts +0 -0
  1281. /package/dist/components/{ui/select → select}/Select.vue.d.ts +0 -0
  1282. /package/dist/components/{ui/select → select}/SelectGroup.vue.d.ts +0 -0
  1283. /package/dist/components/{ui/select → select}/SelectItem.vue.d.ts +0 -0
  1284. /package/dist/components/{ui/select → select}/SelectLabel.vue.d.ts +0 -0
  1285. /package/dist/components/{ui/select → select}/SelectScrollDownButton.vue.d.ts +0 -0
  1286. /package/dist/components/{ui/select → select}/SelectScrollUpButton.vue.d.ts +0 -0
  1287. /package/dist/components/{ui/select → select}/SelectSeparator.vue.d.ts +0 -0
  1288. /package/dist/components/{ui/select → select}/SelectTrigger.vue.d.ts +0 -0
  1289. /package/dist/components/{ui/select → select}/SelectValue.vue.d.ts +0 -0
  1290. /package/dist/components/{ui/select → select}/index.d.ts +0 -0
  1291. /package/dist/components/{ui/separator → separator}/Separator.vue.d.ts +0 -0
  1292. /package/dist/components/{ui/separator → separator}/index.d.ts +0 -0
  1293. /package/dist/components/{ui/skeleton → skeleton}/Skeleton.vue.d.ts +0 -0
  1294. /package/dist/components/{ui/skeleton → skeleton}/index.d.ts +0 -0
  1295. /package/dist/{composables/sortable → components/sortable-list/composables}/dropResolver.d.ts +0 -0
  1296. /package/dist/{composables/sortable → components/sortable-list/composables}/ghostRenderer.d.ts +0 -0
  1297. /package/dist/{composables/sortable → components/sortable-list/composables}/index.d.ts +0 -0
  1298. /package/dist/{composables/sortable → components/sortable-list/composables}/touchGate.d.ts +0 -0
  1299. /package/dist/{composables/sortable → components/sortable-list/composables}/transitionTiming.d.ts +0 -0
  1300. /package/dist/components/{custom/spa-view → spa-view}/SpaView.vue.d.ts +0 -0
  1301. /package/dist/components/{custom/spa-view → spa-view}/index.d.ts +0 -0
  1302. /package/dist/components/{custom/split-chars → split-chars}/index.d.ts +0 -0
  1303. /package/dist/components/{custom/stacked-icons → stacked-icons}/StackedIconGroup.vue.d.ts +0 -0
  1304. /package/dist/components/{custom/stacked-icons → stacked-icons}/index.d.ts +0 -0
  1305. /package/dist/components/{custom/status-dot → status-dot}/StatusDot.vue.d.ts +0 -0
  1306. /package/dist/components/{custom/status-dot → status-dot}/index.d.ts +0 -0
  1307. /package/dist/components/{ui/switch → switch}/Switch.vue.d.ts +0 -0
  1308. /package/dist/components/{ui/switch → switch}/index.d.ts +0 -0
  1309. /package/dist/components/{ui/table → table}/Table.vue.d.ts +0 -0
  1310. /package/dist/components/{ui/table → table}/TableBody.vue.d.ts +0 -0
  1311. /package/dist/components/{ui/table → table}/TableCaption.vue.d.ts +0 -0
  1312. /package/dist/components/{ui/table → table}/TableCell.vue.d.ts +0 -0
  1313. /package/dist/components/{ui/table → table}/TableEmpty.vue.d.ts +0 -0
  1314. /package/dist/components/{ui/table → table}/TableHead.vue.d.ts +0 -0
  1315. /package/dist/components/{ui/table → table}/TableHeader.vue.d.ts +0 -0
  1316. /package/dist/components/{ui/table → table}/TableRow.vue.d.ts +0 -0
  1317. /package/dist/components/{ui/table → table}/index.d.ts +0 -0
  1318. /package/dist/components/{custom/tabs → tabs}/index.d.ts +0 -0
  1319. /package/dist/components/{ui/tags-input → tags-input}/TagsInput.vue.d.ts +0 -0
  1320. /package/dist/components/{ui/tags-input → tags-input}/TagsInputInput.vue.d.ts +0 -0
  1321. /package/dist/components/{ui/tags-input → tags-input}/TagsInputItem.vue.d.ts +0 -0
  1322. /package/dist/components/{ui/tags-input → tags-input}/TagsInputItemDelete.vue.d.ts +0 -0
  1323. /package/dist/components/{ui/tags-input → tags-input}/TagsInputItemText.vue.d.ts +0 -0
  1324. /package/dist/components/{ui/tags-input → tags-input}/index.d.ts +0 -0
  1325. /package/dist/components/{ui/textarea → textarea}/Textarea.vue.d.ts +0 -0
  1326. /package/dist/components/{ui/textarea → textarea}/index.d.ts +0 -0
  1327. /package/dist/components/{custom/timeline → timeline}/ContinuousRail.vue.d.ts +0 -0
  1328. /package/dist/components/{custom/timeline → timeline}/ContinuousTimeline.vue.d.ts +0 -0
  1329. /package/dist/components/{custom/timeline → timeline}/ScrubberTimeline.vue.d.ts +0 -0
  1330. /package/dist/components/{custom/timeline → timeline}/SegmentedTimeline.vue.d.ts +0 -0
  1331. /package/dist/components/{custom/timeline → timeline}/geometry.d.ts +0 -0
  1332. /package/dist/components/{custom/timeline → timeline}/index.d.ts +0 -0
  1333. /package/dist/components/{custom/timeline → timeline}/types.d.ts +0 -0
  1334. /package/dist/components/{ui/toast → toast}/ToastAction.vue.d.ts +0 -0
  1335. /package/dist/components/{ui/toast → toast}/ToastClose.vue.d.ts +0 -0
  1336. /package/dist/components/{ui/toast → toast}/ToastDescription.vue.d.ts +0 -0
  1337. /package/dist/components/{ui/toast → toast}/ToastTitle.vue.d.ts +0 -0
  1338. /package/dist/components/{ui/toast → toast}/Toaster.vue.d.ts +0 -0
  1339. /package/dist/components/{ui/toggle-group → toggle-group}/ToggleGroup.vue.d.ts +0 -0
  1340. /package/dist/components/{ui/toggle-group → toggle-group}/ToggleGroupItem.vue.d.ts +0 -0
  1341. /package/dist/components/{ui/toggle-group → toggle-group}/index.d.ts +0 -0
  1342. /package/dist/components/{ui/toggle-group → toggle-group}/toggleGroupContext.d.ts +0 -0
  1343. /package/dist/components/{ui/tooltip → tooltip}/Tooltip.vue.d.ts +0 -0
  1344. /package/dist/components/{ui/tooltip → tooltip}/TooltipContent.vue.d.ts +0 -0
  1345. /package/dist/components/{ui/tooltip → tooltip}/TooltipProvider.vue.d.ts +0 -0
  1346. /package/dist/components/{ui/tooltip → tooltip}/TooltipTrigger.vue.d.ts +0 -0
  1347. /package/dist/components/{ui/tooltip → tooltip}/index.d.ts +0 -0
  1348. /package/dist/components/{custom/typewriter → typewriter}/TypewriterText.vue.d.ts +0 -0
  1349. /package/dist/components/{custom/typewriter → typewriter}/composables/index.d.ts +0 -0
  1350. /package/dist/components/{custom/typewriter → typewriter}/composables/useTypewriter.d.ts +0 -0
  1351. /package/dist/components/{custom/typewriter → typewriter}/index.d.ts +0 -0
  1352. /package/dist/components/{custom/typewriter → typewriter}/types.d.ts +0 -0
  1353. /package/dist/components/{custom/typewriter → typewriter}/utils/keyboard.d.ts +0 -0
  1354. /package/dist/components/{custom/typewriter → typewriter}/utils/pausePatterns.d.ts +0 -0
  1355. /package/dist/components/{custom/typewriter → typewriter}/utils/timing.d.ts +0 -0
  1356. /package/dist/components/{custom/typewriter → typewriter}/utils/typoStateMachine.d.ts +0 -0
  1357. /package/dist/components/{custom/watercolor-dot → watercolor-dot}/WatercolorDot.vue.d.ts +0 -0
  1358. /package/dist/components/{custom/watercolor-dot → watercolor-dot}/index.d.ts +0 -0
  1359. /package/dist/{utils → composables/glass/procedural}/prng.d.ts +0 -0
  1360. /package/dist/{constants-BWj7DkMn.js → constants-D8lSMkOz.js} +0 -0
  1361. /package/dist/{createContext-Cd23P9j0.js → createContext-BQ1Gy_LB.js} +0 -0
  1362. /package/dist/{flow.glsl-DqEGRpl4.js → flow.glsl-CVqPSj8_.js} +0 -0
  1363. /package/dist/{procedural-color.wgsl-C1Y5PkM6.js → procedural-color.wgsl-ByduxnzV.js} +0 -0
  1364. /package/dist/{scrollReader-rc3Ns_NM.js → scrollReader-DzYqPQ6V.js} +0 -0
  1365. /package/dist/{supportsCssTimeline-BWenxvHU.js → supportsCssTimeline-Ie4xJFbD.js} +0 -0
  1366. /package/dist/{useDragVelocity-CjcfX3dA.js → useDragVelocity-BWcNMCux.js} +0 -0
  1367. /package/dist/{useGlobalDark-B4HO9LXG.js → useGlobalDark-DjKMEQE2.js} +0 -0
  1368. /package/dist/{useInterval-BVUI-sez.js → useInterval-ZATRi-1T.js} +0 -0
  1369. /package/dist/{useLiquidFlex-Cc6PjVJD.js → useLiquidFlex-Ch4exNvN.js} +0 -0
  1370. /package/dist/{useResizeObserver-DdEn3v2f.js → useResizeObserver-DDuoBeBo.js} +0 -0
  1371. /package/dist/{useResolveTokenColor-ChOnCckA.js → useResolveTokenColor-DVT5kwv6.js} +0 -0
  1372. /package/dist/{useTextHighlight-Bma3UlKA.js → useTextHighlight-C46Le9u_.js} +0 -0
  1373. /package/dist/{useTimer-BBLGPXR8.js → useTimer-CkDV8SC2.js} +0 -0
  1374. /package/dist/{useViewportReady-C9pYnn7K.js → useViewportReady-c0isoKL8.js} +0 -0
  1375. /package/dist/{vReveal-CT1KtwZA.js → vReveal-DUmiEkX_.js} +0 -0
  1376. /package/dist/{vSpecular-EX7loENl.js → vSpecular-DlYN0UZy.js} +0 -0
  1377. /package/dist/{writeVelocityWeight-Bh83xZfs.js → writeVelocityWeight-D1rvdxJu.js} +0 -0
package/dist/aurora.js CHANGED
@@ -1,17 +1,17 @@
1
- import { t as e } from "./_plugin-vue_export-helper-gLzyemvl.js";
2
- import { t } from "./usePointerVelocityField-BrkqZFhj.js";
3
- import { a as n, c as r, i, l as a, n as o, o as s, r as c, s as l, t as u } from "./procedural-color.wgsl-C1Y5PkM6.js";
4
- import { t as d } from "./flow.glsl-DqEGRpl4.js";
5
- import { i as f, n as p, r as m, t as h } from "./useGpuSubstrate-Ceet70xq.js";
6
- import { n as g, t as _ } from "./compile-INR_tPk_.js";
7
- import { a as v, i as y, n as ee, o as te, r as ne, t as b } from "./presets-QvYgnFIZ.js";
8
- import { a as re, c as x, i as ie, l as S, o as C, t as w } from "./color-B9jZdhJX.js";
9
- import { t as ae } from "./useIntersectionPause-DO8Vl4gs.js";
10
- import { t as oe } from "./useScrollProgress-A0M6qRl7.js";
11
- import { computed as T, createElementBlock as se, createElementVNode as ce, defineComponent as le, normalizeClass as ue, normalizeStyle as de, onBeforeUnmount as fe, onMounted as pe, openBlock as me, readonly as he, ref as E, unref as D, watch as O } from "vue";
12
- import { interpolateHue as ge, rawOklabToOklch as _e, srgbToOKLab as ve } from "@mkbabb/value.js";
13
- //#region src/components/custom/aurora/constants/shaders/aurora.vert.ts
14
- var ye = "#version 300 es\nin vec2 aPos;\nout vec2 vUv;\nvoid main() {\n vUv = aPos * 0.5 + 0.5;\n gl_Position = vec4(aPos, 0.0, 1.0);\n}", be = "// ── Palette LUT (W5 — OKLCh/OKLab interpolation) ──────────────────────────────\n// The endpoints stay CPU-baked to LINEAR sRGB (the Aras precompute pattern); only\n// the BETWEEN-endpoint interpolation runs in perceptual space. AX.W11 — the ramp\n// itself (the smoothstep ease + the OKLab-rectangular-vs-OKLCh-hue-arc dispatch on\n// uHuePath) is the shared samplePaletteRamp from procedural-color.glsl, the SAME\n// source the WebGPU twin splices; samplePalette here only selects the bracketing\n// stop pair + the raw inter-stop t and hands them to the shared ramp.\nvec3 samplePalette(float id) {\n id = clamp(id, 0.0, 1.0);\n float scaled = id * float(uStopCount - 1);\n int i0 = int(floor(scaled));\n int i1 = min(i0 + 1, uStopCount - 1);\n float t = fract(scaled);\n return samplePaletteRamp(uPalette[i0], uPalette[i1], t, uHuePath);\n}\n\n// ── Nuclei field ──────────────────────────────────────────────────────────\nvoid nucleiField(vec2 p, float t, out float paletteId, out float valueMod) {\n float accumBias = 0.0;\n float accumValue = 0.0;\n float accumW = 0.0;\n for (int i = 0; i < MAX_NUCLEI; i++) {\n if (i >= uNucleiCount) break;\n vec2 posI = uNucleiPos[i]\n + uNucleiDriftRadius[i] * vec2(\n cos(t * uNucleiDrift * K_NUCLEI + uNucleiDriftPhase[i]),\n sin(t * uNucleiDrift * K_NUCLEI + uNucleiDriftPhase[i] * 1.13)\n );\n vec2 diff = p - posI;\n // Anisotropic Gaussian: rotate diff into the nucleus's local frame\n // (major axis along uNucleiAngle), then scale the major-axis component by\n // 1/elongation so the squared distance describes an ellipse. Defaults\n // 1.0/0.0 reduce to the isotropic dot(diff, diff).\n float ca = cos(uNucleiAngle[i]);\n float sa = sin(uNucleiAngle[i]);\n vec2 local = vec2( ca * diff.x + sa * diff.y,\n -sa * diff.x + ca * diff.y);\n float along = local.x / max(uNucleiElong[i], 0.01);\n float across = local.y;\n float d2 = along * along + across * across;\n float r = max(uNucleiRadius[i], 0.01);\n float w = exp(-uSoftmaxBeta * d2 / (r * r));\n accumBias += w * uNucleiPaletteBias[i];\n accumValue += w * uNucleiValueBias[i];\n accumW += w;\n }\n paletteId = accumBias / max(accumW, 1e-4);\n valueMod = accumValue / max(accumW, 1e-4);\n\n // Palette drift — slow global paletteId breathe between adjacent stops. The\n // rate rides K_PAL (perceptible ~30–60s hue cycle at the default coefficient);\n // the amplitude lifts the authored coefficient into a 0.03..0.06 paletteId band\n // so the palette visibly travels rather than dithering within one stop.\n float palAmp = clamp(uPaletteDrift * 6.0, 0.0, 0.06);\n paletteId += palAmp * sin(t * uPaletteDrift * K_PAL);\n paletteId = clamp(paletteId, 0.0, 1.0);\n}\n", xe = "// ── Flow field ────────────────────────────────────────────────────────────\n// Structure-tensor prototype (body defined post-sampleBase in the mediums block).\n// Returns vec3(dir.x, dir.y, coherence) — the minor-eigenvector tangent + A.\nvec3 structureTensorField(vec2 p, float t, vec2 fallbackDir);\n\nvec2 flowField(vec2 p, float t) {\n vec2 dir = vec2(1.0, 0.0);\n if (uFlowPattern == 1) {\n // radial\n dir = normalize(p - uFlowFocal + 1e-4);\n } else if (uFlowPattern == 2) {\n // swirl — tangent to radial\n vec2 rad = normalize(p - uFlowFocal + 1e-4);\n dir = vec2(-rad.y, rad.x);\n } else if (uFlowPattern == 3) {\n // diagonal\n float a = radians(uFlowAngle);\n dir = vec2(cos(a), sin(a));\n } else if (uFlowPattern == 4) {\n // multi — curl-noise driven\n float n = fbm(p * 2.0 + t * 0.02);\n float a = n * 6.2831;\n dir = vec2(cos(a), sin(a));\n } else if (uFlowPattern == 5) {\n // tensor / ETF — the color field's OWN edge-tangent flow (AW.W4.1). The\n // diagonal angle seeds the smooth fallback the coherence-weighted blend\n // relaxes toward in low-structure zones. Returns directly (no curl/cursor\n // post-mix — the tensor field already carries the structure orientation;\n // the cursor warp still drives the underlying color field in domainWarp).\n float a = radians(uFlowAngle);\n vec2 fallback = vec2(cos(a), sin(a));\n return structureTensorField(p, t, fallback).xy;\n }\n // curl — perturb by noise. Radial gets much less curl so rays stay clean.\n if (uFlowCurl > 0.0) {\n float n = fbm(p * 3.0) - 0.5;\n float curlAmt = uFlowCurl;\n if (uFlowPattern == 1) curlAmt *= 0.25; // radial: preserve ray clarity\n if (uFlowPattern == 2) curlAmt *= 0.55; // swirl: allow moderate curl\n float a = atan(dir.y, dir.x) + n * 3.14159 * curlAmt;\n dir = vec2(cos(a), sin(a));\n }\n // cursor influence — swirl around the cursor position\n if (uCursorStrength > 0.001) {\n vec2 toCur = uCursor - p;\n float d = length(toCur);\n float r = max(uCursorRadius, 0.01);\n float w = exp(-(d * d) / (r * r * 0.5));\n // swirl tangent\n vec2 tangent = vec2(-toCur.y, toCur.x) / max(d, 1e-4);\n float a0 = atan(dir.y, dir.x);\n float a1 = atan(tangent.y, tangent.x);\n // blend angle\n float da = a1 - a0;\n da = atan(sin(da), cos(da)); // wrap to [-pi, pi]\n float a = a0 + da * w * uCursorStrength;\n dir = vec2(cos(a), sin(a));\n }\n // AW.W8.1 — velocity-reactive swirl-BURST: a fast flick (uCursorBurst, decaying\n // over ~1s) injects a transient flow bias along the pointer velocity, distinct from\n // the steady attraction above (the stateless swirl is SUPERSEDED by this form). The\n // burst is gated by the master tempo scalar on the CPU side (it decays to 0 under\n // PRM/pause), so this term cannot leak motion under reduced-motion.\n if (uCursorBurst > 0.001) {\n vec2 toCur = uCursor - p;\n float d = length(toCur);\n float r = max(uCursorRadius, 0.01);\n float w = exp(-(d * d) / (r * r * 0.7));\n // Bias the flow toward the velocity direction, scaled by the decaying burst.\n vec2 velDir = uCursorVelocity / max(length(uCursorVelocity), 1e-4);\n float a0 = atan(dir.y, dir.x);\n float a1 = atan(velDir.y, velDir.x);\n float da = atan(sin(a1 - a0), cos(a1 - a0));\n float a = a0 + da * w * uCursorBurst * 0.8;\n dir = vec2(cos(a), sin(a));\n }\n return dir;\n}\n", Se = "// Khronos PBR-Neutral tonemap (hue + saturation preserving)\nvec3 aces(vec3 color) {\n const float startCompression = 0.8 - 0.04;\n const float desaturation = 0.15;\n float x = min(color.r, min(color.g, color.b));\n float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n color -= offset;\n float peak = max(color.r, max(color.g, color.b));\n if (peak < startCompression) return clamp(color, 0.0, 1.0);\n float d = 1.0 - startCompression;\n float newPeak = 1.0 - d * d / (peak + d - startCompression);\n color *= newPeak / peak;\n float g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);\n return clamp(mix(color, newPeak * vec3(1.0), g), 0.0, 1.0);\n}\n", Ce = "// ── Curved swept brushstroke primitive ────────────────────────────────────\n// A stroke is a curved spine from A to B with quadratic bulge K (sideways offset\n// at midpoint). Width varies along length via a shape profile. Edge is ragged\n// (bristle-modulated), ends are rounded blobs, inside has streak modulation.\n//\n// For pixel p, we invert an approximate projection onto the curved spine:\n// 1) project p onto straight AB axis -> along0, cross0\n// 2) at parameter along0, spine offset = 4·K·along0·(1-along0) perpendicular\n// 3) cross = cross0 - spineOffset, refine along one iteration\n// Coverage blends paint atop col based on per-stroke color sampled from the\n// underlying base at spine midpoint — so overlapping strokes from different\n// palette regions meet at hard, ragged demarcations.\n\nstruct StrokeHit {\n float coverage; // 0..1\n vec3 color;\n float alongT; // 0..1 along spine, for internal modulation\n float crossN; // cross distance / current half-width, signed\n float edgeN; // distance to edge in half-widths (0 = at edge, 1 = at spine)\n};\n\nStrokeHit noHit() { return StrokeHit(0.0, vec3(0.0), 0.0, 0.0, 0.0); }\n\nvec2 rotateDir(vec2 dir, float angle) {\n float ca = cos(angle), sa = sin(angle);\n return vec2(dir.x * ca - dir.y * sa, dir.x * sa + dir.y * ca);\n}\n\nvec2 safeDir(vec2 dir) {\n float len = length(dir);\n return len > 1e-4 ? dir / len : vec2(1.0, 0.0);\n}\n\n// Shape profile along the stroke. type:\n// 0 tapered — thin-fat-thin (classic brush)\n// 1 load-drag — fat start, tapers to a point\n// 2 dab — ellipse-like, round center\n// 3 even — near-constant, slight end taper\n// 4 comma — van-Gogh atomic dab: ASYMMETRIC taper, fat near one end and\n// drawn to a fine point at the other (the divisionist crescent\n// mark). The width peak sits off-centre (~0.32) so the two ends\n// taper at DIFFERENT rates — a loaded round head + a dragged tail.\nfloat strokeShape(float t, int type) {\n t = clamp(t, 0.0, 1.0);\n if (type == 1) {\n // loaded at t=0, tapering\n return pow(1.0 - t, 0.55) * smoothstep(0.0, 0.08, t);\n } else if (type == 2) {\n // dab / blob\n float d = t - 0.5;\n return exp(-d * d * 12.0);\n } else if (type == 3) {\n // mostly even, slight end softening\n return smoothstep(0.0, 0.08, t) * smoothstep(1.0, 0.92, t) * 0.95 + 0.05;\n } else if (type == 4) {\n // comma / crescent — width peaks at ~0.32 then drags to a fine tail. The two\n // sides of the peak fall at different exponents (a fat round head, a long thin\n // tail), so the mark reads as a directional van-Gogh comma, not a symmetric oval.\n float peak = 0.32;\n float head = smoothstep(0.0, peak, t); // rounded loaded head\n float tail = pow(clamp((1.0 - t) / (1.0 - peak), 0.0, 1.0), 1.6); // dragged thin tail\n return clamp(min(head, tail) * 1.04, 0.0, 1.0);\n }\n // 0 tapered\n return smoothstep(0.0, 0.22, t) * smoothstep(1.0, 0.78, t);\n}\n\n// A single curved stroke.\n// a, b — endpoints\n// halfW — base half-width (world units)\n// bulge — signed perpendicular midpoint offset, in world units\n// shapeType — 0..3\n// bristleFreq — spatial frequency of edge raggedness\n// bristleAmp — 0..0.5 fraction of halfW chewed away at edge extrema\n// streakSeed — uniqueness seed for internal streaks\n// colAtMid — pre-sampled color at midpoint\nStrokeHit curvedStroke(vec2 p, vec2 a, vec2 b, float halfW,\n float bulge, int shapeType,\n float bristleFreq, float bristleAmp,\n float streakSeed, vec3 colAtMid) {\n vec2 ab = b - a;\n float L = length(ab);\n if (L < 1e-5) return noHit();\n vec2 tang = ab / L;\n vec2 norm = vec2(-tang.y, tang.x);\n\n vec2 rel = p - a;\n float along0 = dot(rel, tang) / L; // straight projection 0..1 along AB\n float cross0 = dot(rel, norm); // signed cross\n\n // Spine sideways offset due to bulge (parabolic)\n float bend = 4.0 * bulge * along0 * (1.0 - along0);\n float cross1 = cross0 - bend;\n\n // One refinement step: as the spine bends, the closest-point along shifts.\n // Spine tangent differs from straight tangent; first-order correction:\n float dBend = 4.0 * bulge * (1.0 - 2.0 * along0); // d(bend)/d(along)\n float along1 = along0 + (cross1 * dBend) / (L * (1.0 + dBend * dBend / (L * L)));\n\n // Bristle-ragged edge: half-width gets chewed by 1D noise along the spine\n float edgeNoise = fbm(vec2(along1 * bristleFreq, streakSeed * 7.3)) - 0.5;\n float edgeNoise2 = fbm(vec2(along1 * bristleFreq * 2.3, streakSeed * 3.1 + 17.0)) - 0.5;\n float edgeMod = 1.0 - bristleAmp * (0.6 + 0.4 * edgeNoise) * (0.5 + edgeNoise2);\n\n // Width profile along the stroke\n float shape = strokeShape(along1, shapeType);\n float halfWNow = halfW * shape * edgeMod;\n\n // Inside-segment coverage\n float cov = 0.0;\n if (along1 >= 0.0 && along1 <= 1.0 && halfWNow > 1e-6) {\n float cn = abs(cross1) / halfWNow;\n // fwidth-derived AA: half-width from the field's screen-space gradient so the\n // edge holds ~1px regardless of zoom/DPR (mirrors metaball.frag.ts:252-255).\n float aaC = max(fwidth(cn), 1e-6);\n cov = 1.0 - smoothstep(1.0 - aaC, 1.0 + aaC, cn);\n }\n\n // End-cap blobs (rounded tips, not perpendicular cuts)\n float capA = 0.0, capB = 0.0;\n {\n vec2 capCenterA = a + norm * (bulge * 0.0); // at a\n vec2 capCenterB = a + tang * L + norm * bend * 0.0 + norm * 0.0; // at b; bend is 0 at endpoints\n capCenterB = b;\n float endShapeA = strokeShape(0.02, shapeType);\n float endShapeB = strokeShape(0.98, shapeType);\n float rA = halfW * endShapeA * (0.9 + 0.2 * fbm(vec2(streakSeed * 13.0)));\n float rB = halfW * endShapeB * (0.9 + 0.2 * fbm(vec2(streakSeed * 19.0 + 5.0)));\n float dA = length(p - capCenterA);\n float dB = length(p - capCenterB);\n // fwidth-derived AA on the clean Euclidean cap distances (mirrors metaball.frag.ts:252-255).\n float aaA = max(fwidth(dA), 1e-6);\n float aaB = max(fwidth(dB), 1e-6);\n capA = 1.0 - smoothstep(rA - aaA, rA + aaA, dA);\n capB = 1.0 - smoothstep(rB - aaB, rB + aaB, dB);\n // Only apply caps if we're BEYOND the segment; otherwise the segment wins.\n capA *= (along1 < 0.05) ? 1.0 : 0.0;\n capB *= (along1 > 0.95) ? 1.0 : 0.0;\n }\n\n float coverage = max(cov, max(capA, capB));\n if (coverage < 0.002) return noHit();\n\n // Edge distance (for impasto later): 0 at edge, 1 at spine\n float edgeDist = halfWNow > 1e-6 ? clamp(1.0 - abs(cross1) / halfWNow, 0.0, 1.0) : 0.0;\n\n return StrokeHit(\n coverage,\n colAtMid,\n clamp(along1, 0.0, 1.0),\n halfWNow > 1e-6 ? cross1 / halfWNow : 0.0,\n edgeDist\n );\n}\n\n// The painterly STROKE mediums (those that deposit via paintStrokeLayers/paintOver):\n// oil (3), van-Gogh (5), oil-pastel (6). For these the stroke OVER-composite runs in\n// OKLab so overlapping complementaries mix through a chromatic path, not the linear-\n// RGB grey mud; the smooth/atmospheric pole never reaches paintOver so it pays nothing.\nbool isPainterlyStroke() {\n return uMedium == 3 || uMedium == 5 || uMedium == 6;\n}\n\n// OKLab OVER-composite: lerp L,a,b of the over-color toward the under-color (the\n// Ottosson matrices spliced from procedural-color.glsl.ts — no new color math). Two\n// complementary-hued strokes overlapping transition through OKLab, where the midpoint\n// holds chroma, instead of the linear mix() that desaturates toward grey (slice 8 F2).\nvec3 paintOverOklab(vec3 under, vec3 over, float alpha) {\n vec3 labU = linOklab(under);\n vec3 labO = linOklab(over);\n return max(oklabToLinearSrgb(mix(labU, labO, alpha)), vec3(0.0));\n}\n\n// Composite stroke over col with internal streaking + ACCUMULATE paint HEIGHT.\n// streakAmp — 0..0.2 how much internal streaks darken/lighten\n// impastoAmp — 0..1 paint-thickness contribution (the height the relight reads)\n// hardness — 0..1 how crisp the compositing transition is (1 = razor, 0 = creamy)\n//\n// AW.W4.2 — the fixed-RGB edge rim (the phantom upper-left light) is RETIRED. Each\n// stroke now deposits PAINT HEIGHT into the height accumulator (coverage x per-stroke\n// thickness, perturbed by the bristle/streak fbm for ridges/grooves); mediumOil\n// derives a normal from the accumulated height gradient (dFdx/dFdy) and relights it\n// once with the movable uLightDir source (relightImpasto), in linear before aces().\n//\n// AX.W13 — the internal streak now perturbs HUE + CHROMA in OKLCh (not value-only),\n// so a single stroke carries a small hue gradient (broken color at the ATOM level —\n// adjacent strokes shimmer like real impasto, not flat stamped swatches; slice 8 F5);\n// and the OVER-composite runs in OKLab on the painterly stroke mediums so overlapping\n// complementaries mix as pigment, not the linear-mix grey (slice 8 F2).\n// impastoFloor — the per-stroke height-crown floor: oil's 0.4+0.6*edgeN reads\n// floor=0.4 (the crown tapers to 40% at the stroke edge); the van-Gogh\n// profile passes floor=1.0 so each atomic dab catches a FULL-height\n// glint (scope item 1d). The crown magnitude is floor + (1-floor)*edgeN.\nvoid paintOver(inout vec3 col, inout float height, StrokeHit s,\n float streakFreq, float streakAmp,\n float impastoAmp, float hardness, float streakSeed,\n float impastoFloor) {\n if (s.coverage < 0.002) return;\n float strokeOpacity = clamp(uStrokeAmount, 0.0, 1.0);\n if (strokeOpacity <= 0.001) return;\n vec3 c = s.color;\n\n // Internal streaks — fbm along spine, modulated by cross position. Gives\n // the loaded-brush look: some bristles carry more pigment than others.\n float streakA = fbm(vec2(s.alongT * streakFreq, s.crossN * 2.7 + streakSeed));\n float streakB = fbm(vec2(s.alongT * streakFreq * 0.6 + streakSeed * 3.7, s.crossN * 4.1));\n float streak = 0.6 * (streakA - 0.5) + 0.4 * (streakB - 0.5);\n\n // ── WITHIN-stroke OKLCh broken color (AX.W13, slice 8 F5). The streak fBm perturbs\n // the stroke's HUE + CHROMA along alongT/crossN, seeded per-stroke, so a single\n // stroke reads a small hue gradient (the atom-level broken-color shimmer). Value is\n // carried by the same streak so the loaded-brush light/dark survives. Gated to the\n // painterly stroke mediums + uBrokenColor (the smooth pole keeps the cheap value-only\n // streak). A second decorrelated fBm drives the hue axis so hue ≠ a scaled value.\n float hueStreak = fbm(vec2(s.alongT * streakFreq * 0.45 + streakSeed * 5.3,\n s.crossN * 1.9 + streakSeed * 1.7)) - 0.5;\n if (isPainterlyStroke() && uBrokenColor > 0.001) {\n vec3 lch = oklabToOklch(linOklab(c));\n // ±~10° within-stroke hue swing + ±~9% chroma, scaled by uBrokenColor. Smaller\n // than the per-stroke cell jitter (brokenColorJitter) — this is the intra-stroke\n // gradient layered on top of the per-cell pigment patch.\n lch.z += hueStreak * (20.0 * PI / 180.0) * uBrokenColor;\n lch.y = max(lch.y * (1.0 + (streak) * 0.18 * uBrokenColor), 0.0);\n c = max(oklabToLinearSrgb(oklchToOklab(lch)), vec3(0.0));\n }\n // Value streak (the loaded-brush light/dark across the bristles) — kept for every\n // medium that reaches paintOver (the smooth pole never does). The along-spine value\n // modulation is the loaded-brush light/dark that gives each stroke its OWN directional\n // luminance band — the structure-tensor signal a low-contrast color field (a uniform-hue\n // oil field) has no other source for (the §4.2 anisotropy lift on the flat-palette case).\n c *= 1.0 + streak * streakAmp * 3.2;\n\n // Cross-stroke ridge/valley shading — a catch-light along the spine centre, darkening to\n // the stroke edges. This is the strongest DIRECTIONAL luminance cue: it carves a bright\n // ridge down the stroke's length and dark grooves between adjacent strokes, so a field of\n // parallel strokes reads as parallel light/dark bands (the high-A van-Gogh signature) even\n // where the underlying colour is flat. s.edgeN is 0 at the edge, 1 at the spine.\n float ridgeShade = smoothstep(0.0, 0.55, s.edgeN);\n c *= 1.0 + (ridgeShade - 0.5) * 0.30;\n\n float softLimit = mix(0.35, 0.98, hardness);\n float alpha = smoothstep(0.0, 1.0 - softLimit, s.coverage) * strokeOpacity;\n // OKLab OVER-composite on the painterly stroke mediums (overlap mixes as pigment,\n // not grey); the smooth pole never reaches paintOver, so it keeps the cheap path.\n col = isPainterlyStroke() ? paintOverOklab(col, c, alpha) : mix(col, c, alpha);\n\n // ── Accumulate paint HEIGHT (AW.W4.2). Thickness peaks at the stroke spine and\n // falls toward the impastoFloor at the edge (edgeN: 0=edge, 1=spine), perturbed by\n // the bristle streak so ridges/grooves form. The relight reads the gradient of this\n // field. The van-Gogh profile's floor=1.0 gives every atomic dab a full-height crown.\n float ridge = 0.7 + 0.3 * (streak + 0.5);\n float crown = impastoFloor + (1.0 - impastoFloor) * s.edgeN;\n height += s.coverage * impastoAmp * crown * ridge * alpha;\n}\n\n// AW.W4.2 — relight the accumulated paint height. Derive a normal from the height\n// gradient (dFdx/dFdy — derivatives are in-pattern; fwidth is already used for AA),\n// then apply diffuse + Blinn specular from the movable uLightDir/uLightColor source.\n// LINEAR-space lighting BEFORE aces() (the tonemap/OETF stay locked); thin strokes\n// inherit a low shininess, thick impasto raises it (high-height ridges catch a sharp\n// glint). canvasBase is the tooth height so the canvas weave also catches the light.\nvec3 relightImpasto(vec3 col, float height, float canvasBase) {\n float h = height + canvasBase;\n // Height-gradient normal. heightScale trades relief depth for surface flatness.\n float heightScale = 6.0;\n vec3 N = normalize(vec3(-dFdx(h) * 40.0, -dFdy(h) * 40.0, 1.0 / heightScale));\n vec3 L = normalize(uLightDir);\n vec3 V = vec3(0.0, 0.0, 1.0); // view straight on\n vec3 H = normalize(L + V);\n float diff = max(dot(N, L), 0.0);\n // Thick impasto → high shininess (sharp glint); thin paint → broad soft sheen.\n float shininess = mix(8.0, 64.0, clamp(height * 2.0, 0.0, 1.0));\n float spec = pow(max(dot(N, H), 0.0), shininess);\n // Modulate the lit terms by how much paint sits here (no relief on bare ground).\n float relief = clamp(h * 1.5, 0.0, 1.0);\n vec3 lit = col * (1.0 + uImpasto * relief * (diff - 0.5) * 0.5 * uLightColor);\n // The specular glint is gated to ACCUMULATED-thick paint (height²) — a per-fine-stroke\n // sharp glint on every thin fill dab read as bright isotropic SPECKLE that buried the\n // directional stroke bands (the §4.2 anisotropy / §4.3 slope sink on the low-contrast\n // oil field). Only where real impasto has built up does the raked glint fire, so the\n // highlight tracks the macro ridges, not the fine speckle.\n float specGate = clamp(height, 0.0, 1.0);\n lit += uImpasto * relief * spec * specGate * 0.5 * uLightColor;\n return lit;\n}\n\n// Best-of-9-neighbor placement: sample 3x3 surrounding cells and take the\n// stroke that covers this pixel most. Breaks the grid by per-cell jitter and\n// sparse density via noise thresholding.\n// energyGrade — the SBR energy-grade magnitude (0 = none, the oil/oil-pastel\n// baseline; 1 = the full van-Gogh Starry-Night cascade — long\n// confident strokes in the lights/coherent zones, short dabs in\n// the darks/flat zones). The van-Gogh profile carries 1.0 (the\n// energy grade is a PROFILE field, not a buried uMedium==5 branch).\nStrokeHit bestOil(vec2 p, float cellSize, float lenMul, float halfWMul,\n float jitterAmt, float density, int shapeType,\n float bristleAmp, vec2 flow, float t, float seed,\n float energyGrade) {\n vec2 cell = floor(p / cellSize);\n\n StrokeHit best = noHit();\n // 3x3 neighborhood\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cc = cell + vec2(float(dx), float(dy));\n vec2 hh = hash22(cc + seed) - 0.5;\n // Density gate — noise threshold; sparse placement.\n float gate = hash21(cc * 1.7 + seed * 0.3);\n if (gate > density) continue;\n\n vec2 center = (cc + 0.5 + hh * jitterAmt) * cellSize;\n\n // Per-stroke direction source — the AW.W4.1 strokeOrient switch:\n // uStrokeOrient==0 (flow) — the layer-provided hand-authored flowField.\n // uStrokeOrient==1 (tensor) — the structure-tensor minor eigenvector at the\n // cell center (the color field's edge-tangent),\n // so strokes hug the color zones (van Gogh).\n // coh carries the per-cell coherence A for the W4.3 energy grading (long\n // confident strokes where structure is coherent, stubby dabs in flat zones).\n vec2 f;\n float coh = 1.0;\n if (uStrokeOrient == 1) {\n vec3 tf = structureTensorField(center, t, safeDir(flow));\n f = safeDir(tf.xy);\n coh = tf.z;\n } else {\n f = safeDir(flow);\n }\n // Per-stroke deterministic local perturbation so alternate stroke layers stay\n // live. Tensor strokes get FAR less angular jitter (the field already orients them\n // — over-jittering the tensor strokes scatters their directions and the rendered\n // field reads isotropic, the §4.2 anisotropy floor). The flow-oriented (non-tensor)\n // strokes keep the full jitter (they have no per-cell orientation source).\n float jScale = (uStrokeOrient == 1) ? 0.15 : 1.0;\n float angJ = (hash21(cc + seed + 11.0) - 0.5) * 0.9 * jScale; // +/- 0.45/0.07 rad\n float curlScale = (uStrokeOrient == 1) ? 0.30 : 1.0;\n float localCurl = (fbm(center * (2.6 + seed * 0.11) + seed * 1.9) - 0.5) * 0.55 * uFlowCurl * curlScale;\n vec2 dir = rotateDir(f, angJ + localCurl);\n\n // AX.W13 — the SBR energy grade is a PROFILE field (energyGrade), not a buried\n // uMedium==5 branch. The van-Gogh profile passes energyGrade=1.0 (the full\n // Starry-Night cascade); oil/oil-pastel pass 0.0 (uniform length). The grade\n // modulates stroke length by local luminance (bright → long confident strokes,\n // dark → short dabs, the Kolmogorov/Batchelor congruence) AND by coherence\n // (coherent zones → long, flat → stubby), lerped in by energyGrade so a profile\n // can dial the cascade from off (0) to full (1).\n float energy = 1.0;\n if (energyGrade > 0.001) {\n float luma = clamp(dot(sampleBase(center, t), W_LUMA), 0.0, 1.0);\n float graded = mix(0.5, 1.5, luma) * mix(0.6, 1.0, coh);\n energy = mix(1.0, graded, energyGrade);\n }\n\n float lenV = cellSize * lenMul * (0.65 + 0.55 * hash21(cc + seed + 23.0)) * energy;\n float halfW = cellSize * halfWMul * (0.70 + 0.55 * hash21(cc + seed + 41.0));\n float bulge = (hash21(cc + seed + 53.0) - 0.5) * lenV * 0.35;\n\n vec2 a = center - dir * (lenV * 0.5);\n vec2 b = center + dir * (lenV * 0.5);\n\n vec3 colMid = brokenColorJitter(\n sampleBase(center, t),\n hash21(cc + seed + 89.0),\n hash21(cc * 2.3 + seed + 97.0),\n 1.0\n );\n\n StrokeHit h = curvedStroke(p, a, b, halfW, bulge, shapeType,\n 7.0, bristleAmp,\n hash21(cc + seed + 67.0), colMid);\n if (h.coverage > best.coverage) best = h;\n }\n }\n return best;\n}\n", we = "// ── Van-Gogh — DEDICATED atomic-dab body (W-AUR-VANGOGH-REBUILD) ─────────────\n// REBUILT FROM FIRST PRINCIPLES. The prior path routed van-Gogh through the shared\n// oil paintStrokeMedium cascade — four DENSE layers of LONG-THIN tensor-oriented\n// strokes (lenMul up to 5.2, widMul 0.22) hugging a continuous coherent field. Packed\n// that tight, thin strokes that follow continuous iso-bands MERGE into smooth flowing\n// filaments — the \"marbled flow-bands\" read (a spirograph/fingerprint, not impasto),\n// AND the per-cell 8-tap structure tensor × 4 layers × 9 cells = ~324 sampleBase/pixel\n// made it run at ~4fps. Van Gogh's sky is NOT continuous flow — it is DISCRETE, SHORT,\n// LOADED comma dabs, separated by visible ground, queued into swirl ROWS.\n//\n// The rebuild is a purpose-built two-layer DAB pass, disjoint from the oil cascade:\n// • orientation from the analytic SWIRL flowField (van-Gogh skies ARE swirl rows) +\n// per-cell angular jitter — NOT the expensive per-cell tensor (the lag source, and\n// the marble source: a jittered discrete dab can NOT merge into a continuous\n// filament the way a tensor-locked thin stroke does).\n// • SHORT comma dabs (len/wid ≈ 2.6 : 1 — a loaded crescent mark, not a 10:1\n// filament), so each reads as a SEPARABLE atom.\n// • SPARSE placement with visible inter-dab ground (density ≈ 0.42), over a darkened\n// swirl underpainting (the Starry-Night visible ground the bright dabs read over).\n// • a single sampleBase per cell + OKLCh broken-color jitter (pigment shimmer);\n// full-height impasto crown per dab (each catches its own raked glint).\n// This is ~2 layers × 9 cells × ~1 sampleBase ≈ 20/pixel (a ~16× cost cut, ~60fps), and\n// jittered short dabs CANNOT marble.\n\n// One atomic comma dab — a CLEAN analytic crescent SDF (NOT the oil curvedStroke).\n// The oil curvedStroke's spine-projection + rounded end-caps + fwidth-AA + bristle\n// edge each leave a thin sub-pixel skirt, and a field of those skirts over open ground\n// abuts into a faint network of SEAM LINES. A van-Gogh dab needs none of that\n// machinery — it is a short oriented capsule (rounded line segment) whose half-width\n// tapers along its length (the loaded-head → dragged-tail comma). The capsule SDF is\n// derivative-free (smoothstep AA against the analytic distance), so no fwidth skirt, no\n// best-of-9 seam. Returns a StrokeHit (coverage/color/alongT/edgeN) for paintOver.\n// cellSize — dab cell pitch (UV units); lenMul/widMul — dab aspect off the cell;\n// density — placement gate (sparse → visible gaps); seed — layer decorrelation.\nStrokeHit vangoghDab(vec2 p, float cellSize, float lenMul, float widMul,\n float density, float jitterAmt, float angJitter,\n vec2 flow, float t, float seed) {\n vec2 cell = floor(p / cellSize);\n StrokeHit best = noHit();\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cc = cell + vec2(float(dx), float(dy));\n // Sparse density gate — leaves visible canvas ground between dabs (atomicity).\n if (hash21(cc * 1.7 + seed * 0.3) > density) continue;\n vec2 jit = (hash22(cc + seed) - 0.5) * jitterAmt;\n vec2 center = (cc + 0.5 + jit) * cellSize;\n\n // Orientation: the analytic swirl flow at the cell center + per-cell angular\n // jitter (so adjacent dabs FAN — the divisionist scatter that keeps the dabs from\n // locking into perfectly-concentric rows) + a flow-noise curl wobble.\n float ang = (hash21(cc + seed + 11.0) - 0.5) * angJitter;\n float curl = (fbm(center * 3.1 + seed * 1.9) - 0.5) * (0.18 + 0.3 * uFlowCurl);\n vec2 dir = rotateDir(safeDir(flow), ang + curl);\n\n // SHORT comma — len ≈ the cell pitch (a contained dab, not a tiling filament).\n float len = cellSize * lenMul * (0.82 + 0.30 * hash21(cc + seed + 23.0));\n float halfW = max(cellSize * widMul * (0.86 + 0.28 * hash21(cc + seed + 41.0)), 0.010);\n\n // Local dab frame: along = projection onto the dab axis (centred 0), perp = cross.\n vec2 rel = p - center;\n float along = dot(rel, dir);\n float perp = dot(rel, vec2(-dir.y, dir.x));\n // The comma TAPER: half-width peaks ~1/3 from the loaded head and drags to a fine\n // tail (the asymmetric crescent). u in [0,1] along the dab from head to tail.\n float halfLen = len * 0.5;\n float u = clamp((along + halfLen) / max(len, 1e-5), 0.0, 1.0);\n float head = smoothstep(0.0, 0.30, u); // rounded loaded head\n float tail = pow(clamp((1.0 - u) / 0.70, 0.0, 1.0), 1.3); // dragged thin tail\n float prof = clamp(min(head, tail) * 1.05, 0.0, 1.0);\n float wNow = halfW * prof;\n // A gentle comma CURVE — bow the spine sideways so the mark reads as a crescent.\n float bowAmt = (hash21(cc + seed + 53.0) - 0.5) * halfW * 1.4;\n float spine = bowAmt * sin(u * PI); // 0 at ends, max mid\n float d = abs(perp - spine);\n // Derivative-free AA: a fixed fraction of the dab width (no fwidth skirt). Coverage\n // is 1 in the dab body, smoothly 0 at the edge; outside the [head,tail] span wNow→0\n // so the dab self-terminates with no end-cap blob.\n float aa = max(halfW * 0.45, 0.002);\n float cov = (wNow > 1e-5) ? (1.0 - smoothstep(wNow - aa, wNow + aa, d)) : 0.0;\n if (cov < 0.004) continue;\n\n // One sampleBase per cell + OKLCh broken-color jitter (pigment patch shimmer). The\n // dab pigment is chroma-boosted (saturate3 1.22) AND value-lifted (×1.14) at the\n // SOURCE — the loaded brush mark deposits BRIGHTER + more saturated pigment than the\n // base field, so the loaded-mark pixels lift BOTH the §4.1 colourfulness AND the field\n // mean-luma. The higher mean raises the gap-fraction threshold (meanLum·0.6) so the\n // moderate-depth inter-dab ground falls below it (the gap-fraction atomicity read is\n // DECOUPLED from the ground floor depth — the ground can stay only moderately dark, so\n // the §4.3 slope is NOT over-steepened, while the bright dabs manufacture the gap). The\n // dark ground is untouched, so this lifts C + gap WITHOUT a band-conflicting deep ground.\n vec3 colMid = brokenColorJitter(\n saturate3(sampleBase(center, t), 1.22),\n hash21(cc + seed + 89.0),\n hash21(cc * 2.3 + seed + 97.0),\n 1.0\n );\n\n // edgeN: 1 at the spine, 0 at the edge (the impasto crown reads it).\n float edgeN = (wNow > 1e-5) ? clamp(1.0 - d / wNow, 0.0, 1.0) : 0.0;\n if (cov > best.coverage) {\n best = StrokeHit(cov, colMid, u, (wNow > 1e-5 ? (perp - spine) / wNow : 0.0), edgeN);\n }\n }\n }\n return best;\n}\n\nvec3 mediumVangogh(vec3 col, vec2 p, float t) {\n vec3 result = col;\n float height = 0.0;\n\n // The swirl flow basis (van-Gogh sky = swirl rows). Computed ONCE per pixel.\n vec2 flow = flowField(p, t);\n\n // Dab cell pitch in UV [0,1]. CHUNKY, SEPARABLE marks — the big layer is ~1/14 of\n // the frame so it reads as a distinct loaded brush dab (not a fine speckle, not a\n // screen-spanning filament). uStrokeScale (authored ~110) modulates the pitch\n // INVERSELY (higher = finer dabs) around the ~0.07 chunky default; clamped so the\n // dab never collapses to noise or balloons past one screen. uStrokeAnisotropy\n // stretches the comma aspect (longer, more directional marks).\n float pitch = clamp(7.0 / max(uStrokeScale, 20.0), 0.044, 0.12);\n // The dab LENGTH ≈ the cell pitch (lenAniso ~1.2-1.7) so a dab sits WITHIN its cell\n // and leaves visible ground around it — a longer dab (lenMul > 2) spans neighbour\n // cells and tiles the field into continuous coverage (no gaps, the gap-fraction floor\n // miss + the marble). Narrow width keeps it a directional crescent, not a wide shard.\n // lenAniso/widAniso — the comma aspect. The W-AUR-VANGOGH-CONFIG reconcile lengthened\n // the comma (1.25-1.75 → 1.5-2.0) and THINNED it (0.40-0.30 → 0.32-0.24): the rebuilt\n // dabs measured §4.2 structure-tensor anisotropy A=0.699, BELOW the reference band\n // floor 0.732 (the dabs read slightly too short-fat → locally isotropic, dragging mean\n // A down). A LONGER, THINNER comma hugs the swirl-flow tangent more strongly so the\n // rendered field reads coherent the way the tensor metric measures it (A lift), while\n // the thinner width LEAVES MORE inter-dab ground (the gap-fraction atomicity read is\n // preserved, not closed). The length stays ≈ the cell pitch so each dab remains a\n // CONTAINED separable mark, not a tiling filament.\n float lenAniso = mix(2.1, 2.7, uStrokeAnisotropy); // comma length / cell pitch (a contained dab)\n float widAniso = mix(0.23, 0.16, uStrokeAnisotropy); // comma width / cell pitch (a thin loaded crescent)\n\n // Layer 1 — the big swirl-row dabs: the loaded gestural marks, SPARSE so the dark\n // underpainting shows BETWEEN them (the atomicity read — visible inter-dab ground).\n // hardness 0.74 — the loaded brush deposits with a SOFT shoulder, so adjacent dabs\n // feather instead of razor-clipping into hard polygon shards. jitterAmt 0.85 fully\n // scatters the cell centres so the placement GRID never reads as a periodic seam.\n // angJitter EASED 0.55 → 0.38 (the reconcile A lift): a tighter angular spread keeps\n // adjacent dabs more flow-aligned (coherent) while the per-cell curl wobble still\n // breaks the perfectly-concentric-rows read (the dabs FAN gently, not lock to a grid).\n // angJitter eased 0.38 → 0.26 + hardness 0.74 → 0.84 (the §4.2 A lift): a tighter angular\n // spread keeps adjacent dabs strongly flow-aligned (the structure-tensor coherence) and a\n // sharper edge gives each dab a STRONGER directional gradient (a soft dab's faint edge\n // reads weakly anisotropic). The per-cell curl wobble still breaks the perfectly-\n // concentric-rows read, so the dabs FAN gently rather than locking to a grid.\n StrokeHit dBig = vangoghDab(p, pitch, lenAniso, widAniso,\n 0.30, 0.50, 0.08, flow, t, 1.3);\n // streakFreq raised 14 → 34 (the §4.3 slope fix): a high-frequency streak runs ALONG the\n // dab spine, injecting fine-scale luma energy that flattens the too-steep β WITHOUT\n // adding new isotropic marks (the along-spine streak stays directional, so the §4.2\n // anisotropy the long-thin dab carries is preserved — the band-conflict resolution).\n paintOver(result, height, dBig, 48.0, 0.34,\n uImpasto * 0.75 * uStrokeAmount, 0.84, 1.3, 1.0 /* full crown */);\n\n // Layer 2 — two-thirds-pitch accent dabs (the divisionist sparkle between the big\n // marks — denser placement but still contained dabs, so dark canvas survives between).\n // angJitter eased 0.5 → 0.34 (same A-lift reasoning — the accent dabs queue along the\n // flow rather than scattering isotropically); hardness 0.78 → 0.86 sharpens the gradient.\n StrokeHit dSml = vangoghDab(p + vec2(-5.1, 8.4), pitch * 0.62, lenAniso * 0.95,\n widAniso * 0.95, 0.36, 0.60, 0.20, flow, t, 4.1);\n paintOver(result, height, dSml, 42.0, 0.22,\n uImpasto * 0.55 * uStrokeAmount, 0.86, 4.1, 1.0);\n\n // Layer 3 — the FINE divisionist flecks (W-AUR-VANGOGH-CONFIG reconcile). The two-layer\n // field read as a few BIG cobalt dabs over a smooth empty teal ground (the side-by-side\n // against starry-night-crop.png: the painting is DENSE small varied flecks, not sparse\n // large marks). The flecks are LONG·THIN directional commas hugging the swirl tangent\n // (the A-preserving fleck — short fat flecks read isotropic and drag §4.2 down). Sparse\n // density 0.30 keeps the inter-fleck ground open (the gap-fraction atomicity read).\n // The flecks are FINE (≈0.42× pitch) directional commas, tightly flow-aligned (angJitter\n // 0.22) and SPARSE (0.30) — the divisionist sparkle between the loaded marks that keeps\n // the inter-dab ground open (atomicity) while adding the small-mark mid-band energy. Thin\n // + flow-aligned so the §4.2 anisotropy the long dabs carry survives the added small marks.\n StrokeHit dFleck = vangoghDab(p + vec2(8.7, -3.2), pitch * 0.42, lenAniso * 1.0,\n widAniso * 0.68, 0.30, 0.85, 0.22, flow, t, 7.7);\n paintOver(result, height, dFleck, 30.0, 0.16,\n uImpasto * 0.40 * uStrokeAmount, 0.80, 7.7, 1.0);\n\n // ── Flow-aligned GROUND swirl-GROOVING (W-AUR-VANGOGH-CONFIG reconcile) ──\n // The bare ground between the dabs was a SMOOTH low-frequency teal gradient — the §4.3\n // power-spectrum slope ran too STEEP (β≈−2.0: too much low-frequency nuclei-field energy\n // vs the high band). Van Gogh's actual sky has the swirl BRUSHWORK everywhere, so groove\n // the OPEN GROUND with a flow-aligned ripple. It is SUBTRACTIVE-biased (it only darkens,\n // never brightens the ground), so it DEEPENS the inter-dab valleys (MORE gap-fraction —\n // atomicity preserved/strengthened) while injecting the across-flow mid-band luma energy\n // that flattens β. Gated to the open ground (low height) via the (1-height) gate so it\n // never lifts/erodes the loaded dab bodies (the dab read is untouched). Across the swirl\n // FLOW axis so the grooves run WITH the sky's brushwork direction.\n // The ground swirl-combing — a FIXED-global-angle directional grain on the open ground.\n // A flow-FOLLOWING comb varies its direction with the swirl across the readback window,\n // so its blurred structure tensor averages toward isotropic (no §4.2 lift). A comb at one\n // GLOBAL angle (van-Gogh's dominant diagonal stroke grain) is COHERENT over the whole\n // window ⇒ every open-ground pixel reads the SAME direction (the §4.2 mean-anisotropy lift\n // the swirl comb could not reach). Two resolved bands (≈22 + ≈44 across the global axis ⇒\n // ~21px + ~11px at 464px, both in the §4.3 fit window) also feed the β flatten. Gated to\n // the open ground (low height) so the loaded dabs are untouched; SUBTRACTIVE-biased so the\n // inter-dab valleys deepen (gap-fraction preserved, not filled).\n vec2 gdir = normalize(vec2(0.82, 0.57)); // the dominant global stroke grain axis\n float gacross = dot(p, vec2(-gdir.y, gdir.x));\n float groundGate = 1.0 - smoothstep(0.05, 0.28, height);\n float groove = sin(gacross * 22.0) + 0.5 * sin(gacross * 44.0 + 1.3);\n result *= 1.0 - 0.16 * groundGate * (0.5 - 0.5 * groove);\n\n // Canvas tooth (fine linen weave — base relief the raking light catches).\n float tooth1 = vnoise(p * 220.0);\n float tooth2 = vnoise(p * 220.0 * vec2(0.6, 2.4) + 37.0);\n float tooth = (0.6 * tooth1 + 0.4 * tooth2) - 0.5;\n result *= 1.0 + tooth * 0.06 * uCanvasGrain;\n\n // Relight the accumulated impasto height (raking light catches each dab's crown —\n // the visible impasto ridge that makes a dab read as a RAISED loaded mark).\n float canvasBase = tooth * 0.06 * 0.5;\n result = relightImpasto(result, height, canvasBase);\n\n // The visible Starry-Night GROUND — the open canvas between dabs (low accumulated\n // height) darkens toward the deep underpainting, so the bright impasto dabs read as\n // SEPARABLE atomic marks over a darker field (the dab↔ground contrast the user's\n // \"reads as strokes\" bar needs, AND the painterly-statistics gap-fraction floor — the\n // dark inter-dab ground must register as a measurable fraction of the field). 0.30\n // floor over a WIDER smoothstep (0..0.40): deep enough that the open gaps read as the\n // dark Starry-Night sky between marks (clearing the 4% gap floor) while the gradual\n // ramp keeps the gaps reading as flowing underpainting, not the hard black ink LINES a\n // narrow near-black step (0.26 / 0.0..0.32) produced.\n // The smoothstep FLOOR starts at 0.10 (not 0): a dab's faint AA coverage TAIL deposits\n // a sliver of height, and where many tails align along the swirl flow those slivers\n // accumulate into a faint continuous height ridge that read as thin curved LINES in the\n // ground. Holding the ground full-dark until a real dab CORE (height > 0.10) lifts out\n // keeps the open field clean — only the loaded dab bodies emerge, the tails stay ground.\n result *= mix(0.115, 1.0, smoothstep(0.085, 0.31, height));\n\n // The van-Gogh chroma — a light OKLCh punch. EASED to 0.92 (off 1.04) in the\n // W-AUR-VANGOGH-CONFIG reconcile: the rebuilt discrete-dab register's per-dab OKLCh\n // broken-color jitter (the ±16° hue + ±chroma swing per cell) lifts the field's\n // colourfulness on its own, so the prior 1.04 punch on TOP overshot the §4.1\n // reference band (rendered C=100.5 vs the painting's measured 70.67 ± 15/+25 →\n // ceiling 95.67 — neon, not Starry Night's rich-but-not-garish blue/gold). The 0.92\n // demote pulls the rendered colourfulness back IN-band while the broken-color jitter\n // keeps the per-dab pigment variation (the discrete-stroke read is untouched — this\n // is a chroma scale, not a dab-geometry change). Band-anchored on the real painting\n // (proof:aurora-arresting), NOT a widened band.\n result = saturate3(result, 1.0);\n return result;\n}\n\n", Te = "StrokeProfile profileFor(int medium, int mode) {\n // The oil baseline (mode 0) — balanced modern-abstract/palette-knife hybrid.\n StrokeProfile prof = StrokeProfile(\n 0, // shapeType — tapered\n 0.25, // bristleAmp\n 9.0, // streakFreq\n 0.09, // streakAmp\n 0.9, // impastoAmp\n 0.80, // hardness\n 340.0, // toothScale — W-AUR-VANGOGH-CONFIG reconcile: FINER 240 → 340. Oil's §4.3 β sat\n // right AT the −1.45 band ceiling (±0.02 frame variance straddling\n // it, surfaced once the vangogh bands went green and the spec reached\n // the oil β assert). MEASURED on the live GPU: ADDING fine high-\n // frequency tooth energy steepens oil's power-spectrum slope (more\n // negative — coarsening it the other way pushed β SHALLOWER to\n // −1.33). A finer, stronger tooth moves β to a safe distance inside\n // the −5/3 band [−1.85, −1.45]. Oil-only (oil-pastel sets 280).\n 0.14, // toothAmp — raised 0.09 → 0.14 (same oil-β steepen: more fine-grain high band).\n 1.03, // pigmentSat\n 0.65, // densityBig\n 0.78, // densityMed\n 0.90, // densitySml\n 0.0, // energyGrade — oil is uniform-length (no Starry-Night cascade)\n 0.4, // impastoFloor — oil's 0.4+0.6·edgeN crown falloff\n 0.92, // densityFill — oil fills DENSELY with the directional low-relief fill so the\n // flat-colour regions between the macro strokes are TEXTURED with\n // flow-aligned fine strokes (the §4.2 anisotropy needs every pixel\n // to carry directional gradient; a flat untextured region reads as\n // an isotropic/degenerate tensor and drags mean A down). The fill\n // is now directional + low-streak, so dense coverage textures\n // WITHOUT the prior round-dab speckle.\n 1.0 // groundFloor — oil keeps the full base (no ground darken; fills everywhere)\n );\n\n // W-AUR-VANGOGH-REBUILD — the van-Gogh medium NO LONGER routes through this oil\n // StrokeProfile cascade. It is a DEDICATED atomic-dab body (mediumVangogh / vangoghDab\n // below) — the prior profile-driven cascade (four dense layers of long-thin\n // tensor-oriented strokes) merged into the \"marbled flow-bands\" read and ran at ~4fps.\n // profileFor now serves ONLY the oil + oil-pastel stroke mediums; the MEDIUM_VANGOGH\n // case is removed (no caller). MEDIUM_VANGOGH stays #define'd (the main() dispatch +\n // isPainterlyStroke still key off uMedium==5).\n\n // ── Oil-pastel — broad smeared directional strokes deposited via the brush engine\n // (slice 8 F1). Creamy soft edges (low hardness), heavy build-up, and a chroma punch.\n // Distinct from the dry-crayon tooth-multiply (mediumCrayon): oil-pastel LAYS strokes.\n if (medium == MEDIUM_OILPASTEL) {\n prof.shapeType = 0; // tapered directional smear — a round dab reads locally\n // isotropic (steep β / low A); the creamy oil-pastel mark\n // is a broad DIRECTIONAL smear, which carries the §4.2\n // coherence + adds the directional mid-band the §4.3 slope\n // needs (the round-dab profile rolled β off to −2.8)\n prof.bristleAmp = 0.10; // smooth creamy edges (waxy pastel, not bristle)\n prof.streakFreq = 18.0; // finer internal smear — adds the mid/high-band the smooth\n // round-dab profile lacked (the β-too-steep fix); the\n // directional along-spine streak flattens the §4.3 slope\n // without crossing the strokes\n prof.streakAmp = 0.20;\n prof.impastoAmp = 0.7; // build-up, but flatter than oil impasto\n prof.hardness = 0.42; // CREAMY — soft compositing, strokes blend on overlap\n prof.toothScale = 280.0;\n prof.toothAmp = 0.12; // the pastel tooth reads stronger\n prof.pigmentSat = 0.80; // the waxy chroma — eased off 1.16 so the rendered C clears\n // the §4.1 band ceiling with margin while the K-M subtractive\n // overlap path (paintOverOklab) keeps the chroma OFF the grey floor\n prof.hardness = 0.58; // creamy but the strokes still REGISTER — a too-soft blend\n // (0.42) smeared the marks into the smooth colour zones and\n // the field rolled off too steep (β≈−2.9, a near-gradient);\n // a crisper deposit keeps the mid/high-band the −5/3 slope needs\n prof.densityBig = 0.62; // broad directional coverage — but NOT over-dense: too many\n // overlapping creamy strokes point in slightly-varied\n // directions and the local §4.2 coherence DROPS (over-dense\n // measured A=0.57 < the 0.62-density A=0.63). The mid-density\n // flow-aligned deposit is the coherence sweet spot.\n prof.densityMed = 0.78;\n prof.densitySml = 0.90;\n prof.energyGrade = 0.80; // a strong Starry-Night length cascade — varies stroke length\n // by luma/coherence so the dab-size energy spreads across\n // scales (the −5/3 cascade the uniform-length 0.0 grade lacked,\n // the §4.3 β-too-steep fix). Not the full van-Gogh 1.0 (oil-\n // pastel keeps its creamy broad character).\n prof.impastoFloor = 0.55; // a softer crown than van-Gogh's full-height glint\n return prof;\n }\n\n // ── Oil sub-modes (mode dispatch on the oil medium).\n if (mode == 1) { // palette knife — razor edges, heavy impasto\n prof.shapeType = 3; // flat, even\n prof.bristleAmp = 0.12;\n prof.streakFreq = 4.0; prof.streakAmp = 0.05;\n prof.impastoAmp = 1.6;\n prof.hardness = 0.95;\n prof.toothAmp = 0.04;\n prof.densityBig = 0.80; prof.densityMed = 0.88; prof.densitySml = 0.70;\n } else if (mode == 3) { // thick brushwork — heavy bristle brush\n prof.shapeType = 0; // tapered\n prof.bristleAmp = 0.32;\n prof.streakFreq = 14.0; prof.streakAmp = 0.14;\n prof.impastoAmp = 1.2;\n prof.hardness = 0.85;\n prof.toothAmp = 0.07;\n }\n return prof;\n}\n", Ee = "// ── Medium overlays ───────────────────────────────────────────────────────\n\n// A quick re-computation of base color for edge-mask sampling\nvec3 sampleBase(vec2 p, float t) {\n vec2 pw = domainWarp(p, t);\n float id; float vm;\n nucleiField(pw, t, id, vm);\n vec3 c = samplePalette(id);\n c *= 1.0 + uValueVariance * vm;\n return c;\n}\n\n// ── Structure-tensor / edge-tangent-flow (AW.W4.1) ─────────────────────────\n// The keystone of the painterly engine: derive stroke orientation from the COLOR\n// FIELD's OWN structure, not a hand-authored flow pattern. A 3x3 Sobel over\n// luma(sampleBase) yields the gradient (Gx,Gy); the 2x2 structure tensor\n// J = [[Gx², GxGy],[GxGy, Gy²]] eigen-decomposes closed-form into the MINOR\n// eigenvector (the edge-TANGENT — least color change, the stroke direction; the\n// MAJOR eigenvector is the gradient/edge-NORMAL and would make strokes cross the\n// bands) and the coherence A = (λ1-λ2)/(λ1+λ2). Low-coherence (flat) zones relax\n// toward the smooth fallbackDir by (1-A) so tensor noise never reads as jitter.\n// Single-pass small-tap WebGL2 form; the Gaussian-smoothed multi-tap + LIC smear\n// is the AW.W7 WebGPU multi-pass fold. Returns vec3(tangent.x, tangent.y, A).\nvec3 structureTensorField(vec2 p, float t, vec2 fallbackDir) {\n float e = 0.0035; // small-tap neighborhood (edge-mask scale)\n // 3x3 luma samples.\n float l00 = dot(sampleBase(p + vec2(-e, -e), t), W_LUMA);\n float l10 = dot(sampleBase(p + vec2( 0.0, -e), t), W_LUMA);\n float l20 = dot(sampleBase(p + vec2( e, -e), t), W_LUMA);\n float l01 = dot(sampleBase(p + vec2(-e, 0.0), t), W_LUMA);\n float l21 = dot(sampleBase(p + vec2( e, 0.0), t), W_LUMA);\n float l02 = dot(sampleBase(p + vec2(-e, e), t), W_LUMA);\n float l12 = dot(sampleBase(p + vec2( 0.0, e), t), W_LUMA);\n float l22 = dot(sampleBase(p + vec2( e, e), t), W_LUMA);\n // Sobel derivatives.\n float Gx = (l20 + 2.0 * l21 + l22) - (l00 + 2.0 * l01 + l02);\n float Gy = (l02 + 2.0 * l12 + l22) - (l00 + 2.0 * l10 + l20);\n // Structure tensor components.\n float Jxx = Gx * Gx;\n float Jyy = Gy * Gy;\n float Jxy = Gx * Gy;\n // Closed-form 2x2 eigenvalues: λ = 0.5(tr ± sqrt((Jxx-Jyy)² + 4Jxy²)).\n float tr = Jxx + Jyy;\n float disc = sqrt(max((Jxx - Jyy) * (Jxx - Jyy) + 4.0 * Jxy * Jxy, 0.0));\n float lambdaMaj = 0.5 * (tr + disc);\n float lambdaMin = 0.5 * (tr - disc);\n // The MAJOR eigenvector points along the gradient (the edge NORMAL); the MINOR\n // is its perpendicular — the edge TANGENT (the stroke direction). The principal\n // angle is θ = 0.5·atan2(2·Jxy, Jxx-Jyy); this form is robust at Jxy≈0 (where the\n // (λ-Jyy, Jxy) eigenvector formula collapses to a zero vector). The tangent is at\n // θ + 90°. Guard the fully-isotropic (no-gradient) degenerate case → fallback dir.\n vec2 tangent;\n if (disc < 1e-7) {\n tangent = fallbackDir;\n } else {\n float theta = 0.5 * atan(2.0 * Jxy, Jxx - Jyy); // major (gradient) angle\n tangent = vec2(-sin(theta), cos(theta)); // perpendicular = tangent\n }\n // Coherence A in [0,1] — high where one eigenvalue dominates (a strong edge),\n // ~0 in flat zones. Relax toward the smooth fallback by (1 - A).\n float A = (lambdaMaj - lambdaMin) / (lambdaMaj + lambdaMin + 1e-6);\n A = clamp(A, 0.0, 1.0);\n // Coherence-weighted blend: full tensor in coherent zones, smooth in flat ones.\n // Resolve the 180° sign ambiguity toward the fallback so the blend is continuous.\n if (dot(tangent, fallbackDir) < 0.0) tangent = -tangent;\n // The blend weight is a low-power curve (A^0.35) so even MODERATE-coherence zones queue\n // strongly along the tangent (a flowing van-Gogh band reads coherent the way the\n // structure-tensor metric measures it; a linear A under-orients the mid-band and the\n // rendered field reads too isotropic — the §4.2 anisotropy lift). The flat-zone (A≈0)\n // relax to the fallback survives (0^0.35=0), so tensor noise never reads as jitter.\n float blendW = pow(A, 0.28);\n vec2 dir = normalize(mix(fallbackDir, tangent, blendW) + 1e-6);\n return vec3(dir, A);\n}\n\nvec3 mediumWatercolor(vec3 col, vec2 p, float t) {\n // Wet-edge cauliflowers via luma-gradient magnitude\n float eps = 0.004;\n vec3 cx1 = sampleBase(p + vec2(eps, 0.0), t);\n vec3 cx2 = sampleBase(p - vec2(eps, 0.0), t);\n vec3 cy1 = sampleBase(p + vec2(0.0, eps), t);\n vec3 cy2 = sampleBase(p - vec2(0.0, eps), t);\n float gx = dot(cx1 - cx2, W_LUMA);\n float gy = dot(cy1 - cy2, W_LUMA);\n float edge = sqrt(gx * gx + gy * gy) / (2.0 * eps);\n float mask = smoothstep(0.0, 2.5, edge);\n col *= mix(1.0, 0.78, mask * uWetEdge);\n\n // Granulation — pigment settles in paper tooth\n float paper = 0.5 * vnoise(p * 160.0) + 0.5 * vnoise(p * 360.0);\n float pigLoad = 1.0 - dot(col, W_LUMA);\n col *= 1.0 - uGranulation * pigLoad * (paper - 0.5);\n\n // Wash banding — faint horizontal wet gradient\n float band = fbm(vec2(p.x * 1.5, p.y * 0.4));\n col *= 1.0 + 0.04 * (band - 0.5);\n return col;\n}\n\nvec3 mediumPastel(vec3 col, vec2 p, float t) {\n vec2 flow = flowField(p, t);\n vec2 perp = vec2(-flow.y, flow.x);\n float along = dot(p, flow) * uStrokeScale;\n float across = dot(p, perp) * uStrokeScale;\n across += 0.03 * (vnoise(p * 260.0) - 0.5);\n\n float aniso = mix(1.0, 0.18, uStrokeAnisotropy);\n float stroke = fbm(vec2(along * aniso, across));\n col *= mix(1.0, 0.82 + 0.32 * stroke, uStrokeAmount);\n\n // Pastel tooth — tiny high-frequency grain\n float tooth = vnoise(p * 800.0);\n col *= 1.0 - 0.08 * uStrokeAmount * (tooth - 0.5);\n return col;\n}\n", De = "// ── Medium id constants (mirror uniformBridge.ts MEDIUM_ID — the uMedium ladder) ──\n// The StrokeProfile selector (AX.W12 + AX.W13) dispatches on the medium id: oil,\n// van-Gogh, and oil-pastel each AUTHOR a first-class profile in profileFor.\n#define MEDIUM_OIL 3\n#define MEDIUM_CRAYON 4\n#define MEDIUM_VANGOGH 5\n#define MEDIUM_OILPASTEL 6\n\n// ── Crayon — DRY wax pigment on paper tooth (first-class medium, uMedium==4) ──\n// Crayon is not strokes. It's dry pigment crumbs dragged across paper tooth — the\n// DRY tooth-multiply model: anisotropic tooth noise multiplied into the base, a hard\n// SCUMBLE that lets the lower color show through the broken upper layer, and stable\n// OKLCh broken-color pigment patches. NO sheen, NO burnish film — that waxy gloss is\n// the OIL-PASTEL deposition's signature (mediumOilPastel), distinct from dry crayon\n// (AX.W13 slice 8 F1 — the split). Crayon shares the SUBSTRATE (the structure-tensor\n// orientation, the tooth noise, OKLCh brokenColorJitter), not the dispatch body.\nvec3 mediumCrayon(vec3 col, vec2 p, float t) {\n // Orient the deposition along the structure-tensor edge-tangent (the bridge forces\n // tensor for crayon, so read the tensor field directly).\n vec2 flow = structureTensorField(p, t, flowField(p, t)).xy;\n float ang = atan(flow.y, flow.x);\n float ca = cos(-ang), sa = sin(-ang);\n vec2 pr = vec2(p.x * ca - p.y * sa, p.x * sa + p.y * ca);\n\n float aniso = mix(0.45, 0.95, uStrokeAnisotropy);\n float scale = max(uStrokeScale * 1.6, 180.0);\n\n // ── Paper TOOTH height field — the relief the dry pigment rides. Anisotropic\n // (squished along flow, coarse cross-flow). Peaks = ridges, valleys = paper pits.\n float t1 = vnoise(vec2(pr.x * scale * aniso, pr.y * scale));\n float t2 = vnoise(vec2(pr.x * scale * aniso * 0.4, pr.y * scale * 0.4) + 11.0);\n float t3 = vnoise(vec2(pr.x * scale * aniso * 2.1, pr.y * scale * 2.1) + 23.0);\n float tooth = 0.55 * t1 + 0.30 * t2 + 0.15 * t3;\n\n // ── DRY TOOTH-MULTIPLY — the crayon multiplies the tooth relief into the base\n // color (dark in the pits, bright on the ridges). The pressure (uStrokeAmount) sets\n // how hard the multiply bites. This is the DRY model — no pigment build-up, no sheen.\n float pressure = clamp(uStrokeAmount, 0.0, 1.0);\n float bite = mix(0.18, 0.46, pressure); // multiply strength\n vec3 result = col * (1.0 - bite * (0.5 - tooth));\n\n // ── HARD SCUMBLE — a broken upper layer that lets the lower color show through the\n // gaps. A coarse mask gates a HARD (high-contrast) dragged pass so the dry crayon\n // reads as broken pigment crumbs, not a smooth wash. Drag follows the tensor flow.\n float scumbleMask = smoothstep(0.42, 0.78, vnoise(vec2(pr.x * scale * 0.55, pr.y * scale * 0.22) + 7.0));\n float scumbleCoverage = scumbleMask * pressure * 0.7; // hard broken upper layer\n vec3 paper = col * mix(0.80, 0.94, pressure); // the paper showing through\n result = mix(paper, result, scumbleCoverage);\n\n // ── Broken-color pigment: stable wax/pigment patches in OKLCh (W5), not flicker.\n vec2 pigmentCell = floor(pr * max(scale * 0.18, 32.0));\n float pigmentMask = smoothstep(0.28, 0.82, vnoise(pr * scale * 0.21 + 19.0));\n result = brokenColorJitter(\n result,\n hash21(pigmentCell + 17.0),\n hash21(pigmentCell * 2.1 + 31.0),\n 0.45 + 0.55 * pigmentMask\n );\n\n // Crayon is saturation-amplified (the wax chroma punch — but DRY, no sheen).\n result = saturate3(result, 1.08);\n\n return result;\n}\n\n// ── StrokeProfile — the oil-stroke parameter vector (AX.W12, slice 8 F6) ──────\n// The SBR \"stroke = parameter vector\" canon (facet 11): the per-mode if-ladder knobs\n// become struct FIELDS — logic-as-DATA, not an imperative branch. profileFor(medium,\n// mode) populates the profile for a (medium, mode) pair; paintStrokeLayers(profile) runs\n// the four-layer bestOil/paintOver cascade off it. A new medium (the W13 van-Gogh /\n// oil-pastel profiles) AUTHORS a profile entry — it never edits a monolith.\nstruct StrokeProfile {\n int shapeType; // 0 tapered, 1 load-drag, 2 dab, 3 even, 4 comma/crescent\n float bristleAmp; // edge raggedness 0..0.5\n float streakFreq; // internal-streak spatial frequency\n float streakAmp; // internal-streak amplitude\n float impastoAmp; // paint-thickness contribution (the relight reads the height)\n float hardness; // edge-compositing crispness 0..1\n float toothScale; // canvas-tooth (linen weave) spatial frequency\n float toothAmp; // canvas-tooth amplitude\n float pigmentSat; // pigment saturation boost (OKLCh chroma scale)\n float densityBig; // layer-1 (big gestural) placement density gate\n float densityMed; // layer-2 (medium body) placement density gate\n float densitySml; // layer-3 (small dabs) placement density gate\n float energyGrade; // AX.W13 — SBR energy-grade magnitude (0 off; 1 the van-Gogh\n // Starry-Night length cascade). The energy grade is a PROFILE\n // field, NOT a buried uMedium==5 bestOil branch (slice 8 F0).\n float impastoFloor;// AX.W13 — the per-stroke height-crown floor (0.4 oil falloff;\n // 1.0 van-Gogh FULL-height crown so each dab catches its glint).\n float densityFill; // AX.W13 — layer-4 fill-dab density. Oil/oil-pastel fill the\n // bald spots (0.95, full coverage); van-Gogh sets it LOW so the\n // sparse atomic dabs keep their visible inter-stroke ground gaps\n // (the atomicity read — a 0.95 fill would close every gap to a smear).\n float groundFloor; // AX.W13 — the bare-ground darken floor. The gaps between strokes\n // (low accumulated height) multiply toward this floor, so van-Gogh's\n // sparse atomic dabs read over a visibly darker underpainting (the\n // Starry-Night visible ground). Oil/oil-pastel keep 1.0 (no darken).\n};\n\n// The (medium, mode) -> StrokeProfile selector. The if-ladder's knobs are the profile's\n// fields; a new medium adds a CASE here (never an edit to a dispatch body). mode is the\n// uStrokeMode oil-stroke sub-mode (0 oil, 1 palette-knife, 3 brushwork). crayon\n// (uMedium==4) is a PEER tooth-multiply medium that never reaches the stroke cascade.\n// The painterly STROKE mediums are oil (MEDIUM_OIL), van-Gogh (MEDIUM_VANGOGH) and\n// oil-pastel (MEDIUM_OILPASTEL) — each AUTHORS its own profile entry below.\n" + Te + "\n// The single parameterized four-layer stroke cascade (AX.W12). The four hand-unrolled\n// bestOil/paintOver invocations collapse into ONE body driven by the profile + the\n// uniform-derived per-layer scale/anisotropy multipliers (which are mode-INVARIANT — the\n// per-layer offsets, seeds, and len/wid muls are fixed across modes, so they stay here as\n// the cascade's structure; only the profile's knobs differentiate the medium). The\n// mode passes through for the two mode-special-cased shapes (knife layer-3 dabs +\n// layer-4 fill shape), which are placement details of the cascade, not profile knobs.\nvoid paintStrokeLayers(inout vec3 col, inout float height, StrokeProfile prof,\n int mode, vec2 p, float t) {\n // Scales & multipliers from uniforms (mode-invariant cascade structure).\n float baseScale = max(uStrokeScale * 0.006, 0.008);\n // Three primary layers: big gestural, medium body, small dabs.\n // W-AUR-STUDIO D5 — the −5/3 radii respacing was MEASURED + REVERTED (recorded, not\n // silently struck). The φ-adjacent geometric candidate (2.4 / 1.45 / 0.87, a fixed\n // ≈1.66× step) moved oil-pastel β −2.534 → −2.413 — TOWARD the −5/3 band but NOT into\n // it (floor −1.85), so the keep-iff-into-band gate failed. The single-pass WebGL2 path\n // is the true limiter (HC-aurora §5): the oil-pastel β + the oil/oil-pastel anisotropy\n // residual stays the oil/oil-pastel stroke-cascade ceiling. BB.W-AUR-KUWAHARA DECIDED the\n // booking: the SOFT anisotropic-Kuwahara finish ships as the OPT-IN mediumKuwahara() body\n // (uMedium==7) the consumer selects — NOT a re-tune of these oil/oil-pastel knobs. The\n // hand-set 2.4 / 1.1 / 0.45 stays — it is van-Gogh's landed-band spacing.\n float sBig = baseScale * 2.4;\n float sMed = baseScale * 1.1;\n float sSml = baseScale * 0.45;\n\n // Strokes are elongated HARD (long·thin) so the rendered field reads strongly\n // directional — the §4.2 structure-tensor anisotropy lift. A short fat dab is locally\n // isotropic and drags the measured A down; a long thin stroke that hugs the tensor\n // tangent is what gives Starry Night its A≈0.83. The width muls are pulled tighter to\n // keep the long·thin aspect.\n float lenMulBig = mix(3.0, 5.2, uStrokeAnisotropy);\n float widMulBig = mix(0.42, 0.22, uStrokeAnisotropy);\n float lenMulMed = mix(2.8, 4.8, uStrokeAnisotropy);\n float widMulMed = mix(0.40, 0.21, uStrokeAnisotropy);\n float lenMulSml = mix(2.2, 3.6, uStrokeAnisotropy);\n float widMulSml = mix(0.36, 0.23, uStrokeAnisotropy);\n\n float jitterAmt = 0.75; // large jitter — no grid\n vec2 flow = flowField(p, t);\n\n // Layer 1 — big gestural strokes (sparse, shaping)\n StrokeHit hBig = bestOil(p, sBig, lenMulBig, widMulBig, jitterAmt * 0.55,\n prof.densityBig, prof.shapeType, prof.bristleAmp, flow, t, 1.3,\n prof.energyGrade);\n paintOver(col, height, hBig, prof.streakFreq * 0.7, prof.streakAmp,\n uImpasto * prof.impastoAmp * uStrokeAmount, prof.hardness, 1.3, prof.impastoFloor);\n\n // Layer 2 — medium body strokes\n StrokeHit hMed = bestOil(p + vec2(11.3, 3.7), sMed, lenMulMed, widMulMed,\n jitterAmt, prof.densityMed, prof.shapeType, prof.bristleAmp, flow, t, 2.7,\n prof.energyGrade);\n paintOver(col, height, hMed, prof.streakFreq, prof.streakAmp,\n uImpasto * prof.impastoAmp * uStrokeAmount, prof.hardness, 2.7, prof.impastoFloor);\n\n // Layer 3 — small strokes (more frequent, smaller). Even the knife layer-3 stays the\n // medium's DIRECTIONAL shape, not a round dab — the round-dab sparkle was a fine-scale\n // isotropic speckle that dragged the §4.2 anisotropy down + rolled the §4.3 slope shallow.\n int smlShape = prof.shapeType;\n StrokeHit hSml = bestOil(p + vec2(-5.1, 8.4), sSml, lenMulSml, widMulSml,\n jitterAmt * 0.9, prof.densitySml, smlShape,\n prof.bristleAmp * 0.85, flow, t, 4.1, prof.energyGrade);\n paintOver(col, height, hSml, prof.streakFreq * 1.4, prof.streakAmp * 0.6,\n uImpasto * prof.impastoAmp * 0.45 * uStrokeAmount, prof.hardness, 4.1, prof.impastoFloor);\n\n // Layer 4 — fill strokes (dense, fine) — cover bald spots. The density is\n // PROFILE-driven (prof.densityFill): oil/oil-pastel fill to full coverage; van-Gogh\n // keeps it sparse so the bare-ground gaps between its atomic dabs survive. The fill is\n // ELONGATED + flow-oriented (NOT a round dab) — a dense round-dab fill is locally\n // isotropic and was the dominant §4.2 anisotropy sink; an oriented fine stroke keeps the\n // fill directional so the whole field reads coherent.\n float sFill = baseScale * 0.22;\n float lenMulFill = mix(2.0, 3.2, uStrokeAnisotropy);\n float widMulFill = mix(0.34, 0.24, uStrokeAnisotropy);\n int fillShape = (mode == 1) ? 3 : prof.shapeType; // knife=even; others inherit the medium's directional shape\n StrokeHit hFill = bestOil(p + vec2(3.9, -6.2), sFill, lenMulFill, widMulFill,\n jitterAmt * 0.8, prof.densityFill, fillShape,\n prof.bristleAmp * 0.6, flow, t, 8.9, prof.energyGrade);\n // The fill is a low-relief, low-streak base coat — it covers bald spots WITHOUT adding\n // fine bright speckle (a high-impasto/high-streak fill caught a per-dab glint that read\n // as isotropic noise over the directional macro strokes — the §4.2/§4.3 sink). Its\n // positional jitter is tamed too so the fill strokes stay flow-aligned, not scattered.\n paintOver(col, height, hFill, prof.streakFreq * 1.2, prof.streakAmp * 0.35,\n uImpasto * prof.impastoAmp * 0.18 * uStrokeAmount, prof.hardness * 0.9, 8.9, prof.impastoFloor);\n\n // Optional crosshatch layer\n if (uStrokeLayers == 2) {\n vec2 flow2 = vec2(-flow.y, flow.x);\n StrokeHit hX = bestOil(p + vec2(7.3, -2.1), sMed, lenMulMed * 0.9, widMulMed,\n jitterAmt, prof.densityMed * 0.7, prof.shapeType, prof.bristleAmp, flow2, t, 6.5,\n prof.energyGrade);\n paintOver(col, height, hX, prof.streakFreq, prof.streakAmp * 0.85,\n uImpasto * prof.impastoAmp * 0.55 * uStrokeAmount, prof.hardness, 6.5, prof.impastoFloor);\n }\n}\n\n// The shared stroke-medium SUBSTRATE finish (AX.W12 + AX.W13): paint the four-layer\n// cascade off the profile, then canvas-tooth + relight + saturation. The three painterly\n// STROKE mediums (oil / van-Gogh / oil-pastel) each AUTHOR their own profile and call\n// this — the substrate is shared, the PROFILE (not a dispatch-body fork) differentiates\n// the medium (slice 8 F6). mode passes through for the cascade's mode-special-cased shapes.\nvec3 paintStrokeMedium(vec3 col, vec2 p, float t, StrokeProfile prof, int mode) {\n vec3 result = col;\n // AW.W4.2 — accumulated paint HEIGHT across the stroke layers. The relight reads\n // its gradient for the normal; the canvas tooth seeds the base relief.\n float height = 0.0;\n paintStrokeLayers(result, height, prof, mode, p, t);\n\n // Canvas tooth — linen weave\n float tooth1 = vnoise(p * prof.toothScale);\n float tooth2 = vnoise(p * prof.toothScale * vec2(0.6, 2.4) + 37.0);\n float tooth = (0.6 * tooth1 + 0.4 * tooth2) - 0.5;\n result *= 1.0 + tooth * prof.toothAmp * uCanvasGrain;\n\n // AW.W4.2 — relight the accumulated paint height with the movable uLightDir\n // source (diffuse + Blinn specular, in LINEAR before aces()). The canvas tooth\n // is the base relief term so the weave also catches the raking light.\n float canvasBase = tooth * prof.toothAmp * 0.5;\n result = relightImpasto(result, height, canvasBase);\n\n // AX.W13 — the visible ground. The bare-ground gaps (low accumulated stroke height)\n // multiply toward prof.groundFloor, so van-Gogh's sparse atomic dabs read as separable\n // marks over a darker underpainting (oil/oil-pastel keep groundFloor=1.0 → no-op). The\n // smoothstep keeps the impasto dabs (high height) at full value; only the open ground\n // between them darkens.\n result *= mix(prof.groundFloor, 1.0, smoothstep(0.0, 0.38, height));\n\n // Pigment saturation boost\n result = saturate3(result, prof.pigmentSat);\n\n return result;\n}\n\nvec3 mediumOil(vec3 col, vec2 p, float t) {\n // The oil medium is a thin body: fetch the oil profile (mode-dispatched), paint via\n // the shared stroke substrate. uStrokeMode: 0 oil (gestural), 1 knife, 3 brushwork.\n int mode = uStrokeMode;\n StrokeProfile prof = profileFor(MEDIUM_OIL, mode);\n return paintStrokeMedium(col, p, t, prof, mode);\n}\n\n#define MEDIUM_KUWAHARA 7\n\n// ── Kuwahara — the anisotropic generalized Kuwahara painterly finish (uMedium==7,\n// BB.W-AUR-KUWAHARA) ───────────────────────────────────────────────────────────────\n// The SOTA edge-preserving painterly smoothing: the generalized/anisotropic Kuwahara\n// of Kyprianidis 2010, the SOFT polynomial-weighted variant (NOT the pre-2010 hard\n// argmin, which BANDS the flat field into an 8-spoke pinwheel — the §4.2 anti-regression).\n// Aurora is a PROCEDURAL field (no input texture), so the operator runs over the\n// sampleBase() color field directly: an elliptical kernel oriented along the structure\n// tensor (elongated along the edge-tangent, narrowed across by the anisotropy), divided\n// into 8 overlapping sectors via smooth weights; each sector accumulates a weighted mean\n// + variance, and the output is the variance-weighted blend of the sector means\n// (1/(1+var^q) — the low-variance sectors dominate, the SOFT criterion). The result is\n// flat painterly oil-paint patches with crisp colour-zone boundaries — the §4.3 −5/3\n// cascade carried by the multi-scale patch structure, the §4.2 anisotropy carried by the\n// ellipse hugging the tensor. Single-pass small-radius WebGL2 form: 4 rings × 8 angular\n// taps = 32 procedural neighbourhood samples (cost-bounded; the offscreen-park / PRM\n// freeze the substrate owns is untouched — a parked frame attaches zero of these taps).\nvec3 mediumKuwahara(vec3 col, vec2 p, float t) {\n // Orient the kernel along the structure-tensor edge-tangent + read the coherence A.\n vec3 stf = structureTensorField(p, t, flowField(p, t));\n vec2 tangent = stf.xy;\n float A = stf.z;\n // The ellipse axes: major along the tangent, minor across. Anisotropy squeezes the\n // minor axis (coherent zones → long-thin patch along the colour band; flat zones →\n // near-circular so the operator degrades gracefully to the isotropic Kuwahara). The\n // base radius rides uStrokeScale so the painterly patch size tracks the studio knob.\n float radius = clamp(0.010 + uStrokeScale * 0.00018, 0.006, 0.024);\n float aniso = mix(1.0, 0.34, clamp(A, 0.0, 1.0)); // minor/major axis ratio\n vec2 ax = tangent; // major-axis unit vector (edge-tangent)\n vec2 ay = vec2(-tangent.y, tangent.x); // minor-axis unit vector (edge-normal)\n\n // 8 sectors, soft polynomial weights. Each sector i centers on angle i·45°; a sample's\n // sector weight is a smooth gaussian-of-angular-distance so sectors OVERLAP (no hard\n // argmin → no pinwheel banding). The center sample seeds all sectors equally.\n const int SECTORS = 8;\n vec3 m[8]; // per-sector weighted colour sum\n vec3 s[8]; // per-sector weighted colour² sum (for variance)\n float w[8]; // per-sector weight sum\n for (int i = 0; i < SECTORS; i++) { m[i] = vec3(0.0); s[i] = vec3(0.0); w[i] = 0.0; }\n\n // 4 rings × 8 angular taps over the elliptical disc. Each tap: sample the procedural\n // field, then deposit into the sectors by the soft angular weight × the radial falloff.\n const int RINGS = 4;\n const int TAPS = 8;\n for (int r = 1; r <= RINGS; r++) {\n float rr = float(r) / float(RINGS); // 0.25 .. 1.0\n float radial = 1.0 - 0.6 * rr; // inner taps weigh more (gaussian-ish)\n for (int a = 0; a < TAPS; a++) {\n float ang = 6.2831853 * float(a) / float(TAPS);\n // Elliptical offset: major axis full radius, minor axis squeezed by aniso.\n vec2 dirE = ax * cos(ang) + ay * (sin(ang) * aniso);\n vec2 off = dirE * (radius * rr);\n vec3 c = sampleBase(p + off, t);\n // The sample's angular bin (its sector) — soft, so it spills into neighbours.\n for (int k = 0; k < SECTORS; k++) {\n float sectorAng = 6.2831853 * float(k) / float(SECTORS);\n // Smallest signed angular distance to the sector center.\n float d = ang - sectorAng;\n d = atan(sin(d), cos(d)); // wrap to [-π, π]\n float sw = exp(-d * d * 2.2) * radial; // gaussian angular weight × radial\n m[k] += c * sw;\n s[k] += c * c * sw;\n w[k] += sw;\n }\n }\n }\n\n // Per-sector mean + scalar luma-variance, then the SOFT variance-weighted blend.\n vec3 accum = vec3(0.0);\n float accumW = 0.0;\n for (int k = 0; k < SECTORS; k++) {\n float wk = max(w[k], 1e-4);\n vec3 mean = m[k] / wk;\n vec3 var3 = max(s[k] / wk - mean * mean, vec3(0.0));\n float variance = dot(var3, W_LUMA); // perceptual scalar variance\n // SOFT criterion: low-variance sectors (flat, inside a colour zone) dominate; a\n // high-variance sector (straddling an edge) is suppressed. q controls the sharpness;\n // a finite q (not argmin) keeps the blend continuous → no pinwheel spoke.\n float sectorW = 1.0 / (1.0 + pow(variance * 320.0, 4.0));\n accum += mean * sectorW;\n accumW += sectorW;\n }\n vec3 result = accum / max(accumW, 1e-4);\n\n // The center sample anchors the result in near-flat zones (where every sector reads the\n // same colour) so the operator is a no-op there — the smoothing only BITES at edges.\n vec3 center = sampleBase(p, t);\n result = mix(center, result, clamp(0.35 + 0.65 * A, 0.0, 1.0));\n\n // A faint canvas tooth + pigment-saturation lift so the flattened patches read as\n // oil-paint, not a posterized blur (the painterly identity the smoothing alone lacks).\n float tooth = vnoise(p * 300.0) - 0.5;\n result *= 1.0 + tooth * 0.06 * uCanvasGrain;\n result = saturate3(result, 1.04);\n\n // Blend toward the incoming col by uStrokeAmount so the studio amount knob controls\n // the finish strength (uStrokeAmount=0 → the raw field passes through; default → full).\n return mix(col, result, clamp(uStrokeAmount, 0.0, 1.0));\n}\n\n" + we + "// AX.W13 — the oil-pastel medium (uMedium==6) is a DISTINCT stroke-deposition body,\n// split out of the dry-crayon tooth-multiply (mediumCrayon) (slice 8 F1). It DEPOSITS\n// broad smeared directional strokes via the same brush engine with a creamy soft\n// hardness, heavy pigment build-up where strokes overlap, and a chroma punch — the\n// stroke-deposition model that gives oil-pastel its depth and less-uniform read.\n// Shares the SUBSTRATE (the stroke cascade + tooth + relight) with oil/van-Gogh, NOT\n// the dispatch body of dry crayon. The bridge forces tensor orientation.\nvec3 mediumOilPastel(vec3 col, vec2 p, float t) {\n StrokeProfile prof = profileFor(MEDIUM_OILPASTEL, 0);\n return paintStrokeMedium(col, p, t, prof, 0);\n}", k = "\n", Oe = `#version 300 es
1
+ import { t as e } from "./_plugin-vue_export-helper-C1je1s0u.js";
2
+ import { t } from "./usePointerVelocityField-CwXyeW0Z.js";
3
+ import { d as n, s as r } from "./pointerFieldMappings-4VtmkOWv.js";
4
+ import { t as i } from "./useScrollProgress-C-yImzhU.js";
5
+ import { t as a } from "./useIntersectionPause-Cmt5Tnv9.js";
6
+ import { a as o, c as s, i as c, l, n as u, o as d, r as f, s as p, t as m } from "./procedural-color.wgsl-ByduxnzV.js";
7
+ import { t as h } from "./flow.glsl-CVqPSj8_.js";
8
+ import { i as g, n as _, r as v, t as y } from "./useGpuSubstrate-DcY584kE.js";
9
+ import { n as b, t as x } from "./compile-C55K3P9g.js";
10
+ import { a as S, c as C, i as ee, l as w, o as T, t as E } from "./color-Bp5jmv4Z.js";
11
+ import { computed as D, createElementBlock as te, createElementVNode as ne, defineComponent as re, normalizeClass as ie, normalizeStyle as ae, onBeforeUnmount as oe, onMounted as se, openBlock as ce, readonly as le, ref as O, unref as k, watch as A } from "vue";
12
+ import { interpolateHue as ue, oklabToLinearSRGB as de, rawOklabToOklch as fe, rawOklchToOklab as pe, srgbToOKLab as me } from "@mkbabb/value.js";
13
+ //#region src/components/aurora/constants/shaders/aurora.vert.ts
14
+ var he = "#version 300 es\nin vec2 aPos;\nout vec2 vUv;\nvoid main() {\n vUv = aPos * 0.5 + 0.5;\n gl_Position = vec4(aPos, 0.0, 1.0);\n}", ge = "// ── Palette LUT (W5 — OKLCh/OKLab interpolation) ──────────────────────────────\n// The endpoints stay CPU-baked to LINEAR sRGB (the Aras precompute pattern); only\n// the BETWEEN-endpoint interpolation runs in perceptual space. AX.W11 — the ramp\n// itself (the smoothstep ease + the OKLab-rectangular-vs-OKLCh-hue-arc dispatch on\n// uHuePath) is the shared samplePaletteRamp from procedural-color.glsl, the SAME\n// source the WebGPU twin splices; samplePalette here only selects the bracketing\n// stop pair + the raw inter-stop t and hands them to the shared ramp.\nvec3 samplePalette(float id) {\n id = clamp(id, 0.0, 1.0);\n float scaled = id * float(uStopCount - 1);\n int i0 = int(floor(scaled));\n int i1 = min(i0 + 1, uStopCount - 1);\n float t = fract(scaled);\n return samplePaletteRamp(uPalette[i0], uPalette[i1], t, uHuePath);\n}\n\n// ── Nuclei field ──────────────────────────────────────────────────────────\nvoid nucleiField(vec2 p, float t, out float paletteId, out float valueMod) {\n float accumBias = 0.0;\n float accumValue = 0.0;\n float accumW = 0.0;\n for (int i = 0; i < MAX_NUCLEI; i++) {\n if (i >= uNucleiCount) break;\n vec2 posI = uNucleiPos[i]\n + uNucleiDriftRadius[i] * vec2(\n cos(t * uNucleiDrift * K_NUCLEI + uNucleiDriftPhase[i]),\n sin(t * uNucleiDrift * K_NUCLEI + uNucleiDriftPhase[i] * 1.13)\n );\n vec2 diff = p - posI;\n // Anisotropic Gaussian: rotate diff into the nucleus's local frame\n // (major axis along uNucleiAngle), then scale the major-axis component by\n // 1/elongation so the squared distance describes an ellipse. Defaults\n // 1.0/0.0 reduce to the isotropic dot(diff, diff).\n float ca = cos(uNucleiAngle[i]);\n float sa = sin(uNucleiAngle[i]);\n vec2 local = vec2( ca * diff.x + sa * diff.y,\n -sa * diff.x + ca * diff.y);\n float along = local.x / max(uNucleiElong[i], 0.01);\n float across = local.y;\n float d2 = along * along + across * across;\n float r = max(uNucleiRadius[i], 0.01);\n float w = exp(-uSoftmaxBeta * d2 / (r * r));\n accumBias += w * uNucleiPaletteBias[i];\n accumValue += w * uNucleiValueBias[i];\n accumW += w;\n }\n paletteId = accumBias / max(accumW, 1e-4);\n valueMod = accumValue / max(accumW, 1e-4);\n\n // Palette drift — slow global paletteId breathe between adjacent stops. The\n // rate rides K_PAL (perceptible ~30–60s hue cycle at the default coefficient);\n // the amplitude lifts the authored coefficient into a 0.03..0.06 paletteId band\n // so the palette visibly travels rather than dithering within one stop.\n float palAmp = clamp(uPaletteDrift * 6.0, 0.0, 0.06);\n paletteId += palAmp * sin(t * uPaletteDrift * K_PAL);\n paletteId = clamp(paletteId, 0.0, 1.0);\n}\n", _e = "// ── Flow field ────────────────────────────────────────────────────────────\n// Structure-tensor prototype (body defined post-sampleBase in the mediums block).\n// Returns vec4(dir.x, dir.y, coherence, packedGrad) — the minor-eigenvector tangent + A + the\n// metal-gradient .w lane (BG.W-AUR-METAL-FINISH widened vec3→vec4). The forward decl MUST match\n// the vec4 definition or WebKit's compiler rejects the mismatched signature (L1b).\nvec4 structureTensorField(vec2 p, float t, vec2 fallbackDir);\n\nvec2 flowField(vec2 p, float t) {\n vec2 dir = vec2(1.0, 0.0);\n if (uFlowPattern == 1) {\n // radial\n dir = normalize(p - uFlowFocal + 1e-4);\n } else if (uFlowPattern == 2) {\n // swirl — tangent to radial\n vec2 rad = normalize(p - uFlowFocal + 1e-4);\n dir = vec2(-rad.y, rad.x);\n } else if (uFlowPattern == 3) {\n // diagonal\n float a = radians(uFlowAngle);\n dir = vec2(cos(a), sin(a));\n } else if (uFlowPattern == 4) {\n // multi — curl-noise driven\n float n = fbm(p * 2.0 + t * 0.02);\n float a = n * 6.2831;\n dir = vec2(cos(a), sin(a));\n } else if (uFlowPattern == 5) {\n // tensor / ETF — the color field's OWN edge-tangent flow (AW.W4.1). The\n // diagonal angle seeds the smooth fallback the coherence-weighted blend\n // relaxes toward in low-structure zones. Returns directly (no curl/cursor\n // post-mix — the tensor field already carries the structure orientation;\n // the cursor warp still drives the underlying color field in domainWarp).\n float a = radians(uFlowAngle);\n vec2 fallback = vec2(cos(a), sin(a));\n return structureTensorField(p, t, fallback).xy;\n }\n // curl — perturb by noise. Radial gets much less curl so rays stay clean.\n if (uFlowCurl > 0.0) {\n float n = fbm(p * 3.0) - 0.5;\n float curlAmt = uFlowCurl;\n if (uFlowPattern == 1) curlAmt *= 0.25; // radial: preserve ray clarity\n if (uFlowPattern == 2) curlAmt *= 0.55; // swirl: allow moderate curl\n float a = atan(dir.y, dir.x) + n * 3.14159 * curlAmt;\n dir = vec2(cos(a), sin(a));\n }\n // cursor influence — swirl around the cursor position\n if (uCursorStrength > 0.001) {\n vec2 toCur = uCursor - p;\n float d = length(toCur);\n float r = max(uCursorRadius, 0.01);\n float w = exp(-(d * d) / (r * r * 0.5));\n // swirl tangent\n vec2 tangent = vec2(-toCur.y, toCur.x) / max(d, 1e-4);\n float a0 = atan(dir.y, dir.x);\n float a1 = atan(tangent.y, tangent.x);\n // blend angle\n float da = a1 - a0;\n da = atan(sin(da), cos(da)); // wrap to [-pi, pi]\n float a = a0 + da * w * uCursorStrength;\n dir = vec2(cos(a), sin(a));\n }\n // AW.W8.1 — velocity-reactive swirl-BURST: a fast flick (uCursorBurst, decaying\n // over ~1s) injects a transient flow bias along the pointer velocity, distinct from\n // the steady attraction above (the stateless swirl is SUPERSEDED by this form). The\n // burst is gated by the master tempo scalar on the CPU side (it decays to 0 under\n // PRM/pause), so this term cannot leak motion under reduced-motion.\n if (uCursorBurst > 0.001) {\n vec2 toCur = uCursor - p;\n float d = length(toCur);\n float r = max(uCursorRadius, 0.01);\n float w = exp(-(d * d) / (r * r * 0.7));\n // Bias the flow toward the velocity direction, scaled by the decaying burst.\n vec2 velDir = uCursorVelocity / max(length(uCursorVelocity), 1e-4);\n float a0 = atan(dir.y, dir.x);\n float a1 = atan(velDir.y, velDir.x);\n float da = atan(sin(a1 - a0), cos(a1 - a0));\n float a = a0 + da * w * uCursorBurst * 0.8;\n dir = vec2(cos(a), sin(a));\n }\n return dir;\n}\n", ve = "// Khronos PBR-Neutral tonemap (hue + saturation preserving)\nvec3 aces(vec3 color) {\n const float startCompression = 0.8 - 0.04;\n const float desaturation = 0.15;\n float x = min(color.r, min(color.g, color.b));\n float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n color -= offset;\n float peak = max(color.r, max(color.g, color.b));\n if (peak < startCompression) return clamp(color, 0.0, 1.0);\n float d = 1.0 - startCompression;\n float newPeak = 1.0 - d * d / (peak + d - startCompression);\n color *= newPeak / peak;\n float g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);\n return clamp(mix(color, newPeak * vec3(1.0), g), 0.0, 1.0);\n}\n", ye = "// ── Curved swept brushstroke primitive ────────────────────────────────────\n// A stroke is a curved spine from A to B with quadratic bulge K (sideways offset\n// at midpoint). Width varies along length via a shape profile. Edge is ragged\n// (bristle-modulated), ends are rounded blobs, inside has streak modulation.\n//\n// For pixel p, we invert an approximate projection onto the curved spine:\n// 1) project p onto straight AB axis -> along0, cross0\n// 2) at parameter along0, spine offset = 4·K·along0·(1-along0) perpendicular\n// 3) cross = cross0 - spineOffset, refine along one iteration\n// Coverage blends paint atop col based on per-stroke color sampled from the\n// underlying base at spine midpoint — so overlapping strokes from different\n// palette regions meet at hard, ragged demarcations.\n\nstruct StrokeHit {\n float coverage; // 0..1\n vec3 color;\n float alongT; // 0..1 along spine, for internal modulation\n float crossN; // cross distance / current half-width, signed\n float edgeN; // distance to edge in half-widths (0 = at edge, 1 = at spine)\n};\n\nStrokeHit noHit() { return StrokeHit(0.0, vec3(0.0), 0.0, 0.0, 0.0); }\n\nvec2 rotateDir(vec2 dir, float angle) {\n float ca = cos(angle), sa = sin(angle);\n return vec2(dir.x * ca - dir.y * sa, dir.x * sa + dir.y * ca);\n}\n\nvec2 safeDir(vec2 dir) {\n float len = length(dir);\n return len > 1e-4 ? dir / len : vec2(1.0, 0.0);\n}\n\n// Shape profile along the stroke. type:\n// 0 tapered — thin-fat-thin (classic brush)\n// 1 load-drag — fat start, tapers to a point\n// 2 dab — ellipse-like, round center\n// 3 even — near-constant, slight end taper\n// 4 comma — van-Gogh atomic dab: ASYMMETRIC taper, fat near one end and\n// drawn to a fine point at the other (the divisionist crescent\n// mark). The width peak sits off-centre (~0.32) so the two ends\n// taper at DIFFERENT rates — a loaded round head + a dragged tail.\nfloat strokeShape(float t, int type) {\n t = clamp(t, 0.0, 1.0);\n if (type == 1) {\n // loaded at t=0, tapering\n return pow(1.0 - t, 0.55) * smoothstep(0.0, 0.08, t);\n } else if (type == 2) {\n // dab / blob\n float d = t - 0.5;\n return exp(-d * d * 12.0);\n } else if (type == 3) {\n // mostly even, slight end softening\n return smoothstep(0.0, 0.08, t) * smoothstep(1.0, 0.92, t) * 0.95 + 0.05;\n } else if (type == 4) {\n // comma / crescent — width peaks at ~0.32 then drags to a fine tail. The two\n // sides of the peak fall at different exponents (a fat round head, a long thin\n // tail), so the mark reads as a directional van-Gogh comma, not a symmetric oval.\n float peak = 0.32;\n float head = smoothstep(0.0, peak, t); // rounded loaded head\n float tail = pow(clamp((1.0 - t) / (1.0 - peak), 0.0, 1.0), 1.6); // dragged thin tail\n return clamp(min(head, tail) * 1.04, 0.0, 1.0);\n }\n // 0 tapered\n return smoothstep(0.0, 0.22, t) * smoothstep(1.0, 0.78, t);\n}\n\n// A single curved stroke.\n// a, b — endpoints\n// halfW — base half-width (world units)\n// bulge — signed perpendicular midpoint offset, in world units\n// shapeType — 0..3\n// bristleFreq — spatial frequency of edge raggedness\n// bristleAmp — 0..0.5 fraction of halfW chewed away at edge extrema\n// streakSeed — uniqueness seed for internal streaks\n// colAtMid — pre-sampled color at midpoint\nStrokeHit curvedStroke(vec2 p, vec2 a, vec2 b, float halfW,\n float bulge, int shapeType,\n float bristleFreq, float bristleAmp,\n float streakSeed, vec3 colAtMid) {\n vec2 ab = b - a;\n float L = length(ab);\n if (L < 1e-5) return noHit();\n vec2 tang = ab / L;\n vec2 norm = vec2(-tang.y, tang.x);\n\n vec2 rel = p - a;\n float along0 = dot(rel, tang) / L; // straight projection 0..1 along AB\n float cross0 = dot(rel, norm); // signed cross\n\n // Spine sideways offset due to bulge (parabolic)\n float bend = 4.0 * bulge * along0 * (1.0 - along0);\n float cross1 = cross0 - bend;\n\n // One refinement step: as the spine bends, the closest-point along shifts.\n // Spine tangent differs from straight tangent; first-order correction:\n float dBend = 4.0 * bulge * (1.0 - 2.0 * along0); // d(bend)/d(along)\n float along1 = along0 + (cross1 * dBend) / (L * (1.0 + dBend * dBend / (L * L)));\n\n // Bristle-ragged edge: half-width gets chewed by 1D noise along the spine\n float edgeNoise = fbm(vec2(along1 * bristleFreq, streakSeed * 7.3)) - 0.5;\n float edgeNoise2 = fbm(vec2(along1 * bristleFreq * 2.3, streakSeed * 3.1 + 17.0)) - 0.5;\n float edgeMod = 1.0 - bristleAmp * (0.6 + 0.4 * edgeNoise) * (0.5 + edgeNoise2);\n\n // Width profile along the stroke\n float shape = strokeShape(along1, shapeType);\n float halfWNow = halfW * shape * edgeMod;\n\n // Inside-segment coverage\n float cov = 0.0;\n if (along1 >= 0.0 && along1 <= 1.0 && halfWNow > 1e-6) {\n float cn = abs(cross1) / halfWNow;\n // fwidth-derived AA: half-width from the field's screen-space gradient so the\n // edge holds ~1px regardless of zoom/DPR (mirrors metaball.frag.ts:252-255).\n float aaC = max(fwidth(cn), 1e-6);\n cov = 1.0 - smoothstep(1.0 - aaC, 1.0 + aaC, cn);\n }\n\n // End-cap blobs (rounded tips, not perpendicular cuts)\n float capA = 0.0, capB = 0.0;\n {\n vec2 capCenterA = a + norm * (bulge * 0.0); // at a\n vec2 capCenterB = a + tang * L + norm * bend * 0.0 + norm * 0.0; // at b; bend is 0 at endpoints\n capCenterB = b;\n float endShapeA = strokeShape(0.02, shapeType);\n float endShapeB = strokeShape(0.98, shapeType);\n float rA = halfW * endShapeA * (0.9 + 0.2 * fbm(vec2(streakSeed * 13.0)));\n float rB = halfW * endShapeB * (0.9 + 0.2 * fbm(vec2(streakSeed * 19.0 + 5.0)));\n float dA = length(p - capCenterA);\n float dB = length(p - capCenterB);\n // fwidth-derived AA on the clean Euclidean cap distances (mirrors metaball.frag.ts:252-255).\n float aaA = max(fwidth(dA), 1e-6);\n float aaB = max(fwidth(dB), 1e-6);\n capA = 1.0 - smoothstep(rA - aaA, rA + aaA, dA);\n capB = 1.0 - smoothstep(rB - aaB, rB + aaB, dB);\n // Only apply caps if we're BEYOND the segment; otherwise the segment wins.\n capA *= (along1 < 0.05) ? 1.0 : 0.0;\n capB *= (along1 > 0.95) ? 1.0 : 0.0;\n }\n\n float coverage = max(cov, max(capA, capB));\n if (coverage < 0.002) return noHit();\n\n // Edge distance (for impasto later): 0 at edge, 1 at spine\n float edgeDist = halfWNow > 1e-6 ? clamp(1.0 - abs(cross1) / halfWNow, 0.0, 1.0) : 0.0;\n\n return StrokeHit(\n coverage,\n colAtMid,\n clamp(along1, 0.0, 1.0),\n halfWNow > 1e-6 ? cross1 / halfWNow : 0.0,\n edgeDist\n );\n}\n\n// The painterly STROKE mediums (those that deposit via paintStrokeLayers/paintOver):\n// oil (3), van-Gogh (5), oil-pastel (6). For these the stroke OVER-composite runs in\n// OKLab so overlapping complementaries mix through a chromatic path, not the linear-\n// RGB grey mud; the smooth/atmospheric pole never reaches paintOver so it pays nothing.\nbool isPainterlyStroke() {\n return uMedium == 3 || uMedium == 5 || uMedium == 6;\n}\n\n// OKLab OVER-composite: lerp L,a,b of the over-color toward the under-color (the\n// Ottosson matrices spliced from procedural-color.glsl.ts — no new color math). Two\n// complementary-hued strokes overlapping transition through OKLab, where the midpoint\n// holds chroma, instead of the linear mix() that desaturates toward grey (slice 8 F2).\nvec3 paintOverOklab(vec3 under, vec3 over, float alpha) {\n vec3 labU = linOklab(under);\n vec3 labO = linOklab(over);\n return max(oklabToLinearSrgb(mix(labU, labO, alpha)), vec3(0.0));\n}\n\n// Composite stroke over col with internal streaking + ACCUMULATE paint HEIGHT.\n// streakAmp — 0..0.2 how much internal streaks darken/lighten\n// impastoAmp — 0..1 paint-thickness contribution (the height the relight reads)\n// hardness — 0..1 how crisp the compositing transition is (1 = razor, 0 = creamy)\n//\n// AW.W4.2 — the fixed-RGB edge rim (the phantom upper-left light) is RETIRED. Each\n// stroke now deposits PAINT HEIGHT into the height accumulator (coverage x per-stroke\n// thickness, perturbed by the bristle/streak fbm for ridges/grooves); mediumOil\n// derives a normal from the accumulated height gradient (dFdx/dFdy) and relights it\n// once with the movable uLightDir source (relightImpasto), in linear before aces().\n//\n// AX.W13 — the internal streak now perturbs HUE + CHROMA in OKLCh (not value-only),\n// so a single stroke carries a small hue gradient (broken color at the ATOM level —\n// adjacent strokes shimmer like real impasto, not flat stamped swatches; slice 8 F5);\n// and the OVER-composite runs in OKLab on the painterly stroke mediums so overlapping\n// complementaries mix as pigment, not the linear-mix grey (slice 8 F2).\n// impastoFloor — the per-stroke height-crown floor: oil's 0.4+0.6*edgeN reads\n// floor=0.4 (the crown tapers to 40% at the stroke edge); the van-Gogh\n// profile passes floor=1.0 so each atomic dab catches a FULL-height\n// glint (scope item 1d). The crown magnitude is floor + (1-floor)*edgeN.\nvoid paintOver(inout vec3 col, inout float height, StrokeHit s,\n float streakFreq, float streakAmp,\n float impastoAmp, float hardness, float streakSeed,\n float impastoFloor) {\n if (s.coverage < 0.002) return;\n float strokeOpacity = clamp(uStrokeAmount, 0.0, 1.0);\n if (strokeOpacity <= 0.001) return;\n vec3 c = s.color;\n\n // Internal streaks — fbm along spine, modulated by cross position. Gives\n // the loaded-brush look: some bristles carry more pigment than others.\n float streakA = fbm(vec2(s.alongT * streakFreq, s.crossN * 2.7 + streakSeed));\n float streakB = fbm(vec2(s.alongT * streakFreq * 0.6 + streakSeed * 3.7, s.crossN * 4.1));\n float streak = 0.6 * (streakA - 0.5) + 0.4 * (streakB - 0.5);\n\n // ── WITHIN-stroke OKLCh broken color (AX.W13, slice 8 F5). The streak fBm perturbs\n // the stroke's HUE + CHROMA along alongT/crossN, seeded per-stroke, so a single\n // stroke reads a small hue gradient (the atom-level broken-color shimmer). Value is\n // carried by the same streak so the loaded-brush light/dark survives. Gated to the\n // painterly stroke mediums + uBrokenColor (the smooth pole keeps the cheap value-only\n // streak). A second decorrelated fBm drives the hue axis so hue ≠ a scaled value.\n float hueStreak = fbm(vec2(s.alongT * streakFreq * 0.45 + streakSeed * 5.3,\n s.crossN * 1.9 + streakSeed * 1.7)) - 0.5;\n if (isPainterlyStroke() && uBrokenColor > 0.001) {\n vec3 lch = oklabToOklch(linOklab(c));\n // ±~10° within-stroke hue swing + ±~9% chroma, scaled by uBrokenColor. Smaller\n // than the per-stroke cell jitter (brokenColorJitter) — this is the intra-stroke\n // gradient layered on top of the per-cell pigment patch.\n lch.z += hueStreak * (20.0 * PI / 180.0) * uBrokenColor;\n lch.y = max(lch.y * (1.0 + (streak) * 0.18 * uBrokenColor), 0.0);\n c = max(oklabToLinearSrgb(oklchToOklab(lch)), vec3(0.0));\n }\n // Value streak (the loaded-brush light/dark across the bristles) — kept for every\n // medium that reaches paintOver (the smooth pole never does). The along-spine value\n // modulation is the loaded-brush light/dark that gives each stroke its OWN directional\n // luminance band — the structure-tensor signal a low-contrast color field (a uniform-hue\n // oil field) has no other source for (the §4.2 anisotropy lift on the flat-palette case).\n c *= 1.0 + streak * streakAmp * 3.2;\n\n // Cross-stroke ridge/valley shading — a catch-light along the spine centre, darkening to\n // the stroke edges. This is the strongest DIRECTIONAL luminance cue: it carves a bright\n // ridge down the stroke's length and dark grooves between adjacent strokes, so a field of\n // parallel strokes reads as parallel light/dark bands (the high-A van-Gogh signature) even\n // where the underlying colour is flat. s.edgeN is 0 at the edge, 1 at the spine.\n float ridgeShade = smoothstep(0.0, 0.55, s.edgeN);\n c *= 1.0 + (ridgeShade - 0.5) * 0.30;\n\n float softLimit = mix(0.35, 0.98, hardness);\n float alpha = smoothstep(0.0, 1.0 - softLimit, s.coverage) * strokeOpacity;\n // OKLab OVER-composite on the painterly stroke mediums (overlap mixes as pigment,\n // not grey); the smooth pole never reaches paintOver, so it keeps the cheap path.\n col = isPainterlyStroke() ? paintOverOklab(col, c, alpha) : mix(col, c, alpha);\n\n // ── Accumulate paint HEIGHT (AW.W4.2). Thickness peaks at the stroke spine and\n // falls toward the impastoFloor at the edge (edgeN: 0=edge, 1=spine), perturbed by\n // the bristle streak so ridges/grooves form. The relight reads the gradient of this\n // field. The van-Gogh profile's floor=1.0 gives every atomic dab a full-height crown.\n float ridge = 0.7 + 0.3 * (streak + 0.5);\n float crown = impastoFloor + (1.0 - impastoFloor) * s.edgeN;\n height += s.coverage * impastoAmp * crown * ridge * alpha;\n}\n\n// AW.W4.2 — relight the accumulated paint height. Derive a normal from the height\n// gradient (dFdx/dFdy — derivatives are in-pattern; fwidth is already used for AA),\n// then apply diffuse + Blinn specular from the movable uLightDir/uLightColor source.\n// LINEAR-space lighting BEFORE aces() (the tonemap/OETF stay locked); thin strokes\n// inherit a low shininess, thick impasto raises it (high-height ridges catch a sharp\n// glint). canvasBase is the tooth height so the canvas weave also catches the light.\nvec3 relightImpasto(vec3 col, float height, float canvasBase) {\n float h = height + canvasBase;\n // Height-gradient normal. heightScale trades relief depth for surface flatness.\n float heightScale = 6.0;\n vec3 N = normalize(vec3(-dFdx(h) * 40.0, -dFdy(h) * 40.0, 1.0 / heightScale));\n vec3 L = normalize(uLightDir);\n vec3 V = vec3(0.0, 0.0, 1.0); // view straight on\n vec3 H = normalize(L + V);\n float diff = max(dot(N, L), 0.0);\n // Thick impasto → high shininess (sharp glint); thin paint → broad soft sheen.\n float shininess = mix(8.0, 64.0, clamp(height * 2.0, 0.0, 1.0));\n float spec = pow(max(dot(N, H), 0.0), shininess);\n // Modulate the lit terms by how much paint sits here (no relief on bare ground).\n float relief = clamp(h * 1.5, 0.0, 1.0);\n vec3 lit = col * (1.0 + uImpasto * relief * (diff - 0.5) * 0.5 * uLightColor);\n // The specular glint is gated to ACCUMULATED-thick paint (height²) — a per-fine-stroke\n // sharp glint on every thin fill dab read as bright isotropic SPECKLE that buried the\n // directional stroke bands (the §4.2 anisotropy / §4.3 slope sink on the low-contrast\n // oil field). Only where real impasto has built up does the raked glint fire, so the\n // highlight tracks the macro ridges, not the fine speckle.\n float specGate = clamp(height, 0.0, 1.0);\n lit += uImpasto * relief * spec * specGate * 0.5 * uLightColor;\n return lit;\n}\n\n// Best-of-9-neighbor placement: sample 3x3 surrounding cells and take the\n// stroke that covers this pixel most. Breaks the grid by per-cell jitter and\n// sparse density via noise thresholding.\n// energyGrade — the SBR energy-grade magnitude (0 = none, the oil/oil-pastel\n// baseline; 1 = the full van-Gogh Starry-Night cascade — long\n// confident strokes in the lights/coherent zones, short dabs in\n// the darks/flat zones). The van-Gogh profile carries 1.0 (the\n// energy grade is a PROFILE field, not a buried uMedium==5 branch).\nStrokeHit bestOil(vec2 p, float cellSize, float lenMul, float halfWMul,\n float jitterAmt, float density, int shapeType,\n float bristleAmp, vec2 flow, float t, float seed,\n float energyGrade) {\n vec2 cell = floor(p / cellSize);\n\n StrokeHit best = noHit();\n // 3x3 neighborhood\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cc = cell + vec2(float(dx), float(dy));\n vec2 hh = hash22(cc + seed) - 0.5;\n // Density gate — noise threshold; sparse placement.\n float gate = hash21(cc * 1.7 + seed * 0.3);\n if (gate > density) continue;\n\n vec2 center = (cc + 0.5 + hh * jitterAmt) * cellSize;\n\n // Per-stroke direction source — the AW.W4.1 strokeOrient switch:\n // uStrokeOrient==0 (flow) — the layer-provided hand-authored flowField.\n // uStrokeOrient==1 (tensor) — the structure-tensor minor eigenvector at the\n // cell center (the color field's edge-tangent),\n // so strokes hug the color zones (van Gogh).\n // coh carries the per-cell coherence A for the W4.3 energy grading (long\n // confident strokes where structure is coherent, stubby dabs in flat zones).\n vec2 f;\n float coh = 1.0;\n if (uStrokeOrient == 1) {\n // vec4 (the metal-finish widen) — .xy tangent + .z coherence; the .w gradient lane\n // is unused here. A vec3 local would be a type-mismatch WebKit rejects (L1c).\n vec4 tf = structureTensorField(center, t, safeDir(flow));\n f = safeDir(tf.xy);\n coh = tf.z;\n } else {\n f = safeDir(flow);\n }\n // Per-stroke deterministic local perturbation so alternate stroke layers stay\n // live. Tensor strokes get FAR less angular jitter (the field already orients them\n // — over-jittering the tensor strokes scatters their directions and the rendered\n // field reads isotropic, the §4.2 anisotropy floor). The flow-oriented (non-tensor)\n // strokes keep the full jitter (they have no per-cell orientation source).\n float jScale = (uStrokeOrient == 1) ? 0.15 : 1.0;\n float angJ = (hash21(cc + seed + 11.0) - 0.5) * 0.9 * jScale; // +/- 0.45/0.07 rad\n float curlScale = (uStrokeOrient == 1) ? 0.30 : 1.0;\n float localCurl = (fbm(center * (2.6 + seed * 0.11) + seed * 1.9) - 0.5) * 0.55 * uFlowCurl * curlScale;\n vec2 dir = rotateDir(f, angJ + localCurl);\n\n // AX.W13 — the SBR energy grade is a PROFILE field (energyGrade), not a buried\n // uMedium==5 branch. The van-Gogh profile passes energyGrade=1.0 (the full\n // Starry-Night cascade); oil/oil-pastel pass 0.0 (uniform length). The grade\n // modulates stroke length by local luminance (bright → long confident strokes,\n // dark → short dabs, the Kolmogorov/Batchelor congruence) AND by coherence\n // (coherent zones → long, flat → stubby), lerped in by energyGrade so a profile\n // can dial the cascade from off (0) to full (1).\n float energy = 1.0;\n if (energyGrade > 0.001) {\n float luma = clamp(dot(sampleBase(center, t), W_LUMA), 0.0, 1.0);\n float graded = mix(0.5, 1.5, luma) * mix(0.6, 1.0, coh);\n energy = mix(1.0, graded, energyGrade);\n }\n\n float lenV = cellSize * lenMul * (0.65 + 0.55 * hash21(cc + seed + 23.0)) * energy;\n float halfW = cellSize * halfWMul * (0.70 + 0.55 * hash21(cc + seed + 41.0));\n float bulge = (hash21(cc + seed + 53.0) - 0.5) * lenV * 0.35;\n\n vec2 a = center - dir * (lenV * 0.5);\n vec2 b = center + dir * (lenV * 0.5);\n\n vec3 colMid = brokenColorJitter(\n sampleBase(center, t),\n hash21(cc + seed + 89.0),\n hash21(cc * 2.3 + seed + 97.0),\n 1.0\n );\n\n StrokeHit h = curvedStroke(p, a, b, halfW, bulge, shapeType,\n 7.0, bristleAmp,\n hash21(cc + seed + 67.0), colMid);\n if (h.coverage > best.coverage) best = h;\n }\n }\n return best;\n}\n", be = "// ── Van-Gogh — DEDICATED atomic-dab body (W-AUR-VANGOGH-REBUILD) ─────────────\n// REBUILT FROM FIRST PRINCIPLES. The prior path routed van-Gogh through the shared\n// oil paintStrokeMedium cascade — four DENSE layers of LONG-THIN tensor-oriented\n// strokes (lenMul up to 5.2, widMul 0.22) hugging a continuous coherent field. Packed\n// that tight, thin strokes that follow continuous iso-bands MERGE into smooth flowing\n// filaments — the \"marbled flow-bands\" read (a spirograph/fingerprint, not impasto),\n// AND the per-cell 8-tap structure tensor × 4 layers × 9 cells = ~324 sampleBase/pixel\n// made it run at ~4fps. Van Gogh's sky is NOT continuous flow — it is DISCRETE, SHORT,\n// LOADED comma dabs, separated by visible ground, queued into swirl ROWS.\n//\n// The rebuild is a purpose-built two-layer DAB pass, disjoint from the oil cascade:\n// • orientation from the analytic SWIRL flowField (van-Gogh skies ARE swirl rows) +\n// per-cell angular jitter — NOT the expensive per-cell tensor (the lag source, and\n// the marble source: a jittered discrete dab can NOT merge into a continuous\n// filament the way a tensor-locked thin stroke does).\n// • SHORT comma dabs (len/wid ≈ 2.6 : 1 — a loaded crescent mark, not a 10:1\n// filament), so each reads as a SEPARABLE atom.\n// • SPARSE placement with visible inter-dab ground (density ≈ 0.42), over a darkened\n// swirl underpainting (the Starry-Night visible ground the bright dabs read over).\n// • a single sampleBase per cell + OKLCh broken-color jitter (pigment shimmer);\n// full-height impasto crown per dab (each catches its own raked glint).\n// This is ~2 layers × 9 cells × ~1 sampleBase ≈ 20/pixel (a ~16× cost cut, ~60fps), and\n// jittered short dabs CANNOT marble.\n\n// One atomic comma dab — a CLEAN analytic crescent SDF (NOT the oil curvedStroke).\n// The oil curvedStroke's spine-projection + rounded end-caps + fwidth-AA + bristle\n// edge each leave a thin sub-pixel skirt, and a field of those skirts over open ground\n// abuts into a faint network of SEAM LINES. A van-Gogh dab needs none of that\n// machinery — it is a short oriented capsule (rounded line segment) whose half-width\n// tapers along its length (the loaded-head → dragged-tail comma). The capsule SDF is\n// derivative-free (smoothstep AA against the analytic distance), so no fwidth skirt, no\n// best-of-9 seam. Returns a StrokeHit (coverage/color/alongT/edgeN) for paintOver.\n// cellSize — dab cell pitch (UV units); lenMul/widMul — dab aspect off the cell;\n// density — placement gate (sparse → visible gaps); seed — layer decorrelation.\nStrokeHit vangoghDab(vec2 p, float cellSize, float lenMul, float widMul,\n float density, float jitterAmt, float angJitter,\n vec2 flow, float t, float seed) {\n vec2 cell = floor(p / cellSize);\n StrokeHit best = noHit();\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cc = cell + vec2(float(dx), float(dy));\n // Sparse density gate — leaves visible canvas ground between dabs (atomicity).\n if (hash21(cc * 1.7 + seed * 0.3) > density) continue;\n vec2 jit = (hash22(cc + seed) - 0.5) * jitterAmt;\n vec2 center = (cc + 0.5 + jit) * cellSize;\n\n // Orientation: the analytic swirl flow at the cell center + per-cell angular\n // jitter (so adjacent dabs FAN — the divisionist scatter that keeps the dabs from\n // locking into perfectly-concentric rows) + a flow-noise curl wobble.\n float ang = (hash21(cc + seed + 11.0) - 0.5) * angJitter;\n float curl = (fbm(center * 3.1 + seed * 1.9) - 0.5) * (0.18 + 0.3 * uFlowCurl);\n vec2 dir = rotateDir(safeDir(flow), ang + curl);\n\n // SHORT comma — len ≈ the cell pitch (a contained dab, not a tiling filament).\n float len = cellSize * lenMul * (0.82 + 0.30 * hash21(cc + seed + 23.0));\n float halfW = max(cellSize * widMul * (0.86 + 0.28 * hash21(cc + seed + 41.0)), 0.010);\n\n // Local dab frame: along = projection onto the dab axis (centred 0), perp = cross.\n vec2 rel = p - center;\n float along = dot(rel, dir);\n float perp = dot(rel, vec2(-dir.y, dir.x));\n // The comma TAPER: half-width peaks ~1/3 from the loaded head and drags to a fine\n // tail (the asymmetric crescent). u in [0,1] along the dab from head to tail.\n float halfLen = len * 0.5;\n float u = clamp((along + halfLen) / max(len, 1e-5), 0.0, 1.0);\n float head = smoothstep(0.0, 0.30, u); // rounded loaded head\n float tail = pow(clamp((1.0 - u) / 0.70, 0.0, 1.0), 1.3); // dragged thin tail\n float prof = clamp(min(head, tail) * 1.05, 0.0, 1.0);\n float wNow = halfW * prof;\n // A gentle comma CURVE — bow the spine sideways so the mark reads as a crescent.\n float bowAmt = (hash21(cc + seed + 53.0) - 0.5) * halfW * 1.4;\n float spine = bowAmt * sin(u * PI); // 0 at ends, max mid\n float d = abs(perp - spine);\n // Derivative-free AA: a fixed fraction of the dab width (no fwidth skirt). Coverage\n // is 1 in the dab body, smoothly 0 at the edge; outside the [head,tail] span wNow→0\n // so the dab self-terminates with no end-cap blob.\n float aa = max(halfW * 0.45, 0.002);\n float cov = (wNow > 1e-5) ? (1.0 - smoothstep(wNow - aa, wNow + aa, d)) : 0.0;\n if (cov < 0.004) continue;\n\n // One sampleBase per cell + OKLCh broken-color jitter (pigment patch shimmer). The\n // dab pigment is chroma-boosted (saturate3 1.22) AND value-lifted (×1.14) at the\n // SOURCE — the loaded brush mark deposits BRIGHTER + more saturated pigment than the\n // base field, so the loaded-mark pixels lift BOTH the §4.1 colourfulness AND the field\n // mean-luma. The higher mean raises the gap-fraction threshold (meanLum·0.6) so the\n // moderate-depth inter-dab ground falls below it (the gap-fraction atomicity read is\n // DECOUPLED from the ground floor depth — the ground can stay only moderately dark, so\n // the §4.3 slope is NOT over-steepened, while the bright dabs manufacture the gap). The\n // dark ground is untouched, so this lifts C + gap WITHOUT a band-conflicting deep ground.\n vec3 colMid = brokenColorJitter(\n saturate3(sampleBase(center, t), 1.22),\n hash21(cc + seed + 89.0),\n hash21(cc * 2.3 + seed + 97.0),\n 1.0\n );\n\n // edgeN: 1 at the spine, 0 at the edge (the impasto crown reads it).\n float edgeN = (wNow > 1e-5) ? clamp(1.0 - d / wNow, 0.0, 1.0) : 0.0;\n if (cov > best.coverage) {\n best = StrokeHit(cov, colMid, u, (wNow > 1e-5 ? (perp - spine) / wNow : 0.0), edgeN);\n }\n }\n }\n return best;\n}\n\nvec3 mediumVangogh(vec3 col, vec2 p, float t) {\n vec3 result = col;\n float height = 0.0;\n\n // The swirl flow basis (van-Gogh sky = swirl rows). Computed ONCE per pixel.\n vec2 flow = flowField(p, t);\n\n // Dab cell pitch in UV [0,1]. CHUNKY, SEPARABLE marks — the big layer is ~1/14 of\n // the frame so it reads as a distinct loaded brush dab (not a fine speckle, not a\n // screen-spanning filament). uStrokeScale (authored ~110) modulates the pitch\n // INVERSELY (higher = finer dabs) around the ~0.07 chunky default; clamped so the\n // dab never collapses to noise or balloons past one screen. uStrokeAnisotropy\n // stretches the comma aspect (longer, more directional marks).\n float pitch = clamp(7.0 / max(uStrokeScale, 20.0), 0.044, 0.12);\n // The dab LENGTH ≈ the cell pitch (lenAniso ~1.2-1.7) so a dab sits WITHIN its cell\n // and leaves visible ground around it — a longer dab (lenMul > 2) spans neighbour\n // cells and tiles the field into continuous coverage (no gaps, the gap-fraction floor\n // miss + the marble). Narrow width keeps it a directional crescent, not a wide shard.\n // lenAniso/widAniso — the comma aspect. The W-AUR-VANGOGH-CONFIG reconcile lengthened\n // the comma (1.25-1.75 → 1.5-2.0) and THINNED it (0.40-0.30 → 0.32-0.24): the rebuilt\n // dabs measured §4.2 structure-tensor anisotropy A=0.699, BELOW the reference band\n // floor 0.732 (the dabs read slightly too short-fat → locally isotropic, dragging mean\n // A down). A LONGER, THINNER comma hugs the swirl-flow tangent more strongly so the\n // rendered field reads coherent the way the tensor metric measures it (A lift), while\n // the thinner width LEAVES MORE inter-dab ground (the gap-fraction atomicity read is\n // preserved, not closed). The length stays ≈ the cell pitch so each dab remains a\n // CONTAINED separable mark, not a tiling filament.\n float lenAniso = mix(2.1, 2.7, uStrokeAnisotropy); // comma length / cell pitch (a contained dab)\n float widAniso = mix(0.23, 0.16, uStrokeAnisotropy); // comma width / cell pitch (a thin loaded crescent)\n\n // Layer 1 — the big swirl-row dabs: the loaded gestural marks, SPARSE so the dark\n // underpainting shows BETWEEN them (the atomicity read — visible inter-dab ground).\n // hardness 0.74 — the loaded brush deposits with a SOFT shoulder, so adjacent dabs\n // feather instead of razor-clipping into hard polygon shards. jitterAmt 0.85 fully\n // scatters the cell centres so the placement GRID never reads as a periodic seam.\n // angJitter EASED 0.55 → 0.38 (the reconcile A lift): a tighter angular spread keeps\n // adjacent dabs more flow-aligned (coherent) while the per-cell curl wobble still\n // breaks the perfectly-concentric-rows read (the dabs FAN gently, not lock to a grid).\n // angJitter eased 0.38 → 0.26 + hardness 0.74 → 0.84 (the §4.2 A lift): a tighter angular\n // spread keeps adjacent dabs strongly flow-aligned (the structure-tensor coherence) and a\n // sharper edge gives each dab a STRONGER directional gradient (a soft dab's faint edge\n // reads weakly anisotropic). The per-cell curl wobble still breaks the perfectly-\n // concentric-rows read, so the dabs FAN gently rather than locking to a grid.\n StrokeHit dBig = vangoghDab(p, pitch, lenAniso, widAniso,\n 0.30, 0.50, 0.08, flow, t, 1.3);\n // streakFreq raised 14 → 34 (the §4.3 slope fix): a high-frequency streak runs ALONG the\n // dab spine, injecting fine-scale luma energy that flattens the too-steep β WITHOUT\n // adding new isotropic marks (the along-spine streak stays directional, so the §4.2\n // anisotropy the long-thin dab carries is preserved — the band-conflict resolution).\n paintOver(result, height, dBig, 48.0, 0.34,\n uImpasto * 0.75 * uStrokeAmount, 0.84, 1.3, 1.0 /* full crown */);\n\n // Layer 2 — two-thirds-pitch accent dabs (the divisionist sparkle between the big\n // marks — denser placement but still contained dabs, so dark canvas survives between).\n // angJitter eased 0.5 → 0.34 (same A-lift reasoning — the accent dabs queue along the\n // flow rather than scattering isotropically); hardness 0.78 → 0.86 sharpens the gradient.\n StrokeHit dSml = vangoghDab(p + vec2(-5.1, 8.4), pitch * 0.62, lenAniso * 0.95,\n widAniso * 0.95, 0.36, 0.60, 0.20, flow, t, 4.1);\n paintOver(result, height, dSml, 42.0, 0.22,\n uImpasto * 0.55 * uStrokeAmount, 0.86, 4.1, 1.0);\n\n // Layer 3 — the FINE divisionist flecks (W-AUR-VANGOGH-CONFIG reconcile). The two-layer\n // field read as a few BIG cobalt dabs over a smooth empty teal ground (the side-by-side\n // against starry-night-crop.png: the painting is DENSE small varied flecks, not sparse\n // large marks). The flecks are LONG·THIN directional commas hugging the swirl tangent\n // (the A-preserving fleck — short fat flecks read isotropic and drag §4.2 down). Sparse\n // density 0.30 keeps the inter-fleck ground open (the gap-fraction atomicity read).\n // The flecks are FINE (≈0.42× pitch) directional commas, tightly flow-aligned (angJitter\n // 0.22) and SPARSE (0.30) — the divisionist sparkle between the loaded marks that keeps\n // the inter-dab ground open (atomicity) while adding the small-mark mid-band energy. Thin\n // + flow-aligned so the §4.2 anisotropy the long dabs carry survives the added small marks.\n StrokeHit dFleck = vangoghDab(p + vec2(8.7, -3.2), pitch * 0.42, lenAniso * 1.0,\n widAniso * 0.68, 0.30, 0.85, 0.22, flow, t, 7.7);\n paintOver(result, height, dFleck, 30.0, 0.16,\n uImpasto * 0.40 * uStrokeAmount, 0.80, 7.7, 1.0);\n\n // ── Flow-aligned GROUND swirl-GROOVING (W-AUR-VANGOGH-CONFIG reconcile) ──\n // The bare ground between the dabs was a SMOOTH low-frequency teal gradient — the §4.3\n // power-spectrum slope ran too STEEP (β≈−2.0: too much low-frequency nuclei-field energy\n // vs the high band). Van Gogh's actual sky has the swirl BRUSHWORK everywhere, so groove\n // the OPEN GROUND with a flow-aligned ripple. It is SUBTRACTIVE-biased (it only darkens,\n // never brightens the ground), so it DEEPENS the inter-dab valleys (MORE gap-fraction —\n // atomicity preserved/strengthened) while injecting the across-flow mid-band luma energy\n // that flattens β. Gated to the open ground (low height) via the (1-height) gate so it\n // never lifts/erodes the loaded dab bodies (the dab read is untouched). Across the swirl\n // FLOW axis so the grooves run WITH the sky's brushwork direction.\n // The ground swirl-combing — a FIXED-global-angle directional grain on the open ground.\n // A flow-FOLLOWING comb varies its direction with the swirl across the readback window,\n // so its blurred structure tensor averages toward isotropic (no §4.2 lift). A comb at one\n // GLOBAL angle (van-Gogh's dominant diagonal stroke grain) is COHERENT over the whole\n // window ⇒ every open-ground pixel reads the SAME direction (the §4.2 mean-anisotropy lift\n // the swirl comb could not reach). Two resolved bands (≈22 + ≈44 across the global axis ⇒\n // ~21px + ~11px at 464px, both in the §4.3 fit window) also feed the β flatten. Gated to\n // the open ground (low height) so the loaded dabs are untouched; SUBTRACTIVE-biased so the\n // inter-dab valleys deepen (gap-fraction preserved, not filled).\n vec2 gdir = normalize(vec2(0.82, 0.57)); // the dominant global stroke grain axis\n float gacross = dot(p, vec2(-gdir.y, gdir.x));\n float groundGate = 1.0 - smoothstep(0.05, 0.28, height);\n float groove = sin(gacross * 22.0) + 0.5 * sin(gacross * 44.0 + 1.3);\n result *= 1.0 - 0.16 * groundGate * (0.5 - 0.5 * groove);\n\n // Canvas tooth (fine linen weave — base relief the raking light catches).\n float tooth1 = vnoise(p * 220.0);\n float tooth2 = vnoise(p * 220.0 * vec2(0.6, 2.4) + 37.0);\n float tooth = (0.6 * tooth1 + 0.4 * tooth2) - 0.5;\n result *= 1.0 + tooth * 0.06 * uCanvasGrain;\n\n // Relight the accumulated impasto height (raking light catches each dab's crown —\n // the visible impasto ridge that makes a dab read as a RAISED loaded mark).\n float canvasBase = tooth * 0.06 * 0.5;\n result = relightImpasto(result, height, canvasBase);\n\n // The visible Starry-Night GROUND — the open canvas between dabs (low accumulated\n // height) darkens toward the deep underpainting, so the bright impasto dabs read as\n // SEPARABLE atomic marks over a darker field (the dab↔ground contrast the user's\n // \"reads as strokes\" bar needs, AND the painterly-statistics gap-fraction floor — the\n // dark inter-dab ground must register as a measurable fraction of the field). 0.30\n // floor over a WIDER smoothstep (0..0.40): deep enough that the open gaps read as the\n // dark Starry-Night sky between marks (clearing the 4% gap floor) while the gradual\n // ramp keeps the gaps reading as flowing underpainting, not the hard black ink LINES a\n // narrow near-black step (0.26 / 0.0..0.32) produced.\n // The smoothstep FLOOR starts at 0.10 (not 0): a dab's faint AA coverage TAIL deposits\n // a sliver of height, and where many tails align along the swirl flow those slivers\n // accumulate into a faint continuous height ridge that read as thin curved LINES in the\n // ground. Holding the ground full-dark until a real dab CORE (height > 0.10) lifts out\n // keeps the open field clean — only the loaded dab bodies emerge, the tails stay ground.\n result *= mix(0.115, 1.0, smoothstep(0.085, 0.31, height));\n\n // The van-Gogh chroma — a light OKLCh punch. EASED to 0.92 (off 1.04) in the\n // W-AUR-VANGOGH-CONFIG reconcile: the rebuilt discrete-dab register's per-dab OKLCh\n // broken-color jitter (the ±16° hue + ±chroma swing per cell) lifts the field's\n // colourfulness on its own, so the prior 1.04 punch on TOP overshot the §4.1\n // reference band (rendered C=100.5 vs the painting's measured 70.67 ± 15/+25 →\n // ceiling 95.67 — neon, not Starry Night's rich-but-not-garish blue/gold). The 0.92\n // demote pulls the rendered colourfulness back IN-band while the broken-color jitter\n // keeps the per-dab pigment variation (the discrete-stroke read is untouched — this\n // is a chroma scale, not a dab-geometry change). Band-anchored on the real painting\n // (proof:aurora-arresting), NOT a widened band.\n result = saturate3(result, 1.0);\n return result;\n}\n\n", xe = "StrokeProfile profileFor(int medium, int mode) {\n // The oil baseline (mode 0) — balanced modern-abstract/palette-knife hybrid.\n StrokeProfile prof = StrokeProfile(\n 0, // shapeType — tapered\n 0.25, // bristleAmp\n 9.0, // streakFreq\n 0.09, // streakAmp\n 0.9, // impastoAmp\n 0.80, // hardness\n 340.0, // toothScale — W-AUR-VANGOGH-CONFIG reconcile: FINER 240 → 340. Oil's §4.3 β sat\n // right AT the −1.45 band ceiling (±0.02 frame variance straddling\n // it, surfaced once the vangogh bands went green and the spec reached\n // the oil β assert). MEASURED on the live GPU: ADDING fine high-\n // frequency tooth energy steepens oil's power-spectrum slope (more\n // negative — coarsening it the other way pushed β SHALLOWER to\n // −1.33). A finer, stronger tooth moves β to a safe distance inside\n // the −5/3 band [−1.85, −1.45]. Oil-only (oil-pastel sets 280).\n 0.14, // toothAmp — raised 0.09 → 0.14 (same oil-β steepen: more fine-grain high band).\n 1.03, // pigmentSat\n 0.65, // densityBig\n 0.78, // densityMed\n 0.90, // densitySml\n 0.0, // energyGrade — oil is uniform-length (no Starry-Night cascade)\n 0.4, // impastoFloor — oil's 0.4+0.6·edgeN crown falloff\n 0.92, // densityFill — oil fills DENSELY with the directional low-relief fill so the\n // flat-colour regions between the macro strokes are TEXTURED with\n // flow-aligned fine strokes (the §4.2 anisotropy needs every pixel\n // to carry directional gradient; a flat untextured region reads as\n // an isotropic/degenerate tensor and drags mean A down). The fill\n // is now directional + low-streak, so dense coverage textures\n // WITHOUT the prior round-dab speckle.\n 1.0 // groundFloor — oil keeps the full base (no ground darken; fills everywhere)\n );\n\n // W-AUR-VANGOGH-REBUILD — the van-Gogh medium NO LONGER routes through this oil\n // StrokeProfile cascade. It is a DEDICATED atomic-dab body (mediumVangogh / vangoghDab\n // below) — the prior profile-driven cascade (four dense layers of long-thin\n // tensor-oriented strokes) merged into the \"marbled flow-bands\" read and ran at ~4fps.\n // profileFor now serves ONLY the oil + oil-pastel stroke mediums; the MEDIUM_VANGOGH\n // case is removed (no caller). MEDIUM_VANGOGH stays #define'd (the main() dispatch +\n // isPainterlyStroke still key off uMedium==5).\n\n // ── Oil-pastel — broad smeared directional strokes deposited via the brush engine\n // (slice 8 F1). Creamy soft edges (low hardness), heavy build-up, and a chroma punch.\n // Distinct from the dry-crayon tooth-multiply (mediumCrayon): oil-pastel LAYS strokes.\n if (medium == MEDIUM_OILPASTEL) {\n prof.shapeType = 0; // tapered directional smear — a round dab reads locally\n // isotropic (steep β / low A); the creamy oil-pastel mark\n // is a broad DIRECTIONAL smear, which carries the §4.2\n // coherence + adds the directional mid-band the §4.3 slope\n // needs (the round-dab profile rolled β off to −2.8)\n prof.bristleAmp = 0.10; // smooth creamy edges (waxy pastel, not bristle)\n prof.streakFreq = 18.0; // finer internal smear — adds the mid/high-band the smooth\n // round-dab profile lacked (the β-too-steep fix); the\n // directional along-spine streak flattens the §4.3 slope\n // without crossing the strokes\n prof.streakAmp = 0.20;\n prof.impastoAmp = 0.7; // build-up, but flatter than oil impasto\n prof.hardness = 0.42; // CREAMY — soft compositing, strokes blend on overlap\n prof.toothScale = 280.0;\n prof.toothAmp = 0.12; // the pastel tooth reads stronger\n prof.pigmentSat = 0.80; // the waxy chroma — eased off 1.16 so the rendered C clears\n // the §4.1 band ceiling with margin while the K-M subtractive\n // overlap path (paintOverOklab) keeps the chroma OFF the grey floor\n prof.hardness = 0.58; // creamy but the strokes still REGISTER — a too-soft blend\n // (0.42) smeared the marks into the smooth colour zones and\n // the field rolled off too steep (β≈−2.9, a near-gradient);\n // a crisper deposit keeps the mid/high-band the −5/3 slope needs\n prof.densityBig = 0.62; // broad directional coverage — but NOT over-dense: too many\n // overlapping creamy strokes point in slightly-varied\n // directions and the local §4.2 coherence DROPS (over-dense\n // measured A=0.57 < the 0.62-density A=0.63). The mid-density\n // flow-aligned deposit is the coherence sweet spot.\n prof.densityMed = 0.78;\n prof.densitySml = 0.90;\n prof.energyGrade = 0.80; // a strong Starry-Night length cascade — varies stroke length\n // by luma/coherence so the dab-size energy spreads across\n // scales (the −5/3 cascade the uniform-length 0.0 grade lacked,\n // the §4.3 β-too-steep fix). Not the full van-Gogh 1.0 (oil-\n // pastel keeps its creamy broad character).\n prof.impastoFloor = 0.55; // a softer crown than van-Gogh's full-height glint\n return prof;\n }\n\n // ── Oil sub-modes (mode dispatch on the oil medium).\n if (mode == 1) { // palette knife — razor edges, heavy impasto\n prof.shapeType = 3; // flat, even\n prof.bristleAmp = 0.12;\n prof.streakFreq = 4.0; prof.streakAmp = 0.05;\n prof.impastoAmp = 1.6;\n prof.hardness = 0.95;\n prof.toothAmp = 0.04;\n prof.densityBig = 0.80; prof.densityMed = 0.88; prof.densitySml = 0.70;\n } else if (mode == 3) { // thick brushwork — heavy bristle brush\n prof.shapeType = 0; // tapered\n prof.bristleAmp = 0.32;\n prof.streakFreq = 14.0; prof.streakAmp = 0.14;\n prof.impastoAmp = 1.2;\n prof.hardness = 0.85;\n prof.toothAmp = 0.07;\n }\n return prof;\n}\n", Se = "\n// ── Gradient pack (BG.W-AUR-METAL-FINISH) ──────────────────────────────────\n// structureTensorField re-plumbs its already-computed luma gradient (Gx,Gy) out through\n// the vec4 return's .w lane so the metal medium pays ZERO extra taps (a second Sobel is\n// 8 sampleBase() taps). 12 bits per bounded component ([-4,4]) into one f32, exact under\n// highp; the .xy/.z crayon/kuwahara callers are transparent to the widen.\nfloat packGrad(float gx, float gy) {\n float qx = floor(clamp(gx * 0.125 + 0.5, 0.0, 1.0) * 4095.0);\n float qy = floor(clamp(gy * 0.125 + 0.5, 0.0, 1.0) * 4095.0);\n return qx + qy * 4096.0;\n}\nvec2 unpackGrad(float packed) {\n float qy = floor(packed * (1.0 / 4096.0));\n float qx = packed - qy * 4096.0;\n return (vec2(qx, qy) * (1.0 / 4095.0) - 0.5) * 8.0;\n}\n", Ce = "#define MEDIUM_METAL 8\n#define MEDIUM_METALGRAD 9\n\n// ── Metal — the two-term anisotropic BRDF over the field's own relief (uMedium==8/9,\n// BG.W-AUR-METAL-FINISH) ─────────────────────────────────────────────────────────\n// Metal is a MUTUALLY-EXCLUSIVE medium (NOT a finish axis) — the field re-lights as\n// warm folded metal: the luma HEIGHT field (the packed structure-tensor gradient →\n// the surface normal) catches an anisotropic Blinn streak (brushed metal, the streak\n// runs ALONG the coherent edge-tangent) plus a sharp crest, both raked by a cursor-\n// synthesized light that reads on BOTH backends (uCursor is in-struct — a phantom\n// uLightDir read would be flat on the WGSL primary). The catch is the ACHROMATIC-WARM\n// anchor (AURORA_CATCH_LIGHT_ANCHOR ≈ [1.0,0.97,0.90], never a cold chrome-blue). The\n// body keeps the field HUE (technicolor valley base); the height rides the relief.\n// ZERO new taps — structureTensorField ALREADY computed the gradient (unpacked from .w).\nconst vec3 METAL_CATCH_WARM = vec3(1.0, 0.97, 0.90); // AURORA_CATCH_LIGHT_ANCHOR\nconst float METAL_HEIGHT_SCALE = 2.2; // gradient → normal tilt (× uMetalHeightScale)\nconst float METAL_LIGHT_Z = 0.55; // synth-light z (toward viewer)\nconst vec2 METAL_IDLE_RAKE = vec2(0.32, 0.34); // upper-right idle rake bias\nconst float METAL_SHININESS_ANISO = 6.0; // anisotropic streak exponent (brushed)\nconst float METAL_SHININESS_CREST = 40.0; // crest specular exponent (sharp)\nconst float METAL_COHERENCE_FLOOR = 0.22; // streak gates on edge coherence A\nconst float METAL_BODY_FLOOR = 0.42; // diffuse valley floor (dark side reads)\nconst float METAL_GRADIENT_FLATTEN = 0.55; // metal-gradient pre-flatten toward luma\nconst float METAL_SPARKLE_DENSITY = 240.0; // metal-gradient per-cell flake grid\nconst float METAL_SPARKLE_THRESH = 0.72; // only some cells flake\nconst float METAL_SPARKLE_AMP = 0.6; // flake glint amplitude\n\n// The shared metal BRDF core — takes the ALREADY-computed structureTensorField vec4 so\n// the caller pays ZERO extra taps (metal-gradient reuses the same stf). WebKit-fenced:\n// every pow base is clamped to [0,1], the exponents are compile-time constants.\nvec3 metalShade(vec3 baseCol, vec2 p, vec4 stf) {\n vec2 tangent = stf.xy;\n float A = stf.z;\n vec2 grad = unpackGrad(stf.w);\n // Height-field normal: N = normalize(vec3(grad * scale, 1)). The luma relief tilts\n // the surface; the flat field reads near vec3(0,0,1) (facing the viewer).\n vec3 N = normalize(vec3(grad * (METAL_HEIGHT_SCALE * uMetalHeightScale), 1.0));\n vec3 V = vec3(0.0, 0.0, 1.0);\n // Cursor-synthesized rake light (in-struct on BOTH backends — never uLightDir). The\n // idle bias keeps a still field lit from the upper-right; a moving cursor rakes it.\n vec3 L = normalize(vec3((uCursor - p) + METAL_IDLE_RAKE, METAL_LIGHT_Z));\n vec3 H = normalize(L + V);\n // Anisotropic streak — brushed metal: the highlight runs ALONG the edge-tangent, so\n // it is a function of the H-component PERPENDICULAR to the tangent (sinTH).\n float tH = dot(normalize(tangent), H.xy);\n float sinTH = sqrt(clamp(1.0 - tH * tH, 0.0, 1.0));\n float streak = pow(clamp(sinTH, 0.0, 1.0), METAL_SHININESS_ANISO);\n float crest = pow(clamp(dot(N, H), 0.0, 1.0), METAL_SHININESS_CREST);\n float spec = streak * crest;\n // Coherence gate — the anisotropic streak reads only where the field has a real edge\n // (a flat zone has no brush direction; A≈0 → no streak).\n spec *= smoothstep(0.0, METAL_COHERENCE_FLOOR, A);\n // Technicolor valley base — the body keeps the FIELD hue; the diffuse term rides the\n // height relief so the ridges brighten and the pits fall toward the floor.\n float diff = clamp(dot(N, L), 0.0, 1.0);\n vec3 body = baseCol * (METAL_BODY_FLOOR + (1.0 - METAL_BODY_FLOOR) * diff);\n // The catch is the achromatic-warm anchor, scaled by the polish knob.\n return body + METAL_CATCH_WARM * (spec * clamp(uMetalPolish, 0.0, 4.0));\n}\n\nvec3 mediumMetal(vec3 col, vec2 p, float t) {\n vec4 stf = structureTensorField(p, t, flowField(p, t));\n return metalShade(col, p, stf);\n}\n\n// metal-gradient (uMedium==9) — the SAME BRDF over a pre-flattened/gradient base + a\n// twinkle-in-place flake sparkle (position FIXED per cell, PHASE-animated, gated on\n// facing — flake glint, never a boil).\nvec3 mediumMetalGradient(vec3 col, vec2 p, float t) {\n vec4 stf = structureTensorField(p, t, flowField(p, t));\n // Pre-flatten toward luma (the smoother gradient-metallic base) — same BRDF, calmer body.\n // NB: flat is a GLSL reserved interpolation qualifier — WebKit's compiler REJECTS it as an\n // identifier (ANGLE tolerates it); named flatCol so the WebKit aurora shader compiles (L1a).\n vec3 flatCol = mix(col, vec3(dot(col, W_LUMA)), METAL_GRADIENT_FLATTEN);\n vec3 metal = metalShade(flatCol, p, stf);\n // The height-field normal facing (recomputed from the same packed gradient — ZERO taps).\n vec2 grad = unpackGrad(stf.w);\n float facing = normalize(vec3(grad * (METAL_HEIGHT_SCALE * uMetalHeightScale), 1.0)).z;\n // Twinkle-in-place: a fixed per-cell flake seed, phase-animated glint gated on facing.\n vec2 cell = floor(p * METAL_SPARKLE_DENSITY);\n float seed = hash21(cell);\n float tw = pow(clamp(sin(t + seed * 6.2831853), 0.0, 1.0), 40.0);\n float flakeGate = step(METAL_SPARKLE_THRESH, seed);\n metal += METAL_CATCH_WARM * (tw * flakeGate * clamp(facing, 0.0, 1.0) * METAL_SPARKLE_AMP);\n return metal;\n}\n", we = "// ── Medium overlays ───────────────────────────────────────────────────────\n\n// A quick re-computation of base color for edge-mask sampling\nvec3 sampleBase(vec2 p, float t) {\n vec2 pw = domainWarp(p, t);\n float id; float vm;\n nucleiField(pw, t, id, vm);\n vec3 c = samplePalette(id);\n c *= 1.0 + uValueVariance * vm;\n return c;\n}\n" + Se + "\n// ── Structure-tensor / edge-tangent-flow (AW.W4.1) ─────────────────────────\n// The keystone of the painterly engine: derive stroke orientation from the COLOR\n// FIELD's OWN structure, not a hand-authored flow pattern. A 3x3 Sobel over\n// luma(sampleBase) yields the gradient (Gx,Gy); the 2x2 structure tensor\n// J = [[Gx², GxGy],[GxGy, Gy²]] eigen-decomposes closed-form into the MINOR\n// eigenvector (the edge-TANGENT — least color change, the stroke direction) + the\n// coherence A = (λ1-λ2)/(λ1+λ2); flat zones relax toward fallbackDir by (1-A). The\n// single-pass small-tap WebGL2 form. Returns vec4(tangent.xy, A, packGrad(Gx,Gy)) —\n// the .w lane carries the metal medium's gradient (BG.W-AUR-METAL-FINISH; the .xy/.z\n// callers are byte-unchanged).\nvec4 structureTensorField(vec2 p, float t, vec2 fallbackDir) {\n float e = 0.0035; // small-tap neighborhood (edge-mask scale)\n // 3x3 luma samples.\n float l00 = dot(sampleBase(p + vec2(-e, -e), t), W_LUMA);\n float l10 = dot(sampleBase(p + vec2( 0.0, -e), t), W_LUMA);\n float l20 = dot(sampleBase(p + vec2( e, -e), t), W_LUMA);\n float l01 = dot(sampleBase(p + vec2(-e, 0.0), t), W_LUMA);\n float l21 = dot(sampleBase(p + vec2( e, 0.0), t), W_LUMA);\n float l02 = dot(sampleBase(p + vec2(-e, e), t), W_LUMA);\n float l12 = dot(sampleBase(p + vec2( 0.0, e), t), W_LUMA);\n float l22 = dot(sampleBase(p + vec2( e, e), t), W_LUMA);\n // Sobel derivatives.\n float Gx = (l20 + 2.0 * l21 + l22) - (l00 + 2.0 * l01 + l02);\n float Gy = (l02 + 2.0 * l12 + l22) - (l00 + 2.0 * l10 + l20);\n // Structure tensor components.\n float Jxx = Gx * Gx;\n float Jyy = Gy * Gy;\n float Jxy = Gx * Gy;\n // Closed-form 2x2 eigenvalues: λ = 0.5(tr ± sqrt((Jxx-Jyy)² + 4Jxy²)).\n float tr = Jxx + Jyy;\n float disc = sqrt(max((Jxx - Jyy) * (Jxx - Jyy) + 4.0 * Jxy * Jxy, 0.0));\n float lambdaMaj = 0.5 * (tr + disc);\n float lambdaMin = 0.5 * (tr - disc);\n // The MAJOR eigenvector points along the gradient (the edge NORMAL); the MINOR\n // is its perpendicular — the edge TANGENT (the stroke direction). The principal\n // angle is θ = 0.5·atan2(2·Jxy, Jxx-Jyy); this form is robust at Jxy≈0 (where the\n // (λ-Jyy, Jxy) eigenvector formula collapses to a zero vector). The tangent is at\n // θ + 90°. Guard the fully-isotropic (no-gradient) degenerate case → fallback dir.\n vec2 tangent;\n if (disc < 1e-7) {\n tangent = fallbackDir;\n } else {\n float theta = 0.5 * atan(2.0 * Jxy, Jxx - Jyy); // major (gradient) angle\n tangent = vec2(-sin(theta), cos(theta)); // perpendicular = tangent\n }\n // Coherence A in [0,1] — high where one eigenvalue dominates (a strong edge),\n // ~0 in flat zones. Relax toward the smooth fallback by (1 - A).\n float A = (lambdaMaj - lambdaMin) / (lambdaMaj + lambdaMin + 1e-6);\n A = clamp(A, 0.0, 1.0);\n // Coherence-weighted blend: full tensor in coherent zones, smooth in flat ones.\n // Resolve the 180° sign ambiguity toward the fallback so the blend is continuous.\n if (dot(tangent, fallbackDir) < 0.0) tangent = -tangent;\n // The blend weight is a low-power curve (A^0.35) so even MODERATE-coherence zones queue\n // strongly along the tangent (a flowing van-Gogh band reads coherent the way the\n // structure-tensor metric measures it; a linear A under-orients the mid-band and the\n // rendered field reads too isotropic — the §4.2 anisotropy lift). The flat-zone (A≈0)\n // relax to the fallback survives (0^0.35=0), so tensor noise never reads as jitter.\n float blendW = pow(A, 0.28);\n vec2 dir = normalize(mix(fallbackDir, tangent, blendW) + 1e-6);\n return vec4(dir, A, packGrad(Gx, Gy));\n}\n\nvec3 mediumWatercolor(vec3 col, vec2 p, float t) {\n // Wet-edge cauliflowers via luma-gradient magnitude\n float eps = 0.004;\n vec3 cx1 = sampleBase(p + vec2(eps, 0.0), t);\n vec3 cx2 = sampleBase(p - vec2(eps, 0.0), t);\n vec3 cy1 = sampleBase(p + vec2(0.0, eps), t);\n vec3 cy2 = sampleBase(p - vec2(0.0, eps), t);\n float gx = dot(cx1 - cx2, W_LUMA);\n float gy = dot(cy1 - cy2, W_LUMA);\n float edge = sqrt(gx * gx + gy * gy) / (2.0 * eps);\n float mask = smoothstep(0.0, 2.5, edge);\n col *= mix(1.0, 0.78, mask * uWetEdge);\n\n // Granulation — pigment settles in paper tooth\n float paper = 0.5 * vnoise(p * 160.0) + 0.5 * vnoise(p * 360.0);\n float pigLoad = 1.0 - dot(col, W_LUMA);\n col *= 1.0 - uGranulation * pigLoad * (paper - 0.5);\n\n // Wash banding — faint horizontal wet gradient\n float band = fbm(vec2(p.x * 1.5, p.y * 0.4));\n col *= 1.0 + 0.04 * (band - 0.5);\n return col;\n}\n\nvec3 mediumPastel(vec3 col, vec2 p, float t) {\n vec2 flow = flowField(p, t);\n vec2 perp = vec2(-flow.y, flow.x);\n float along = dot(p, flow) * uStrokeScale;\n float across = dot(p, perp) * uStrokeScale;\n across += 0.03 * (vnoise(p * 260.0) - 0.5);\n\n float aniso = mix(1.0, 0.18, uStrokeAnisotropy);\n float stroke = fbm(vec2(along * aniso, across));\n col *= mix(1.0, 0.82 + 0.32 * stroke, uStrokeAmount);\n\n // Pastel tooth — tiny high-frequency grain\n float tooth = vnoise(p * 800.0);\n col *= 1.0 - 0.08 * uStrokeAmount * (tooth - 0.5);\n return col;\n}\n", Te = "// ── Medium id constants (mirror uniformBridge.ts MEDIUM_ID — the uMedium ladder) ──\n// The StrokeProfile selector (AX.W12 + AX.W13) dispatches on the medium id: oil,\n// van-Gogh, and oil-pastel each AUTHOR a first-class profile in profileFor.\n#define MEDIUM_OIL 3\n#define MEDIUM_CRAYON 4\n#define MEDIUM_VANGOGH 5\n#define MEDIUM_OILPASTEL 6\n\n// ── Crayon — DRY wax pigment on paper tooth (first-class medium, uMedium==4) ──\n// Crayon is not strokes. It's dry pigment crumbs dragged across paper tooth — the\n// DRY tooth-multiply model: anisotropic tooth noise multiplied into the base, a hard\n// SCUMBLE that lets the lower color show through the broken upper layer, and stable\n// OKLCh broken-color pigment patches. NO sheen, NO burnish film — that waxy gloss is\n// the OIL-PASTEL deposition's signature (mediumOilPastel), distinct from dry crayon\n// (AX.W13 slice 8 F1 — the split). Crayon shares the SUBSTRATE (the structure-tensor\n// orientation, the tooth noise, OKLCh brokenColorJitter), not the dispatch body.\nvec3 mediumCrayon(vec3 col, vec2 p, float t) {\n // Orient the deposition along the structure-tensor edge-tangent (the bridge forces\n // tensor for crayon, so read the tensor field directly).\n vec2 flow = structureTensorField(p, t, flowField(p, t)).xy;\n float ang = atan(flow.y, flow.x);\n float ca = cos(-ang), sa = sin(-ang);\n vec2 pr = vec2(p.x * ca - p.y * sa, p.x * sa + p.y * ca);\n\n float aniso = mix(0.45, 0.95, uStrokeAnisotropy);\n float scale = max(uStrokeScale * 1.6, 180.0);\n\n // ── Paper TOOTH height field — the relief the dry pigment rides. Anisotropic\n // (squished along flow, coarse cross-flow). Peaks = ridges, valleys = paper pits.\n float t1 = vnoise(vec2(pr.x * scale * aniso, pr.y * scale));\n float t2 = vnoise(vec2(pr.x * scale * aniso * 0.4, pr.y * scale * 0.4) + 11.0);\n float t3 = vnoise(vec2(pr.x * scale * aniso * 2.1, pr.y * scale * 2.1) + 23.0);\n float tooth = 0.55 * t1 + 0.30 * t2 + 0.15 * t3;\n\n // ── DRY TOOTH-MULTIPLY — the crayon multiplies the tooth relief into the base\n // color (dark in the pits, bright on the ridges). The pressure (uStrokeAmount) sets\n // how hard the multiply bites. This is the DRY model — no pigment build-up, no sheen.\n float pressure = clamp(uStrokeAmount, 0.0, 1.0);\n float bite = mix(0.18, 0.46, pressure); // multiply strength\n vec3 result = col * (1.0 - bite * (0.5 - tooth));\n\n // ── HARD SCUMBLE — a broken upper layer that lets the lower color show through the\n // gaps. A coarse mask gates a HARD (high-contrast) dragged pass so the dry crayon\n // reads as broken pigment crumbs, not a smooth wash. Drag follows the tensor flow.\n float scumbleMask = smoothstep(0.42, 0.78, vnoise(vec2(pr.x * scale * 0.55, pr.y * scale * 0.22) + 7.0));\n float scumbleCoverage = scumbleMask * pressure * 0.7; // hard broken upper layer\n vec3 paper = col * mix(0.80, 0.94, pressure); // the paper showing through\n result = mix(paper, result, scumbleCoverage);\n\n // ── Broken-color pigment: stable wax/pigment patches in OKLCh (W5), not flicker.\n vec2 pigmentCell = floor(pr * max(scale * 0.18, 32.0));\n float pigmentMask = smoothstep(0.28, 0.82, vnoise(pr * scale * 0.21 + 19.0));\n result = brokenColorJitter(\n result,\n hash21(pigmentCell + 17.0),\n hash21(pigmentCell * 2.1 + 31.0),\n 0.45 + 0.55 * pigmentMask\n );\n\n // Crayon is saturation-amplified (the wax chroma punch — but DRY, no sheen).\n result = saturate3(result, 1.08);\n\n return result;\n}\n\n// ── StrokeProfile — the oil-stroke parameter vector (AX.W12, slice 8 F6) ──────\n// The SBR \"stroke = parameter vector\" canon (facet 11): the per-mode if-ladder knobs\n// become struct FIELDS — logic-as-DATA, not an imperative branch. profileFor(medium,\n// mode) populates the profile for a (medium, mode) pair; paintStrokeLayers(profile) runs\n// the four-layer bestOil/paintOver cascade off it. A new medium (the W13 van-Gogh /\n// oil-pastel profiles) AUTHORS a profile entry — it never edits a monolith.\nstruct StrokeProfile {\n int shapeType; // 0 tapered, 1 load-drag, 2 dab, 3 even, 4 comma/crescent\n float bristleAmp; // edge raggedness 0..0.5\n float streakFreq; // internal-streak spatial frequency\n float streakAmp; // internal-streak amplitude\n float impastoAmp; // paint-thickness contribution (the relight reads the height)\n float hardness; // edge-compositing crispness 0..1\n float toothScale; // canvas-tooth (linen weave) spatial frequency\n float toothAmp; // canvas-tooth amplitude\n float pigmentSat; // pigment saturation boost (OKLCh chroma scale)\n float densityBig; // layer-1 (big gestural) placement density gate\n float densityMed; // layer-2 (medium body) placement density gate\n float densitySml; // layer-3 (small dabs) placement density gate\n float energyGrade; // AX.W13 — SBR energy-grade magnitude (0 off; 1 the van-Gogh\n // Starry-Night length cascade). The energy grade is a PROFILE\n // field, NOT a buried uMedium==5 bestOil branch (slice 8 F0).\n float impastoFloor;// AX.W13 — the per-stroke height-crown floor (0.4 oil falloff;\n // 1.0 van-Gogh FULL-height crown so each dab catches its glint).\n float densityFill; // AX.W13 — layer-4 fill-dab density. Oil/oil-pastel fill the\n // bald spots (0.95, full coverage); van-Gogh sets it LOW so the\n // sparse atomic dabs keep their visible inter-stroke ground gaps\n // (the atomicity read — a 0.95 fill would close every gap to a smear).\n float groundFloor; // AX.W13 — the bare-ground darken floor. The gaps between strokes\n // (low accumulated height) multiply toward this floor, so van-Gogh's\n // sparse atomic dabs read over a visibly darker underpainting (the\n // Starry-Night visible ground). Oil/oil-pastel keep 1.0 (no darken).\n};\n\n// The (medium, mode) -> StrokeProfile selector. The if-ladder's knobs are the profile's\n// fields; a new medium adds a CASE here (never an edit to a dispatch body). mode is the\n// uStrokeMode oil-stroke sub-mode (0 oil, 1 palette-knife, 3 brushwork). crayon\n// (uMedium==4) is a PEER tooth-multiply medium that never reaches the stroke cascade.\n// The painterly STROKE mediums are oil (MEDIUM_OIL), van-Gogh (MEDIUM_VANGOGH) and\n// oil-pastel (MEDIUM_OILPASTEL) — each AUTHORS its own profile entry below.\n" + xe + "\n// The single parameterized four-layer stroke cascade (AX.W12). The four hand-unrolled\n// bestOil/paintOver invocations collapse into ONE body driven by the profile + the\n// uniform-derived per-layer scale/anisotropy multipliers (which are mode-INVARIANT — the\n// per-layer offsets, seeds, and len/wid muls are fixed across modes, so they stay here as\n// the cascade's structure; only the profile's knobs differentiate the medium). The\n// mode passes through for the two mode-special-cased shapes (knife layer-3 dabs +\n// layer-4 fill shape), which are placement details of the cascade, not profile knobs.\nvoid paintStrokeLayers(inout vec3 col, inout float height, StrokeProfile prof,\n int mode, vec2 p, float t) {\n // Scales & multipliers from uniforms (mode-invariant cascade structure).\n float baseScale = max(uStrokeScale * 0.006, 0.008);\n // Three primary layers: big gestural, medium body, small dabs.\n // W-AUR-STUDIO D5 — the −5/3 radii respacing was MEASURED + REVERTED (recorded, not\n // silently struck). The φ-adjacent geometric candidate (2.4 / 1.45 / 0.87, a fixed\n // ≈1.66× step) moved oil-pastel β −2.534 → −2.413 — TOWARD the −5/3 band but NOT into\n // it (floor −1.85), so the keep-iff-into-band gate failed. The single-pass WebGL2 path\n // is the true limiter (HC-aurora §5): the oil-pastel β + the oil/oil-pastel anisotropy\n // residual stays the oil/oil-pastel stroke-cascade ceiling. BB.W-AUR-KUWAHARA DECIDED the\n // booking: the SOFT anisotropic-Kuwahara finish ships as the OPT-IN mediumKuwahara() body\n // (uMedium==7) the consumer selects — NOT a re-tune of these oil/oil-pastel knobs. The\n // hand-set 2.4 / 1.1 / 0.45 stays — it is van-Gogh's landed-band spacing.\n float sBig = baseScale * 2.4;\n float sMed = baseScale * 1.1;\n float sSml = baseScale * 0.45;\n\n // Strokes are elongated HARD (long·thin) so the rendered field reads strongly\n // directional — the §4.2 structure-tensor anisotropy lift. A short fat dab is locally\n // isotropic and drags the measured A down; a long thin stroke that hugs the tensor\n // tangent is what gives Starry Night its A≈0.83. The width muls are pulled tighter to\n // keep the long·thin aspect.\n float lenMulBig = mix(3.0, 5.2, uStrokeAnisotropy);\n float widMulBig = mix(0.42, 0.22, uStrokeAnisotropy);\n float lenMulMed = mix(2.8, 4.8, uStrokeAnisotropy);\n float widMulMed = mix(0.40, 0.21, uStrokeAnisotropy);\n float lenMulSml = mix(2.2, 3.6, uStrokeAnisotropy);\n float widMulSml = mix(0.36, 0.23, uStrokeAnisotropy);\n\n float jitterAmt = 0.75; // large jitter — no grid\n vec2 flow = flowField(p, t);\n\n // Layer 1 — big gestural strokes (sparse, shaping)\n StrokeHit hBig = bestOil(p, sBig, lenMulBig, widMulBig, jitterAmt * 0.55,\n prof.densityBig, prof.shapeType, prof.bristleAmp, flow, t, 1.3,\n prof.energyGrade);\n paintOver(col, height, hBig, prof.streakFreq * 0.7, prof.streakAmp,\n uImpasto * prof.impastoAmp * uStrokeAmount, prof.hardness, 1.3, prof.impastoFloor);\n\n // Layer 2 — medium body strokes\n StrokeHit hMed = bestOil(p + vec2(11.3, 3.7), sMed, lenMulMed, widMulMed,\n jitterAmt, prof.densityMed, prof.shapeType, prof.bristleAmp, flow, t, 2.7,\n prof.energyGrade);\n paintOver(col, height, hMed, prof.streakFreq, prof.streakAmp,\n uImpasto * prof.impastoAmp * uStrokeAmount, prof.hardness, 2.7, prof.impastoFloor);\n\n // Layer 3 — small strokes (more frequent, smaller). Even the knife layer-3 stays the\n // medium's DIRECTIONAL shape, not a round dab — the round-dab sparkle was a fine-scale\n // isotropic speckle that dragged the §4.2 anisotropy down + rolled the §4.3 slope shallow.\n int smlShape = prof.shapeType;\n StrokeHit hSml = bestOil(p + vec2(-5.1, 8.4), sSml, lenMulSml, widMulSml,\n jitterAmt * 0.9, prof.densitySml, smlShape,\n prof.bristleAmp * 0.85, flow, t, 4.1, prof.energyGrade);\n paintOver(col, height, hSml, prof.streakFreq * 1.4, prof.streakAmp * 0.6,\n uImpasto * prof.impastoAmp * 0.45 * uStrokeAmount, prof.hardness, 4.1, prof.impastoFloor);\n\n // Layer 4 — fill strokes (dense, fine) — cover bald spots. The density is\n // PROFILE-driven (prof.densityFill): oil/oil-pastel fill to full coverage; van-Gogh\n // keeps it sparse so the bare-ground gaps between its atomic dabs survive. The fill is\n // ELONGATED + flow-oriented (NOT a round dab) — a dense round-dab fill is locally\n // isotropic and was the dominant §4.2 anisotropy sink; an oriented fine stroke keeps the\n // fill directional so the whole field reads coherent.\n float sFill = baseScale * 0.22;\n float lenMulFill = mix(2.0, 3.2, uStrokeAnisotropy);\n float widMulFill = mix(0.34, 0.24, uStrokeAnisotropy);\n int fillShape = (mode == 1) ? 3 : prof.shapeType; // knife=even; others inherit the medium's directional shape\n StrokeHit hFill = bestOil(p + vec2(3.9, -6.2), sFill, lenMulFill, widMulFill,\n jitterAmt * 0.8, prof.densityFill, fillShape,\n prof.bristleAmp * 0.6, flow, t, 8.9, prof.energyGrade);\n // The fill is a low-relief, low-streak base coat — it covers bald spots WITHOUT adding\n // fine bright speckle (a high-impasto/high-streak fill caught a per-dab glint that read\n // as isotropic noise over the directional macro strokes — the §4.2/§4.3 sink). Its\n // positional jitter is tamed too so the fill strokes stay flow-aligned, not scattered.\n paintOver(col, height, hFill, prof.streakFreq * 1.2, prof.streakAmp * 0.35,\n uImpasto * prof.impastoAmp * 0.18 * uStrokeAmount, prof.hardness * 0.9, 8.9, prof.impastoFloor);\n\n // Optional crosshatch layer\n if (uStrokeLayers == 2) {\n vec2 flow2 = vec2(-flow.y, flow.x);\n StrokeHit hX = bestOil(p + vec2(7.3, -2.1), sMed, lenMulMed * 0.9, widMulMed,\n jitterAmt, prof.densityMed * 0.7, prof.shapeType, prof.bristleAmp, flow2, t, 6.5,\n prof.energyGrade);\n paintOver(col, height, hX, prof.streakFreq, prof.streakAmp * 0.85,\n uImpasto * prof.impastoAmp * 0.55 * uStrokeAmount, prof.hardness, 6.5, prof.impastoFloor);\n }\n}\n\n// The shared stroke-medium SUBSTRATE finish (AX.W12 + AX.W13): paint the four-layer\n// cascade off the profile, then canvas-tooth + relight + saturation. The three painterly\n// STROKE mediums (oil / van-Gogh / oil-pastel) each AUTHOR their own profile and call\n// this — the substrate is shared, the PROFILE (not a dispatch-body fork) differentiates\n// the medium (slice 8 F6). mode passes through for the cascade's mode-special-cased shapes.\nvec3 paintStrokeMedium(vec3 col, vec2 p, float t, StrokeProfile prof, int mode) {\n vec3 result = col;\n // AW.W4.2 — accumulated paint HEIGHT across the stroke layers. The relight reads\n // its gradient for the normal; the canvas tooth seeds the base relief.\n float height = 0.0;\n paintStrokeLayers(result, height, prof, mode, p, t);\n\n // Canvas tooth — linen weave\n float tooth1 = vnoise(p * prof.toothScale);\n float tooth2 = vnoise(p * prof.toothScale * vec2(0.6, 2.4) + 37.0);\n float tooth = (0.6 * tooth1 + 0.4 * tooth2) - 0.5;\n result *= 1.0 + tooth * prof.toothAmp * uCanvasGrain;\n\n // AW.W4.2 — relight the accumulated paint height with the movable uLightDir\n // source (diffuse + Blinn specular, in LINEAR before aces()). The canvas tooth\n // is the base relief term so the weave also catches the raking light.\n float canvasBase = tooth * prof.toothAmp * 0.5;\n result = relightImpasto(result, height, canvasBase);\n\n // AX.W13 — the visible ground. The bare-ground gaps (low accumulated stroke height)\n // multiply toward prof.groundFloor, so van-Gogh's sparse atomic dabs read as separable\n // marks over a darker underpainting (oil/oil-pastel keep groundFloor=1.0 → no-op). The\n // smoothstep keeps the impasto dabs (high height) at full value; only the open ground\n // between them darkens.\n result *= mix(prof.groundFloor, 1.0, smoothstep(0.0, 0.38, height));\n\n // Pigment saturation boost\n result = saturate3(result, prof.pigmentSat);\n\n return result;\n}\n\nvec3 mediumOil(vec3 col, vec2 p, float t) {\n // The oil medium is a thin body: fetch the oil profile (mode-dispatched), paint via\n // the shared stroke substrate. uStrokeMode: 0 oil (gestural), 1 knife, 3 brushwork.\n int mode = uStrokeMode;\n StrokeProfile prof = profileFor(MEDIUM_OIL, mode);\n return paintStrokeMedium(col, p, t, prof, mode);\n}\n\n#define MEDIUM_KUWAHARA 7\n\n// ── Kuwahara — the anisotropic generalized Kuwahara painterly finish (uMedium==7,\n// BB.W-AUR-KUWAHARA) ───────────────────────────────────────────────────────────────\n// The SOTA edge-preserving painterly smoothing: the generalized/anisotropic Kuwahara of\n// Kyprianidis 2010, the SOFT polynomial-weighted variant (NOT the pre-2010 hard argmin,\n// which BANDS the flat field into an 8-spoke pinwheel — the §4.2 anti-regression). Aurora\n// is a PROCEDURAL field (no input texture), so the operator runs over sampleBase() directly:\n// an elliptical kernel oriented along the structure tensor (elongated along the edge-tangent,\n// narrowed by the anisotropy), divided into 8 overlapping sectors via smooth weights; the\n// output is the variance-weighted blend of the sector means (1/(1+var^q) — low-variance\n// sectors dominate, the SOFT criterion → flat oil-paint patches with crisp zone boundaries).\n// Single-pass small-radius WebGL2 form: 4 rings × 8 angular taps = 32 procedural samples\n// (cost-bounded; the offscreen-park / PRM freeze the substrate owns is untouched).\nvec3 mediumKuwahara(vec3 col, vec2 p, float t) {\n // Orient the kernel along the structure-tensor edge-tangent + read the coherence A\n // (the field widened vec3→vec4 for metal's gradient; kuwahara reads only .xy/.z).\n vec4 stf = structureTensorField(p, t, flowField(p, t));\n vec2 tangent = stf.xy;\n float A = stf.z;\n // The ellipse axes: major along the tangent, minor across. Anisotropy squeezes the\n // minor axis (coherent zones → long-thin patch along the colour band; flat zones →\n // near-circular so the operator degrades gracefully to the isotropic Kuwahara). The\n // base radius rides uStrokeScale so the painterly patch size tracks the studio knob.\n float radius = clamp(0.010 + uStrokeScale * 0.00018, 0.006, 0.024);\n float aniso = mix(1.0, 0.34, clamp(A, 0.0, 1.0)); // minor/major axis ratio\n vec2 ax = tangent; // major-axis unit vector (edge-tangent)\n vec2 ay = vec2(-tangent.y, tangent.x); // minor-axis unit vector (edge-normal)\n\n // 8 sectors, soft polynomial weights. Each sector i centers on angle i·45°; a sample's\n // sector weight is a smooth gaussian-of-angular-distance so sectors OVERLAP (no hard\n // argmin → no pinwheel banding). The center sample seeds all sectors equally.\n const int SECTORS = 8;\n vec3 m[8]; // per-sector weighted colour sum\n vec3 s[8]; // per-sector weighted colour² sum (for variance)\n float w[8]; // per-sector weight sum\n for (int i = 0; i < SECTORS; i++) { m[i] = vec3(0.0); s[i] = vec3(0.0); w[i] = 0.0; }\n\n // 4 rings × 8 angular taps over the elliptical disc. Each tap: sample the procedural\n // field, then deposit into the sectors by the soft angular weight × the radial falloff.\n const int RINGS = 4;\n const int TAPS = 8;\n for (int r = 1; r <= RINGS; r++) {\n float rr = float(r) / float(RINGS); // 0.25 .. 1.0\n float radial = 1.0 - 0.6 * rr; // inner taps weigh more (gaussian-ish)\n for (int a = 0; a < TAPS; a++) {\n float ang = 6.2831853 * float(a) / float(TAPS);\n // Elliptical offset: major axis full radius, minor axis squeezed by aniso.\n vec2 dirE = ax * cos(ang) + ay * (sin(ang) * aniso);\n vec2 off = dirE * (radius * rr);\n vec3 c = sampleBase(p + off, t);\n // The sample's angular bin (its sector) — soft, so it spills into neighbours.\n for (int k = 0; k < SECTORS; k++) {\n float sectorAng = 6.2831853 * float(k) / float(SECTORS);\n // Smallest signed angular distance to the sector center.\n float d = ang - sectorAng;\n d = atan(sin(d), cos(d)); // wrap to [-π, π]\n float sw = exp(-d * d * 2.2) * radial; // gaussian angular weight × radial\n m[k] += c * sw;\n s[k] += c * c * sw;\n w[k] += sw;\n }\n }\n }\n\n // Per-sector mean + scalar luma-variance, then the SOFT variance-weighted blend.\n vec3 accum = vec3(0.0);\n float accumW = 0.0;\n for (int k = 0; k < SECTORS; k++) {\n float wk = max(w[k], 1e-4);\n vec3 mean = m[k] / wk;\n vec3 var3 = max(s[k] / wk - mean * mean, vec3(0.0));\n float variance = dot(var3, W_LUMA); // perceptual scalar variance\n // SOFT criterion: low-variance sectors (flat, inside a colour zone) dominate; a\n // high-variance sector (straddling an edge) is suppressed. q controls the sharpness;\n // a finite q (not argmin) keeps the blend continuous → no pinwheel spoke.\n float sectorW = 1.0 / (1.0 + pow(variance * 320.0, 4.0));\n accum += mean * sectorW;\n accumW += sectorW;\n }\n vec3 result = accum / max(accumW, 1e-4);\n\n // The center sample anchors the result in near-flat zones (where every sector reads the\n // same colour) so the operator is a no-op there — the smoothing only BITES at edges.\n vec3 center = sampleBase(p, t);\n result = mix(center, result, clamp(0.35 + 0.65 * A, 0.0, 1.0));\n\n // A faint canvas tooth + pigment-saturation lift so the flattened patches read as\n // oil-paint, not a posterized blur (the painterly identity the smoothing alone lacks).\n float tooth = vnoise(p * 300.0) - 0.5;\n result *= 1.0 + tooth * 0.06 * uCanvasGrain;\n result = saturate3(result, 1.04);\n\n // Blend toward the incoming col by uStrokeAmount so the studio amount knob controls\n // the finish strength (uStrokeAmount=0 → the raw field passes through; default → full).\n return mix(col, result, clamp(uStrokeAmount, 0.0, 1.0));\n}\n\n" + Ce + be + "// AX.W13 — the oil-pastel medium (uMedium==6) is a DISTINCT stroke-deposition body,\n// split out of the dry-crayon tooth-multiply (mediumCrayon) (slice 8 F1). It DEPOSITS\n// broad smeared directional strokes via the same brush engine with a creamy soft\n// hardness, heavy pigment build-up where strokes overlap, and a chroma punch — the\n// stroke-deposition model that gives oil-pastel its depth and less-uniform read.\n// Shares the SUBSTRATE (the stroke cascade + tooth + relight) with oil/van-Gogh, NOT\n// the dispatch body of dry crayon. The bridge forces tensor orientation.\nvec3 mediumOilPastel(vec3 col, vec2 p, float t) {\n StrokeProfile prof = profileFor(MEDIUM_OILPASTEL, 0);\n return paintStrokeMedium(col, p, t, prof, 0);\n}", j = "\n", Ee = `#version 300 es
15
15
  precision highp float;
16
16
 
17
17
  in vec2 vUv;
@@ -85,6 +85,13 @@ uniform float uImpasto;
85
85
  uniform float uBrokenColor;
86
86
  uniform float uCanvasGrain;
87
87
 
88
+ // BG.W-AUR-METAL-FINISH — the metal-medium knobs (uMedium==8/9). uMetalPolish scales
89
+ // the specular catch intensity; uMetalHeightScale scales the luma-relief → normal tilt.
90
+ // On the WGSL primary these ride the free cursor.z/.w pad lanes (uniformBridgeWGPU); the
91
+ // .frag carries them as their own uniforms. Written 0 on a non-metal config → no-op.
92
+ uniform float uMetalPolish;
93
+ uniform float uMetalHeightScale;
94
+
88
95
  // AW.W4.2 — the impasto relight axis. A movable directional source lighting the
89
96
  // accumulated paint-height field (diffuse + Blinn specular, in LINEAR before aces()).
90
97
  // AW.W8 drives uLightDir from the cursor (cursor-as-light). Default = upper-left so
@@ -151,7 +158,7 @@ float vnoise(vec2 p) {
151
158
  // The rotated-octave FBM rotation constant — spliced from the shared chunk (AV.W2
152
159
  // — the one FBM_ROT). The loop below stays aurora-local (2.02 lacunarity +
153
160
  // uniform-driven octaves, per §3a — only the rotation constant converges).
154
- ${n}
161
+ ${o}
155
162
 
156
163
  float fbm(vec2 p) {
157
164
  float v = 0.0;
@@ -172,7 +179,7 @@ float fbm(vec2 p) {
172
179
  // lacunarity loop the rest of the warp uses). The curl operator is consumed ONLY on
173
180
  // the OPT-IN warpMode == "curl" branch (uWarpMode == 3) — the default warp paths are
174
181
  // byte-untouched (no curl call), so every existing aurora gate stays byte-equivalent.
175
- ${d}
182
+ ${h}
176
183
 
177
184
  // The scalar fbm potential ψ for curlFBM — aurora's own fbm. The splice above
178
185
  // forward-declares potentialFBM; this defines it (ES 3.00 allows the prototype).
@@ -186,19 +193,19 @@ float potentialFBM(vec2 p) { return fbm(p); }
186
193
  // fbm above (the cost-tiering is preserved per AX.W12 §3a — this is an ADDITIVE basis,
187
194
  // not a blanket upgrade). The aurora-local hash21/vnoise/fbm loop stays (legitimately
188
195
  // divergent per the chunk's §3a).
189
- ${a}
196
+ ${l}
190
197
 
191
198
  // The sRGB OETF (linearToSrgb) — spliced from the shared procedural-color chunk
192
199
  // (AV.W2 — the single OETF source; the AV.W1 local copy is deleted here). Aurora's
193
200
  // linear pipeline closes the seam with this transfer before fragColor (the
194
201
  // proof:aurora-space-gamma seam).
195
- ${s}
202
+ ${d}
196
203
 
197
204
  // W5 — the four Ottosson OKLab/OKLCh matrices + their space fns, spliced from the
198
205
  // SAME shared chunk the goo-blob uses (zero new payload, 1e-6-verified). PI is
199
206
  // defined first because the chunk's oklabToOklch folds the hue into [0, 2pi).
200
207
  const float PI = 3.141592653589793;
201
- ${l}
208
+ ${p}
202
209
 
203
210
  // ── OKLCh palette ramp (W5 interp · AX.W11 single-sourced twin) ───────────────
204
211
  // The muddy-midtone kill: distant-hue stops interpolated by a plain linear mix()
@@ -210,7 +217,7 @@ ${l}
210
217
  // the smoothstep-eased samplePaletteRamp dispatcher) is SPLICED from the shared
211
218
  // procedural-color chunk (the single ramp source). composition.glsl.ts's
212
219
  // samplePalette calls samplePaletteRamp.
213
- ${r}
220
+ ${s}
214
221
 
215
222
  // Interleaved Gradient Noise (Jimenez) — a 1-LSB triangular dither applied in
216
223
  // DISPLAY space AFTER the OETF, so 8-bit mid-tone banding on the soft gradient is
@@ -286,26 +293,353 @@ vec2 domainWarp(vec2 p, float t) {
286
293
  return warped;
287
294
  }
288
295
 
289
- ` + be + k + xe + k + "// ── Color utils (OKLCh — W5; the sRGB YIQ hueShift matrix is DELETED) ──────────\nconst vec3 W_LUMA = vec3(0.2126, 0.7152, 0.0722);\n\n// Linear sRGB → OKLab (the cbrt-LMS path; the goo-blob's srgbToOklab takes gamma,\n// here the color field is already linear so we skip the OETF inverse).\nvec3 linOklab(vec3 lin) {\n vec3 lms = LINEAR_SRGB_TO_LMS * lin;\n return LMS_TO_OKLAB * (sign(lms) * pow(abs(lms), vec3(1.0 / 3.0)));\n}\n\n// Broken color (W5) — hue + chroma jitter at fixed PERCEPTUAL lightness, in OKLCh.\n// Broken color is hue variation at constant VALUE, which only OKLCh makes true (the\n// prior YIQ-style sRGB rotation muddied value). This is the seam AW.W4's van-Gogh /\n// oil-pastel per-stroke pigment jitter consumes (the pigment-variation read).\nvec3 brokenColorJitter(vec3 c, float hueSeed, float valueSeed, float strength) {\n float amt = clamp(uBrokenColor * strength, 0.0, 1.0);\n if (amt <= 0.001) return c;\n vec3 lch = oklabToOklch(linOklab(c));\n // ±~16° hue swing + ±~12% chroma swing; L held so value reads constant.\n lch.z += (hueSeed - 0.5) * (32.0 * PI / 180.0) * amt;\n lch.y = max(lch.y * (1.0 + (valueSeed - 0.5) * 0.28 * amt), 0.0);\n return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3(0.0));\n}\n\n// Saturation (W5) — chroma scale at fixed L/H in OKLCh (the perceptual saturation,\n// replacing the luma-mix sRGB form). amt=1 is identity; amt<1 desaturates toward\n// the achromatic axis with NO lightness shift (the muddy-luma-mix grey is gone).\nvec3 saturate3(vec3 c, float amt) {\n vec3 lch = oklabToOklch(linOklab(c));\n lch.y = max(lch.y * amt, 0.0);\n return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3(0.0));\n}\n\n// BD.W-AUR-VIVIDNESS — the §3 chroma FLOOR. Operate in OKLab: lightness + hue are\n// untouched, chroma is lifted toward the floor. A pale zone BLOOMS to transmission-fit;\n// a vivid zone (already above the floor) is byte-untouched. The near-gray hue guard is\n// STRUCTURAL: below VIVID_EPS the (a,b) direction is precision noise, so the lift\n// synthesizes along the WARM anchor (amber, both components positive) — NEVER the noisy\n// near-zero vector, NEVER a cold/teal hue. uVividness:0 returns c identically (the gated\n// byte-identity opt-out). Mode factor: a dark route lifts the floor a touch (a dim field\n// needs more chroma to read vivid through glass) — derived from the field's own L.\nconst float VIVID_TARGET = 0.115;\nconst float VIVID_EPS = 0.012;\n// The warm amber anchor in OKLab (a,b): OKLCh hue 70°, unit chroma. cos/sin(70°) — both\n// POSITIVE (warm yellow-orange). The near-gray fallback direction, the warm-floor law.\nconst vec2 VIVID_WARM_ANCHOR = vec2(0.34202, 0.93969);\nvec3 vividnessFloor(vec3 c) {\n if (uVividness <= 0.0001) return c;\n vec3 lab = linOklab(c);\n float C = length(lab.yz);\n // Mode-aware: dim fields (low L) get a slightly higher target so they read vivid\n // through glass. mix factor is gentle (1.0 .. 1.18) so light routes are unaffected.\n float modeLift = mix(1.18, 1.0, clamp(lab.x * 1.4, 0.0, 1.0));\n float Cmin = uVividness * VIVID_TARGET * modeLift;\n vec2 hueDir = (C > VIVID_EPS) ? lab.yz / C : VIVID_WARM_ANCHOR;\n lab.yz = hueDir * max(C, Cmin);\n return max(oklabToLinearSrgb(lab), vec3(0.0));\n}\n\n" + Se + k + Ee + k + Ce + k + De + k + "\n// ── Main ──────────────────────────────────────────────────────────────────\nvoid main() {\n // Normalized 0..1 coordinates for nuclei, domain warp, and medium sampling.\n vec2 uv = vUv;\n vec2 pN = uv;\n\n float t = uTime;\n\n // Warp in pN space\n vec2 p_warp = domainWarp(pN, t);\n\n // Composition\n float paletteId; float valueMod;\n nucleiField(p_warp, t, paletteId, valueMod);\n vec3 col = samplePalette(paletteId);\n col *= 1.0 + uValueVariance * valueMod;\n\n // Breath — slow global luminance wobble\n float breath = sin(t * 6.2831 / max(uBreathPeriod, 1.0));\n col *= 1.0 + uBreathDepth * breath * 0.5;\n\n // Medium dispatch (AX.W13 — each is a FIRST-CLASS body, no shared dispatch):\n // 1 pastel · 2 watercolor · 3 oil · 4 crayon (DRY tooth-multiply) ·\n // 5 van-Gogh (atomic comma/crescent dabs) · 6 oil-pastel (stroke deposition) ·\n // 7 kuwahara (anisotropic-Kuwahara edge-preserving painterly finish — BB.W-AUR-KUWAHARA).\n // van-Gogh is no longer a mediumOil passthrough; oil-pastel and crayon no longer\n // share a body — they share the SUBSTRATE (the tooth/placement helpers), not the\n // dispatch body (slice 8 F0/F1). Kuwahara is OPT-IN (default-off — no preset selects\n // it unless a config explicitly sets medium:\"kuwahara\"); the smooth default + the\n // van-Gogh HERO + the existing painterly bodies are byte-unchanged by its addition.\n if (uMedium == 1) col = mediumPastel(col, pN, t);\n else if (uMedium == 2) col = mediumWatercolor(col, pN, t);\n else if (uMedium == 3) col = mediumOil(col, pN, t);\n else if (uMedium == 4) col = mediumCrayon(col, pN, t);\n else if (uMedium == 5) col = mediumVangogh(col, pN, t);\n else if (uMedium == 6) col = mediumOilPastel(col, pN, t);\n else if (uMedium == 7) col = mediumKuwahara(col, pN, t);\n\n // Saturation trim\n col = saturate3(col, uSaturation);\n\n // BD.W-AUR-VIVIDNESS — the §3 chroma floor (warm-anchored, hue-preserving). Lifts a\n // pale zone toward the transmissive floor so warm glass over the field reads\n // transmissive-not-gray; a vivid zone is untouched; uVividness:0 is a no-op.\n col = vividnessFloor(col);\n\n // Tonemap + film grain\n col = aces(col);\n float grain = hash21(gl_FragCoord.xy + t * 17.0);\n col += (grain - 0.5) * uPaperGrain;\n\n col = clamp(col * 0.985 + 0.008, 0.0, 1.0);\n\n // MANDATORY OETF — closes the seam (mirrors metaball.frag.ts:278). The whole\n // pipeline above (linear palette LUT, ACES tonemap, grain) runs in LINEAR; without\n // this transfer the aurora ships ~2.2× too dark (linear 0.5 → ~0.215, not ~0.735).\n col = linearToSrgb(col);\n\n // 1-LSB triangular IGN dither in DISPLAY space, AFTER the OETF — breaks 8-bit\n // mid-tone banding on the soft gradient. Texture-free (the canonical Jimenez IGN).\n col += (1.0 / 255.0) * (ign(gl_FragCoord.xy) - 0.5);\n\n // Premultiply operates on DISPLAY-space color (matches the blob: OETF, then premul).\n fragColor = vec4(col * uAlpha, uAlpha);\n}\n";
296
+ ` + ge + j + _e + j + "// ── Color utils (OKLCh — W5; the sRGB YIQ hueShift matrix is DELETED) ──────────\nconst vec3 W_LUMA = vec3(0.2126, 0.7152, 0.0722);\n\n// Linear sRGB → OKLab (the cbrt-LMS path; the goo-blob's srgbToOklab takes gamma,\n// here the color field is already linear so we skip the OETF inverse).\nvec3 linOklab(vec3 lin) {\n vec3 lms = LINEAR_SRGB_TO_LMS * lin;\n return LMS_TO_OKLAB * (sign(lms) * pow(abs(lms), vec3(1.0 / 3.0)));\n}\n\n// Broken color (W5) — hue + chroma jitter at fixed PERCEPTUAL lightness, in OKLCh.\n// Broken color is hue variation at constant VALUE, which only OKLCh makes true (the\n// prior YIQ-style sRGB rotation muddied value). This is the seam AW.W4's van-Gogh /\n// oil-pastel per-stroke pigment jitter consumes (the pigment-variation read).\nvec3 brokenColorJitter(vec3 c, float hueSeed, float valueSeed, float strength) {\n float amt = clamp(uBrokenColor * strength, 0.0, 1.0);\n if (amt <= 0.001) return c;\n vec3 lch = oklabToOklch(linOklab(c));\n // ±~16° hue swing + ±~12% chroma swing; L held so value reads constant.\n lch.z += (hueSeed - 0.5) * (32.0 * PI / 180.0) * amt;\n lch.y = max(lch.y * (1.0 + (valueSeed - 0.5) * 0.28 * amt), 0.0);\n return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3(0.0));\n}\n\n// Saturation (W5) — chroma scale at fixed L/H in OKLCh (the perceptual saturation,\n// replacing the luma-mix sRGB form). amt=1 is identity; amt<1 desaturates toward\n// the achromatic axis with NO lightness shift (the muddy-luma-mix grey is gone).\nvec3 saturate3(vec3 c, float amt) {\n vec3 lch = oklabToOklch(linOklab(c));\n lch.y = max(lch.y * amt, 0.0);\n return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3(0.0));\n}\n\n// BD.W-AUR-VIVIDNESS — the §3 chroma FLOOR. Operate in OKLab: lightness + hue are\n// untouched, chroma is lifted toward the floor. A pale zone BLOOMS to transmission-fit;\n// a vivid zone (already above the floor) is byte-untouched. The near-gray hue guard is\n// STRUCTURAL: below VIVID_EPS the (a,b) direction is precision noise, so the lift\n// synthesizes along the WARM anchor (amber, both components positive) — NEVER the noisy\n// near-zero vector, NEVER a cold/teal hue. uVividness:0 returns c identically (the gated\n// byte-identity opt-out). Mode factor: a dark route lifts the floor a touch (a dim field\n// needs more chroma to read vivid through glass) — derived from the field's own L.\nconst float VIVID_TARGET = 0.115;\nconst float VIVID_EPS = 0.012;\n// The warm amber anchor in OKLab (a,b): OKLCh hue 70°, unit chroma. cos/sin(70°) — both\n// POSITIVE (warm yellow-orange). The near-gray fallback direction, the warm-floor law.\nconst vec2 VIVID_WARM_ANCHOR = vec2(0.34202, 0.93969);\nvec3 vividnessFloor(vec3 c) {\n if (uVividness <= 0.0001) return c;\n vec3 lab = linOklab(c);\n float C = length(lab.yz);\n // Mode-aware: dim fields (low L) get a slightly higher target so they read vivid\n // through glass. mix factor is gentle (1.0 .. 1.18) so light routes are unaffected.\n float modeLift = mix(1.18, 1.0, clamp(lab.x * 1.4, 0.0, 1.0));\n float Cmin = uVividness * VIVID_TARGET * modeLift;\n vec2 hueDir = (C > VIVID_EPS) ? lab.yz / C : VIVID_WARM_ANCHOR;\n lab.yz = hueDir * max(C, Cmin);\n return max(oklabToLinearSrgb(lab), vec3(0.0));\n}\n\n" + ve + j + we + j + ye + j + Te + j + "\n// ── Main ──────────────────────────────────────────────────────────────────\nvoid main() {\n // Normalized 0..1 coordinates for nuclei, domain warp, and medium sampling.\n vec2 uv = vUv;\n vec2 pN = uv;\n\n float t = uTime;\n\n // Warp in pN space\n vec2 p_warp = domainWarp(pN, t);\n\n // Composition\n float paletteId; float valueMod;\n nucleiField(p_warp, t, paletteId, valueMod);\n vec3 col = samplePalette(paletteId);\n col *= 1.0 + uValueVariance * valueMod;\n\n // Breath — slow global luminance wobble\n float breath = sin(t * 6.2831 / max(uBreathPeriod, 1.0));\n col *= 1.0 + uBreathDepth * breath * 0.5;\n\n // Medium dispatch (AX.W13 — each is a FIRST-CLASS body, no shared dispatch):\n // 1 pastel · 2 watercolor · 3 oil · 4 crayon (DRY tooth-multiply) ·\n // 5 van-Gogh (atomic comma/crescent dabs) · 6 oil-pastel (stroke deposition) ·\n // 7 kuwahara (anisotropic-Kuwahara edge-preserving painterly finish — BB.W-AUR-KUWAHARA).\n // van-Gogh is no longer a mediumOil passthrough; oil-pastel and crayon no longer\n // share a body — they share the SUBSTRATE (the tooth/placement helpers), not the\n // dispatch body (slice 8 F0/F1). Kuwahara is OPT-IN (default-off — no preset selects\n // it unless a config explicitly sets medium:\"kuwahara\"); the smooth default + the\n // van-Gogh HERO + the existing painterly bodies are byte-unchanged by its addition.\n if (uMedium == 1) col = mediumPastel(col, pN, t);\n else if (uMedium == 2) col = mediumWatercolor(col, pN, t);\n else if (uMedium == 3) col = mediumOil(col, pN, t);\n else if (uMedium == 4) col = mediumCrayon(col, pN, t);\n else if (uMedium == 5) col = mediumVangogh(col, pN, t);\n else if (uMedium == 6) col = mediumOilPastel(col, pN, t);\n else if (uMedium == 7) col = mediumKuwahara(col, pN, t);\n // BG.W-AUR-METAL-FINISH — the mutually-exclusive metal mediums (opt-in, uMedium==8/9;\n // the smooth default + every existing medium are byte-unchanged by these arms).\n else if (uMedium == 8) col = mediumMetal(col, pN, t);\n else if (uMedium == 9) col = mediumMetalGradient(col, pN, t);\n\n // Saturation trim\n col = saturate3(col, uSaturation);\n\n // BD.W-AUR-VIVIDNESS — the §3 chroma floor (warm-anchored, hue-preserving). Lifts a\n // pale zone toward the transmissive floor so warm glass over the field reads\n // transmissive-not-gray; a vivid zone is untouched; uVividness:0 is a no-op.\n col = vividnessFloor(col);\n\n // Tonemap + film grain\n col = aces(col);\n float grain = hash21(gl_FragCoord.xy + t * 17.0);\n col += (grain - 0.5) * uPaperGrain;\n\n col = clamp(col * 0.985 + 0.008, 0.0, 1.0);\n\n // MANDATORY OETF — closes the seam (mirrors metaball.frag.ts:278). The whole\n // pipeline above (linear palette LUT, ACES tonemap, grain) runs in LINEAR; without\n // this transfer the aurora ships ~2.2× too dark (linear 0.5 → ~0.215, not ~0.735).\n col = linearToSrgb(col);\n\n // 1-LSB triangular IGN dither in DISPLAY space, AFTER the OETF — breaks 8-bit\n // mid-tone banding on the soft gradient. Texture-free (the canonical Jimenez IGN).\n col += (1.0 / 255.0) * (ign(gl_FragCoord.xy) - 0.5);\n\n // Premultiply operates on DISPLAY-space color (matches the blob: OETF, then premul).\n fragColor = vec4(col * uAlpha, uAlpha);\n}\n", De = `#version 300 es
297
+ precision highp float;
298
+
299
+ in vec2 vUv;
300
+ out vec4 fragColor;
301
+
302
+ #define MAX_NUCLEI 6
303
+ #define BLUR_RINGS 3
304
+ #define BLUR_SECTORS 8
305
+ const float PI = 3.141592653589793;
306
+
307
+ uniform float uTime;
308
+
309
+ // The drifting field uniforms — the SAME nuclei/warp/cursor lanes the palette program
310
+ // reads; here they drive the BLUR ZONE, not the color.
311
+ uniform int uNucleiCount;
312
+ uniform vec2 uNucleiPos[MAX_NUCLEI];
313
+ uniform float uNucleiRadius[MAX_NUCLEI];
314
+ uniform float uNucleiValueBias[MAX_NUCLEI];
315
+ uniform float uNucleiDriftRadius[MAX_NUCLEI];
316
+ uniform float uNucleiDriftPhase[MAX_NUCLEI];
317
+ uniform float uNucleiElong[MAX_NUCLEI];
318
+ uniform float uNucleiAngle[MAX_NUCLEI];
319
+ uniform float uSoftmaxBeta;
320
+ uniform float uNucleiDrift;
321
+ uniform float uWarpAmount;
322
+ uniform float uWarpScale;
323
+ uniform float uWarpDrift;
324
+ uniform int uNoiseOctaves;
325
+ uniform vec2 uCursor;
326
+ uniform float uCursorStrength;
327
+ uniform float uCursorRadius;
328
+
329
+ // Output shaping (shared with the palette program's meaning).
330
+ uniform float uSaturation;
331
+ uniform float uPaperGrain;
332
+ uniform float uAlpha;
333
+ uniform float uVividness;
334
+
335
+ // ── The image lane (this program's OWN uniform tail) ──
336
+ uniform sampler2D uImage;
337
+ uniform float uBlurMin; // 0..1 uv-space blur radius at zone=0 (near-sharp)
338
+ uniform float uBlurMax; // 0..1 uv-space blur radius at zone=1 (dissolved)
339
+ uniform float uImageAspect; // canvas W/H — keeps the bokeh circular in screen space
340
+
341
+ // Authoring-scale → rad/sec lifts (byte-identical to aurora.frag.ts).
342
+ const float K_NUCLEI = 14.0;
343
+ const float K_WARP = 5.0;
344
+
345
+ // ── Noise (aurora-local hash21/vnoise/fbm — the same compact foundation) ──
346
+ float hash21(vec2 p) {
347
+ p = fract(p * vec2(123.34, 456.21));
348
+ p += dot(p, p + 45.32);
349
+ return fract(p.x * p.y);
350
+ }
351
+ float vnoise(vec2 p) {
352
+ vec2 i = floor(p);
353
+ vec2 f = fract(p);
354
+ vec2 u = f * f * (3.0 - 2.0 * f);
355
+ float a = hash21(i);
356
+ float b = hash21(i + vec2(1.0, 0.0));
357
+ float c = hash21(i + vec2(0.0, 1.0));
358
+ float d = hash21(i + vec2(1.0, 1.0));
359
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
360
+ }
361
+ ${o}
362
+ float fbm(vec2 p) {
363
+ float v = 0.0;
364
+ float a = 0.5;
365
+ for (int i = 0; i < 5; i++) {
366
+ if (i >= uNoiseOctaves) break;
367
+ v += a * vnoise(p);
368
+ p = FBM_ROT * p * 2.02;
369
+ a *= 0.5;
370
+ }
371
+ return v;
372
+ }
373
+ // Interleaved Gradient Noise (Jimenez) — display-space 1-LSB dither.
374
+ float ign(vec2 p) {
375
+ return fract(52.9829189 * fract(dot(p, vec2(0.06711056, 0.00583715))));
376
+ }
377
+
378
+ ${d}
379
+ ${p}
380
+
381
+ // linear-sRGB → raw OKLab (the vividnessFloor helper — mirrors aurora.frag's linOklab).
382
+ vec3 linOklab(vec3 lin) {
383
+ vec3 lms = LINEAR_SRGB_TO_LMS * lin;
384
+ return LMS_TO_OKLAB * (sign(lms) * pow(abs(lms), vec3(1.0 / 3.0)));
385
+ }
386
+
387
+ // The Quilez double-warp (the fbm branch — byte-parallel to aurora.frag's default warp)
388
+ // + the cursor swirl. The SAME drift that moves the palette field here moves the blur zone.
389
+ vec2 domainWarp(vec2 p, float t) {
390
+ vec2 q = vec2(fbm(p * uWarpScale + vec2(0.0, 0.0) + t * uWarpDrift * K_WARP),
391
+ fbm(p * uWarpScale + vec2(5.2, 1.3) + t * uWarpDrift * K_WARP));
392
+ vec2 r = vec2(fbm(p * uWarpScale + 4.0 * q + vec2(1.7, 9.2)),
393
+ fbm(p * uWarpScale + 4.0 * q + vec2(8.3, 2.8)));
394
+ vec2 warped = p + uWarpAmount * r;
395
+ if (uCursorStrength > 0.001) {
396
+ vec2 toP = p - uCursor;
397
+ float d = length(toP);
398
+ float rr = max(uCursorRadius, 0.01);
399
+ float w = exp(-(d * d) / (rr * rr * 0.45));
400
+ float ang = w * uCursorStrength * 2.1;
401
+ float ca = cos(ang), sa = sin(ang);
402
+ vec2 rotated = vec2(ca * toP.x - sa * toP.y, sa * toP.x + ca * toP.y) + uCursor;
403
+ warped = mix(warped, rotated + uWarpAmount * r * 0.7, w * uCursorStrength);
404
+ }
405
+ return warped;
406
+ }
407
+
408
+ // The drifting BLUR ZONE — a smooth [0,1] scalar from the anisotropic-Gaussian nuclei
409
+ // softmax (the SAME field nucleiField reads), drift-coupled. Reads high where a nucleus
410
+ // sits → that region dissolves; the inter-nucleus gaps stay near-sharp.
411
+ float zoneField(vec2 p, float t) {
412
+ float accum = 0.0;
413
+ float accumW = 0.0;
414
+ for (int i = 0; i < MAX_NUCLEI; i++) {
415
+ if (i >= uNucleiCount) break;
416
+ float driftPhase = uNucleiDriftPhase[i];
417
+ vec2 posI = uNucleiPos[i] + uNucleiDriftRadius[i] * vec2(
418
+ cos(t * uNucleiDrift * K_NUCLEI + driftPhase),
419
+ sin(t * uNucleiDrift * K_NUCLEI + driftPhase * 1.13));
420
+ vec2 diff = p - posI;
421
+ float ang = uNucleiAngle[i];
422
+ float ca = cos(ang), sa = sin(ang);
423
+ vec2 local = vec2(ca * diff.x + sa * diff.y, -sa * diff.x + ca * diff.y);
424
+ float along = local.x / max(uNucleiElong[i], 0.01);
425
+ float d2 = along * along + local.y * local.y;
426
+ float rad = max(uNucleiRadius[i], 0.01);
427
+ float w = exp(-uSoftmaxBeta * d2 / (rad * rad));
428
+ accum += w * (0.5 + 0.5 * uNucleiValueBias[i]);
429
+ accumW += w;
430
+ }
431
+ return clamp(accum / max(accumW, 1e-4), 0.0, 1.0);
432
+ }
433
+
434
+ // Object-fit:cover — map the screen uv into the image so a non-matching aspect crops,
435
+ // never stretches. uImageAspect is the canvas aspect (W/H); the image is authored to
436
+ // fill it. A centred cover keeps the photo readable under the dissolve.
437
+ vec2 coverUv(vec2 uv) {
438
+ vec2 c = uv - 0.5;
439
+ c.x *= max(uImageAspect, 0.0001);
440
+ float s = 1.0 / max(uImageAspect, 1.0);
441
+ return c * s + 0.5;
442
+ }
443
+
444
+ // The bounded 24-tap zone blur — a FIXED 3-ring × 8-sector stratified kernel. The radius
445
+ // is per-fragment (mix(uBlurMin, uBlurMax, zone)); every tap is sampled in LINEAR light
446
+ // (srgbToLinear) so the average is a physically-correct bokeh. The x-offset is divided by
447
+ // the canvas aspect so the kernel stays circular in screen space.
448
+ vec3 zoneBlur(vec2 uv, float radius) {
449
+ vec3 sum = srgbToLinear(texture(uImage, coverUv(uv)).rgb);
450
+ float wsum = 1.0;
451
+ for (int ring = 1; ring <= BLUR_RINGS; ring++) {
452
+ float rr = radius * (float(ring) / float(BLUR_RINGS));
453
+ for (int s = 0; s < BLUR_SECTORS; s++) {
454
+ float a = (float(s) + 0.5 * float(ring)) / float(BLUR_SECTORS) * 2.0 * PI;
455
+ vec2 off = vec2(cos(a) / max(uImageAspect, 0.0001), sin(a)) * rr;
456
+ sum += srgbToLinear(texture(uImage, coverUv(uv + off)).rgb);
457
+ wsum += 1.0;
458
+ }
459
+ }
460
+ return sum / wsum;
461
+ }
462
+
463
+ // The §3 chroma FLOOR — source-agnostic (operates on the final linear col), the WGSL/GLSL
464
+ // twin of aurora.frag's vividnessFloor. A washed-out photo blooms to transmission-fit; a
465
+ // vivid photo is untouched; uVividness:0 is a no-op.
466
+ const float VIVID_TARGET = 0.115;
467
+ const float VIVID_EPS = 0.012;
468
+ const vec2 VIVID_WARM_ANCHOR = vec2(0.34202, 0.93969);
469
+ vec3 vividnessFloor(vec3 c) {
470
+ if (uVividness <= 0.0001) return c;
471
+ vec3 lab = linOklab(c);
472
+ float C = length(lab.yz);
473
+ float modeLift = mix(1.18, 1.0, clamp(lab.x * 1.4, 0.0, 1.0));
474
+ float Cmin = uVividness * VIVID_TARGET * modeLift;
475
+ vec2 hueDir = (C > VIVID_EPS) ? lab.yz / C : VIVID_WARM_ANCHOR;
476
+ lab.yz = hueDir * max(C, Cmin);
477
+ return max(oklabToLinearSrgb(lab), vec3(0.0));
478
+ }
479
+
480
+ vec3 saturate3(vec3 c, float amt) {
481
+ vec3 lch = oklabToOklch(linOklab(c));
482
+ lch.y = max(lch.y * amt, 0.0);
483
+ return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3(0.0));
484
+ }
485
+
486
+
487
+ // ── PBR-Neutral tonemap (named aces() — the tonemap slot; byte-parallel to aurora.frag) ──
488
+ vec3 aces(vec3 color) {
489
+ const float startCompression = 0.8 - 0.04;
490
+ const float desaturation = 0.15;
491
+ float x = min(color.r, min(color.g, color.b));
492
+ float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
493
+ color -= offset;
494
+ float peak = max(color.r, max(color.g, color.b));
495
+ if (peak < startCompression) return clamp(color, 0.0, 1.0);
496
+ float d = 1.0 - startCompression;
497
+ float newPeak = 1.0 - d * d / (peak + d - startCompression);
498
+ color *= newPeak / peak;
499
+ float g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);
500
+ return clamp(mix(color, newPeak * vec3(1.0), g), 0.0, 1.0);
501
+ }
502
+
503
+ void main() {
504
+ vec2 uv = vUv;
505
+ float t = uTime;
506
+
507
+ // The SAME drifting field the palette program computes — here it drives BLUR, not color.
508
+ vec2 p_warp = domainWarp(uv, t);
509
+ float zone = zoneField(p_warp, t);
510
+
511
+ // Per-fragment blur radius — near-sharp at zone 0, dissolved at zone 1.
512
+ float radius = mix(uBlurMin, uBlurMax, zone);
513
+ vec3 col = zoneBlur(uv, radius);
514
+
515
+ // Saturation trim + the source-agnostic vividness floor (a washed photo blooms).
516
+ col = saturate3(col, uSaturation);
517
+ col = vividnessFloor(col);
518
+
519
+ // Tonemap + film grain (byte-parallel closing of the palette program's seam).
520
+ col = aces(col);
521
+ float grain = hash21(gl_FragCoord.xy + t * 17.0);
522
+ col += (grain - 0.5) * uPaperGrain;
523
+ col = clamp(col * 0.985 + 0.008, 0.0, 1.0);
524
+
525
+ // MANDATORY OETF (the whole pipeline above runs in LINEAR) + display-space IGN dither.
526
+ col = linearToSrgb(col);
527
+ col += (1.0 / 255.0) * (ign(gl_FragCoord.xy) - 0.5);
528
+
529
+ // Premultiply on display-space color (matches the palette path: OETF, then premul).
530
+ fragColor = vec4(col * uAlpha, uAlpha);
531
+ }
532
+ `, Oe = {
533
+ premultiplyAlpha: "none",
534
+ colorSpaceConversion: "none"
535
+ };
536
+ function M(e) {
537
+ return createImageBitmap(e, Oe);
538
+ }
539
+ async function ke(e) {
540
+ return typeof e == "string" ? M(await (await fetch(e)).blob()) : e instanceof Blob ? M(e) : e;
541
+ }
542
+ function Ae() {
543
+ let e = new ImageData(1, 1);
544
+ return e.data.set([
545
+ 128,
546
+ 128,
547
+ 128,
548
+ 255
549
+ ]), e;
550
+ }
551
+ function je(e) {
552
+ return e instanceof HTMLImageElement ? {
553
+ width: e.naturalWidth,
554
+ height: e.naturalHeight
555
+ } : {
556
+ width: e.width,
557
+ height: e.height
558
+ };
559
+ }
560
+ function Me(e, t, n = {}) {
561
+ let { linearFilter: r = !0, clampToEdge: i = !0 } = n, a = e.createTexture();
562
+ e.bindTexture(e.TEXTURE_2D, a), e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !1), e.pixelStorei(e.UNPACK_COLORSPACE_CONVERSION_WEBGL, e.NONE), e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL, !1), e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, e.RGBA, e.UNSIGNED_BYTE, t);
563
+ let o = r ? e.LINEAR : e.NEAREST;
564
+ e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, o), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, o);
565
+ let s = i ? e.CLAMP_TO_EDGE : e.REPEAT;
566
+ return e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, s), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, s), e.pixelStorei(e.UNPACK_COLORSPACE_CONVERSION_WEBGL, e.BROWSER_DEFAULT_WEBGL), a;
567
+ }
568
+ var Ne = 2;
569
+ function Pe(e, t) {
570
+ let { width: n, height: r } = je(t), i = e.createTexture({
571
+ label: "[texture-upload] image",
572
+ size: [
573
+ n,
574
+ r,
575
+ 1
576
+ ],
577
+ format: "rgba8unorm",
578
+ usage: Ne | 20
579
+ });
580
+ return e.queue.copyExternalImageToTexture({
581
+ source: t,
582
+ flipY: !1
583
+ }, {
584
+ texture: i,
585
+ premultipliedAlpha: !1
586
+ }, [
587
+ n,
588
+ r,
589
+ 1
590
+ ]), {
591
+ texture: i,
592
+ width: n,
593
+ height: r
594
+ };
595
+ }
596
+ //#endregion
597
+ //#region src/components/aurora/composables/auroraImageSource.ts
598
+ function Fe(e) {
599
+ let t = null, n = null, r;
600
+ return {
601
+ getDecodedImage: () => t,
602
+ setImageUploader(e) {
603
+ n = e, e && t && e(t);
604
+ },
605
+ ensureDecoded(i) {
606
+ i.source !== "image" || i.src == null || i.src !== r && (r = i.src, ke(i.src).then((r) => {
607
+ t = r, n?.(r), e.wake();
608
+ }).catch((t) => {
609
+ e.onError?.(t instanceof Error ? t : Error(String(t)));
610
+ }));
611
+ }
612
+ };
613
+ }
614
+ function Ie(e, t, n) {
615
+ let r = null;
616
+ e.activeTexture(e.TEXTURE0);
617
+ let i = (n) => {
618
+ e.useProgram(t), e.activeTexture(e.TEXTURE0), r && e.deleteTexture(r), r = Me(e, n);
619
+ };
620
+ return i(n.getDecodedImage() ?? Ae()), n.setImageUploader(i), () => {
621
+ r && e.deleteTexture(r), n.setImageUploader(null);
622
+ };
623
+ }
290
624
  //#endregion
291
- //#region src/components/custom/aurora/constants/renderMode.ts
292
- function A() {
625
+ //#region src/components/aurora/constants/renderMode.ts
626
+ function N() {
293
627
  let e;
294
628
  try {
295
- e = p();
629
+ e = _();
296
630
  } catch {
297
631
  return !1;
298
632
  }
299
633
  return e === null ? !1 : e.includes("swiftshader") || e.includes("llvmpipe") || e.includes("software") || e.includes("basic render") || e.includes("microsoft basic");
300
634
  }
301
- function j(e, t = {}) {
302
- return e !== "css" && !t.forceWebGLUnderSoftwareRaster && A() ? "css" : e === "auto" ? "webgl" : e;
635
+ function Le(e, t = {}) {
636
+ return e !== "css" && !t.forceWebGLUnderSoftwareRaster && N() ? "css" : e === "auto" ? "webgl" : e;
303
637
  }
304
638
  //#endregion
305
- //#region src/components/custom/aurora/composables/glSetup.ts
306
- var M = "[Aurora]", ke = /* @__PURE__ */ "uTime.uPalette.uStopCount.uNucleiCount.uNucleiPos.uNucleiRadius.uNucleiPaletteBias.uNucleiValueBias.uNucleiDriftRadius.uNucleiDriftPhase.uNucleiElong.uNucleiAngle.uSoftmaxBeta.uValueVariance.uWarpAmount.uWarpScale.uWarpDrift.uWarpMode.uNoiseOctaves.uMedium.uHuePath.uFlowPattern.uFlowFocal.uFlowAngle.uFlowCurl.uCursor.uCursorStrength.uCursorRadius.uCursorVelocity.uCursorBurst.uStrokeAmount.uStrokeScale.uStrokeAnisotropy.uStrokeLayers.uStrokeMode.uStrokeOrient.uLightDir.uLightColor.uWetEdge.uGranulation.uImpasto.uBrokenColor.uCanvasGrain.uNucleiDrift.uPaletteDrift.uBreathDepth.uBreathPeriod.uSaturation.uPaperGrain.uAlpha.uVividness".split(".");
307
- function Ae(e, t, n) {
308
- let r = _(e, e.VERTEX_SHADER, t, M), i = _(e, e.FRAGMENT_SHADER, n, M), a = g(e, r, i, M);
639
+ //#region src/components/aurora/composables/glSetup.ts
640
+ var P = "[Aurora]", Re = /* @__PURE__ */ "uTime.uPalette.uStopCount.uNucleiCount.uNucleiPos.uNucleiRadius.uNucleiPaletteBias.uNucleiValueBias.uNucleiDriftRadius.uNucleiDriftPhase.uNucleiElong.uNucleiAngle.uSoftmaxBeta.uValueVariance.uWarpAmount.uWarpScale.uWarpDrift.uWarpMode.uNoiseOctaves.uMedium.uHuePath.uFlowPattern.uFlowFocal.uFlowAngle.uFlowCurl.uCursor.uCursorStrength.uCursorRadius.uCursorVelocity.uCursorBurst.uStrokeAmount.uStrokeScale.uStrokeAnisotropy.uStrokeLayers.uStrokeMode.uStrokeOrient.uLightDir.uLightColor.uWetEdge.uGranulation.uImpasto.uBrokenColor.uCanvasGrain.uMetalPolish.uMetalHeightScale.uNucleiDrift.uPaletteDrift.uBreathDepth.uBreathPeriod.uSaturation.uPaperGrain.uAlpha.uVividness.uImage.uBlurMin.uBlurMax.uImageAspect".split(".");
641
+ function ze(e, t, n) {
642
+ let r = x(e, e.VERTEX_SHADER, t, P), i = x(e, e.FRAGMENT_SHADER, n, P), a = b(e, r, i, P);
309
643
  e.useProgram(a);
310
644
  let o = e.createVertexArray();
311
645
  e.bindVertexArray(o);
@@ -321,7 +655,7 @@ function Ae(e, t, n) {
321
655
  let c = e.getAttribLocation(a, "aPos");
322
656
  e.enableVertexAttribArray(c), e.vertexAttribPointer(c, 2, e.FLOAT, !1, 0, 0);
323
657
  let l = {};
324
- for (let t of ke) l[t] = e.getUniformLocation(a, t);
658
+ for (let t of Re) l[t] = e.getUniformLocation(a, t);
325
659
  return {
326
660
  program: a,
327
661
  vs: r,
@@ -334,69 +668,172 @@ function Ae(e, t, n) {
334
668
  };
335
669
  }
336
670
  //#endregion
337
- //#region src/components/custom/aurora/composables/color.ts
338
- function N(e, t = 8, n) {
671
+ //#region src/components/aurora/constants/presets.ts
672
+ var Be = 6, Ve = 8, He = 1, Ue = .115, We = .004, Ge = .06, F = {
673
+ palette: [
674
+ {
675
+ L: .64,
676
+ C: .17,
677
+ h: 30
678
+ },
679
+ {
680
+ L: .76,
681
+ C: .15,
682
+ h: 55
683
+ },
684
+ {
685
+ L: .87,
686
+ C: .13,
687
+ h: 82
688
+ }
689
+ ],
690
+ nuclei: [{
691
+ x: .3,
692
+ y: .3,
693
+ radius: .5,
694
+ paletteBias: 0,
695
+ valueBias: 0,
696
+ driftRadius: .045,
697
+ driftPhase: 0
698
+ }, {
699
+ x: .7,
700
+ y: .65,
701
+ radius: .5,
702
+ paletteBias: 1,
703
+ valueBias: .05,
704
+ driftRadius: .045,
705
+ driftPhase: 2.4
706
+ }],
707
+ softmaxBeta: 3,
708
+ valueVariance: .08,
709
+ warpAmount: .5,
710
+ warpScale: 1.6,
711
+ warpDrift: .008,
712
+ warpMode: "fbm",
713
+ noiseOctaves: 4,
714
+ medium: "smooth",
715
+ flow: {
716
+ pattern: "none",
717
+ focalX: .5,
718
+ focalY: .5,
719
+ angle: 0,
720
+ curl: 0
721
+ },
722
+ strokeAmount: 0,
723
+ strokeScale: 140,
724
+ strokeAnisotropy: .7,
725
+ strokeLayers: 1,
726
+ strokeMode: "oil",
727
+ wetEdge: 0,
728
+ granulation: 0,
729
+ impasto: 0,
730
+ brokenColor: 0,
731
+ canvasGrain: 0,
732
+ nucleiDrift: .015,
733
+ paletteDrift: .015,
734
+ breathDepth: .05,
735
+ breathPeriod: 40,
736
+ saturation: 1,
737
+ paperGrain: .008,
738
+ alpha: 1,
739
+ vividness: 1
740
+ }, Ke = {
741
+ medium: "crayon",
742
+ strokeOrient: "tensor",
743
+ granulation: .3,
744
+ canvasGrain: .5,
745
+ strokeAmount: .35,
746
+ strokeAnisotropy: .5,
747
+ strokeLayers: 1,
748
+ impasto: 0,
749
+ brokenColor: 0,
750
+ wetEdge: 0,
751
+ saturation: .92,
752
+ paperGrain: .008
753
+ };
754
+ //#endregion
755
+ //#region src/components/aurora/composables/color.ts
756
+ function I(e, t = 8, n) {
339
757
  let r = n ?? new Float32Array(t * 3), i = Math.min(e.length, t);
340
758
  for (let t = 0; t < i; t++) {
341
- let [n, i, a] = x(e[t]);
759
+ let [n, i, a] = C(e[t]);
342
760
  r[t * 3 + 0] = n, r[t * 3 + 1] = i, r[t * 3 + 2] = a;
343
761
  }
344
762
  for (let e = i; e < t; e++) r[e * 3 + 0] = 0, r[e * 3 + 1] = 0, r[e * 3 + 2] = 0;
345
763
  return r;
346
764
  }
347
- function P(e) {
765
+ function qe(e) {
348
766
  if (e.length === 0) return "transparent";
349
- if (e.length === 1) return C(e[0]);
767
+ if (e.length === 1) return T(e[0]);
350
768
  let t = e.length;
351
769
  return `linear-gradient(135deg, ${e.map((e, n) => {
352
770
  let r = Math.round(n / (t - 1) * 100);
353
- return `${C(e)} ${r}%`;
771
+ return `${T(e)} ${r}%`;
354
772
  }).join(", ")})`;
355
773
  }
356
- function je(e) {
357
- let t = e.replace("#", ""), n = parseInt(t.slice(0, 2), 16), r = parseInt(t.slice(2, 4), 16), i = parseInt(t.slice(4, 6), 16), [a, o, s] = ve(n / 255, r / 255, i / 255), [c, l, u] = _e(a, o, s);
774
+ function Je(e) {
775
+ let t = e.replace("#", ""), n = parseInt(t.slice(0, 2), 16), r = parseInt(t.slice(2, 4), 16), i = parseInt(t.slice(4, 6), 16), [a, o, s] = me(n / 255, r / 255, i / 255), [c, l, u] = fe(a, o, s);
358
776
  return {
359
777
  L: c,
360
778
  C: l,
361
779
  h: u
362
780
  };
363
781
  }
364
- var Me = [.35, .95];
365
- function F(e, t = {}) {
366
- let n = typeof e == "string" ? w(e) : e, { stopCount: r = 4, harmony: i = "analogous", lightnessSpread: a = .32, chromaFalloff: o = .85, hueSpread: s = 28, lightnessEasing: c = "linear", chromaEasing: l = "bell", temperatureShift: u = 0, avoidHues: d } = t, f = Math.max(2, Math.min(8, Math.round(r))), [p, m] = Me, h = n.L - a / 2, g = n.L + a / 2;
367
- h < p && (g += p - h, h = p), g > m && (h -= g - m, g = m), h = Math.max(p, h), g = Math.min(m, g);
368
- let _ = [];
369
- for (let e = 0; e < f; e++) {
370
- let t = f === 1 ? 0 : e / (f - 1), r = h + (g - h) * I(t, c), a = n.C * o, p;
371
- if (l === "bell") p = a + (n.C - a) * Ne(t);
782
+ var Ye = [.35, .95], Xe = [.18, .42];
783
+ function Ze(e, t) {
784
+ return e ? [Math.max(0, Math.min(1, e[0])), Math.max(0, Math.min(1, e[1]))] : t === "dark" ? Xe : Ye;
785
+ }
786
+ function Qe(e, t = {}) {
787
+ let n = typeof e == "string" ? E(e) : e, { stopCount: r = 4, harmony: i = "analogous", lightnessSpread: a = .32, chromaFalloff: o = .85, hueSpread: s = 28, lightnessEasing: c = "linear", chromaEasing: l = "bell", temperatureShift: u = 0, avoidHues: d, scheme: f, lBand: p } = t, m = Math.max(2, Math.min(8, Math.round(r))), [h, g] = Ze(p, f), _ = n.L - a / 2, v = n.L + a / 2;
788
+ _ < h && (v += h - _, _ = h), v > g && (_ -= v - g, v = g), _ = Math.max(h, _), v = Math.min(g, v);
789
+ let y = [], b = -Infinity;
790
+ for (let e = 0; e < m; e++) {
791
+ let t = m === 1 ? 0 : e / (m - 1), r = _ + (v - _) * et(t, c), a = n.C * o, f;
792
+ if (l === "bell") f = a + (n.C - a) * tt(t);
372
793
  else {
373
- let e = l === "sine" ? I(t, "sine") : t;
374
- p = n.C - (n.C - a) * e;
794
+ let e = l === "sine" ? et(t, "sine") : t;
795
+ f = n.C - (n.C - a) * e;
375
796
  }
376
- let m = ie(n.h, i, s, t);
377
- u > 0 && (m = Le(m, t, u)), d && d.length > 0 && (m = ze(m, d)), _.push(re({
797
+ let p = ee(n.h, i, s, t);
798
+ u > 0 && (p = at(p, t, u)), d && d.length > 0 && (p = st(p, d));
799
+ let h = $e(S({
378
800
  L: r,
379
- C: p,
380
- h: m
381
- }));
801
+ C: f,
802
+ h: p
803
+ }), b);
804
+ b = h.L, y.push(h);
805
+ }
806
+ return y;
807
+ }
808
+ function $e(e, t) {
809
+ if (e.L >= t) return e;
810
+ let { h: n } = e, r = t, i = e.C;
811
+ for (let e = 0; e < 48; e++) {
812
+ let [e, t, a] = pe(r, i, n), [o, s, c] = de(e, t, a);
813
+ if (Math.max(o, s, c) <= 1) break;
814
+ i *= .99;
382
815
  }
383
- return _;
816
+ return {
817
+ L: r,
818
+ C: i,
819
+ h: n
820
+ };
384
821
  }
385
- function I(e, t) {
822
+ function et(e, t) {
386
823
  return t === "sine" ? .5 - .5 * Math.cos(Math.PI * e) : e;
387
824
  }
388
- function Ne(e) {
825
+ function tt(e) {
389
826
  return Math.sin(Math.PI * e);
390
827
  }
391
- var Pe = 70, Fe = 250, Ie = 22;
392
- function Le(e, t, n) {
828
+ var nt = 70, rt = 250, it = 22;
829
+ function at(e, t, n) {
393
830
  let r = (t - .5) * 2;
394
831
  if (r === 0 || n === 0) return e;
395
- let i = (ge(e, r >= 0 ? Pe : Fe, 1, "shorter") - e + 540) % 360 - 180;
396
- return ((e + Math.sign(i) * Math.min(Math.abs(r) * n * Ie, Math.abs(i))) % 360 + 360) % 360;
832
+ let i = (ue(e, r >= 0 ? nt : rt, 1, "shorter") - e + 540) % 360 - 180;
833
+ return ((e + Math.sign(i) * Math.min(Math.abs(r) * n * it, Math.abs(i))) % 360 + 360) % 360;
397
834
  }
398
835
  var L = (e) => (e % 360 + 360) % 360;
399
- function Re(e, t, n) {
836
+ function ot(e, t, n) {
400
837
  let r = L(e), i = L(t), a = L(n);
401
838
  return i <= a ? r >= i && r <= a : r >= i || r <= a;
402
839
  }
@@ -404,12 +841,12 @@ function R(e, t) {
404
841
  let n = Math.abs(L(e) - L(t)) % 360;
405
842
  return n > 180 ? 360 - n : n;
406
843
  }
407
- function ze(e, t) {
844
+ function st(e, t) {
408
845
  let n = .5, r = L(e);
409
846
  for (let e = 0; e < t.length + 2; e++) {
410
847
  let e = !1;
411
848
  for (let [i, a] of t) {
412
- if (!Re(r, i, a)) continue;
849
+ if (!ot(r, i, a)) continue;
413
850
  let t = L(i - n), o = L(a + n);
414
851
  r = R(r, t) <= R(r, o) ? t : o, e = !0;
415
852
  }
@@ -418,8 +855,16 @@ function ze(e, t) {
418
855
  return r;
419
856
  }
420
857
  //#endregion
421
- //#region src/components/custom/aurora/composables/uniformBridge.ts
422
- var z = {
858
+ //#region src/components/aurora/composables/uniformBridge.ts
859
+ var ct = {
860
+ x: .5,
861
+ y: .5,
862
+ strength: 0,
863
+ radius: .25,
864
+ velX: 0,
865
+ velY: 0,
866
+ burst: 0
867
+ }, z = {
423
868
  smooth: 0,
424
869
  pastel: 1,
425
870
  watercolor: 2,
@@ -427,13 +872,15 @@ var z = {
427
872
  crayon: 4,
428
873
  vangogh: 5,
429
874
  "oil-pastel": 6,
430
- kuwahara: 7
875
+ kuwahara: 7,
876
+ metal: 8,
877
+ "metal-gradient": 9
431
878
  }, B = {
432
879
  shorter: 0,
433
880
  longer: 1,
434
881
  increasing: 2,
435
882
  decreasing: 3
436
- }, Be = {
883
+ }, lt = {
437
884
  none: 0,
438
885
  radial: 1,
439
886
  swirl: 2,
@@ -448,7 +895,7 @@ var z = {
448
895
  cellular: 1,
449
896
  hybrid: 2,
450
897
  curl: 3
451
- }, Ve = {
898
+ }, ut = {
452
899
  oil: 0,
453
900
  knife: 1,
454
901
  chunky: 3
@@ -457,20 +904,20 @@ var z = {
457
904
  C: .0125,
458
905
  h: 77.5
459
906
  };
460
- function He(e) {
461
- return e === void 0 ? S(U.L, U.C, U.h) : Array.isArray(e) ? e : S(e.L, e.C, e.h);
907
+ function dt(e) {
908
+ return e === void 0 ? w(U.L, U.C, U.h) : Array.isArray(e) ? e : w(e.L, e.C, e.h);
462
909
  }
463
- function Ue(e) {
910
+ function ft(e) {
464
911
  return z[e.medium];
465
912
  }
466
- function We(e) {
467
- return Ve[e.strokeMode];
913
+ function pt(e) {
914
+ return ut[e.strokeMode];
468
915
  }
469
- function Ge(e) {
916
+ function mt(e) {
470
917
  return e.medium === "vangogh" || e.medium === "oil-pastel" || e.medium === "crayon" || e.medium === "kuwahara" ? V.tensor : V[e.strokeOrient ?? "flow"];
471
918
  }
472
- function Ke(e, t, n, r) {
473
- let i = (e) => 1 - e, a = {
919
+ function ht(e, t, n) {
920
+ let r = (e) => 1 - e, i = {
474
921
  palette: new Float32Array(24),
475
922
  pos: new Float32Array(12),
476
923
  rad: new Float32Array(6),
@@ -481,89 +928,90 @@ function Ke(e, t, n, r) {
481
928
  elong: new Float32Array(6),
482
929
  angle: new Float32Array(6)
483
930
  };
484
- return function(o) {
485
- e.useProgram(t), N(o.palette, 8, a.palette), e.uniform3fv(n.uPalette, a.palette), e.uniform1i(n.uStopCount, Math.min(o.palette.length, 8));
486
- let s = Math.min(o.nuclei.length, 6);
487
- e.uniform1i(n.uNucleiCount, s);
488
- for (let e = 0; e < s; e++) {
489
- let t = o.nuclei[e];
490
- a.pos[e * 2 + 0] = t.x, a.pos[e * 2 + 1] = i(t.y), a.rad[e] = t.radius, a.pb[e] = t.paletteBias, a.vb[e] = t.valueBias, a.dr[e] = t.driftRadius, a.dp[e] = t.driftPhase, a.elong[e] = t.elongation ?? 1, a.angle[e] = -(t.angle ?? 0) * Math.PI / 180;
931
+ return function(a) {
932
+ e.useProgram(t), I(a.palette, 8, i.palette), e.uniform3fv(n.uPalette, i.palette), e.uniform1i(n.uStopCount, Math.min(a.palette.length, 8));
933
+ let o = Math.min(a.nuclei.length, 6);
934
+ e.uniform1i(n.uNucleiCount, o);
935
+ for (let e = 0; e < o; e++) {
936
+ let t = a.nuclei[e];
937
+ i.pos[e * 2 + 0] = t.x, i.pos[e * 2 + 1] = r(t.y), i.rad[e] = t.radius, i.pb[e] = t.paletteBias, i.vb[e] = t.valueBias, i.dr[e] = t.driftRadius, i.dp[e] = t.driftPhase, i.elong[e] = t.elongation ?? 1, i.angle[e] = -(t.angle ?? 0) * Math.PI / 180;
491
938
  }
492
- for (let e = s; e < 6; e++) a.pos[e * 2 + 0] = 0, a.pos[e * 2 + 1] = 0, a.rad[e] = 0, a.pb[e] = 0, a.vb[e] = 0, a.dr[e] = 0, a.dp[e] = 0, a.elong[e] = 1, a.angle[e] = 0;
493
- e.uniform2fv(n.uNucleiPos, a.pos), e.uniform1fv(n.uNucleiRadius, a.rad), e.uniform1fv(n.uNucleiPaletteBias, a.pb), e.uniform1fv(n.uNucleiValueBias, a.vb), e.uniform1fv(n.uNucleiDriftRadius, a.dr), e.uniform1fv(n.uNucleiDriftPhase, a.dp), e.uniform1fv(n.uNucleiElong, a.elong), e.uniform1fv(n.uNucleiAngle, a.angle), e.uniform1f(n.uSoftmaxBeta, o.softmaxBeta), e.uniform1f(n.uValueVariance, o.valueVariance), e.uniform1f(n.uWarpAmount, o.warpAmount), e.uniform1f(n.uWarpScale, o.warpScale), e.uniform1f(n.uWarpDrift, o.warpDrift), e.uniform1i(n.uWarpMode, H[o.warpMode]), e.uniform1i(n.uNoiseOctaves, o.noiseOctaves), e.uniform1i(n.uMedium, Ue(o)), e.uniform1i(n.uHuePath, B[o.huePath ?? "shorter"]), e.uniform1i(n.uFlowPattern, Be[o.flow.pattern]), e.uniform2f(n.uFlowFocal, o.flow.focalX, i(o.flow.focalY)), e.uniform1f(n.uFlowAngle, o.flow.angle), e.uniform1f(n.uFlowCurl, o.flow.curl), e.uniform2f(n.uCursor, r.x, i(r.y)), e.uniform1f(n.uCursorStrength, r.strength), e.uniform1f(n.uCursorRadius, r.radius), e.uniform2f(n.uCursorVelocity, r.velX, -r.velY), e.uniform1f(n.uCursorBurst, r.burst), e.uniform1f(n.uStrokeAmount, o.strokeAmount), e.uniform1f(n.uStrokeScale, o.strokeScale), e.uniform1f(n.uStrokeAnisotropy, o.strokeAnisotropy), e.uniform1i(n.uStrokeLayers, o.strokeLayers), e.uniform1i(n.uStrokeMode, We(o)), e.uniform1i(n.uStrokeOrient, Ge(o));
939
+ for (let e = o; e < 6; e++) i.pos[e * 2 + 0] = 0, i.pos[e * 2 + 1] = 0, i.rad[e] = 0, i.pb[e] = 0, i.vb[e] = 0, i.dr[e] = 0, i.dp[e] = 0, i.elong[e] = 1, i.angle[e] = 0;
940
+ e.uniform2fv(n.uNucleiPos, i.pos), e.uniform1fv(n.uNucleiRadius, i.rad), e.uniform1fv(n.uNucleiPaletteBias, i.pb), e.uniform1fv(n.uNucleiValueBias, i.vb), e.uniform1fv(n.uNucleiDriftRadius, i.dr), e.uniform1fv(n.uNucleiDriftPhase, i.dp), e.uniform1fv(n.uNucleiElong, i.elong), e.uniform1fv(n.uNucleiAngle, i.angle), e.uniform1f(n.uSoftmaxBeta, a.softmaxBeta), e.uniform1f(n.uValueVariance, a.valueVariance), e.uniform1f(n.uWarpAmount, a.warpAmount), e.uniform1f(n.uWarpScale, a.warpScale), e.uniform1f(n.uWarpDrift, a.warpDrift), e.uniform1i(n.uWarpMode, H[a.warpMode]), e.uniform1i(n.uNoiseOctaves, a.noiseOctaves), e.uniform1i(n.uMedium, ft(a)), e.uniform1i(n.uHuePath, B[a.huePath ?? "shorter"]), e.uniform1i(n.uFlowPattern, lt[a.flow.pattern]), e.uniform2f(n.uFlowFocal, a.flow.focalX, r(a.flow.focalY)), e.uniform1f(n.uFlowAngle, a.flow.angle), e.uniform1f(n.uFlowCurl, a.flow.curl);
941
+ let s = ct;
942
+ e.uniform2f(n.uCursor, s.x, r(s.y)), e.uniform1f(n.uCursorStrength, s.strength), e.uniform1f(n.uCursorRadius, s.radius), e.uniform2f(n.uCursorVelocity, s.velX, -s.velY), e.uniform1f(n.uCursorBurst, s.burst), e.uniform1f(n.uStrokeAmount, a.strokeAmount), e.uniform1f(n.uStrokeScale, a.strokeScale), e.uniform1f(n.uStrokeAnisotropy, a.strokeAnisotropy), e.uniform1i(n.uStrokeLayers, a.strokeLayers), e.uniform1i(n.uStrokeMode, pt(a)), e.uniform1i(n.uStrokeOrient, mt(a));
494
943
  {
495
- let t = o.lightDir ?? [
944
+ let t = a.lightDir ?? [
496
945
  -.5,
497
946
  .6,
498
947
  .62
499
- ], r = He(o.lightColor);
948
+ ], r = dt(a.lightColor);
500
949
  e.uniform3f(n.uLightDir, t[0], t[1], t[2]), e.uniform3f(n.uLightColor, r[0], r[1], r[2]);
501
950
  }
502
- e.uniform1f(n.uWetEdge, o.wetEdge), e.uniform1f(n.uGranulation, o.granulation), e.uniform1f(n.uImpasto, o.impasto), e.uniform1f(n.uBrokenColor, o.brokenColor), e.uniform1f(n.uCanvasGrain, o.canvasGrain), e.uniform1f(n.uNucleiDrift, o.nucleiDrift), e.uniform1f(n.uPaletteDrift, o.paletteDrift), e.uniform1f(n.uBreathDepth, o.breathDepth), e.uniform1f(n.uBreathPeriod, o.breathPeriod), e.uniform1f(n.uSaturation, o.saturation), e.uniform1f(n.uPaperGrain, o.paperGrain), e.uniform1f(n.uAlpha, o.alpha), e.uniform1f(n.uVividness, o.vividness ?? 1);
951
+ e.uniform1f(n.uWetEdge, a.wetEdge), e.uniform1f(n.uGranulation, a.granulation), e.uniform1f(n.uImpasto, a.impasto), e.uniform1f(n.uBrokenColor, a.brokenColor), e.uniform1f(n.uCanvasGrain, a.canvasGrain), e.uniform1f(n.uMetalPolish, a.metalPolish ?? 1), e.uniform1f(n.uMetalHeightScale, a.metalHeightScale ?? 1), e.uniform1f(n.uNucleiDrift, a.nucleiDrift), e.uniform1f(n.uPaletteDrift, a.paletteDrift), e.uniform1f(n.uBreathDepth, a.breathDepth), e.uniform1f(n.uBreathPeriod, a.breathPeriod), e.uniform1f(n.uSaturation, a.saturation), e.uniform1f(n.uPaperGrain, a.paperGrain), e.uniform1f(n.uAlpha, a.alpha), e.uniform1f(n.uVividness, a.vividness ?? 1), e.uniform1i(n.uImage, 0), e.uniform1f(n.uBlurMin, a.imageBlur?.min ?? .004), e.uniform1f(n.uBlurMax, a.imageBlur?.max ?? .06);
952
+ let c = e.drawingBufferHeight > 0 ? e.drawingBufferWidth / e.drawingBufferHeight : 1;
953
+ e.uniform1f(n.uImageAspect, c);
503
954
  };
504
955
  }
505
956
  //#endregion
506
- //#region src/components/custom/aurora/composables/cursorModel.ts
507
- var W = .22, qe = .18, Je = .992, Ye = .96, G = .3;
508
- function Xe() {
957
+ //#region src/components/aurora/composables/frameLoop.ts
958
+ var W = .001, gt = 1e-4;
959
+ function G(e, t, i) {
960
+ let a = r(n(e), t), o = a.burst;
961
+ if (i > 0) {
962
+ let t = e.acceleration.value, n = e.velocity.value, r = -(t.x * n.x + t.y * n.y);
963
+ r > 0 && (o = Math.min(1, o + r * 3));
964
+ }
509
965
  return {
966
+ x: a.cx,
967
+ y: a.cy,
968
+ strength: a.strength,
969
+ radius: a.radius,
970
+ velX: a.velX,
971
+ velY: a.velY,
972
+ burst: o
973
+ };
974
+ }
975
+ function K(e) {
976
+ let t = e.attractorVelocity.value;
977
+ return e.engagement.value > W || e.speed.value > W || e.burst.value > W || Math.hypot(t.x, t.y) > gt;
978
+ }
979
+ function _t(e) {
980
+ let { gl: t, prog: n, uniforms: r, pointerField: i, getCursorScalars: a, getConfig: o, getReducedMotion: s } = e, c = (e) => 1 - e, l = null, u = {
510
981
  x: .5,
511
982
  y: .5,
512
- targetX: .5,
513
- targetY: .5,
514
983
  strength: 0,
515
- targetStrength: 0,
516
984
  radius: .25,
517
985
  velX: 0,
518
986
  velY: 0,
519
987
  burst: 0
520
988
  };
521
- }
522
- function K(e, t = 1) {
523
- let n = Math.max(0, Math.min(1, t));
524
- e.x += (e.targetX - e.x) * W, e.y += (e.targetY - e.y) * W, e.strength += (e.targetStrength - e.strength) * qe, e.targetStrength *= Je, e.velX *= (1 - G) * n, e.velY *= (1 - G) * n, e.burst *= Ye * n;
525
- }
526
- function Ze(e, t, n) {
527
- let r = .12, i = Math.max(-r, Math.min(r, t)), a = Math.max(-r, Math.min(r, n));
528
- e.velX += (i - e.velX) * G, e.velY += (a - e.velY) * G;
529
- let o = Math.hypot(i, a);
530
- e.burst = Math.min(1, e.burst + o * 4);
531
- }
532
- function q(e) {
533
- return e.targetStrength > .001 || e.strength > .001 || Math.abs(e.x - e.targetX) > .001 || Math.abs(e.y - e.targetY) > .001;
534
- }
535
- //#endregion
536
- //#region src/components/custom/aurora/composables/frameLoop.ts
537
- function Qe(e) {
538
- let { gl: t, prog: n, uniforms: r, cursor: i, getConfig: a, getReducedMotion: o, pointerField: s } = e, c = (e) => 1 - e, l = null;
539
- function u() {
540
- return +!o();
989
+ function d() {
990
+ return +!s();
541
991
  }
542
- function d(e) {
543
- if (t.useProgram(n), t.uniform2f(r.uCursor, i.x, c(i.y)), t.uniform1f(r.uCursorStrength, i.strength), t.uniform1f(r.uCursorRadius, i.radius), t.uniform2f(r.uCursorVelocity, i.velX, -i.velY), t.uniform1f(r.uCursorBurst, i.burst), t.uniform1f(r.uTime, e), a().interactivity?.light) {
544
- let n = u(), a = e * .25, o = Math.cos(a) * .5, s = Math.sin(a) * .5, c = (i.x - .5) * 2, l = (.5 - i.y) * 2, d = i.strength * n;
545
- o = o * (1 - d) + c * d, s = s * (1 - d) + l * d, t.uniform3f(r.uLightDir, o * n + (1 - n) * -.5, s * n + (1 - n) * .6, .62);
992
+ function f(e) {
993
+ if (t.useProgram(n), t.uniform2f(r.uCursor, u.x, c(u.y)), t.uniform1f(r.uCursorStrength, u.strength), t.uniform1f(r.uCursorRadius, u.radius), t.uniform2f(r.uCursorVelocity, u.velX, -u.velY), t.uniform1f(r.uCursorBurst, u.burst), t.uniform1f(r.uTime, e), o().interactivity?.light) {
994
+ let n = d(), i = e * .25, a = Math.cos(i) * .5, o = Math.sin(i) * .5, s = (u.x - .5) * 2, c = (.5 - u.y) * 2, l = u.strength * n;
995
+ a = a * (1 - l) + s * l, o = o * (1 - l) + c * l, t.uniform3f(r.uLightDir, a * n + (1 - n) * -.5, o * n + (1 - n) * .6, .62);
546
996
  }
547
997
  t.clear(t.COLOR_BUFFER_BIT), t.drawArrays(t.TRIANGLES, 0, 3);
548
998
  }
549
- function f() {
550
- if (o()) return !1;
551
- let e = a();
552
- return e.nucleiDrift !== 0 || e.paletteDrift !== 0 || e.breathDepth !== 0 || e.warpDrift !== 0 || e.interactivity?.light && i.burst > .001 ? !0 : q(i);
999
+ function p() {
1000
+ if (s()) return !1;
1001
+ let e = o();
1002
+ return e.nucleiDrift !== 0 || e.paletteDrift !== 0 || e.breathDepth !== 0 || e.warpDrift !== 0 ? !0 : K(i);
553
1003
  }
554
1004
  return {
555
1005
  frame: (e) => {
556
- let t = l === null ? 0 : Math.max(0, (e - l) * 1e3);
557
- l = e, s.tick(u() === 0 ? 0 : t);
558
- let n = s.acceleration.value, r = s.velocity.value, a = -(n.x * r.x + n.y * r.y);
559
- a > 0 && u() > 0 && (i.burst = Math.min(1, i.burst + a * 6)), K(i, u()), d(e);
1006
+ let t = d(), n = l === null ? 0 : Math.max(0, (e - l) * 1e3);
1007
+ l = e, i.tick(t === 0 ? 0 : n), u = G(i, a(), t), f(e);
560
1008
  },
561
- needsAnimation: f
1009
+ needsAnimation: p
562
1010
  };
563
1011
  }
564
1012
  //#endregion
565
- //#region src/components/custom/aurora/constants/shaders/aurora.wgsl.ts
566
- var $e = `
1013
+ //#region src/components/aurora/constants/shaders/aurora.wgsl.ts
1014
+ var vt = `
567
1015
  const MAX_NUCLEI: i32 = 6;
568
1016
  const MAX_STOPS: i32 = 8;
569
1017
  const PI: f32 = 3.141592653589793;
@@ -583,7 +1031,9 @@ struct Uniforms {
583
1031
  // scalars3: (uBreathPeriod, uCursorStrength, uCursorRadius, uVividness)
584
1032
  // BD.W-AUR-VIVIDNESS — the .w pad lane now carries the §3 chroma-floor strength.
585
1033
  scalars3: vec4<f32>,
586
- // cursor: (uCursor.x, uCursor.y, _pad, _pad)
1034
+ // cursor: (uCursor.x, uCursor.y, uMetalPolish, uMetalHeightScale)
1035
+ // BG.W-AUR-METAL-FINISH — the two free pad lanes carry the metal-medium knobs (the
1036
+ // metal light is cursor-synthesized so it reads in-struct on the WGSL primary too).
587
1037
  cursor: vec4<f32>,
588
1038
  // ints: (uStopCount, uNucleiCount, uWarpMode, uNoiseOctaves)
589
1039
  ints0: vec4<i32>,
@@ -636,7 +1086,7 @@ fn vnoise(p: vec2<f32>) -> f32 {
636
1086
  return mix(mix(a, b, uu.x), mix(c, d, uu.x), uu.y);
637
1087
  }
638
1088
 
639
- ${u}
1089
+ ${m}
640
1090
 
641
1091
  fn fbm(p0: vec2<f32>) -> f32 {
642
1092
  var v = 0.0;
@@ -652,9 +1102,9 @@ fn fbm(p0: vec2<f32>) -> f32 {
652
1102
  return v;
653
1103
  }
654
1104
 
655
- ${o}
1105
+ ${u}
1106
+ ${f}
656
1107
  ${c}
657
- ${i}
658
1108
 
659
1109
  // Interleaved Gradient Noise (Jimenez) — display-space 1-LSB dither.
660
1110
  fn ign(p: vec2<f32>) -> f32 {
@@ -848,6 +1298,27 @@ fn mGranulation() -> f32 { return u.scalars5.y; }
848
1298
  fn mBrokenColor() -> f32 { return u.scalars5.z; }
849
1299
  fn mKuwaharaQ() -> f32 { return u.scalars5.w; }
850
1300
  fn mKuwaharaRadius() -> f32 { return u.kuwahara.x; }
1301
+ // BG.W-AUR-METAL-FINISH — the metal-medium knobs ride the FREE cursor.z/.w pad lanes
1302
+ // (uniformBridgeWGPU packs them; written 0 on a non-metal config → no-op). These read
1303
+ // the IN-STRUCT cursor — the metal light is cursor-synthesized so it crosses to WGSL
1304
+ // (a phantom uLightDir read would be flat on the primary — uLightDir is .frag-only).
1305
+ fn mMetalPolish() -> f32 { return u.cursor.z; }
1306
+ fn mMetalHeightScale() -> f32 { return u.cursor.w; }
1307
+
1308
+ // ── Gradient pack (BG.W-AUR-METAL-FINISH; the WGSL twin) ────────────────────
1309
+ // structureTensorField re-plumbs its already-computed luma gradient (Gx,Gy) out
1310
+ // through the return's .w lane so the metal medium pays ZERO extra taps. 12 bits per
1311
+ // bounded component ([-4,4]) into one f32; the crayon/kuwahara callers read only .xy/.z.
1312
+ fn packGrad(gx: f32, gy: f32) -> f32 {
1313
+ let qx = floor(clamp(gx * 0.125 + 0.5, 0.0, 1.0) * 4095.0);
1314
+ let qy = floor(clamp(gy * 0.125 + 0.5, 0.0, 1.0) * 4095.0);
1315
+ return qx + qy * 4096.0;
1316
+ }
1317
+ fn unpackGrad(packed: f32) -> vec2<f32> {
1318
+ let qy = floor(packed * (1.0 / 4096.0));
1319
+ let qx = packed - qy * 4096.0;
1320
+ return (vec2<f32>(qx, qy) * (1.0 / 4095.0) - 0.5) * 8.0;
1321
+ }
851
1322
 
852
1323
  // ── Base color re-sample (the edge-mask operator the mediums Sobel/sector-sample) ──
853
1324
  // The WGSL twin of mediums.glsl.ts sampleBase: warp -> nuclei field -> palette -> value.
@@ -870,8 +1341,10 @@ fn brokenColorJitter(c: vec3<f32>, hueSeed: f32, valueSeed: f32, strength: f32)
870
1341
  }
871
1342
 
872
1343
  // ── Structure-tensor / edge-tangent-flow (AW.W4.1; the WGSL twin) ───────────
873
- // Returns vec3(tangent.x, tangent.y, A) — the minor-eigenvector edge-tangent + coherence.
874
- fn structureTensorField(p: vec2<f32>, t: f32, fallbackDir: vec2<f32>) -> vec3<f32> {
1344
+ // Returns vec4(tangent.x, tangent.y, A, packGrad(Gx,Gy)) — the minor-eigenvector
1345
+ // edge-tangent + coherence + the metal medium's packed gradient (BG.W-AUR-METAL-FINISH;
1346
+ // the .xy/.z crayon/kuwahara callers are byte-unchanged).
1347
+ fn structureTensorField(p: vec2<f32>, t: f32, fallbackDir: vec2<f32>) -> vec4<f32> {
875
1348
  let e = 0.0035;
876
1349
  let l00 = dot(sampleBase(p + vec2<f32>(-e, -e), t), W_LUMA);
877
1350
  let l10 = dot(sampleBase(p + vec2<f32>(0.0, -e), t), W_LUMA);
@@ -902,7 +1375,7 @@ fn structureTensorField(p: vec2<f32>, t: f32, fallbackDir: vec2<f32>) -> vec3<f3
902
1375
  if (dot(tangent, fallbackDir) < 0.0) { tangent = -tangent; }
903
1376
  let blendW = pow(A, 0.28);
904
1377
  let dir = normalize(mix(fallbackDir, tangent, blendW) + vec2<f32>(1e-6, 1e-6));
905
- return vec3<f32>(dir, A);
1378
+ return vec4<f32>(dir, A, packGrad(Gx, Gy));
906
1379
  }
907
1380
 
908
1381
  // ── Flow field (the WGSL twin — the simple flow seed the medium fallback dirs use) ──
@@ -1088,18 +1561,86 @@ fn mediumKuwahara(col0: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
1088
1561
  return mix(col0, result, clamp(mStrokeAmount(), 0.0, 1.0));
1089
1562
  }
1090
1563
 
1564
+ // ── Metal — the two-term anisotropic BRDF (uMedium==8/9; the WGSL twin) ──────
1565
+ // The field re-lights as warm folded metal: the luma HEIGHT field (the packed
1566
+ // structure-tensor gradient → the surface normal) catches an anisotropic Blinn streak
1567
+ // (brushed metal, running ALONG the coherent edge-tangent) plus a sharp crest, both
1568
+ // raked by the IN-STRUCT cursor-synth light (crosses to WGSL — never uLightDir). The
1569
+ // catch is the achromatic-warm anchor (never a cold chrome-blue). ZERO extra taps —
1570
+ // the gradient is unpacked from the tensor's .w lane the caller already computed.
1571
+ const METAL_CATCH_WARM: vec3<f32> = vec3<f32>(1.0, 0.97, 0.90);
1572
+ const METAL_HEIGHT_SCALE: f32 = 2.2;
1573
+ const METAL_LIGHT_Z: f32 = 0.55;
1574
+ const METAL_IDLE_RAKE: vec2<f32> = vec2<f32>(0.32, 0.34);
1575
+ const METAL_SHININESS_ANISO: f32 = 6.0;
1576
+ const METAL_SHININESS_CREST: f32 = 40.0;
1577
+ const METAL_COHERENCE_FLOOR: f32 = 0.22;
1578
+ const METAL_BODY_FLOOR: f32 = 0.42;
1579
+ const METAL_GRADIENT_FLATTEN: f32 = 0.55;
1580
+ const METAL_SPARKLE_DENSITY: f32 = 240.0;
1581
+ const METAL_SPARKLE_THRESH: f32 = 0.72;
1582
+ const METAL_SPARKLE_AMP: f32 = 0.6;
1583
+
1584
+ fn metalShade(baseCol: vec3<f32>, p: vec2<f32>, stf: vec4<f32>) -> vec3<f32> {
1585
+ let tangent = stf.xy;
1586
+ let A = stf.z;
1587
+ let grad = unpackGrad(stf.w);
1588
+ let N = normalize(vec3<f32>(grad * (METAL_HEIGHT_SCALE * mMetalHeightScale()), 1.0));
1589
+ let V = vec3<f32>(0.0, 0.0, 1.0);
1590
+ // Cursor-synth rake light (u.cursor is in-struct — crosses to WGSL).
1591
+ let L = normalize(vec3<f32>((u.cursor.xy - p) + METAL_IDLE_RAKE, METAL_LIGHT_Z));
1592
+ let H = normalize(L + V);
1593
+ // Anisotropic streak — brushed metal along the edge-tangent.
1594
+ let tH = dot(normalize(tangent), H.xy);
1595
+ let sinTH = sqrt(clamp(1.0 - tH * tH, 0.0, 1.0));
1596
+ let streak = pow(clamp(sinTH, 0.0, 1.0), METAL_SHININESS_ANISO);
1597
+ let crest = pow(clamp(dot(N, H), 0.0, 1.0), METAL_SHININESS_CREST);
1598
+ var spec = streak * crest;
1599
+ spec = spec * smoothstep(0.0, METAL_COHERENCE_FLOOR, A);
1600
+ // Technicolor valley base — the body keeps the FIELD hue; luma rides the relief.
1601
+ let diff = clamp(dot(N, L), 0.0, 1.0);
1602
+ let body = baseCol * (METAL_BODY_FLOOR + (1.0 - METAL_BODY_FLOOR) * diff);
1603
+ return body + METAL_CATCH_WARM * (spec * clamp(mMetalPolish(), 0.0, 4.0));
1604
+ }
1605
+
1606
+ fn mediumMetal(col: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
1607
+ let stf = structureTensorField(p, t, flowField(p, t));
1608
+ return metalShade(col, p, stf);
1609
+ }
1610
+
1611
+ // metal-gradient (uMedium==9) — the SAME BRDF over a pre-flattened base + the
1612
+ // twinkle-in-place flake sparkle (position FIXED per cell, phase-animated, facing-gated).
1613
+ fn mediumMetalGradient(col: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
1614
+ let stf = structureTensorField(p, t, flowField(p, t));
1615
+ let flat = mix(col, vec3<f32>(dot(col, W_LUMA)), METAL_GRADIENT_FLATTEN);
1616
+ var metal = metalShade(flat, p, stf);
1617
+ let grad = unpackGrad(stf.w);
1618
+ let facing = normalize(vec3<f32>(grad * (METAL_HEIGHT_SCALE * mMetalHeightScale()), 1.0)).z;
1619
+ let cell = floor(p * METAL_SPARKLE_DENSITY);
1620
+ let seed = hash21(cell);
1621
+ let tw = pow(clamp(sin(t + seed * 6.2831853), 0.0, 1.0), 40.0);
1622
+ let flakeGate = step(METAL_SPARKLE_THRESH, seed);
1623
+ metal = metal + METAL_CATCH_WARM * (tw * flakeGate * clamp(facing, 0.0, 1.0) * METAL_SPARKLE_AMP);
1624
+ return metal;
1625
+ }
1626
+
1091
1627
  // ── Medium dispatch (the WGSL twin of the GLSL main() if-ladder) ────────────
1092
1628
  // uMedium: 0 smooth · 1 pastel · 2 watercolor · 3 oil · 4 crayon · 5 vangogh ·
1093
- // 6 oil-pastel · 7 kuwahara. The cheap peer mediums (pastel/watercolor/crayon) +
1094
- // kuwahara port their own bodies; the oil/vangogh/oil-pastel STROKE cascade renders
1095
- // the anisotropic-Kuwahara PAINTERLY finish here (a real oil-paint read, never the
1096
- // smooth core — the "NO FALLBACKS on Safari" mandate; the full per-dab Starry-Night
1097
- // stroke WGSL is the booked W-AURORA-WGPU-MEDIUMS-STROKES tail).
1629
+ // 6 oil-pastel · 7 kuwahara · 8 metal · 9 metal-gradient. The cheap peer mediums
1630
+ // (pastel/watercolor/crayon) + kuwahara + metal port their own bodies; the
1631
+ // oil/vangogh/oil-pastel STROKE cascade renders the anisotropic-Kuwahara PAINTERLY
1632
+ // finish here (a real oil-paint read, never the smooth core — the "NO FALLBACKS on
1633
+ // Safari" mandate; the full per-dab Starry-Night stroke WGSL is the booked
1634
+ // W-AURORA-WGPU-MEDIUMS-STROKES tail).
1098
1635
  fn applyMedium(col: vec3<f32>, p: vec2<f32>, t: f32) -> vec3<f32> {
1099
1636
  let medium = u.ints1.x;
1100
1637
  if (medium == 1) { return mediumPastel(col, p, t); }
1101
1638
  if (medium == 2) { return mediumWatercolor(col, p, t); }
1102
1639
  if (medium == 4) { return mediumCrayon(col, p, t); }
1640
+ // BG.W-AUR-METAL-FINISH — metal DUAL-PORTS (a .frag-only metal is invisible on the
1641
+ // WGSL primary of both browsers); 8 metal, 9 metal-gradient.
1642
+ if (medium == 8) { return mediumMetal(col, p, t); }
1643
+ if (medium == 9) { return mediumMetalGradient(col, p, t); }
1103
1644
  // oil(3) / vangogh(5) / oil-pastel(6) / kuwahara(7) all render the painterly
1104
1645
  // anisotropic-Kuwahara finish on the WGSL primary (the WebGL2 fallback carries the
1105
1646
  // full per-dab stroke cascade for oil/vangogh/oil-pastel).
@@ -1186,7 +1727,251 @@ fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
1186
1727
  // Premultiply on DISPLAY-space color (matches the WebGL2 path: OETF, then premul).
1187
1728
  return vec4<f32>(col * alpha, alpha);
1188
1729
  }
1189
- `, J = {
1730
+ `, yt = `
1731
+ const MAX_NUCLEI: i32 = 6;
1732
+ const PI: f32 = 3.141592653589793;
1733
+ const BLUR_RINGS: i32 = 3;
1734
+ const BLUR_SECTORS: i32 = 8;
1735
+
1736
+ // The image program's OWN uniform struct (packed vec4 lanes — trivial std140/WGSL
1737
+ // alignment). DISTINCT from the palette program's 576-byte struct (a separate program).
1738
+ struct ImageUniforms {
1739
+ // scalars0: (uTime, uWarpAmount, uWarpScale, uWarpDrift)
1740
+ scalars0: vec4<f32>,
1741
+ // scalars1: (uSoftmaxBeta, uNucleiDrift, uCursorStrength, uCursorRadius)
1742
+ scalars1: vec4<f32>,
1743
+ // scalars2: (uSaturation, uPaperGrain, uAlpha, uVividness)
1744
+ scalars2: vec4<f32>,
1745
+ // image: (uBlurMin, uBlurMax, uImageAspect, _)
1746
+ image: vec4<f32>,
1747
+ // cursor: (uCursor.x, uCursor.y, _, _)
1748
+ cursor: vec4<f32>,
1749
+ // ints: (uNucleiCount, uNoiseOctaves, _, _)
1750
+ ints: vec4<i32>,
1751
+ // nuc0[i] = (pos.x, pos.y, radius, valueBias); nuc1[i] = (driftRadius, driftPhase, elong, angle)
1752
+ nuc0: array<vec4<f32>, 6>,
1753
+ nuc1: array<vec4<f32>, 6>,
1754
+ };
1755
+
1756
+ @group(0) @binding(0) var<uniform> u: ImageUniforms;
1757
+ @group(0) @binding(1) var imgTex: texture_2d<f32>;
1758
+ @group(0) @binding(2) var imgSampler: sampler;
1759
+
1760
+ const K_NUCLEI: f32 = 14.0;
1761
+ const K_WARP: f32 = 5.0;
1762
+
1763
+ // ── Noise (aurora-local hash21/vnoise/fbm — the same compact foundation) ──
1764
+ fn hash21(p0: vec2<f32>) -> f32 {
1765
+ var p = fract(p0 * vec2<f32>(123.34, 456.21));
1766
+ p = p + dot(p, p + 45.32);
1767
+ return fract(p.x * p.y);
1768
+ }
1769
+ fn vnoise(p: vec2<f32>) -> f32 {
1770
+ let i = floor(p);
1771
+ let f = fract(p);
1772
+ let uu = f * f * (3.0 - 2.0 * f);
1773
+ let a = hash21(i);
1774
+ let b = hash21(i + vec2<f32>(1.0, 0.0));
1775
+ let c = hash21(i + vec2<f32>(0.0, 1.0));
1776
+ let d = hash21(i + vec2<f32>(1.0, 1.0));
1777
+ return mix(mix(a, b, uu.x), mix(c, d, uu.x), uu.y);
1778
+ }
1779
+ ${m}
1780
+ fn fbm(p0: vec2<f32>) -> f32 {
1781
+ var v = 0.0;
1782
+ var a = 0.5;
1783
+ var p = p0;
1784
+ let octaves = u.ints.y;
1785
+ for (var i = 0; i < 5; i = i + 1) {
1786
+ if (i >= octaves) { break; }
1787
+ v = v + a * vnoise(p);
1788
+ p = FBM_ROT * p * 2.02;
1789
+ a = a * 0.5;
1790
+ }
1791
+ return v;
1792
+ }
1793
+ fn ign(p: vec2<f32>) -> f32 {
1794
+ return fract(52.9829189 * fract(dot(p, vec2<f32>(0.06711056, 0.00583715))));
1795
+ }
1796
+
1797
+ ${u}
1798
+ ${f}
1799
+
1800
+ fn linOklab(lin: vec3<f32>) -> vec3<f32> {
1801
+ let lms = LINEAR_SRGB_TO_LMS * lin;
1802
+ return LMS_TO_OKLAB * cbrt3(lms);
1803
+ }
1804
+
1805
+ // The Quilez double-warp (fbm) + the cursor swirl — the drift that moves the blur zone.
1806
+ fn domainWarp(p: vec2<f32>, t: f32) -> vec2<f32> {
1807
+ let warpAmount = u.scalars0.y;
1808
+ let warpScale = u.scalars0.z;
1809
+ let warpDrift = u.scalars0.w;
1810
+ let cursorStrength = u.scalars1.z;
1811
+ let cursorRadius = u.scalars1.w;
1812
+ let cursor = u.cursor.xy;
1813
+ let q = vec2<f32>(fbm(p * warpScale + vec2<f32>(0.0, 0.0) + t * warpDrift * K_WARP),
1814
+ fbm(p * warpScale + vec2<f32>(5.2, 1.3) + t * warpDrift * K_WARP));
1815
+ let r = vec2<f32>(fbm(p * warpScale + 4.0 * q + vec2<f32>(1.7, 9.2)),
1816
+ fbm(p * warpScale + 4.0 * q + vec2<f32>(8.3, 2.8)));
1817
+ var warped = p + warpAmount * r;
1818
+ if (cursorStrength > 0.001) {
1819
+ let toP = p - cursor;
1820
+ let d = length(toP);
1821
+ let rr = max(cursorRadius, 0.01);
1822
+ let w = exp(-(d * d) / (rr * rr * 0.45));
1823
+ let ang = w * cursorStrength * 2.1;
1824
+ let ca = cos(ang);
1825
+ let sa = sin(ang);
1826
+ let rotated = vec2<f32>(ca * toP.x - sa * toP.y, sa * toP.x + ca * toP.y) + cursor;
1827
+ warped = mix(warped, rotated + warpAmount * r * 0.7, w * cursorStrength);
1828
+ }
1829
+ return warped;
1830
+ }
1831
+
1832
+ // The drifting BLUR ZONE — the anisotropic-Gaussian nuclei softmax (the SAME field the
1833
+ // palette program reads), drift-coupled.
1834
+ fn zoneField(p: vec2<f32>, t: f32) -> f32 {
1835
+ let nucleiCount = u.ints.x;
1836
+ let nucleiDrift = u.scalars1.y;
1837
+ let softmaxBeta = u.scalars1.x;
1838
+ var accum = 0.0;
1839
+ var accumW = 0.0;
1840
+ for (var i = 0; i < MAX_NUCLEI; i = i + 1) {
1841
+ if (i >= nucleiCount) { break; }
1842
+ let n0 = u.nuc0[i]; // pos.x, pos.y, radius, valueBias
1843
+ let n1 = u.nuc1[i]; // driftRadius, driftPhase, elong, angle
1844
+ let posI = n0.xy + n1.x * vec2<f32>(
1845
+ cos(t * nucleiDrift * K_NUCLEI + n1.y),
1846
+ sin(t * nucleiDrift * K_NUCLEI + n1.y * 1.13));
1847
+ let diff = p - posI;
1848
+ let ca = cos(n1.w);
1849
+ let sa = sin(n1.w);
1850
+ let local = vec2<f32>(ca * diff.x + sa * diff.y, -sa * diff.x + ca * diff.y);
1851
+ let along = local.x / max(n1.z, 0.01);
1852
+ let d2 = along * along + local.y * local.y;
1853
+ let rad = max(n0.z, 0.01);
1854
+ let w = exp(-softmaxBeta * d2 / (rad * rad));
1855
+ accum = accum + w * (0.5 + 0.5 * n0.w);
1856
+ accumW = accumW + w;
1857
+ }
1858
+ return clamp(accum / max(accumW, 1e-4), 0.0, 1.0);
1859
+ }
1860
+
1861
+ fn coverUv(uv: vec2<f32>) -> vec2<f32> {
1862
+ let aspect = max(u.image.z, 0.0001);
1863
+ var c = uv - vec2<f32>(0.5);
1864
+ c.x = c.x * aspect;
1865
+ let s = 1.0 / max(aspect, 1.0);
1866
+ return c * s + vec2<f32>(0.5);
1867
+ }
1868
+
1869
+ // The bounded 24-tap zone blur — a FIXED 3-ring × 8-sector stratified kernel, radius
1870
+ // per-fragment, sampled in LINEAR light. textureSampleLevel (explicit LOD 0) — WGSL has
1871
+ // no implicit derivative in a varying-radius loop.
1872
+ fn zoneBlur(uv: vec2<f32>, radius: f32) -> vec3<f32> {
1873
+ let aspect = max(u.image.z, 0.0001);
1874
+ var sum = srgbToLinear(textureSampleLevel(imgTex, imgSampler, coverUv(uv), 0.0).rgb);
1875
+ var wsum = 1.0;
1876
+ for (var ring = 1; ring <= BLUR_RINGS; ring = ring + 1) {
1877
+ let rr = radius * (f32(ring) / f32(BLUR_RINGS));
1878
+ for (var s = 0; s < BLUR_SECTORS; s = s + 1) {
1879
+ let a = (f32(s) + 0.5 * f32(ring)) / f32(BLUR_SECTORS) * 2.0 * PI;
1880
+ let off = vec2<f32>(cos(a) / aspect, sin(a)) * rr;
1881
+ sum = sum + srgbToLinear(textureSampleLevel(imgTex, imgSampler, coverUv(uv + off), 0.0).rgb);
1882
+ wsum = wsum + 1.0;
1883
+ }
1884
+ }
1885
+ return sum / wsum;
1886
+ }
1887
+
1888
+ const VIVID_TARGET: f32 = 0.115;
1889
+ const VIVID_EPS: f32 = 0.012;
1890
+ const VIVID_WARM_ANCHOR: vec2<f32> = vec2<f32>(0.34202, 0.93969);
1891
+ fn vividnessFloor(c: vec3<f32>, vividness: f32) -> vec3<f32> {
1892
+ if (vividness <= 0.0001) { return c; }
1893
+ var lab = linOklab(c);
1894
+ let C = length(lab.yz);
1895
+ let modeLift = mix(1.18, 1.0, clamp(lab.x * 1.4, 0.0, 1.0));
1896
+ let Cmin = vividness * VIVID_TARGET * modeLift;
1897
+ var hueDir = VIVID_WARM_ANCHOR;
1898
+ if (C > VIVID_EPS) { hueDir = lab.yz / C; }
1899
+ let yz = hueDir * max(C, Cmin);
1900
+ lab = vec3<f32>(lab.x, yz.x, yz.y);
1901
+ return max(oklabToLinearSrgb(lab), vec3<f32>(0.0));
1902
+ }
1903
+
1904
+ fn saturate3(c: vec3<f32>, amt: f32) -> vec3<f32> {
1905
+ var lch = oklabToOklch(linOklab(c));
1906
+ lch.y = max(lch.y * amt, 0.0);
1907
+ return max(oklabToLinearSrgb(oklchToOklab(lch)), vec3<f32>(0.0));
1908
+ }
1909
+
1910
+ fn aces(color0: vec3<f32>) -> vec3<f32> {
1911
+ let startCompression = 0.8 - 0.04;
1912
+ let desaturation = 0.15;
1913
+ var color = color0;
1914
+ let x = min(color.r, min(color.g, color.b));
1915
+ var offset = 0.04;
1916
+ if (x < 0.08) { offset = x - 6.25 * x * x; }
1917
+ color = color - offset;
1918
+ let peak = max(color.r, max(color.g, color.b));
1919
+ if (peak < startCompression) { return clamp(color, vec3<f32>(0.0), vec3<f32>(1.0)); }
1920
+ let d = 1.0 - startCompression;
1921
+ let newPeak = 1.0 - d * d / (peak + d - startCompression);
1922
+ color = color * (newPeak / peak);
1923
+ let g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);
1924
+ return clamp(mix(color, newPeak * vec3<f32>(1.0), g), vec3<f32>(0.0), vec3<f32>(1.0));
1925
+ }
1926
+
1927
+ struct VSOut {
1928
+ @builtin(position) pos: vec4<f32>,
1929
+ @location(0) uv: vec2<f32>,
1930
+ };
1931
+
1932
+ @vertex
1933
+ fn vs_main(@builtin(vertex_index) vi: u32) -> VSOut {
1934
+ var p = vec2<f32>(-1.0, -1.0);
1935
+ if (vi == 1u) { p = vec2<f32>(3.0, -1.0); }
1936
+ else if (vi == 2u) { p = vec2<f32>(-1.0, 3.0); }
1937
+ var out: VSOut;
1938
+ out.pos = vec4<f32>(p, 0.0, 1.0);
1939
+ out.uv = p * 0.5 + 0.5;
1940
+ return out;
1941
+ }
1942
+
1943
+ @fragment
1944
+ fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
1945
+ let t = u.scalars0.x;
1946
+ let saturation = u.scalars2.x;
1947
+ let paperGrain = u.scalars2.y;
1948
+ let alpha = u.scalars2.z;
1949
+ let vividness = u.scalars2.w;
1950
+ let blurMin = u.image.x;
1951
+ let blurMax = u.image.y;
1952
+
1953
+ let uv = in.uv;
1954
+ let p_warp = domainWarp(uv, t);
1955
+ let zone = zoneField(p_warp, t);
1956
+
1957
+ let radius = mix(blurMin, blurMax, zone);
1958
+ var col = zoneBlur(uv, radius);
1959
+
1960
+ col = saturate3(col, saturation);
1961
+ col = vividnessFloor(col, vividness);
1962
+
1963
+ col = aces(col);
1964
+ let fragCoord = in.pos.xy;
1965
+ let grain = hash21(fragCoord + t * 17.0);
1966
+ col = col + (grain - 0.5) * paperGrain;
1967
+ col = clamp(col * 0.985 + 0.008, vec3<f32>(0.0), vec3<f32>(1.0));
1968
+
1969
+ col = linearToSrgb(col);
1970
+ col = col + (1.0 / 255.0) * (ign(fragCoord) - 0.5);
1971
+
1972
+ return vec4<f32>(col * alpha, alpha);
1973
+ }
1974
+ `, q = {
1190
1975
  scalars0: 0,
1191
1976
  scalars1: 4,
1192
1977
  scalars2: 8,
@@ -1201,8 +1986,8 @@ fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
1201
1986
  scalars4: 132,
1202
1987
  scalars5: 136,
1203
1988
  kuwahara: 140
1204
- }, et = .01, tt = 8, nt = 4, Y = (e) => 1 - e;
1205
- function rt() {
1989
+ }, bt = .01, xt = 8, St = 4, Ct = (e) => 1 - e;
1990
+ function wt() {
1206
1991
  let e = /* @__PURE__ */ new ArrayBuffer(576);
1207
1992
  return {
1208
1993
  buffer: e,
@@ -1211,56 +1996,97 @@ function rt() {
1211
1996
  paletteScratch: new Float32Array(24)
1212
1997
  };
1213
1998
  }
1214
- function it(e, t, n, r) {
1999
+ function Tt(e, t, n, r) {
1215
2000
  let { f32: i, i32: a, paletteScratch: o } = e;
1216
- i[J.scalars0 + 0] = r, i[J.scalars0 + 1] = t.softmaxBeta, i[J.scalars0 + 2] = t.valueVariance, i[J.scalars0 + 3] = t.warpAmount, i[J.scalars1 + 0] = t.warpScale, i[J.scalars1 + 1] = t.warpDrift, i[J.scalars1 + 2] = t.saturation, i[J.scalars1 + 3] = t.paperGrain, i[J.scalars2 + 0] = t.alpha, i[J.scalars2 + 1] = t.nucleiDrift, i[J.scalars2 + 2] = t.paletteDrift, i[J.scalars2 + 3] = t.breathDepth, i[J.scalars3 + 0] = t.breathPeriod, i[J.scalars3 + 1] = n.strength, i[J.scalars3 + 2] = n.radius, i[J.scalars3 + 3] = t.vividness ?? 1, i[J.cursor + 0] = n.x, i[J.cursor + 1] = Y(n.y), i[J.cursor + 2] = 0, i[J.cursor + 3] = 0, a[J.ints0 + 0] = Math.min(t.palette.length, 8);
2001
+ i[q.scalars0 + 0] = r, i[q.scalars0 + 1] = t.softmaxBeta, i[q.scalars0 + 2] = t.valueVariance, i[q.scalars0 + 3] = t.warpAmount, i[q.scalars1 + 0] = t.warpScale, i[q.scalars1 + 1] = t.warpDrift, i[q.scalars1 + 2] = t.saturation, i[q.scalars1 + 3] = t.paperGrain, i[q.scalars2 + 0] = t.alpha, i[q.scalars2 + 1] = t.nucleiDrift, i[q.scalars2 + 2] = t.paletteDrift, i[q.scalars2 + 3] = t.breathDepth, i[q.scalars3 + 0] = t.breathPeriod, i[q.scalars3 + 1] = n.strength, i[q.scalars3 + 2] = n.radius, i[q.scalars3 + 3] = t.vividness ?? 1, i[q.cursor + 0] = n.x, i[q.cursor + 1] = Ct(n.y), i[q.cursor + 2] = t.metalPolish ?? 1, i[q.cursor + 3] = t.metalHeightScale ?? 1, a[q.ints0 + 0] = Math.min(t.palette.length, 8);
1217
2002
  let s = Math.min(t.nuclei.length, 6);
1218
- a[J.ints0 + 1] = s, a[J.ints0 + 2] = H[t.warpMode], a[J.ints0 + 3] = t.noiseOctaves, a[J.ints1 + 0] = z[t.medium], a[J.ints1 + 1] = B[t.huePath ?? "shorter"], a[J.ints1 + 2] = 0, a[J.ints1 + 3] = 0, N(t.palette, 8, o);
2003
+ a[q.ints0 + 1] = s, a[q.ints0 + 2] = H[t.warpMode], a[q.ints0 + 3] = t.noiseOctaves, a[q.ints1 + 0] = z[t.medium], a[q.ints1 + 1] = B[t.huePath ?? "shorter"], a[q.ints1 + 2] = 0, a[q.ints1 + 3] = 0, I(t.palette, 8, o);
1219
2004
  for (let e = 0; e < 8; e++) {
1220
- let t = J.palette + e * 4;
2005
+ let t = q.palette + e * 4;
1221
2006
  i[t + 0] = o[e * 3 + 0], i[t + 1] = o[e * 3 + 1], i[t + 2] = o[e * 3 + 2], i[t + 3] = 0;
1222
2007
  }
1223
2008
  for (let e = 0; e < 6; e++) {
1224
- let n = J.nuc0 + e * 4, r = J.nuc1 + e * 4, a = J.nuc2 + e * 4;
2009
+ let n = q.nuc0 + e * 4, r = q.nuc1 + e * 4, a = q.nuc2 + e * 4;
1225
2010
  if (e < s) {
1226
2011
  let o = t.nuclei[e];
1227
- i[n + 0] = o.x, i[n + 1] = Y(o.y), i[n + 2] = o.radius, i[n + 3] = o.paletteBias, i[r + 0] = o.valueBias, i[r + 1] = o.driftRadius, i[r + 2] = o.driftPhase, i[r + 3] = o.elongation ?? 1, i[a + 0] = -(o.angle ?? 0) * Math.PI / 180, i[a + 1] = 0, i[a + 2] = 0, i[a + 3] = 0;
2012
+ i[n + 0] = o.x, i[n + 1] = Ct(o.y), i[n + 2] = o.radius, i[n + 3] = o.paletteBias, i[r + 0] = o.valueBias, i[r + 1] = o.driftRadius, i[r + 2] = o.driftPhase, i[r + 3] = o.elongation ?? 1, i[a + 0] = -(o.angle ?? 0) * Math.PI / 180, i[a + 1] = 0, i[a + 2] = 0, i[a + 3] = 0;
1228
2013
  } else i[n + 0] = 0, i[n + 1] = 0, i[n + 2] = 0, i[n + 3] = 0, i[r + 0] = 0, i[r + 1] = 0, i[r + 2] = 0, i[r + 3] = 1, i[a + 0] = 0, i[a + 1] = 0, i[a + 2] = 0, i[a + 3] = 0;
1229
2014
  }
1230
- return i[J.scalars4 + 0] = t.strokeAmount, i[J.scalars4 + 1] = t.strokeScale, i[J.scalars4 + 2] = t.strokeAnisotropy, i[J.scalars4 + 3] = t.canvasGrain, i[J.scalars5 + 0] = t.wetEdge, i[J.scalars5 + 1] = t.granulation, i[J.scalars5 + 2] = t.brokenColor, i[J.scalars5 + 3] = t.kuwaharaQ ?? nt, i[J.kuwahara + 0] = t.kuwaharaRadius ?? et, i[J.kuwahara + 1] = tt, i[J.kuwahara + 2] = 0, i[J.kuwahara + 3] = 0, e;
2015
+ return i[q.scalars4 + 0] = t.strokeAmount, i[q.scalars4 + 1] = t.strokeScale, i[q.scalars4 + 2] = t.strokeAnisotropy, i[q.scalars4 + 3] = t.canvasGrain, i[q.scalars5 + 0] = t.wetEdge, i[q.scalars5 + 1] = t.granulation, i[q.scalars5 + 2] = t.brokenColor, i[q.scalars5 + 3] = t.kuwaharaQ ?? St, i[q.kuwahara + 0] = t.kuwaharaRadius ?? bt, i[q.kuwahara + 1] = xt, i[q.kuwahara + 2] = 0, i[q.kuwahara + 3] = 0, e;
2016
+ }
2017
+ var J = {
2018
+ scalars0: 0,
2019
+ scalars1: 4,
2020
+ scalars2: 8,
2021
+ image: 12,
2022
+ cursor: 16,
2023
+ ints: 20,
2024
+ nuc0: 24,
2025
+ nuc1: 48
2026
+ }, Et = (e) => 1 - e;
2027
+ function Dt() {
2028
+ let e = /* @__PURE__ */ new ArrayBuffer(288);
2029
+ return {
2030
+ buffer: e,
2031
+ f32: new Float32Array(e),
2032
+ i32: new Int32Array(e)
2033
+ };
2034
+ }
2035
+ function Ot(e, t, n, r, i) {
2036
+ let { f32: a, i32: o } = e;
2037
+ a[J.scalars0 + 0] = r, a[J.scalars0 + 1] = t.warpAmount, a[J.scalars0 + 2] = t.warpScale, a[J.scalars0 + 3] = t.warpDrift, a[J.scalars1 + 0] = t.softmaxBeta, a[J.scalars1 + 1] = t.nucleiDrift, a[J.scalars1 + 2] = n.strength, a[J.scalars1 + 3] = n.radius, a[J.scalars2 + 0] = t.saturation, a[J.scalars2 + 1] = t.paperGrain, a[J.scalars2 + 2] = t.alpha, a[J.scalars2 + 3] = t.vividness ?? 1, a[J.image + 0] = t.imageBlur?.min ?? .004, a[J.image + 1] = t.imageBlur?.max ?? .06, a[J.image + 2] = i, a[J.image + 3] = 0, a[J.cursor + 0] = n.x, a[J.cursor + 1] = Et(n.y), a[J.cursor + 2] = 0, a[J.cursor + 3] = 0;
2038
+ let s = Math.min(t.nuclei.length, 6);
2039
+ o[J.ints + 0] = s, o[J.ints + 1] = t.noiseOctaves, o[J.ints + 2] = 0, o[J.ints + 3] = 0;
2040
+ for (let e = 0; e < 6; e++) {
2041
+ let n = J.nuc0 + e * 4, r = J.nuc1 + e * 4;
2042
+ if (e < s) {
2043
+ let i = t.nuclei[e];
2044
+ a[n + 0] = i.x, a[n + 1] = Et(i.y), a[n + 2] = i.radius, a[n + 3] = i.valueBias, a[r + 0] = i.driftRadius, a[r + 1] = i.driftPhase, a[r + 2] = i.elongation ?? 1, a[r + 3] = -(i.angle ?? 0) * Math.PI / 180;
2045
+ } else a[n + 0] = 0, a[n + 1] = 0, a[n + 2] = 0, a[n + 3] = 0, a[r + 0] = 0, a[r + 1] = 0, a[r + 2] = 1, a[r + 3] = 0;
2046
+ }
2047
+ return e;
1231
2048
  }
1232
2049
  //#endregion
1233
- //#region src/components/custom/aurora/composables/wgpuSetup.ts
1234
- var at = 64, ot = 8, st = 2;
1235
- function ct(e) {
1236
- let { canvas: t, cursor: n, getConfig: r, getReducedMotion: i, pointerField: a } = e, o = null;
1237
- return function(e, s, c) {
1238
- let l = e.createShaderModule({
2050
+ //#region src/components/aurora/composables/wgpuSetup.ts
2051
+ var kt = 64, At = 8, Y = 2;
2052
+ function jt(e) {
2053
+ let { canvas: t, getCursorScalars: n, getConfig: r, getReducedMotion: i, pointerField: a, getDecodedImage: o, registerImageUploader: s } = e, c = null;
2054
+ return function(e, l, u) {
2055
+ if (r().source === "image") return Mt(e, l, u, {
2056
+ canvas: t,
2057
+ getCursorScalars: n,
2058
+ getConfig: r,
2059
+ getReducedMotion: i,
2060
+ pointerField: a,
2061
+ getDecodedImage: o,
2062
+ registerImageUploader: s
2063
+ });
2064
+ let d = e.createShaderModule({
1239
2065
  label: "[Aurora] aurora.wgsl",
1240
- code: $e
1241
- }), u = e.createBuffer({
2066
+ code: vt
2067
+ }), f = e.createBuffer({
1242
2068
  label: "[Aurora] uniforms",
1243
2069
  size: 576,
1244
- usage: at | ot
1245
- }), d = e.createBindGroupLayout({
2070
+ usage: kt | At
2071
+ }), p = e.createBindGroupLayout({
1246
2072
  label: "[Aurora] bind-group-0",
1247
2073
  entries: [{
1248
2074
  binding: 0,
1249
- visibility: st,
2075
+ visibility: Y,
1250
2076
  buffer: { type: "uniform" }
1251
2077
  }]
1252
- }), p = e.createRenderPipeline({
2078
+ }), m = e.createRenderPipeline({
1253
2079
  label: "[Aurora] pipeline",
1254
- layout: e.createPipelineLayout({ bindGroupLayouts: [d] }),
2080
+ layout: e.createPipelineLayout({ bindGroupLayouts: [p] }),
1255
2081
  vertex: {
1256
- module: l,
2082
+ module: d,
1257
2083
  entryPoint: "vs_main"
1258
2084
  },
1259
2085
  fragment: {
1260
- module: l,
2086
+ module: d,
1261
2087
  entryPoint: "fs_main",
1262
2088
  targets: [{
1263
- format: c,
2089
+ format: u,
1264
2090
  blend: {
1265
2091
  color: {
1266
2092
  srcFactor: "one",
@@ -1276,25 +2102,22 @@ function ct(e) {
1276
2102
  }]
1277
2103
  },
1278
2104
  primitive: { topology: "triangle-list" }
1279
- }), m = e.createBindGroup({
2105
+ }), h = e.createBindGroup({
1280
2106
  label: "[Aurora] bind-group",
1281
- layout: d,
2107
+ layout: p,
1282
2108
  entries: [{
1283
2109
  binding: 0,
1284
- resource: { buffer: u }
2110
+ resource: { buffer: f }
1285
2111
  }]
1286
- }), h = rt();
1287
- function g() {
1288
- let e = f(), n = t.getBoundingClientRect(), r = t.parentElement?.getBoundingClientRect(), i = n.width || r?.width || 1, a = n.height || r?.height || 1, o = Math.max(1, Math.round(i * e)), s = Math.max(1, Math.round(a * e));
1289
- (t.width !== o || t.height !== s) && (t.width = o, t.height = s);
1290
- }
1291
- function _(t) {
1292
- let c = +!i(), l = o === null ? 0 : Math.max(0, (t - o) * 1e3);
1293
- o = t, a.tick(c === 0 ? 0 : l);
1294
- let d = a.acceleration.value, f = a.velocity.value, g = -(d.x * f.x + d.y * f.y);
1295
- g > 0 && c > 0 && (n.burst = Math.min(1, n.burst + g * 6)), K(n, c), it(h, r(), n, t), e.queue.writeBuffer(u, 0, h.buffer);
1296
- let _ = s.getCurrentTexture().createView(), v = e.createCommandEncoder({ label: "[Aurora] frame" }), y = v.beginRenderPass({ colorAttachments: [{
1297
- view: _,
2112
+ }), g = wt();
2113
+ function _(e) {}
2114
+ function v(t) {
2115
+ let o = +!i(), s = c === null ? 0 : Math.max(0, (t - c) * 1e3);
2116
+ c = t, a.tick(o === 0 ? 0 : s);
2117
+ let u = G(a, n(), o);
2118
+ Tt(g, r(), u, t), e.queue.writeBuffer(f, 0, g.buffer);
2119
+ let d = l.getCurrentTexture().createView(), p = e.createCommandEncoder({ label: "[Aurora] frame" }), _ = p.beginRenderPass({ colorAttachments: [{
2120
+ view: d,
1298
2121
  clearValue: {
1299
2122
  r: 0,
1300
2123
  g: 0,
@@ -1304,34 +2127,169 @@ function ct(e) {
1304
2127
  loadOp: "clear",
1305
2128
  storeOp: "store"
1306
2129
  }] });
1307
- y.setPipeline(p), y.setBindGroup(0, m), y.draw(3, 1, 0, 0), y.end(), e.queue.submit([v.finish()]);
2130
+ _.setPipeline(m), _.setBindGroup(0, h), _.draw(3, 1, 0, 0), _.end(), e.queue.submit([p.finish()]);
1308
2131
  }
1309
- function v() {
2132
+ function y() {
1310
2133
  if (i()) return !1;
1311
2134
  let e = r();
1312
- return e.nucleiDrift !== 0 || e.paletteDrift !== 0 || e.breathDepth !== 0 || e.warpDrift !== 0 || e.interactivity?.light && n.burst > .001 ? !0 : q(n);
2135
+ return e.nucleiDrift !== 0 || e.paletteDrift !== 0 || e.breathDepth !== 0 || e.warpDrift !== 0 ? !0 : K(a);
1313
2136
  }
1314
2137
  return {
1315
- frame: _,
1316
- shouldContinue: v,
1317
- resize: g,
2138
+ frame: v,
2139
+ shouldContinue: y,
2140
+ resize: _,
1318
2141
  time: (e) => i() ? 3.7 : e,
1319
2142
  teardown: () => {
1320
- u.destroy();
2143
+ f.destroy();
1321
2144
  }
1322
2145
  };
1323
2146
  };
1324
2147
  }
2148
+ function Mt(e, t, n, r) {
2149
+ let { canvas: i, getCursorScalars: a, getConfig: o, getReducedMotion: s, pointerField: c, getDecodedImage: l, registerImageUploader: u } = r, d = null, f = e.createShaderModule({
2150
+ label: "[Aurora] aurora-image.wgsl",
2151
+ code: yt
2152
+ }), p = e.createBuffer({
2153
+ label: "[Aurora] image uniforms",
2154
+ size: 288,
2155
+ usage: kt | At
2156
+ }), m = e.createSampler({
2157
+ label: "[Aurora] image sampler",
2158
+ magFilter: "linear",
2159
+ minFilter: "linear",
2160
+ addressModeU: "clamp-to-edge",
2161
+ addressModeV: "clamp-to-edge"
2162
+ }), h = e.createBindGroupLayout({
2163
+ label: "[Aurora] image bind-group-0",
2164
+ entries: [
2165
+ {
2166
+ binding: 0,
2167
+ visibility: Y,
2168
+ buffer: { type: "uniform" }
2169
+ },
2170
+ {
2171
+ binding: 1,
2172
+ visibility: Y,
2173
+ texture: {
2174
+ sampleType: "float",
2175
+ viewDimension: "2d"
2176
+ }
2177
+ },
2178
+ {
2179
+ binding: 2,
2180
+ visibility: Y,
2181
+ sampler: { type: "filtering" }
2182
+ }
2183
+ ]
2184
+ }), g = e.createRenderPipeline({
2185
+ label: "[Aurora] image pipeline",
2186
+ layout: e.createPipelineLayout({ bindGroupLayouts: [h] }),
2187
+ vertex: {
2188
+ module: f,
2189
+ entryPoint: "vs_main"
2190
+ },
2191
+ fragment: {
2192
+ module: f,
2193
+ entryPoint: "fs_main",
2194
+ targets: [{
2195
+ format: n,
2196
+ blend: {
2197
+ color: {
2198
+ srcFactor: "one",
2199
+ dstFactor: "one-minus-src-alpha",
2200
+ operation: "add"
2201
+ },
2202
+ alpha: {
2203
+ srcFactor: "one",
2204
+ dstFactor: "one-minus-src-alpha",
2205
+ operation: "add"
2206
+ }
2207
+ }
2208
+ }]
2209
+ },
2210
+ primitive: { topology: "triangle-list" }
2211
+ }), _ = Pe(e, l() ?? Ae()).texture;
2212
+ function v() {
2213
+ return e.createBindGroup({
2214
+ label: "[Aurora] image bind-group",
2215
+ layout: h,
2216
+ entries: [
2217
+ {
2218
+ binding: 0,
2219
+ resource: { buffer: p }
2220
+ },
2221
+ {
2222
+ binding: 1,
2223
+ resource: _.createView()
2224
+ },
2225
+ {
2226
+ binding: 2,
2227
+ resource: m
2228
+ }
2229
+ ]
2230
+ });
2231
+ }
2232
+ let y = v();
2233
+ u((t) => {
2234
+ _.destroy(), _ = Pe(e, t).texture, y = v();
2235
+ });
2236
+ let b = Dt();
2237
+ function x(e) {}
2238
+ function S(n) {
2239
+ let r = +!s(), l = d === null ? 0 : Math.max(0, (n - d) * 1e3);
2240
+ d = n, c.tick(r === 0 ? 0 : l);
2241
+ let u = G(c, a(), r), f = i.height > 0 ? i.width / i.height : 1;
2242
+ Ot(b, o(), u, n, f), e.queue.writeBuffer(p, 0, b.buffer);
2243
+ let m = t.getCurrentTexture().createView(), h = e.createCommandEncoder({ label: "[Aurora] image frame" }), _ = h.beginRenderPass({ colorAttachments: [{
2244
+ view: m,
2245
+ clearValue: {
2246
+ r: 0,
2247
+ g: 0,
2248
+ b: 0,
2249
+ a: 0
2250
+ },
2251
+ loadOp: "clear",
2252
+ storeOp: "store"
2253
+ }] });
2254
+ _.setPipeline(g), _.setBindGroup(0, y), _.draw(3, 1, 0, 0), _.end(), e.queue.submit([h.finish()]);
2255
+ }
2256
+ function C() {
2257
+ if (s()) return !1;
2258
+ let e = o();
2259
+ return e.nucleiDrift !== 0 || e.warpDrift !== 0 || e.paletteDrift !== 0 ? !0 : K(c);
2260
+ }
2261
+ return {
2262
+ frame: S,
2263
+ shouldContinue: C,
2264
+ resize: x,
2265
+ time: (e) => s() ? 3.7 : e,
2266
+ teardown: () => {
2267
+ u(null), _.destroy(), p.destroy();
2268
+ }
2269
+ };
2270
+ }
1325
2271
  //#endregion
1326
- //#region src/components/custom/aurora/composables/runtime.ts
1327
- function lt(e) {
2272
+ //#region src/components/aurora/composables/runtime.ts
2273
+ function Nt(e) {
1328
2274
  return e.mode === "capture" ? !0 : e.initStrategy === "eager";
1329
2275
  }
1330
- function ut(e) {
2276
+ function Pt(e) {
1331
2277
  return typeof e.preserveDrawingBuffer == "boolean" ? e.preserveDrawingBuffer : e.mode === "capture";
1332
2278
  }
1333
- function X(e, n, r = {}) {
1334
- let i = ut(r), a = !r.forceWebGLUnderSoftwareRaster && A(), o = n, s = Xe(), c = t(), l = null, u = a ? {
2279
+ function Ft(e, n, r = {}) {
2280
+ let i = Pt(r), a = !r.forceWebGLUnderSoftwareRaster && N(), o = n, s = t({
2281
+ mass: 1,
2282
+ damping: .9,
2283
+ attractorResponse: .28,
2284
+ leadGain: .08,
2285
+ halfLifeMs: 110
2286
+ }), c = .8, l = .25, u = () => ({
2287
+ strength: c,
2288
+ radius: l
2289
+ }), d = null, f = Fe({
2290
+ wake: () => p.wake(),
2291
+ onError: r.onInitError
2292
+ }), p = a ? {
1335
2293
  arm: () => {},
1336
2294
  suspend: () => {},
1337
2295
  resume: () => {},
@@ -1339,102 +2297,99 @@ function X(e, n, r = {}) {
1339
2297
  renderAt: () => {},
1340
2298
  dispose: () => {},
1341
2299
  reducedMotion: !1
1342
- } : h(e, {
2300
+ } : y(e, {
1343
2301
  mode: r.mode === "capture" ? "capture" : "live",
2302
+ dprPolicy: g,
2303
+ revealBloom: r.revealBloom ?? !1,
1344
2304
  contextAttrs: {
1345
2305
  antialias: !1,
1346
2306
  alpha: !0,
1347
2307
  premultipliedAlpha: !0,
1348
2308
  preserveDrawingBuffer: i
1349
2309
  },
1350
- setupWGPU: ct({
2310
+ setupWGPU: jt({
1351
2311
  canvas: e,
1352
- cursor: s,
2312
+ getCursorScalars: u,
1353
2313
  getConfig: () => o,
1354
- getReducedMotion: () => u.reducedMotion,
1355
- pointerField: c
2314
+ getReducedMotion: () => p.reducedMotion,
2315
+ pointerField: s,
2316
+ getDecodedImage: () => f.getDecodedImage(),
2317
+ registerImageUploader: (e) => f.setImageUploader(e)
1356
2318
  }),
1357
2319
  setupGL: (t) => {
1358
- let { program: n, vs: r, fs: i, uniforms: a, geometry: d } = Ae(t, ye, Oe);
1359
- function p() {
1360
- let r = f(), i = e.getBoundingClientRect(), a = e.parentElement?.getBoundingClientRect(), o = i.width || a?.width || 1, s = i.height || a?.height || 1, c = Math.max(1, Math.round(o * r)), l = Math.max(1, Math.round(s * r));
1361
- (e.width !== c || e.height !== l) && (e.width = c, e.height = l), t.viewport(0, 0, c, l), t.useProgram(n);
2320
+ let n = o.source === "image", { program: r, vs: i, fs: a, uniforms: c, geometry: l } = ze(t, he, n ? De : Ee), m = n ? Ie(t, r, f) : null;
2321
+ function h(n) {
2322
+ t.viewport(0, 0, n?.w ?? e.width, n?.h ?? e.height), t.useProgram(r);
1362
2323
  }
1363
- let m = Ke(t, n, a, s), h = Qe({
2324
+ let g = ht(t, r, c), _ = _t({
1364
2325
  gl: t,
1365
- prog: n,
1366
- uniforms: a,
1367
- cursor: s,
2326
+ prog: r,
2327
+ uniforms: c,
2328
+ pointerField: s,
2329
+ getCursorScalars: u,
1368
2330
  getConfig: () => o,
1369
- getReducedMotion: () => u.reducedMotion,
1370
- pointerField: c
2331
+ getReducedMotion: () => p.reducedMotion
1371
2332
  });
1372
- return t.clearColor(0, 0, 0, 0), t.disable(t.DEPTH_TEST), t.enable(t.BLEND), t.blendFunc(t.ONE, t.ONE_MINUS_SRC_ALPHA), l = (e) => {
1373
- o = e, m(e);
1374
- }, l(o), requestAnimationFrame(() => {
1375
- p(), requestAnimationFrame(p);
1376
- }), {
1377
- frame: h.frame,
1378
- shouldContinue: h.needsAnimation,
1379
- resize: p,
1380
- time: (e) => u.reducedMotion ? 3.7 : e,
2333
+ return t.clearColor(0, 0, 0, 0), t.disable(t.DEPTH_TEST), t.enable(t.BLEND), t.blendFunc(t.ONE, t.ONE_MINUS_SRC_ALPHA), d = (e) => {
2334
+ o = e, g(e);
2335
+ }, d(o), {
2336
+ frame: _.frame,
2337
+ shouldContinue: _.needsAnimation,
2338
+ resize: h,
2339
+ time: (e) => p.reducedMotion ? 3.7 : e,
1381
2340
  teardown: () => {
1382
- t.deleteProgram(n), t.deleteShader(r), t.deleteShader(i), t.deleteBuffer(d.buf), t.deleteVertexArray(d.vao);
2341
+ t.deleteProgram(r), t.deleteShader(i), t.deleteShader(a), t.deleteBuffer(l.buf), t.deleteVertexArray(l.vao), m?.();
1383
2342
  }
1384
2343
  };
1385
2344
  }
1386
2345
  });
1387
- function d(e, t, n = .8) {
1388
- s.targetX = e, s.targetY = t, s.targetStrength = n, c.setPointer(e, t), u.wake();
2346
+ function m(e, t, n = .8) {
2347
+ c = n, s.setActive(!0), s.setPointer(e, t), p.wake();
1389
2348
  }
1390
- function p(e, t) {
1391
- u.reducedMotion || (Ze(s, e, t), u.wake());
1392
- }
1393
- function m() {
1394
- s.targetStrength = 0, u.wake();
1395
- }
1396
- function g(e) {
1397
- s.radius = e, u.wake();
2349
+ function h() {
2350
+ s.setActive(!1), p.wake();
1398
2351
  }
1399
2352
  function _(e) {
1400
- u.wake();
2353
+ l = e, p.wake();
1401
2354
  }
1402
- function v() {
1403
- u.armAsync ? u.armAsync().catch((e) => {
2355
+ function v(e) {
2356
+ p.wake();
2357
+ }
2358
+ function b() {
2359
+ p.armAsync ? p.armAsync().catch((e) => {
1404
2360
  r.onInitError?.(e instanceof Error ? e : Error(String(e)));
1405
- }) : u.arm();
2361
+ }) : p.arm();
1406
2362
  }
1407
- function y() {
1408
- return u.armAsync ? u.armAsync() : (u.arm(), Promise.resolve());
2363
+ function x() {
2364
+ return p.armAsync ? p.armAsync() : (p.arm(), Promise.resolve());
1409
2365
  }
1410
- return r.mode !== "capture" && lt(r) && v(), {
1411
- arm: () => v(),
1412
- armAsync: () => y(),
2366
+ return f.ensureDecoded(o), r.mode !== "capture" && Nt(r) && b(), {
2367
+ arm: () => b(),
2368
+ armAsync: () => x(),
1413
2369
  update: (e) => {
1414
- o = e, l?.(e), u.wake();
2370
+ o = e, d?.(e), f.ensureDecoded(e), p.wake();
1415
2371
  },
1416
- setCursor: d,
1417
- clearCursor: m,
1418
- setCursorRadius: g,
1419
- setReducedMotion: _,
1420
- injectCursorVelocity: p,
2372
+ setCursor: m,
2373
+ clearCursor: h,
2374
+ setCursorRadius: _,
2375
+ setReducedMotion: v,
1421
2376
  get reducedMotion() {
1422
- return u.reducedMotion;
2377
+ return p.reducedMotion;
1423
2378
  },
1424
- pause: (e = "manual") => u.suspend(e),
1425
- resume: (e = "manual") => u.resume(e),
1426
- renderAt: (e) => u.renderAt(e),
1427
- dispose: () => u.dispose()
2379
+ pause: (e = "manual") => p.suspend(e),
2380
+ resume: (e = "manual") => p.resume(e),
2381
+ renderAt: (e) => p.renderAt(e),
2382
+ dispose: () => p.dispose()
1428
2383
  };
1429
2384
  }
1430
2385
  //#endregion
1431
- //#region src/components/custom/aurora/composables/configSource.ts
1432
- function dt(e) {
2386
+ //#region src/components/aurora/composables/configSource.ts
2387
+ function It(e) {
1433
2388
  return typeof e == "function" ? e : e && typeof e == "object" && "value" in e ? () => e.value : () => e;
1434
2389
  }
1435
2390
  //#endregion
1436
- //#region src/components/custom/aurora/composables/useAurora.ts
1437
- function ft(e) {
2391
+ //#region src/components/aurora/composables/useAurora.ts
2392
+ function Lt(e) {
1438
2393
  if (typeof window > "u") return () => {};
1439
2394
  if (typeof window.requestIdleCallback == "function") {
1440
2395
  let t = window.requestIdleCallback(() => e(), { timeout: 2e3 });
@@ -1451,12 +2406,12 @@ function ft(e) {
1451
2406
  r = !0, cancelAnimationFrame(t), n !== void 0 && clearTimeout(n);
1452
2407
  };
1453
2408
  }
1454
- function pt(e, t, n = {}, r = {}) {
1455
- let i = dt(t), a = r.renderMode === "css", o = null, s = null, c = null, l = null, u = null, d = null, f = null, p = !1, m = E(!1), h = n.mode === "capture" || n.initStrategy === "eager";
1456
- function g() {
1457
- f && o && o.setReducedMotion(f.matches);
2409
+ function Rt(e, t, n = {}, r = {}) {
2410
+ let o = It(t), s = r.renderMode === "css", c = null, l = null, u = null, d = null, f = null, p = null, m = null, h = !1, g = O(!1), _ = n.mode === "capture" || n.initStrategy === "eager";
2411
+ function v() {
2412
+ m && c && c.setReducedMotion(m.matches);
1458
2413
  }
1459
- function _(e) {
2414
+ function y(e) {
1460
2415
  let t = e instanceof Error ? e : Error(String(e));
1461
2416
  if (n.onInitError) {
1462
2417
  n.onInitError(t);
@@ -1464,69 +2419,68 @@ function pt(e, t, n = {}, r = {}) {
1464
2419
  }
1465
2420
  Promise.reject(t);
1466
2421
  }
1467
- function v() {
1468
- if (!(p || !o)) {
1469
- p = !0;
2422
+ function b() {
2423
+ if (!(h || !c)) {
2424
+ h = !0;
1470
2425
  try {
1471
- o.arm();
2426
+ c.arm();
1472
2427
  } catch (e) {
1473
- _(e);
2428
+ y(e);
1474
2429
  return;
1475
2430
  }
1476
- m.value = !0, f = window.matchMedia("(prefers-reduced-motion: reduce)"), f.addEventListener("change", g), s = O(i, (e) => o?.update(e), { deep: !0 }), i().interactivity?.scroll && e.value && (l = O(oe({
2431
+ g.value = !0, c.update(o()), m = window.matchMedia("(prefers-reduced-motion: reduce)"), m.addEventListener("change", v), l = A(o, (e) => c?.update(e), { deep: !0 }), o().interactivity?.scroll && e.value && (d = A(i({
1477
2432
  target: e,
1478
2433
  trackExit: !0
1479
2434
  }), (e) => {
1480
- !o || o.reducedMotion || o.setCursorRadius(.2 + e * .25);
2435
+ !c || c.reducedMotion || c.setCursorRadius(.2 + e * .25);
1481
2436
  }));
1482
2437
  }
1483
2438
  }
1484
- return pe(() => {
2439
+ return se(() => {
1485
2440
  let t = e.value;
1486
- if (!t || a) return;
2441
+ if (!t || s) return;
1487
2442
  try {
1488
- o = X(t, i(), {
2443
+ c = Ft(t, o(), {
1489
2444
  initStrategy: "deferred",
1490
2445
  ...n
1491
2446
  });
1492
2447
  } catch (e) {
1493
- _(e);
2448
+ y(e);
1494
2449
  return;
1495
2450
  }
1496
- if (h) {
1497
- v();
2451
+ if (_) {
2452
+ b();
1498
2453
  return;
1499
2454
  }
1500
- d = ae(e, {
1501
- pause: () => o?.pause("off-screen"),
1502
- resume: () => o?.resume("off-screen")
2455
+ p = a(e, {
2456
+ pause: () => c?.pause("off-screen"),
2457
+ resume: () => c?.resume("off-screen")
1503
2458
  }, { pauseWhenHidden: !1 });
1504
- let r = d.isIntersecting;
1505
- c = O(r, (e) => {
1506
- !e || p || u || (u = ft(() => {
1507
- u = null, r.value && v();
2459
+ let r = p.isIntersecting;
2460
+ u = A(r, (e) => {
2461
+ !e || h || f || (f = Lt(() => {
2462
+ f = null, r.value && b();
1508
2463
  }));
1509
2464
  }, { immediate: !0 });
1510
- }), fe(() => {
1511
- u?.(), c?.(), s?.(), l?.(), d?.dispose(), f?.removeEventListener("change", g), o?.dispose(), o = null;
2465
+ }), oe(() => {
2466
+ f?.(), u?.(), l?.(), d?.(), p?.dispose(), m?.removeEventListener("change", v), c?.dispose(), c = null;
1512
2467
  }), {
1513
- setCursor: (e, t, n) => o?.setCursor(e, t, n),
1514
- clearCursor: () => o?.clearCursor(),
1515
- setCursorRadius: (e) => o?.setCursorRadius(e),
1516
- injectCursorVelocity: (e, t) => o?.injectCursorVelocity(e, t),
1517
- renderAt: (e) => o?.renderAt(e),
1518
- pause: () => o?.pause(),
1519
- resume: () => o?.resume(),
1520
- isArmed: he(m)
2468
+ setCursor: (e, t, n) => c?.setCursor(e, t, n),
2469
+ clearCursor: () => c?.clearCursor(),
2470
+ setCursorRadius: (e) => c?.setCursorRadius(e),
2471
+ renderAt: (e) => c?.renderAt(e),
2472
+ pause: () => c?.pause(),
2473
+ resume: () => c?.resume(),
2474
+ isArmed: le(g)
1521
2475
  };
1522
2476
  }
1523
2477
  //#endregion
1524
- //#region src/components/custom/aurora/composables/auroraFallbackGround.ts
1525
- function Z(e) {
2478
+ //#region src/components/aurora/composables/auroraFallbackGround.ts
2479
+ function X(e) {
1526
2480
  let t = Math.max(0, Math.min(1, e));
1527
2481
  return t <= .0031308 ? t * 12.92 : 1.055 * t ** (1 / 2.4) - .055;
1528
2482
  }
1529
- function mt([e, t, n]) {
2483
+ function zt([e, t, n]) {
1530
2484
  let r = .76, i = Math.min(e, Math.min(t, n)), a = i < .08 ? i - 6.25 * i * i : .04, o = e - a, s = t - a, c = n - a, l = Math.max(o, Math.max(s, c)), u = (e) => Math.max(0, Math.min(1, e));
1531
2485
  if (l < r) return [
1532
2486
  u(o),
@@ -1542,10 +2496,10 @@ function mt([e, t, n]) {
1542
2496
  u(c + (f - c) * m)
1543
2497
  ];
1544
2498
  }
1545
- function ht([e, t, n]) {
2499
+ function Bt([e, t, n]) {
1546
2500
  return .2126 * e + .7152 * t + .0722 * n;
1547
2501
  }
1548
- function gt(e, t) {
2502
+ function Vt(e, t) {
1549
2503
  let n = e.length;
1550
2504
  if (n === 0) return [
1551
2505
  0,
@@ -1560,7 +2514,7 @@ function gt(e, t) {
1560
2514
  s[2] + (c[2] - s[2]) * o
1561
2515
  ];
1562
2516
  }
1563
- function _t(e, t, n, r) {
2517
+ function Z(e, t, n, r) {
1564
2518
  let i = 0, a = 0, o = 0;
1565
2519
  for (let s of e) {
1566
2520
  let e = n - s.x, c = r - s.y, l = (s.angle ?? 0) * Math.PI / 180, u = Math.cos(l), d = Math.sin(l), f = u * e + d * c, p = -d * e + u * c, m = f / Math.max(s.elongation ?? 1, .01), h = p, g = m * m + h * h, _ = Math.max(s.radius, .01), v = Math.exp(-t * g / (_ * _));
@@ -1572,33 +2526,33 @@ function _t(e, t, n, r) {
1572
2526
  valueMod: a / s
1573
2527
  };
1574
2528
  }
1575
- function vt(e, t, n) {
1576
- let r = e.palette.map((e) => x(e)), { paletteId: i, valueMod: a } = _t(e.nuclei, e.softmaxBeta, t, n), o = gt(r, i), s = 1 + e.valueVariance * a, c = [
2529
+ function Ht(e, t, n) {
2530
+ let r = e.palette.map((e) => C(e)), { paletteId: i, valueMod: a } = Z(e.nuclei, e.softmaxBeta, t, n), o = Vt(r, i), s = 1 + e.valueVariance * a, c = [
1577
2531
  o[0] * s,
1578
2532
  o[1] * s,
1579
2533
  o[2] * s
1580
2534
  ];
1581
- return c = mt(c), c = [
2535
+ return c = zt(c), c = [
1582
2536
  Math.max(0, Math.min(1, c[0] * .985 + .008)),
1583
2537
  Math.max(0, Math.min(1, c[1] * .985 + .008)),
1584
2538
  Math.max(0, Math.min(1, c[2] * .985 + .008))
1585
2539
  ], [
1586
- Z(c[0]),
1587
- Z(c[1]),
1588
- Z(c[2])
2540
+ X(c[0]),
2541
+ X(c[1]),
2542
+ X(c[2])
1589
2543
  ];
1590
2544
  }
1591
- function yt([e, t, n]) {
2545
+ function Ut([e, t, n]) {
1592
2546
  let r = (e) => Math.round(Math.max(0, Math.min(1, e)) * 255);
1593
2547
  return `rgb(${r(e)}, ${r(t)}, ${r(n)})`;
1594
2548
  }
1595
- function bt(e) {
1596
- return ht(e.map((e) => {
2549
+ function Wt(e) {
2550
+ return Bt(e.map((e) => {
1597
2551
  let t = Math.max(0, Math.min(1, e));
1598
2552
  return t <= .04045 ? t / 12.92 : ((t + .055) / 1.055) ** 2.4;
1599
2553
  }));
1600
2554
  }
1601
- function xt(e, t = {}) {
2555
+ function Gt(e, t = {}) {
1602
2556
  let n = Math.max(2, Math.min(16, Math.round(t.grid ?? 8))), r = [], i = 0, a = [
1603
2557
  0,
1604
2558
  0,
@@ -1611,13 +2565,13 @@ function xt(e, t = {}) {
1611
2565
  0
1612
2566
  ];
1613
2567
  for (let t = 0; t < n; t++) for (let s = 0; s < n; s++) {
1614
- let c = (s + .5) / n, l = (t + .5) / n, u = vt(e, c, l);
2568
+ let c = (s + .5) / n, l = (t + .5) / n, u = Ht(e, c, l);
1615
2569
  r.push({
1616
2570
  x: c,
1617
2571
  y: l,
1618
2572
  color: u
1619
2573
  });
1620
- let d = bt(u);
2574
+ let d = Wt(u);
1621
2575
  i += d;
1622
2576
  let f = (l < .5 ? 0 : 2) + (c < .5 ? 0 : 1);
1623
2577
  a[f] += d, o[f] += 1;
@@ -1634,10 +2588,10 @@ function xt(e, t = {}) {
1634
2588
  ];
1635
2589
  for (let e of r) l[0] += e.color[0], l[1] += e.color[1], l[2] += e.color[2];
1636
2590
  l[0] /= r.length, l[1] /= r.length, l[2] /= r.length;
1637
- let u = St(r, n);
2591
+ let u = Kt(r, n);
1638
2592
  if (u) return {
1639
2593
  backgroundImage: `url("${u}")`,
1640
- backgroundColor: yt(l),
2594
+ backgroundColor: Ut(l),
1641
2595
  metrics: {
1642
2596
  mean: s,
1643
2597
  quadrants: c
@@ -1649,14 +2603,14 @@ function xt(e, t = {}) {
1649
2603
  let t = (e.x * 100).toFixed(2), n = (e.y * 100).toFixed(2), r = (e) => Math.round(Math.max(0, Math.min(1, e)) * 255), [i, a, o] = e.color, s = `rgba(${r(i)}, ${r(a)}, ${r(o)}, 0.7)`, c = `rgba(${r(i)}, ${r(a)}, ${r(o)}, 0)`;
1650
2604
  return `radial-gradient(circle ${d.toFixed(2)}% at ${t}% ${n}%, ${s} 0%, ${c} 100%)`;
1651
2605
  }).join(", "),
1652
- backgroundColor: yt(l),
2606
+ backgroundColor: Ut(l),
1653
2607
  metrics: {
1654
2608
  mean: s,
1655
2609
  quadrants: c
1656
2610
  }
1657
2611
  };
1658
2612
  }
1659
- function St(e, t) {
2613
+ function Kt(e, t) {
1660
2614
  if (typeof document > "u") return null;
1661
2615
  let n;
1662
2616
  try {
@@ -1680,124 +2634,123 @@ function St(e, t) {
1680
2634
  }
1681
2635
  }
1682
2636
  //#endregion
1683
- //#region src/components/custom/aurora/Aurora.vue?vue&type=script&setup=true&lang.ts
1684
- var Ct = ["data-aurora-substrate"], wt = /* @__PURE__ */ e(/* @__PURE__ */ le({
2637
+ //#region src/components/aurora/Aurora.vue?vue&type=script&setup=true&lang.ts
2638
+ var qt = ["data-aurora-substrate"], Jt = /* @__PURE__ */ e(/* @__PURE__ */ re({
1685
2639
  __name: "Aurora",
1686
2640
  props: {
1687
- config: { default: () => b },
2641
+ config: { default: () => F },
1688
2642
  runtimeOptions: {},
1689
2643
  onInitError: {},
1690
2644
  renderMode: { default: "auto" },
1691
2645
  opacityCeiling: { default: 1 }
1692
2646
  },
1693
2647
  setup(e, { expose: t }) {
1694
- let n = e, r = j(n.renderMode, { forceWebGLUnderSoftwareRaster: n.runtimeOptions?.forceWebGLUnderSoftwareRaster ?? !1 }), i = T(() => Math.max(0, Math.min(1, n.opacityCeiling))), a = E(null), o = pt(a, () => n.config, T(() => ({
2648
+ let n = e, r = Le(n.renderMode, { forceWebGLUnderSoftwareRaster: n.runtimeOptions?.forceWebGLUnderSoftwareRaster ?? !1 }), i = D(() => Math.max(0, Math.min(1, n.opacityCeiling))), a = O(null), o = Rt(a, () => n.config, D(() => ({
1695
2649
  ...n.runtimeOptions ?? {},
1696
2650
  ...n.onInitError ? { onInitError: n.onInitError } : {}
1697
- })).value, { renderMode: r }), s = T(() => r === "css"), c = T(() => xt(n.config)), l = T(() => s.value ? c.value.backgroundImage : P(n.config.palette)), u = T(() => s.value ? c.value.backgroundColor : "transparent");
2651
+ })).value, { renderMode: r }), s = D(() => Gt(n.config)), c = D(() => s.value.backgroundImage), l = D(() => s.value.backgroundColor);
1698
2652
  return t({
1699
2653
  config: n.config,
1700
2654
  canvasRef: a,
1701
2655
  setCursor: o.setCursor,
1702
2656
  clearCursor: o.clearCursor,
1703
2657
  setCursorRadius: o.setCursorRadius,
1704
- injectCursorVelocity: o.injectCursorVelocity,
1705
2658
  renderAt: o.renderAt,
1706
2659
  pause: o.pause,
1707
2660
  resume: o.resume,
1708
2661
  isArmed: o.isArmed
1709
- }), (e, t) => (me(), se("div", {
2662
+ }), (e, t) => (ce(), te("div", {
1710
2663
  class: "aurora-root block h-full w-full overflow-hidden",
1711
- "data-aurora-substrate": D(r),
1712
- style: de({ "--aurora-opacity-ceiling": i.value })
1713
- }, [ce("div", {
2664
+ "data-aurora-substrate": k(r),
2665
+ style: ae({ "--aurora-opacity-ceiling": i.value })
2666
+ }, [ne("div", {
1714
2667
  class: "aurora-placeholder h-full w-full",
1715
2668
  "aria-hidden": "true",
1716
- style: de({
1717
- backgroundImage: l.value,
1718
- backgroundColor: u.value
2669
+ style: ae({
2670
+ backgroundImage: c.value,
2671
+ backgroundColor: l.value
1719
2672
  })
1720
- }, null, 4), ce("canvas", {
2673
+ }, null, 4), ne("canvas", {
1721
2674
  ref_key: "canvasRef",
1722
2675
  ref: a,
1723
2676
  "aria-hidden": "true",
1724
- class: ue(["aurora-canvas block h-full w-full", { "aurora-canvas--armed": D(o).isArmed.value }])
1725
- }, null, 2)], 12, Ct));
2677
+ class: ie(["aurora-canvas block h-full w-full", { "aurora-canvas--armed": k(o).isArmed.value }])
2678
+ }, null, 2)], 12, qt));
1726
2679
  }
1727
- }), [["__scopeId", "data-v-3eae1d97"]]);
2680
+ }), [["__scopeId", "data-v-3cc40d85"]]);
1728
2681
  //#endregion
1729
- //#region src/components/custom/aurora/composables/useCursorInteraction.ts
1730
- function Tt(e, t, n) {
1731
- let r = dt(t), i = n.hitFraction ?? .35, a = null, o = null, s = null, c = null;
1732
- function l(e, t) {
2682
+ //#region src/components/aurora/composables/useCursorInteraction.ts
2683
+ function Yt(e, t, n) {
2684
+ let r = It(t), i = n.hitFraction ?? .35, a = null, o = null;
2685
+ function s(e, t) {
1733
2686
  let n = t.getBoundingClientRect();
1734
2687
  return {
1735
2688
  x: (e.clientX - n.left) / Math.max(n.width, 1),
1736
2689
  y: (e.clientY - n.top) / Math.max(n.height, 1)
1737
2690
  };
1738
2691
  }
1739
- function u(e, t, n) {
2692
+ function c(e, t, n) {
1740
2693
  let r = t - e.x, i = n - e.y, a = (e.angle ?? 0) * Math.PI / 180, o = Math.cos(a), s = Math.sin(a), c = o * r + s * i, l = -s * r + o * i, u = c / Math.max(e.elongation ?? 1, .01), d = l;
1741
2694
  return u * u + d * d;
1742
2695
  }
1743
- function d(e, t) {
2696
+ function l(e, t) {
1744
2697
  let n = null, a = Infinity;
1745
2698
  for (let o = 0; o < r().nuclei.length; o++) {
1746
- let s = r().nuclei[o], c = u(s, e, t), l = s.radius * i;
1747
- c < l * l && c < a && (a = c, n = o);
2699
+ let s = r().nuclei[o], l = c(s, e, t), u = s.radius * i;
2700
+ l < u * u && l < a && (a = l, n = o);
1748
2701
  }
1749
2702
  return n;
1750
2703
  }
1751
- function f(e, t) {
2704
+ function u(e, t) {
1752
2705
  let n = 0, i = 0;
1753
2706
  for (let a of r().nuclei) {
1754
- let o = u(a, e, t), s = Math.max(a.radius, .01), c = Math.exp(-r().softmaxBeta * o / (s * s));
1755
- n += c * a.paletteBias, i += c;
2707
+ let o = c(a, e, t), s = Math.max(a.radius, .01), l = Math.exp(-r().softmaxBeta * o / (s * s));
2708
+ n += l * a.paletteBias, i += l;
1756
2709
  }
1757
2710
  return i > 1e-4 ? n / i : .5;
1758
2711
  }
1759
- function p() {
2712
+ function d() {
1760
2713
  if (r().nuclei.length === 0) return .5;
1761
2714
  let e = r().nuclei.map((e) => e.radius).sort((e, t) => e - t);
1762
2715
  return e[Math.floor(e.length / 2)];
1763
2716
  }
1764
- function m(e, t) {
2717
+ function f(e, t) {
1765
2718
  return {
1766
2719
  x: e,
1767
2720
  y: t,
1768
- radius: p(),
1769
- paletteBias: f(e, t),
2721
+ radius: d(),
2722
+ paletteBias: u(e, t),
1770
2723
  valueBias: 0,
1771
2724
  driftRadius: .012,
1772
2725
  driftPhase: Math.random() * Math.PI * 2
1773
2726
  };
1774
2727
  }
1775
- function h(t) {
2728
+ function p(t) {
1776
2729
  let i = e.value;
1777
2730
  if (!i) return;
1778
- let { x: o, y: u } = l(t, i);
1779
- a !== null && (r().nuclei[a].x = Math.max(0, Math.min(1, o)), r().nuclei[a].y = Math.max(0, Math.min(1, u))), n.setCursor(o, u, 1), n.injectVelocity && s !== null && c !== null && n.injectVelocity(o - s, u - c), s = o, c = u;
2731
+ let { x: o, y: c } = s(t, i);
2732
+ a !== null && (r().nuclei[a].x = Math.max(0, Math.min(1, o)), r().nuclei[a].y = Math.max(0, Math.min(1, c))), n.setCursor(o, c, 1);
1780
2733
  }
1781
- function g() {
1782
- s = null, c = null, a === null && n.clearCursor();
2734
+ function m() {
2735
+ a === null && n.clearCursor();
1783
2736
  }
1784
- function _(t) {
2737
+ function h(t) {
1785
2738
  let n = e.value;
1786
2739
  if (!n) return;
1787
- let { x: i, y: s } = l(t, n), c = d(i, s);
1788
- if (t.altKey && c === null) {
2740
+ let { x: i, y: c } = s(t, n), u = l(i, c);
2741
+ if (t.altKey && u === null) {
1789
2742
  if (r().nuclei.length >= 6) return;
1790
- r().nuclei.push(m(i, s)), t.preventDefault();
2743
+ r().nuclei.push(f(i, c)), t.preventDefault();
1791
2744
  return;
1792
2745
  }
1793
- if ((t.shiftKey || t.button === 2) && c !== null) {
2746
+ if ((t.shiftKey || t.button === 2) && u !== null) {
1794
2747
  if (r().nuclei.length <= 1) return;
1795
- r().nuclei.splice(c, 1), t.preventDefault();
2748
+ r().nuclei.splice(u, 1), t.preventDefault();
1796
2749
  return;
1797
2750
  }
1798
- c !== null && t.button === 0 && (a = c, o = t.pointerId, n.setPointerCapture(t.pointerId), t.preventDefault());
2751
+ u !== null && t.button === 0 && (a = u, o = t.pointerId, n.setPointerCapture(t.pointerId), t.preventDefault());
1799
2752
  }
1800
- function v(t) {
2753
+ function g(t) {
1801
2754
  let n = e.value;
1802
2755
  if (n && o !== null && t.pointerId === o) {
1803
2756
  try {
@@ -1806,25 +2759,25 @@ function Tt(e, t, n) {
1806
2759
  o = null, a = null;
1807
2760
  }
1808
2761
  }
1809
- function y(t) {
2762
+ function _(t) {
1810
2763
  let n = e.value;
1811
2764
  if (!n) return;
1812
2765
  let i = {
1813
2766
  clientX: t.clientX,
1814
2767
  clientY: t.clientY
1815
- }, a = n.getBoundingClientRect(), o = d((i.clientX - a.left) / Math.max(a.width, 1), (i.clientY - a.top) / Math.max(a.height, 1));
2768
+ }, a = n.getBoundingClientRect(), o = l((i.clientX - a.left) / Math.max(a.width, 1), (i.clientY - a.top) / Math.max(a.height, 1));
1816
2769
  o !== null && r().nuclei.length > 1 && (r().nuclei.splice(o, 1), t.preventDefault());
1817
2770
  }
1818
- return pe(() => {
2771
+ return se(() => {
1819
2772
  let t = e.value;
1820
- t && (t.addEventListener("pointermove", h), t.addEventListener("pointerleave", g), t.addEventListener("pointerdown", _), t.addEventListener("pointerup", v), t.addEventListener("pointercancel", v), t.addEventListener("contextmenu", y));
1821
- }), fe(() => {
2773
+ t && (t.addEventListener("pointermove", p), t.addEventListener("pointerleave", m), t.addEventListener("pointerdown", h), t.addEventListener("pointerup", g), t.addEventListener("pointercancel", g), t.addEventListener("contextmenu", _));
2774
+ }), oe(() => {
1822
2775
  let t = e.value;
1823
- t && (t.removeEventListener("pointermove", h), t.removeEventListener("pointerleave", g), t.removeEventListener("pointerdown", _), t.removeEventListener("pointerup", v), t.removeEventListener("pointercancel", v), t.removeEventListener("contextmenu", y));
2776
+ t && (t.removeEventListener("pointermove", p), t.removeEventListener("pointerleave", m), t.removeEventListener("pointerdown", h), t.removeEventListener("pointerup", g), t.removeEventListener("pointercancel", g), t.removeEventListener("contextmenu", _));
1824
2777
  }), { isDragging: () => a };
1825
2778
  }
1826
2779
  //#endregion
1827
- //#region src/components/custom/aurora/composables/atoms-fields.ts
2780
+ //#region src/components/aurora/composables/atoms-fields.ts
1828
2781
  function Q(e, t, n) {
1829
2782
  return e + (t - e) * n;
1830
2783
  }
@@ -1844,8 +2797,12 @@ var $ = {
1844
2797
  temperatureShift: {
1845
2798
  calm: .15,
1846
2799
  vivid: .5
2800
+ },
2801
+ hueSpread: {
2802
+ calm: 16,
2803
+ vivid: 44
1847
2804
  }
1848
- }, Et = {
2805
+ }, Xt = {
1849
2806
  still: {
1850
2807
  nucleiDrift: 0,
1851
2808
  paletteDrift: 0,
@@ -1865,8 +2822,8 @@ var $ = {
1865
2822
  breathDepth: .05
1866
2823
  }
1867
2824
  };
1868
- function Dt(e, t, n) {
1869
- let r = m(n, 0, 1);
2825
+ function Zt(e, t, n) {
2826
+ let r = v(n, 0, 1);
1870
2827
  switch (t) {
1871
2828
  case "watercolor":
1872
2829
  e.wetEdge = r, e.granulation = r * .8;
@@ -1883,29 +2840,35 @@ function Dt(e, t, n) {
1883
2840
  case "kuwahara":
1884
2841
  e.strokeAmount = r, e.canvasGrain = r * .05;
1885
2842
  break;
2843
+ case "metal":
2844
+ case "metal-gradient":
2845
+ e.metalPolish = r * 4;
2846
+ break;
1886
2847
  }
1887
2848
  }
1888
- function Ot(e, t) {
2849
+ function Qt(e, t) {
1889
2850
  switch (t) {
1890
- case "watercolor": return m(e.wetEdge, 0, 1);
2851
+ case "watercolor": return v(e.wetEdge, 0, 1);
1891
2852
  case "oil":
1892
2853
  case "vangogh":
1893
2854
  case "pastel":
1894
2855
  case "oil-pastel":
1895
2856
  case "crayon":
1896
- case "kuwahara": return m(e.strokeAmount, 0, 1);
2857
+ case "kuwahara": return v(e.strokeAmount, 0, 1);
2858
+ case "metal":
2859
+ case "metal-gradient": return v((e.metalPolish ?? 1) / 4, 0, 1);
1897
2860
  }
1898
2861
  }
1899
- function kt(e) {
2862
+ function $t(e) {
1900
2863
  return e.nucleiDrift + e.paletteDrift + e.warpDrift > .001 ? "drifting" : e.breathDepth > .001 ? "breathing" : "still";
1901
2864
  }
1902
- function At(e, t, n) {
1903
- return n === t ? 0 : m((e - t) / (n - t), 0, 1);
2865
+ function en(e, t, n) {
2866
+ return n === t ? 0 : v((e - t) / (n - t), 0, 1);
1904
2867
  }
1905
2868
  //#endregion
1906
- //#region src/components/custom/aurora/composables/atoms.ts
1907
- var jt = {}, Mt = .61803398875;
1908
- function Nt(e, t = "composed") {
2869
+ //#region src/components/aurora/composables/atoms.ts
2870
+ var tn = {}, nn = .61803398875;
2871
+ function rn(e, t = "composed") {
1909
2872
  let n = Math.max(1, Math.min(6, Math.round(e))), r = [
1910
2873
  [.33, .33],
1911
2874
  [.67, .67],
@@ -1916,8 +2879,8 @@ function Nt(e, t = "composed") {
1916
2879
  ], i = (e) => {
1917
2880
  switch (t) {
1918
2881
  case "scattered": {
1919
- let t = e * Mt * Math.PI * 2, r = .12 + .3 * Math.sqrt((e + .5) / n);
1920
- return [m(.5 + r * Math.cos(t), .1, .9), m(.5 + r * Math.sin(t), .1, .9)];
2882
+ let t = e * nn * Math.PI * 2, r = .12 + .3 * Math.sqrt((e + .5) / n);
2883
+ return [v(.5 + r * Math.cos(t), .1, .9), v(.5 + r * Math.sin(t), .1, .9)];
1921
2884
  }
1922
2885
  case "centred": {
1923
2886
  if (n === 1) return [.5, .5];
@@ -1940,47 +2903,81 @@ function Nt(e, t = "composed") {
1940
2903
  };
1941
2904
  });
1942
2905
  }
1943
- function Pt(e) {
2906
+ var an = .03;
2907
+ function on(e, t, n) {
2908
+ let r = e.length;
2909
+ if (r === 0 || t <= 0) return;
2910
+ let i = e.reduce((e, t) => e + t.C, 0) / r, a = Math.min(.22, i * 1.5), o = (e, t, n) => S({
2911
+ L: e,
2912
+ C: t,
2913
+ h: n
2914
+ }).C;
2915
+ if (e.forEach((e, n) => {
2916
+ let r = n % 2 == 0 ? a : an, i = v(Q(e.C, r, t), 0, .4);
2917
+ e.C = o(e.L, i, e.h);
2918
+ }), n) {
2919
+ let t = 0;
2920
+ for (let n = 1; n < r; n++) e[n].L < e[t].L && (t = n);
2921
+ let n = e[t];
2922
+ n.C = o(n.L, an, n.h);
2923
+ }
2924
+ }
2925
+ function sn(e) {
1944
2926
  return e < .4 ? "fbm" : e < .75 ? "hybrid" : "cellular";
1945
2927
  }
1946
- function Ft(e, t) {
1947
- let n = m(t, 0, 1);
1948
- e.warpAmount = m(Q(.2, .6, n), 0, .6), e.warpScale = m(Q(1, 2.6, n), .5, 3), e.warpMode = Pt(n), e.noiseOctaves = n < .5 ? 3 : n < .85 ? 4 : 5;
2928
+ function cn(e, t) {
2929
+ let n = v(t, 0, 1);
2930
+ e.warpAmount = v(Q(.2, .6, n), 0, .6), e.warpScale = v(Q(1, 2.6, n), .5, 3), e.warpMode = sn(n), e.noiseOctaves = n < .5 ? 3 : n < .85 ? 4 : 5;
1949
2931
  }
1950
- function It(e = jt, t = b) {
2932
+ function ln(e = tn, t = F) {
1951
2933
  let n = {
1952
2934
  ...t,
1953
2935
  palette: t.palette.map((e) => ({ ...e })),
1954
2936
  nuclei: t.nuclei.map((e) => ({ ...e })),
1955
2937
  flow: { ...t.flow }
1956
- }, r = e.colorEnergy === void 0 ? void 0 : m(e.colorEnergy, 0, 1);
1957
- if (e.seed !== void 0 && (n.palette = F(e.seed, {
1958
- harmony: e.harmony ?? "analogous",
1959
- stopCount: 4,
1960
- temperatureShift: r === void 0 ? 0 : Q($.temperatureShift.calm, $.temperatureShift.vivid, r)
1961
- })), r !== void 0 && (n.saturation = m(Q($.saturation.calm, $.saturation.vivid, r), .6, 1.3), n.valueVariance = m(Q($.valueVariance.calm, $.valueVariance.vivid, r), 0, .3), n.breathDepth = m(Q($.breathDepth.calm, $.breathDepth.vivid, r), 0, .15)), e.zones !== void 0 && (n.nuclei = Nt(e.zones.count, e.zones.arrangement ?? "composed")), e.noise !== void 0 && Ft(n, e.noise), e.medium !== void 0 && (n.medium = e.medium.kind, (e.medium.kind === "vangogh" || e.medium.kind === "oil-pastel") && (n.strokeOrient = "tensor"), e.medium.kind !== "smooth" && e.medium.amount !== void 0 && Dt(n, e.medium.kind, e.medium.amount)), e.motion !== void 0) {
1962
- let t = Et[e.motion];
1963
- n.nucleiDrift = m(t.nucleiDrift, 0, .05), n.paletteDrift = m(t.paletteDrift, 0, .04), n.warpDrift = m(t.warpDrift, 0, .015), n.breathDepth = m(e.motion === "still" ? 0 : Math.max(n.breathDepth, t.breathDepth), 0, .15);
2938
+ }, r = e.colorEnergy === void 0 ? void 0 : v(e.colorEnergy, 0, 1);
2939
+ if (e.seed !== void 0) {
2940
+ let t = e.hueSpread === void 0 ? r === void 0 ? void 0 : Q($.hueSpread.calm, $.hueSpread.vivid, r) : v(e.hueSpread, 0, 180);
2941
+ n.palette = Qe(e.seed, {
2942
+ harmony: e.harmony ?? "analogous",
2943
+ stopCount: 4,
2944
+ temperatureShift: r === void 0 ? 0 : Q($.temperatureShift.calm, $.temperatureShift.vivid, r),
2945
+ ...t === void 0 ? {} : { hueSpread: t },
2946
+ ...e.lightnessScheme === void 0 ? {} : { scheme: e.lightnessScheme },
2947
+ ...e.lBand === void 0 ? {} : { lBand: e.lBand }
2948
+ }), e.chromaVariance !== void 0 && e.chromaVariance > 0 && on(n.palette, v(e.chromaVariance, 0, 1), e.chromaCounterpoint ?? !1);
2949
+ }
2950
+ if (r !== void 0 && (n.saturation = v(Q($.saturation.calm, $.saturation.vivid, r), .6, 1.3), n.valueVariance = v(Q($.valueVariance.calm, $.valueVariance.vivid, r), 0, .3), n.breathDepth = v(Q($.breathDepth.calm, $.breathDepth.vivid, r), 0, .15)), e.zones !== void 0 && (n.nuclei = rn(e.zones.count, e.zones.arrangement ?? "composed")), e.noise !== void 0 && cn(n, e.noise), e.medium !== void 0 && (n.medium = e.medium.kind, (e.medium.kind === "vangogh" || e.medium.kind === "oil-pastel") && (n.strokeOrient = "tensor"), e.medium.kind !== "smooth" && e.medium.amount !== void 0 && Zt(n, e.medium.kind, e.medium.amount)), e.motion !== void 0) {
2951
+ let t = Xt[e.motion];
2952
+ n.nucleiDrift = v(t.nucleiDrift, 0, .05), n.paletteDrift = v(t.paletteDrift, 0, .04), n.warpDrift = v(t.warpDrift, 0, .015), n.breathDepth = v(e.motion === "still" ? 0 : Math.max(n.breathDepth, t.breathDepth), 0, .15);
1964
2953
  }
1965
- return e.interactivity !== void 0 && (n.interactivity = { ...e.interactivity }), n;
2954
+ if (e.interactivity !== void 0) {
2955
+ let t = e.interactivity;
2956
+ n.interactivity = {
2957
+ ...t,
2958
+ swirl: t.swirl ?? !0,
2959
+ amplitude: t.amplitude === void 0 ? .5 : v(t.amplitude, 0, 1)
2960
+ };
2961
+ }
2962
+ return n;
1966
2963
  }
1967
- function Lt(e) {
2964
+ function un(e) {
1968
2965
  let t = e.medium, n = t === "smooth" ? { kind: t } : {
1969
2966
  kind: t,
1970
- amount: Ot(e, t)
2967
+ amount: Qt(e, t)
1971
2968
  };
1972
2969
  return {
1973
- seed: e.palette.length > 0 ? C(e.palette[0]) : "#3a7bd5",
2970
+ seed: e.palette.length > 0 ? T(e.palette[0]) : "#3a7bd5",
1974
2971
  harmony: "analogous",
1975
- colorEnergy: At(e.saturation, $.saturation.calm, $.saturation.vivid),
2972
+ colorEnergy: en(e.saturation, $.saturation.calm, $.saturation.vivid),
1976
2973
  zones: {
1977
2974
  count: Math.max(1, Math.min(6, e.nuclei.length)),
1978
2975
  arrangement: "composed"
1979
2976
  },
1980
- noise: At(e.warpAmount, .2, .6),
2977
+ noise: en(e.warpAmount, .2, .6),
1981
2978
  medium: n,
1982
- motion: kt(e)
2979
+ motion: $t(e)
1983
2980
  };
1984
2981
  }
1985
2982
  //#endregion
1986
- export { wt as Aurora, jt as DEFAULT_ATOMS, b as DEFAULT_AURORA_CONFIG, ee as DEFAULT_VIVIDNESS, ne as MAX_NUCLEI, y as MAX_STOPS, v as PAPER_WASH_GROUND, te as VIVID_TARGET, xt as auroraFallbackGround, Lt as configToAtoms, X as createAurora, w as cssToOklch, F as deriveAurora, N as flattenPalette, je as hexToOklchStop, A as isSoftwareWebGLRenderer, _t as nucleiFieldStatic, Nt as nucleiPrior, C as oklchStopToHex, x as oklchToLinear, P as paletteToCssGradient, ht as relativeLuminance, It as resolveAtoms, j as resolveRenderMode, vt as sampleAuroraField, pt as useAurora, Tt as useCursorInteraction };
2983
+ export { Jt as Aurora, tn as DEFAULT_ATOMS, F as DEFAULT_AURORA_CONFIG, He as DEFAULT_VIVIDNESS, Ge as IMAGE_BLUR_MAX_DEFAULT, We as IMAGE_BLUR_MIN_DEFAULT, Be as MAX_NUCLEI, Ve as MAX_STOPS, Ke as PAPER_WASH_GROUND, Ue as VIVID_TARGET, Gt as auroraFallbackGround, un as configToAtoms, Ft as createAurora, E as cssToOklch, Qe as deriveAurora, I as flattenPalette, Je as hexToOklchStop, N as isSoftwareWebGLRenderer, Z as nucleiFieldStatic, rn as nucleiPrior, T as oklchStopToHex, C as oklchToLinear, qe as paletteToCssGradient, Bt as relativeLuminance, ln as resolveAtoms, Le as resolveRenderMode, Ht as sampleAuroraField, Rt as useAurora, Yt as useCursorInteraction };