@mkbabb/glass-ui 5.0.0 → 6.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 (470) hide show
  1. package/README.md +30 -27
  2. package/dist/DropdownMenuTrigger-BzQtd9lt.js +65 -0
  3. package/dist/{FadingScroll-BSRLqQCx.js → FadingScroll-C1ZWEjmG.js} +32 -25
  4. package/dist/{Input-DKf-XwUM.js → Input-B4WQ_CMc.js} +1 -1
  5. package/dist/{PagerDots-BP6jh7z4.js → PagerDots-BoTQ7g5l.js} +123 -95
  6. package/dist/{accent-tone-solve-CBw3L0cy.js → accent-tone-solve-Dii9ePhK.js} +1 -1
  7. package/dist/animated-digit.js +1 -1
  8. package/dist/aurora.js +324 -314
  9. package/dist/blob-config.d.ts +0 -4
  10. package/dist/blob-config.js +1 -1
  11. package/dist/blob.js +280 -261
  12. package/dist/{button-BXzhydVB.js → button-32mg6xA8.js} +63 -56
  13. package/dist/button.js +1 -1
  14. package/dist/canvas.js +1 -1
  15. package/dist/{CardAction-2uUvjMQK.js → card-16xmzIr3.js} +29 -11
  16. package/dist/card.js +1 -1
  17. package/dist/carousel.d.ts +1 -2
  18. package/dist/carousel.js +26 -95
  19. package/dist/chip.d.ts +0 -9
  20. package/dist/chip.js +1 -1
  21. package/dist/collapsible.js +1 -1
  22. package/dist/color-swatch.js +1 -0
  23. package/dist/color.js +87 -3
  24. package/dist/{CommandShortcut-fmdbsEJL.js → command-BjPjUU9z.js} +56 -51
  25. package/dist/command.js +1 -1
  26. package/dist/completion-seal.js +64 -55
  27. package/dist/components/_shared/ModalOverlay.vue.d.ts +5 -52
  28. package/dist/components/_shared/field-surfaces.css +1 -0
  29. package/dist/components/_shared/menuItemVariants.d.ts +2 -2
  30. package/dist/components/_shared/useMotionAxis.d.ts +2 -2
  31. package/dist/components/_shared/valueDomain.d.ts +6 -0
  32. package/dist/components/alert/index.d.ts +1 -1
  33. package/dist/components/animated-digit/AnimatedDigit.vue.d.ts +1 -1
  34. package/dist/components/aurora/Aurora.vue.d.ts +7 -1
  35. package/dist/components/aurora/composables/runtime.d.ts +5 -3
  36. package/dist/components/aurora/composables/useAurora.d.ts +4 -2
  37. package/dist/components/avatar/AvatarImage.vue.d.ts +3 -1
  38. package/dist/components/badge/index.d.ts +2 -2
  39. package/dist/components/blob/Blob.vue.d.ts +11 -0
  40. package/dist/components/blob/composables/useMetaballRenderer.d.ts +2 -0
  41. package/dist/components/button/Button.vue.d.ts +4 -2
  42. package/dist/components/button/index.d.ts +2 -2
  43. package/dist/components/card/Card.vue.d.ts +4 -4
  44. package/dist/components/card/ScrollCard.vue.d.ts +1 -1
  45. package/dist/components/card/styles.css +1 -0
  46. package/dist/components/carousel/Carousel.vue.d.ts +2 -2
  47. package/dist/components/carousel/CarouselNext.vue.d.ts +1 -1
  48. package/dist/components/carousel/CarouselPrevious.vue.d.ts +1 -1
  49. package/dist/components/carousel/index.d.ts +0 -1
  50. package/dist/components/carousel/useCarousel.d.ts +2 -2
  51. package/dist/components/combobox/ComboboxList.vue.d.ts +1 -1
  52. package/dist/components/combobox/index.d.ts +1 -3
  53. package/dist/components/command/Command.vue.d.ts +1 -1
  54. package/dist/components/command/CommandDialog.vue.d.ts +9 -6
  55. package/dist/components/completion-seal/styles.css +1 -0
  56. package/dist/components/constellation/Constellation.vue.d.ts +6 -1
  57. package/dist/components/constellation/composables/useConstellation.d.ts +3 -16
  58. package/dist/components/constellation/constants.d.ts +6 -16
  59. package/dist/components/constellation/constellationField.d.ts +3 -5
  60. package/dist/components/constellation/constellationInteraction.d.ts +1 -1
  61. package/dist/components/constellation/constellationRender.d.ts +11 -21
  62. package/dist/components/constellation/constellationTypes.d.ts +12 -9
  63. package/dist/components/constellation/index.d.ts +1 -1
  64. package/dist/components/controls/DarkModeToggle.vue.d.ts +0 -2
  65. package/dist/components/data-table/DataTable.vue.d.ts +14 -2
  66. package/dist/components/data-table/index.d.ts +1 -2
  67. package/dist/components/data-table/types.d.ts +26 -1
  68. package/dist/components/deck/constants.d.ts +0 -10
  69. package/dist/components/deck/index.d.ts +0 -1
  70. package/dist/components/dialog/DialogContent.vue.d.ts +7 -1
  71. package/dist/components/dialog/index.d.ts +0 -1
  72. package/dist/components/dock/DockControl.vue.d.ts +4 -4
  73. package/dist/components/dock/DockStack.vue.d.ts +2 -2
  74. package/dist/components/dock/GlassDock.vue.d.ts +1 -0
  75. package/dist/components/dock/composables/dockMorphContext.d.ts +2 -0
  76. package/dist/components/dock/composables/dockMorphMeasure.d.ts +11 -1
  77. package/dist/components/dock/composables/useDockClickIntegrity.d.ts +4 -0
  78. package/dist/components/dock/composables/useDockOverflowFit.d.ts +3 -3
  79. package/dist/components/dock/composables/useDockPopover.d.ts +2 -0
  80. package/dist/components/dock/composables/useDockShellProps.d.ts +7 -0
  81. package/dist/components/dock/composables/useDockState.d.ts +2 -2
  82. package/dist/components/dock/constants.d.ts +0 -12
  83. package/dist/components/dock/index.d.ts +1 -0
  84. package/dist/components/dock/styles/adaptive-legibility.css +1 -0
  85. package/dist/components/dock/styles/controls/icon-button.css +1 -0
  86. package/dist/{styles/dock-controls → components/dock/styles/controls}/touch-floor.css +1 -1
  87. package/dist/components/dock/styles/controls.css +1 -0
  88. package/dist/{styles/dock → components/dock/styles}/density.css +1 -1
  89. package/dist/components/dock/styles/dock.css +1 -0
  90. package/dist/components/dock/styles/index.css +1 -0
  91. package/dist/components/dock/styles/layer-group.css +1 -0
  92. package/dist/components/dock/styles/layers.css +1 -0
  93. package/dist/components/dock/styles/overflow.css +1 -0
  94. package/dist/components/dock/styles/popover.css +1 -0
  95. package/dist/components/dock/styles/shape.css +1 -0
  96. package/dist/components/dock/styles/shell.css +1 -0
  97. package/dist/components/drawer/Drawer.vue.d.ts +3 -3
  98. package/dist/components/drawer/composables/drawerSnapContext.d.ts +3 -1
  99. package/dist/components/drawer/constants.d.ts +6 -6
  100. package/dist/components/drawer/index.d.ts +4 -6
  101. package/dist/components/drawer/styles.css +1 -0
  102. package/dist/components/dropdown-menu/DropdownMenuContent.vue.d.ts +1 -1
  103. package/dist/components/dropdown-menu/DropdownMenuTrigger.vue.d.ts +9 -3
  104. package/dist/components/dropdown-menu/index.d.ts +0 -1
  105. package/dist/components/easing/EasingConfigurator.vue.d.ts +1 -1
  106. package/dist/components/easing/EasingPicker.vue.d.ts +2 -2
  107. package/dist/components/easing/composables/useEasingPicker.d.ts +4 -0
  108. package/dist/components/easing/constants.d.ts +2 -0
  109. package/dist/components/fading-scroll/composables/useFadingScroll.d.ts +3 -3
  110. package/dist/components/fourier-field/FourierField.vue.d.ts +7 -1
  111. package/dist/components/fourier-field/composables/useFourierField.d.ts +2 -1
  112. package/dist/components/handmark/HandMark.vue.d.ts +1 -1
  113. package/dist/components/handmark/geometry.d.ts +1 -1
  114. package/dist/components/handmark/index.d.ts +4 -6
  115. package/dist/components/icon-chip/styles.css +1 -0
  116. package/dist/components/index.d.ts +0 -1
  117. package/dist/components/infinite-scroll/index.d.ts +1 -0
  118. package/dist/components/instrument-chassis/styles.css +1 -0
  119. package/dist/components/labeled-field/LabeledField.vue.d.ts +12 -2
  120. package/dist/components/labeled-field/LabeledInput.vue.d.ts +10 -3
  121. package/dist/components/liquid-grid/LiquidGrid.vue.d.ts +4 -0
  122. package/dist/components/liquid-grid/composables/useLiquidGrid.d.ts +2 -1
  123. package/dist/components/metric-stack/MetricStack.vue.d.ts +1 -1
  124. package/dist/components/pager-dots/PagerDots.vue.d.ts +1 -1
  125. package/dist/components/popover/PopoverContent.vue.d.ts +1 -1
  126. package/dist/components/progress/Progress.vue.d.ts +5 -40
  127. package/dist/components/progress/ProgressDefault.vue.d.ts +1 -17
  128. package/dist/components/progress/ProgressGradient.vue.d.ts +1 -0
  129. package/dist/components/progress/ProgressLiquid.vue.d.ts +1 -0
  130. package/dist/components/progress/index.d.ts +0 -5
  131. package/dist/components/progress/valueMarks.css +1 -0
  132. package/dist/components/pulse/Pulse.vue.d.ts +2 -2
  133. package/dist/components/scroll-progress-rim/styles.css +1 -0
  134. package/dist/components/search/FuzzySearch.vue.d.ts +4 -2
  135. package/dist/components/search/SearchBar.vue.d.ts +2 -2
  136. package/dist/components/search/searchVariants.d.ts +1 -1
  137. package/dist/components/select/SelectContent.vue.d.ts +1 -1
  138. package/dist/components/select/index.d.ts +0 -2
  139. package/dist/components/skeleton/Skeleton.vue.d.ts +1 -1
  140. package/dist/components/slider/Slider.vue.d.ts +2 -0
  141. package/dist/components/split-chars/SplitChars.vue.d.ts +1 -1
  142. package/dist/components/surface/Surface.vue.d.ts +1 -1
  143. package/dist/components/table/Table.vue.d.ts +4 -0
  144. package/dist/components/tabs/SegmentedTabs.vue.d.ts +10 -0
  145. package/dist/components/tabs/index.d.ts +1 -1
  146. package/dist/components/tabs/styles/drag.css +1 -0
  147. package/dist/components/tags-input/TagsInput.vue.d.ts +2 -2
  148. package/dist/components/timeline/ContinuousTimeline.vue.d.ts +1 -1
  149. package/dist/components/timeline/GlassTimeline.vue.d.ts +4 -4
  150. package/dist/components/toast/Toast.vue.d.ts +3 -3
  151. package/dist/components/toast/use-toast.d.ts +4 -4
  152. package/dist/components/typewriter/TypewriterText.vue.d.ts +1 -4
  153. package/dist/components/typewriter/composables/useTypewriter.d.ts +0 -1
  154. package/dist/components/typewriter/utils/graphemes.d.ts +1 -0
  155. package/dist/components/watercolor-dot/WatercolorDot.vue.d.ts +2 -2
  156. package/dist/composables/glass/useGlassBackdropLuminance.d.ts +31 -0
  157. package/dist/composables/glass/webgpu/rendererStatus.d.ts +13 -0
  158. package/dist/composables/glass/webgpu/useGpuSubstrate.d.ts +3 -0
  159. package/dist/composables/glass/webgpu/webgpuCanvasTypes.d.ts +2 -0
  160. package/dist/composables/motion/springProjection.d.ts +16 -0
  161. package/dist/composables/motion/useAnimatedNumber.d.ts +1 -6
  162. package/dist/composables/motion/useCountup.d.ts +1 -6
  163. package/dist/composables/motion/useDockCtaReceive.d.ts +55 -0
  164. package/dist/composables/motion/useElementMorph.d.ts +8 -0
  165. package/dist/composables/motion/useLiquidPress.d.ts +12 -4
  166. package/dist/composables/motion/useNumericTransition.d.ts +2 -0
  167. package/dist/composables/motion/useTextHighlight.d.ts +2 -1
  168. package/dist/configurator-CSENXXSy.js +311 -0
  169. package/dist/configurator.js +2 -3
  170. package/dist/constellation.js +235 -571
  171. package/dist/controls.js +55 -63
  172. package/dist/{createCanvasLifecycle-DlrcvWbb.js → createCanvasLifecycle-hsFkQVdl.js} +32 -32
  173. package/dist/dark-DIH-blY1.js +70 -0
  174. package/dist/dark.d.ts +1 -2
  175. package/dist/dark.js +2 -20
  176. package/dist/{DataTable-Bxya8nBn.js → data-table-DveMdgBM.js} +231 -120
  177. package/dist/data-table.js +2 -2
  178. package/dist/deck.js +10 -21
  179. package/dist/dialog-BzQxKrUr.js +281 -0
  180. package/dist/dialog.js +2 -3
  181. package/dist/dock.js +561 -428
  182. package/dist/{dockContext-d-WpJN2Z.js → dockContext-4S9qP0Z4.js} +1 -1
  183. package/dist/dom.js +196 -7
  184. package/dist/drawer.js +111 -66
  185. package/dist/dropdown-menu-DORIA52F.js +378 -0
  186. package/dist/dropdown-menu.js +3 -2
  187. package/dist/easing.d.ts +0 -9
  188. package/dist/easing.js +334 -187
  189. package/dist/expandable-container.js +12 -4
  190. package/dist/fading-scroll.js +1 -1
  191. package/dist/focus-scope.js +1 -1
  192. package/dist/forms.js +37 -78
  193. package/dist/fourier-field.js +273 -263
  194. package/dist/fourier-math.d.ts +0 -6
  195. package/dist/fourier-math.js +112 -2
  196. package/dist/glass-ui.css +1 -1
  197. package/dist/glass-ui.js +131 -195
  198. package/dist/handmark.d.ts +0 -2
  199. package/dist/handmark.js +82 -82
  200. package/dist/header-ribbon.js +41 -30
  201. package/dist/{IconChip-CwLmBJ_K.js → icon-chip-BWuxz1-u.js} +1 -1
  202. package/dist/icon-chip.js +1 -1
  203. package/dist/{IconTooltip-D9sbK-Mk.js → icon-tooltip-CO6rw0dZ.js} +1 -1
  204. package/dist/icon-tooltip.js +1 -1
  205. package/dist/index.d.ts +0 -1
  206. package/dist/infinite-scroll.d.ts +0 -1
  207. package/dist/infinite-scroll.js +17 -15
  208. package/dist/instrument-chassis.js +1 -1
  209. package/dist/keyboard.js +104 -2
  210. package/dist/label.js +1 -1
  211. package/dist/labeled-field.js +95 -69
  212. package/dist/liquid-grid.js +173 -162
  213. package/dist/metric-badge.js +3 -3
  214. package/dist/metric-cell.js +2 -2
  215. package/dist/metric-stack.js +1 -1
  216. package/dist/motion-core.js +15 -16
  217. package/dist/motion-curves.d.ts +0 -20
  218. package/dist/motion.js +59 -58
  219. package/dist/{Notification-DQv2cOh9.js → notification-DVs7ODMg.js} +17 -8
  220. package/dist/notification.js +1 -1
  221. package/dist/{NumberFieldContent-BkE7xPS9.js → number-field-PvkGedHk.js} +2 -2
  222. package/dist/number-field.js +1 -1
  223. package/dist/pager-dots.js +1 -1
  224. package/dist/paper-backdrop.js +31 -2
  225. package/dist/{PopoverContent-DOtszFWK.js → popover-WMgyRSyN.js} +7 -2
  226. package/dist/popover.js +1 -1
  227. package/dist/procedural-color.wgsl-B9mLK7v0.js +377 -0
  228. package/dist/progress-C-HHuFZy.js +192 -0
  229. package/dist/progress.js +2 -2
  230. package/dist/pulse.js +3 -1
  231. package/dist/reactive.js +19 -3
  232. package/dist/rendererStatus-C2-zC2Q-.js +40 -0
  233. package/dist/{resolveCanvasColor-B3L-akX0.js → resolveCanvasColor-yarP5bdk.js} +1 -1
  234. package/dist/scroll-progress-rim.js +1 -1
  235. package/dist/search.js +187 -146
  236. package/dist/{SelectScrollDownButton-CDtwaWkZ.js → select-BIv4R3Ir.js} +109 -44
  237. package/dist/select.js +2 -4
  238. package/dist/separator-CBU94kTM.js +62 -0
  239. package/dist/separator.js +1 -1
  240. package/dist/sidebar.js +1 -1
  241. package/dist/slider-Cc_qw6GA.js +166 -0
  242. package/dist/slider.js +1 -1
  243. package/dist/sortable-list.js +43 -43
  244. package/dist/styles/accessibility.css +1 -0
  245. package/dist/styles/components.css +1 -1
  246. package/dist/styles/glass/control-surfaces.css +1 -1
  247. package/dist/styles/glass/glass-capsule.css +1 -1
  248. package/dist/styles/glass/ladder.css +1 -1
  249. package/dist/styles/glass/liquid-fill.css +1 -1
  250. package/dist/styles/glass/material-roles.css +1 -0
  251. package/dist/styles/glass/material.css +1 -1
  252. package/dist/styles/glass/surface-axis.css +1 -1
  253. package/dist/styles/glass/surfaces-pager.css +1 -1
  254. package/dist/styles/glass/surfaces.css +1 -1
  255. package/dist/styles/glass.css +1 -1
  256. package/dist/styles/index.css +1 -1
  257. package/dist/styles/theme/bridges.css +1 -1
  258. package/dist/styles/tokens/glass-fx.css +1 -1
  259. package/dist/styles/tokens/glass.css +1 -1
  260. package/dist/styles/tokens/offsets.css +1 -1
  261. package/dist/styles/tokens/scale-paper.css +1 -1
  262. package/dist/styles/tokens/scheme-spring.css +1 -1
  263. package/dist/styles/tokens/shadow.css +1 -1
  264. package/dist/styles/tokens.d.ts +53 -0
  265. package/dist/styles/tokens.ts +58 -0
  266. package/dist/styles/typography/scale.css +1 -1
  267. package/dist/styles/typography/semantic.css +1 -1
  268. package/dist/styles/typography/utilities.css +1 -1
  269. package/dist/styles/utilities/base.css +1 -1
  270. package/dist/styles/utilities/btn.css +1 -1
  271. package/dist/styles/utilities/components.css +1 -1
  272. package/dist/styles/utilities.css +1 -1
  273. package/dist/{Switch-BPBfhMU3.js → switch-Boj4Ucn5.js} +1 -1
  274. package/dist/switch.js +1 -1
  275. package/dist/tabs.js +51 -45
  276. package/dist/timeline.js +2 -2
  277. package/dist/toast.js +1 -1
  278. package/dist/{ToggleGroupItem-DNWx2aSW.js → toggle-group-BPchFsns.js} +10 -7
  279. package/dist/toggle-group.js +1 -1
  280. package/dist/tokens.d.ts +1 -53
  281. package/dist/tokens.js +1 -1
  282. package/dist/{TooltipProvider-GtfYdSVf.js → tooltip-BmOQJzh0.js} +1 -0
  283. package/dist/tooltip.js +1 -1
  284. package/dist/typewriter.js +151 -166
  285. package/dist/{useAccentTone-D25DxviG.js → useAccentTone-C-p6WdPe.js} +1 -1
  286. package/dist/{useAnimatedNumber-2XC4aRB6.js → useAnimatedNumber-BRVVaFFc.js} +1 -1
  287. package/dist/useDockCtaReceive-CK-RLASa.js +257 -0
  288. package/dist/{useGooMorph-CU1pwuC6.js → useGooMorph-D1F6QJlH.js} +140 -59
  289. package/dist/{useIntersectionPause-Cmt5Tnv9.js → useIntersectionPause-B-dbxl9w.js} +1 -1
  290. package/dist/useLiquidPress-BYcwwGQV.js +68 -0
  291. package/dist/{useRAFLoop-CvOo_kgb.js → useRAFLoop-BtwQ9DyY.js} +1 -1
  292. package/dist/{useScrollProgress-C-yImzhU.js → useScrollProgress-DZI4nf4v.js} +1 -1
  293. package/dist/{useSelectionGroup-Btpf24aY.js → useSelectionGroup-LDzBdR1Y.js} +3 -3
  294. package/dist/{useTabRovingFocus-CG1H1k1J.js → useTabRovingFocus-DkLYwo4L.js} +1 -1
  295. package/dist/{useTouchGate-BlegwvwL.js → useTouchGate-Cj5fOkTv.js} +1 -1
  296. package/dist/valueDomain-B8L04u3U.js +13 -0
  297. package/dist/watercolor-dot.js +5 -3
  298. package/package.json +5 -12
  299. package/src/styles/accessibility.css +48 -0
  300. package/src/styles/glass/glass-capsule.css +2 -2
  301. package/src/styles/glass/ladder.css +1 -1
  302. package/src/styles/glass/material-roles.css +18 -0
  303. package/src/styles/glass/material.css +18 -12
  304. package/src/styles/glass.css +5 -5
  305. package/src/styles/index.css +38 -30
  306. package/src/styles/theme/bridges.css +0 -6
  307. package/src/styles/tokens/glass-fx.css +1 -5
  308. package/src/styles/tokens/glass.css +1 -2
  309. package/src/styles/tokens/offsets.css +0 -1
  310. package/src/styles/tokens/property-regs.css +11 -10
  311. package/src/styles/tokens/scale-paper.css +0 -1
  312. package/src/styles/tokens/scheme-motion.css +3 -0
  313. package/src/styles/tokens/scheme-spring.css +0 -10
  314. package/src/styles/tokens/shadow.css +3 -29
  315. package/src/styles/tokens.ts +58 -0
  316. package/src/styles/typography/scale.css +5 -2
  317. package/src/styles/typography/semantic.css +5 -5
  318. package/src/styles/typography/utilities.css +5 -5
  319. package/src/styles/utilities/base.css +5 -5
  320. package/src/styles/utilities/btn.css +6 -27
  321. package/src/styles/utilities.css +4 -6
  322. package/dist/ConfiguratorRow-BV6zPjTM.js +0 -151
  323. package/dist/DialogContent-Bl4v10AC.js +0 -192
  324. package/dist/DialogFooter-C0v4Hz2F.js +0 -168
  325. package/dist/PaperBackdrop-BYwE8_kg.js +0 -31
  326. package/dist/Progress-uWLyXE7J.js +0 -308
  327. package/dist/SelectGroup-BuEptUsa.js +0 -31
  328. package/dist/SelectSeparator-4QGephvr.js +0 -49
  329. package/dist/Separator-DqJ6PfOd.js +0 -44
  330. package/dist/color-Bp5jmv4Z.js +0 -86
  331. package/dist/components/carousel/GlassCarouselPager.vue.d.ts +0 -50
  332. package/dist/components/combobox/ComboboxSeparator.vue.d.ts +0 -18
  333. package/dist/components/combobox/ComboboxViewport.vue.d.ts +0 -18
  334. package/dist/components/constellation/composables/constellationGLSetup.d.ts +0 -10
  335. package/dist/components/constellation/composables/constellationWGPUSetup.d.ts +0 -19
  336. package/dist/components/constellation/composables/uniformBridgeWGPU.d.ts +0 -66
  337. package/dist/components/constellation/shaders/constellation-lines.glsl.d.ts +0 -2
  338. package/dist/components/constellation/shaders/constellation-lines.wgsl.d.ts +0 -1
  339. package/dist/components/constellation/shaders/constellation-points.glsl.d.ts +0 -2
  340. package/dist/components/constellation/shaders/constellation-points.wgsl.d.ts +0 -1
  341. package/dist/components/deck/composables/useDeckSpring.d.ts +0 -22
  342. package/dist/components/dialog/DialogScrollContent.vue.d.ts +0 -33
  343. package/dist/components/progress/ProgressSectioned.vue.d.ts +0 -47
  344. package/dist/components/progress/useProgressGeometry.d.ts +0 -60
  345. package/dist/components/section/Section.vue.d.ts +0 -73
  346. package/dist/components/section/index.d.ts +0 -1
  347. package/dist/components/stacked-icons/StackedIconGroup.vue.d.ts +0 -30
  348. package/dist/components/stacked-icons/index.d.ts +0 -2
  349. package/dist/components/stacked-icons/types.d.ts +0 -19
  350. package/dist/dropdown-menu-DaGlVdp9.js +0 -421
  351. package/dist/math-CIEcwsYi.js +0 -112
  352. package/dist/procedural-color.wgsl-ByduxnzV.js +0 -4
  353. package/dist/slider-Cxuj_W_H.js +0 -151
  354. package/dist/stacked-icons.d.ts +0 -1
  355. package/dist/stacked-icons.js +0 -98
  356. package/dist/styles/cards.css +0 -1
  357. package/dist/styles/completion-seal.css +0 -1
  358. package/dist/styles/dock/adaptive-legibility.css +0 -1
  359. package/dist/styles/dock/dock.css +0 -1
  360. package/dist/styles/dock/layer-group.css +0 -1
  361. package/dist/styles/dock/layers.css +0 -1
  362. package/dist/styles/dock/overflow.css +0 -1
  363. package/dist/styles/dock/popover.css +0 -1
  364. package/dist/styles/dock/shape.css +0 -1
  365. package/dist/styles/dock/shell.css +0 -1
  366. package/dist/styles/dock-controls/icon-button.css +0 -1
  367. package/dist/styles/dock-controls.css +0 -1
  368. package/dist/styles/dock.css +0 -1
  369. package/dist/styles/drawer.css +0 -1
  370. package/dist/styles/icon-chip.css +0 -1
  371. package/dist/styles/instrument-chassis.css +0 -1
  372. package/dist/styles/scroll-progress-rim.css +0 -1
  373. package/dist/styles/select.css +0 -1
  374. package/dist/styles/tabs/segmented-tabs-drag.css +0 -1
  375. package/dist/styles/utilities/animate.css +0 -0
  376. package/dist/useConfiguratorState-Dq35N_7t.js +0 -167
  377. package/dist/useDockCtaReceive-BgMmeINo.js +0 -161
  378. package/dist/useGlobalDark-DjKMEQE2.js +0 -53
  379. package/dist/useGpuSubstrate-DcY584kE.js +0 -347
  380. package/dist/useInterval-ZATRi-1T.js +0 -18
  381. package/dist/useKeyboardShortcuts-ynVmNFo3.js +0 -104
  382. package/dist/useLiquidPress-BXNHydZh.js +0 -40
  383. package/dist/useTextHighlight-C46Le9u_.js +0 -72
  384. package/dist/useViewportReady-c0isoKL8.js +0 -191
  385. package/src/styles/card-scroll.css +0 -189
  386. package/src/styles/cards.css +0 -485
  387. package/src/styles/completion-seal.css +0 -205
  388. package/src/styles/configurator.css +0 -359
  389. package/src/styles/dialog-placement.css +0 -68
  390. package/src/styles/dock/adaptive-legibility.css +0 -119
  391. package/src/styles/dock/crossfade.css +0 -139
  392. package/src/styles/dock/cta-seat.css +0 -87
  393. package/src/styles/dock/density.css +0 -458
  394. package/src/styles/dock/dock.css +0 -199
  395. package/src/styles/dock/fisheye.css +0 -81
  396. package/src/styles/dock/layer-group.css +0 -329
  397. package/src/styles/dock/layers.css +0 -438
  398. package/src/styles/dock/morph.css +0 -455
  399. package/src/styles/dock/overflow.css +0 -332
  400. package/src/styles/dock/popover.css +0 -249
  401. package/src/styles/dock/search.css +0 -68
  402. package/src/styles/dock/section.css +0 -59
  403. package/src/styles/dock/shape.css +0 -188
  404. package/src/styles/dock/shell-regions.css +0 -73
  405. package/src/styles/dock/shell.css +0 -500
  406. package/src/styles/dock-controls/dark-mode-toggle.css +0 -123
  407. package/src/styles/dock-controls/icon-button.css +0 -221
  408. package/src/styles/dock-controls/tab-button.css +0 -143
  409. package/src/styles/dock-controls/touch-floor.css +0 -119
  410. package/src/styles/dock-controls/triggers.css +0 -157
  411. package/src/styles/dock-controls.css +0 -92
  412. package/src/styles/dock.css +0 -219
  413. package/src/styles/drawer.css +0 -434
  414. package/src/styles/feedback-tone.css +0 -104
  415. package/src/styles/icon-chip.css +0 -256
  416. package/src/styles/instrument-chassis.css +0 -449
  417. package/src/styles/menu.css +0 -187
  418. package/src/styles/scroll-progress-rim.css +0 -87
  419. package/src/styles/segmented-tabs.css +0 -424
  420. package/src/styles/select.css +0 -201
  421. package/src/styles/tabs/segmented-tabs-drag.css +0 -200
  422. package/src/styles/utilities/animate.css +0 -29
  423. /package/dist/{coalesce-metric-B8o7zT9u.js → coalesce-metric-znAcLzkB.js} +0 -0
  424. /package/dist/{CollapsibleContent-DiHcB_HH.js → collapsible-bPzS1aQk.js} +0 -0
  425. /package/dist/{compile-C55K3P9g.js → compile-DK3Fri1B.js} +0 -0
  426. /package/dist/{styles → components/_shared}/feedback-tone.css +0 -0
  427. /package/dist/{styles → components/_shared}/menu.css +0 -0
  428. /package/dist/{styles → components/card}/card-scroll.css +0 -0
  429. /package/dist/{styles/configurator.css → components/configurator/styles.css} +0 -0
  430. /package/dist/{styles/dock-controls → components/controls}/dark-mode-toggle.css +0 -0
  431. /package/dist/{styles/dialog-placement.css → components/dialog/placement.css} +0 -0
  432. /package/dist/{styles/dock-controls → components/dock/styles/controls}/tab-button.css +0 -0
  433. /package/dist/{styles/dock-controls → components/dock/styles/controls}/triggers.css +0 -0
  434. /package/dist/{styles/dock → components/dock/styles}/crossfade.css +0 -0
  435. /package/dist/{styles/dock → components/dock/styles}/cta-seat.css +0 -0
  436. /package/dist/{styles/dock → components/dock/styles}/fisheye.css +0 -0
  437. /package/dist/{styles/dock → components/dock/styles}/morph.css +0 -0
  438. /package/dist/{styles/dock → components/dock/styles}/search.css +0 -0
  439. /package/dist/{styles/dock → components/dock/styles}/section.css +0 -0
  440. /package/dist/{styles/dock → components/dock/styles}/shell-regions.css +0 -0
  441. /package/dist/{styles/segmented-tabs.css → components/tabs/styles/segmented.css} +0 -0
  442. /package/dist/{constants-D8lSMkOz.js → constants-DRZmNIY-.js} +0 -0
  443. /package/dist/{createContext-BQ1Gy_LB.js → createContext-FU0n5MGK.js} +0 -0
  444. /package/dist/{flow.glsl-CVqPSj8_.js → flow.glsl-DEGFGE11.js} +0 -0
  445. /package/dist/{FocusScope-BzKwhsBn.js → focus-scope-DUTKveod.js} +0 -0
  446. /package/dist/{InstrumentChassis-Dss5Tjcm.js → instrument-chassis-Cvstg4_U.js} +0 -0
  447. /package/dist/{Label-C84TaQiw.js → label-Cj38tJKG.js} +0 -0
  448. /package/dist/{menuItemVariants-DbO-Fr74.js → menuItemVariants-D6AOzzND.js} +0 -0
  449. /package/dist/{pointerFieldMappings-4VtmkOWv.js → pointerFieldMappings-CZojkgKj.js} +0 -0
  450. /package/dist/{presets-B07HzyKd.js → presets-CxeNvxuO.js} +0 -0
  451. /package/dist/{prng-B0PLRmR6.js → prng-Dz2_9RJu.js} +0 -0
  452. /package/dist/{scrollReader-DzYqPQ6V.js → scrollReader-C2oK9Hb8.js} +0 -0
  453. /package/dist/{supportsCssTimeline-Ie4xJFbD.js → supportsCssTimeline-Dz-GVxXM.js} +0 -0
  454. /package/dist/{Toaster-C_-WeU9W.js → toast-kAbchIN2.js} +0 -0
  455. /package/dist/{useControlSize-DJwe-7ZQ.js → useControlSize-CFfOk8I-.js} +0 -0
  456. /package/dist/{useDocumentVisibility-CpJGUgcJ.js → useDocumentVisibility-YeBDGqtI.js} +0 -0
  457. /package/dist/{useDragMorph-65ihHePq.js → useDragMorph-7ygF9O0m.js} +0 -0
  458. /package/dist/{useDragVelocity-BWcNMCux.js → useDragVelocity-CbMZEBaC.js} +0 -0
  459. /package/dist/{useFuzzySearch-KslRxiJY.js → useFuzzySearch-BOgep7RE.js} +0 -0
  460. /package/dist/{useLeadTrail-DOH4XkL1.js → useLeadTrail-BYu8dq4G.js} +0 -0
  461. /package/dist/{usePointerVelocityField-CwXyeW0Z.js → usePointerVelocityField-BdvnO0py.js} +0 -0
  462. /package/dist/{useResizeObserver-DDuoBeBo.js → useResizeObserver-BcUTquV7.js} +0 -0
  463. /package/dist/{useResolveTokenColor-DVT5kwv6.js → useResolveTokenColor-C07e-qaT.js} +0 -0
  464. /package/dist/{useRoutePointer-DL7I0gY4.js → useRoutePointer-BDNMFN73.js} +0 -0
  465. /package/dist/{useSpringMount-CNvvgGiC.js → useSpringMount-C6-DBx4e.js} +0 -0
  466. /package/dist/{useTimer-CkDV8SC2.js → useTimer-D8koDvJS.js} +0 -0
  467. /package/dist/{useUserInvalidAria-Bkruei7M.js → useUserInvalidAria-Cr4nR3tu.js} +0 -0
  468. /package/dist/{vReveal-DUmiEkX_.js → vReveal-DZfWl9XI.js} +0 -0
  469. /package/dist/{vSpecular-DlYN0UZy.js → vSpecular-CQFmLNzA.js} +0 -0
  470. /package/dist/{writeVelocityWeight-D1rvdxJu.js → writeVelocityWeight-D_AcvTsE.js} +0 -0
