@mkbabb/glass-ui 3.7.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/dist/CardAction-q2qHCJFG.js +157 -0
  2. package/dist/{CommandShortcut-CY0aQTz5.js → CommandShortcut-SzWRhROC.js} +2 -2
  3. package/dist/{ContextMenuSubContent-BeDz7G6f.js → ContextMenuSubContent-Do977Cbf.js} +1 -1
  4. package/dist/{DataTable-gtPOLZvl.js → DataTable-CvlWXz65.js} +3 -3
  5. package/dist/DeckProgress-AVgbIULY.js +23 -0
  6. package/dist/{DialogContent-DG1YMR-P.js → DialogContent-DjZWT3lK.js} +2 -2
  7. package/dist/{DialogFooter-BCIaDP15.js → DialogFooter-Gprw8H_A.js} +1 -1
  8. package/dist/{DiscoGlyph-ZoBYpoxI.js → DiscoGlyph-CG0F410s.js} +1 -1
  9. package/dist/{GlyphFace-Ce_oe3tM.js → GlyphFace-DRjDkB0s.js} +1 -1
  10. package/dist/{HoverPopover-DXpOEw1P.js → HoverPopover-D56O6Ylp.js} +1 -1
  11. package/dist/{IconTooltip-Cu86JR4e.js → IconTooltip-D2T5nYOM.js} +1 -1
  12. package/dist/{MetricBadge-D-bRaQUD.js → MetricBadge-lTc002u2.js} +1 -1
  13. package/dist/{Notification-B5WHP3_1.js → Notification-BxK8LZMw.js} +1 -1
  14. package/dist/{PopoverContent-F1bWnYoh.js → PopoverContent-BId6ggf_.js} +1 -1
  15. package/dist/{Progress-c4vo4ALi.js → Progress-iEuD9pxG.js} +4 -4
  16. package/dist/{ScrollingText-BEp377U5.js → ScrollingText-CVyqxvfv.js} +2 -2
  17. package/dist/{SelectScrollDownButton-DAo5NmY_.js → SelectScrollDownButton-C7TRe-ep.js} +2 -2
  18. package/dist/{ToggleGroupItem-C-AIkBUw.js → ToggleGroupItem-CkXUcBlt.js} +1 -1
  19. package/dist/{UnderlineTabs-D_c1iYo-.js → UnderlineTabs-Uxn-R3MT.js} +2 -2
  20. package/dist/animated-digit.js +2 -2
  21. package/dist/api/index.d.ts +4 -2
  22. package/dist/api.js +1 -1
  23. package/dist/aurora.js +336 -405
  24. package/dist/canvas.d.ts +1 -0
  25. package/dist/canvas.js +3 -0
  26. package/dist/card.js +1 -1
  27. package/dist/carousel.js +105 -104
  28. package/dist/collapsible.js +1 -1
  29. package/dist/{color-DjJCAQ6f.js → color-DMLTunJK.js} +22 -14
  30. package/dist/color.js +2 -2
  31. package/dist/command.js +1 -1
  32. package/dist/compile-BBTRjvQS.js +158 -0
  33. package/dist/components/custom/aurora/composables/atoms.d.ts +90 -25
  34. package/dist/components/custom/aurora/composables/color.d.ts +0 -12
  35. package/dist/components/custom/aurora/composables/uniformBridge.d.ts +34 -23
  36. package/dist/components/custom/aurora/constants/presets.d.ts +10 -7
  37. package/dist/components/custom/aurora/constants/renderMode.d.ts +22 -0
  38. package/dist/components/custom/aurora/constants/shaders/aurora.wgsl.d.ts +1 -1
  39. package/dist/components/custom/aurora/constants/shaders/brush.glsl.d.ts +1 -1
  40. package/dist/components/custom/aurora/constants/shaders/composition.glsl.d.ts +1 -1
  41. package/dist/components/custom/aurora/constants/shaders/mediums.glsl.d.ts +1 -1
  42. package/dist/components/custom/aurora/index.d.ts +3 -3
  43. package/dist/components/custom/constellation/Constellation.vue.d.ts +40 -5
  44. package/dist/components/custom/constellation/constellationField.d.ts +110 -5
  45. package/dist/components/custom/constellation/index.d.ts +2 -2
  46. package/dist/components/custom/dock/GlassDock.vue.d.ts +12 -4
  47. package/dist/components/custom/dock/composables/dockMorphContext.d.ts +57 -0
  48. package/dist/components/custom/dock/composables/index.d.ts +3 -0
  49. package/dist/components/custom/dock/composables/useDockHold.d.ts +61 -0
  50. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +13 -59
  51. package/dist/components/custom/dock/index.d.ts +2 -0
  52. package/dist/components/custom/goo-blob/GooBlob.vue.d.ts +13 -0
  53. package/dist/components/custom/goo-blob/composables/useBlobMood.d.ts +4 -0
  54. package/dist/components/custom/goo-blob/composables/useBlobPointer.d.ts +2 -0
  55. package/dist/components/custom/goo-blob/composables/useBlobSatellites.d.ts +2 -0
  56. package/dist/components/custom/goo-blob/composables/useMetaballRenderer.d.ts +20 -5
  57. package/dist/components/custom/goo-blob/index.d.ts +1 -1
  58. package/dist/components/custom/goo-blob/shaders/sdf-body.glsl.d.ts +1 -1
  59. package/dist/components/custom/goo-blob/shaders/watercolor-edges.glsl.d.ts +2 -2
  60. package/dist/components/custom/goo-blob/types.d.ts +8 -0
  61. package/dist/components/ui/card/Card.vue.d.ts +23 -7
  62. package/dist/components/ui/card/index.d.ts +1 -1
  63. package/dist/components/ui/progress/ProgressDefault.vue.d.ts +14 -4
  64. package/dist/components/ui/slider/Slider.vue.d.ts +3 -1
  65. package/dist/composables/color/index.d.ts +19 -0
  66. package/dist/composables/dom/index.d.ts +1 -1
  67. package/dist/composables/dom/useResolveTokenColor.d.ts +27 -0
  68. package/dist/composables/glass/canvas2d/index.d.ts +2 -1
  69. package/dist/composables/glass/canvas2d/resolveCanvasColor.d.ts +20 -0
  70. package/dist/composables/glass/canvas2d/useCanvas2D.d.ts +15 -1
  71. package/dist/composables/glass/index.d.ts +3 -1
  72. package/dist/composables/glass/useSpecularTracking.d.ts +33 -0
  73. package/dist/composables/glass/webgl/createCanvasLifecycle.d.ts +1 -1
  74. package/dist/composables/glass/webgl/shaders/procedural-color.glsl.d.ts +4 -0
  75. package/dist/composables/glass/webgl/useWebGLCanvas.d.ts +1 -1
  76. package/dist/composables/motion/core/index.d.ts +1 -0
  77. package/dist/configurator.js +1 -1
  78. package/dist/confirm-dialog.js +1 -1
  79. package/dist/constellation.js +144 -75
  80. package/dist/context-menu.js +2 -2
  81. package/dist/controls.js +2 -2
  82. package/dist/dark.js +1 -1
  83. package/dist/data-table.js +1 -1
  84. package/dist/deck-progress.d.ts +1 -0
  85. package/dist/deck-progress.js +2 -0
  86. package/dist/dialog.js +2 -2
  87. package/dist/disco-glyph.js +1 -1
  88. package/dist/dock.js +386 -285
  89. package/dist/{dockContext-DLgrVWsU.js → dockContext-BKeIMmNk.js} +1 -1
  90. package/dist/dom.js +6 -6
  91. package/dist/{dropdown-menu-BWpwutt0.js → dropdown-menu-B_4bWyyG.js} +2 -2
  92. package/dist/dropdown-menu.js +1 -1
  93. package/dist/expandable-container.js +1 -1
  94. package/dist/fonts/README.md +26 -18
  95. package/dist/forms.js +3 -3
  96. package/dist/fourier-field.js +37 -37
  97. package/dist/glass-carousel.js +12 -7
  98. package/dist/glass-panel.js +7 -7
  99. package/dist/glass-ui.css +1 -1
  100. package/dist/glass-ui.js +150 -162
  101. package/dist/glyph-face.js +2 -2
  102. package/dist/goo-blob.js +353 -270
  103. package/dist/header-ribbon.js +1 -1
  104. package/dist/hover-card.js +1 -1
  105. package/dist/hover-popover.js +1 -1
  106. package/dist/icon-tooltip.js +1 -1
  107. package/dist/index.d.ts +1 -0
  108. package/dist/instrument-chassis.js +1 -1
  109. package/dist/instrument-rail.js +1 -1
  110. package/dist/keyboard.js +1 -1
  111. package/dist/{keys-Dyf_uTs5.js → keys-BsYjEFOW.js} +1 -1
  112. package/dist/label.js +1 -1
  113. package/dist/labeled-field.js +6 -6
  114. package/dist/metric-badge.js +1 -1
  115. package/dist/metric-stack.js +1 -1
  116. package/dist/motion-core.js +65 -65
  117. package/dist/motion.js +3 -3
  118. package/dist/notification.js +1 -1
  119. package/dist/paper-backdrop.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 +2 -2
  124. package/dist/resolveCanvasColor-BBiYfp8g.js +11 -0
  125. package/dist/responsive-tabs.js +2 -2
  126. package/dist/scrolling-text.js +1 -1
  127. package/dist/search.js +7 -7
  128. package/dist/select.js +3 -3
  129. package/dist/separator.js +1 -1
  130. package/dist/{sheet-Cv1uO-Gq.js → sheet-VZEtNFvO.js} +2 -2
  131. package/dist/sheet.js +1 -1
  132. package/dist/slider-D9puf-Ko.js +142 -0
  133. package/dist/slider.js +1 -1
  134. package/dist/sortable-list.js +3 -3
  135. package/dist/styles/components.css +1 -1
  136. package/dist/styles/dock-controls.css +21 -18
  137. package/dist/styles/dock.css +415 -224
  138. package/dist/styles/fonts.css +0 -25
  139. package/dist/styles/glass.css +100 -41
  140. package/dist/styles/theme.css +9 -2
  141. package/dist/styles/tokens.css +139 -32
  142. package/dist/styles/typography.css +52 -69
  143. package/dist/styles/utilities.css +2 -1
  144. package/dist/styles/view-transition.css +12 -40
  145. package/dist/switch.js +1 -1
  146. package/dist/tabs.js +5 -5
  147. package/dist/timeline.js +3 -3
  148. package/dist/toast.js +1 -1
  149. package/dist/toggle-group.js +1 -1
  150. package/dist/tooltip.js +1 -1
  151. package/dist/typewriter.js +1 -1
  152. package/dist/{useAnimatedNumber-C5I3wWd8.js → useAnimatedNumber-C_3wZLx4.js} +1 -1
  153. package/dist/{useCanvas2D-C31yfUGY.js → useCanvas2D-ClrQuZtp.js} +2 -1
  154. package/dist/{useConfiguratorState-B24TcgIn.js → useConfiguratorState-CMff4GzH.js} +3 -3
  155. package/dist/useResolveTokenColor-r9pnNjqK.js +24 -0
  156. package/dist/useSpecularTracking-BVRZsRHA.js +26 -0
  157. package/dist/{useTextHighlight-aMPdEpkq.js → useTextHighlight-9nMW23Qb.js} +1 -1
  158. package/dist/{useTouchGate-YQRwyUGU.js → useTouchGate-WFyJYsth.js} +1 -1
  159. package/dist/vReveal-CqaCz_mC.js +44 -0
  160. package/dist/watercolor-dot.js +2 -2
  161. package/package.json +36 -4
  162. package/src/fonts/README.md +26 -18
  163. package/src/styles/dock-controls.css +21 -18
  164. package/src/styles/dock.css +415 -224
  165. package/src/styles/fonts.css +0 -25
  166. package/src/styles/glass.css +100 -41
  167. package/src/styles/theme.css +9 -2
  168. package/src/styles/tokens.css +139 -32
  169. package/src/styles/typography.css +52 -69
  170. package/src/styles/utilities.css +2 -1
  171. package/src/styles/view-transition.css +12 -40
  172. package/dist/CardAction-D8nSE62a.js +0 -163
  173. package/dist/compile-iM4IUB66.js +0 -158
  174. package/dist/fonts/fraunces/fraunces-latin.woff2 +0 -0
  175. package/dist/slider-BA9wIs5e.js +0 -130
  176. package/dist/useViewTransition-DaN5Zrox.js +0 -21
  177. package/dist/vReveal-BE2TsPoR.js +0 -24
  178. package/src/fonts/fraunces/fraunces-latin.woff2 +0 -0
  179. /package/dist/{CollapsibleContent-D7UNsXQr.js → CollapsibleContent-CP9qF1v4.js} +0 -0
  180. /package/dist/{ContextMenuContent-DGKZX1Du.js → ContextMenuContent-DDa0v27s.js} +0 -0
  181. /package/dist/{HoverCardContent-Bn0UBMY9.js → HoverCardContent-B6CcQ8He.js} +0 -0
  182. /package/dist/{Input-DWQQIOC4.js → Input-DVG_J0ne.js} +0 -0
  183. /package/dist/{InstrumentChassis-BLJBl1BW.js → InstrumentChassis-C2f6cBaQ.js} +0 -0
  184. /package/dist/{InstrumentRail-BElFwKyt.js → InstrumentRail-CUJ05YVG.js} +0 -0
  185. /package/dist/{Label-DBc7bKzZ.js → Label-zRfbQdCn.js} +0 -0
  186. /package/dist/{ModalOverlay-D1VrWyoi.js → ModalOverlay-B1GkAjNb.js} +0 -0
  187. /package/dist/{PaperBackdrop-DCGoGatv.js → PaperBackdrop-CqwjnfLv.js} +0 -0
  188. /package/dist/{SelectGroup-BcaFjvP4.js → SelectGroup-BFiod7X2.js} +0 -0
  189. /package/dist/{SelectSeparator-COFMJGng.js → SelectSeparator-L8pPEn4L.js} +0 -0
  190. /package/dist/{Separator-DZyqsCum.js → Separator-D7sD7RKj.js} +0 -0
  191. /package/dist/{Switch-2rsAtDfA.js → Switch-LDKLmmgx.js} +0 -0
  192. /package/dist/{TabsList-COqIdW7i.js → TabsList-qyHZ2lKY.js} +0 -0
  193. /package/dist/{Toaster-BMaeziJJ.js → Toaster-CabYEEF_.js} +0 -0
  194. /package/dist/{TooltipProvider-CD2IXfRv.js → TooltipProvider-CmZzCuaG.js} +0 -0
  195. /package/dist/{_plugin-vue_export-helper-gLzyemvl.js → _plugin-vue_export-helper-ok8pgSl5.js} +0 -0
  196. /package/dist/composables/{dom → motion}/useTextHighlight.d.ts +0 -0
  197. /package/dist/{constants-CS75AWHG.js → constants-BPOqYJAm.js} +0 -0
  198. /package/dist/{createContext-CvNyBk4o.js → createContext-B44Sah_H.js} +0 -0
  199. /package/dist/{menuItemVariants-B4eFR5Ix.js → menuItemVariants-DKM85SNE.js} +0 -0
  200. /package/dist/{presets-BKVyQfbt.js → presets-D1XPuTj-.js} +0 -0
  201. /package/dist/{prng-wHuHlNHE.js → prng-COGhh02-.js} +0 -0
  202. /package/dist/{useGlassRenderer-HebgSEgN.js → useGlassRenderer-5I0YkI4t.js} +0 -0
  203. /package/dist/{useGlobalDark-yhL4Wp-s.js → useGlobalDark-D3EBWzXK.js} +0 -0
  204. /package/dist/{useIntersectionPause-Cc-H9ees.js → useIntersectionPause-Bj4sPkMh.js} +0 -0
  205. /package/dist/{useInterval-D3USn0yc.js → useInterval-CcLfq2WU.js} +0 -0
  206. /package/dist/{useKeyboardShortcuts-Be3w_Rwk.js → useKeyboardShortcuts-BXWXOZ-9.js} +0 -0
  207. /package/dist/{useResizeObserver-CSyxGxIX.js → useResizeObserver-CWCbk5Px.js} +0 -0
  208. /package/dist/{useScrollProgress-CAH8Ofwt.js → useScrollProgress-C9ysDic5.js} +0 -0
  209. /package/dist/{useSortable-C8ReQ50P.js → useSortable-MGAbCGVJ.js} +0 -0
  210. /package/dist/{useSpringMount-LRZqJTaF.js → useSpringMount-BJSHcLl3.js} +0 -0
  211. /package/dist/{useTimer-DEJonOZa.js → useTimer-3xqf_54b.js} +0 -0
  212. /package/dist/{useUserInvalidAria-CQKjEfwP.js → useUserInvalidAria-DoJKMZ3s.js} +0 -0
  213. /package/dist/{useViewportReady-K96m-Mdv.js → useViewportReady-RIr5Wgkh.js} +0 -0
