@mkbabb/glass-ui 3.9.0 → 3.10.1

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 (265) hide show
  1. package/dist/{CardAction-DuArVky-.js → CardAction-DrAcAV4d.js} +2 -2
  2. package/dist/{CommandShortcut-CefCj5mt.js → CommandShortcut-mV2e1aG6.js} +2 -2
  3. package/dist/{DataTable-CUHMukiQ.js → DataTable-C3E6jZ5B.js} +2 -2
  4. package/dist/{DialogContent-BRkT1cjP.js → DialogContent-BxaaafFi.js} +1 -1
  5. package/dist/{HoverPopover-2LOIW34a.js → HoverPopover-CDA_SaCe.js} +1 -1
  6. package/dist/{MetricBadge-lTc002u2.js → MetricBadge-idgrkqoP.js} +1 -1
  7. package/dist/{Notification-BxK8LZMw.js → Notification-Cu0nN17_.js} +3 -3
  8. package/dist/{NumberFieldContent-BbLOh8RU.js → NumberFieldContent-CHEWghnY.js} +2 -2
  9. package/dist/{PopoverContent-BId6ggf_.js → PopoverContent-DpUvdYY-.js} +1 -1
  10. package/dist/{Progress-iEuD9pxG.js → Progress-BW-StFw2.js} +1 -1
  11. package/dist/{ScrollingText-BPP84wKo.js → ScrollingText-DruYCni_.js} +1 -1
  12. package/dist/{SelectScrollDownButton-T32cVFeM.js → SelectScrollDownButton-pirzjm--.js} +3 -3
  13. package/dist/{Switch-LDKLmmgx.js → Switch-DeAqg6pi.js} +1 -1
  14. package/dist/{TabsList-B8CVOQPC.js → TabsList-BAVzOZpg.js} +2 -2
  15. package/dist/{Toaster-1rYWrmAm.js → Toaster-CvuuW_y9.js} +49 -46
  16. package/dist/{ToggleGroupItem-Cev4pOVK.js → ToggleGroupItem-DtD37b4G.js} +4 -4
  17. package/dist/animated-digit.js +2 -2
  18. package/dist/api/index.d.ts +4 -4
  19. package/dist/api.js +1 -1
  20. package/dist/aurora.js +238 -547
  21. package/dist/{badge-BvwvT50i.js → badge-NdCQMvvB.js} +2 -2
  22. package/dist/badge.js +1 -1
  23. package/dist/{button-DN39cGqL.js → button-DyiWFAOE.js} +12 -12
  24. package/dist/button.js +1 -1
  25. package/dist/canvas.js +2 -2
  26. package/dist/card.js +1 -1
  27. package/dist/carousel.js +5 -5
  28. package/dist/collapsible.js +1 -1
  29. package/dist/{color-8jBjWiJ6.js → color-B65wWyQz.js} +9 -7
  30. package/dist/color.js +1 -1
  31. package/dist/command.js +1 -1
  32. package/dist/{compile-DAjIoEy2.js → compile-Ce_V55zi.js} +23 -23
  33. package/dist/components/custom/aurora/composables/atoms.d.ts +21 -4
  34. package/dist/components/custom/aurora/composables/runtime.d.ts +0 -9
  35. package/dist/components/custom/aurora/composables/uniformBridge.d.ts +0 -11
  36. package/dist/components/custom/aurora/constants/renderMode.d.ts +0 -32
  37. package/dist/components/custom/aurora/constants/shaders/brush.glsl.d.ts +1 -1
  38. package/dist/components/custom/aurora/constants/shaders/mediums.glsl.d.ts +2 -2
  39. package/dist/components/custom/aurora/constants/shaders/tonemap.glsl.d.ts +1 -1
  40. package/dist/components/custom/aurora/constants/shaders/vangogh-medium.glsl.d.ts +1 -0
  41. package/dist/components/custom/aurora/index.d.ts +1 -1
  42. package/dist/components/custom/constellation/Constellation.vue.d.ts +85 -1
  43. package/dist/components/custom/constellation/composables/createConstellationField.d.ts +35 -0
  44. package/dist/components/custom/constellation/composables/useConstellationPointer.d.ts +35 -0
  45. package/dist/components/custom/constellation/constants.d.ts +36 -0
  46. package/dist/components/custom/constellation/constellationDraw.d.ts +18 -0
  47. package/dist/components/custom/constellation/constellationField.d.ts +174 -63
  48. package/dist/components/custom/constellation/constellationInteraction.d.ts +102 -0
  49. package/dist/components/custom/constellation/index.d.ts +4 -2
  50. package/dist/components/custom/controls/DarkModeToggle.vue.d.ts +11 -0
  51. package/dist/components/custom/dock/GlassDock.vue.d.ts +2 -110
  52. package/dist/components/custom/dock/composables/dockMorphContext.d.ts +36 -0
  53. package/dist/components/custom/dock/composables/useDockMorphWindow.d.ts +15 -0
  54. package/dist/components/custom/dock/composables/useDockShellProps.d.ts +131 -0
  55. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +44 -0
  56. package/dist/components/custom/dock/constants.d.ts +23 -0
  57. package/dist/components/custom/fourier-field/FourierField.vue.d.ts +6 -0
  58. package/dist/components/custom/fourier-field/index.d.ts +25 -1
  59. package/dist/components/custom/fourier-field/math.d.ts +20 -8
  60. package/dist/components/custom/fourier-field/presets.d.ts +54 -0
  61. package/dist/components/custom/goo-blob/GooBlob.vue.d.ts +8 -10
  62. package/dist/components/custom/goo-blob/composables/buildMetaballProgram.d.ts +18 -0
  63. package/dist/components/custom/goo-blob/composables/uploadBlobUniforms.d.ts +41 -0
  64. package/dist/components/custom/goo-blob/composables/useBlobPointer.d.ts +4 -3
  65. package/dist/components/custom/goo-blob/composables/useMetaballRenderer.d.ts +16 -21
  66. package/dist/components/custom/goo-blob/constants.d.ts +52 -0
  67. package/dist/components/custom/goo-blob/index.d.ts +1 -1
  68. package/dist/components/custom/goo-blob/shaders/metaball-uniforms.glsl.d.ts +1 -0
  69. package/dist/components/custom/goo-blob/types.d.ts +59 -25
  70. package/dist/components/custom/instrument-chassis/InstrumentChassis.vue.d.ts +2 -2
  71. package/dist/components/custom/tabs/constants.d.ts +12 -0
  72. package/dist/components/custom/underline/GlassUnderline.vue.d.ts +84 -0
  73. package/dist/components/custom/underline/index.d.ts +2 -0
  74. package/dist/components/custom/underline/types.d.ts +56 -0
  75. package/dist/components/ui/drawer/Drawer.vue.d.ts +1 -0
  76. package/dist/components/ui/dropdown-menu/DropdownMenuSubContent.vue.d.ts +2 -2
  77. package/dist/components/ui/slider/index.d.ts +25 -18
  78. package/dist/components/ui/toast/use-toast.d.ts +2 -2
  79. package/dist/composables/color/index.d.ts +24 -7
  80. package/dist/composables/glass/useSpecularTracking.d.ts +12 -3
  81. package/dist/composables/glass/webgl/shaders/procedural-color.glsl.d.ts +1 -6
  82. package/dist/composables/motion/curves.d.ts +48 -0
  83. package/dist/composables/motion/index.d.ts +2 -0
  84. package/dist/composables/motion/springPresets.d.ts +33 -0
  85. package/dist/composables/motion/suite.d.ts +2 -0
  86. package/dist/composables/motion/useSpringMount.d.ts +1 -1
  87. package/dist/configurator.js +1 -1
  88. package/dist/confirm-dialog.js +2 -2
  89. package/dist/constellation.js +322 -147
  90. package/dist/controls.js +48 -14
  91. package/dist/dark.js +1 -1
  92. package/dist/data-table.js +1 -1
  93. package/dist/dialog.js +2 -2
  94. package/dist/dock.js +340 -327
  95. package/dist/dockContext-bho8B1A4.js +17 -0
  96. package/dist/{dropdown-menu-D77jX6Df.js → dropdown-menu-DVnQcA0E.js} +7 -4
  97. package/dist/dropdown-menu.js +1 -1
  98. package/dist/expandable-container.js +1 -1
  99. package/dist/forms.js +2 -2
  100. package/dist/fourier-field.js +147 -120
  101. package/dist/fourier-math.d.ts +1 -0
  102. package/dist/fourier-math.js +2 -0
  103. package/dist/glass-ui.css +1 -1
  104. package/dist/glass-ui.js +286 -207
  105. package/dist/goo-blob.js +368 -322
  106. package/dist/hover-popover.js +1 -1
  107. package/dist/icon-tooltip.js +1 -1
  108. package/dist/index.d.ts +0 -2
  109. package/dist/keyboard.js +1 -1
  110. package/dist/labeled-field.js +5 -5
  111. package/dist/math-BUU9hHID.js +43 -0
  112. package/dist/metric-badge.js +1 -1
  113. package/dist/metric-stack.js +2 -2
  114. package/dist/motion-core.js +4 -4
  115. package/dist/motion-curves.d.ts +1 -0
  116. package/dist/motion-curves.js +130 -0
  117. package/dist/motion.js +38 -37
  118. package/dist/notification.js +1 -1
  119. package/dist/number-field.js +1 -1
  120. package/dist/popover.js +1 -1
  121. package/dist/progress.js +1 -1
  122. package/dist/pulse.js +1 -1
  123. package/dist/reactive.js +1 -1
  124. package/dist/scrolling-text.js +1 -1
  125. package/dist/search.js +6 -6
  126. package/dist/select.js +1 -1
  127. package/dist/{sheet-VZEtNFvO.js → sheet-ChSXcJpU.js} +1 -1
  128. package/dist/sheet.js +1 -1
  129. package/dist/{slider-DC2mwuoe.js → slider-sfl8gFDD.js} +8 -8
  130. package/dist/slider.js +1 -1
  131. package/dist/sortable-list.js +2 -2
  132. package/dist/springPresets-aRSm-4_k.js +40 -0
  133. package/dist/stacked-icons.js +6 -6
  134. package/dist/styles/cards.css +2 -2
  135. package/dist/styles/components.css +1 -1
  136. package/dist/styles/dock/layer-group.css +38 -4
  137. package/dist/styles/dock/layers.css +11 -1
  138. package/dist/styles/dock/morph.css +95 -19
  139. package/dist/styles/dock/shell.css +12 -0
  140. package/dist/styles/dock-controls.css +25 -12
  141. package/dist/styles/drawer.css +14 -4
  142. package/dist/styles/floating-panel.css +2 -0
  143. package/dist/styles/glass/a11y-fallback.css +245 -0
  144. package/dist/styles/glass/ladder.css +304 -0
  145. package/dist/styles/glass/material.css +238 -0
  146. package/dist/styles/glass/progress-rail.css +78 -0
  147. package/dist/styles/glass/squircle.css +66 -0
  148. package/dist/styles/glass/surfaces.css +306 -0
  149. package/dist/styles/glass-refract.css +2 -0
  150. package/dist/styles/glass.css +31 -1052
  151. package/dist/styles/hover-popover.css +2 -0
  152. package/dist/styles/index.css +24 -6
  153. package/dist/styles/instrument-chassis.css +4 -0
  154. package/dist/styles/theme.css +14 -14
  155. package/dist/styles/tokens/color-radius.css +250 -0
  156. package/dist/styles/tokens/dark-arm.css +194 -0
  157. package/dist/styles/tokens/glass.css +413 -0
  158. package/dist/styles/tokens/light-dark.css +158 -0
  159. package/dist/styles/tokens/offsets-sizing.css +406 -0
  160. package/dist/styles/tokens/property-regs.css +169 -0
  161. package/dist/styles/tokens/scale-paper.css +361 -0
  162. package/dist/styles/tokens/scheme-motion.css +334 -0
  163. package/dist/styles/tokens/shadow.css +132 -0
  164. package/dist/styles/tokens.css +22 -2269
  165. package/dist/styles/transitions.css +20 -2
  166. package/dist/styles/typography.css +18 -6
  167. package/dist/styles/utilities/a11y-overrides.css +140 -0
  168. package/dist/styles/utilities/animate.css +26 -0
  169. package/dist/styles/utilities/base.css +365 -0
  170. package/dist/styles/utilities/btn.css +399 -0
  171. package/dist/styles/utilities/components.css +317 -0
  172. package/dist/styles/utilities.css +19 -1170
  173. package/dist/switch.js +1 -1
  174. package/dist/tabs.js +98 -98
  175. package/dist/timeline.js +2 -2
  176. package/dist/toast.js +1 -1
  177. package/dist/toggle-group.js +1 -1
  178. package/dist/typewriter.js +1 -1
  179. package/dist/underline.d.ts +1 -0
  180. package/dist/underline.js +85 -0
  181. package/dist/{useAnimatedNumber-C5I3wWd8.js → useAnimatedNumber-DfVgP4te.js} +1 -1
  182. package/dist/{useConfiguratorState-DxAqksK6.js → useConfiguratorState-BdQXh9ie.js} +1 -1
  183. package/dist/useSpecularTracking-DFK_fhpG.js +32 -0
  184. package/dist/useSpringMount-DXUzxBjV.js +108 -0
  185. package/dist/watercolor-dot.js +2 -2
  186. package/package.json +62 -38
  187. package/src/styles/cards.css +2 -2
  188. package/src/styles/dock/layer-group.css +38 -4
  189. package/src/styles/dock/layers.css +11 -1
  190. package/src/styles/dock/morph.css +95 -19
  191. package/src/styles/dock/shell.css +12 -0
  192. package/src/styles/dock-controls.css +25 -12
  193. package/src/styles/drawer.css +12 -4
  194. package/src/styles/glass/a11y-fallback.css +245 -0
  195. package/src/styles/glass/ladder.css +304 -0
  196. package/src/styles/glass/material.css +238 -0
  197. package/src/styles/glass/progress-rail.css +78 -0
  198. package/src/styles/glass/squircle.css +66 -0
  199. package/src/styles/glass/surfaces.css +306 -0
  200. package/src/styles/glass.css +31 -1052
  201. package/src/styles/index.css +24 -6
  202. package/src/styles/theme.css +14 -14
  203. package/src/styles/tokens/color-radius.css +250 -0
  204. package/src/styles/tokens/dark-arm.css +194 -0
  205. package/src/styles/tokens/glass.css +413 -0
  206. package/src/styles/tokens/light-dark.css +158 -0
  207. package/src/styles/tokens/offsets-sizing.css +406 -0
  208. package/src/styles/tokens/property-regs.css +169 -0
  209. package/src/styles/tokens/scale-paper.css +361 -0
  210. package/src/styles/tokens/scheme-motion.css +334 -0
  211. package/src/styles/tokens/shadow.css +132 -0
  212. package/src/styles/tokens.css +22 -2269
  213. package/src/styles/transitions.css +20 -2
  214. package/src/styles/typography.css +18 -6
  215. package/src/styles/utilities/a11y-overrides.css +140 -0
  216. package/src/styles/utilities/animate.css +26 -0
  217. package/src/styles/utilities/base.css +365 -0
  218. package/src/styles/utilities/btn.css +399 -0
  219. package/src/styles/utilities/components.css +317 -0
  220. package/src/styles/utilities.css +19 -1170
  221. package/dist/DeckProgress-Dmk4_AKN.js +0 -23
  222. package/dist/InstrumentRail-CUJ05YVG.js +0 -44
  223. package/dist/components/custom/aurora/composables/gpuRuntime.d.ts +0 -16
  224. package/dist/components/custom/aurora/constants/shaders/aurora.wgsl.d.ts +0 -7
  225. package/dist/components/custom/deck-progress/DeckProgress.vue.d.ts +0 -27
  226. package/dist/components/custom/deck-progress/index.d.ts +0 -2
  227. package/dist/components/custom/dialog-native/GlassDialogNative.vue.d.ts +0 -57
  228. package/dist/components/custom/dialog-native/index.d.ts +0 -1
  229. package/dist/components/custom/glass-panel/GlassPanel.vue.d.ts +0 -41
  230. package/dist/components/custom/glass-panel/index.d.ts +0 -2
  231. package/dist/components/custom/header-ribbon/HeaderRibbon.vue.d.ts +0 -31
  232. package/dist/components/custom/header-ribbon/index.d.ts +0 -2
  233. package/dist/components/custom/header-ribbon/types.d.ts +0 -7
  234. package/dist/components/custom/instrument-rail/InstrumentRail.vue.d.ts +0 -91
  235. package/dist/components/custom/instrument-rail/index.d.ts +0 -2
  236. package/dist/composables/glass/createGPUCanvas.d.ts +0 -40
  237. package/dist/deck-progress.d.ts +0 -1
  238. package/dist/deck-progress.js +0 -2
  239. package/dist/dockContext-BKeIMmNk.js +0 -9
  240. package/dist/glass-panel.d.ts +0 -1
  241. package/dist/glass-panel.js +0 -44
  242. package/dist/header-ribbon.d.ts +0 -1
  243. package/dist/header-ribbon.js +0 -63
  244. package/dist/instrument-rail.d.ts +0 -1
  245. package/dist/instrument-rail.js +0 -2
  246. package/dist/useGlassRenderer-5I0YkI4t.js +0 -69
  247. package/dist/useSpecularTracking-BVRZsRHA.js +0 -26
  248. package/dist/useSpringMount-BJSHcLl3.js +0 -113
  249. /package/dist/{CollapsibleContent-CP9qF1v4.js → CollapsibleContent-Drow5WkV.js} +0 -0
  250. /package/dist/{DialogFooter-Gprw8H_A.js → DialogFooter-DufLHi0y.js} +0 -0
  251. /package/dist/{IconTooltip-yefK7cJc.js → IconTooltip-BrQ5p181.js} +0 -0
  252. /package/dist/{Input-DWQQIOC4.js → Input-B-F818RU.js} +0 -0
  253. /package/dist/{_plugin-vue_export-helper-ok8pgSl5.js → _plugin-vue_export-helper-DWghtRt7.js} +0 -0
  254. /package/dist/{constants-CS75AWHG.js → constants-C8NMonuo.js} +0 -0
  255. /package/dist/{presets-BKVyQfbt.js → presets-1OhFpaIC.js} +0 -0
  256. /package/dist/{prng-wHuHlNHE.js → prng-CjVgzjQT.js} +0 -0
  257. /package/dist/{resolveCanvasColor-BBiYfp8g.js → resolveCanvasColor-CRvVzOvP.js} +0 -0
  258. /package/dist/{useCanvas2D-ClrQuZtp.js → useCanvas2D-CSeH8h16.js} +0 -0
  259. /package/dist/{useGlobalDark-yhL4Wp-s.js → useGlobalDark-D7R9OypB.js} +0 -0
  260. /package/dist/{useIntersectionPause-Cc-H9ees.js → useIntersectionPause-DAdVPVp4.js} +0 -0
  261. /package/dist/{useInterval-Dsmqwi03.js → useInterval-D3USn0yc.js} +0 -0
  262. /package/dist/{useKeyboardShortcuts-Be3w_Rwk.js → useKeyboardShortcuts-i8tHd5WO.js} +0 -0
  263. /package/dist/{useScrollProgress-CAH8Ofwt.js → useScrollProgress-CcgmgMQt.js} +0 -0
  264. /package/dist/{useSortable-C8ReQ50P.js → useSortable-DnyGXKKY.js} +0 -0
  265. /package/dist/{useTextHighlight-DON84L8w.js → useTextHighlight-B3b10W6r.js} +0 -0