package/dist/blob.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { t as e } from "./_plugin-vue_export-helper-C1je1s0u.js";
2
- import { t } from "./useResolveTokenColor-DVT5kwv6.js";
3
- import { t as n } from "./usePointerVelocityField-CwXyeW0Z.js";
4
- import { t as r } from "./useIntersectionPause-Cmt5Tnv9.js";
5
- import { a as i, n as a, o, r as s, s as c, t as l } from "./procedural-color.wgsl-ByduxnzV.js";
6
- import { a as u, t as d } from "./useGpuSubstrate-DcY584kE.js";
7
- import { n as f, t as p } from "./compile-C55K3P9g.js";
8
- import { s as m, t as h } from "./color-Bp5jmv4Z.js";
9
- import { a as g, i as _, n as v, o as y, r as b, t as x } from "./presets-B07HzyKd.js";
10
- import { n as S, t as C } from "./prng-B0PLRmR6.js";
11
- import { computed as w, createElementBlock as T, createElementVNode as E, defineComponent as D, inject as O, normalizeStyle as k, onScopeDispose as A, onUnmounted as j, openBlock as M, readonly as N, ref as P, useTemplateRef as F, watch as I } from "vue";
12
- import { SpringProgress as L } from "@mkbabb/keyframes.js";
2
+ import { t } from "./useResolveTokenColor-C07e-qaT.js";
3
+ import { t as n } from "./usePointerVelocityField-BdvnO0py.js";
4
+ import { t as r } from "./useIntersectionPause-B-dbxl9w.js";
5
+ import { a as i, i as a, n as o, o as s, r as c, t as l } from "./presets-CxeNvxuO.js";
6
+ import { cssToOklch as u, oklchToGammaRgb as d } from "./color.js";
7
+ import { a as f, d as p, f as m, l as h, n as g, r as _, t as v, u as y } from "./procedural-color.wgsl-B9mLK7v0.js";
8
+ import { a as b } from "./rendererStatus-C2-zC2Q-.js";
9
+ import { n as x, t as S } from "./compile-DK3Fri1B.js";
10
+ import { n as C, t as w } from "./prng-Dz2_9RJu.js";
11
+ import { computed as T, createCommentVNode as E, createElementBlock as D, createElementVNode as O, defineComponent as k, inject as A, normalizeStyle as j, onScopeDispose as M, onUnmounted as N, openBlock as P, readonly as F, ref as I, shallowRef as L, useTemplateRef as R, watch as z } from "vue";
12
+ import { SpringProgress as B } from "@mkbabb/keyframes.js";
13
13
  //#region src/components/blob/constants.ts