package/dist/goo-blob.js CHANGED
@@ -1,23 +1,25 @@
1
- import { t as e } from "./_plugin-vue_export-helper-gLzyemvl.js";
2
- import { d as t, l as n, n as r, o as i, r as a, s as o, t as s } from "./compile-iM4IUB66.js";
3
- import { t as c } from "./useIntersectionPause-Cc-H9ees.js";
4
- import { n as l, t as u } from "./prng-wHuHlNHE.js";
5
- import { computed as d, createElementBlock as f, createElementVNode as p, defineComponent as m, inject as h, normalizeStyle as g, onScopeDispose as _, onUnmounted as v, openBlock as y, readonly as b, ref as x, useTemplateRef as S, watch as C } from "vue";
6
- import { SpringProgress as w } from "@mkbabb/keyframes.js";
1
+ import { t as e } from "./_plugin-vue_export-helper-ok8pgSl5.js";
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-BBTRjvQS.js";
4
+ import { t as l } from "./useIntersectionPause-Bj4sPkMh.js";
5
+ import { n as u, t as d } from "./prng-COGhh02-.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";
7
8
  //#region src/components/custom/goo-blob/types.ts
8
- var T = {
9
+ var E = {
9
10
  canvasSize: 200,
10
- bodyRadius: .25,
11
+ bodyRadius: .22,
11
12
  satelliteCount: 3,
12
- satelliteRadius: .13,
13
- orbitRadius: .35,
13
+ satelliteRadius: .082,
14
+ orbitRadius: .17,
15
+ quality: "full",
14
16
  tempo: 1,
15
- smoothK: .12,
17
+ smoothK: .05,
16
18
  merge: "quadratic",
17
- noiseAmp: .025,
19
+ noiseAmp: .038,
18
20
  noiseFreq: 3.5,
19
21
  noiseSpeed: .08,
20
- warpAmp: 0,
22
+ warpAmp: .35,
21
23
  pulseFreq: .3,
22
24
  pulseAmp: .008,
23
25
  hueRange: 5,
@@ -26,13 +28,13 @@ var T = {
26
28
  colorNoiseFreq: 2,
27
29
  colorNoiseSpeed: .05,
28
30
  paletteStops: [],
29
- iridescence: 0,
31
+ iridescence: .18,
30
32
  iridHue: 85,
31
33
  iridSpeed: .06,
32
- sssScale: 0,
34
+ sssScale: .2,
33
35
  sssPower: 2,
34
- coreGlow: 0,
35
- lit: !1,
36
+ coreGlow: .1,
37
+ lit: !0,
36
38
  rimColor: "var(--foreground)",
37
39
  lightDir: [
38
40
  .4,
@@ -44,10 +46,10 @@ var T = {
44
46
  rimPower: 2.5,
45
47
  rimStrength: .5,
46
48
  pointerAttraction: .35,
47
- pointerStrength: .08,
48
- stretch: .4,
49
+ pointerStrength: .45,
50
+ stretch: .5,
49
51
  clickImpulse: .5,
50
- eccentricity: .25,
52
+ eccentricity: .05,
51
53
  orbitSpeedScale: 1,
52
54
  wobbleScale: 1,
53
55
  mergeRate: 1,
@@ -55,21 +57,21 @@ var T = {
55
57
  absorbedDuration: [2e3, 4e3],
56
58
  emergeDuration: 2200,
57
59
  orbitDuration: [8e3, 14e3]
58
- }, E = Symbol("blobConfig");
60
+ }, D = Symbol("blobConfig");
59
61
  //#endregion
60
62
  //#region src/components/custom/goo-blob/composables/easing.ts
61
- function D(e) {
63
+ function O(e) {
62
64
  return e < .5 ? 2 * e * e : 1 - 2 * (1 - e) * (1 - e);
63
65
  }
64
- function O(e) {
66
+ function k(e) {
65
67
  return e * e;
66
68
  }
67
- function k(e) {
69
+ function A(e) {
68
70
  return 1 - (1 - e) * (1 - e);
69
71
  }
70
72
  //#endregion
71
73
  //#region src/components/custom/goo-blob/composables/useBlobMood.ts
72
- var A = {
74
+ var j = {
73
75
  idle: {
74
76
  valence: 0,
75
77
  arousal: .35
@@ -90,37 +92,37 @@ var A = {
90
92
  valence: .7,
91
93
  arousal: 1
92
94
  }
93
- }, j = (e, t, n) => e + (t - e) * n;
94
- function M({ valence: e, arousal: t }) {
95
+ }, M = (e, t, n) => e + (t - e) * n;
96
+ function N({ valence: e, arousal: t }) {
95
97
  return {
96
- orbitSpeedScale: j(.4, 2.2, t),
97
- wobbleScale: j(.5, 2, t),
98
- pulseFreq: j(.15, 1.5, t),
99
- pulseAmp: j(.008, .05, t),
100
- noiseAmp: j(.015, .045, t),
101
- hueRange: j(3, 25, t * .6 + (e * .5 + .5) * .4),
102
- satShift: j(-.05, .1, e * .5 + .5),
103
- brightnessShift: j(-.03, .08, e * .5 + .5),
104
- smoothK: j(.16, .32, t),
105
- pointerAttraction: j(-.2, .6, e * .5 + .5) * (.4 + .6 * t),
106
- mergeRate: j(2, .3, t),
107
- iridScale: j(.4, 1.8, t)
98
+ orbitSpeedScale: M(.4, 2.2, t),
99
+ wobbleScale: M(.5, 2, t),
100
+ pulseFreq: M(.15, 1.5, t),
101
+ pulseAmp: M(.008, .05, t),
102
+ noiseAmp: M(.015, .045, t),
103
+ hueRange: M(3, 25, t * .6 + (e * .5 + .5) * .4),
104
+ satShift: M(-.05, .1, e * .5 + .5),
105
+ brightnessShift: M(-.03, .08, e * .5 + .5),
106
+ smoothK: M(.85, 1.35, t),
107
+ pointerAttraction: M(-.2, .6, e * .5 + .5) * (.4 + .6 * t),
108
+ mergeRate: M(2, .3, t),
109
+ iridScale: M(.55, 1.35, t)
108
110
  };
109
111
  }
110
- var N = {
111
- idle: M(A.idle),
112
- happy: M(A.happy),
113
- curious: M(A.curious),
114
- sleepy: M(A.sleepy),
115
- excited: M(A.excited)
116
- }, P = {
112
+ var P = {
113
+ idle: N(j.idle),
114
+ happy: N(j.happy),
115
+ curious: N(j.curious),
116
+ sleepy: N(j.sleepy),
117
+ excited: N(j.excited)
118
+ }, F = {
117
119
  idle: 1500,
118
120
  happy: 1200,
119
121
  curious: 800,
120
122
  sleepy: 2500,
121
123
  excited: 600
122
124
  };
123
- function F(e, t, n) {
125
+ function I(e, t, n) {
124
126
  let r = (e, t) => e + (t - e) * n;
125
127
  return {
126
128
  orbitSpeedScale: r(e.orbitSpeedScale, t.orbitSpeedScale),
@@ -137,46 +139,52 @@ function F(e, t, n) {
137
139
  iridScale: r(e.iridScale, t.iridScale)
138
140
  };
139
141
  }
140
- var I = 6e3;
141
- function L() {
142
- let e = x("idle"), t = x({ ...N.idle }), n = { ...N.idle }, r = { ...N.idle }, i = 0, a = 0, o = !1, s = 0;
143
- function c(s) {
144
- s === e.value && !o || (e.value = s, n = { ...t.value }, r = N[s], a = P[s], i = 0, o = !0);
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 = 0;
145
+ function l(s) {
146
+ s === e.value && !o || (e.value = s, n = { ...t.value }, r = P[s], a = F[s], i = 0, o = !0);
145
147
  }
146
- function l(e) {
147
- if (e.clicked) {
148
- s = 900, c("excited");
148
+ function u(e) {
149
+ if (c = e.idleMs, e.clicked) {
150
+ s = 900, l("excited");
149
151
  return;
150
152
  }
151
- s > 0 || (e.pointerActive ? c("curious") : e.idleMs > I ? c("sleepy") : c("idle"));
153
+ s > 0 || (e.pointerActive ? l("curious") : e.idleMs > L ? l("sleepy") : l("idle"));
152
154
  }
153
- function u(e) {
155
+ function d() {
156
+ return o || s > 0 ? !1 : !(e.value !== "sleepy" && c < L);
157
+ }
158
+ function f() {
159
+ return o || s > 0 || e.value === "sleepy" ? Infinity : Math.max(0, L - c);
160
+ }
161
+ function p(e) {
154
162
  if (s > 0 && (s = Math.max(0, s - e)), !o) return;
155
163
  i += e;
156
- let c = Math.min(i / a, 1), l = D(c);
157
- t.value = F(n, r, l), c >= 1 && (o = !1);
164
+ let c = Math.min(i / a, 1), l = O(c);
165
+ t.value = I(n, r, l), c >= 1 && (o = !1);
158
166
  }
159
167
  return {
160
- currentMood: b(e),
161
- params: b(t),
162
- setMood: c,
163
- update: l,
164
- tick: u
168
+ currentMood: x(e),
169
+ params: x(t),
170
+ setMood: l,
171
+ update: u,
172
+ tick: p,
173
+ isSettled: d,
174
+ nextAutoMoodMs: f
165
175
  };
166
176
  }
167
- function R(e) {
168
- let t = x({
177
+ function z(e) {
178
+ let t = S({
169
179
  x: 0,
170
180
  y: 0
171
- }), n = x({
181
+ }), n = S({
172
182
  x: 0,
173
183
  y: 0
174
- }), r = x(!1), i = x(0), a = 0, o = 0, s = {
175
- from: 0,
176
- to: 0,
184
+ }), r = S(!1), i = S(0), a = 0, o = 0, s = {
177
185
  response: .18,
178
186
  dampingFraction: 1
179
- }, c = new w(s), l = new w(s), u = Array.from({ length: 15 }, () => ({
187
+ }, c = new T(s), l = new T(s), u = Array.from({ length: 15 }, () => ({
180
188
  x: 0,
181
189
  y: 0,
182
190
  radius: 0
@@ -191,12 +199,12 @@ function R(e) {
191
199
  r.value = !1;
192
200
  }
193
201
  let _ = null;
194
- C(e, (e) => {
202
+ w(e, (e) => {
195
203
  _ &&= (_(), null), e && (e.addEventListener("pointermove", h), e.addEventListener("pointerleave", g), _ = () => {
196
204
  e.removeEventListener("pointermove", h), e.removeEventListener("pointerleave", g);
197
205
  });
198
- }, { immediate: !0 }), v(() => _?.());
199
- function y(e = 16) {
206
+ }, { immediate: !0 }), y(() => _?.());
207
+ function v(e = 16) {
200
208
  let s = Math.min(e, 50) / 1e3;
201
209
  r.value ? O = 0 : O += Math.min(e, 50);
202
210
  let h = r.value ? a : 0, g = r.value ? o : 0;
@@ -214,7 +222,7 @@ function R(e) {
214
222
  let _ = Math.hypot(c.velocity, l.velocity);
215
223
  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));
216
224
  }
217
- function S(e) {
225
+ function b(e) {
218
226
  let t = [];
219
227
  for (let n = 0; n < f; n++) {
220
228
  let r = u[(d - n + 30) % 15];
@@ -229,13 +237,13 @@ function R(e) {
229
237
  count: f
230
238
  };
231
239
  }
232
- let T = !1;
240
+ let C = !1;
233
241
  function E(e) {
234
- m += e * 18, T = !0;
242
+ m += e * 18, C = !0;
235
243
  }
236
244
  function D() {
237
- let e = T;
238
- return T = !1, e;
245
+ let e = C;
246
+ return C = !1, e;
239
247
  }
240
248
  let O = 0;
241
249
  function k() {
@@ -247,28 +255,33 @@ function R(e) {
247
255
  y: 0
248
256
  }, p = 0, m = 0, i.value = 0, f = 0;
249
257
  }
258
+ let A = .001;
259
+ function j() {
260
+ 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);
261
+ }
250
262
  return {
251
- pointer: b(t),
252
- velocity: b(n),
253
- active: b(r),
254
- pulse: b(i),
263
+ pointer: x(t),
264
+ velocity: x(n),
265
+ active: x(r),
266
+ pulse: x(i),
255
267
  idleMs: () => O,
256
- tick: y,
257
- trailSources: S,
268
+ tick: v,
269
+ trailSources: b,
258
270
  click: E,
259
271
  consumeClick: D,
260
- rest: k
272
+ rest: k,
273
+ isAtRest: j
261
274
  };
262
275
  }
263
276
  //#endregion
264
277
  //#region src/components/custom/goo-blob/composables/useBlobSatellites.ts
265
- function z(e, t, n) {
278
+ function B(e, t, n) {
266
279
  return t + e() * (n - t);
267
280
  }
268
- function B(e) {
281
+ function V(e) {
269
282
  return e < 0 ? 0 : e > 1 ? 1 : e;
270
283
  }
271
- function V(e, t, n) {
284
+ function H(e, t, n) {
272
285
  return e + (t - e) * n;
273
286
  }
274
287
  function ee(e, t, n, r, i) {
@@ -298,10 +311,10 @@ function ee(e, t, n, r, i) {
298
311
  endY: 0
299
312
  };
300
313
  }
301
- function H(e, t, n, r) {
314
+ function U(e, t, n, r) {
302
315
  e.phase = t, e.phaseStart = n, e.phaseDuration = r;
303
316
  }
304
- function U(e, t, n, r) {
317
+ function W(e, t, n, r) {
305
318
  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));
306
319
  return {
307
320
  x: (e.baseRadiusX + o) * Math.cos(a) + e.pertXAmp * Math.sin(e.pertXFreq * i + e.pertXPhase),
@@ -313,9 +326,9 @@ function te(e, t, n, r, i) {
313
326
  let a = n * (.8 + t() * .4), o = r * (.3 + t() * .7);
314
327
  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;
315
328
  }
316
- var W = .75, G = 2e3;
317
- function K(e, t) {
318
- let n = l(u(t + "goo")), r = [], i = [], a = [], o = -Infinity, s = e.orbitRadius;
329
+ var G = .75, K = 2e3;
330
+ function q(e, t) {
331
+ let n = u(d(t + "goo")), r = [], i = [], a = [], o = -Infinity, s = e.orbitRadius;
319
332
  function c() {
320
333
  let t = e.orbitRadius;
321
334
  if (t !== s && s > 0) {
@@ -324,7 +337,7 @@ function K(e, t) {
324
337
  s = t;
325
338
  }
326
339
  }
327
- function d(t) {
340
+ function l(t) {
328
341
  let o = e.satelliteCount;
329
342
  for (; r.length < o;) r.push(ee(n, r.length, e.orbitRadius, e.eccentricity, t)), i.push({
330
343
  x: 0,
@@ -339,65 +352,65 @@ function K(e, t) {
339
352
  r.length > o && (r.length = o, i.length = o, a.length = o);
340
353
  }
341
354
  function f(t, s) {
342
- d(t), c();
343
- let l = r.length, u = s.mergeRate, f = e.satelliteRadius, p = e.mergeDuration, m = e.emergeDuration, h = e.orbitDuration, g = e.absorbedDuration;
344
- for (let c = 0; c < l; c++) {
345
- let l = r[c], d = t - l.phaseStart, _ = B(l.phaseDuration > 0 ? d / l.phaseDuration : 1);
355
+ l(t), c();
356
+ let u = r.length, d = s.mergeRate, f = e.satelliteRadius, p = e.mergeDuration, m = e.emergeDuration, h = e.orbitDuration, g = e.absorbedDuration;
357
+ for (let c = 0; c < u; c++) {
358
+ let l = r[c], u = t - l.phaseStart, _ = V(l.phaseDuration > 0 ? u / l.phaseDuration : 1);
346
359
  switch (l.phase) {
347
360
  case "orbiting":
348
- if (_ >= 1) if (t - o < 3e3 * u) l.phaseStart = t, l.phaseDuration = z(n, h[0], h[1]);
361
+ if (_ >= 1) if (t - o < 3e3 * d) l.phaseStart = t, l.phaseDuration = B(n, h[0], h[1]);
349
362
  else {
350
- let e = U(l, t, s.orbitSpeedScale, s.wobbleScale);
363
+ let e = W(l, t, s.orbitSpeedScale, s.wobbleScale);
351
364
  l.startX = e.x, l.startY = e.y;
352
365
  let n = Math.hypot(e.x, e.y), r = n > .01 ? .08 / n : 0;
353
- l.endX = e.x * r, l.endY = e.y * r, H(l, "merging", t, p), o = t;
366
+ l.endX = e.x * r, l.endY = e.y * r, U(l, "merging", t, p), o = t;
354
367
  }
355
368
  break;
356
369
  case "merging":
357
- _ >= 1 && H(l, "absorbed", t, z(n, g[0], g[1]));
370
+ _ >= 1 && U(l, "absorbed", t, B(n, g[0], g[1]));
358
371
  break;
359
372
  case "absorbed":
360
373
  if (_ >= 1) {
361
374
  te(l, n, e.orbitRadius, e.eccentricity, t);
362
- let r = U(l, t + 3e3, s.orbitSpeedScale, s.wobbleScale);
375
+ let r = W(l, t + 3e3, s.orbitSpeedScale, s.wobbleScale);
363
376
  l.endX = r.x, l.endY = r.y;
364
377
  let i = Math.hypot(r.x, r.y), a = i > .01 ? .08 / i : 0;
365
- l.startX = r.x * a, l.startY = r.y * a, H(l, "emerging", t, m);
378
+ l.startX = r.x * a, l.startY = r.y * a, U(l, "emerging", t, m);
366
379
  }
367
380
  break;
368
381
  case "emerging":
369
382
  if (_ >= 1) {
370
383
  let e = a[c];
371
- e.x = l.endX, e.y = l.endY, e.start = t, l.timeOrigin = t, l.phaseOffset = Math.atan2(l.endY, l.endX), H(l, "orbiting", t, z(n, h[0], h[1]));
384
+ 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]));
372
385
  }
373
386
  break;
374
387
  }
375
388
  let v, y, b, x;
376
389
  switch (l.phase) {
377
390
  case "orbiting": {
378
- let e = U(l, t, s.orbitSpeedScale, s.wobbleScale), n = a[c], r = t - n.start;
379
- if (n.start > 0 && r < G) {
380
- let t = B(r / G), i = t * t * (3 - 2 * t);
381
- v = V(n.x, e.x, i), y = V(n.y, e.y, i);
391
+ let e = W(l, t, s.orbitSpeedScale, s.wobbleScale), n = a[c], r = t - n.start;
392
+ if (n.start > 0 && r < K) {
393
+ let t = V(r / K), i = t * t * (3 - 2 * t);
394
+ v = H(n.x, e.x, i), y = H(n.y, e.y, i);
382
395
  } else v = e.x, y = e.y;
383
- b = W, x = 1;
396
+ b = G, x = 1;
384
397
  break;
385
398
  }
386
399
  case "merging": {
387
- let e = O(B((t - l.phaseStart) / l.phaseDuration));
388
- v = V(l.startX, l.endX, e), y = V(l.startY, l.endY, e);
389
- let n = B((t - l.phaseStart) / l.phaseDuration);
390
- b = n > .85 ? V(W, 0, (n - .85) / .15) : W, x = V(1, .65, e);
400
+ let e = k(V((t - l.phaseStart) / l.phaseDuration));
401
+ v = H(l.startX, l.endX, e), y = H(l.startY, l.endY, e);
402
+ let n = V((t - l.phaseStart) / l.phaseDuration);
403
+ b = n > .85 ? H(G, 0, (n - .85) / .15) : G, x = H(1, .65, e);
391
404
  break;
392
405
  }
393
406
  case "absorbed":
394
407
  v = 0, y = 0, b = 0, x = .5;
395
408
  break;
396
409
  case "emerging": {
397
- let e = k(B((t - l.phaseStart) / l.phaseDuration));
398
- v = V(l.startX, l.endX, e), y = V(l.startY, l.endY, e);
399
- let n = B((t - l.phaseStart) / l.phaseDuration);
400
- b = n < .1 ? V(0, W, n / .1) : W, x = V(.65, 1, e);
410
+ let e = A(V((t - l.phaseStart) / l.phaseDuration));
411
+ v = H(l.startX, l.endX, e), y = H(l.startY, l.endY, e);
412
+ let n = V((t - l.phaseStart) / l.phaseDuration);
413
+ b = n < .1 ? H(0, G, n / .1) : G, x = H(.65, 1, e);
401
414
  break;
402
415
  }
403
416
  }
@@ -409,20 +422,86 @@ function K(e, t) {
409
422
  for (let e of r) e.phaseOffset += (n() - .5) * .6, e.pertXPhase += n() * Math.PI, e.pertYPhase += n() * Math.PI;
410
423
  }
411
424
  function m(e) {
412
- n = l(u(e + "goo"));
425
+ n = u(d(e + "goo"));
426
+ }
427
+ function h() {
428
+ for (let e of r) if (e.phase !== "orbiting") return !1;
429
+ return !0;
430
+ }
431
+ function g(e) {
432
+ let t = Infinity;
433
+ for (let e of r) {
434
+ let n = e.phaseStart + e.phaseDuration;
435
+ n < t && (t = n);
436
+ }
437
+ return t === Infinity ? e + 3e4 : t;
413
438
  }
414
439
  return {
415
440
  sources: i,
416
441
  tick: f,
417
442
  nudge: p,
418
- reseed: m
443
+ reseed: m,
444
+ isQuiescent: h,
445
+ nextEventMs: g
419
446
  };
420
447
  }
421
448
  //#endregion
422
449
  //#region src/components/custom/goo-blob/shaders/metaball.vert.ts
423
- 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// 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}", 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 + 2.0 lacunarity, per §3a).", ae = "float fbm(vec2 p, int octaves) {\n float value = 0.0;\n float amp = 0.5;\n float freq = 1.0;\n for (int i = 0; i < 4; i++) {\n if (i >= octaves) break;\n value += amp * noised(p * freq).x;\n p = FBM_ROT * p;\n freq *= 2.0;\n amp *= 0.5;\n }\n return value;\n}\n\n// One domain-warp pass: offset the sample point by a low-frequency FBM of itself\n// (the IQ fbm(p + W*fbm(p)) marbling). warpAmp (uniform-driven) is the warp\n// strength; warpAmp == 0.0 degrades to plain fbm (the pre-warp look).\nfloat fbmWarped(vec2 p, int octaves, float warpAmp) {\n if (warpAmp <= 0.0) return fbm(p, octaves);\n vec2 q = vec2(fbm(p + vec2(0.0, 0.0), octaves), fbm(p + vec2(5.2, 1.3), octaves));\n return fbm(p + warpAmp * (q - 0.5), octaves);\n}\n", 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}", q = "\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// 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 + q + `${o}
450
+ 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) {
451
+ float value = 0.0;
452
+ float amp = 0.5;
453
+ float freq = 1.0;
454
+ for (int i = 0; i < 4; i++) {
455
+ if (i >= octaves) break;
456
+ value += amp * noised(p * freq).x;
457
+ p = FBM_ROT * p;
458
+ freq *= ${J.toFixed(1)};
459
+ amp *= ${Y.toFixed(2)};
460
+ }
461
+ return value;
462
+ }
424
463
 
425
- ` + ae + q + re + q + `
464
+ // AX.W15 — FBM with ANALYTIC GRADIENT. Returns vec3(value, ∂/∂x, ∂/∂y). The
465
+ // gradient accumulates noised()'s analytic gradient per octave, chain-ruled
466
+ // through the per-octave frequency scale AND the FBM_ROT rotation: octave i samples
467
+ // at R^i · (freq·p), so the gradient w.r.t. the ORIGINAL p picks up freq and
468
+ // the accumulated rotation transpose (R^T)^i. The keystone feed for the
469
+ // analytic surface normal — it DELETES the per-pixel 4-tap finite difference.
470
+ vec3 fbmG(vec2 p, int octaves) {
471
+ float value = 0.0;
472
+ vec2 grad = vec2(0.0);
473
+ float amp = 0.5;
474
+ float freq = 1.0;
475
+ // The accumulated octave rotation R^i — its transpose maps the i-th octave's
476
+ // local gradient back into the ORIGINAL p frame. Seeded at identity (octave 0).
477
+ mat2 rotAccum = mat2(1.0, 0.0, 0.0, 1.0);
478
+ vec2 pp = p;
479
+ for (int i = 0; i < 4; i++) {
480
+ if (i >= octaves) break;
481
+ vec3 n = noised(pp * freq);
482
+ value += amp * n.x;
483
+ // d(value)/dp = amp · freq · (R^i)^T · noised.yz (the rotated chain rule).
484
+ grad += amp * freq * (transpose(rotAccum) * n.yz);
485
+ pp = FBM_ROT * pp;
486
+ freq *= ${J.toFixed(1)};
487
+ amp *= ${Y.toFixed(2)};
488
+ rotAccum = FBM_ROT * rotAccum;
489
+ }
490
+ return vec3(value, grad);
491
+ }
492
+
493
+ // One domain-warp pass with the ANALYTIC GRADIENT carried (warp-Jacobian
494
+ // APPROXIMATION per the SOTA deepening [2]: the warp is low-frequency, so the
495
+ // gradient of the OUTER fbm dominates and the warp-offset Jacobian is dropped —
496
+ // the error is sub-perceptible and full autodiff is overfit for one blob).
497
+ vec3 fbmWarpedG(vec2 p, int octaves, float warpAmp) {
498
+ if (warpAmp <= 0.0) return fbmG(p, octaves);
499
+ vec2 q = vec2(fbm(p + vec2(0.0, 0.0), octaves), fbm(p + vec2(5.2, 1.3), octaves));
500
+ return fbmG(p + warpAmp * (q - 0.5), octaves);
501
+ }
502
+ `, 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}
503
+
504
+ ` + ae + X + re + X + `
426
505
  // --- Color (Ottosson OKLab/OKLCh — value.js EXACT constants, transposed) ---
427
506
  //
428
507
  // The OETF (srgbToLinear/linearToSrgb) + the four Ottosson matrices + their space
@@ -431,42 +510,40 @@ var ne = "#version 300 es\n\nin vec2 aPosition;\nout vec2 vUv;\n\nvoid main() {\
431
510
  // ONCE so the OETF can never diverge from aurora's; the line-for-line TS port
432
511
  // (__tests__/metaball-color.glsl-port.ts) mirrors that chunk. The gamut-clamp
433
512
  // below stays blob-local (aurora has no in-shader OKLCh path).
513
+ ${r}
434
514
  ${n}
435
- ${t}
436
515
 
437
- ` + oe + q + "\n// The composite SDF field — the domain-warped body membrane smin-merged with the\n// satellites. Factored so the lit-surface block (W9.b) can sample the SAME field\n// at a screen-space epsilon to derive the IQ tetrahedron normal: the normal MUST\n// ride the composite distance the alpha is cut from, not a clean circle.\nfloat sceneDist(vec2 uv) {\n // Pulsing body radius.\n float bodyR = uBodyRadius + sin(uPulsePhase) * uPulseAmp;\n\n // Velocity-driven VOLUME-PRESERVING squash-and-stretch (W10). Stretch the body\n // along the motion direction by sa = 1 + |v|*k and squash the PERPENDICULAR\n // axis by EXACTLY 1/sa (NOT 1 - amt, which loses area so the blob SHRINKS at\n // speed). Applied as an anisotropic basis in body space: q = (dot/sa, dot*sa).\n vec2 bodyUv = uv;\n float speed = length(uVelocity);\n if (uStretch > 0.0 && speed > 1e-4) {\n vec2 ax = uVelocity / speed; // motion axis (unit)\n vec2 perp = vec2(-ax.y, ax.x); // perpendicular\n float sa = 1.0 + speed * uStretch; // stretch factor along motion\n bodyUv = vec2(dot(uv, ax) / sa, dot(uv, perp) * sa);\n }\n\n // Domain-warped FBM displacement — the organic marbled watercolor membrane.\n float noiseVal = fbmWarped(bodyUv * uNoiseFreq + uTime * uNoiseSpeed, 3, uWarpAmp);\n float bodyDisplacement = (noiseVal - 0.5) * uNoiseAmp;\n\n float d = sdCircle(bodyUv, vec2(0.0), bodyR + bodyDisplacement);\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 float satD = sdCircle(uv, uSatPos[i], uSatRadius[i]);\n satD += (1.0 - uSatOpacity[i]) * 0.3;\n d = smin(d, satD, 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. COMPILE-TIME\n // array, DYNAMIC break (mirrors the satellite loop).\n for (int i = 0; i < TRAIL_N; i++) {\n if (i >= uTrailCount) break;\n float trailD = sdCircle(uv, uTrailPos[i], uTrailRadius[i]);\n d = smin(d, trailD, uSmoothK);\n }\n return d;\n}\n\n// W9.b — the IQ 4-tap tetrahedron gradient of the composite SDF, lifted to a\n// pseudo-3D surface normal so the droplet reads as a rounded bead (flat centre,\n// steep rim) rather than a flat sticker.\n//\n// SCREEN-SPACE epsilon: the smin + domain-warped FBM field is NOT a unit-gradient\n// SDF, so a tiny fixed epsilon shimmers; the tap offset is ~1.5px / uResolution.y\n// so it tracks the rendered pixel size at any zoom. normalize() is guarded with\n// +1e-6 (the gate's |N| ~ 1 assertion holds across the interior).\n//\n// The Z lift: 'interior' is the normalized depth inward from the rim\n// (-d / bodyR, 0 at the edge, ~1 deep inside); the dome height\n// z = sqrt(max(0, 1 - (1 - interior)^2)) is the unit half-sphere profile (flat\n// at the centre, steep at the rim). n3 = normalize(vec3(grad2d * (1 - z), z))\n// tilts the normal outward along the SDF gradient near the rim and points it at\n// the viewer deep inside.\nvec3 surfaceNormal(vec2 uv, float d, float bodyR) {\n const vec2 k = vec2(1.0, -1.0);\n float eps = 1.5 / max(uResolution.y, 1.0);\n vec2 grad2d = normalize(\n k.xy * sceneDist(uv + k.xy * eps) +\n k.yy * sceneDist(uv + k.yy * eps) +\n k.yx * sceneDist(uv + k.yx * eps) +\n k.xx * sceneDist(uv + k.xx * eps) + vec2(1e-6));\n\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(grad2d * (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 // 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 if (uPointerActive > 0.5) {\n vec2 pointerDir = uPointer - uv;\n float pointerDist = length(pointerDir);\n float influence = smoothstep(0.4, 0.0, pointerDist) * uPointerAttraction * uPointerStrength;\n uv -= normalize(pointerDir + 1e-6) * influence;\n }\n\n // The pulsing body radius — also reused below for the inner-glow falloff scale.\n float bodyR = uBodyRadius + sin(uPulsePhase) * uPulseAmp;\n\n // Composite domain-warped membrane field.\n float d = sceneDist(uv);\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 — computed ONCE here and reused by the iridescence (W11.a),\n // the fake-SSS (W11.a), and the lit glass block (W9.b).\n vec3 N = surfaceNormal(uv, 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 // Inner-luminosity ramp: brighter where the body is thick.\n oklch.x = min(oklch.x + uCoreGlow * 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 oklch.z += sss * 0.1; // warm the leaking edge slightly\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 float spec = pow(max(dot(N, H), 0.0), uSpecShininess) * uSpecStrength;\n\n // Fresnel/Schlick rim — fed uRimColor (the --foreground warm rim via the\n // injected ColorResolver, NOT a cold-blue default). Attenuated where the\n // body is thick so the sheen rides the rim, not the core. The rim Fresnel\n // uses uRimPower (the W9.b knob), distinct from the iridescence's fixed 2.5.\n float rimFres = pow(1.0 - max(dot(N, V), 0.0), uRimPower);\n float rim = rimFres * uRimStrength * (1.0 - 0.6 * thickness);\n vec3 rimLin = srgbToLinear(uRimColor);\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 vec3 highlight = max(warmCream * spec, rimLin * rim);\n lin += highlight;\n }\n\n vec3 rgb = clamp(linearToSrgb(lin), 0.0, 1.0); // MANDATORY OETF — closes the seam\n\n // Edit #8 — premultiply AFTER the OETF: straight-alpha gamma → premultiplied.\n fragColor = vec4(rgb * alpha, alpha);\n}", J = 4, Y = 15, X = 4, Z = "[GooBlob]", Q = 1 / 1.6, ce = /* @__PURE__ */ "uResolution.uTime.uBaseColor.uPointer.uPointerActive.uPointerAttraction.uPointerStrength.uBodyRadius.uPulsePhase.uPulseAmp.uNoiseAmp.uNoiseFreq.uNoiseSpeed.uWarpAmp.uSmoothK.uMerge.uLit.uRimColor.uLightDir.uSpecStrength.uSpecShininess.uRimPower.uRimStrength.uIridescence.uIridHue.uIridSpeed.uSssScale.uSssPower.uCoreGlow.uHueRange.uSatShift.uBrightnessShift.uColorNoiseFreq.uColorNoiseSpeed.uStopCount.uSatCount.uTrailCount.uVelocity.uStretch".split(".");
438
- function $(e) {
439
- let { canvasRef: t, color: n, mood: o, pointer: l, satellites: u, config: d, colorResolver: f } = e;
440
- if (typeof f != "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.");
441
- let p = 0, m = 0, h = /* @__PURE__ */ new Map();
442
- function g(e) {
443
- let t = h.get(e);
516
+ ` + 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). sa = 1 + |v|·k\n // along motion, EXACTLY 1/sa perpendicular (area-preserving). The basis (ax,\n // perp) is captured so the gradient can be transformed back below.\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 + speed * 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.W15 REDRESS — the falloff radius WIDENS 0.4 to 0.65. The flick lands the\n // pointer at ~0.32 uv from the body centre; with the old 0.4 cutoff the body sat\n // deep in the dead smoothstep tail (~0.10 weight), so even a strong strength left\n // a sub-floor centroid shift (the live 0.0011 vs the 0.012 gate). 0.65 reaches the\n // whole creature coherently — the body, satellites and trail all tilt toward the\n // cursor as one — so the lean READS. Paired with pointerStrength 0.45 (types.ts).\n if (uPointerActive > 0.5) {\n vec2 pointerDir = uPointer - uv;\n float pointerDist = length(pointerDir);\n float influence = smoothstep(0.65, 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 vec3 highlight = max(warmCream * spec, rimLin * rim);\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(".");
517
+ function de(e) {
518
+ let { canvasRef: t, color: n, rimColor: r, paletteStops: s, mood: u, pointer: d, satellites: f, config: p, colorResolver: m } = e;
519
+ 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.");
520
+ let h = 0, g = 0, _ = /* @__PURE__ */ new Map();
521
+ function v(e) {
522
+ let t = _.get(e);
444
523
  if (t) return t;
445
- let n = f(e);
446
- return h.size > 256 && h.clear(), h.set(e, n), n;
524
+ let n = m(e);
525
+ return _.size > 256 && _.clear(), _.set(e, n), n;
447
526
  }
448
- let _ = /* @__PURE__ */ new Map();
449
- function y(e, t) {
450
- let n = _.get(e);
451
- if (n) return n;
452
- let r = e;
453
- if (e.includes("var(") && typeof window < "u" && t) {
454
- let n = t.style.color;
455
- t.style.color = e, r = getComputedStyle(t).color || e, t.style.color = n;
456
- }
457
- let i = f(r);
458
- return _.size > 64 && _.clear(), _.set(e, i), i;
527
+ let b = null, x = !1, S = null;
528
+ function C() {
529
+ S !== null && (clearTimeout(S), S = null);
459
530
  }
460
- let b = null, x = !1;
461
- c(t, {
462
- pause: () => b?.suspend("off-screen"),
463
- resume: () => b?.resume("off-screen")
531
+ function T(e) {
532
+ if (C(), typeof setTimeout > "u") return;
533
+ let t = Math.min(Math.max(e - g, 16), 3e4);
534
+ S = setTimeout(() => {
535
+ S = null, b?.wake();
536
+ }, t);
537
+ }
538
+ l(t, {
539
+ pause: () => b?.suspend("off-screen-io"),
540
+ resume: () => b?.resume("off-screen-io")
464
541
  }, {
465
542
  rootMargin: "200px",
466
543
  pauseWhenHidden: !1
467
544
  });
468
- function S(e) {
469
- b = a(e, {
545
+ function E(e) {
546
+ b = o(e, {
470
547
  contextAttrs: {
471
548
  alpha: !0,
472
549
  premultipliedAlpha: !0,
@@ -474,12 +551,12 @@ function $(e) {
474
551
  preserveDrawingBuffer: !1
475
552
  },
476
553
  setup: (t) => {
477
- let a = s(t, t.VERTEX_SHADER, ne, Z), c = s(t, t.FRAGMENT_SHADER, se, Z), f = r(t, a, c, Z);
478
- t.useProgram(f);
479
- let h = t.createVertexArray();
480
- t.bindVertexArray(h);
481
- let _ = t.createBuffer();
482
- t.bindBuffer(t.ARRAY_BUFFER, _), t.bufferData(t.ARRAY_BUFFER, new Float32Array([
554
+ let o = c(t, t.VERTEX_SHADER, ne, Q), l = c(t, t.FRAGMENT_SHADER, se, Q), m = i(t, o, l, Q);
555
+ t.useProgram(m);
556
+ let _ = t.createVertexArray();
557
+ t.bindVertexArray(_);
558
+ let y = t.createBuffer();
559
+ t.bindBuffer(t.ARRAY_BUFFER, y), t.bufferData(t.ARRAY_BUFFER, new Float32Array([
483
560
  -1,
484
561
  -1,
485
562
  1,
@@ -493,82 +570,87 @@ function $(e) {
493
570
  1,
494
571
  1
495
572
  ]), t.STATIC_DRAW);
496
- let v = t.getAttribLocation(f, "aPosition");
497
- t.enableVertexAttribArray(v), t.vertexAttribPointer(v, 2, t.FLOAT, !1, 0, 0);
498
- let S = {};
499
- for (let e of ce) S[e] = t.getUniformLocation(f, e);
500
- let C = [], w = [], E = [];
501
- for (let e = 0; e < J; e++) C.push(t.getUniformLocation(f, `uSatPos[${e}]`)), w.push(t.getUniformLocation(f, `uSatRadius[${e}]`)), E.push(t.getUniformLocation(f, `uSatOpacity[${e}]`));
502
- let D = [], O = [];
503
- for (let e = 0; e < Y; e++) D.push(t.getUniformLocation(f, `uTrailPos[${e}]`)), O.push(t.getUniformLocation(f, `uTrailRadius[${e}]`));
504
- let k = [];
505
- for (let e = 0; e < X; e++) k.push(t.getUniformLocation(f, `uPalette[${e}]`));
573
+ let S = t.getAttribLocation(m, "aPosition");
574
+ t.enableVertexAttribArray(S), t.vertexAttribPointer(S, 2, t.FLOAT, !1, 0, 0);
575
+ let w = {};
576
+ for (let e of ue) w[e] = t.getUniformLocation(m, e);
577
+ let E = [], D = [], O = [];
578
+ 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}]`));
579
+ let k = [], A = [];
580
+ for (let e = 0; e < le; e++) k.push(t.getUniformLocation(m, `uTrailPos[${e}]`)), A.push(t.getUniformLocation(m, `uTrailRadius[${e}]`));
581
+ let j = [];
582
+ for (let e = 0; e < Z; e++) j.push(t.getUniformLocation(m, `uPalette[${e}]`));
506
583
  t.enable(t.BLEND), t.blendFunc(t.ONE, t.ONE_MINUS_SRC_ALPHA);
507
- function A() {
508
- let n = i(), r = e.clientWidth || d.canvasSize, a = e.clientHeight || d.canvasSize, o = Math.round(r * n), s = Math.round(a * n);
509
- (e.width !== o || e.height !== s) && (e.width = o, e.height = s), t.viewport(0, 0, o, s);
584
+ function M() {
585
+ 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));
586
+ (e.width !== s || e.height !== c) && (e.width = s, e.height = c), t.viewport(0, 0, s, c);
510
587
  }
511
- function j(r) {
512
- let i = p ? (r - p) * 1e3 : 16;
513
- p = r;
514
- let a = Math.min(i, 50), s = b?.reducedMotion ?? !1, c = (s || x ? 0 : d.tempo) * a;
515
- m += c, s || o.update({
516
- pointerActive: l.active.value,
517
- clicked: l.consumeClick(),
518
- idleMs: l.idleMs()
519
- }), o.tick(c), s ? l.rest() : l.tick(c), u.tick(m, o.params.value);
520
- let _ = o.params.value, v = g(n.value);
521
- t.useProgram(f), t.bindVertexArray(h), t.uniform2f(S.uResolution, e.width, e.height), t.uniform1f(S.uTime, m / 1e3), t.uniform3f(S.uBaseColor, v[0], v[1], v[2]);
522
- let A = d.paletteStops, j = Math.min(A.length, X);
523
- t.uniform1i(S.uStopCount, j);
524
- for (let n = 0; n < X; n++) {
525
- let r = k[n] ?? null, i = A[n];
526
- if (i) {
527
- let n = y(i, e);
528
- t.uniform3f(r, n[0], n[1], n[2]);
529
- } else t.uniform3f(r, v[0], v[1], v[2]);
588
+ function N(i) {
589
+ let a = h ? (i - h) * 1e3 : 16;
590
+ h = i;
591
+ let o = Math.min(a, 50), c = b?.reducedMotion ?? !1, l = (c || x ? 0 : p.tempo) * o;
592
+ g += l, c || u.update({
593
+ pointerActive: d.active.value,
594
+ clicked: d.consumeClick(),
595
+ idleMs: d.idleMs()
596
+ }), u.tick(l), c ? d.rest() : d.tick(l), f.tick(g, u.params.value);
597
+ let y = u.params.value, S = v(n.value);
598
+ 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]);
599
+ let C = s.value, T = Math.min(C.length, Z);
600
+ t.uniform1i(w.uStopCount, T);
601
+ for (let e = 0; e < Z; e++) {
602
+ let n = j[e] ?? null, r = C[e];
603
+ if (r) {
604
+ let e = v(r);
605
+ t.uniform3f(n, e[0], e[1], e[2]);
606
+ } else t.uniform3f(n, S[0], S[1], S[2]);
530
607
  }
531
- let M = l.pointer.value;
532
- t.uniform2f(S.uPointer, M.x * .5 * Q, M.y * .5 * Q), t.uniform1f(S.uPointerActive, +!!l.active.value), t.uniform1f(S.uPointerAttraction, d.pointerAttraction + _.pointerAttraction), t.uniform1f(S.uPointerStrength, d.pointerStrength * Q);
533
- let N = l.velocity.value;
534
- t.uniform2f(S.uVelocity, N.x * .5 * Q, N.y * .5 * Q), t.uniform1f(S.uStretch, d.stretch);
535
- let P = l.trailSources(d.satelliteRadius * .7);
536
- t.uniform1i(S.uTrailCount, P.count);
537
- for (let e = 0; e < Y; e++) {
538
- let n = D[e] ?? null, r = O[e] ?? null, i = P.sources[e];
539
- i ? (t.uniform2f(n, i.x * .5 * Q, i.y * .5 * Q), t.uniform1f(r, i.radius * Q)) : (t.uniform2f(n, 0, 0), t.uniform1f(r, 0));
608
+ let M = d.pointer.value;
609
+ 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 * $);
610
+ let N = d.velocity.value;
611
+ t.uniform2f(w.uVelocity, N.x * .5 * $, N.y * .5 * $), t.uniform1f(w.uStretch, p.stretch);
612
+ let P = d.trailSources(p.satelliteRadius * .7);
613
+ t.uniform1i(w.uTrailCount, P.count);
614
+ for (let e = 0; e < le; e++) {
615
+ let n = k[e] ?? null, r = A[e] ?? null, i = P.sources[e];
616
+ i ? (t.uniform2f(n, i.x * .5 * $, i.y * .5 * $), t.uniform1f(r, i.radius * $)) : (t.uniform2f(n, 0, 0), t.uniform1f(r, 0));
540
617
  }
541
- t.uniform1f(S.uBodyRadius, d.bodyRadius * Q), t.uniform1f(S.uPulsePhase, r * d.pulseFreq * _.pulseFreq * Math.PI * 2);
542
- let F = l.pulse.value * d.clickImpulse;
543
- t.uniform1f(S.uPulseAmp, (d.pulseAmp * _.pulseAmp / .015 + F) * Q), t.uniform1f(S.uNoiseAmp, d.noiseAmp * _.noiseAmp / .025 * Q), t.uniform1f(S.uNoiseFreq, d.noiseFreq), t.uniform1f(S.uNoiseSpeed, d.noiseSpeed), t.uniform1f(S.uWarpAmp, d.warpAmp), t.uniform1f(S.uSmoothK, d.smoothK * (_.smoothK / T.smoothK)), t.uniform1f(S.uMerge, +(d.merge === "circular")), t.uniform1f(S.uHueRange, d.hueRange + _.hueRange), t.uniform1f(S.uSatShift, d.satShift + _.satShift), t.uniform1f(S.uBrightnessShift, d.brightnessShift + _.brightnessShift), t.uniform1f(S.uColorNoiseFreq, d.colorNoiseFreq), t.uniform1f(S.uColorNoiseSpeed, d.colorNoiseSpeed), t.uniform1f(S.uLit, +!!d.lit);
544
- let I = y(d.rimColor, e);
545
- t.uniform3f(S.uRimColor, I[0], I[1], I[2]), t.uniform3f(S.uLightDir, d.lightDir[0], d.lightDir[1], d.lightDir[2]), t.uniform1f(S.uSpecStrength, d.specStrength), t.uniform1f(S.uSpecShininess, d.specShininess), t.uniform1f(S.uRimPower, d.rimPower), t.uniform1f(S.uRimStrength, d.rimStrength), t.uniform1f(S.uIridescence, d.iridescence * _.iridScale), t.uniform1f(S.uIridHue, d.iridHue * (Math.PI / 180)), t.uniform1f(S.uIridSpeed, d.iridSpeed), t.uniform1f(S.uSssScale, d.sssScale * _.iridScale), t.uniform1f(S.uSssPower, d.sssPower), t.uniform1f(S.uCoreGlow, d.coreGlow);
546
- let L = u.sources;
547
- t.uniform1i(S.uSatCount, L.length);
548
- for (let e = 0; e < J; e++) {
549
- let n = C[e] ?? null, r = w[e] ?? null, i = E[e] ?? null, a = L[e];
550
- a ? (t.uniform2f(n, a.x * Q, a.y * Q), t.uniform1f(r, a.radius * Q), t.uniform1f(i, a.opacity)) : (t.uniform2f(n, 0, 0), t.uniform1f(r, 0), t.uniform1f(i, 0));
618
+ t.uniform1f(w.uBodyRadius, p.bodyRadius * $), t.uniform1f(w.uPulsePhase, i * p.pulseFreq * y.pulseFreq * Math.PI * 2);
619
+ let F = d.pulse.value * p.clickImpulse;
620
+ 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"));
621
+ 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;
622
+ 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);
623
+ let R = v(r.value);
624
+ 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);
625
+ let z = f.sources;
626
+ t.uniform1i(w.uSatCount, z.length);
627
+ for (let e = 0; e < ce; e++) {
628
+ let n = E[e] ?? null, r = D[e] ?? null, i = O[e] ?? null, a = z[e];
629
+ 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));
551
630
  }
552
631
  t.clearColor(0, 0, 0, 0), t.clear(t.COLOR_BUFFER_BIT), t.drawArrays(t.TRIANGLES, 0, 6), t.bindVertexArray(null);
553
632
  }
554
- function M() {
555
- return !x;
633
+ function P() {
634
+ if (x) return !1;
635
+ if (!u.isSettled() || !d.isAtRest() || !f.isQuiescent()) return C(), !0;
636
+ let e = f.nextEventMs(g), t = u.nextAutoMoodMs(), n = Number.isFinite(t) ? g + t : Infinity;
637
+ return T(Math.min(e, n)), !1;
556
638
  }
557
639
  return {
558
- frame: j,
559
- shouldContinue: M,
560
- resize: A,
640
+ frame: N,
641
+ shouldContinue: P,
642
+ resize: M,
561
643
  teardown: () => {
562
- t.deleteProgram(f), t.deleteShader(a), t.deleteShader(c), t.deleteBuffer(_), t.deleteVertexArray(h);
644
+ t.deleteProgram(m), t.deleteShader(o), t.deleteShader(l), t.deleteBuffer(y), t.deleteVertexArray(_);
563
645
  }
564
646
  };
565
647
  }
566
648
  }), b.arm();
567
649
  }
568
- return C(t, (e) => {
569
- e && !b && S(e);
570
- }, { immediate: !0 }), C(n, () => b?.wake()), v(() => {
571
- b?.dispose(), b = null;
650
+ return w(t, (e) => {
651
+ e && !b && E(e);
652
+ }, { immediate: !0 }), w(n, () => b?.wake()), y(() => {
653
+ C(), b?.dispose(), b = null;
572
654
  }), {
573
655
  pause: () => {
574
656
  x = !0, b?.suspend("manual");
@@ -580,80 +662,81 @@ function $(e) {
580
662
  }
581
663
  //#endregion
582
664
  //#region src/components/custom/goo-blob/GooBlob.vue
583
- var le = /* @__PURE__ */ e(/* @__PURE__ */ m({
665
+ var fe = /* @__PURE__ */ e(/* @__PURE__ */ h({
584
666
  __name: "GooBlob",
585
667
  props: {
586
668
  color: {},
587
669
  colorResolver: { type: Function },
588
670
  config: {},
589
- seed: { default: "" }
590
- },
591
- emits: ["click"],
592
- setup(e, { expose: t, emit: n }) {
593
- let r = n, i = h(E, null), a = e.config ?? i;
594
- if (!a) 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.");
595
- let o = S("canvasRef"), s = S("wrapperRef"), c = L(), l = R(s), u = K(a, e.color + e.seed), m = x(e.color);
596
- function v(e) {
597
- if (!e.includes("var(")) return e;
598
- let t = s.value;
599
- if (typeof window > "u" || !t) return e;
600
- let n = t.style.color;
601
- t.style.color = e;
602
- let r = getComputedStyle(t).color;
603
- return t.style.color = n, r || e;
671
+ seed: { default: "" },
672
+ paused: {
673
+ type: Boolean,
674
+ default: !1
604
675
  }
605
- function b() {
606
- m.value = v(e.color);
676
+ },
677
+ emits: ["click", "update:paused"],
678
+ setup(e, { expose: n, emit: r }) {
679
+ let i = r, a = g(D, null), o = e.config ?? a;
680
+ 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.");
681
+ 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]);
682
+ function E() {
683
+ let t = c.value;
684
+ 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));
607
685
  }
608
- $({
609
- canvasRef: o,
610
- color: m,
611
- mood: c,
612
- pointer: l,
613
- satellites: u,
614
- config: a,
686
+ let O = de({
687
+ canvasRef: s,
688
+ color: y,
689
+ rimColor: x,
690
+ paletteStops: T,
691
+ mood: l,
692
+ pointer: u,
693
+ satellites: d,
694
+ config: o,
615
695
  colorResolver: e.colorResolver
616
- }), C(s, b, { immediate: !0 });
617
- let w = null;
618
- typeof document < "u" && (w = new MutationObserver(b), w.observe(document.documentElement, {
696
+ });
697
+ w(c, E, { immediate: !0 });
698
+ let k = null;
699
+ typeof document < "u" && (k = new MutationObserver(E), k.observe(document.documentElement, {
619
700
  attributes: !0,
620
701
  attributeFilter: ["class"]
621
- })), C(d(() => e.color), (t) => {
622
- b(), u.reseed(t + e.seed);
623
- }), _(() => {
624
- w?.disconnect(), w = null;
702
+ })), w(f(() => e.color), (t) => {
703
+ E(), d.reseed(t + e.seed);
704
+ }), w(() => e.paused, (e) => e ? O.pause() : O.resume(), { immediate: !0 }), v(() => {
705
+ k?.disconnect(), k = null;
625
706
  });
626
- function T() {
627
- u.nudge();
707
+ function A() {
708
+ d.nudge();
628
709
  }
629
- function D(e) {
630
- c.setMood(e);
710
+ function j(e) {
711
+ l.setMood(e);
631
712
  }
632
- function O() {
633
- l.click(a.clickImpulse);
713
+ function M() {
714
+ u.click(o.clickImpulse);
634
715
  }
635
- function k() {
636
- O(), r("click");
716
+ function N() {
717
+ M(), i("click");
637
718
  }
638
- return t({
639
- nudge: T,
640
- setMood: D,
641
- pulse: O,
642
- currentMood: c.currentMood
643
- }), (t, n) => (y(), f("div", {
719
+ return n({
720
+ nudge: A,
721
+ setMood: j,
722
+ pulse: M,
723
+ currentMood: l.currentMood,
724
+ pause: O.pause,
725
+ resume: O.resume
726
+ }), (t, n) => (b(), p("div", {
644
727
  ref_key: "wrapperRef",
645
- ref: s,
728
+ ref: c,
646
729
  class: "goo-blob-wrapper",
647
- style: g({ "--blob-color": e.color }),
648
- onClick: k
649
- }, [p("canvas", {
730
+ style: _({ "--blob-color": e.color }),
731
+ onClick: N
732
+ }, [m("canvas", {
650
733
  ref_key: "canvasRef",
651
- ref: o,
734
+ ref: s,
652
735
  class: "goo-blob-canvas",
653
736
  "aria-hidden": "true",
654
737
  "data-testid": "goo-blob-canvas"
655
738
  }, null, 512)], 4));
656
739
  }
657
- }), [["__scopeId", "data-v-b71203fd"]]);
740
+ }), [["__scopeId", "data-v-d2901aa9"]]);
658
741
  //#endregion
659
- export { T as BLOB_CONFIG_DEFAULTS, E as BLOB_CONFIG_KEY, le as GooBlob, L as useBlobMood, R as useBlobPointer, K as useBlobSatellites, $ as useMetaballRenderer };
742
+ 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 };