package/dist/goo-blob.js CHANGED
@@ -1,77 +1,77 @@
1
- import { t as e } from "./_plugin-vue_export-helper-ok8pgSl5.js";
1
+ import { t as e } from "./_plugin-vue_export-helper-DWghtRt7.js";
2
2
  import { t } from "./useResolveTokenColor-r9pnNjqK.js";
3
- import { d as n, l as r, n as i, o as a, r as o, s, t as c } from "./compile-DAjIoEy2.js";
4
- import { t as l } from "./useIntersectionPause-Cc-H9ees.js";
5
- import { n as u, t as d } from "./prng-wHuHlNHE.js";
6
- import { computed as f, createElementBlock as p, createElementVNode as m, defineComponent as h, inject as g, normalizeStyle as _, onScopeDispose as v, onUnmounted as y, openBlock as b, readonly as x, ref as S, useTemplateRef as C, watch as w } from "vue";
7
- import { SpringProgress as T } from "@mkbabb/keyframes.js";
3
+ import { a as n, c as r, n as i, o as a, r as o, s, t as c } from "./compile-Ce_V55zi.js";
4
+ import { s as l, t as u } from "./color-B65wWyQz.js";
5
+ import { t as d } from "./useIntersectionPause-DAdVPVp4.js";
6
+ import { n as f, t as p } from "./prng-CjVgzjQT.js";
7
+ import { computed as m, createElementBlock as h, createElementVNode as g, defineComponent as _, inject as v, normalizeStyle as y, onScopeDispose as b, onUnmounted as x, openBlock as S, readonly as C, ref as w, useTemplateRef as T, watch as E } from "vue";
8
+ import { SpringProgress as D } from "@mkbabb/keyframes.js";
8
9
  //#region src/components/custom/goo-blob/types.ts