14
- var R = 1 / 1.6, z = {
14
+ var V = 1 / 1.6, H = {
15
15
  idle: {
16
16
  valence: 0,
17
17
  arousal: .35
@@ -32,48 +32,48 @@ var R = 1 / 1.6, z = {
32
32
  valence: .7,
33
33
  arousal: 1
34
34
  }
35
- }, B = (e, t, n) => e + (t - e) * n;
36
- function V({ valence: e, arousal: t }) {
35
+ }, U = (e, t, n) => e + (t - e) * n;
36
+ function W({ valence: e, arousal: t }) {
37
37
  return {
38
- orbitSpeedScale: B(.4, 2.2, t),
39
- wobbleScale: B(.5, 2, t),
40
- pulseFreq: B(.15, 1.5, t),
41
- pulseAmp: B(.008, .05, t),
42
- noiseAmp: B(.015, .045, t),
43
- hueRange: B(3, 25, t * .6 + (e * .5 + .5) * .4),
44
- satShift: B(-.05, .1, e * .5 + .5),
45
- brightnessShift: B(-.03, .08, e * .5 + .5),
46
- smoothK: B(.85, 1.35, t),
47
- pointerAttraction: B(-.2, .6, e * .5 + .5) * (.7 + .15 * t),
48
- mergeRate: B(2, .3, t),
49
- iridScale: B(.55, 1.35, t)
38
+ orbitSpeedScale: U(.4, 2.2, t),
39
+ wobbleScale: U(.5, 2, t),
40
+ pulseFreq: U(.15, 1.5, t),
41
+ pulseAmp: U(.008, .05, t),
42
+ noiseAmp: U(.015, .045, t),
43
+ hueRange: U(3, 25, t * .6 + (e * .5 + .5) * .4),
44
+ satShift: U(-.05, .1, e * .5 + .5),
45
+ brightnessShift: U(-.03, .08, e * .5 + .5),
46
+ smoothK: U(.85, 1.35, t),
47
+ pointerAttraction: U(-.2, .6, e * .5 + .5) * (.7 + .15 * t),
48
+ mergeRate: U(2, .3, t),
49
+ iridScale: U(.55, 1.35, t)
50
50
  };
51
51
  }
52
- var H = {
53
- idle: V(z.idle),
54
- happy: V(z.happy),
55
- curious: V(z.curious),
56
- sleepy: V(z.sleepy),
57
- excited: V(z.excited)
58
- }, U = {
52
+ var G = {
53
+ idle: W(H.idle),
54
+ happy: W(H.happy),
55
+ curious: W(H.curious),
56
+ sleepy: W(H.sleepy),
57
+ excited: W(H.excited)
58
+ }, ee = {
59
59
  idle: 1500,
60
60
  happy: 1200,
61
61
  curious: 800,
62
62
  sleepy: 2500,
63
63
  excited: 600
64
- }, ee = 6e3, W = .35, te = .85, ne = .2, re = .015, G = .02, K = .01, q = .015, J = .75, ie = 2e3, ae = .4, oe = .18, se = 5200, ce = /* @__PURE__ */ "uResolution.uTime.uBaseColor.uPointer.uPointerActive.uPointerAttraction.uPointerStrength.uBodyRadius.uPulsePhase.uPulseAmp.uNoiseAmp.uNoiseFreq.uNoiseSpeed.uWarpAmp.uSmoothK.uMerge.uStage.uMorphT.uMaxReach.uLit.uRimColor.uLightDir.uSpecStrength.uSpecShininess.uRimPower.uRimStrength.uShadow.uShadowSoftness.uIridescence.uIridHue.uIridSpeed.uSssScale.uSssPower.uCoreGlow.uHueRange.uSatShift.uBrightnessShift.uColorNoiseFreq.uColorNoiseSpeed.uStopCount.uSatCount.uSatColorActive.uTrailCount.uVelocity.uStretch".split(".");
64
+ }, te = 6e3, ne = .35, re = .85, K = .2, q = .015, ie = .02, ae = .01, oe = .015, J = .75, se = 2e3, ce = .4, le = .18, ue = 5200, de = /* @__PURE__ */ "uResolution.uTime.uBaseColor.uPointer.uPointerActive.uPointerAttraction.uPointerStrength.uBodyRadius.uPulsePhase.uPulseAmp.uNoiseAmp.uNoiseFreq.uNoiseSpeed.uWarpAmp.uSmoothK.uMerge.uStage.uMorphT.uMaxReach.uLit.uRimColor.uLightDir.uSpecStrength.uSpecShininess.uRimPower.uRimStrength.uShadow.uShadowSoftness.uIridescence.uIridHue.uIridSpeed.uSssScale.uSssPower.uCoreGlow.uHueRange.uSatShift.uBrightnessShift.uColorNoiseFreq.uColorNoiseSpeed.uStopCount.uSatCount.uSatColorActive.uTrailCount.uVelocity.uStretch".split(".");
65
65
  //#endregion
66
66
  //#region src/components/blob/composables/easing.ts
67
- function le(e) {
67
+ function fe(e) {
68
68
  return e < .5 ? 2 * e * e : 1 - 2 * (1 - e) * (1 - e);
69
69
  }
70
- function ue(e) {
70
+ function pe(e) {
71
71
  return e * e;
72
72
  }
73
- function de(e) {
73
+ function me(e) {
74
74
  return 1 - (1 - e) * (1 - e);
75
75
  }
76
- function fe(e) {
76
+ function he(e) {
77
77
  let t = e < 0 ? 0 : e > 1 ? 1 : e;
78
78
  if (t < .3) {
79
79
  let e = t / .3;
@@ -88,7 +88,7 @@ function fe(e) {
88
88
  }
89
89
  //#endregion
90
90
  //#region src/components/blob/composables/useBlobMood.ts
91
- function pe(e, t, n) {
91
+ function ge(e, t, n) {
92
92
  let r = (e, t) => e + (t - e) * n;
93
93
  return {
94
94
  orbitSpeedScale: r(e.orbitSpeedScale, t.orbitSpeedScale),
@@ -105,10 +105,10 @@ function pe(e, t, n) {
105
105
  iridScale: r(e.iridScale, t.iridScale)
106
106
  };
107
107
  }
108
- function me() {
109
- let e = P("idle"), t = P({ ...H.idle }), n = { ...H.idle }, r = { ...H.idle }, i = 0, a = 0, o = !1, s = 0, c = !1, l = !1, u = 0;
108
+ function _e() {
109
+ let e = I("idle"), t = I({ ...G.idle }), n = { ...G.idle }, r = { ...G.idle }, i = 0, a = 0, o = !1, s = 0, c = !1, l = !1, u = 0;
110
110
  function d(s, l = {}) {
111
- (l.source ?? "manual") === "manual" && (c = !0), !(s === e.value && !o) && (e.value = s, n = { ...t.value }, r = H[s], a = U[s], i = 0, o = !0);
111
+ (l.source ?? "manual") === "manual" && (c = !0), !(s === e.value && !o) && (e.value = s, n = { ...t.value }, r = G[s], a = ee[s], i = 0, o = !0);
112
112
  }
113
113
  function f(e) {
114
114
  u = e.idleMs;
@@ -125,17 +125,17 @@ function me() {
125
125
  return o || s > 0 || c && e.value !== "idle" ? !1 : !(!c && e.value !== "sleepy" && u < 6e3);
126
126
  }
127
127
  function m() {
128
- return o || s > 0 || c || e.value === "sleepy" ? Infinity : Math.max(0, ee - u);
128
+ return o || s > 0 || c || e.value === "sleepy" ? Infinity : Math.max(0, te - u);
129
129
  }
130
130
  function h(e) {
131
131
  if (s > 0 && (s = Math.max(0, s - e)), !o) return;
132
132
  i += e;
133
- let c = Math.min(i / a, 1), l = le(c);
134
- t.value = pe(n, r, l), c >= 1 && (o = !1);
133
+ let c = Math.min(i / a, 1), l = fe(c);
134
+ t.value = ge(n, r, l), c >= 1 && (o = !1);
135
135
  }
136
136
  return {
137
- currentMood: N(e),
138
- params: N(t),
137
+ currentMood: F(e),
138
+ params: F(t),
139
139
  setMood: d,
140
140
  update: f,
141
141
  tick: h,
@@ -145,17 +145,17 @@ function me() {
145
145
  }
146
146
  //#endregion
147
147
  //#region src/components/blob/composables/useBlobPointer.ts
148
- function he(e, t = {}) {
149
- let { hitRadius: n } = t, r = P({
148
+ function ve(e, t = {}) {
149
+ let { hitRadius: n } = t, r = I({
150
150
  x: 0,
151
151
  y: 0
152
- }), i = P({
152
+ }), i = I({
153
153
  x: 0,
154
154
  y: 0
155
- }), a = P(!1), o = P(0), s = 0, c = 0, l = {
155
+ }), a = I(!1), o = I(0), s = 0, c = 0, l = {
156
156
  response: .18,
157
157
  dampingFraction: 1
158
- }, u = new L(l), d = new L(l), f = Array.from({ length: 15 }, () => ({
158
+ }, u = new B(l), d = new B(l), f = Array.from({ length: 15 }, () => ({
159
159
  x: 0,
160
160
  y: 0,
161
161
  radius: 0
@@ -181,11 +181,11 @@ function he(e, t = {}) {
181
181
  a.value = !1;
182
182
  }
183
183
  let x = null;
184
- I(e, (e) => {
184
+ z(e, (e) => {
185
185
  x &&= (x(), null), e && (e.addEventListener("pointermove", y), e.addEventListener("pointerleave", b), x = () => {
186
186
  e.removeEventListener("pointermove", y), e.removeEventListener("pointerleave", b);
187
187
  });
188
- }, { immediate: !0 }), j(() => x?.());
188
+ }, { immediate: !0 }), N(() => x?.());
189
189
  function S(e = 16) {
190
190
  let t = Math.min(e, 50), n = t / 1e3;
191
191
  a.value ? D = 0 : D += Math.min(e, 50);
@@ -197,7 +197,7 @@ function he(e, t = {}) {
197
197
  x: u.velocity,
198
198
  y: d.velocity
199
199
  }, h !== 0 || g !== 0) {
200
- let e = -324 * h - 2 * W * 18 * g;
200
+ let e = -324 * h - 2 * ne * 18 * g;
201
201
  g += e * n, h += g * n, h < -.9 && (h = -.9), Math.abs(h) < 1e-4 && Math.abs(g) < 1e-4 && (h = 0, g = 0);
202
202
  }
203
203
  o.value = h;
@@ -241,14 +241,14 @@ function he(e, t = {}) {
241
241
  return !(a.value || Math.hypot(u.velocity, d.velocity) > .001 || Math.abs(u.value) > .001 || Math.abs(d.value) > .001 || m > 0 || h !== 0 || g !== 0);
242
242
  }
243
243
  return {
244
- pointer: N(r),
245
- velocity: N(i),
246
- active: N(a),
244
+ pointer: F(r),
245
+ velocity: F(i),
246
+ active: F(a),
247
247
  rawPointer: () => ({
248
248
  x: s,
249
249
  y: c
250
250
  }),
251
- pulse: N(o),
251
+ pulse: F(o),
252
252
  idleMs: () => D,
253
253
  tick: S,
254
254
  trailSources: C,
@@ -261,8 +261,8 @@ function he(e, t = {}) {
261
261
  }
262
262
  //#endregion
263
263
  //#region src/components/blob/composables/satelliteKinematics.ts
264
- function ge(e, t, n, r, i) {
265
- let a = t / 4 * Math.PI * 2 + (e() - .5) * Math.PI, o = n * (te + e() * ne), s = r * (.3 + e() * .7);
264
+ function ye(e, t, n, r, i) {
265
+ let a = t / 4 * Math.PI * 2 + (e() - .5) * Math.PI, o = n * (re + e() * K), s = r * (.3 + e() * .7);
266
266
  return {
267
267
  phase: "orbiting",
268
268
  phaseStart: i,
@@ -272,9 +272,9 @@ function ge(e, t, n, r, i) {
272
272
  phaseOffset: a,
273
273
  baseRadiusX: o * (1 - s),
274
274
  baseRadiusY: o * (1 + s),
275
- wobbleAmp1: re + e() * G,
275
+ wobbleAmp1: q + e() * ie,
276
276
  wobbleFreq1: .08 + e() * .22,
277
- wobbleAmp2: K + e() * q,
277
+ wobbleAmp2: ae + e() * oe,
278
278
  wobbleFreq2: .18 + e() * .32,
279
279
  pertXAmp: .03 + e() * .05,
280
280
  pertXFreq: .06 + e() * .18,
@@ -290,21 +290,21 @@ function ge(e, t, n, r, i) {
290
290
  snapFired: !1
291
291
  };
292
292
  }
293
- function _e(e, t, n, r) {
293
+ function be(e, t, n, r) {
294
294
  let i = (t - e.timeOrigin) / 1e3, a = e.angularSpeed * n * i + e.phaseOffset, o = r * (e.wobbleAmp1 * Math.sin(e.wobbleFreq1 * i) + e.wobbleAmp2 * Math.sin(e.wobbleFreq2 * i + 1.3));
295
295
  return {
296
296
  x: (e.baseRadiusX + o) * Math.cos(a) + e.pertXAmp * Math.sin(e.pertXFreq * i + e.pertXPhase),
297
297
  y: (e.baseRadiusY + o) * Math.sin(a) + e.pertYAmp * Math.cos(e.pertYFreq * i + e.pertYPhase)
298
298
  };
299
299
  }
300
- function ve(e, t, n, r, i) {
300
+ function xe(e, t, n, r, i) {
301
301
  e.timeOrigin = i, e.angularSpeed = .08 + t() * .16, e.phaseOffset = t() * Math.PI * 2;
302
- let a = n * (te + t() * ne), o = r * (.3 + t() * .7);
303
- e.baseRadiusX = a * (1 - o), e.baseRadiusY = a * (1 + o), e.wobbleAmp1 = re + t() * G, e.wobbleFreq1 = .08 + t() * .22, e.wobbleAmp2 = K + t() * q, e.wobbleFreq2 = .18 + t() * .32, e.pertXAmp = .03 + t() * .05, e.pertXFreq = .06 + t() * .18, e.pertXPhase = t() * Math.PI * 2, e.pertYAmp = .03 + t() * .05, e.pertYFreq = .07 + t() * .17, e.pertYPhase = t() * Math.PI * 2;
302
+ let a = n * (re + t() * K), o = r * (.3 + t() * .7);
303
+ e.baseRadiusX = a * (1 - o), e.baseRadiusY = a * (1 + o), e.wobbleAmp1 = q + t() * ie, e.wobbleFreq1 = .08 + t() * .22, e.wobbleAmp2 = ae + t() * oe, e.wobbleFreq2 = .18 + t() * .32, e.pertXAmp = .03 + t() * .05, e.pertXFreq = .06 + t() * .18, e.pertXPhase = t() * Math.PI * 2, e.pertYAmp = .03 + t() * .05, e.pertYFreq = .07 + t() * .17, e.pertYPhase = t() * Math.PI * 2;
304
304
  }
305
305
  //#endregion
306
306
  //#region src/components/blob/composables/useBlobSatellites.ts
307
- function ye(e, t, n) {
307
+ function Se(e, t, n) {
308
308
  return t + e() * (n - t);
309
309
  }
310
310
  function Y(e) {
@@ -316,8 +316,8 @@ function X(e, t, n) {
316
316
  function Z(e, t, n, r) {
317
317
  e.phase = t, e.phaseStart = n, e.phaseDuration = r;
318
318
  }
319
- function be(e, t) {
320
- let n = S(C(t + "goo")), r = [], i = [], a = [], o = -Infinity, s = e.geometry.orbitRadius, c = -1, l = null;
319
+ function Ce(e, t) {
320
+ let n = C(w(t + "goo")), r = [], i = [], a = [], o = -Infinity, s = e.geometry.orbitRadius, c = -1, l = null;
321
321
  function u() {
322
322
  let t = e.geometry.orbitRadius;
323
323
  if (t !== s && s > 0) {
@@ -328,7 +328,7 @@ function be(e, t) {
328
328
  }
329
329
  function d(t) {
330
330
  let o = e.geometry.satelliteCount;
331
- for (; r.length < o;) r.push(ge(n, r.length, e.geometry.orbitRadius, e.geometry.eccentricity, t)), i.push({
331
+ for (; r.length < o;) r.push(ye(n, r.length, e.geometry.orbitRadius, e.geometry.eccentricity, t)), i.push({
332
332
  x: 0,
333
333
  y: 0,
334
334
  radius: e.geometry.satelliteRadius,
@@ -343,30 +343,30 @@ function be(e, t) {
343
343
  }
344
344
  function f(t, s) {
345
345
  d(t), u();
346
- let f = r.length, p = s.mergeRate, m = e.geometry.satelliteRadius, h = e.satellites.mergeDuration, g = e.satellites.emergeDuration, _ = e.satellites.orbitDuration, v = e.satellites.absorbedDuration, y = e.surface.fissionAmp ?? 0, b = Math.max(0, Math.min(1, (2 - p) / 1.7)), x = Math.max(0, Math.min(1, y * (.4 + .6 * b))), S = ae - oe;
346
+ let f = r.length, p = s.mergeRate, m = e.geometry.satelliteRadius, h = e.satellites.mergeDuration, g = e.satellites.emergeDuration, _ = e.satellites.orbitDuration, v = e.satellites.absorbedDuration, y = e.surface.fissionAmp ?? 0, b = Math.max(0, Math.min(1, (2 - p) / 1.7)), x = Math.max(0, Math.min(1, y * (.4 + .6 * b))), S = ce - le;
347
347
  for (let u = 0; u < f; u++) {
348
348
  let d = r[u], f = t - d.phaseStart, y = Y(d.phaseDuration > 0 ? f / d.phaseDuration : 1);
349
349
  switch (d.phase) {
350
350
  case "orbiting":
351
- if (y >= 1) if (t - o < 3e3 * p) d.phaseStart = t, d.phaseDuration = ye(n, _[0], _[1]);
352
- else if (x > 0 && c < 0 && n() < x * .75) d.phaseOffset = d.angularSpeed * s.orbitSpeedScale * ((t - d.timeOrigin) / 1e3) + d.phaseOffset, d.timeOrigin = t, d.fissioning = !0, d.snapFired = !1, c = u, Z(d, "fissioning", t, se), o = t;
351
+ if (y >= 1) if (t - o < 3e3 * p) d.phaseStart = t, d.phaseDuration = Se(n, _[0], _[1]);
352
+ else if (x > 0 && c < 0 && n() < x * .75) d.phaseOffset = d.angularSpeed * s.orbitSpeedScale * ((t - d.timeOrigin) / 1e3) + d.phaseOffset, d.timeOrigin = t, d.fissioning = !0, d.snapFired = !1, c = u, Z(d, "fissioning", t, ue), o = t;
353
353
  else {
354
- let e = _e(d, t, s.orbitSpeedScale, s.wobbleScale);
354
+ let e = be(d, t, s.orbitSpeedScale, s.wobbleScale);
355
355
  d.startX = e.x, d.startY = e.y;
356
356
  let n = Math.hypot(e.x, e.y), r = n > .01 ? .08 / n : 0;
357
357
  d.endX = e.x * r, d.endY = e.y * r, Z(d, "merging", t, h), o = t;
358
358
  }
359
359
  break;
360
360
  case "fissioning":
361
- y >= 1 && (d.fissioning = !1, c === u && (c = -1), d.timeOrigin = t, Z(d, "orbiting", t, ye(n, _[0], _[1])));
361
+ y >= 1 && (d.fissioning = !1, c === u && (c = -1), d.timeOrigin = t, Z(d, "orbiting", t, Se(n, _[0], _[1])));
362
362
  break;
363
363
  case "merging":
364
- y >= 1 && Z(d, "absorbed", t, ye(n, v[0], v[1]));
364
+ y >= 1 && Z(d, "absorbed", t, Se(n, v[0], v[1]));
365
365
  break;
366
366
  case "absorbed":
367
367
  if (y >= 1) {
368
- ve(d, n, e.geometry.orbitRadius, e.geometry.eccentricity, t);
369
- let r = _e(d, t + 3e3, s.orbitSpeedScale, s.wobbleScale);
368
+ xe(d, n, e.geometry.orbitRadius, e.geometry.eccentricity, t);
369
+ let r = be(d, t + 3e3, s.orbitSpeedScale, s.wobbleScale);
370
370
  d.endX = r.x, d.endY = r.y;
371
371
  let i = Math.hypot(r.x, r.y), a = i > .01 ? .08 / i : 0;
372
372
  d.startX = r.x * a, d.startY = r.y * a, Z(d, "emerging", t, g);
@@ -375,23 +375,23 @@ function be(e, t) {
375
375
  case "emerging":
376
376
  if (y >= 1) {
377
377
  let e = a[u];
378
- e.x = d.endX, e.y = d.endY, e.start = t, d.timeOrigin = t, d.phaseOffset = Math.atan2(d.endY, d.endX), Z(d, "orbiting", t, ye(n, _[0], _[1]));
378
+ e.x = d.endX, e.y = d.endY, e.start = t, d.timeOrigin = t, d.phaseOffset = Math.atan2(d.endY, d.endX), Z(d, "orbiting", t, Se(n, _[0], _[1]));
379
379
  }
380
380
  break;
381
381
  }
382
382
  let b, C, w, T;
383
383
  switch (d.phase) {
384
384
  case "orbiting": {
385
- let e = _e(d, t, s.orbitSpeedScale, s.wobbleScale), n = a[u], r = t - n.start;
385
+ let e = be(d, t, s.orbitSpeedScale, s.wobbleScale), n = a[u], r = t - n.start;
386
386
  if (n.start > 0 && r < 2e3) {
387
- let t = Y(r / ie), i = t * t * (3 - 2 * t);
387
+ let t = Y(r / se), i = t * t * (3 - 2 * t);
388
388
  b = X(n.x, e.x, i), C = X(n.y, e.y, i);
389
389
  } else b = e.x, C = e.y;
390
390
  w = J, T = 1;
391
391
  break;
392
392
  }
393
393
  case "merging": {
394
- let e = ue(Y((t - d.phaseStart) / d.phaseDuration));
394
+ let e = pe(Y((t - d.phaseStart) / d.phaseDuration));
395
395
  b = X(d.startX, d.endX, e), C = X(d.startY, d.endY, e);
396
396
  let n = Y((t - d.phaseStart) / d.phaseDuration);
397
397
  w = n > .85 ? X(J, 0, (n - .85) / .15) : J, T = X(1, .65, e);
@@ -401,14 +401,14 @@ function be(e, t) {
401
401
  b = 0, C = 0, w = 0, T = .5;
402
402
  break;
403
403
  case "emerging": {
404
- let e = de(Y((t - d.phaseStart) / d.phaseDuration));
404
+ let e = me(Y((t - d.phaseStart) / d.phaseDuration));
405
405
  b = X(d.startX, d.endX, e), C = X(d.startY, d.endY, e);
406
406
  let n = Y((t - d.phaseStart) / d.phaseDuration);
407
407
  w = n < .1 ? X(0, J, n / .1) : J, T = X(.65, 1, e);
408
408
  break;
409
409
  }
410
410
  case "fissioning": {
411
- let e = Y((t - d.phaseStart) / d.phaseDuration), n = fe(e), r = oe + S * n, i = _e(d, t, s.orbitSpeedScale, s.wobbleScale), a = Math.hypot(i.x, i.y), o = a > 1e-4 ? i.x / a : Math.cos(d.phaseOffset), c = a > 1e-4 ? i.y / a : Math.sin(d.phaseOffset);
411
+ let e = Y((t - d.phaseStart) / d.phaseDuration), n = he(e), r = le + S * n, i = be(d, t, s.orbitSpeedScale, s.wobbleScale), a = Math.hypot(i.x, i.y), o = a > 1e-4 ? i.x / a : Math.cos(d.phaseOffset), c = a > 1e-4 ? i.y / a : Math.sin(d.phaseOffset);
412
412
  b = o * r, C = c * r, w = J, T = X(.78, 1, Y(n)), !d.snapFired && e >= .42 && (d.snapFired = !0, l?.(Math.min(.4, .18 + .22 * x)));
413
413
  break;
414
414
  }
@@ -421,7 +421,7 @@ function be(e, t) {
421
421
  for (let e of r) e.phaseOffset += (n() - .5) * .6, e.pertXPhase += n() * Math.PI, e.pertYPhase += n() * Math.PI;
422
422
  }
423
423
  function m(e) {
424
- n = S(C(e + "goo"));
424
+ n = C(w(e + "goo"));
425
425
  }
426
426
  function h(e) {
427
427
  l = e;
@@ -450,7 +450,7 @@ function be(e, t) {
450
450
  }
451
451
  //#endregion
452
452
  //#region src/components/blob/shaders/metaball.vert.ts
453
- var xe = "#version 300 es\n\nin vec2 aPosition;\nout vec2 vUv;\n\nvoid main() {\n vUv = 0.5 * (aPosition + 1.0);\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}", Se = "// --- SDF ---\n\nfloat sdCircle(vec2 p, vec2 center, float radius) {\n return length(p - center) - radius;\n}\n\n// AX.W15 — the VALUE+GRADIENT circle: returns vec3(d, dd/dx, dd/dy). The circle\n// gradient is the UNIT radial direction (p - center)/length(p - center) (the\n// eikonal property holds EXACTLY for a circle), guarded at the degenerate centre.\n// This is the keystone of the analytic-gradient smin: carrying the gradient\n// through the scene field DELETES the per-pixel 4-tap normal (4 full sceneDist\n// evals, each running 3-octave FBM + the sat/trail loops).\nvec3 sdgCircle(vec2 p, vec2 center, float radius) {\n vec2 d = p - center;\n float len = length(d);\n vec2 grad = len > 1e-6 ? d / len : vec2(0.0, 1.0);\n return vec3(len - radius, grad);\n}\n\n// IQ 2024 quadratic-polynomial smin, NORMALIZED so k is a blend band in distance\n// units. The k *= 4.0 pre-scale makes the h*h*k*0.25 poly's effective blend width\n// equal to k (the un-normalized form's width was 0.25*k).\nfloat sminQuadratic(float a, float b, float k) {\n k *= 4.0;\n float h = max(k - abs(a - b), 0.0) / k;\n return min(a, b) - h * h * k * 0.25;\n}\n\n// IQ circular smin — a quarter-circle fillet at the seam (rounder than the\n// quadratic). The k *= 1.0/(1.0-sqrt(0.5)) factor normalizes k to the same\n// blend-band units so the merge axis swaps shape without re-tuning uSmoothK.\nfloat sminCircular(float a, float b, float k) {\n k *= 1.0 / (1.0 - sqrt(0.5));\n float h = max(k - abs(a - b), 0.0) / k;\n return min(a, b) - k * 0.5 * (1.0 + h - sqrt(1.0 - h * (h - 2.0)));\n}\n\n// Config-gated merge dispatch — uMerge 0 = quadratic, 1 = circular.\nfloat smin(float a, float b, float k) {\n if (uMerge > 0.5) return sminCircular(a, b, k);\n return sminQuadratic(a, b, k);\n}\n\n// AX.W15 — the VALUE+GRADIENT smin. a/b are vec3(dist, grad.xy); the blended\n// gradient is mix(a.yz, b.yz, w) with the interpolation weight w the distance\n// blend uses (IQ's vec2-smin insight). This propagates the analytic gradient\n// through the merge so the surface normal reads the field gradient DIRECTLY — no\n// finite-difference tap. The blend weight matches each variant.\nvec3 sminQuadraticG(vec3 a, vec3 b, float k) {\n k *= 4.0;\n float h = max(k - abs(a.x - b.x), 0.0) / k;\n float m = h * h * k * 0.25;\n // h-weight that selects which surface dominates (0 → a, 1 → b).\n float w = (a.x < b.x) ? 0.5 * h * h : 1.0 - 0.5 * h * h;\n float dist = min(a.x, b.x) - m;\n vec2 grad = mix(a.yz, b.yz, w);\n return vec3(dist, grad);\n}\n\nvec3 sminCircularG(vec3 a, vec3 b, float k) {\n k *= 1.0 / (1.0 - sqrt(0.5));\n float h = max(k - abs(a.x - b.x), 0.0) / k;\n float m = k * 0.5 * (1.0 + h - sqrt(1.0 - h * (h - 2.0)));\n float w = (a.x < b.x) ? 0.5 * h : 1.0 - 0.5 * h;\n float dist = min(a.x, b.x) - m;\n vec2 grad = mix(a.yz, b.yz, w);\n return vec3(dist, grad);\n}\n\nvec3 sminG(vec3 a, vec3 b, float k) {\n if (uMerge > 0.5) return sminCircularG(a, b, k);\n return sminQuadraticG(a, b, k);\n}", Ce = "// --- Noise ---\n\nfloat hash21(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\n\n// IQ analytic-derivative gradient noise — value in .x, ANALYTIC gradient\n// (d/dx, d/dy) in .yz, from one eval. The quintic fade has a continuous 2nd\n// derivative so the gradient is smooth (a cubic smoothstep fade would crease it).\n// (Inigo Quilez, https://iquilezles.org/articles/gradientnoise/.)\nvec3 noised(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n\n // Quintic fade + its derivative.\n vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n vec2 du = 30.0 * f * f * (f * (f - 2.0) + 1.0);\n\n // Per-corner gradient vectors from the hash (centred to [-1, 1]).\n vec2 ga = -1.0 + 2.0 * vec2(hash21(i + vec2(0.0, 0.0)), hash21(i + vec2(7.3, 0.0)));\n vec2 gb = -1.0 + 2.0 * vec2(hash21(i + vec2(1.0, 0.0)), hash21(i + vec2(8.3, 0.0)));\n vec2 gc = -1.0 + 2.0 * vec2(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(7.3, 1.0)));\n vec2 gd = -1.0 + 2.0 * vec2(hash21(i + vec2(1.0, 1.0)), hash21(i + vec2(8.3, 1.0)));\n\n float va = dot(ga, f - vec2(0.0, 0.0));\n float vb = dot(gb, f - vec2(1.0, 0.0));\n float vc = dot(gc, f - vec2(0.0, 1.0));\n float vd = dot(gd, f - vec2(1.0, 1.0));\n\n // Value, remapped to [0,1] so it drops in for the prior valueNoise.\n float n = va + u.x * (vb - va) + u.y * (vc - va) + u.x * u.y * (va - vb - vc + vd);\n float value = 0.5 + 0.5 * n;\n\n // Analytic gradient (chain rule through the bilinear blend + the fade).\n vec2 grad =\n ga + u.x * (gb - ga) + u.y * (gc - ga) + u.x * u.y * (ga - gb - gc + gd) +\n du * (vec2(u.y, u.x) * (va - vb - vc + vd) + vec2(vb, vc) - va);\n return vec3(value, 0.5 * grad);\n}\n\n// Rotated-octave FBM over the analytic gradient noise: a fixed ~0.5 rad 2x2\n// rotation between octaves breaks the axis-aligned banding. The rotation CONSTANT\n// is spliced from the shared chunk (AV.W2 — the one FBM_ROT); the loops below\n// stay blob-local (param octaves + the LIQUID lacunarity/persistence, per §3a).", we = 1.8, Te = .42, Ee = `float fbm(vec2 p, int octaves) {
453
+ var we = "#version 300 es\n\nin vec2 aPosition;\nout vec2 vUv;\n\nvoid main() {\n vUv = 0.5 * (aPosition + 1.0);\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}", Te = "// --- SDF ---\n\nfloat sdCircle(vec2 p, vec2 center, float radius) {\n return length(p - center) - radius;\n}\n\n// AX.W15 — the VALUE+GRADIENT circle: returns vec3(d, dd/dx, dd/dy). The circle\n// gradient is the UNIT radial direction (p - center)/length(p - center) (the\n// eikonal property holds EXACTLY for a circle), guarded at the degenerate centre.\n// This is the keystone of the analytic-gradient smin: carrying the gradient\n// through the scene field DELETES the per-pixel 4-tap normal (4 full sceneDist\n// evals, each running 3-octave FBM + the sat/trail loops).\nvec3 sdgCircle(vec2 p, vec2 center, float radius) {\n vec2 d = p - center;\n float len = length(d);\n vec2 grad = len > 1e-6 ? d / len : vec2(0.0, 1.0);\n return vec3(len - radius, grad);\n}\n\n// IQ 2024 quadratic-polynomial smin, NORMALIZED so k is a blend band in distance\n// units. The k *= 4.0 pre-scale makes the h*h*k*0.25 poly's effective blend width\n// equal to k (the un-normalized form's width was 0.25*k).\nfloat sminQuadratic(float a, float b, float k) {\n k *= 4.0;\n float h = max(k - abs(a - b), 0.0) / k;\n return min(a, b) - h * h * k * 0.25;\n}\n\n// IQ circular smin — a quarter-circle fillet at the seam (rounder than the\n// quadratic). The k *= 1.0/(1.0-sqrt(0.5)) factor normalizes k to the same\n// blend-band units so the merge axis swaps shape without re-tuning uSmoothK.\nfloat sminCircular(float a, float b, float k) {\n k *= 1.0 / (1.0 - sqrt(0.5));\n float h = max(k - abs(a - b), 0.0) / k;\n return min(a, b) - k * 0.5 * (1.0 + h - sqrt(1.0 - h * (h - 2.0)));\n}\n\n// Config-gated merge dispatch — uMerge 0 = quadratic, 1 = circular.\nfloat smin(float a, float b, float k) {\n if (uMerge > 0.5) return sminCircular(a, b, k);\n return sminQuadratic(a, b, k);\n}\n\n// AX.W15 — the VALUE+GRADIENT smin. a/b are vec3(dist, grad.xy); the blended\n// gradient is mix(a.yz, b.yz, w) with the interpolation weight w the distance\n// blend uses (IQ's vec2-smin insight). This propagates the analytic gradient\n// through the merge so the surface normal reads the field gradient DIRECTLY — no\n// finite-difference tap. The blend weight matches each variant.\nvec3 sminQuadraticG(vec3 a, vec3 b, float k) {\n k *= 4.0;\n float h = max(k - abs(a.x - b.x), 0.0) / k;\n float m = h * h * k * 0.25;\n // h-weight that selects which surface dominates (0 → a, 1 → b).\n float w = (a.x < b.x) ? 0.5 * h * h : 1.0 - 0.5 * h * h;\n float dist = min(a.x, b.x) - m;\n vec2 grad = mix(a.yz, b.yz, w);\n return vec3(dist, grad);\n}\n\nvec3 sminCircularG(vec3 a, vec3 b, float k) {\n k *= 1.0 / (1.0 - sqrt(0.5));\n float h = max(k - abs(a.x - b.x), 0.0) / k;\n float m = k * 0.5 * (1.0 + h - sqrt(1.0 - h * (h - 2.0)));\n float w = (a.x < b.x) ? 0.5 * h : 1.0 - 0.5 * h;\n float dist = min(a.x, b.x) - m;\n vec2 grad = mix(a.yz, b.yz, w);\n return vec3(dist, grad);\n}\n\nvec3 sminG(vec3 a, vec3 b, float k) {\n if (uMerge > 0.5) return sminCircularG(a, b, k);\n return sminQuadraticG(a, b, k);\n}", Ee = "// --- Noise ---\n\nfloat hash21(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\n\n// IQ analytic-derivative gradient noise — value in .x, ANALYTIC gradient\n// (d/dx, d/dy) in .yz, from one eval. The quintic fade has a continuous 2nd\n// derivative so the gradient is smooth (a cubic smoothstep fade would crease it).\n// (Inigo Quilez, https://iquilezles.org/articles/gradientnoise/.)\nvec3 noised(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n\n // Quintic fade + its derivative.\n vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n vec2 du = 30.0 * f * f * (f * (f - 2.0) + 1.0);\n\n // Per-corner gradient vectors from the hash (centred to [-1, 1]).\n vec2 ga = -1.0 + 2.0 * vec2(hash21(i + vec2(0.0, 0.0)), hash21(i + vec2(7.3, 0.0)));\n vec2 gb = -1.0 + 2.0 * vec2(hash21(i + vec2(1.0, 0.0)), hash21(i + vec2(8.3, 0.0)));\n vec2 gc = -1.0 + 2.0 * vec2(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(7.3, 1.0)));\n vec2 gd = -1.0 + 2.0 * vec2(hash21(i + vec2(1.0, 1.0)), hash21(i + vec2(8.3, 1.0)));\n\n float va = dot(ga, f - vec2(0.0, 0.0));\n float vb = dot(gb, f - vec2(1.0, 0.0));\n float vc = dot(gc, f - vec2(0.0, 1.0));\n float vd = dot(gd, f - vec2(1.0, 1.0));\n\n // Value, remapped to [0,1] so it drops in for the prior valueNoise.\n float n = va + u.x * (vb - va) + u.y * (vc - va) + u.x * u.y * (va - vb - vc + vd);\n float value = 0.5 + 0.5 * n;\n\n // Analytic gradient (chain rule through the bilinear blend + the fade).\n vec2 grad =\n ga + u.x * (gb - ga) + u.y * (gc - ga) + u.x * u.y * (ga - gb - gc + gd) +\n du * (vec2(u.y, u.x) * (va - vb - vc + vd) + vec2(vb, vc) - va);\n return vec3(value, 0.5 * grad);\n}\n\n// Rotated-octave FBM over the analytic gradient noise: a fixed ~0.5 rad 2x2\n// rotation between octaves breaks the axis-aligned banding. The rotation CONSTANT\n// is spliced from the shared chunk (AV.W2 — the one FBM_ROT); the loops below\n// stay blob-local (param octaves + the LIQUID lacunarity/persistence, per §3a).", De = 1.8, Oe = .42, ke = `float fbm(vec2 p, int octaves) {
454
454
  float value = 0.0;
455
455
  float amp = 0.5;
456
456
  float freq = 1.0;
@@ -458,8 +458,8 @@ var xe = "#version 300 es\n\nin vec2 aPosition;\nout vec2 vUv;\n\nvoid main() {\
458
458
  if (i >= octaves) break;
459
459
  value += amp * noised(p * freq).x;
460
460
  p = FBM_ROT * p;
461
- freq *= ${we.toFixed(1)};
462
- amp *= ${Te.toFixed(2)};
461
+ freq *= ${De.toFixed(1)};
462
+ amp *= ${Oe.toFixed(2)};
463
463
  }
464
464
  return value;
465
465
  }
@@ -486,8 +486,8 @@ vec3 fbmG(vec2 p, int octaves) {
486
486
  // d(value)/dp = amp · freq · (R^i)^T · noised.yz (the rotated chain rule).
487
487
  grad += amp * freq * (transpose(rotAccum) * n.yz);
488
488
  pp = FBM_ROT * pp;
489
- freq *= ${we.toFixed(1)};
490
- amp *= ${Te.toFixed(2)};
489
+ freq *= ${De.toFixed(1)};
490
+ amp *= ${Oe.toFixed(2)};
491
491
  rotAccum = FBM_ROT * rotAccum;
492
492
  }
493
493
  return vec3(value, grad);
@@ -502,9 +502,9 @@ vec3 fbmWarpedG(vec2 p, int octaves, float warpAmp) {
502
502
  vec2 q = vec2(fbm(p + vec2(0.0, 0.0), octaves), fbm(p + vec2(5.2, 1.3), octaves));
503
503
  return fbmG(p + warpAmp * (q - 0.5), octaves);
504
504
  }
505
- `, De = "// Edit #4's gamut step — hue-preserving inward chroma clamp. If the linear result\n// is out of [0,1], bisect chroma toward 0 (L + h fixed) until in gamut. Preserves\n// hue exactly (only C shrinks). 16 steps resolve C to < 2^-16 of its span.\nbool inGamut(vec3 lin) {\n return all(greaterThanEqual(lin, vec3(0.0))) && all(lessThanEqual(lin, vec3(1.0)));\n}\nvec3 gamutClampOklch(vec3 lch) {\n vec3 lin = oklabToLinearSrgb(oklchToOklab(lch));\n if (inGamut(lin)) return lch;\n float lo = 0.0;\n float hi = lch.y;\n for (int i = 0; i < 16; i++) {\n float mid = 0.5 * (lo + hi);\n vec3 test = vec3(lch.x, mid, lch.z);\n if (inGamut(oklabToLinearSrgb(oklchToOklab(test)))) {\n lo = mid;\n } else {\n hi = mid;\n }\n }\n return vec3(lch.x, lo, lch.z);\n}", Oe = "#version 300 es\nprecision highp float;\n\nin vec2 vUv;\nout vec4 fragColor;\n\nuniform vec2 uResolution;\nuniform float uTime;\nuniform vec3 uBaseColor;\n\n// Multi-stop palette (W11.b) — 2-4 in-family OKLCh stops (uploaded GAMMA sRGB, like\n// uBaseColor). uStopCount <= 1 falls back to uBaseColor (the single-color default,\n// zero regression). MAX_BLOB_STOPS is a compile-time #define.\n#define MAX_BLOB_STOPS 4\nuniform int uStopCount;\nuniform vec3 uPalette[MAX_BLOB_STOPS];\n\n// Pointer\nuniform vec2 uPointer;\nuniform float uPointerActive;\nuniform float uPointerAttraction;\nuniform float uPointerStrength;\n\n// Main body\nuniform float uBodyRadius;\n\n// Pulsation\nuniform float uPulsePhase;\nuniform float uPulseAmp;\n\n// Surface noise\nuniform float uNoiseAmp;\nuniform float uNoiseFreq;\nuniform float uNoiseSpeed;\n\n// Gooey\nuniform float uSmoothK;\nuniform float uMerge; // 0 = quadratic smin, 1 = circular smin (rounder menisci)\n\n// BC.W-GOOBLOB-PLAIN — the STAGE-1 gate. 1.0 = the plain shadowless lightless\n// fill-only floor (variant=\"blob\"); 0.0 = the full lit pipeline (variant=\"meatball\" /\n// STAGE 2). The WebGL2 fallback transcribes the SAME stripped branch the WGSL primary\n// gates (research/viz/goo-blob.md §5 — the GLSL twin).\n// BD.W-GOO-CAROUSEL-DECK — uStage is now DERIVED from uMorphT (uStage = uMorphT<=0 ?\n// 1 : 0) at upload; the SHADING morph (below) reads uMorphT directly.\nuniform float uStage;\n\n// BD.W-GOO-CAROUSEL-DECK — the blob to meatball SHADING-MORPH scalar. 0.0 = the flat blob\n// fill (byte-identical to the STAGE-1 floor), 1.0 = the fully-dressed lit meatball; the\n// in-between LERPS the surface shading (NOT the geometry — the smin field is shared). The\n// renderer resolves it from config.morphT (variant to endpoint back-compat: blob to 0,\n// meatball to 1). A consumer ANIMATING morphT 0 to 1 gets the live morph.\nuniform float uMorphT;\n\n// AX.W16 (arm 5) — the PRE-FBM bounding-discard radius (UV space). main() early-outs\n// to a transparent write for any fragment OUTSIDE this radius BEFORE the two 3-octave\n// FBM calls + the OKLCh round-trip. The renderer uploads it PADDED by every\n// outward-expanding term (body + eccentric orbit + sat radius + smin band + FBM edge\n// amplitude + click-pulse + a lean/squash safety pad) so it NEVER clips the wet\n// meniscus (IQ: inflate the bound to match any outward op).\nuniform float uMaxReach;\n\n// Membrane — domain-warp strength on the FBM edge displacement (0 = plain fbm).\nuniform float uWarpAmp;\n\n// Lit glass surface (W9.b) — gated behind uLit so the flat fill stays default.\nuniform float uLit; // 0 = flat fill (default), 1 = lit droplet\nuniform vec3 uRimColor; // Fresnel rim tint (GAMMA sRGB, via the /color leaf)\nuniform vec3 uLightDir; // normalized light direction (x, y, z)\nuniform float uSpecStrength; // Blinn-Phong specular weight\nuniform float uSpecShininess; // specular exponent (16-64, tight glint)\nuniform float uRimPower; // Fresnel/Schlick exponent (~2-3)\nuniform float uRimStrength; // Fresnel rim weight\n\n// BC.W-GOOBLOB-MEATBALL — the procedural 2D SDF soft-shadow march (T2, the GLSL twin of\n// the WGSL res.z/res.w lanes). uShadow gates the IQ rmshadows soft contact shadow that\n// FOLLOWS the irregular silhouette; uShadowSoftness is the penumbra hardness (4-48).\nuniform float uShadow; // 0 = no shadow, 1 = the soft contact shadow ON\nuniform float uShadowSoftness; // penumbra hardness (inverse light-source size, 4-48)\n\n// Iridescence + fake subsurface (W11.a) — translucent-gel read.\nuniform float uIridescence; // warm-pearl rim sheen weight (0 = off)\nuniform float uIridHue; // base hue (radians) the cosine palette biases toward (warm)\nuniform float uIridSpeed; // animated-thickness scroll for the iridescent t\nuniform float uSssScale; // fast-SSS back-light weight\nuniform float uSssPower; // fast-SSS exponent\nuniform float uCoreGlow; // thickness-driven inner-luminosity lift\n\n// Color perturbation (perceptually uniform — OKLCh L/C/h)\nuniform float uHueRange; // degrees of hue swing (converted to radians)\nuniform float uSatShift; // OKLCh chroma swing\nuniform float uBrightnessShift; // OKLCh lightness bias\nuniform float uColorNoiseFreq;\nuniform float uColorNoiseSpeed;\n\n// Satellites (max 4)\n#define MAX_SATS 4\nuniform int uSatCount;\nuniform vec2 uSatPos[MAX_SATS];\nuniform float uSatRadius[MAX_SATS];\nuniform float uSatOpacity[MAX_SATS];\n\n// F9.R1 (BG.W-BLOB-SATELLITE-SHADE) — the per-satellite EXPLICIT-SHADE seam (the GL\n// color-seam widen the value.js hero blob asked for; the BA-VJS-5 / C-1 residual, the\n// W-GOO-REDRESS arm-B book discharged). uSatColorActive == 0 is the DEFAULT (the derived\n// palette shade — byte-identical to HEAD): blendSatColor() early-returns and touches\n// nothing. When a consumer supplies explicit per-satellite shades (uSatColor[i], GAMMA\n// sRGB, at uSatColorAmt[i] weight — typically 1) the fragment blends the base palette\n// OKLCh toward each satellite's shade, weighted by that satellite's smin-field proximity\n// at this pixel. The body keeps the derived base (the ask is per-SATELLITE).\nuniform int uSatColorActive;\nuniform vec3 uSatColor[MAX_SATS];\nuniform float uSatColorAmt[MAX_SATS];\n\n// Pointer trail (W10) — a decaying-radius pseudopod toward the cursor. uTrail is a\n// COMPILE-TIME-SIZED array (GLSL ES 3.00 forbids a uniform-sized array) with a\n// DYNAMIC break on uTrailCount, mirroring the satellite loop. Later samples paint\n// smaller metaballs (r *= 1 - i/N) so the trail tapers into a tail.\n#define TRAIL_N 15\nuniform int uTrailCount;\nuniform vec2 uTrailPos[TRAIL_N];\nuniform float uTrailRadius[TRAIL_N];\n\n// Velocity-driven volume-preserving squash-and-stretch (W10).\nuniform vec2 uVelocity; // smoothed pointer velocity (motion direction + speed)\nuniform float uStretch; // squash-stretch magnitude (0 = off)\n\nconst float PI = 3.141592653589793;\n", Q = "\n", ke = Oe + Q + Ce + Q + `${i}
505
+ `, Ae = "// Edit #4's gamut step — hue-preserving inward chroma clamp. If the linear result\n// is out of [0,1], bisect chroma toward 0 (L + h fixed) until in gamut. Preserves\n// hue exactly (only C shrinks). 16 steps resolve C to < 2^-16 of its span.\nbool inGamut(vec3 lin) {\n return all(greaterThanEqual(lin, vec3(0.0))) && all(lessThanEqual(lin, vec3(1.0)));\n}\nvec3 gamutClampOklch(vec3 lch) {\n vec3 lin = oklabToLinearSrgb(oklchToOklab(lch));\n if (inGamut(lin)) return lch;\n float lo = 0.0;\n float hi = lch.y;\n for (int i = 0; i < 16; i++) {\n float mid = 0.5 * (lo + hi);\n vec3 test = vec3(lch.x, mid, lch.z);\n if (inGamut(oklabToLinearSrgb(oklchToOklab(test)))) {\n lo = mid;\n } else {\n hi = mid;\n }\n }\n return vec3(lch.x, lo, lch.z);\n}", je = "#version 300 es\nprecision highp float;\n\nin vec2 vUv;\nout vec4 fragColor;\n\nuniform vec2 uResolution;\nuniform float uTime;\nuniform vec3 uBaseColor;\n\n// Multi-stop palette (W11.b) — 2-4 in-family OKLCh stops (uploaded GAMMA sRGB, like\n// uBaseColor). uStopCount <= 1 falls back to uBaseColor (the single-color default,\n// zero regression). MAX_BLOB_STOPS is a compile-time #define.\n#define MAX_BLOB_STOPS 4\nuniform int uStopCount;\nuniform vec3 uPalette[MAX_BLOB_STOPS];\n\n// Pointer\nuniform vec2 uPointer;\nuniform float uPointerActive;\nuniform float uPointerAttraction;\nuniform float uPointerStrength;\n\n// Main body\nuniform float uBodyRadius;\n\n// Pulsation\nuniform float uPulsePhase;\nuniform float uPulseAmp;\n\n// Surface noise\nuniform float uNoiseAmp;\nuniform float uNoiseFreq;\nuniform float uNoiseSpeed;\n\n// Gooey\nuniform float uSmoothK;\nuniform float uMerge; // 0 = quadratic smin, 1 = circular smin (rounder menisci)\n\n// BC.W-GOOBLOB-PLAIN — the STAGE-1 gate. 1.0 = the plain shadowless lightless\n// fill-only floor (variant=\"blob\"); 0.0 = the full lit pipeline (variant=\"meatball\" /\n// STAGE 2). The WebGL2 fallback transcribes the SAME stripped branch the WGSL primary\n// gates (research/viz/goo-blob.md §5 — the GLSL twin).\n// BD.W-GOO-CAROUSEL-DECK — uStage is now DERIVED from uMorphT (uStage = uMorphT<=0 ?\n// 1 : 0) at upload; the SHADING morph (below) reads uMorphT directly.\nuniform float uStage;\n\n// BD.W-GOO-CAROUSEL-DECK — the blob to meatball SHADING-MORPH scalar. 0.0 = the flat blob\n// fill (byte-identical to the STAGE-1 floor), 1.0 = the fully-dressed lit meatball; the\n// in-between LERPS the surface shading (NOT the geometry — the smin field is shared). The\n// renderer resolves it from config.morphT (variant to endpoint back-compat: blob to 0,\n// meatball to 1). A consumer ANIMATING morphT 0 to 1 gets the live morph.\nuniform float uMorphT;\n\n// AX.W16 (arm 5) — the PRE-FBM bounding-discard radius (UV space). main() early-outs\n// to a transparent write for any fragment OUTSIDE this radius BEFORE the two 3-octave\n// FBM calls + the OKLCh round-trip. The renderer uploads it PADDED by every\n// outward-expanding term (body + eccentric orbit + sat radius + smin band + FBM edge\n// amplitude + click-pulse + a lean/squash safety pad) so it NEVER clips the wet\n// meniscus (IQ: inflate the bound to match any outward op).\nuniform float uMaxReach;\n\n// Membrane — domain-warp strength on the FBM edge displacement (0 = plain fbm).\nuniform float uWarpAmp;\n\n// Lit glass surface (W9.b) — gated behind uLit so the flat fill stays default.\nuniform float uLit; // 0 = flat fill (default), 1 = lit droplet\nuniform vec3 uRimColor; // Fresnel rim tint (GAMMA sRGB, via the /color leaf)\nuniform vec3 uLightDir; // normalized light direction (x, y, z)\nuniform float uSpecStrength; // Blinn-Phong specular weight\nuniform float uSpecShininess; // specular exponent (16-64, tight glint)\nuniform float uRimPower; // Fresnel/Schlick exponent (~2-3)\nuniform float uRimStrength; // Fresnel rim weight\n\n// BC.W-GOOBLOB-MEATBALL — the procedural 2D SDF soft-shadow march (T2, the GLSL twin of\n// the WGSL res.z/res.w lanes). uShadow gates the IQ rmshadows soft contact shadow that\n// FOLLOWS the irregular silhouette; uShadowSoftness is the penumbra hardness (4-48).\nuniform float uShadow; // 0 = no shadow, 1 = the soft contact shadow ON\nuniform float uShadowSoftness; // penumbra hardness (inverse light-source size, 4-48)\n\n// Iridescence + fake subsurface (W11.a) — translucent-gel read.\nuniform float uIridescence; // warm-pearl rim sheen weight (0 = off)\nuniform float uIridHue; // base hue (radians) the cosine palette biases toward (warm)\nuniform float uIridSpeed; // animated-thickness scroll for the iridescent t\nuniform float uSssScale; // fast-SSS back-light weight\nuniform float uSssPower; // fast-SSS exponent\nuniform float uCoreGlow; // thickness-driven inner-luminosity lift\n\n// Color perturbation (perceptually uniform — OKLCh L/C/h)\nuniform float uHueRange; // degrees of hue swing (converted to radians)\nuniform float uSatShift; // OKLCh chroma swing\nuniform float uBrightnessShift; // OKLCh lightness bias\nuniform float uColorNoiseFreq;\nuniform float uColorNoiseSpeed;\n\n// Satellites (max 4)\n#define MAX_SATS 4\nuniform int uSatCount;\nuniform vec2 uSatPos[MAX_SATS];\nuniform float uSatRadius[MAX_SATS];\nuniform float uSatOpacity[MAX_SATS];\n\n// F9.R1 (BG.W-BLOB-SATELLITE-SHADE) — the per-satellite EXPLICIT-SHADE seam (the GL\n// color-seam widen the value.js hero blob asked for; the BA-VJS-5 / C-1 residual, the\n// W-GOO-REDRESS arm-B book discharged). uSatColorActive == 0 is the DEFAULT (the derived\n// palette shade — byte-identical to HEAD): blendSatColor() early-returns and touches\n// nothing. When a consumer supplies explicit per-satellite shades (uSatColor[i], GAMMA\n// sRGB, at uSatColorAmt[i] weight — typically 1) the fragment blends the base palette\n// OKLCh toward each satellite's shade, weighted by that satellite's smin-field proximity\n// at this pixel. The body keeps the derived base (the ask is per-SATELLITE).\nuniform int uSatColorActive;\nuniform vec3 uSatColor[MAX_SATS];\nuniform float uSatColorAmt[MAX_SATS];\n\n// Pointer trail (W10) — a decaying-radius pseudopod toward the cursor. uTrail is a\n// COMPILE-TIME-SIZED array (GLSL ES 3.00 forbids a uniform-sized array) with a\n// DYNAMIC break on uTrailCount, mirroring the satellite loop. Later samples paint\n// smaller metaballs (r *= 1 - i/N) so the trail tapers into a tail.\n#define TRAIL_N 15\nuniform int uTrailCount;\nuniform vec2 uTrailPos[TRAIL_N];\nuniform float uTrailRadius[TRAIL_N];\n\n// Velocity-driven volume-preserving squash-and-stretch (W10).\nuniform vec2 uVelocity; // smoothed pointer velocity (motion direction + speed)\nuniform float uStretch; // squash-stretch magnitude (0 = off)\n\nconst float PI = 3.141592653589793;\n", Q = "\n", Me = je + Q + Ee + Q + `${y}
506
506
 
507
- ` + Ee + Q + Se + Q + `
507
+ ` + ke + Q + Te + Q + `
508
508
  // --- Color (Ottosson OKLab/OKLCh — value.js EXACT constants, transposed) ---
509
509
  //
510
510
  // The OETF (srgbToLinear/linearToSrgb) + the four Ottosson matrices + their space
@@ -513,13 +513,13 @@ vec3 fbmWarpedG(vec2 p, int octaves, float warpAmp) {
513
513
  // ONCE so the OETF can never diverge from aurora's; the line-for-line TS port
514
514
  // (__tests__/metaball-color.glsl-port.ts) mirrors that chunk. The gamut-clamp
515
515
  // below stays blob-local (aurora has no in-shader OKLCh path).
516
- ${o}
517
- ${c}
516
+ ${p}
517
+ ${m}
518
518
 
519
- ` + De + Q + "\n// AX.W15 — de-synced breath. The body throb was a single sin(uPulsePhase) — a\n// mechanical pulse that re-syncs every cycle. Three DETUNED sines at IRRATIONAL\n// frequency ratios (1, 0.13/0.09 ≈ 1.444, 0.31) never re-phase, so the membrane\n// breathes like a living creature (an asymmetric slower-exhale calm band) rather\n// than a metronome. Normalized so the composite stays in ~[-1, 1].\nfloat breath(float phase) {\n return (sin(phase)\n + 0.5 * sin(phase * 1.4444 + 1.7)\n + 0.28 * sin(phase * 0.31 + 4.1)) / 1.78;\n}\n\n// AX.W15 — the composite SDF field WITH its ANALYTIC GRADIENT, returned as\n// vec3(dist, ∂d/∂x, ∂d/∂y). The domain-warped body membrane smin-merged with the\n// satellites + trail; the gradient propagates through sminG's mix(a.yz, b.yz, h)\n// so the surface normal reads the field gradient DIRECTLY (the 4-tap finite\n// difference is DELETED — its 4 full evals per lit pixel are gone).\n//\n// The ANISOTROPIC SQUASH (W10 volume-preserving stretch) is a linear map\n// bodyUv = D·R·uv (R rotates world→(motion-axis, perp); D = diag(1/sa, sa)). The\n// body field's gradient is computed in bodyUv space, so it MUST be transformed back\n// to uv space by M^T = R^T·D (the inverse-transpose handling the SOTA-deepening [2]\n// warns the 4-tap did implicitly by sampling in screen space).\nvec3 sceneDistG(vec2 uv) {\n // De-synced pulsing body radius.\n float bodyR = uBodyRadius + breath(uPulsePhase) * uPulseAmp;\n\n // Velocity-driven VOLUME-PRESERVING squash-and-stretch (W10), SATURATED (AX.W46\n // D5). sa is the stretch along motion, EXACTLY 1/sa perpendicular (area-preserving).\n // The basis (ax, perp) is captured so the gradient can be transformed back below.\n //\n // The W10 form sa = 1 + speed*uStretch rode an UNBOUNDED critically-damped spring\n // velocity (O(5-8)/s on a fast flick) -> sa ~ 1.78-2.25x elongation, a violent\n // taffy-pull. A tanh saturation sa = 1 + tanh(speed*k)*uStretch caps the elongation\n // at 1 + uStretch (~1.5x at the default stretch 0.5) no matter how fast the flick —\n // the fastest flick reads as a lively bounce, never a rubber-band snap (the standard\n // volume-preserving squash-and-stretch restraint). k = 1.6 keeps the tanh in its\n // near-linear regime for a slow drag (the gentle squash still reads) and saturates\n // only the fast flick.\n vec2 bodyUv = uv;\n vec2 ax = vec2(1.0, 0.0);\n vec2 perp = vec2(0.0, 1.0);\n float sa = 1.0;\n float speed = length(uVelocity);\n bool squashed = uStretch > 0.0 && speed > 1e-4;\n if (squashed) {\n ax = uVelocity / speed;\n perp = vec2(-ax.y, ax.x);\n sa = 1.0 + tanh(speed * 1.6) * uStretch;\n bodyUv = vec2(dot(uv, ax) / sa, dot(uv, perp) * sa);\n }\n\n // Domain-warped FBM displacement WITH its analytic gradient (the warp-Jacobian\n // approximation per [2]). disp = (noiseVal - 0.5) · uNoiseAmp; its gradient in\n // bodyUv space is uNoiseAmp · uNoiseFreq · fbmGrad (the uNoiseFreq chain factor\n // from the bodyUv·uNoiseFreq argument).\n vec3 fbmv = fbmWarpedG(bodyUv * uNoiseFreq + uTime * uNoiseSpeed, 3, uWarpAmp);\n float bodyDisplacement = (fbmv.x - 0.5) * uNoiseAmp;\n vec2 dispGradBody = uNoiseAmp * uNoiseFreq * fbmv.yz;\n\n // Body circle WITH gradient (in bodyUv space). The displaced radius subtracts\n // the displacement, so the body gradient is circleGrad - dispGrad (sign per\n // [2]: d = circleDist - displacement ⇒ grad = circleGrad - dispGrad).\n vec3 bodyG = sdgCircle(bodyUv, vec2(0.0), bodyR + bodyDisplacement);\n vec2 bodyGradBody = bodyG.yz - dispGradBody;\n\n // Transform the body gradient back to uv space: g_uv = R^T · D · g_body, i.e.\n // scale by D = diag(1/sa, sa) in the (ax, perp) frame then reconstruct in world.\n vec2 bodyGradUv;\n if (squashed) {\n vec2 scaled = vec2(bodyGradBody.x / sa, bodyGradBody.y * sa);\n bodyGradUv = scaled.x * ax + scaled.y * perp;\n } else {\n bodyGradUv = bodyGradBody;\n }\n vec3 d = vec3(bodyG.x, bodyGradUv);\n\n // Satellites — smin-merged into the body (uMerge selects quadratic/circular).\n for (int i = 0; i < MAX_SATS; i++) {\n if (i >= uSatCount) break;\n vec3 satG = sdgCircle(uv, uSatPos[i], uSatRadius[i]);\n satG.x += (1.0 - uSatOpacity[i]) * 0.3;\n d = sminG(d, satG, uSmoothK);\n }\n\n // Pointer trail — a decaying-radius pseudopod reaching toward the cursor,\n // smin-merged so it stretches an elastic limb and snaps back.\n for (int i = 0; i < TRAIL_N; i++) {\n if (i >= uTrailCount) break;\n vec3 trailG = sdgCircle(uv, uTrailPos[i], uTrailRadius[i]);\n d = sminG(d, trailG, uSmoothK);\n }\n return d;\n}\n\n// AX.W15 — the analytic surface normal. The field gradient grad2d arrives\n// DIRECTLY from sceneDistG (no 4-tap). The smin field is sub-unit (the CD family\n// |grad| ≤ 1) so the gradient is NOT unit-length — normalize() before the dome\n// lift (the unit contract is on the FINAL lifted normal N, not the raw field\n// gradient). The Z dome: 'interior' is the normalized depth inward from the rim\n// (-d/bodyR); z = sqrt(1 - (1 - interior)^2) is the unit half-sphere profile (flat\n// centre, steep rim). N tilts outward along the field gradient near the rim and\n// points at the viewer deep inside.\nvec3 surfaceNormalFromGrad(vec2 grad2d, float d, float bodyR) {\n vec2 g = normalize(grad2d + vec2(1e-6));\n float interior = clamp(-d / max(bodyR, 1e-4), 0.0, 1.0);\n float z = sqrt(max(0.0, 1.0 - (1.0 - interior) * (1.0 - interior)));\n return normalize(vec3(g * (1.0 - z), z) + vec3(0.0, 0.0, 1e-6));\n}\n\n// BC.W-GOOBLOB-MEATBALL — the 2D SDF soft-shadow march (IQ rmshadows improved-penumbra,\n// research/viz/goo-blob.md §2.3, §5). The GLSL twin of the WGSL softShadow2D — a procedural\n// soft contact shadow FOLLOWING the irregular metaball silhouette (NOT a hard disc/box\n// shadow). Marches from ro along rd (the in-plane projection of uLightDir),\n// accumulating the closest miss via the Aaltonen penumbra (y = h*h/(2*ph) + d =\n// sqrt(h*h - y*y)) that kills the banding the naive res = min(res, h/(w*t)) shows. CHEAP:\n// 24 steps, re-uses the SAME sceneDistG().x field (NO separate field re-eval, NO FBO/\n// multi-pass — the procedural field needs none). w is the penumbra hardness (inverse\n// light-source size -> uShadowSoftness). Derivative-FREE. Returns 1.0 (lit) -> 0.0 (occluded).\nfloat softShadow2D(vec2 ro, vec2 rd, float mint, float maxt, float w) {\n float res = 1.0;\n float ph = 1e20;\n float t = mint;\n for (int i = 0; i < 24; i++) {\n if (t >= maxt) break;\n float h = sceneDistG(ro + rd * t).x;\n if (h < 0.001) return 0.0;\n float y = h * h / (2.0 * ph);\n float dd = sqrt(max(h * h - y * y, 0.0));\n res = min(res, dd / (w * max(0.001, t - y)));\n ph = h;\n t += h;\n }\n return clamp(res, 0.0, 1.0);\n}\n\n// W11.b — sample the multi-stop palette at t in [0,1], interpolating adjacent\n// stops in OKLab with a MIDPOINT CHROMA-BUMP (a linear OKLab mix of a vivid pair\n// dips chroma through grey; the bump lifts it back). Falls back to uBaseColor when\n// uStopCount <= 1. Returns an OKLCh stop [L, C, h(rad)].\nvec3 samplePaletteOklch(float t) {\n if (uStopCount <= 1) return oklabToOklch(srgbToOklab(uBaseColor));\n float n = float(uStopCount);\n float ft = clamp(t, 0.0, 1.0) * (n - 1.0);\n int i0 = int(floor(ft));\n int i1 = min(i0 + 1, uStopCount - 1);\n float f = ft - float(i0);\n // Fetch adjacent stops (uPalette is gamma sRGB) → OKLab.\n vec3 labA = srgbToOklab(uPalette[i0]);\n vec3 labB = srgbToOklab(uPalette[i1]);\n vec3 lab = mix(labA, labB, f);\n vec3 lch = oklabToOklch(lab);\n // Midpoint chroma-bump: a bell (peaks at f=0.5) lifts C off the grey midpoint.\n lch.y += 0.03 * sin(PI * f);\n return lch;\n}\n\n// F9.R1 (BG.W-BLOB-SATELLITE-SHADE) — the per-satellite explicit-shade blend. The GL\n// color-seam widen value.js's hero blob asked for (the BA-VJS-5 / C-1 residual, the\n// W-GOO-REDRESS arm-B book discharged). DEFAULT OFF: uSatColorActive == 0 returns oklch\n// UNCHANGED (uniform control flow, zero cost, byte-identical to HEAD). When ON, each\n// satellite carrying a positive uSatColorAmt tints the fragments in its smin-field\n// neighbourhood toward its explicit shade — mixed in OKLab (the samplePaletteOklch\n// convention; no hue wrap). The proximity weight rides the SAME opacity-inflated distance\n// the sceneDistG satellite term uses, so a fading satellite's tint fades with it. The\n// body keeps the derived palette base (no uBodyColor fork — the ask is per-SATELLITE).\nvec3 blendSatColor(vec3 oklch, vec2 uv) {\n if (uSatColorActive == 0) return oklch;\n vec3 lab = oklchToOklab(oklch);\n for (int i = 0; i < MAX_SATS; i++) {\n if (i >= uSatCount) break;\n float amt = clamp(uSatColorAmt[i], 0.0, 1.0);\n if (amt <= 0.0) continue;\n // Proximity: 1 well inside satellite i, fading to 0 across the smin band. The\n // opacity-inflated distance matches sceneDistG's satellite term.\n float di = sdCircle(uv, uSatPos[i], uSatRadius[i]) + (1.0 - uSatOpacity[i]) * 0.3;\n float w = (1.0 - smoothstep(-uSatRadius[i], uSmoothK, di)) * amt;\n lab = mix(lab, srgbToOklab(uSatColor[i]), clamp(w, 0.0, 1.0));\n }\n return oklabToOklch(lab);\n}\n\nvoid main() {\n vec2 uv = vUv - 0.5;\n\n // AX.W16 (arm 5) — PRE-FBM bounding early-out. The oversized canvas (1.6x the\n // wrapper) runs the full fragment ALU — two 3-octave FBM evals + the OKLCh\n // round-trip + the lit/iridescence/SSS block — on a large transparent border\n // otherwise (~60% of the canvas is outside the droplet reach). Any fragment beyond\n // uMaxReach (the PADDED worst-case painted reach, uploaded so it never clips the\n // wet meniscus) writes transparent and returns BEFORE any of that work. This is a\n // transparent WRITE, NOT a GLSL discard: the pass is a pure premultiplied blend\n // with no depth, and discard disables the tiled-renderer fast path on mobile GPUs.\n // No fwidth is computed before the return, so there is no\n // derivative-in-non-uniform-control-flow hazard (the kept pixels compute their own\n // fwidth normally below). The pad covers the pointer-lean uv shift, so testing the\n // pre-deform uv is safe.\n if (dot(uv, uv) > uMaxReach * uMaxReach) {\n fragColor = vec4(0.0);\n return;\n }\n\n // Pointer deformation — honor the SIGN of uPointerAttraction (W10): a positive\n // attraction leans the body IN toward the cursor, a negative shies it AWAY. The\n // signed influence flows straight into the UV shift (no hardcoded repulsion).\n //\n // AY.W-BLOB-CONFIG D2 — the SIGN was INVERTED in the rendered result. The\n // sample-shift sign here was uv -= dir*influence; the live readback (an attraction\n // sweep over a HELD pointer) measured the body shifting MORE toward the cursor as\n // attraction went MORE NEGATIVE (a=-1 -> +0.081, a=0 -> +0.063, a=+1 -> +0.042) —\n // exactly inverted: a shy-away -1 LUNGED at the cursor, a lean-in +1 pulled back.\n // pointerDir = uPointer - uv is the toward-pointer direction in SAMPLE space; to\n // MOVE the rendered body TOWARD the pointer the sample must shift ALONG pointerDir\n // (sample the field from where the pointer is), so the sign is uv += dir*influence.\n // A positive attraction now shifts the body toward the cursor (leans in), a negative\n // shifts it away (shies) — the sign the comment + the demo slider always promised,\n // now true in the render.\n //\n // AX.W46 D5 — the falloff radius NARROWS 0.65 → 0.5 (the calm-lean reconciliation).\n // The W15 REDRESS widened it to 0.65 to clear a synthetic floor; the live π-lane\n // read the result as a LUNGE. The drama lives in the STRENGTH (pointerStrength,\n // dropped to 0.18 in types.ts), NOT the falloff — the falloff's job is purely to keep\n // the lean COHERENT across the creature so the body, satellites and trail all tilt\n // toward the cursor as ONE. At 0.5 the body (sitting ≈0.2 uv from the cursor on a\n // hover-flick) is still well inside the cutoff, so the whole creature tilts as one —\n // a gentle, coherent \"it notices you\" lean rather than the body lunging a body-width.\n if (uPointerActive > 0.5) {\n vec2 pointerDir = uPointer - uv;\n float pointerDist = length(pointerDir);\n float influence = smoothstep(0.5, 0.0, pointerDist) * uPointerAttraction * uPointerStrength;\n uv += normalize(pointerDir + 1e-6) * influence;\n }\n\n // The de-synced pulsing body radius — also reused below for the inner-glow scale.\n float bodyR = uBodyRadius + breath(uPulsePhase) * uPulseAmp;\n\n // Composite domain-warped membrane field WITH its analytic gradient (AX.W15).\n vec3 scene = sceneDistG(uv);\n float d = scene.x;\n vec2 fieldGrad = scene.yz;\n\n // Edit #1 — fwidth-based anti-aliased edge: derive the smoothstep half-width\n // from the SDF screen-space gradient so the edge stays ~1px regardless of zoom.\n float aa = max(fwidth(d), 1e-6);\n float alpha = 1.0 - smoothstep(-aa, aa, d);\n\n if (alpha < 0.001) {\n fragColor = vec4(0.0);\n return;\n }\n\n // Edit #4 — perceptually-uniform OKLCh variation. Gamma base → linear → OKLab\n // → OKLCh; perturb L/C/h; OKLCh → OKLab → linear; hue-preserving gamut clamp.\n // The base is the multi-stop palette sample (W11.b) — distributed across the\n // body/satellites by the color noise field — or uBaseColor when single-stop.\n float colorNoise = fbm(uv * uColorNoiseFreq + uTime * uColorNoiseSpeed, 3);\n vec3 oklch = samplePaletteOklch(colorNoise);\n // F9.R1 — per-satellite explicit shade (default no-op at uSatColorActive == 0).\n oklch = blendSatColor(oklch, uv);\n\n oklch.z += (colorNoise - 0.5) * uHueRange * (PI / 180.0); // hue swing, radians\n oklch.y = max(oklch.y + (colorNoise - 0.5) * uSatShift, 0.0); // chroma swing\n oklch.x = clamp(oklch.x + uBrightnessShift, 0.0, 1.0); // lightness bias\n\n // ── BD.W-GOO-CAROUSEL-DECK — the blob to meatball SHADING MORPH (uMorphT). ──\n // The user #1 ask: the goo should MORPH BLOB and MEATBALL from one to another\n // — a CONTINUOUS in-between, not a hard variant cut. The KEY FACT: the body\n // GEOMETRY is IDENTICAL across blob/meatball (the smin SDF field, the satellites,\n // the fwidth-AA — all computed ABOVE, before this gate). ONLY the SURFACE shading\n // (flat fill vs lit/shadow/iridescence/SSS) differs. So the morph is a uMorphT\n // scalar LERPING the SHADING — NOT a geometry rebuild, NOT a path interpolation.\n //\n // uMorphT = 0 -> the flat warm-cream blob (the STAGE-1 floor, byte-identical to\n // the old uStage > 0.5 early-return);\n // uMorphT = 1 -> the lit meatball (the full STAGE-2 dressing, byte-identical to\n // the old else path);\n // 0 < uMorphT < 1 -> the CONTINUOUS in-between (the morph the user asked for).\n //\n // uMorphT resolves from variant for back-compat (blob -> 0, meatball -> 1); a\n // consumer ANIMATING config.morphT 0..1 gets the live morph. The smin field is\n // byte-UNTOUCHED (the geometry is shared — that is the whole point).\n //\n // The flat color is computed ALWAYS (cheap); the EXPENSIVE dressing (the soft-shadow\n // secondary march) is gated uMorphT > 0.0 so a pure blob pays ZERO shadow-march\n // cost (the SLOW-fix discipline — a flat blob is as cheap as the old early-return).\n float morphT = clamp(uMorphT, 0.0, 1.0);\n\n // STAGE-1 flat fill — the warm-cream blob color, off the PRE-dressing oklch (the\n // dressing mutates oklch below, so the flat read must snapshot it here).\n vec3 flatOkl = gamutClampOklch(oklch);\n vec3 flatLin = oklabToLinearSrgb(oklchToOklab(flatOkl));\n vec3 flatRgb = clamp(linearToSrgb(flatLin), 0.0, 1.0);\n\n // If we are fully flat (a pure blob, morphT == 0), emit the flat fill + dither and\n // return — the byte-identical STAGE-1 floor, zero dressing cost.\n if (morphT <= 0.0) {\n float ign1 = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));\n flatRgb = clamp(flatRgb + (ign1 - 0.5) / 255.0, 0.0, 1.0);\n fragColor = vec4(flatRgb * alpha, alpha);\n return;\n }\n\n // Surface normal — from the ANALYTIC field gradient (AX.W15: the 4-tap is\n // deleted). Computed ONCE here and reused by the iridescence (W11.a), the\n // fake-SSS (W11.a), and the lit glass block (W9.b).\n vec3 N = surfaceNormalFromGrad(fieldGrad, d, bodyR);\n vec3 V = vec3(0.0, 0.0, 1.0);\n float thickness = clamp(-d / max(bodyR, 1e-4), 0.0, 1.0); // 0 at rim, ~1 deep in\n float fres = pow(1.0 - max(dot(N, V), 0.0), 2.5); // rim-weighted angle\n\n // ── W11.a iridescence — warm-biased IQ cosine palette driving OKLCh HUE ──\n //\n // A thin-film-like sheen on the RIM (fres-weighted), NOT the cold-blue default:\n // an IQ cosine palette (a + b*cos(2pi(c*t + d))) maps the Fresnel/edge angle +\n // the FBM color field + an animated thickness onto a HUE OFFSET biased to the\n // warm arc (uIridHue), with the chroma clamped to a warm-pearl band so the rim\n // reads cream/gold (congruent with the warm-cream-glass identity). Mixed into\n // OKLCh BEFORE the gamut clamp. Default LOW.\n if (uIridescence > 0.0) {\n float t = fres + 0.3 * colorNoise + uTime * uIridSpeed;\n // Cosine palette in HUE space, centred on the warm uIridHue (~0.18 turn of\n // warm sweep so the sheen shimmers gold→peach, never swinging to cold blue).\n float iridHue = uIridHue + 0.18 * PI * cos(2.0 * PI * t);\n float w = fres * uIridescence; // rim-weighted blend\n oklch.z = mix(oklch.z, iridHue, w);\n // Warm-pearl chroma cap: lift chroma toward a pale-pearl band, clamped.\n oklch.y = min(oklch.y + 0.04 * w, oklch.y + 0.08);\n oklch.x = min(oklch.x + 0.05 * w, 1.0); // a touch brighter at the sheen\n }\n\n // ── W11.a fake subsurface translucency — thickness inner-glow + back-light ──\n //\n // A bright translucent CORE fading to a light-leaking EDGE (the -d ramp) plus\n // the fast-SSS back-light (light wrapping through the thin rim). Both lift OKLCh\n // L and warm the hue, consuming the W9 normal. In OKLCh before the gamut clamp.\n if (uCoreGlow > 0.0 || uSssScale > 0.0) {\n // Beer-Lambert inner luminosity (AX.W15): a SATURATING 1 - exp(-k·thickness)\n // curve — a flat thick core with a fast warm rim falloff — NOT the linear\n // coreGlow·thickness ramp (which over-brightens deep interiors). k ≈ 3 reads\n // as glass depth.\n oklch.x = min(oklch.x + uCoreGlow * (1.0 - exp(-3.0 * thickness)), 1.0);\n // Fast-SSS back-light: light wrapping through the thin (low-thickness) rim.\n vec3 L = normalize(uLightDir + vec3(1e-6));\n float back = pow(clamp(dot(V, -(L + N * thickness)), 0.0, 1.0), uSssPower);\n float sss = back * uSssScale * (1.0 - thickness);\n oklch.x = min(oklch.x + sss, 1.0);\n // Warm the THIN leaking rim only (scale by 1 - thickness): the SSS hue-warm\n // shift rides the rim, not the core (AX.W15 — only the thin rim warms).\n oklch.z += sss * 0.1 * (1.0 - thickness);\n }\n\n // ── BC.W-GOOBLOB-MEATBALL — the soft contact shadow (T2, the GLSL twin). A procedural\n // soft shadow FOLLOWING the irregular silhouette: march from this fragment's uv\n // toward the in-plane projection of uLightDir; where the metaball field occludes the\n // light, DARKEN the OKLCh L — a soft grounded contact band under the dome\n // (PROCEDURAL, silhouette-following, unlike the static CSS gel-dome drop-shadow).\n // Rim-weighted (1 - thickness) so the lit interior stays bright. Gated uShadow > 0.5;\n // variant=blob (STAGE 1) ships shadowless via the uStage early-return above. ──\n if (uShadow > 0.5) {\n vec2 L2 = normalize(uLightDir.xy + vec2(1e-6));\n float sh = softShadow2D(uv, L2, max(aa, 0.004), bodyR * 1.5, max(uShadowSoftness, 4.0));\n // The contact band sits on the LOWER rim (the side AWAY from the light), gated by\n // the away-facing rim weight + a thin-rim Gaussian band (peak thickness ≈ 0.18) so\n // the deep-lit interior + the light-facing edge stay BRIGHT (the warm-cream body\n // mean + the proof:blob-warm-default floor hold). The 0.20 cap is a soft grounding.\n float away = clamp(-dot(normalize(fieldGrad + vec2(1e-6)), L2), 0.0, 1.0);\n float band = exp(-pow((thickness - 0.18) / 0.16, 2.0));\n float shadowDarken = (1.0 - sh) * away * band * 0.20;\n oklch.x = max(oklch.x - shadowDarken, 0.0);\n }\n\n oklch = gamutClampOklch(oklch);\n\n vec3 lin = oklabToLinearSrgb(oklchToOklab(oklch));\n\n // ── W9.b lit glass surface — Blinn-Phong glint + Fresnel rim, in LINEAR ──\n //\n // The lit terms enter lin in LINEAR space BEFORE the OETF (linearToSrgb)\n // and BEFORE the * alpha premultiply — a post-OETF apply double-gammas the\n // highlight and fringes the premultiplied edge (the named A5/A2 trap). The\n // prior flat inner-glow lift is SUBSUMED by the Fresnel rim (the curvature\n // read now comes from the surface normal, not a flat smoothstep). Gated behind\n // uLit so the flat fill stays the default (zero regression).\n if (uLit > 0.5) {\n // N, V, thickness are already computed in main() (reused by iridescence/SSS).\n vec3 L = normalize(uLightDir + vec3(1e-6)); // light direction\n vec3 H = normalize(L + V); // Blinn-Phong half-vector\n\n // Warm-cream specular glint — a near-white OKLCh TINT (L~0.97, C~0.03,\n // hue~85°) routed through the SAME spliced OKLCh matrices, NOT hardcoded\n // sRGB white (pure white reads cheap-CG). Linearized for the linear add.\n vec3 warmCream = oklabToLinearSrgb(oklchToOklab(vec3(0.97, 0.03, radians(85.0))));\n\n // ENERGY-CONSERVING Blinn-Phong (AX.W15 [9]): the (shininess+2)/8 factor\n // DECOUPLES shininess from strength (without it, raising shininess dims the\n // glint, so the two knobs fight). SPECULAR ANTIALIASING: the FBM membrane\n // makes the normal vary fast, so a tight glint (16-64) STROBES on small\n // dock-grid blobs. Widen the effective lobe where the normal varies\n // (Toksvig-style fwidth clamp) — drop shininess, NOT raise it. nVar reads\n // the screen-space normal derivative; a high-variance pixel softens the\n // exponent so the glint stays stable.\n float nVar = length(fwidth(N));\n float shininess = uSpecShininess / (1.0 + 24.0 * nVar);\n float energyNorm = (shininess + 2.0) / 8.0;\n float spec = pow(max(dot(N, H), 0.0), shininess) * uSpecStrength * energyNorm;\n\n // Fresnel/Schlick rim — fed uRimColor (the --foreground warm rim via the\n // /color leaf). FOREGROUND-AWARE MIN-CONTRAST GUARD (AX.W15 [10]):\n // a var(--primary) blob in dark mode resolves a rim near the BODY color, so\n // the rim washes out (no contrast). When the rim's luminance sits too close\n // to the body's, the guard CHROMA-REDUCES and L-LIFTS the rim stop (a\n // perceptual move, NOT a re-tint) so the curved rim always reads. Computed in\n // OKLCh so the lift is perceptual.\n vec3 rimOkl = oklabToOklch(srgbToOklab(uRimColor));\n float bodyL = oklch.x; // the post-perturb body lightness\n float dL = abs(rimOkl.x - bodyL);\n // If the rim is within 0.22 L of the body, push it AWAY (lift if the body is\n // dark, the dark-mode primary case; the chroma-reduce keeps it neutral-warm).\n float lack = clamp((0.22 - dL) / 0.22, 0.0, 1.0);\n rimOkl.x = clamp(mix(rimOkl.x, (bodyL < 0.5 ? 0.92 : 0.18), lack), 0.0, 1.0);\n rimOkl.y *= mix(1.0, 0.5, lack); // chroma-reduce toward a pale pearl\n vec3 rimLin = oklabToLinearSrgb(oklchToOklab(rimOkl));\n\n float rimFres = pow(1.0 - max(dot(N, V), 0.0), uRimPower);\n float rim = rimFres * uRimStrength * (1.0 - 0.6 * thickness);\n\n // Combine the two warm highlights and add in LINEAR. max(spec, rim*scale)\n // keeps the glint from stacking on the rim into a blown hotspot.\n //\n // AX.W46 D4 — CLAMP the linear highlight below unity before the add (the\n // belt-and-braces guard the re-derived specStrength makes rarely-binding but\n // never lets a worst-case normal blow to a hard white spot). The energy-\n // conserving Blinn-Phong CAN still spike on a grazing normal where the Toksvig\n // widen has not kicked in; capping the highlight magnitude at 0.85 (a contained\n // warm gleam, sub-unity) means the OETF clamp below can never crush a\n // pure-white pixel over the dome. The cap is on the highlight ALONE (not the\n // composited lin), so the body color underneath is untouched — it caps only\n // the additive catch-light's energy.\n vec3 highlight = max(warmCream * spec, rimLin * rim);\n highlight = min(highlight, vec3(0.85));\n lin += highlight;\n }\n\n vec3 rgb = clamp(linearToSrgb(lin), 0.0, 1.0); // MANDATORY OETF — closes the seam\n\n // ── BD.W-GOO-CAROUSEL-DECK — the blob to meatball SHADING MORPH compose. ──\n // rgb is the fully-dressed meatball surface; flatRgb (snapshotted before the\n // dressing) is the flat blob fill. The morph is a CONTINUOUS lerp between them on\n // morphT — at morphT==1 it is byte-identical to the dressed meatball, and the\n // morphT==0 case already returned the flat fill above. The geometry (alpha/silhouette)\n // is shared, so only the SURFACE shading interpolates (the morph from one to\n // another). The dither below applies to the composited result.\n rgb = mix(flatRgb, rgb, morphT);\n\n // IGN dither (AX.W15 [2][9]) — the low-chroma warm-cream dome BANDS on 8-bit\n // panels (visible Mach steps in the smooth L roll). Interleaved-gradient noise at\n // 1/255, applied AFTER linearToSrgb and BEFORE the *alpha premultiply (aurora\n // ships the same splice). A triangular ±0.5 LSB dither decorrelates the steps.\n float ign = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));\n rgb = clamp(rgb + (ign - 0.5) / 255.0, 0.0, 1.0);\n\n // Edit #8 — premultiply AFTER the OETF: straight-alpha gamma → premultiplied.\n fragColor = vec4(rgb * alpha, alpha);\n}";
519
+ ` + Ae + Q + "\n// AX.W15 — de-synced breath. The body throb was a single sin(uPulsePhase) — a\n// mechanical pulse that re-syncs every cycle. Three DETUNED sines at IRRATIONAL\n// frequency ratios (1, 0.13/0.09 ≈ 1.444, 0.31) never re-phase, so the membrane\n// breathes like a living creature (an asymmetric slower-exhale calm band) rather\n// than a metronome. Normalized so the composite stays in ~[-1, 1].\nfloat breath(float phase) {\n return (sin(phase)\n + 0.5 * sin(phase * 1.4444 + 1.7)\n + 0.28 * sin(phase * 0.31 + 4.1)) / 1.78;\n}\n\n// AX.W15 — the composite SDF field WITH its ANALYTIC GRADIENT, returned as\n// vec3(dist, ∂d/∂x, ∂d/∂y). The domain-warped body membrane smin-merged with the\n// satellites + trail; the gradient propagates through sminG's mix(a.yz, b.yz, h)\n// so the surface normal reads the field gradient DIRECTLY (the 4-tap finite\n// difference is DELETED — its 4 full evals per lit pixel are gone).\n//\n// The ANISOTROPIC SQUASH (W10 volume-preserving stretch) is a linear map\n// bodyUv = D·R·uv (R rotates world→(motion-axis, perp); D = diag(1/sa, sa)). The\n// body field's gradient is computed in bodyUv space, so it MUST be transformed back\n// to uv space by M^T = R^T·D (the inverse-transpose handling the SOTA-deepening [2]\n// warns the 4-tap did implicitly by sampling in screen space).\nvec3 sceneDistG(vec2 uv) {\n // De-synced pulsing body radius.\n float bodyR = uBodyRadius + breath(uPulsePhase) * uPulseAmp;\n\n // Velocity-driven VOLUME-PRESERVING squash-and-stretch (W10), SATURATED (AX.W46\n // D5). sa is the stretch along motion, EXACTLY 1/sa perpendicular (area-preserving).\n // The basis (ax, perp) is captured so the gradient can be transformed back below.\n //\n // The W10 form sa = 1 + speed*uStretch rode an UNBOUNDED critically-damped spring\n // velocity (O(5-8)/s on a fast flick) -> sa ~ 1.78-2.25x elongation, a violent\n // taffy-pull. A tanh saturation sa = 1 + tanh(speed*k)*uStretch caps the elongation\n // at 1 + uStretch (~1.5x at the default stretch 0.5) no matter how fast the flick —\n // the fastest flick reads as a lively bounce, never a rubber-band snap (the standard\n // volume-preserving squash-and-stretch restraint). k = 1.6 keeps the tanh in its\n // near-linear regime for a slow drag (the gentle squash still reads) and saturates\n // only the fast flick.\n vec2 bodyUv = uv;\n vec2 ax = vec2(1.0, 0.0);\n vec2 perp = vec2(0.0, 1.0);\n float sa = 1.0;\n float speed = length(uVelocity);\n bool squashed = uStretch > 0.0 && speed > 1e-4;\n if (squashed) {\n ax = uVelocity / speed;\n perp = vec2(-ax.y, ax.x);\n sa = 1.0 + tanh(speed * 1.6) * uStretch;\n bodyUv = vec2(dot(uv, ax) / sa, dot(uv, perp) * sa);\n }\n\n // Domain-warped FBM displacement WITH its analytic gradient (the warp-Jacobian\n // approximation per [2]). disp = (noiseVal - 0.5) · uNoiseAmp; its gradient in\n // bodyUv space is uNoiseAmp · uNoiseFreq · fbmGrad (the uNoiseFreq chain factor\n // from the bodyUv·uNoiseFreq argument).\n vec3 fbmv = fbmWarpedG(bodyUv * uNoiseFreq + uTime * uNoiseSpeed, 3, uWarpAmp);\n float bodyDisplacement = (fbmv.x - 0.5) * uNoiseAmp;\n vec2 dispGradBody = uNoiseAmp * uNoiseFreq * fbmv.yz;\n\n // Body circle WITH gradient (in bodyUv space). The displaced radius subtracts\n // the displacement, so the body gradient is circleGrad - dispGrad (sign per\n // [2]: d = circleDist - displacement ⇒ grad = circleGrad - dispGrad).\n vec3 bodyG = sdgCircle(bodyUv, vec2(0.0), bodyR + bodyDisplacement);\n vec2 bodyGradBody = bodyG.yz - dispGradBody;\n\n // Transform the body gradient back to uv space: g_uv = R^T · D · g_body, i.e.\n // scale by D = diag(1/sa, sa) in the (ax, perp) frame then reconstruct in world.\n vec2 bodyGradUv;\n if (squashed) {\n vec2 scaled = vec2(bodyGradBody.x / sa, bodyGradBody.y * sa);\n bodyGradUv = scaled.x * ax + scaled.y * perp;\n } else {\n bodyGradUv = bodyGradBody;\n }\n vec3 d = vec3(bodyG.x, bodyGradUv);\n\n // Satellites — smin-merged into the body (uMerge selects quadratic/circular).\n for (int i = 0; i < MAX_SATS; i++) {\n if (i >= uSatCount) break;\n vec3 satG = sdgCircle(uv, uSatPos[i], uSatRadius[i]);\n satG.x += (1.0 - uSatOpacity[i]) * 0.3;\n d = sminG(d, satG, uSmoothK);\n }\n\n // Pointer trail — a decaying-radius pseudopod reaching toward the cursor,\n // smin-merged so it stretches an elastic limb and snaps back.\n for (int i = 0; i < TRAIL_N; i++) {\n if (i >= uTrailCount) break;\n vec3 trailG = sdgCircle(uv, uTrailPos[i], uTrailRadius[i]);\n d = sminG(d, trailG, uSmoothK);\n }\n return d;\n}\n\n// AX.W15 — the analytic surface normal. The field gradient grad2d arrives\n// DIRECTLY from sceneDistG (no 4-tap). The smin field is sub-unit (the CD family\n// |grad| ≤ 1) so the gradient is NOT unit-length — normalize() before the dome\n// lift (the unit contract is on the FINAL lifted normal N, not the raw field\n// gradient). The Z dome: 'interior' is the normalized depth inward from the rim\n// (-d/bodyR); z = sqrt(1 - (1 - interior)^2) is the unit half-sphere profile (flat\n// centre, steep rim). N tilts outward along the field gradient near the rim and\n// points at the viewer deep inside.\nvec3 surfaceNormalFromGrad(vec2 grad2d, float d, float bodyR) {\n vec2 g = normalize(grad2d + vec2(1e-6));\n float interior = clamp(-d / max(bodyR, 1e-4), 0.0, 1.0);\n float z = sqrt(max(0.0, 1.0 - (1.0 - interior) * (1.0 - interior)));\n return normalize(vec3(g * (1.0 - z), z) + vec3(0.0, 0.0, 1e-6));\n}\n\n// BC.W-GOOBLOB-MEATBALL — the 2D SDF soft-shadow march (IQ rmshadows improved-penumbra,\n// research/viz/goo-blob.md §2.3, §5). The GLSL twin of the WGSL softShadow2D — a procedural\n// soft contact shadow FOLLOWING the irregular metaball silhouette (NOT a hard disc/box\n// shadow). Marches from ro along rd (the in-plane projection of uLightDir),\n// accumulating the closest miss via the Aaltonen penumbra (y = h*h/(2*ph) + d =\n// sqrt(h*h - y*y)) that kills the banding the naive res = min(res, h/(w*t)) shows. CHEAP:\n// 24 steps, re-uses the SAME sceneDistG().x field (NO separate field re-eval, NO FBO/\n// multi-pass — the procedural field needs none). w is the penumbra hardness (inverse\n// light-source size -> uShadowSoftness). Derivative-FREE. Returns 1.0 (lit) -> 0.0 (occluded).\nfloat softShadow2D(vec2 ro, vec2 rd, float mint, float maxt, float w) {\n float res = 1.0;\n float ph = 1e20;\n float t = mint;\n for (int i = 0; i < 24; i++) {\n if (t >= maxt) break;\n float h = sceneDistG(ro + rd * t).x;\n if (h < 0.001) return 0.0;\n float y = h * h / (2.0 * ph);\n float dd = sqrt(max(h * h - y * y, 0.0));\n res = min(res, dd / (w * max(0.001, t - y)));\n ph = h;\n t += h;\n }\n return clamp(res, 0.0, 1.0);\n}\n\n// W11.b — sample the multi-stop palette at t in [0,1], interpolating adjacent\n// stops in OKLab with a MIDPOINT CHROMA-BUMP (a linear OKLab mix of a vivid pair\n// dips chroma through grey; the bump lifts it back). Falls back to uBaseColor when\n// uStopCount <= 1. Returns an OKLCh stop [L, C, h(rad)].\nvec3 samplePaletteOklch(float t) {\n if (uStopCount <= 1) return oklabToOklch(srgbToOklab(uBaseColor));\n float n = float(uStopCount);\n float ft = clamp(t, 0.0, 1.0) * (n - 1.0);\n int i0 = int(floor(ft));\n int i1 = min(i0 + 1, uStopCount - 1);\n float f = ft - float(i0);\n // Fetch adjacent stops (uPalette is gamma sRGB) → OKLab.\n vec3 labA = srgbToOklab(uPalette[i0]);\n vec3 labB = srgbToOklab(uPalette[i1]);\n vec3 lab = mix(labA, labB, f);\n vec3 lch = oklabToOklch(lab);\n // Midpoint chroma-bump: a bell (peaks at f=0.5) lifts C off the grey midpoint.\n lch.y += 0.03 * sin(PI * f);\n return lch;\n}\n\n// F9.R1 (BG.W-BLOB-SATELLITE-SHADE) — the per-satellite explicit-shade blend. The GL\n// color-seam widen value.js's hero blob asked for (the BA-VJS-5 / C-1 residual, the\n// W-GOO-REDRESS arm-B book discharged). DEFAULT OFF: uSatColorActive == 0 returns oklch\n// UNCHANGED (uniform control flow, zero cost, byte-identical to HEAD). When ON, each\n// satellite carrying a positive uSatColorAmt tints the fragments in its smin-field\n// neighbourhood toward its explicit shade — mixed in OKLab (the samplePaletteOklch\n// convention; no hue wrap). The proximity weight rides the SAME opacity-inflated distance\n// the sceneDistG satellite term uses, so a fading satellite's tint fades with it. The\n// body keeps the derived palette base (no uBodyColor fork — the ask is per-SATELLITE).\nvec3 blendSatColor(vec3 oklch, vec2 uv) {\n if (uSatColorActive == 0) return oklch;\n vec3 lab = oklchToOklab(oklch);\n for (int i = 0; i < MAX_SATS; i++) {\n if (i >= uSatCount) break;\n float amt = clamp(uSatColorAmt[i], 0.0, 1.0);\n if (amt <= 0.0) continue;\n // Proximity: 1 well inside satellite i, fading to 0 across the smin band. The\n // opacity-inflated distance matches sceneDistG's satellite term.\n float di = sdCircle(uv, uSatPos[i], uSatRadius[i]) + (1.0 - uSatOpacity[i]) * 0.3;\n float w = (1.0 - smoothstep(-uSatRadius[i], uSmoothK, di)) * amt;\n lab = mix(lab, srgbToOklab(uSatColor[i]), clamp(w, 0.0, 1.0));\n }\n return oklabToOklch(lab);\n}\n\nvoid main() {\n vec2 uv = vUv - 0.5;\n\n // AX.W16 (arm 5) — PRE-FBM bounding early-out. The oversized canvas (1.6x the\n // wrapper) runs the full fragment ALU — two 3-octave FBM evals + the OKLCh\n // round-trip + the lit/iridescence/SSS block — on a large transparent border\n // otherwise (~60% of the canvas is outside the droplet reach). Any fragment beyond\n // uMaxReach (the PADDED worst-case painted reach, uploaded so it never clips the\n // wet meniscus) writes transparent and returns BEFORE any of that work. This is a\n // transparent WRITE, NOT a GLSL discard: the pass is a pure premultiplied blend\n // with no depth, and discard disables the tiled-renderer fast path on mobile GPUs.\n // No fwidth is computed before the return, so there is no\n // derivative-in-non-uniform-control-flow hazard (the kept pixels compute their own\n // fwidth normally below). The pad covers the pointer-lean uv shift, so testing the\n // pre-deform uv is safe.\n if (dot(uv, uv) > uMaxReach * uMaxReach) {\n fragColor = vec4(0.0);\n return;\n }\n\n // Pointer deformation — honor the SIGN of uPointerAttraction (W10): a positive\n // attraction leans the body IN toward the cursor, a negative shies it AWAY. The\n // signed influence flows straight into the UV shift (no hardcoded repulsion).\n //\n // AY.W-BLOB-CONFIG D2 — the SIGN was INVERTED in the rendered result. The\n // sample-shift sign here was uv -= dir*influence; the live readback (an attraction\n // sweep over a HELD pointer) measured the body shifting MORE toward the cursor as\n // attraction went MORE NEGATIVE (a=-1 -> +0.081, a=0 -> +0.063, a=+1 -> +0.042) —\n // exactly inverted: a shy-away -1 LUNGED at the cursor, a lean-in +1 pulled back.\n // pointerDir = uPointer - uv is the toward-pointer direction in SAMPLE space; to\n // MOVE the rendered body TOWARD the pointer the sample must shift ALONG pointerDir\n // (sample the field from where the pointer is), so the sign is uv += dir*influence.\n // A positive attraction now shifts the body toward the cursor (leans in), a negative\n // shifts it away (shies) — the sign the comment + the demo slider always promised,\n // now true in the render.\n //\n // AX.W46 D5 — the falloff radius NARROWS 0.65 → 0.5 (the calm-lean reconciliation).\n // The W15 REDRESS widened it to 0.65 to clear a synthetic floor; the live π-lane\n // read the result as a LUNGE. The drama lives in the STRENGTH (pointerStrength,\n // dropped to 0.18 in types.ts), NOT the falloff — the falloff's job is purely to keep\n // the lean COHERENT across the creature so the body, satellites and trail all tilt\n // toward the cursor as ONE. At 0.5 the body (sitting ≈0.2 uv from the cursor on a\n // hover-flick) is still well inside the cutoff, so the whole creature tilts as one —\n // a gentle, coherent \"it notices you\" lean rather than the body lunging a body-width.\n if (uPointerActive > 0.5) {\n vec2 pointerDir = uPointer - uv;\n float pointerDist = length(pointerDir);\n float influence = smoothstep(0.5, 0.0, pointerDist) * uPointerAttraction * uPointerStrength;\n uv += normalize(pointerDir + 1e-6) * influence;\n }\n\n // The de-synced pulsing body radius — also reused below for the inner-glow scale.\n float bodyR = uBodyRadius + breath(uPulsePhase) * uPulseAmp;\n\n // Composite domain-warped membrane field WITH its analytic gradient (AX.W15).\n vec3 scene = sceneDistG(uv);\n float d = scene.x;\n vec2 fieldGrad = scene.yz;\n\n // Edit #1 — fwidth-based anti-aliased edge: derive the smoothstep half-width\n // from the SDF screen-space gradient so the edge stays ~1px regardless of zoom.\n float aa = max(fwidth(d), 1e-6);\n float alpha = 1.0 - smoothstep(-aa, aa, d);\n\n if (alpha < 0.001) {\n fragColor = vec4(0.0);\n return;\n }\n\n // Edit #4 — perceptually-uniform OKLCh variation. Gamma base → linear → OKLab\n // → OKLCh; perturb L/C/h; OKLCh → OKLab → linear; hue-preserving gamut clamp.\n // The base is the multi-stop palette sample (W11.b) — distributed across the\n // body/satellites by the color noise field — or uBaseColor when single-stop.\n float colorNoise = fbm(uv * uColorNoiseFreq + uTime * uColorNoiseSpeed, 3);\n vec3 oklch = samplePaletteOklch(colorNoise);\n // F9.R1 — per-satellite explicit shade (default no-op at uSatColorActive == 0).\n oklch = blendSatColor(oklch, uv);\n\n oklch.z += (colorNoise - 0.5) * uHueRange * (PI / 180.0); // hue swing, radians\n oklch.y = max(oklch.y + (colorNoise - 0.5) * uSatShift, 0.0); // chroma swing\n oklch.x = clamp(oklch.x + uBrightnessShift, 0.0, 1.0); // lightness bias\n\n // ── BD.W-GOO-CAROUSEL-DECK — the blob to meatball SHADING MORPH (uMorphT). ──\n // The user #1 ask: the goo should MORPH BLOB and MEATBALL from one to another\n // — a CONTINUOUS in-between, not a hard variant cut. The KEY FACT: the body\n // GEOMETRY is IDENTICAL across blob/meatball (the smin SDF field, the satellites,\n // the fwidth-AA — all computed ABOVE, before this gate). ONLY the SURFACE shading\n // (flat fill vs lit/shadow/iridescence/SSS) differs. So the morph is a uMorphT\n // scalar LERPING the SHADING — NOT a geometry rebuild, NOT a path interpolation.\n //\n // uMorphT = 0 -> the flat warm-cream blob (the STAGE-1 floor, byte-identical to\n // the old uStage > 0.5 early-return);\n // uMorphT = 1 -> the lit meatball (the full STAGE-2 dressing, byte-identical to\n // the old else path);\n // 0 < uMorphT < 1 -> the CONTINUOUS in-between (the morph the user asked for).\n //\n // uMorphT resolves from variant for back-compat (blob -> 0, meatball -> 1); a\n // consumer ANIMATING config.morphT 0..1 gets the live morph. The smin field is\n // byte-UNTOUCHED (the geometry is shared — that is the whole point).\n //\n // The flat color is computed ALWAYS (cheap); the EXPENSIVE dressing (the soft-shadow\n // secondary march) is gated uMorphT > 0.0 so a pure blob pays ZERO shadow-march\n // cost (the SLOW-fix discipline — a flat blob is as cheap as the old early-return).\n float morphT = clamp(uMorphT, 0.0, 1.0);\n\n // STAGE-1 flat fill — the warm-cream blob color, off the PRE-dressing oklch (the\n // dressing mutates oklch below, so the flat read must snapshot it here).\n vec3 flatOkl = gamutClampOklch(oklch);\n vec3 flatLin = oklabToLinearSrgb(oklchToOklab(flatOkl));\n vec3 flatRgb = clamp(linearToSrgb(flatLin), 0.0, 1.0);\n\n // If we are fully flat (a pure blob, morphT == 0), emit the flat fill + dither and\n // return — the byte-identical STAGE-1 floor, zero dressing cost.\n if (morphT <= 0.0) {\n float ign1 = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));\n flatRgb = clamp(flatRgb + (ign1 - 0.5) / 255.0, 0.0, 1.0);\n fragColor = vec4(flatRgb * alpha, alpha);\n return;\n }\n\n // Surface normal — from the ANALYTIC field gradient (AX.W15: the 4-tap is\n // deleted). Computed ONCE here and reused by the iridescence (W11.a), the\n // fake-SSS (W11.a), and the lit glass block (W9.b).\n vec3 N = surfaceNormalFromGrad(fieldGrad, d, bodyR);\n vec3 V = vec3(0.0, 0.0, 1.0);\n float thickness = clamp(-d / max(bodyR, 1e-4), 0.0, 1.0); // 0 at rim, ~1 deep in\n float fres = pow(1.0 - max(dot(N, V), 0.0), 2.5); // rim-weighted angle\n\n // ── W11.a iridescence — warm-biased IQ cosine palette driving OKLCh HUE ──\n //\n // A thin-film-like sheen on the RIM (fres-weighted), NOT the cold-blue default:\n // an IQ cosine palette (a + b*cos(2pi(c*t + d))) maps the Fresnel/edge angle +\n // the FBM color field + an animated thickness onto a HUE OFFSET biased to the\n // warm arc (uIridHue), with the chroma clamped to a warm-pearl band so the rim\n // reads cream/gold (congruent with the warm-cream-glass identity). Mixed into\n // OKLCh BEFORE the gamut clamp. Default LOW.\n if (uIridescence > 0.0) {\n float t = fres + 0.3 * colorNoise + uTime * uIridSpeed;\n // Cosine palette in HUE space, centred on the warm uIridHue (~0.18 turn of\n // warm sweep so the sheen shimmers gold→peach, never swinging to cold blue).\n float iridHue = uIridHue + 0.18 * PI * cos(2.0 * PI * t);\n float w = fres * uIridescence; // rim-weighted blend\n oklch.z = mix(oklch.z, iridHue, w);\n // Warm-pearl chroma cap: lift chroma toward a pale-pearl band, clamped.\n oklch.y = min(oklch.y + 0.04 * w, oklch.y + 0.08);\n oklch.x = min(oklch.x + 0.05 * w, 1.0); // a touch brighter at the sheen\n }\n\n // ── W11.a fake subsurface translucency — thickness inner-glow + back-light ──\n //\n // A bright translucent CORE fading to a light-leaking EDGE (the -d ramp) plus\n // the fast-SSS back-light (light wrapping through the thin rim). Both lift OKLCh\n // L and warm the hue, consuming the W9 normal. In OKLCh before the gamut clamp.\n if (uCoreGlow > 0.0 || uSssScale > 0.0) {\n // Beer-Lambert inner luminosity (AX.W15): a SATURATING 1 - exp(-k·thickness)\n // curve — a flat thick core with a fast warm rim falloff — NOT the linear\n // coreGlow·thickness ramp (which over-brightens deep interiors). k ≈ 3 reads\n // as glass depth.\n oklch.x = min(oklch.x + uCoreGlow * (1.0 - exp(-3.0 * thickness)), 1.0);\n // Fast-SSS back-light: light wrapping through the thin (low-thickness) rim.\n vec3 L = normalize(uLightDir + vec3(1e-6));\n float back = pow(clamp(dot(V, -(L + N * thickness)), 0.0, 1.0), uSssPower);\n float sss = back * uSssScale * (1.0 - thickness);\n oklch.x = min(oklch.x + sss, 1.0);\n // Warm the THIN leaking rim only (scale by 1 - thickness): the SSS hue-warm\n // shift rides the rim, not the core (AX.W15 — only the thin rim warms).\n oklch.z += sss * 0.1 * (1.0 - thickness);\n }\n\n // ── BC.W-GOOBLOB-MEATBALL — the soft contact shadow (T2, the GLSL twin). A procedural\n // soft shadow FOLLOWING the irregular silhouette: march from this fragment's uv\n // toward the in-plane projection of uLightDir; where the metaball field occludes the\n // light, DARKEN the OKLCh L — a soft grounded contact band under the dome\n // (PROCEDURAL, silhouette-following, unlike the static CSS gel-dome drop-shadow).\n // Rim-weighted (1 - thickness) so the lit interior stays bright. Gated uShadow > 0.5;\n // variant=blob (STAGE 1) ships shadowless via the uStage early-return above. ──\n if (uShadow > 0.5) {\n vec2 L2 = normalize(uLightDir.xy + vec2(1e-6));\n float sh = softShadow2D(uv, L2, max(aa, 0.004), bodyR * 1.5, max(uShadowSoftness, 4.0));\n // The contact band sits on the LOWER rim (the side AWAY from the light), gated by\n // the away-facing rim weight + a thin-rim Gaussian band (peak thickness ≈ 0.18) so\n // the deep-lit interior + the light-facing edge stay BRIGHT (the warm-cream body\n // mean + the proof:blob-warm-default floor hold). The 0.20 cap is a soft grounding.\n float away = clamp(-dot(normalize(fieldGrad + vec2(1e-6)), L2), 0.0, 1.0);\n float band = exp(-pow((thickness - 0.18) / 0.16, 2.0));\n float shadowDarken = (1.0 - sh) * away * band * 0.20;\n oklch.x = max(oklch.x - shadowDarken, 0.0);\n }\n\n oklch = gamutClampOklch(oklch);\n\n vec3 lin = oklabToLinearSrgb(oklchToOklab(oklch));\n\n // ── W9.b lit glass surface — Blinn-Phong glint + Fresnel rim, in LINEAR ──\n //\n // The lit terms enter lin in LINEAR space BEFORE the OETF (linearToSrgb)\n // and BEFORE the * alpha premultiply — a post-OETF apply double-gammas the\n // highlight and fringes the premultiplied edge (the named A5/A2 trap). The\n // prior flat inner-glow lift is SUBSUMED by the Fresnel rim (the curvature\n // read now comes from the surface normal, not a flat smoothstep). Gated behind\n // uLit so the flat fill stays the default (zero regression).\n if (uLit > 0.5) {\n // N, V, thickness are already computed in main() (reused by iridescence/SSS).\n vec3 L = normalize(uLightDir + vec3(1e-6)); // light direction\n vec3 H = normalize(L + V); // Blinn-Phong half-vector\n\n // Warm-cream specular glint — a near-white OKLCh TINT (L~0.97, C~0.03,\n // hue~85°) routed through the SAME spliced OKLCh matrices, NOT hardcoded\n // sRGB white (pure white reads cheap-CG). Linearized for the linear add.\n vec3 warmCream = oklabToLinearSrgb(oklchToOklab(vec3(0.97, 0.03, radians(85.0))));\n\n // ENERGY-CONSERVING Blinn-Phong (AX.W15 [9]): the (shininess+2)/8 factor\n // DECOUPLES shininess from strength (without it, raising shininess dims the\n // glint, so the two knobs fight). SPECULAR ANTIALIASING: the FBM membrane\n // makes the normal vary fast, so a tight glint (16-64) STROBES on small\n // dock-grid blobs. Widen the effective lobe where the normal varies\n // (Toksvig-style fwidth clamp) — drop shininess, NOT raise it. nVar reads\n // the screen-space normal derivative; a high-variance pixel softens the\n // exponent so the glint stays stable.\n float nVar = length(fwidth(N));\n float shininess = uSpecShininess / (1.0 + 24.0 * nVar);\n float energyNorm = (shininess + 2.0) / 8.0;\n float spec = pow(max(dot(N, H), 0.0), shininess) * uSpecStrength * energyNorm;\n\n // Fresnel/Schlick rim — fed uRimColor (the --foreground warm rim via the\n // /color leaf). FOREGROUND-AWARE MIN-CONTRAST GUARD (AX.W15 [10]):\n // a var(--primary) blob in dark mode resolves a rim near the BODY color, so\n // the rim washes out (no contrast). When the rim's luminance sits too close\n // to the body's, the guard CHROMA-REDUCES and L-LIFTS the rim stop (a\n // perceptual move, NOT a re-tint) so the curved rim always reads. Computed in\n // OKLCh so the lift is perceptual.\n vec3 rimOkl = oklabToOklch(srgbToOklab(uRimColor));\n float bodyL = oklch.x; // the post-perturb body lightness\n float dL = abs(rimOkl.x - bodyL);\n // If the rim is within 0.22 L of the body, push it AWAY (lift if the body is\n // dark, the dark-mode primary case; the chroma-reduce keeps it neutral-warm).\n float lack = clamp((0.22 - dL) / 0.22, 0.0, 1.0);\n rimOkl.x = clamp(mix(rimOkl.x, (bodyL < 0.5 ? 0.92 : 0.18), lack), 0.0, 1.0);\n rimOkl.y *= mix(1.0, 0.5, lack); // chroma-reduce toward a pale pearl\n vec3 rimLin = oklabToLinearSrgb(oklchToOklab(rimOkl));\n\n float rimFres = pow(1.0 - max(dot(N, V), 0.0), uRimPower);\n float rim = rimFres * uRimStrength * (1.0 - 0.6 * thickness);\n\n // Combine the two warm highlights and add in LINEAR. max(spec, rim*scale)\n // keeps the glint from stacking on the rim into a blown hotspot.\n //\n // AX.W46 D4 — CLAMP the linear highlight below unity before the add (the\n // belt-and-braces guard the re-derived specStrength makes rarely-binding but\n // never lets a worst-case normal blow to a hard white spot). The energy-\n // conserving Blinn-Phong CAN still spike on a grazing normal where the Toksvig\n // widen has not kicked in; capping the highlight magnitude at 0.85 (a contained\n // warm gleam, sub-unity) means the OETF clamp below can never crush a\n // pure-white pixel over the dome. The cap is on the highlight ALONE (not the\n // composited lin), so the body color underneath is untouched — it caps only\n // the additive catch-light's energy.\n vec3 highlight = max(warmCream * spec, rimLin * rim);\n highlight = min(highlight, vec3(0.85));\n lin += highlight;\n }\n\n vec3 rgb = clamp(linearToSrgb(lin), 0.0, 1.0); // MANDATORY OETF — closes the seam\n\n // ── BD.W-GOO-CAROUSEL-DECK — the blob to meatball SHADING MORPH compose. ──\n // rgb is the fully-dressed meatball surface; flatRgb (snapshotted before the\n // dressing) is the flat blob fill. The morph is a CONTINUOUS lerp between them on\n // morphT — at morphT==1 it is byte-identical to the dressed meatball, and the\n // morphT==0 case already returned the flat fill above. The geometry (alpha/silhouette)\n // is shared, so only the SURFACE shading interpolates (the morph from one to\n // another). The dither below applies to the composited result.\n rgb = mix(flatRgb, rgb, morphT);\n\n // IGN dither (AX.W15 [2][9]) — the low-chroma warm-cream dome BANDS on 8-bit\n // panels (visible Mach steps in the smooth L roll). Interleaved-gradient noise at\n // 1/255, applied AFTER linearToSrgb and BEFORE the *alpha premultiply (aurora\n // ships the same splice). A triangular ±0.5 LSB dither decorrelates the steps.\n float ign = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));\n rgb = clamp(rgb + (ign - 0.5) / 255.0, 0.0, 1.0);\n\n // Edit #8 — premultiply AFTER the OETF: straight-alpha gamma → premultiplied.\n fragColor = vec4(rgb * alpha, alpha);\n}";
520
520
  //#endregion
521
521
  //#region src/components/blob/composables/uploadBlobUniforms.ts
522
- function Ae(e, t, n, r, i, a, o, s, c) {
522
+ function Ne(e, t, n, r, i, a, o, s, c) {
523
523
  let { U: l, satPosLocs: u, satRadLocs: d, satOpLocs: f, satColorLocs: p, satColorAmtLocs: m, trailPosLocs: h, trailRadLocs: g, paletteLocs: _ } = r, { params: v, rgb: y, simTimeMs: b, timeSec: x, resolveColor: S, rimColor: C, paletteStops: w } = c, { geometry: T, membrane: E, color: D, surface: O, interaction: k } = a;
524
524
  e.useProgram(t), e.bindVertexArray(n), e.uniform2f(l.uResolution, i.width, i.height), e.uniform1f(l.uTime, b / 1e3), e.uniform3f(l.uBaseColor, y[0], y[1], y[2]);
525
525
  let A = w, j = Math.min(A.length, 4);
@@ -541,41 +541,41 @@ function Ae(e, t, n, r, i, a, o, s, c) {
541
541
  } else e.uniform3f(n, y[0], y[1], y[2]), e.uniform1f(r, 0);
542
542
  }
543
543
  let P = o.pointer.value, F = k.pointerAttraction + v.pointerAttraction;
544
- e.uniform2f(l.uPointer, P.x * .5 * R, P.y * .5 * R), e.uniform1f(l.uPointerActive, +!!o.active.value), e.uniform1f(l.uPointerAttraction, F), e.uniform1f(l.uPointerStrength, k.pointerStrength * R);
544
+ e.uniform2f(l.uPointer, P.x * .5 * V, P.y * .5 * V), e.uniform1f(l.uPointerActive, +!!o.active.value), e.uniform1f(l.uPointerAttraction, F), e.uniform1f(l.uPointerStrength, k.pointerStrength * V);
545
545
  let I = Math.max(0, Math.min(1, F)), L = o.velocity.value;
546
- e.uniform2f(l.uVelocity, L.x * .5 * R, L.y * .5 * R), e.uniform1f(l.uStretch, k.stretch);
547
- let z = o.trailSources(T.satelliteRadius * .7 * I);
548
- e.uniform1i(l.uTrailCount, z.count);
546
+ e.uniform2f(l.uVelocity, L.x * .5 * V, L.y * .5 * V), e.uniform1f(l.uStretch, k.stretch);
547
+ let R = o.trailSources(T.satelliteRadius * .7 * I);
548
+ e.uniform1i(l.uTrailCount, R.count);
549
549
  for (let t = 0; t < 15; t++) {
550
- let n = h[t] ?? null, r = g[t] ?? null, i = z.sources[t];
551
- i ? (e.uniform2f(n, i.x * .5 * R, i.y * .5 * R), e.uniform1f(r, i.radius * R)) : (e.uniform2f(n, 0, 0), e.uniform1f(r, 0));
550
+ let n = h[t] ?? null, r = g[t] ?? null, i = R.sources[t];
551
+ i ? (e.uniform2f(n, i.x * .5 * V, i.y * .5 * V), e.uniform1f(r, i.radius * V)) : (e.uniform2f(n, 0, 0), e.uniform1f(r, 0));
552
552
  }
553
- e.uniform1f(l.uBodyRadius, T.bodyRadius * R), e.uniform1f(l.uPulsePhase, x * E.pulseFreq * v.pulseFreq * Math.PI * 2);
554
- let B = o.pulse.value * k.clickImpulse;
555
- e.uniform1f(l.uPulseAmp, (E.pulseAmp * v.pulseAmp / .015 + B) * R), e.uniform1f(l.uNoiseAmp, E.noiseAmp * v.noiseAmp / .025 * R), e.uniform1f(l.uNoiseFreq, E.noiseFreq), e.uniform1f(l.uNoiseSpeed, E.noiseSpeed), e.uniform1f(l.uWarpAmp, E.warpAmp);
556
- let V = T.orbitRadius * 1.2 * (1 + T.eccentricity), H = E.smoothK * v.smoothK, U = Math.max(0, V - T.satelliteRadius - T.bodyRadius), ee = H > 0 ? Math.min(1.25, 1 + U / H) : 1;
557
- e.uniform1f(l.uSmoothK, H * ee * R), e.uniform1f(l.uMerge, +(E.merge === "circular"));
558
- let W = typeof a.morphT == "number" ? Math.max(0, Math.min(1, a.morphT)) : a.variant === "blob" ? 0 : 1;
559
- e.uniform1f(l.uMorphT, W), e.uniform1f(l.uStage, +(W <= 0));
560
- let te = (a.surface.fissionAmp ?? 0) > 0 ? ae * 1.12 : 0, ne = Math.max(V, te) + T.satelliteRadius, re = (Math.max(T.bodyRadius, ne) + H * ee + E.noiseAmp * v.noiseAmp / .025 + Math.abs(o.pulse.value) * k.clickImpulse) * R + .1;
561
- e.uniform1f(l.uMaxReach, re), e.uniform1f(l.uHueRange, D.hueRange + v.hueRange), e.uniform1f(l.uSatShift, D.satShift + v.satShift), e.uniform1f(l.uBrightnessShift, D.brightnessShift + v.brightnessShift), e.uniform1f(l.uColorNoiseFreq, D.colorNoiseFreq), e.uniform1f(l.uColorNoiseSpeed, D.colorNoiseSpeed);
562
- let G = W > 0;
563
- e.uniform1f(l.uLit, G && O.lit ? 1 : 0);
553
+ e.uniform1f(l.uBodyRadius, T.bodyRadius * V), e.uniform1f(l.uPulsePhase, x * E.pulseFreq * v.pulseFreq * Math.PI * 2);
554
+ let z = o.pulse.value * k.clickImpulse;
555
+ e.uniform1f(l.uPulseAmp, (E.pulseAmp * v.pulseAmp / .015 + z) * V), e.uniform1f(l.uNoiseAmp, E.noiseAmp * v.noiseAmp / .025 * V), e.uniform1f(l.uNoiseFreq, E.noiseFreq), e.uniform1f(l.uNoiseSpeed, E.noiseSpeed), e.uniform1f(l.uWarpAmp, E.warpAmp);
556
+ let B = T.orbitRadius * 1.2 * (1 + T.eccentricity), H = E.smoothK * v.smoothK, U = Math.max(0, B - T.satelliteRadius - T.bodyRadius), W = H > 0 ? Math.min(1.25, 1 + U / H) : 1;
557
+ e.uniform1f(l.uSmoothK, H * W * V), e.uniform1f(l.uMerge, +(E.merge === "circular"));
558
+ let G = typeof a.morphT == "number" ? Math.max(0, Math.min(1, a.morphT)) : a.variant === "blob" ? 0 : 1;
559
+ e.uniform1f(l.uMorphT, G), e.uniform1f(l.uStage, +(G <= 0));
560
+ let ee = (a.surface.fissionAmp ?? 0) > 0 ? ce * 1.12 : 0, te = Math.max(B, ee) + T.satelliteRadius, ne = (Math.max(T.bodyRadius, te) + H * W + E.noiseAmp * v.noiseAmp / .025 + Math.abs(o.pulse.value) * k.clickImpulse) * V + .1;
561
+ e.uniform1f(l.uMaxReach, ne), e.uniform1f(l.uHueRange, D.hueRange + v.hueRange), e.uniform1f(l.uSatShift, D.satShift + v.satShift), e.uniform1f(l.uBrightnessShift, D.brightnessShift + v.brightnessShift), e.uniform1f(l.uColorNoiseFreq, D.colorNoiseFreq), e.uniform1f(l.uColorNoiseSpeed, D.colorNoiseSpeed);
562
+ let re = G > 0;
563
+ e.uniform1f(l.uLit, re && O.lit ? 1 : 0);
564
564
  let K = S(C);
565
- e.uniform3f(l.uRimColor, K[0], K[1], K[2]), e.uniform3f(l.uLightDir, O.lightDir[0], O.lightDir[1], O.lightDir[2]), e.uniform1f(l.uSpecStrength, O.specStrength), e.uniform1f(l.uSpecShininess, O.specShininess), e.uniform1f(l.uRimPower, O.rimPower), e.uniform1f(l.uRimStrength, O.rimStrength), e.uniform1f(l.uShadow, G && O.shadow ? 1 : 0), e.uniform1f(l.uShadowSoftness, O.shadowSoftness), e.uniform1f(l.uIridescence, O.iridescence * v.iridScale), e.uniform1f(l.uIridHue, O.iridHue * (Math.PI / 180)), e.uniform1f(l.uIridSpeed, O.iridSpeed), e.uniform1f(l.uSssScale, O.sssScale * v.iridScale), e.uniform1f(l.uSssPower, O.sssPower), e.uniform1f(l.uCoreGlow, O.coreGlow);
565
+ e.uniform3f(l.uRimColor, K[0], K[1], K[2]), e.uniform3f(l.uLightDir, O.lightDir[0], O.lightDir[1], O.lightDir[2]), e.uniform1f(l.uSpecStrength, O.specStrength), e.uniform1f(l.uSpecShininess, O.specShininess), e.uniform1f(l.uRimPower, O.rimPower), e.uniform1f(l.uRimStrength, O.rimStrength), e.uniform1f(l.uShadow, re && O.shadow ? 1 : 0), e.uniform1f(l.uShadowSoftness, O.shadowSoftness), e.uniform1f(l.uIridescence, O.iridescence * v.iridScale), e.uniform1f(l.uIridHue, O.iridHue * (Math.PI / 180)), e.uniform1f(l.uIridSpeed, O.iridSpeed), e.uniform1f(l.uSssScale, O.sssScale * v.iridScale), e.uniform1f(l.uSssPower, O.sssPower), e.uniform1f(l.uCoreGlow, O.coreGlow);
566
566
  let q = s.sources;
567
567
  e.uniform1i(l.uSatCount, q.length);
568
568
  for (let t = 0; t < 4; t++) {
569
569
  let n = u[t] ?? null, r = d[t] ?? null, i = f[t] ?? null, a = q[t];
570
- a ? (e.uniform2f(n, a.x * R, a.y * R), e.uniform1f(r, a.radius * R), e.uniform1f(i, a.opacity)) : (e.uniform2f(n, 0, 0), e.uniform1f(r, 0), e.uniform1f(i, 0));
570
+ a ? (e.uniform2f(n, a.x * V, a.y * V), e.uniform1f(r, a.radius * V), e.uniform1f(i, a.opacity)) : (e.uniform2f(n, 0, 0), e.uniform1f(r, 0), e.uniform1f(i, 0));
571
571
  }
572
572
  e.clearColor(0, 0, 0, 0), e.clear(e.COLOR_BUFFER_BIT), e.drawArrays(e.TRIANGLES, 0, 6), e.bindVertexArray(null);
573
573
  }
574
574
  //#endregion
575
575
  //#region src/components/blob/composables/buildMetaballProgram.ts
576
- var je = "[GooBlob]";
577
- function Me(e) {
578
- let t = p(e, e.VERTEX_SHADER, xe, je), n = p(e, e.FRAGMENT_SHADER, ke, je), r = f(e, t, n, je);
576
+ var Pe = "[GooBlob]";
577
+ function Fe(e) {
578
+ let t = S(e, e.VERTEX_SHADER, we, Pe), n = S(e, e.FRAGMENT_SHADER, Me, Pe), r = x(e, t, n, Pe);
579
579
  e.useProgram(r);
580
580
  let i = e.createVertexArray();
581
581
  e.bindVertexArray(i);
@@ -597,13 +597,13 @@ function Me(e) {
597
597
  let o = e.getAttribLocation(r, "aPosition");
598
598
  e.enableVertexAttribArray(o), e.vertexAttribPointer(o, 2, e.FLOAT, !1, 0, 0);
599
599
  let s = {};
600
- for (let t of ce) s[t] = e.getUniformLocation(r, t);
601
- let c = [], l = [], u = [], d = [], m = [];
602
- for (let t = 0; t < 4; t++) c.push(e.getUniformLocation(r, `uSatPos[${t}]`)), l.push(e.getUniformLocation(r, `uSatRadius[${t}]`)), u.push(e.getUniformLocation(r, `uSatOpacity[${t}]`)), d.push(e.getUniformLocation(r, `uSatColor[${t}]`)), m.push(e.getUniformLocation(r, `uSatColorAmt[${t}]`));
603
- let h = [], g = [];
604
- for (let t = 0; t < 15; t++) h.push(e.getUniformLocation(r, `uTrailPos[${t}]`)), g.push(e.getUniformLocation(r, `uTrailRadius[${t}]`));
605
- let _ = [];
606
- for (let t = 0; t < 4; t++) _.push(e.getUniformLocation(r, `uPalette[${t}]`));
600
+ for (let t of de) s[t] = e.getUniformLocation(r, t);
601
+ let c = [], l = [], u = [], d = [], f = [];
602
+ for (let t = 0; t < 4; t++) c.push(e.getUniformLocation(r, `uSatPos[${t}]`)), l.push(e.getUniformLocation(r, `uSatRadius[${t}]`)), u.push(e.getUniformLocation(r, `uSatOpacity[${t}]`)), d.push(e.getUniformLocation(r, `uSatColor[${t}]`)), f.push(e.getUniformLocation(r, `uSatColorAmt[${t}]`));
603
+ let p = [], m = [];
604
+ for (let t = 0; t < 15; t++) p.push(e.getUniformLocation(r, `uTrailPos[${t}]`)), m.push(e.getUniformLocation(r, `uTrailRadius[${t}]`));
605
+ let h = [];
606
+ for (let t = 0; t < 4; t++) h.push(e.getUniformLocation(r, `uPalette[${t}]`));
607
607
  return e.enable(e.BLEND), e.blendFunc(e.ONE, e.ONE_MINUS_SRC_ALPHA), {
608
608
  prog: r,
609
609
  vs: t,
@@ -616,16 +616,16 @@ function Me(e) {
616
616
  satRadLocs: l,
617
617
  satOpLocs: u,
618
618
  satColorLocs: d,
619
- satColorAmtLocs: m,
620
- trailPosLocs: h,
621
- trailRadLocs: g,
622
- paletteLocs: _
619
+ satColorAmtLocs: f,
620
+ trailPosLocs: p,
621
+ trailRadLocs: m,
622
+ paletteLocs: h
623
623
  }
624
624
  };
625
625
  }
626
626
  //#endregion
627
627
  //#region src/components/blob/shaders/metaball.wgsl.ts
628
- var Ne = `
628
+ var Ie = `
629
629
  const MAX_SATS: i32 = 4;
630
630
  const TRAIL_N: i32 = 15;
631
631
  const MAX_BLOB_STOPS: i32 = 4;
@@ -683,7 +683,7 @@ struct Uniforms {
683
683
  // below. NB: do NOT name the chunk with a template-interpolation form in a WGSL comment —
684
684
  // it injects the whole multi-line chunk into this // comment line and breaks the parse
685
685
  // (BD.W-VIZ-BROKEN-FIX D3c).
686
- ${l}
686
+ ${v}
687
687
 
688
688
  const FBM_LACUNARITY: f32 = 1.8;
689
689
  const FBM_GAIN: f32 = 0.42;
@@ -805,8 +805,8 @@ fn sminG(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {
805
805
  return sminQuadraticG(a, b, k);
806
806
  }
807
807
 
808
- ${a}
809
- ${s}
808
+ ${g}
809
+ ${_}
810
810
 
811
811
  // OKLCh gamut clamp + palette sample + breath (BC.W-CARVE6 -> metaball-palette.wgsl)
812
812
  // — spliced AFTER the OKLCH_MATRICES_WGSL chunk above (its matrix source). NB: do NOT
@@ -1228,7 +1228,7 @@ fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
1228
1228
  // premultiply AFTER the OETF: straight-alpha gamma → premultiplied.
1229
1229
  return vec4<f32>(rgb * alpha, alpha);
1230
1230
  }
1231
- `, Pe = 592, $ = {
1231
+ `, Le = 592, $ = {
1232
1232
  s0: 0,
1233
1233
  s1: 4,
1234
1234
  s2: 8,
@@ -1247,24 +1247,24 @@ fn fs_main(in: VSOut) -> @location(0) vec4<f32> {
1247
1247
  satPos: 72,
1248
1248
  trailPos: 88
1249
1249
  };
1250
- function Fe() {
1251
- let e = new ArrayBuffer(Pe);
1250
+ function Re() {
1251
+ let e = new ArrayBuffer(Le);
1252
1252
  return {
1253
1253
  buffer: e,
1254
1254
  f32: new Float32Array(e),
1255
1255
  i32: new Int32Array(e)
1256
1256
  };
1257
1257
  }
1258
- function Ie(e, t, n, r, i, a) {
1259
- let { f32: o, i32: s } = e, { params: c, rgb: l, simTimeMs: u, timeSec: d, resolveColor: f, rimColor: p, paletteStops: m } = a, { geometry: h, membrane: g, color: _, surface: v, interaction: y } = n, b = r.pointer.value, x = y.pointerAttraction + c.pointerAttraction, S = Math.max(0, Math.min(1, x)), C = r.velocity.value, w = r.pulse.value * y.clickImpulse, T = (g.pulseAmp * c.pulseAmp / .015 + w) * R, E = d * g.pulseFreq * c.pulseFreq * Math.PI * 2, D = g.noiseAmp * c.noiseAmp / .025 * R, O = h.orbitRadius * 1.2 * (1 + h.eccentricity), k = g.smoothK * c.smoothK, A = Math.max(0, O - h.satelliteRadius - h.bodyRadius), j = k > 0 ? Math.min(1.25, 1 + A / k) : 1, M = k * j * R, N = (n.surface.fissionAmp ?? 0) > 0 ? ae * 1.12 : 0, P = Math.max(O, N) + h.satelliteRadius, F = (Math.max(h.bodyRadius, P) + k * j + g.noiseAmp * c.noiseAmp / .025 + Math.abs(r.pulse.value) * y.clickImpulse) * R + .1;
1260
- o[$.s0 + 0] = u / 1e3, o[$.s0 + 1] = h.bodyRadius * R, o[$.s0 + 2] = E, o[$.s0 + 3] = T, o[$.s1 + 0] = D, o[$.s1 + 1] = g.noiseFreq, o[$.s1 + 2] = g.noiseSpeed, o[$.s1 + 3] = g.warpAmp;
1258
+ function ze(e, t, n, r, i, a) {
1259
+ let { f32: o, i32: s } = e, { params: c, rgb: l, simTimeMs: u, timeSec: d, resolveColor: f, rimColor: p, paletteStops: m } = a, { geometry: h, membrane: g, color: _, surface: v, interaction: y } = n, b = r.pointer.value, x = y.pointerAttraction + c.pointerAttraction, S = Math.max(0, Math.min(1, x)), C = r.velocity.value, w = r.pulse.value * y.clickImpulse, T = (g.pulseAmp * c.pulseAmp / .015 + w) * V, E = d * g.pulseFreq * c.pulseFreq * Math.PI * 2, D = g.noiseAmp * c.noiseAmp / .025 * V, O = h.orbitRadius * 1.2 * (1 + h.eccentricity), k = g.smoothK * c.smoothK, A = Math.max(0, O - h.satelliteRadius - h.bodyRadius), j = k > 0 ? Math.min(1.25, 1 + A / k) : 1, M = k * j * V, N = (n.surface.fissionAmp ?? 0) > 0 ? ce * 1.12 : 0, P = Math.max(O, N) + h.satelliteRadius, F = (Math.max(h.bodyRadius, P) + k * j + g.noiseAmp * c.noiseAmp / .025 + Math.abs(r.pulse.value) * y.clickImpulse) * V + .1;
1260
+ o[$.s0 + 0] = u / 1e3, o[$.s0 + 1] = h.bodyRadius * V, o[$.s0 + 2] = E, o[$.s0 + 3] = T, o[$.s1 + 0] = D, o[$.s1 + 1] = g.noiseFreq, o[$.s1 + 2] = g.noiseSpeed, o[$.s1 + 3] = g.warpAmp;
1261
1261
  let I = typeof n.morphT == "number" ? Math.max(0, Math.min(1, n.morphT)) : n.variant === "blob" ? 0 : 1, L = I > 0;
1262
- o[$.s2 + 0] = M, o[$.s2 + 1] = +(g.merge === "circular"), o[$.s2 + 2] = F, o[$.s2 + 3] = L && v.lit ? 1 : 0, o[$.s3 + 0] = v.specStrength, o[$.s3 + 1] = v.specShininess, o[$.s3 + 2] = v.rimPower, o[$.s3 + 3] = v.rimStrength, o[$.s4 + 0] = v.iridescence * c.iridScale, o[$.s4 + 1] = v.iridHue * (Math.PI / 180), o[$.s4 + 2] = v.iridSpeed, o[$.s4 + 3] = v.sssScale * c.iridScale, o[$.s5 + 0] = v.sssPower, o[$.s5 + 1] = v.coreGlow, o[$.s5 + 2] = _.hueRange + c.hueRange, o[$.s5 + 3] = _.satShift + c.satShift, o[$.s6 + 0] = _.brightnessShift + c.brightnessShift, o[$.s6 + 1] = _.colorNoiseFreq, o[$.s6 + 2] = _.colorNoiseSpeed, o[$.s6 + 3] = y.stretch, o[$.s7 + 0] = +!!r.active.value, o[$.s7 + 1] = x, o[$.s7 + 2] = y.pointerStrength * R, o[$.s7 + 3] = +(I <= 0), o[$.ptr + 0] = b.x * .5 * R, o[$.ptr + 1] = b.y * .5 * R, o[$.ptr + 2] = C.x * .5 * R, o[$.ptr + 3] = C.y * .5 * R, o[$.base + 0] = l[0], o[$.base + 1] = l[1], o[$.base + 2] = l[2], o[$.base + 3] = I;
1263
- let z = f(p);
1264
- o[$.rim + 0] = z[0], o[$.rim + 1] = z[1], o[$.rim + 2] = z[2], o[$.rim + 3] = 0, o[$.light + 0] = v.lightDir[0], o[$.light + 1] = v.lightDir[1], o[$.light + 2] = v.lightDir[2], o[$.light + 3] = 0, o[$.res + 0] = t.width, o[$.res + 1] = t.height, o[$.res + 2] = L && v.shadow ? 1 : 0, o[$.res + 3] = v.shadowSoftness;
1265
- let B = m, V = Math.min(B.length, 4);
1262
+ o[$.s2 + 0] = M, o[$.s2 + 1] = +(g.merge === "circular"), o[$.s2 + 2] = F, o[$.s2 + 3] = L && v.lit ? 1 : 0, o[$.s3 + 0] = v.specStrength, o[$.s3 + 1] = v.specShininess, o[$.s3 + 2] = v.rimPower, o[$.s3 + 3] = v.rimStrength, o[$.s4 + 0] = v.iridescence * c.iridScale, o[$.s4 + 1] = v.iridHue * (Math.PI / 180), o[$.s4 + 2] = v.iridSpeed, o[$.s4 + 3] = v.sssScale * c.iridScale, o[$.s5 + 0] = v.sssPower, o[$.s5 + 1] = v.coreGlow, o[$.s5 + 2] = _.hueRange + c.hueRange, o[$.s5 + 3] = _.satShift + c.satShift, o[$.s6 + 0] = _.brightnessShift + c.brightnessShift, o[$.s6 + 1] = _.colorNoiseFreq, o[$.s6 + 2] = _.colorNoiseSpeed, o[$.s6 + 3] = y.stretch, o[$.s7 + 0] = +!!r.active.value, o[$.s7 + 1] = x, o[$.s7 + 2] = y.pointerStrength * V, o[$.s7 + 3] = +(I <= 0), o[$.ptr + 0] = b.x * .5 * V, o[$.ptr + 1] = b.y * .5 * V, o[$.ptr + 2] = C.x * .5 * V, o[$.ptr + 3] = C.y * .5 * V, o[$.base + 0] = l[0], o[$.base + 1] = l[1], o[$.base + 2] = l[2], o[$.base + 3] = I;
1263
+ let R = f(p);
1264
+ o[$.rim + 0] = R[0], o[$.rim + 1] = R[1], o[$.rim + 2] = R[2], o[$.rim + 3] = 0, o[$.light + 0] = v.lightDir[0], o[$.light + 1] = v.lightDir[1], o[$.light + 2] = v.lightDir[2], o[$.light + 3] = 0, o[$.res + 0] = t.width, o[$.res + 1] = t.height, o[$.res + 2] = L && v.shadow ? 1 : 0, o[$.res + 3] = v.shadowSoftness;
1265
+ let z = m, B = Math.min(z.length, 4);
1266
1266
  for (let e = 0; e < 4; e++) {
1267
- let t = $.palette + e * 4, n = B[e];
1267
+ let t = $.palette + e * 4, n = z[e];
1268
1268
  if (n) {
1269
1269
  let e = f(n);
1270
1270
  o[t + 0] = e[0], o[t + 1] = e[1], o[t + 2] = e[2];
@@ -1274,33 +1274,33 @@ function Ie(e, t, n, r, i, a) {
1274
1274
  let H = i.sources;
1275
1275
  for (let e = 0; e < 4; e++) {
1276
1276
  let t = $.satPos + e * 4, n = H[e];
1277
- n ? (o[t + 0] = n.x * R, o[t + 1] = n.y * R, o[t + 2] = n.radius * R, o[t + 3] = n.opacity) : (o[t + 0] = 0, o[t + 1] = 0, o[t + 2] = 0, o[t + 3] = 0);
1277
+ n ? (o[t + 0] = n.x * V, o[t + 1] = n.y * V, o[t + 2] = n.radius * V, o[t + 3] = n.opacity) : (o[t + 0] = 0, o[t + 1] = 0, o[t + 2] = 0, o[t + 3] = 0);
1278
1278
  }
1279
1279
  let U = r.trailSources(h.satelliteRadius * .7 * S);
1280
1280
  for (let e = 0; e < 15; e++) {
1281
1281
  let t = $.trailPos + e * 4, n = U.sources[e];
1282
- n ? (o[t + 0] = n.x * .5 * R, o[t + 1] = n.y * .5 * R, o[t + 2] = n.radius * R) : (o[t + 0] = 0, o[t + 1] = 0, o[t + 2] = 0), o[t + 3] = 0;
1282
+ n ? (o[t + 0] = n.x * .5 * V, o[t + 1] = n.y * .5 * V, o[t + 2] = n.radius * V) : (o[t + 0] = 0, o[t + 1] = 0, o[t + 2] = 0), o[t + 3] = 0;
1283
1283
  }
1284
- return s[$.ints + 0] = V, s[$.ints + 1] = H.length, s[$.ints + 2] = U.count, s[$.ints + 3] = 0, e;
1284
+ return s[$.ints + 0] = B, s[$.ints + 1] = H.length, s[$.ints + 2] = U.count, s[$.ints + 3] = 0, e;
1285
1285
  }
1286
1286
  //#endregion
1287
1287
  //#region src/components/blob/composables/wgpuSetup.ts
1288
- var Le = 64, Re = 8, ze = 2;
1289
- function Be(e) {
1288
+ var Be = 64, Ve = 8, He = 2;
1289
+ function Ue(e) {
1290
1290
  let { canvas: t, config: n, pointer: r, satellites: i, resolveFrame: a, shouldContinue: o } = e;
1291
1291
  return function(e, s, c) {
1292
1292
  let l = e.createShaderModule({
1293
1293
  label: "[GooBlob] metaball.wgsl",
1294
- code: Ne
1294
+ code: Ie
1295
1295
  }), u = e.createBuffer({
1296
1296
  label: "[GooBlob] uniforms",
1297
- size: Pe,
1298
- usage: Le | Re
1297
+ size: Le,
1298
+ usage: Be | Ve
1299
1299
  }), d = e.createBindGroupLayout({
1300
1300
  label: "[GooBlob] bind-group-0",
1301
1301
  entries: [{
1302
1302
  binding: 0,
1303
- visibility: ze,
1303
+ visibility: He,
1304
1304
  buffer: { type: "uniform" }
1305
1305
  }]
1306
1306
  }), f = e.createRenderPipeline({
@@ -1337,12 +1337,12 @@ function Be(e) {
1337
1337
  binding: 0,
1338
1338
  resource: { buffer: u }
1339
1339
  }]
1340
- }), m = Fe();
1340
+ }), m = Re();
1341
1341
  function h(e) {}
1342
1342
  function g(o) {
1343
1343
  let c = a(o);
1344
1344
  if (!c) return;
1345
- Ie(m, t, n, r, i, c), e.queue.writeBuffer(u, 0, m.buffer);
1345
+ ze(m, t, n, r, i, c), e.queue.writeBuffer(u, 0, m.buffer);
1346
1346
  let l = s.getCurrentTexture().createView(), d = e.createCommandEncoder({ label: "[GooBlob] frame" }), h = d.beginRenderPass({ colorAttachments: [{
1347
1347
  view: l,
1348
1348
  clearValue: {
@@ -1368,70 +1368,70 @@ function Be(e) {
1368
1368
  }
1369
1369
  //#endregion
1370
1370
  //#region src/components/blob/composables/useMetaballRenderer.ts
1371
- function Ve(e) {
1372
- let { canvasRef: t, color: i, rimColor: a, paletteStops: o, satelliteColors: s, mood: c, pointer: l, satellites: f, config: p } = e, g = 0, _ = 0, v = n();
1373
- f.onPinch((e) => l.click(e));
1371
+ function We(e) {
1372
+ let { canvasRef: t, color: i, rimColor: a, paletteStops: o, satelliteColors: s, mood: c, pointer: l, satellites: p, config: m } = e, g = 0, _ = 0, v = n();
1373
+ p.onPinch((e) => l.click(e));
1374
1374
  let y = /* @__PURE__ */ new Map();
1375
- function b(e) {
1375
+ function x(e) {
1376
1376
  let t = y.get(e);
1377
1377
  if (t) return t;
1378
- let n = m(h(e));
1378
+ let n = d(u(e));
1379
1379
  return y.size > 256 && y.clear(), y.set(e, n), n;
1380
1380
  }
1381
- let x = null, S = !1, C = P(!1), w = null;
1382
- function T() {
1383
- w !== null && (clearTimeout(w), w = null);
1381
+ let S = null, C = L(b("webgpu")), w = !1, T = I(!1), E = null;
1382
+ function D() {
1383
+ E !== null && (clearTimeout(E), E = null);
1384
1384
  }
1385
- function E(e) {
1386
- if (T(), typeof setTimeout > "u") return;
1385
+ function O(e) {
1386
+ if (D(), typeof setTimeout > "u") return;
1387
1387
  let t = Math.min(Math.max(e - _, 16), 3e4);
1388
- w = setTimeout(() => {
1389
- w = null, x?.wake();
1388
+ E = setTimeout(() => {
1389
+ E = null, S?.wake();
1390
1390
  }, t);
1391
1391
  }
1392
1392
  r(t, {
1393
- pause: () => x?.suspend("off-screen-io"),
1394
- resume: () => x?.resume("off-screen-io")
1393
+ pause: () => S?.suspend("off-screen-io"),
1394
+ resume: () => S?.resume("off-screen-io")
1395
1395
  }, {
1396
1396
  rootMargin: "200px",
1397
1397
  pauseWhenHidden: !1
1398
1398
  });
1399
- function D(e) {
1399
+ function k(e) {
1400
1400
  let t = g ? (e - g) * 1e3 : 16;
1401
1401
  g = e;
1402
- let n = Math.max(0, Math.min(t, 50)), r = x?.reducedMotion ?? !1, u = r || S ? 0 : p.tempo, d = u * n;
1402
+ let n = Math.max(0, Math.min(t, 50)), r = S?.reducedMotion ?? !1, u = r || w ? 0 : m.tempo, d = u * n;
1403
1403
  if (_ += d, v.setActive(l.active.value), u > 0 && l.active.value) {
1404
1404
  let e = l.rawPointer();
1405
1405
  v.setPointer(e.x * .5 + .5, e.y * .5 + .5);
1406
1406
  }
1407
1407
  v.tick(u === 0 ? 0 : n);
1408
- let m = v.acceleration.value, h = v.velocity.value, y = -(m.x * h.x + m.y * h.y);
1408
+ let f = v.acceleration.value, h = v.velocity.value, y = -(f.x * h.x + f.y * h.y);
1409
1409
  return y > 0 && u > 0 && l.click(Math.min(.5, y * 4 + v.burst.value * .2)), r || c.update({
1410
1410
  pointerActive: l.active.value,
1411
1411
  clicked: l.consumeClick(),
1412
1412
  idleMs: l.idleMs()
1413
- }), c.tick(d), r ? l.rest() : l.tick(d), f.tick(_, c.params.value), {
1413
+ }), c.tick(d), r ? l.rest() : l.tick(d), p.tick(_, c.params.value), {
1414
1414
  params: c.params.value,
1415
- rgb: b(i.value),
1415
+ rgb: x(i.value),
1416
1416
  simTimeMs: _,
1417
1417
  timeSec: e,
1418
- resolveColor: b,
1418
+ resolveColor: x,
1419
1419
  rimColor: a.value,
1420
1420
  paletteStops: o.value,
1421
1421
  satColors: s?.value
1422
1422
  };
1423
1423
  }
1424
- function O() {
1425
- let e = c.isSettled() && l.isAtRest() && f.isQuiescent();
1426
- if (C.value = e, S) return !1;
1427
- if (!e) return T(), !0;
1428
- let t = f.nextEventMs(_), n = c.nextAutoMoodMs(), r = Number.isFinite(n) ? _ + n : Infinity;
1429
- return E(Math.min(t, r)), !1;
1424
+ function A() {
1425
+ let e = c.isSettled() && l.isAtRest() && p.isQuiescent();
1426
+ if (T.value = e, w) return !1;
1427
+ if (!e) return D(), !0;
1428
+ let t = p.nextEventMs(_), n = c.nextAutoMoodMs(), r = Number.isFinite(n) ? _ + n : Infinity;
1429
+ return O(Math.min(t, r)), !1;
1430
1430
  }
1431
- let k = () => u() * (p.quality === "half" ? .5 : 1);
1432
- function A(t) {
1433
- x = d(t, {
1434
- dprPolicy: k,
1431
+ let j = () => h() * (m.quality === "half" ? .5 : 1);
1432
+ function M(t) {
1433
+ S = f(t, {
1434
+ dprPolicy: j,
1435
1435
  revealBloom: e.revealBloom ?? !0,
1436
1436
  contextAttrs: {
1437
1437
  alpha: !0,
@@ -1439,52 +1439,54 @@ function Ve(e) {
1439
1439
  antialias: !1,
1440
1440
  preserveDrawingBuffer: !1
1441
1441
  },
1442
- setupWGPU: Be({
1442
+ setupWGPU: Ue({
1443
1443
  canvas: t,
1444
- config: p,
1444
+ config: m,
1445
1445
  pointer: l,
1446
- satellites: f,
1447
- resolveFrame: D,
1448
- shouldContinue: O,
1449
- getReducedMotion: () => x?.reducedMotion ?? !1
1446
+ satellites: p,
1447
+ resolveFrame: k,
1448
+ shouldContinue: A,
1449
+ getReducedMotion: () => S?.reducedMotion ?? !1
1450
1450
  }),
1451
1451
  setupGL: (e) => {
1452
- let { prog: n, vs: r, fs: i, vao: a, buf: o, locs: s } = Me(e);
1452
+ let { prog: n, vs: r, fs: i, vao: a, buf: o, locs: s } = Fe(e);
1453
1453
  function c(n) {
1454
1454
  e.viewport(0, 0, n?.w ?? t.width, n?.h ?? t.height);
1455
1455
  }
1456
1456
  function u(r) {
1457
- Ae(e, n, a, s, t, p, l, f, D(r));
1457
+ Ne(e, n, a, s, t, m, l, p, k(r));
1458
1458
  }
1459
1459
  return {
1460
1460
  frame: u,
1461
- shouldContinue: O,
1461
+ shouldContinue: A,
1462
1462
  resize: c,
1463
1463
  teardown: () => {
1464
1464
  e.deleteProgram(n), e.deleteShader(r), e.deleteShader(i), e.deleteBuffer(o), e.deleteVertexArray(a);
1465
1465
  }
1466
1466
  };
1467
- }
1468
- }), x.armAsync();
1467
+ },
1468
+ onStatus: (e) => C.value = e
1469
+ }), S.armAsync().catch(() => void 0);
1469
1470
  }
1470
- return I(t, (e) => {
1471
- e && !x && A(e);
1472
- }, { immediate: !0 }), I(i, () => x?.wake()), I(o, () => x?.wake(), { deep: !0 }), j(() => {
1473
- T(), x?.dispose(), x = null;
1471
+ return z(t, (e) => {
1472
+ e && !S && M(e);
1473
+ }, { immediate: !0 }), z(i, () => S?.wake()), z(a, () => S?.wake()), z(o, () => S?.wake(), { deep: !0 }), s && z(s, () => S?.wake(), { deep: !0 }), N(() => {
1474
+ D(), S?.dispose(), S = null;
1474
1475
  }), {
1475
1476
  pause: () => {
1476
- S = !0, x?.suspend("manual");
1477
+ w = !0, S?.suspend("manual");
1477
1478
  },
1478
1479
  resume: () => {
1479
- S = !1, x?.resume("manual");
1480
+ w = !1, S?.resume("manual");
1480
1481
  },
1481
- wake: () => x?.wake(),
1482
- settled: C
1482
+ wake: () => S?.wake(),
1483
+ settled: T,
1484
+ rendererStatus: F(C)
1483
1485
  };
1484
1486
  }
1485
1487
  //#endregion
1486
1488
  //#region src/components/blob/Blob.vue?vue&type=script&setup=true&lang.ts
1487
- var He = 1.3, Ue = /* @__PURE__ */ e(/* @__PURE__ */ D({
1489
+ var Ge = ["aria-label", "disabled"], Ke = 1.3, qe = /* @__PURE__ */ e(/* @__PURE__ */ k({
1488
1490
  __name: "Blob",
1489
1491
  props: {
1490
1492
  color: {},
@@ -1494,89 +1496,106 @@ var He = 1.3, Ue = /* @__PURE__ */ e(/* @__PURE__ */ D({
1494
1496
  paused: {
1495
1497
  type: Boolean,
1496
1498
  default: !1
1499
+ },
1500
+ pressLabel: {},
1501
+ disabled: {
1502
+ type: Boolean,
1503
+ default: !1
1497
1504
  }
1498
1505
  },
1499
- emits: ["click", "update:paused"],
1506
+ emits: [
1507
+ "click",
1508
+ "update:paused",
1509
+ "rendererStatus"
1510
+ ],
1500
1511
  setup(e, { expose: n, emit: r }) {
1501
- let i = r, a = O(y, null), o = e.config ?? a;
1512
+ let i = r, a = A(s, null), o = e.config ?? a;
1502
1513
  if (!o) throw Error("[glass-ui] Blob: no blob config. Pass an explicit `config` prop (e.g. BLOB_CONFIG_DEFAULTS) or provide(BLOB_CONFIG_KEY, cfg) from an ancestor. There is no silent defaults synthesis.");
1503
- let s = () => e.config ?? a ?? o, c = new Proxy(o, { get(t, n, r) {
1514
+ let c = () => e.config ?? a ?? o, l = new Proxy(o, { get(t, n, r) {
1504
1515
  return n === "variant" && e.variant != null ? e.variant : Reflect.get(t, n, r);
1505
- } }), l = F("canvasRef"), u = F("wrapperRef"), d = F("hitLayerRef"), f = Math.min(1, Math.max(.25, o.geometry.bodyRadius / R * He)), p = `${(f * 50).toFixed(2)}%`, m = me(), h = he(d, { hitRadius: () => f }), g = be(o, e.color + e.seed), _ = t(), v = P(e.color), b = P(o.surface.rimColor), x = P([...o.color.paletteStops]), S = P([...o.color.satelliteColors ?? []]);
1506
- function C() {
1507
- let t = u.value, n = s();
1508
- _.invalidate(), v.value = _.resolve(e.color, t), b.value = _.resolve(n.surface.rimColor, t), x.value = n.color.paletteStops.map((e) => _.resolve(e, t)), S.value = (n.color.satelliteColors ?? []).map((e) => _.resolve(e, t));
1516
+ } }), u = R("canvasRef"), d = R("wrapperRef"), f = R("hitLayerRef"), p = T(() => !!e.pressLabel?.trim()), m = T(() => p.value && !e.disabled && !e.paused), h = T(() => m.value ? f.value : null), g = Math.min(1, Math.max(.25, o.geometry.bodyRadius / V * Ke)), _ = `${(g * 50).toFixed(2)}%`, v = _e(), y = ve(h, { hitRadius: () => g }), b = Ce(o, e.color + e.seed), x = t(), S = I(e.color), C = I(o.surface.rimColor), w = I([...o.color.paletteStops]), k = I([...o.color.satelliteColors ?? []]);
1517
+ function N() {
1518
+ let t = d.value, n = c();
1519
+ x.invalidate(), S.value = x.resolve(e.color, t), C.value = x.resolve(n.surface.rimColor, t), w.value = n.color.paletteStops.map((e) => x.resolve(e, t)), k.value = (n.color.satelliteColors ?? []).map((e) => x.resolve(e, t));
1509
1520
  }
1510
- let D = Ve({
1511
- canvasRef: l,
1512
- color: v,
1513
- rimColor: b,
1514
- paletteStops: x,
1515
- satelliteColors: S,
1516
- mood: m,
1517
- pointer: h,
1518
- satellites: g,
1519
- config: c
1521
+ let F = We({
1522
+ canvasRef: u,
1523
+ color: S,
1524
+ rimColor: C,
1525
+ paletteStops: w,
1526
+ satelliteColors: k,
1527
+ mood: v,
1528
+ pointer: y,
1529
+ satellites: b,
1530
+ config: l
1520
1531
  });
1521
- I(u, C, { immediate: !0 });
1522
- let j = null;
1523
- typeof document < "u" && (j = new MutationObserver(C), j.observe(document.documentElement, {
1532
+ F.rendererStatus && z(F.rendererStatus, (e) => i("rendererStatus", e), {
1533
+ immediate: !0,
1534
+ flush: "sync"
1535
+ }), z(d, N, { immediate: !0 });
1536
+ let L = null;
1537
+ typeof document < "u" && (L = new MutationObserver(N), L.observe(document.documentElement, {
1524
1538
  attributes: !0,
1525
1539
  attributeFilter: ["class"]
1526
- })), I(w(() => e.color), (t) => {
1527
- C(), g.reseed(t + e.seed);
1528
- }), I(() => {
1529
- let e = s();
1540
+ })), z(T(() => e.color), (t) => {
1541
+ N(), b.reseed(t + e.seed);
1542
+ }), z(() => {
1543
+ let e = c();
1530
1544
  return [
1531
1545
  e.color.paletteStops.join("|"),
1532
1546
  (e.color.satelliteColors ?? []).join("|"),
1533
1547
  e.surface.rimColor
1534
1548
  ];
1535
- }, () => C(), { deep: !0 }), I(() => h.active.value, (e) => {
1536
- e && D.wake();
1537
- }), I(() => e.paused, (e) => e ? D.pause() : D.resume(), { immediate: !0 }), A(() => {
1538
- j?.disconnect(), j = null;
1549
+ }, () => N(), { deep: !0 }), z(() => y.active.value, (e) => {
1550
+ e && F.wake();
1551
+ }), z(() => e.paused, (e) => e ? F.pause() : F.resume(), { immediate: !0 }), M(() => {
1552
+ L?.disconnect(), L = null;
1539
1553
  });
1540
- function N() {
1541
- g.nudge();
1554
+ function B() {
1555
+ b.nudge();
1542
1556
  }
1543
- function L(e) {
1544
- m.setMood(e, { source: "manual" });
1557
+ function H(e) {
1558
+ v.setMood(e, { source: "manual" });
1545
1559
  }
1546
- function z() {
1547
- h.click(o.interaction.clickImpulse);
1560
+ function U() {
1561
+ y.click(o.interaction.clickImpulse);
1548
1562
  }
1549
- function B(e) {
1550
- h.hitTest(e.clientX, e.clientY) && (z(), i("click"));
1563
+ function W() {
1564
+ U(), i("click");
1551
1565
  }
1552
1566
  return n({
1553
- nudge: N,
1554
- setMood: L,
1555
- pulse: z,
1556
- currentMood: m.currentMood,
1557
- pause: D.pause,
1558
- resume: D.resume,
1559
- settled: D.settled
1560
- }), (t, n) => (M(), T("div", {
1567
+ nudge: B,
1568
+ setMood: H,
1569
+ pulse: U,
1570
+ currentMood: v.currentMood,
1571
+ pause: F.pause,
1572
+ resume: F.resume,
1573
+ settled: F.settled,
1574
+ rendererStatus: F.rendererStatus
1575
+ }), (t, n) => (P(), D("div", {
1561
1576
  ref_key: "wrapperRef",
1562
- ref: u,
1577
+ ref: d,
1563
1578
  class: "goo-blob-wrapper",
1564
- style: k({ "--blob-color": e.color })
1565
- }, [E("canvas", {
1579
+ style: j({ "--blob-color": e.color })
1580
+ }, [O("canvas", {
1566
1581
  ref_key: "canvasRef",
1567
- ref: l,
1582
+ ref: u,
1568
1583
  class: "goo-blob-canvas",
1569
1584
  "aria-hidden": "true",
1570
1585
  "data-testid": "goo-blob-canvas"
1571
- }, null, 512), E("div", {
1586
+ }, null, 512), p.value ? (P(), D("button", {
1587
+ key: 0,
1572
1588
  ref_key: "hitLayerRef",
1573
- ref: d,
1589
+ ref: f,
1590
+ type: "button",
1574
1591
  class: "goo-blob-hit",
1575
- style: k({ "--blob-hit-radius": p }),
1592
+ "aria-label": e.pressLabel,
1593
+ disabled: e.disabled || e.paused,
1594
+ style: j({ "--blob-hit-radius": _ }),
1576
1595
  "data-testid": "goo-blob-hit",
1577
- onClick: B
1578
- }, null, 4)], 4));
1596
+ onClick: W
1597
+ }, null, 12, Ge)) : E("", !0)], 4));
1579
1598
  }
1580
- }), [["__scopeId", "data-v-c78535cc"]]);
1599
+ }), [["__scopeId", "data-v-dc84a327"]]);
1581
1600
  //#endregion
1582
- export { g as BLOB_CONFIG_DEFAULTS, y as BLOB_CONFIG_KEY, x as BLOB_HERO, Ue as Blob, v as LIGHTNESS_FLOOR_BRACKET, b as LIGHTNESS_FLOOR_DEFAULT, _ as clampLightnessFloor, me as useBlobMood, he as useBlobPointer, be as useBlobSatellites, Ve as useMetaballRenderer };
1601
+ export { i as BLOB_CONFIG_DEFAULTS, s as BLOB_CONFIG_KEY, l as BLOB_HERO, qe as Blob, o as LIGHTNESS_FLOOR_BRACKET, c as LIGHTNESS_FLOOR_DEFAULT, a as clampLightnessFloor, _e as useBlobMood, ve as useBlobPointer, Ce as useBlobSatellites, We as useMetaballRenderer };