9
- var E = {
10
- canvasSize: 200,
11
- bodyRadius: .22,
12
- satelliteCount: 3,
13
- satelliteRadius: .082,
14
- orbitRadius: .17,
10
+ var O = {
11
+ geometry: {
12
+ canvasSize: 200,
13
+ bodyRadius: .22,
14
+ satelliteCount: 3,
15
+ satelliteRadius: .082,
16
+ orbitRadius: .17,
17
+ eccentricity: .05
18
+ },
19
+ satellites: {
20
+ mergeDuration: 1800,
21
+ absorbedDuration: [2e3, 4e3],
22
+ emergeDuration: 2200,
23
+ orbitDuration: [8e3, 14e3]
24
+ },
25
+ membrane: {
26
+ smoothK: .05,
27
+ merge: "quadratic",
28
+ noiseAmp: .038,
29
+ noiseFreq: 3.5,
30
+ noiseSpeed: .08,
31
+ warpAmp: .35,
32
+ pulseFreq: .3,
33
+ pulseAmp: .008
34
+ },
35
+ color: {
36
+ paletteStops: [
37
+ "#b5947f",
38
+ "#d4b27d",
39
+ "#dad6b1"
40
+ ],
41
+ hueRange: 5,
42
+ satShift: 0,
43
+ brightnessShift: 0,
44
+ colorNoiseFreq: 2,
45
+ colorNoiseSpeed: .05
46
+ },
47
+ surface: {
48
+ lit: !0,
49
+ rimColor: "#8c694e",
50
+ lightDir: [
51
+ .4,
52
+ .7,
53
+ .6
54
+ ],
55
+ specStrength: .16,
56
+ specShininess: 20,
57
+ rimPower: 2.5,
58
+ rimStrength: .32,
59
+ iridescence: .09,
60
+ iridHue: 85,
61
+ iridSpeed: .06,
62
+ sssScale: .1,
63
+ sssPower: 2,
64
+ coreGlow: .06
65
+ },
66
+ interaction: {
67
+ pointerAttraction: .35,
68
+ pointerStrength: .1,
69
+ stretch: .5,
70
+ clickImpulse: .5
71
+ },
15
72
  quality: "full",
16
- tempo: 1,
17
- smoothK: .05,
18
- merge: "quadratic",
19
- noiseAmp: .038,
20
- noiseFreq: 3.5,
21
- noiseSpeed: .08,
22
- warpAmp: .35,
23
- pulseFreq: .3,
24
- pulseAmp: .008,
25
- hueRange: 5,
26
- satShift: 0,
27
- brightnessShift: 0,
28
- colorNoiseFreq: 2,
29
- colorNoiseSpeed: .05,
30
- paletteStops: [],
31
- iridescence: .09,
32
- iridHue: 85,
33
- iridSpeed: .06,
34
- sssScale: .1,
35
- sssPower: 2,
36
- coreGlow: .06,
37
- lit: !0,
38
- rimColor: "var(--foreground)",
39
- lightDir: [
40
- .4,
41
- .7,
42
- .6
43
- ],
44
- specStrength: .16,
45
- specShininess: 20,
46
- rimPower: 2.5,
47
- rimStrength: .32,
48
- pointerAttraction: .35,
49
- pointerStrength: .18,
50
- stretch: .5,
51
- clickImpulse: .5,
52
- eccentricity: .05,
53
- orbitSpeedScale: 1,
54
- wobbleScale: 1,
55
- mergeRate: 1,
56
- mergeDuration: 1800,
57
- absorbedDuration: [2e3, 4e3],
58
- emergeDuration: 2200,
59
- orbitDuration: [8e3, 14e3]
60
- }, D = Symbol("blobConfig");
61
- //#endregion
62
- //#region src/components/custom/goo-blob/composables/easing.ts
63
- function O(e) {
64
- return e < .5 ? 2 * e * e : 1 - 2 * (1 - e) * (1 - e);
65
- }
66
- function k(e) {
67
- return e * e;
68
- }
69
- function A(e) {
70
- return 1 - (1 - e) * (1 - e);
71
- }
72
- //#endregion
73
- //#region src/components/custom/goo-blob/composables/useBlobMood.ts
74
- var j = {
73
+ tempo: 1
74
+ }, k = Symbol("blobConfig"), A = 1 / 1.6, j = {
75
75
  idle: {
76
76
  valence: 0,
77
77
  arousal: .35
@@ -121,8 +121,21 @@ var P = {
121
121
  curious: 800,
122
122
  sleepy: 2500,
123
123
  excited: 600
124
- };
125
- function I(e, t, n) {
124
+ }, I = 6e3, L = .35, R = .75, z = 2e3, B = /* @__PURE__ */ "uResolution.uTime.uBaseColor.uPointer.uPointerActive.uPointerAttraction.uPointerStrength.uBodyRadius.uPulsePhase.uPulseAmp.uNoiseAmp.uNoiseFreq.uNoiseSpeed.uWarpAmp.uSmoothK.uMerge.uMaxReach.uLit.uRimColor.uLightDir.uSpecStrength.uSpecShininess.uRimPower.uRimStrength.uIridescence.uIridHue.uIridSpeed.uSssScale.uSssPower.uCoreGlow.uHueRange.uSatShift.uBrightnessShift.uColorNoiseFreq.uColorNoiseSpeed.uStopCount.uSatCount.uTrailCount.uVelocity.uStretch".split(".");
125
+ //#endregion
126
+ //#region src/components/custom/goo-blob/composables/easing.ts
127
+ function ee(e) {
128
+ return e < .5 ? 2 * e * e : 1 - 2 * (1 - e) * (1 - e);
129
+ }
130
+ function te(e) {
131
+ return e * e;
132
+ }
133
+ function ne(e) {
134
+ return 1 - (1 - e) * (1 - e);
135
+ }
136
+ //#endregion
137
+ //#region src/components/custom/goo-blob/composables/useBlobMood.ts
138
+ function re(e, t, n) {
126
139
  let r = (e, t) => e + (t - e) * n;
127
140
  return {
128
141
  orbitSpeedScale: r(e.orbitSpeedScale, t.orbitSpeedScale),
@@ -139,9 +152,8 @@ function I(e, t, n) {
139
152
  iridScale: r(e.iridScale, t.iridScale)
140
153
  };
141
154
  }
142
- var L = 6e3;
143
- function R() {
144
- let e = S("idle"), t = S({ ...P.idle }), n = { ...P.idle }, r = { ...P.idle }, i = 0, a = 0, o = !1, s = 0, c = !1, l = !1, u = 0;
155
+ function V() {
156
+ let e = w("idle"), t = w({ ...P.idle }), n = { ...P.idle }, r = { ...P.idle }, i = 0, a = 0, o = !1, s = 0, c = !1, l = !1, u = 0;
145
157
  function d(s, l = {}) {
146
158
  (l.source ?? "manual") === "manual" && (c = !0), !(s === e.value && !o) && (e.value = s, n = { ...t.value }, r = P[s], a = F[s], i = 0, o = !0);
147
159
  }
@@ -153,24 +165,24 @@ function R() {
153
165
  s = 900, d("excited", { source: "auto" });
154
166
  return;
155
167
  }
156
- s > 0 || (e.pointerActive ? d("curious", { source: "auto" }) : e.idleMs > L ? d("sleepy", { source: "auto" }) : d("idle", { source: "auto" }));
168
+ s > 0 || (e.pointerActive ? d("curious", { source: "auto" }) : e.idleMs > 6e3 ? d("sleepy", { source: "auto" }) : d("idle", { source: "auto" }));
157
169
  }
158
170
  }
159
171
  function p() {
160
- return o || s > 0 || c && e.value !== "idle" ? !1 : !(!c && e.value !== "sleepy" && u < L);
172
+ return o || s > 0 || c && e.value !== "idle" ? !1 : !(!c && e.value !== "sleepy" && u < 6e3);
161
173
  }
162
174
  function m() {
163
- return o || s > 0 || c || e.value === "sleepy" ? Infinity : Math.max(0, L - u);
175
+ return o || s > 0 || c || e.value === "sleepy" ? Infinity : Math.max(0, I - u);
164
176
  }
165
177
  function h(e) {
166
178
  if (s > 0 && (s = Math.max(0, s - e)), !o) return;
167
179
  i += e;
168
- let c = Math.min(i / a, 1), l = O(c);
169
- t.value = I(n, r, l), c >= 1 && (o = !1);
180
+ let c = Math.min(i / a, 1), l = ee(c);
181
+ t.value = re(n, r, l), c >= 1 && (o = !1);
170
182
  }
171
183
  return {
172
- currentMood: x(e),
173
- params: x(t),
184
+ currentMood: C(e),
185
+ params: C(t),
174
186
  setMood: d,
175
187
  update: f,
176
188
  tick: h,
@@ -178,17 +190,19 @@ function R() {
178
190
  nextAutoMoodMs: m
179
191
  };
180
192
  }
181
- function z(e) {
182
- let t = S({
193
+ //#endregion
194
+ //#region src/components/custom/goo-blob/composables/useBlobPointer.ts
195
+ function H(e) {
196
+ let t = w({
183
197
  x: 0,
184
198
  y: 0
185
- }), n = S({
199
+ }), n = w({
186
200
  x: 0,
187
201
  y: 0
188
- }), r = S(!1), i = S(0), a = 0, o = 0, s = {
202
+ }), r = w(!1), i = w(0), a = 0, o = 0, s = {
189
203
  response: .18,
190
204
  dampingFraction: 1
191
- }, c = new T(s), l = new T(s), u = Array.from({ length: 15 }, () => ({
205
+ }, c = new D(s), l = new D(s), u = Array.from({ length: 15 }, () => ({
192
206
  x: 0,
193
207
  y: 0,
194
208
  radius: 0
@@ -203,30 +217,30 @@ function z(e) {
203
217
  r.value = !1;
204
218
  }
205
219
  let _ = null;
206
- w(e, (e) => {
220
+ E(e, (e) => {
207
221
  _ &&= (_(), null), e && (e.addEventListener("pointermove", h), e.addEventListener("pointerleave", g), _ = () => {
208
222
  e.removeEventListener("pointermove", h), e.removeEventListener("pointerleave", g);
209
223
  });
210
- }, { immediate: !0 }), y(() => _?.());
224
+ }, { immediate: !0 }), x(() => _?.());
211
225
  function v(e = 16) {
212
- let s = Math.min(e, 50) / 1e3;
226
+ let s = Math.min(e, 50), h = s / 1e3;
213
227
  r.value ? O = 0 : O += Math.min(e, 50);
214
- let h = r.value ? a : 0, g = r.value ? o : 0;
215
- if (c.target = h, l.target = g, c.tick(s), l.tick(s), t.value = {
228
+ let g = r.value ? a : 0, _ = r.value ? o : 0;
229
+ if (c.target = g, l.target = _, c.tickDt(s), l.tickDt(s), t.value = {
216
230
  x: c.value,
217
231
  y: l.value
218
232
  }, n.value = {
219
233
  x: c.velocity,
220
234
  y: l.velocity
221
235
  }, p !== 0 || m !== 0) {
222
- let e = -324 * p - 2 * .35 * 18 * m;
223
- m += e * s, p += m * s, p < -.9 && (p = -.9), Math.abs(p) < 1e-4 && Math.abs(m) < 1e-4 && (p = 0, m = 0);
236
+ let e = -324 * p - 2 * L * 18 * m;
237
+ m += e * h, p += m * h, p < -.9 && (p = -.9), Math.abs(p) < 1e-4 && Math.abs(m) < 1e-4 && (p = 0, m = 0);
224
238
  }
225
239
  i.value = p;
226
- let _ = Math.hypot(c.velocity, l.velocity);
227
- r.value || _ > .05 ? (d = (d + 1) % 15, u[d].x = c.value, u[d].y = l.value, f = Math.min(f + 1, 15)) : f > 0 && (f = Math.max(0, f - 1));
240
+ let v = Math.hypot(c.velocity, l.velocity);
241
+ r.value || v > .05 ? (d = (d + 1) % 15, u[d].x = c.value, u[d].y = l.value, f = Math.min(f + 1, 15)) : f > 0 && (f = Math.max(0, f - 1));
228
242
  }
229
- function b(e) {
243
+ function y(e) {
230
244
  let t = [];
231
245
  for (let n = 0; n < f; n++) {
232
246
  let r = u[(d - n + 30) % 15];
@@ -241,13 +255,13 @@ function z(e) {
241
255
  count: f
242
256
  };
243
257
  }
244
- let C = !1;
245
- function E(e) {
246
- m += e * 18, C = !0;
258
+ let b = !1;
259
+ function S(e) {
260
+ m += e * 18, b = !0;
247
261
  }
248
- function D() {
249
- let e = C;
250
- return C = !1, e;
262
+ function T() {
263
+ let e = b;
264
+ return b = !1, e;
251
265
  }
252
266
  let O = 0;
253
267
  function k() {
@@ -259,36 +273,35 @@ function z(e) {
259
273
  y: 0
260
274
  }, p = 0, m = 0, i.value = 0, f = 0;
261
275
  }
262
- let A = .001;
263
- function j() {
264
- return !(r.value || Math.hypot(c.velocity, l.velocity) > A || Math.abs(c.value) > A || Math.abs(l.value) > A || f > 0 || p !== 0 || m !== 0);
276
+ function A() {
277
+ return !(r.value || Math.hypot(c.velocity, l.velocity) > .001 || Math.abs(c.value) > .001 || Math.abs(l.value) > .001 || f > 0 || p !== 0 || m !== 0);
265
278
  }
266
279
  return {
267
- pointer: x(t),
268
- velocity: x(n),
269
- active: x(r),
270
- pulse: x(i),
280
+ pointer: C(t),
281
+ velocity: C(n),
282
+ active: C(r),
283
+ pulse: C(i),
271
284
  idleMs: () => O,
272
285
  tick: v,
273
- trailSources: b,
274
- click: E,
275
- consumeClick: D,
286
+ trailSources: y,
287
+ click: S,
288
+ consumeClick: T,
276
289
  rest: k,
277
- isAtRest: j
290
+ isAtRest: A
278
291
  };
279
292
  }
280
293
  //#endregion
281
294
  //#region src/components/custom/goo-blob/composables/useBlobSatellites.ts
282
- function B(e, t, n) {
295
+ function U(e, t, n) {
283
296
  return t + e() * (n - t);
284
297
  }
285
- function V(e) {
298
+ function W(e) {
286
299
  return e < 0 ? 0 : e > 1 ? 1 : e;
287
300
  }
288
- function H(e, t, n) {
301
+ function G(e, t, n) {
289
302
  return e + (t - e) * n;
290
303
  }
291
- function ee(e, t, n, r, i) {
304
+ function ie(e, t, n, r, i) {
292
305
  let a = t / 4 * Math.PI * 2 + (e() - .5) * Math.PI, o = n * (.8 + e() * .4), s = r * (.3 + e() * .7);
293
306
  return {
294
307
  phase: "orbiting",
@@ -315,26 +328,25 @@ function ee(e, t, n, r, i) {
315
328
  endY: 0
316
329
  };
317
330
  }
318
- function U(e, t, n, r) {
331
+ function K(e, t, n, r) {
319
332
  e.phase = t, e.phaseStart = n, e.phaseDuration = r;
320
333
  }
321
- function W(e, t, n, r) {
334
+ function q(e, t, n, r) {
322
335
  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));
323
336
  return {
324
337
  x: (e.baseRadiusX + o) * Math.cos(a) + e.pertXAmp * Math.sin(e.pertXFreq * i + e.pertXPhase),
325
338
  y: (e.baseRadiusY + o) * Math.sin(a) + e.pertYAmp * Math.cos(e.pertYFreq * i + e.pertYPhase)
326
339
  };
327
340
  }
328
- function te(e, t, n, r, i) {
341
+ function ae(e, t, n, r, i) {
329
342
  e.timeOrigin = i, e.angularSpeed = .08 + t() * .16, e.phaseOffset = t() * Math.PI * 2;
330
343
  let a = n * (.8 + t() * .4), o = r * (.3 + t() * .7);
331
344
  e.baseRadiusX = a * (1 - o), e.baseRadiusY = a * (1 + o), e.wobbleAmp1 = .02 + t() * .06, e.wobbleFreq1 = .08 + t() * .22, e.wobbleAmp2 = .015 + t() * .04, 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;
332
345
  }
333
- var G = .75, K = 2e3;
334
- function q(e, t) {
335
- let n = u(d(t + "goo")), r = [], i = [], a = [], o = -Infinity, s = e.orbitRadius;
346
+ function J(e, t) {
347
+ let n = f(p(t + "goo")), r = [], i = [], a = [], o = -Infinity, s = e.geometry.orbitRadius;
336
348
  function c() {
337
- let t = e.orbitRadius;
349
+ let t = e.geometry.orbitRadius;
338
350
  if (t !== s && s > 0) {
339
351
  let e = t / s;
340
352
  for (let t of r) t.baseRadiusX *= e, t.baseRadiusY *= e;
@@ -342,11 +354,11 @@ function q(e, t) {
342
354
  }
343
355
  }
344
356
  function l(t) {
345
- let o = e.satelliteCount;
346
- for (; r.length < o;) r.push(ee(n, r.length, e.orbitRadius, e.eccentricity, t)), i.push({
357
+ let o = e.geometry.satelliteCount;
358
+ for (; r.length < o;) r.push(ie(n, r.length, e.geometry.orbitRadius, e.geometry.eccentricity, t)), i.push({
347
359
  x: 0,
348
360
  y: 0,
349
- radius: e.satelliteRadius,
361
+ radius: e.geometry.satelliteRadius,
350
362
  opacity: 0
351
363
  }), a.push({
352
364
  x: 0,
@@ -355,66 +367,66 @@ function q(e, t) {
355
367
  });
356
368
  r.length > o && (r.length = o, i.length = o, a.length = o);
357
369
  }
358
- function f(t, s) {
370
+ function u(t, s) {
359
371
  l(t), c();
360
- let u = r.length, d = s.mergeRate, f = e.satelliteRadius, p = e.mergeDuration, m = e.emergeDuration, h = e.orbitDuration, g = e.absorbedDuration;
372
+ let u = r.length, d = s.mergeRate, f = e.geometry.satelliteRadius, p = e.satellites.mergeDuration, m = e.satellites.emergeDuration, h = e.satellites.orbitDuration, g = e.satellites.absorbedDuration;
361
373
  for (let c = 0; c < u; c++) {
362
- let l = r[c], u = t - l.phaseStart, _ = V(l.phaseDuration > 0 ? u / l.phaseDuration : 1);
374
+ let l = r[c], u = t - l.phaseStart, _ = W(l.phaseDuration > 0 ? u / l.phaseDuration : 1);
363
375
  switch (l.phase) {
364
376
  case "orbiting":
365
- if (_ >= 1) if (t - o < 3e3 * d) l.phaseStart = t, l.phaseDuration = B(n, h[0], h[1]);
377
+ if (_ >= 1) if (t - o < 3e3 * d) l.phaseStart = t, l.phaseDuration = U(n, h[0], h[1]);
366
378
  else {
367
- let e = W(l, t, s.orbitSpeedScale, s.wobbleScale);
379
+ let e = q(l, t, s.orbitSpeedScale, s.wobbleScale);
368
380
  l.startX = e.x, l.startY = e.y;
369
381
  let n = Math.hypot(e.x, e.y), r = n > .01 ? .08 / n : 0;
370
- l.endX = e.x * r, l.endY = e.y * r, U(l, "merging", t, p), o = t;
382
+ l.endX = e.x * r, l.endY = e.y * r, K(l, "merging", t, p), o = t;
371
383
  }
372
384
  break;
373
385
  case "merging":
374
- _ >= 1 && U(l, "absorbed", t, B(n, g[0], g[1]));
386
+ _ >= 1 && K(l, "absorbed", t, U(n, g[0], g[1]));
375
387
  break;
376
388
  case "absorbed":
377
389
  if (_ >= 1) {
378
- te(l, n, e.orbitRadius, e.eccentricity, t);
379
- let r = W(l, t + 3e3, s.orbitSpeedScale, s.wobbleScale);
390
+ ae(l, n, e.geometry.orbitRadius, e.geometry.eccentricity, t);
391
+ let r = q(l, t + 3e3, s.orbitSpeedScale, s.wobbleScale);
380
392
  l.endX = r.x, l.endY = r.y;
381
393
  let i = Math.hypot(r.x, r.y), a = i > .01 ? .08 / i : 0;
382
- l.startX = r.x * a, l.startY = r.y * a, U(l, "emerging", t, m);
394
+ l.startX = r.x * a, l.startY = r.y * a, K(l, "emerging", t, m);
383
395
  }
384
396
  break;
385
397
  case "emerging":
386
398
  if (_ >= 1) {
387
399
  let e = a[c];
388
- e.x = l.endX, e.y = l.endY, e.start = t, l.timeOrigin = t, l.phaseOffset = Math.atan2(l.endY, l.endX), U(l, "orbiting", t, B(n, h[0], h[1]));
400
+ e.x = l.endX, e.y = l.endY, e.start = t, l.timeOrigin = t, l.phaseOffset = Math.atan2(l.endY, l.endX), K(l, "orbiting", t, U(n, h[0], h[1]));
389
401
  }
390
402
  break;
391
403
  }
392
404
  let v, y, b, x;
393
405
  switch (l.phase) {
394
406
  case "orbiting": {
395
- let e = W(l, t, s.orbitSpeedScale, s.wobbleScale), n = a[c], r = t - n.start;
396
- if (n.start > 0 && r < K) {
397
- let t = V(r / K), i = t * t * (3 - 2 * t);
398
- v = H(n.x, e.x, i), y = H(n.y, e.y, i);
407
+ let e = q(l, t, s.orbitSpeedScale, s.wobbleScale), n = a[c], r = t - n.start;
408
+ if (n.start > 0 && r < 2e3) {
409
+ let t = W(r / z), i = t * t * (3 - 2 * t);
410
+ v = G(n.x, e.x, i), y = G(n.y, e.y, i);
399
411
  } else v = e.x, y = e.y;
400
- b = G, x = 1;
412
+ b = R, x = 1;
401
413
  break;
402
414
  }
403
415
  case "merging": {
404
- let e = k(V((t - l.phaseStart) / l.phaseDuration));
405
- v = H(l.startX, l.endX, e), y = H(l.startY, l.endY, e);
406
- let n = V((t - l.phaseStart) / l.phaseDuration);
407
- b = n > .85 ? H(G, 0, (n - .85) / .15) : G, x = H(1, .65, e);
416
+ let e = te(W((t - l.phaseStart) / l.phaseDuration));
417
+ v = G(l.startX, l.endX, e), y = G(l.startY, l.endY, e);
418
+ let n = W((t - l.phaseStart) / l.phaseDuration);
419
+ b = n > .85 ? G(R, 0, (n - .85) / .15) : R, x = G(1, .65, e);
408
420
  break;
409
421
  }
410
422
  case "absorbed":
411
423
  v = 0, y = 0, b = 0, x = .5;
412
424
  break;
413
425
  case "emerging": {
414
- let e = A(V((t - l.phaseStart) / l.phaseDuration));
415
- v = H(l.startX, l.endX, e), y = H(l.startY, l.endY, e);
416
- let n = V((t - l.phaseStart) / l.phaseDuration);
417
- b = n < .1 ? H(0, G, n / .1) : G, x = H(.65, 1, e);
426
+ let e = ne(W((t - l.phaseStart) / l.phaseDuration));
427
+ v = G(l.startX, l.endX, e), y = G(l.startY, l.endY, e);
428
+ let n = W((t - l.phaseStart) / l.phaseDuration);
429
+ b = n < .1 ? G(0, R, n / .1) : R, x = G(.65, 1, e);
418
430
  break;
419
431
  }
420
432
  }
@@ -422,11 +434,11 @@ function q(e, t) {
422
434
  S.x = v, S.y = y, S.radius = f * x, S.opacity = b;
423
435
  }
424
436
  }
425
- function p() {
437
+ function d() {
426
438
  for (let e of r) e.phaseOffset += (n() - .5) * .6, e.pertXPhase += n() * Math.PI, e.pertYPhase += n() * Math.PI;
427
439
  }
428
440
  function m(e) {
429
- n = u(d(e + "goo"));
441
+ n = f(p(e + "goo"));
430
442
  }
431
443
  function h() {
432
444
  for (let e of r) if (e.phase !== "orbiting") return !1;
@@ -442,8 +454,8 @@ function q(e, t) {
442
454
  }
443
455
  return {
444
456
  sources: i,
445
- tick: f,
446
- nudge: p,
457
+ tick: u,
458
+ nudge: d,
447
459
  reseed: m,
448
460
  isQuiescent: h,
449
461
  nextEventMs: g
@@ -451,7 +463,7 @@ function q(e, t) {
451
463
  }
452
464
  //#endregion
453
465
  //#region src/components/custom/goo-blob/shaders/metaball.vert.ts
454
- var ne = "#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}", re = "// --- 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}", ie = "// --- 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).", J = 1.8, Y = .42, ae = `float fbm(vec2 p, int octaves) {
466
+ var oe = "#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).", Y = 1.8, X = .42, le = `float fbm(vec2 p, int octaves) {
455
467
  float value = 0.0;
456
468
  float amp = 0.5;
457
469
  float freq = 1.0;
@@ -459,8 +471,8 @@ var ne = "#version 300 es\n\nin vec2 aPosition;\nout vec2 vUv;\n\nvoid main() {\
459
471
  if (i >= octaves) break;
460
472
  value += amp * noised(p * freq).x;
461
473
  p = FBM_ROT * p;
462
- freq *= ${J.toFixed(1)};
463
- amp *= ${Y.toFixed(2)};
474
+ freq *= ${Y.toFixed(1)};
475
+ amp *= ${X.toFixed(2)};
464
476
  }
465
477
  return value;
466
478
  }
@@ -487,8 +499,8 @@ vec3 fbmG(vec2 p, int octaves) {
487
499
  // d(value)/dp = amp · freq · (R^i)^T · noised.yz (the rotated chain rule).
488
500
  grad += amp * freq * (transpose(rotAccum) * n.yz);
489
501
  pp = FBM_ROT * pp;
490
- freq *= ${J.toFixed(1)};
491
- amp *= ${Y.toFixed(2)};
502
+ freq *= ${Y.toFixed(1)};
503
+ amp *= ${X.toFixed(2)};
492
504
  rotAccum = FBM_ROT * rotAccum;
493
505
  }
494
506
  return vec3(value, grad);
@@ -503,9 +515,9 @@ vec3 fbmWarpedG(vec2 p, int octaves, float warpAmp) {
503
515
  vec2 q = vec2(fbm(p + vec2(0.0, 0.0), octaves), fbm(p + vec2(5.2, 1.3), octaves));
504
516
  return fbmG(p + warpAmp * (q - 0.5), octaves);
505
517
  }
506
- `, oe = "// 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}", X = "\n", se = "#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// 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 ColorResolver)\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// 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// 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\n" + ie + X + `${s}
518
+ `, ue = "// 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}", de = "#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// 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// 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// 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", Z = "\n", fe = de + Z + ce + Z + `${a}
507
519
 
508
- ` + ae + X + re + X + `
520
+ ` + le + Z + se + Z + `
509
521
  // --- Color (Ottosson OKLab/OKLCh — value.js EXACT constants, transposed) ---
510
522
  //
511
523
  // The OETF (srgbToLinear/linearToSrgb) + the four Ottosson matrices + their space
@@ -514,40 +526,129 @@ vec3 fbmWarpedG(vec2 p, int octaves, float warpAmp) {
514
526
  // ONCE so the OETF can never diverge from aurora's; the line-for-line TS port
515
527
  // (__tests__/metaball-color.glsl-port.ts) mirrors that chunk. The gamut-clamp
516
528
  // below stays blob-local (aurora has no in-shader OKLCh path).
529
+ ${s}
517
530
  ${r}
518
- ${n}
519
531
 
520
- ` + oe + X + "\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// 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\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 // 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\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 // 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 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 // injected ColorResolver). 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 // 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}", ce = 4, le = 15, Z = 4, Q = "[GooBlob]", $ = 1 / 1.6, ue = /* @__PURE__ */ "uResolution.uTime.uBaseColor.uPointer.uPointerActive.uPointerAttraction.uPointerStrength.uBodyRadius.uPulsePhase.uPulseAmp.uNoiseAmp.uNoiseFreq.uNoiseSpeed.uWarpAmp.uSmoothK.uMerge.uMaxReach.uLit.uRimColor.uLightDir.uSpecStrength.uSpecShininess.uRimPower.uRimStrength.uIridescence.uIridHue.uIridSpeed.uSssScale.uSssPower.uCoreGlow.uHueRange.uSatShift.uBrightnessShift.uColorNoiseFreq.uColorNoiseSpeed.uStopCount.uSatCount.uTrailCount.uVelocity.uStretch".split(".");
521
- function de(e) {
522
- let { canvasRef: t, color: n, rimColor: r, paletteStops: s, mood: u, pointer: d, satellites: f, config: p, colorResolver: m } = e;
523
- if (typeof m != "function") throw Error("[GooBlob] a `colorResolver` is required. Pass `defaultBlobColorResolver` from `@mkbabb/glass-ui/color` (or your own `ColorResolver`) — the blob resolves its base CSS color through this seam and will not paint without it.");
524
- let h = 0, g = 0, _ = /* @__PURE__ */ new Map();
525
- function v(e) {
526
- let t = _.get(e);
532
+ ` + ue + Z + "\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// 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\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\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 // 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 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 // 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}";
533
+ //#endregion
534
+ //#region src/components/custom/goo-blob/composables/uploadBlobUniforms.ts
535
+ function pe(e, t, n, r, i, a, o, s, c) {
536
+ let { U: l, satPosLocs: u, satRadLocs: d, satOpLocs: f, trailPosLocs: p, trailRadLocs: m, paletteLocs: h } = r, { params: g, rgb: _, simTimeMs: v, timeSec: y, resolveColor: b, rimColor: x, paletteStops: S } = c, { geometry: C, membrane: w, color: T, surface: E, interaction: D } = a;
537
+ e.useProgram(t), e.bindVertexArray(n), e.uniform2f(l.uResolution, i.width, i.height), e.uniform1f(l.uTime, v / 1e3), e.uniform3f(l.uBaseColor, _[0], _[1], _[2]);
538
+ let O = S, k = Math.min(O.length, 4);
539
+ e.uniform1i(l.uStopCount, k);
540
+ for (let t = 0; t < 4; t++) {
541
+ let n = h[t] ?? null, r = O[t];
542
+ if (r) {
543
+ let t = b(r);
544
+ e.uniform3f(n, t[0], t[1], t[2]);
545
+ } else e.uniform3f(n, _[0], _[1], _[2]);
546
+ }
547
+ let j = o.pointer.value, M = D.pointerAttraction + g.pointerAttraction;
548
+ e.uniform2f(l.uPointer, j.x * .5 * A, j.y * .5 * A), e.uniform1f(l.uPointerActive, +!!o.active.value), e.uniform1f(l.uPointerAttraction, M), e.uniform1f(l.uPointerStrength, D.pointerStrength * A);
549
+ let N = Math.max(0, Math.min(1, M)), P = o.velocity.value;
550
+ e.uniform2f(l.uVelocity, P.x * .5 * A, P.y * .5 * A), e.uniform1f(l.uStretch, D.stretch);
551
+ let F = o.trailSources(C.satelliteRadius * .7 * N);
552
+ e.uniform1i(l.uTrailCount, F.count);
553
+ for (let t = 0; t < 15; t++) {
554
+ let n = p[t] ?? null, r = m[t] ?? null, i = F.sources[t];
555
+ i ? (e.uniform2f(n, i.x * .5 * A, i.y * .5 * A), e.uniform1f(r, i.radius * A)) : (e.uniform2f(n, 0, 0), e.uniform1f(r, 0));
556
+ }
557
+ e.uniform1f(l.uBodyRadius, C.bodyRadius * A), e.uniform1f(l.uPulsePhase, y * w.pulseFreq * g.pulseFreq * Math.PI * 2);
558
+ let I = o.pulse.value * D.clickImpulse;
559
+ e.uniform1f(l.uPulseAmp, (w.pulseAmp * g.pulseAmp / .015 + I) * A), e.uniform1f(l.uNoiseAmp, w.noiseAmp * g.noiseAmp / .025 * A), e.uniform1f(l.uNoiseFreq, w.noiseFreq), e.uniform1f(l.uNoiseSpeed, w.noiseSpeed), e.uniform1f(l.uWarpAmp, w.warpAmp), e.uniform1f(l.uSmoothK, w.smoothK * g.smoothK * A), e.uniform1f(l.uMerge, +(w.merge === "circular"));
560
+ let L = C.orbitRadius * 1.2 * (1 + C.eccentricity) + C.satelliteRadius, R = (Math.max(C.bodyRadius, L) + w.smoothK * g.smoothK + w.noiseAmp * g.noiseAmp / .025 + Math.abs(o.pulse.value) * D.clickImpulse) * A + .1;
561
+ e.uniform1f(l.uMaxReach, R), e.uniform1f(l.uHueRange, T.hueRange + g.hueRange), e.uniform1f(l.uSatShift, T.satShift + g.satShift), e.uniform1f(l.uBrightnessShift, T.brightnessShift + g.brightnessShift), e.uniform1f(l.uColorNoiseFreq, T.colorNoiseFreq), e.uniform1f(l.uColorNoiseSpeed, T.colorNoiseSpeed), e.uniform1f(l.uLit, +!!E.lit);
562
+ let z = b(x);
563
+ e.uniform3f(l.uRimColor, z[0], z[1], z[2]), e.uniform3f(l.uLightDir, E.lightDir[0], E.lightDir[1], E.lightDir[2]), e.uniform1f(l.uSpecStrength, E.specStrength), e.uniform1f(l.uSpecShininess, E.specShininess), e.uniform1f(l.uRimPower, E.rimPower), e.uniform1f(l.uRimStrength, E.rimStrength), e.uniform1f(l.uIridescence, E.iridescence * g.iridScale), e.uniform1f(l.uIridHue, E.iridHue * (Math.PI / 180)), e.uniform1f(l.uIridSpeed, E.iridSpeed), e.uniform1f(l.uSssScale, E.sssScale * g.iridScale), e.uniform1f(l.uSssPower, E.sssPower), e.uniform1f(l.uCoreGlow, E.coreGlow);
564
+ let B = s.sources;
565
+ e.uniform1i(l.uSatCount, B.length);
566
+ for (let t = 0; t < 4; t++) {
567
+ let n = u[t] ?? null, r = d[t] ?? null, i = f[t] ?? null, a = B[t];
568
+ a ? (e.uniform2f(n, a.x * A, a.y * A), e.uniform1f(r, a.radius * A), e.uniform1f(i, a.opacity)) : (e.uniform2f(n, 0, 0), e.uniform1f(r, 0), e.uniform1f(i, 0));
569
+ }
570
+ e.clearColor(0, 0, 0, 0), e.clear(e.COLOR_BUFFER_BIT), e.drawArrays(e.TRIANGLES, 0, 6), e.bindVertexArray(null);
571
+ }
572
+ //#endregion
573
+ //#region src/components/custom/goo-blob/composables/buildMetaballProgram.ts
574
+ var Q = "[GooBlob]";
575
+ function me(e) {
576
+ let t = c(e, e.VERTEX_SHADER, oe, Q), n = c(e, e.FRAGMENT_SHADER, fe, Q), r = i(e, t, n, Q);
577
+ e.useProgram(r);
578
+ let a = e.createVertexArray();
579
+ e.bindVertexArray(a);
580
+ let o = e.createBuffer();
581
+ e.bindBuffer(e.ARRAY_BUFFER, o), e.bufferData(e.ARRAY_BUFFER, new Float32Array([
582
+ -1,
583
+ -1,
584
+ 1,
585
+ -1,
586
+ -1,
587
+ 1,
588
+ -1,
589
+ 1,
590
+ 1,
591
+ -1,
592
+ 1,
593
+ 1
594
+ ]), e.STATIC_DRAW);
595
+ let s = e.getAttribLocation(r, "aPosition");
596
+ e.enableVertexAttribArray(s), e.vertexAttribPointer(s, 2, e.FLOAT, !1, 0, 0);
597
+ let l = {};
598
+ for (let t of B) l[t] = e.getUniformLocation(r, t);
599
+ let u = [], d = [], f = [];
600
+ for (let t = 0; t < 4; t++) u.push(e.getUniformLocation(r, `uSatPos[${t}]`)), d.push(e.getUniformLocation(r, `uSatRadius[${t}]`)), f.push(e.getUniformLocation(r, `uSatOpacity[${t}]`));
601
+ let p = [], m = [];
602
+ for (let t = 0; t < 15; t++) p.push(e.getUniformLocation(r, `uTrailPos[${t}]`)), m.push(e.getUniformLocation(r, `uTrailRadius[${t}]`));
603
+ let h = [];
604
+ for (let t = 0; t < 4; t++) h.push(e.getUniformLocation(r, `uPalette[${t}]`));
605
+ return e.enable(e.BLEND), e.blendFunc(e.ONE, e.ONE_MINUS_SRC_ALPHA), {
606
+ prog: r,
607
+ vs: t,
608
+ fs: n,
609
+ vao: a,
610
+ buf: o,
611
+ locs: {
612
+ U: l,
613
+ satPosLocs: u,
614
+ satRadLocs: d,
615
+ satOpLocs: f,
616
+ trailPosLocs: p,
617
+ trailRadLocs: m,
618
+ paletteLocs: h
619
+ }
620
+ };
621
+ }
622
+ //#endregion
623
+ //#region src/components/custom/goo-blob/composables/useMetaballRenderer.ts
624
+ function $(e) {
625
+ let { canvasRef: t, color: r, rimColor: i, paletteStops: a, mood: s, pointer: c, satellites: f, config: p } = e, m = 0, h = 0, g = /* @__PURE__ */ new Map();
626
+ function _(e) {
627
+ let t = g.get(e);
527
628
  if (t) return t;
528
- let n = m(e);
529
- return _.size > 256 && _.clear(), _.set(e, n), n;
629
+ let n = l(u(e));
630
+ return g.size > 256 && g.clear(), g.set(e, n), n;
530
631
  }
531
- let b = null, x = !1, S = null;
532
- function C() {
533
- S !== null && (clearTimeout(S), S = null);
632
+ let v = null, y = !1, b = null;
633
+ function S() {
634
+ b !== null && (clearTimeout(b), b = null);
534
635
  }
535
- function T(e) {
536
- if (C(), typeof setTimeout > "u") return;
537
- let t = Math.min(Math.max(e - g, 16), 3e4);
538
- S = setTimeout(() => {
539
- S = null, b?.wake();
636
+ function C(e) {
637
+ if (S(), typeof setTimeout > "u") return;
638
+ let t = Math.min(Math.max(e - h, 16), 3e4);
639
+ b = setTimeout(() => {
640
+ b = null, v?.wake();
540
641
  }, t);
541
642
  }
542
- l(t, {
543
- pause: () => b?.suspend("off-screen-io"),
544
- resume: () => b?.resume("off-screen-io")
643
+ d(t, {
644
+ pause: () => v?.suspend("off-screen-io"),
645
+ resume: () => v?.resume("off-screen-io")
545
646
  }, {
546
647
  rootMargin: "200px",
547
648
  pauseWhenHidden: !1
548
649
  });
549
- function E(e) {
550
- b = o(e, {
650
+ function w(e) {
651
+ v = o(e, {
551
652
  contextAttrs: {
552
653
  alpha: !0,
553
654
  premultipliedAlpha: !0,
@@ -555,122 +656,65 @@ function de(e) {
555
656
  preserveDrawingBuffer: !1
556
657
  },
557
658
  setup: (t) => {
558
- let o = c(t, t.VERTEX_SHADER, ne, Q), l = c(t, t.FRAGMENT_SHADER, se, Q), m = i(t, o, l, Q);
559
- t.useProgram(m);
560
- let _ = t.createVertexArray();
561
- t.bindVertexArray(_);
562
- let y = t.createBuffer();
563
- t.bindBuffer(t.ARRAY_BUFFER, y), t.bufferData(t.ARRAY_BUFFER, new Float32Array([
564
- -1,
565
- -1,
566
- 1,
567
- -1,
568
- -1,
569
- 1,
570
- -1,
571
- 1,
572
- 1,
573
- -1,
574
- 1,
575
- 1
576
- ]), t.STATIC_DRAW);
577
- let S = t.getAttribLocation(m, "aPosition");
578
- t.enableVertexAttribArray(S), t.vertexAttribPointer(S, 2, t.FLOAT, !1, 0, 0);
579
- let w = {};
580
- for (let e of ue) w[e] = t.getUniformLocation(m, e);
581
- let E = [], D = [], O = [];
582
- for (let e = 0; e < ce; e++) E.push(t.getUniformLocation(m, `uSatPos[${e}]`)), D.push(t.getUniformLocation(m, `uSatRadius[${e}]`)), O.push(t.getUniformLocation(m, `uSatOpacity[${e}]`));
583
- let k = [], A = [];
584
- for (let e = 0; e < le; e++) k.push(t.getUniformLocation(m, `uTrailPos[${e}]`)), A.push(t.getUniformLocation(m, `uTrailRadius[${e}]`));
585
- let j = [];
586
- for (let e = 0; e < Z; e++) j.push(t.getUniformLocation(m, `uPalette[${e}]`));
587
- t.enable(t.BLEND), t.blendFunc(t.ONE, t.ONE_MINUS_SRC_ALPHA);
588
- function M() {
589
- let n = a(), r = p.quality === "half" ? .5 : 1, i = e.clientWidth || p.canvasSize, o = e.clientHeight || p.canvasSize, s = Math.max(1, Math.round(i * n * r)), c = Math.max(1, Math.round(o * n * r));
659
+ let { prog: o, vs: l, fs: u, vao: d, buf: g, locs: b } = me(t);
660
+ function x() {
661
+ let r = n(), i = p.quality === "half" ? .5 : 1, a = e.clientWidth || p.geometry.canvasSize, o = e.clientHeight || p.geometry.canvasSize, s = Math.max(1, Math.round(a * r * i)), c = Math.max(1, Math.round(o * r * i));
590
662
  (e.width !== s || e.height !== c) && (e.width = s, e.height = c), t.viewport(0, 0, s, c);
591
663
  }
592
- function N(i) {
593
- let a = h ? (i - h) * 1e3 : 16;
594
- h = i;
595
- let o = Math.min(a, 50), c = b?.reducedMotion ?? !1, l = (c || x ? 0 : p.tempo) * o;
596
- g += l, c || u.update({
597
- pointerActive: d.active.value,
598
- clicked: d.consumeClick(),
599
- idleMs: d.idleMs()
600
- }), u.tick(l), c ? d.rest() : d.tick(l), f.tick(g, u.params.value);
601
- let y = u.params.value, S = v(n.value);
602
- t.useProgram(m), t.bindVertexArray(_), t.uniform2f(w.uResolution, e.width, e.height), t.uniform1f(w.uTime, g / 1e3), t.uniform3f(w.uBaseColor, S[0], S[1], S[2]);
603
- let C = s.value, T = Math.min(C.length, Z);
604
- t.uniform1i(w.uStopCount, T);
605
- for (let e = 0; e < Z; e++) {
606
- let n = j[e] ?? null, r = C[e];
607
- if (r) {
608
- let e = v(r);
609
- t.uniform3f(n, e[0], e[1], e[2]);
610
- } else t.uniform3f(n, S[0], S[1], S[2]);
611
- }
612
- let M = d.pointer.value;
613
- t.uniform2f(w.uPointer, M.x * .5 * $, M.y * .5 * $), t.uniform1f(w.uPointerActive, +!!d.active.value), t.uniform1f(w.uPointerAttraction, p.pointerAttraction + y.pointerAttraction), t.uniform1f(w.uPointerStrength, p.pointerStrength * $);
614
- let N = d.velocity.value;
615
- t.uniform2f(w.uVelocity, N.x * .5 * $, N.y * .5 * $), t.uniform1f(w.uStretch, p.stretch);
616
- let P = d.trailSources(p.satelliteRadius * .7);
617
- t.uniform1i(w.uTrailCount, P.count);
618
- for (let e = 0; e < le; e++) {
619
- let n = k[e] ?? null, r = A[e] ?? null, i = P.sources[e];
620
- i ? (t.uniform2f(n, i.x * .5 * $, i.y * .5 * $), t.uniform1f(r, i.radius * $)) : (t.uniform2f(n, 0, 0), t.uniform1f(r, 0));
621
- }
622
- t.uniform1f(w.uBodyRadius, p.bodyRadius * $), t.uniform1f(w.uPulsePhase, i * p.pulseFreq * y.pulseFreq * Math.PI * 2);
623
- let F = d.pulse.value * p.clickImpulse;
624
- t.uniform1f(w.uPulseAmp, (p.pulseAmp * y.pulseAmp / .015 + F) * $), t.uniform1f(w.uNoiseAmp, p.noiseAmp * y.noiseAmp / .025 * $), t.uniform1f(w.uNoiseFreq, p.noiseFreq), t.uniform1f(w.uNoiseSpeed, p.noiseSpeed), t.uniform1f(w.uWarpAmp, p.warpAmp), t.uniform1f(w.uSmoothK, p.smoothK * y.smoothK * $), t.uniform1f(w.uMerge, +(p.merge === "circular"));
625
- let I = p.orbitRadius * 1.2 * (1 + p.eccentricity) + p.satelliteRadius, L = (Math.max(p.bodyRadius, I) + p.smoothK * y.smoothK + p.noiseAmp * y.noiseAmp / .025 + Math.abs(d.pulse.value) * p.clickImpulse) * $ + .1;
626
- t.uniform1f(w.uMaxReach, L), t.uniform1f(w.uHueRange, p.hueRange + y.hueRange), t.uniform1f(w.uSatShift, p.satShift + y.satShift), t.uniform1f(w.uBrightnessShift, p.brightnessShift + y.brightnessShift), t.uniform1f(w.uColorNoiseFreq, p.colorNoiseFreq), t.uniform1f(w.uColorNoiseSpeed, p.colorNoiseSpeed), t.uniform1f(w.uLit, +!!p.lit);
627
- let R = v(r.value);
628
- t.uniform3f(w.uRimColor, R[0], R[1], R[2]), t.uniform3f(w.uLightDir, p.lightDir[0], p.lightDir[1], p.lightDir[2]), t.uniform1f(w.uSpecStrength, p.specStrength), t.uniform1f(w.uSpecShininess, p.specShininess), t.uniform1f(w.uRimPower, p.rimPower), t.uniform1f(w.uRimStrength, p.rimStrength), t.uniform1f(w.uIridescence, p.iridescence * y.iridScale), t.uniform1f(w.uIridHue, p.iridHue * (Math.PI / 180)), t.uniform1f(w.uIridSpeed, p.iridSpeed), t.uniform1f(w.uSssScale, p.sssScale * y.iridScale), t.uniform1f(w.uSssPower, p.sssPower), t.uniform1f(w.uCoreGlow, p.coreGlow);
629
- let z = f.sources;
630
- t.uniform1i(w.uSatCount, z.length);
631
- for (let e = 0; e < ce; e++) {
632
- let n = E[e] ?? null, r = D[e] ?? null, i = O[e] ?? null, a = z[e];
633
- a ? (t.uniform2f(n, a.x * $, a.y * $), t.uniform1f(r, a.radius * $), t.uniform1f(i, a.opacity)) : (t.uniform2f(n, 0, 0), t.uniform1f(r, 0), t.uniform1f(i, 0));
634
- }
635
- t.clearColor(0, 0, 0, 0), t.clear(t.COLOR_BUFFER_BIT), t.drawArrays(t.TRIANGLES, 0, 6), t.bindVertexArray(null);
664
+ function w(n) {
665
+ let l = m ? (n - m) * 1e3 : 16;
666
+ m = n;
667
+ let u = Math.max(0, Math.min(l, 50)), g = v?.reducedMotion ?? !1, x = (g || y ? 0 : p.tempo) * u;
668
+ h += x, g || s.update({
669
+ pointerActive: c.active.value,
670
+ clicked: c.consumeClick(),
671
+ idleMs: c.idleMs()
672
+ }), s.tick(x), g ? c.rest() : c.tick(x), f.tick(h, s.params.value), pe(t, o, d, b, e, p, c, f, {
673
+ params: s.params.value,
674
+ rgb: _(r.value),
675
+ simTimeMs: h,
676
+ timeSec: n,
677
+ resolveColor: _,
678
+ rimColor: i.value,
679
+ paletteStops: a.value
680
+ });
636
681
  }
637
- function P() {
638
- if (x) return !1;
639
- if (!u.isSettled() || !d.isAtRest() || !f.isQuiescent()) return C(), !0;
640
- let e = f.nextEventMs(g), t = u.nextAutoMoodMs(), n = Number.isFinite(t) ? g + t : Infinity;
641
- return T(Math.min(e, n)), !1;
682
+ function T() {
683
+ if (y) return !1;
684
+ if (!s.isSettled() || !c.isAtRest() || !f.isQuiescent()) return S(), !0;
685
+ let e = f.nextEventMs(h), t = s.nextAutoMoodMs(), n = Number.isFinite(t) ? h + t : Infinity;
686
+ return C(Math.min(e, n)), !1;
642
687
  }
643
688
  return {
644
- frame: N,
645
- shouldContinue: P,
646
- resize: M,
689
+ frame: w,
690
+ shouldContinue: T,
691
+ resize: x,
647
692
  teardown: () => {
648
- t.deleteProgram(m), t.deleteShader(o), t.deleteShader(l), t.deleteBuffer(y), t.deleteVertexArray(_);
693
+ t.deleteProgram(o), t.deleteShader(l), t.deleteShader(u), t.deleteBuffer(g), t.deleteVertexArray(d);
649
694
  }
650
695
  };
651
696
  }
652
- }), b.arm();
697
+ }), v.arm();
653
698
  }
654
- return w(t, (e) => {
655
- e && !b && E(e);
656
- }, { immediate: !0 }), w(n, () => b?.wake()), y(() => {
657
- C(), b?.dispose(), b = null;
699
+ return E(t, (e) => {
700
+ e && !v && w(e);
701
+ }, { immediate: !0 }), E(r, () => v?.wake()), E(a, () => v?.wake(), { deep: !0 }), x(() => {
702
+ S(), v?.dispose(), v = null;
658
703
  }), {
659
704
  pause: () => {
660
- x = !0, b?.suspend("manual");
705
+ y = !0, v?.suspend("manual");
661
706
  },
662
707
  resume: () => {
663
- x = !1, b?.resume("manual");
708
+ y = !1, v?.resume("manual");
664
709
  }
665
710
  };
666
711
  }
667
712
  //#endregion
668
713
  //#region src/components/custom/goo-blob/GooBlob.vue
669
- var fe = /* @__PURE__ */ e(/* @__PURE__ */ h({
714
+ var he = /* @__PURE__ */ e(/* @__PURE__ */ _({
670
715
  __name: "GooBlob",
671
716
  props: {
672
717
  color: {},
673
- colorResolver: { type: Function },
674
718
  config: {},
675
719
  seed: { default: "" },
676
720
  paused: {
@@ -680,67 +724,69 @@ var fe = /* @__PURE__ */ e(/* @__PURE__ */ h({
680
724
  },
681
725
  emits: ["click", "update:paused"],
682
726
  setup(e, { expose: n, emit: r }) {
683
- let i = r, a = g(D, null), o = e.config ?? a;
727
+ let i = r, a = v(k, null), o = e.config ?? a;
684
728
  if (!o) throw Error("[glass-ui] GooBlob: 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.");
685
- let s = C("canvasRef"), c = C("wrapperRef"), l = R(), u = z(c), d = q(o, e.color + e.seed), h = t(), y = S(e.color), x = S(o.rimColor), T = S([...o.paletteStops]);
686
- function E() {
687
- let t = c.value;
688
- h.invalidate(), y.value = h.resolve(e.color, t), x.value = h.resolve(o.rimColor, t), T.value = o.paletteStops.map((e) => h.resolve(e, t));
729
+ let s = () => e.config ?? a ?? o, c = T("canvasRef"), l = T("wrapperRef"), u = V(), d = H(l), f = J(o, e.color + e.seed), p = t(), _ = w(e.color), x = w(o.surface.rimColor), C = w([...o.color.paletteStops]);
730
+ function D() {
731
+ let t = l.value, n = s();
732
+ p.invalidate(), _.value = p.resolve(e.color, t), x.value = p.resolve(n.surface.rimColor, t), C.value = n.color.paletteStops.map((e) => p.resolve(e, t));
689
733
  }
690
- let O = de({
691
- canvasRef: s,
692
- color: y,
734
+ let O = $({
735
+ canvasRef: c,
736
+ color: _,
693
737
  rimColor: x,
694
- paletteStops: T,
695
- mood: l,
696
- pointer: u,
697
- satellites: d,
698
- config: o,
699
- colorResolver: e.colorResolver
738
+ paletteStops: C,
739
+ mood: u,
740
+ pointer: d,
741
+ satellites: f,
742
+ config: o
700
743
  });
701
- w(c, E, { immediate: !0 });
702
- let k = null;
703
- typeof document < "u" && (k = new MutationObserver(E), k.observe(document.documentElement, {
744
+ E(l, D, { immediate: !0 });
745
+ let A = null;
746
+ typeof document < "u" && (A = new MutationObserver(D), A.observe(document.documentElement, {
704
747
  attributes: !0,
705
748
  attributeFilter: ["class"]
706
- })), w(f(() => e.color), (t) => {
707
- E(), d.reseed(t + e.seed);
708
- }), w(() => e.paused, (e) => e ? O.pause() : O.resume(), { immediate: !0 }), v(() => {
709
- k?.disconnect(), k = null;
749
+ })), E(m(() => e.color), (t) => {
750
+ D(), f.reseed(t + e.seed);
751
+ }), E(() => {
752
+ let e = s();
753
+ return [e.color.paletteStops.join("|"), e.surface.rimColor];
754
+ }, () => D(), { deep: !0 }), E(() => e.paused, (e) => e ? O.pause() : O.resume(), { immediate: !0 }), b(() => {
755
+ A?.disconnect(), A = null;
710
756
  });
711
- function A() {
712
- d.nudge();
713
- }
714
- function j(e) {
715
- l.setMood(e, { source: "manual" });
757
+ function j() {
758
+ f.nudge();
716
759
  }
717
- function M() {
718
- u.click(o.clickImpulse);
760
+ function M(e) {
761
+ u.setMood(e, { source: "manual" });
719
762
  }
720
763
  function N() {
721
- M(), i("click");
764
+ d.click(o.interaction.clickImpulse);
765
+ }
766
+ function P() {
767
+ N(), i("click");
722
768
  }
723
769
  return n({
724
- nudge: A,
725
- setMood: j,
726
- pulse: M,
727
- currentMood: l.currentMood,
770
+ nudge: j,
771
+ setMood: M,
772
+ pulse: N,
773
+ currentMood: u.currentMood,
728
774
  pause: O.pause,
729
775
  resume: O.resume
730
- }), (t, n) => (b(), p("div", {
776
+ }), (t, n) => (S(), h("div", {
731
777
  ref_key: "wrapperRef",
732
- ref: c,
778
+ ref: l,
733
779
  class: "goo-blob-wrapper",
734
- style: _({ "--blob-color": e.color }),
735
- onClick: N
736
- }, [m("canvas", {
780
+ style: y({ "--blob-color": e.color }),
781
+ onClick: P
782
+ }, [g("canvas", {
737
783
  ref_key: "canvasRef",
738
- ref: s,
784
+ ref: c,
739
785
  class: "goo-blob-canvas",
740
786
  "aria-hidden": "true",
741
787
  "data-testid": "goo-blob-canvas"
742
788
  }, null, 512)], 4));
743
789
  }
744
- }), [["__scopeId", "data-v-ec790b7b"]]);
790
+ }), [["__scopeId", "data-v-bd6cd550"]]);
745
791
  //#endregion
746
- export { E as BLOB_CONFIG_DEFAULTS, D as BLOB_CONFIG_KEY, fe as GooBlob, R as useBlobMood, z as useBlobPointer, q as useBlobSatellites, de as useMetaballRenderer };
792
+ export { O as BLOB_CONFIG_DEFAULTS, k as BLOB_CONFIG_KEY, he as GooBlob, V as useBlobMood, H as useBlobPointer, J as useBlobSatellites, $ as useMetaballRenderer };