@mkbabb/glass-ui 2.1.0 → 3.1.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 (194) hide show
  1. package/dist/{CardFooter-Yi0xtLLd.js → CardFooter-CSGcJkqa.js} +1 -1
  2. package/dist/{CommandShortcut-_INFUMu6.js → CommandShortcut-DWT19a2Y.js} +3 -3
  3. package/dist/{ContextMenuSubContent-DCkweFW9.js → ContextMenuSubContent-gAFxJ-qi.js} +1 -1
  4. package/dist/{DataTable-Ce00dbHD.js → DataTable-R8-Zidms.js} +3 -3
  5. package/dist/{DialogContent-CmCijgX9.js → DialogContent-2fALDSvc.js} +3 -3
  6. package/dist/{DialogFooter-DRdaCok0.js → DialogFooter-ClrNEOVU.js} +2 -2
  7. package/dist/{DiscoGlyph-wRA02zAJ.js → DiscoGlyph-C3JfMnRV.js} +1 -1
  8. package/dist/{GlyphFace-BnPMUZ16.js → GlyphFace-BRS8vUb7.js} +1 -1
  9. package/dist/HoverPopover-CWFCfLx3.js +96 -0
  10. package/dist/{IconTooltip-ge_mBSWR.js → IconTooltip-BkaA7tZ2.js} +1 -1
  11. package/dist/{Input-CbakTe3B.js → Input-DDpFn568.js} +3 -5
  12. package/dist/Label-DJty89bp.js +36 -0
  13. package/dist/{MetricBadge-DRBB18Xq.js → MetricBadge-DmAihkXd.js} +1 -1
  14. package/dist/{Notification-DrI1DT2v.js → Notification-OqIpADml.js} +2 -2
  15. package/dist/NumberFieldContent-DTH9gb_N.js +141 -0
  16. package/dist/{PopoverContent-BCH4eYs8.js → PopoverContent-EiklFrna.js} +1 -1
  17. package/dist/{Progress-CCH-2UBR.js → Progress-FApA9fm_.js} +1 -1
  18. package/dist/{ScrollingText-7P8skg5W.js → ScrollingText-BFd0i2zJ.js} +2 -2
  19. package/dist/{SelectScrollDownButton-yu8EYUnu.js → SelectScrollDownButton-Dth8-wXQ.js} +2 -2
  20. package/dist/{Toaster-DY8_jtHv.js → Toaster-Bjlunvq4.js} +69 -58
  21. package/dist/UnderlineTabs-DAWMLmJG.js +37 -0
  22. package/dist/animated-digit.js +2 -2
  23. package/dist/api/index.d.ts +2 -0
  24. package/dist/api.js +1 -1
  25. package/dist/aurora.js +103 -90
  26. package/dist/badge.js +1 -1
  27. package/dist/{button-BlOW34DT.js → button-C0aHmBbt.js} +2 -0
  28. package/dist/button.js +1 -1
  29. package/dist/card.js +1 -1
  30. package/dist/carousel.js +1 -1
  31. package/dist/collapsible.js +1 -1
  32. package/dist/command.js +1 -1
  33. package/dist/components/custom/aurora/composables/runtime.d.ts +24 -1
  34. package/dist/components/custom/dialog-native/GlassDialogNative.vue.d.ts +57 -0
  35. package/dist/components/custom/dialog-native/index.d.ts +1 -0
  36. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +20 -10
  37. package/dist/components/custom/hover-popover/HoverPopover.vue.d.ts +26 -4
  38. package/dist/components/custom/labeled-field/LabeledField.vue.d.ts +16 -2
  39. package/dist/components/custom/labeled-field/LabeledInput.vue.d.ts +17 -1
  40. package/dist/components/custom/labeled-field/LabeledSelect.vue.d.ts +2 -0
  41. package/dist/components/custom/labeled-field/LabeledSlider.vue.d.ts +2 -0
  42. package/dist/components/custom/labeled-field/LabeledSwitch.vue.d.ts +2 -0
  43. package/dist/components/custom/toggle-chip/ToggleChip.vue.d.ts +6 -4
  44. package/dist/components/ui/input/Input.vue.d.ts +10 -7
  45. package/dist/components/ui/label/Label.vue.d.ts +8 -0
  46. package/dist/components/ui/textarea/Textarea.vue.d.ts +45 -8
  47. package/dist/components/ui/toast/Toaster.vue.d.ts +7 -1
  48. package/dist/components/ui/toast/index.d.ts +1 -0
  49. package/dist/composables/dark/index.d.ts +1 -0
  50. package/dist/composables/dom/index.d.ts +2 -0
  51. package/dist/composables/dom/useIdleReady.d.ts +63 -0
  52. package/dist/composables/dom/useUserInvalidAria.d.ts +32 -0
  53. package/dist/composables/index.d.ts +1 -0
  54. package/dist/composables/motion/core/index.d.ts +8 -0
  55. package/dist/composables/motion/index.d.ts +0 -7
  56. package/dist/composables/motion/supportsCssTimeline.d.ts +8 -0
  57. package/dist/composables/motion/useRAFLoop.d.ts +7 -0
  58. package/dist/composables/motion/useScrollProgress.d.ts +6 -2
  59. package/dist/composables/motion/useStaggerReveal.d.ts +6 -0
  60. package/dist/composables/motion/useViewTransition.d.ts +31 -0
  61. package/dist/composables/motion/useYieldToMain.d.ts +29 -0
  62. package/dist/configurator.js +1 -1
  63. package/dist/confirm-dialog.js +2 -2
  64. package/dist/constants-DwBwnG8N.js +13 -0
  65. package/dist/context-menu.js +2 -2
  66. package/dist/controls.js +2 -2
  67. package/dist/dark.d.ts +1 -1
  68. package/dist/dark.js +13 -2
  69. package/dist/data-table.js +1 -1
  70. package/dist/dialog.js +2 -2
  71. package/dist/disco-glyph.js +1 -1
  72. package/dist/dock.js +195 -176
  73. package/dist/dom.js +5 -4
  74. package/dist/{dropdown-menu-2K-SGkZU.js → dropdown-menu-BvRUamNs.js} +2 -2
  75. package/dist/dropdown-menu.js +1 -1
  76. package/dist/expandable-container.js +3 -3
  77. package/dist/forms.d.ts +1 -0
  78. package/dist/forms.js +47 -42
  79. package/dist/glass-carousel.js +1 -1
  80. package/dist/glass-panel.js +2 -2
  81. package/dist/glass-ui.css +1 -1
  82. package/dist/glass-ui.js +156 -275
  83. package/dist/glyph-face.js +2 -2
  84. package/dist/header-ribbon.js +1 -1
  85. package/dist/hover-card.js +1 -1
  86. package/dist/hover-popover.js +1 -1
  87. package/dist/icon-tooltip.js +1 -1
  88. package/dist/index.d.ts +1 -0
  89. package/dist/instrument-chassis.js +1 -1
  90. package/dist/instrument-rail.js +1 -1
  91. package/dist/keyboard.js +1 -1
  92. package/dist/label.js +1 -1
  93. package/dist/labeled-field.js +96 -57
  94. package/dist/metric-badge.js +1 -1
  95. package/dist/metric-stack.js +1 -1
  96. package/dist/motion-core.d.ts +1 -0
  97. package/dist/motion-core.js +229 -0
  98. package/dist/motion.js +26 -228
  99. package/dist/notification.js +1 -1
  100. package/dist/number-field.d.ts +1 -0
  101. package/dist/number-field.js +2 -0
  102. package/dist/paper-backdrop.js +1 -1
  103. package/dist/popover.js +1 -1
  104. package/dist/progress.js +1 -1
  105. package/dist/pulse.js +1 -1
  106. package/dist/reactive.js +2 -2
  107. package/dist/responsive-tabs.js +3 -3
  108. package/dist/scrolling-text.js +1 -1
  109. package/dist/search.js +6 -6
  110. package/dist/select.js +3 -3
  111. package/dist/separator.js +1 -1
  112. package/dist/{sheet-CLVkb3AO.js → sheet-CukNDezz.js} +53 -53
  113. package/dist/sheet.js +1 -1
  114. package/dist/{slider-BQaLYFLh.js → slider-DJvHkTRe.js} +3 -3
  115. package/dist/slider.js +1 -1
  116. package/dist/sortable-list.js +2 -2
  117. package/dist/styles/animations.css +77 -0
  118. package/dist/styles/cards.css +6 -2
  119. package/dist/styles/dock.css +109 -109
  120. package/dist/styles/drawer.css +2 -2
  121. package/dist/styles/glass.css +89 -6
  122. package/dist/styles/index.css +10 -1
  123. package/dist/styles/instrument-chassis.css +28 -1
  124. package/dist/styles/scroll-driven.css +72 -0
  125. package/dist/styles/theme.css +6 -0
  126. package/dist/styles/tokens.css +345 -289
  127. package/dist/styles/typography.css +65 -131
  128. package/dist/styles/utilities.css +199 -81
  129. package/dist/styles/view-transition.css +62 -0
  130. package/dist/switch.d.ts +1 -0
  131. package/dist/switch.js +2 -0
  132. package/dist/tabs.js +40 -36
  133. package/dist/timeline.js +2 -2
  134. package/dist/toast.js +1 -1
  135. package/dist/toggle-group.js +1 -1
  136. package/dist/tooltip.js +1 -1
  137. package/dist/typewriter.js +1 -1
  138. package/dist/{useAnimatedNumber-DcvTR9B4.js → useAnimatedNumber-DKQYVB7s.js} +9 -20
  139. package/dist/{useConfiguratorState-BlaevW0S.js → useConfiguratorState-BR5vUDL8.js} +5 -5
  140. package/dist/{useBreakpoint-BHlX-MhR.js → useIdleReady-Cmkhm03v.js} +30 -2
  141. package/dist/{useTouchGate-BhhEMlwJ.js → useTouchGate-D9Zvrzyc.js} +1 -1
  142. package/dist/useUserInvalidAria-DVu1eTXG.js +29 -0
  143. package/dist/useViewTransition-DYIK6Gzb.js +16 -0
  144. package/dist/utils/index.d.ts +1 -0
  145. package/dist/utils/moveBefore.d.ts +15 -0
  146. package/package.json +27 -6
  147. package/src/styles/animations.css +77 -0
  148. package/src/styles/cards.css +6 -2
  149. package/src/styles/dock.css +109 -109
  150. package/src/styles/drawer.css +2 -2
  151. package/src/styles/glass.css +89 -6
  152. package/src/styles/index.css +10 -1
  153. package/src/styles/instrument-chassis.css +28 -1
  154. package/src/styles/scroll-driven.css +72 -0
  155. package/src/styles/theme.css +6 -0
  156. package/src/styles/tokens.css +345 -289
  157. package/src/styles/typography.css +65 -131
  158. package/src/styles/utilities.css +199 -81
  159. package/src/styles/view-transition.css +62 -0
  160. package/dist/HoverPopover-Btv4RQfv.js +0 -80
  161. package/dist/Label-C8QMJSsf.js +0 -32
  162. package/dist/UnderlineTabs-BtrUcXn-.js +0 -64
  163. package/dist/composables/motion/useSpringOrchestrator.d.ts +0 -15
  164. /package/dist/{CollapsibleContent-DHRuXE3P.js → CollapsibleContent-CVMOcYlV.js} +0 -0
  165. /package/dist/{ContextMenuContent-CvXfU5qz.js → ContextMenuContent-otjFIu8v.js} +0 -0
  166. /package/dist/{HoverCardContent-4nN5-5bz.js → HoverCardContent-DaGrgJBO.js} +0 -0
  167. /package/dist/{InstrumentChassis-DOaVYyWq.js → InstrumentChassis-CnHTMxds.js} +0 -0
  168. /package/dist/{InstrumentRail-jHDqXj70.js → InstrumentRail-C6dEbi8E.js} +0 -0
  169. /package/dist/{ModalOverlay-DKLVY-cj.js → ModalOverlay-iWiAgbYH.js} +0 -0
  170. /package/dist/{PaperBackdrop-Bc2drCqJ.js → PaperBackdrop-CeZ-w0R0.js} +0 -0
  171. /package/dist/{SelectGroup-O69GTQ77.js → SelectGroup-DdR4tdDY.js} +0 -0
  172. /package/dist/{SelectSeparator-GTHxKO0a.js → SelectSeparator-CXm_hlqA.js} +0 -0
  173. /package/dist/{Separator-_NCypg_C.js → Separator-D8AUMhxY.js} +0 -0
  174. /package/dist/{Switch-CL0uxu8F.js → Switch-Cr1t_F_U.js} +0 -0
  175. /package/dist/{ToggleGroupItem-BYG_8M9M.js → ToggleGroupItem-OesUouE7.js} +0 -0
  176. /package/dist/{TooltipProvider-C5QLSPto.js → TooltipProvider-DE78vbEP.js} +0 -0
  177. /package/dist/{_plugin-vue_export-helper-n-_DRHWS.js → _plugin-vue_export-helper-Dq1MygBL.js} +0 -0
  178. /package/dist/{badge-BbxVKZfw.js → badge-x46my_Fo.js} +0 -0
  179. /package/dist/composables/{motion → dark}/installDarkModeSync.d.ts +0 -0
  180. /package/dist/{dockContext-BDGSrwsV.js → dockContext-D5NZCWJs.js} +0 -0
  181. /package/dist/{keys-DVkcUktU.js → keys-CaTQS-vx.js} +0 -0
  182. /package/dist/{menuItemVariants-B2nDL7zH.js → menuItemVariants-BsbGNq9C.js} +0 -0
  183. /package/dist/{presets-BMzCDrmR.js → presets-a-D93K1S.js} +0 -0
  184. /package/dist/{search-ocd8tmL9.js → search-DBAiUABx.js} +0 -0
  185. /package/dist/{useGlassRenderer-DMDdMH55.js → useGlassRenderer-Ds-nmrGz.js} +0 -0
  186. /package/dist/{useGlobalDark-PMiP5Jku.js → useGlobalDark-B0WvLJE3.js} +0 -0
  187. /package/dist/{useIntersectionPause-CXYfYg_C.js → useIntersectionPause-IY2CwPQb.js} +0 -0
  188. /package/dist/{useInterval-COlTCeVa.js → useInterval-DVgGUf_y.js} +0 -0
  189. /package/dist/{useKeyboardShortcuts-B1ev1YEC.js → useKeyboardShortcuts-Dpw_RUcB.js} +0 -0
  190. /package/dist/{useResizeObserver-F4aRR4Cj.js → useResizeObserver-Cg9npuM3.js} +0 -0
  191. /package/dist/{useSortable-Ck0rBJ4g.js → useSortable-Cq2Y1JLO.js} +0 -0
  192. /package/dist/{useSpringMount-BTRBNzXP.js → useSpringMount-Cfk1XK1R.js} +0 -0
  193. /package/dist/{useTimer-lp5NlH4w.js → useTimer-NAaj9zNq.js} +0 -0
  194. /package/dist/{x-cdWAmO-q.js → x-q7pJa83X.js} +0 -0
package/dist/aurora.js CHANGED
@@ -1,6 +1,6 @@
1
- import { t as e } from "./_plugin-vue_export-helper-n-_DRHWS.js";
2
- import { n as t, r as n, t as r } from "./presets-BMzCDrmR.js";
3
- import { t as i } from "./useIntersectionPause-CXYfYg_C.js";
1
+ import { t as e } from "./_plugin-vue_export-helper-Dq1MygBL.js";
2
+ import { n as t, r as n, t as r } from "./presets-a-D93K1S.js";
3
+ import { t as i } from "./useIntersectionPause-IY2CwPQb.js";
4
4
  import { computed as a, createElementBlock as o, createElementVNode as s, defineComponent as c, normalizeClass as l, normalizeStyle as u, onBeforeUnmount as d, onMounted as f, openBlock as p, readonly as m, ref as h, unref as g, watch as _ } from "vue";
5
5
  //#region src/components/custom/aurora/shaders/aurora.vert.ts
6
6
  var v = "#version 300 es\nin vec2 aPos;\nout vec2 vUv;\nvoid main() {\n vUv = aPos * 0.5 + 0.5;\n gl_Position = vec4(aPos, 0.0, 1.0);\n}", y = "#version 300 es\nprecision highp float;\n\nin vec2 vUv;\nout vec4 fragColor;\n\n#define MAX_NUCLEI 6\n#define MAX_STOPS 8\n\n// ── Uniforms ───────────────────────────────────────────────────────────────\nuniform float uTime;\n\n// Palette baked CPU-side to linear-sRGB\nuniform vec3 uPalette[MAX_STOPS];\nuniform int uStopCount;\n\n// Nuclei (parallel arrays)\nuniform int uNucleiCount;\nuniform vec2 uNucleiPos[MAX_NUCLEI];\nuniform float uNucleiRadius[MAX_NUCLEI];\nuniform float uNucleiPaletteBias[MAX_NUCLEI];\nuniform float uNucleiValueBias[MAX_NUCLEI];\nuniform float uNucleiDriftRadius[MAX_NUCLEI];\nuniform float uNucleiDriftPhase[MAX_NUCLEI];\n// Anisotropy: per-nucleus elongation (1.0 = isotropic) and major-axis angle (radians).\n// Defaults (1.0 / 0.0) reduce to the original circular Gaussian.\nuniform float uNucleiElong[MAX_NUCLEI];\nuniform float uNucleiAngle[MAX_NUCLEI];\nuniform float uSoftmaxBeta;\nuniform float uValueVariance;\n\n// Warp\nuniform float uWarpAmount;\nuniform float uWarpScale;\nuniform float uWarpDrift;\nuniform int uWarpMode; // 0=fbm 1=cellular 2=hybrid\nuniform int uNoiseOctaves;\n\n// Medium\n// 0 smooth, 1 pastel, 2 watercolor, 3 oil\nuniform int uMedium;\nuniform int uFlowPattern; // 0 none, 1 radial, 2 swirl, 3 diagonal, 4 multi\nuniform vec2 uFlowFocal;\nuniform float uFlowAngle;\nuniform float uFlowCurl;\nuniform vec2 uCursor; // in 0..1 screen space (matches pN)\nuniform float uCursorStrength; // 0..1 attraction amount\nuniform float uCursorRadius; // radius of influence (0.05..0.5)\nuniform float uStrokeAmount;\nuniform float uStrokeScale;\nuniform float uStrokeAnisotropy;\nuniform int uStrokeLayers; // 1 or 2 (crosshatch)\nuniform int uStrokeMode; // 0 oil (modern gestural), 1 palette-knife, 2 crayon/oil-pastel, 3 modern-chunky\nuniform float uWetEdge;\nuniform float uGranulation;\nuniform float uImpasto;\nuniform float uBrokenColor;\nuniform float uCanvasGrain;\n\n// Motion\nuniform float uNucleiDrift;\nuniform float uPaletteDrift;\nuniform float uBreathDepth;\nuniform float uBreathPeriod;\n\n// Output\nuniform float uSaturation;\nuniform float uPaperGrain;\nuniform float uAlpha;\n\n// ── Noise ──────────────────────────────────────────────────────────────────\nfloat hash21(vec2 p) {\n p = fract(p * vec2(123.34, 456.21));\n p += dot(p, p + 45.32);\n return fract(p.x * p.y);\n}\n\nvec2 hash22(vec2 p) {\n p = vec2(dot(p, vec2(127.1, 311.7)),\n dot(p, vec2(269.5, 183.3)));\n return fract(sin(p) * 43758.5453);\n}\n\nfloat vnoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\n\nfloat fbm(vec2 p) {\n float v = 0.0;\n float a = 0.5;\n mat2 r = mat2(0.8, 0.6, -0.6, 0.8);\n for (int i = 0; i < 5; i++) {\n if (i >= uNoiseOctaves) break;\n v += a * vnoise(p);\n p = r * p * 2.02;\n a *= 0.5;\n }\n return v;\n}\n\n// Cellular / Worley f1\nfloat cellular(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n float m = 1e9;\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 g = vec2(float(x), float(y));\n vec2 o = hash22(i + g);\n vec2 r = g + o - f;\n m = min(m, dot(r, r));\n }\n }\n return sqrt(m);\n}\n\n// ── Warp ──────────────────────────────────────────────────────────────────\nvec2 domainWarp(vec2 p, float t) {\n // Quilez canonical double warp\n vec2 q = vec2(fbm(p * uWarpScale + vec2(0.0, 0.0) + t * uWarpDrift),\n fbm(p * uWarpScale + vec2(5.2, 1.3) + t * uWarpDrift));\n vec2 r = vec2(fbm(p * uWarpScale + 4.0 * q + vec2(1.7, 9.2)),\n fbm(p * uWarpScale + 4.0 * q + vec2(8.3, 2.8)));\n\n vec2 warp = r;\n if (uWarpMode == 1) {\n // cellular — chunky territories (MEADOW block-like)\n float c1 = cellular(p * uWarpScale * 1.5 + vec2(t * uWarpDrift * 2.0, 0.0));\n float c2 = cellular(p * uWarpScale * 1.5 + vec2(11.0, 7.0 + t * uWarpDrift * 2.0));\n warp = vec2(c1, c2);\n } else if (uWarpMode == 2) {\n // hybrid — fbm + cellular averaged\n float c1 = cellular(p * uWarpScale * 1.2);\n float c2 = cellular(p * uWarpScale * 1.2 + vec2(11.0, 7.0));\n warp = mix(r, vec2(c1, c2), 0.5);\n }\n vec2 warped = p + uWarpAmount * warp;\n\n // Cursor swirl — rotate p around uCursor with radial falloff.\n // This warps the underlying color field so the bands sweep around the pointer.\n if (uCursorStrength > 0.001) {\n vec2 toP = p - uCursor;\n float d = length(toP);\n float r = max(uCursorRadius, 0.01);\n // Smooth falloff; strong near cursor, zero beyond ~1.5× radius.\n float w = exp(-(d * d) / (r * r * 0.45));\n // Max rotation ~120° at cursor center, scaled by strength\n float ang = w * uCursorStrength * 2.1;\n float ca = cos(ang), sa = sin(ang);\n vec2 rotated = vec2(ca * toP.x - sa * toP.y, sa * toP.x + ca * toP.y) + uCursor;\n // Also pinch slightly toward the cursor (gravity) — adds depth to swirl\n float pinch = w * uCursorStrength * 0.08;\n rotated = mix(rotated, uCursor, pinch);\n // Blend original warped position with cursor-rotated version\n warped = mix(warped, rotated + uWarpAmount * warp * 0.7, w * uCursorStrength);\n }\n\n return warped;\n}\n\n// ── Palette LUT ───────────────────────────────────────────────────────────\nvec3 samplePalette(float id) {\n id = clamp(id, 0.0, 1.0);\n float scaled = id * float(uStopCount - 1);\n int i0 = int(floor(scaled));\n int i1 = min(i0 + 1, uStopCount - 1);\n float t = fract(scaled);\n t = smoothstep(0.0, 1.0, t);\n return mix(uPalette[i0], uPalette[i1], t);\n}\n\n// ── Nuclei field ──────────────────────────────────────────────────────────\nvoid nucleiField(vec2 p, float t, out float paletteId, out float valueMod) {\n float accumBias = 0.0;\n float accumValue = 0.0;\n float accumW = 0.0;\n for (int i = 0; i < MAX_NUCLEI; i++) {\n if (i >= uNucleiCount) break;\n vec2 posI = uNucleiPos[i]\n + uNucleiDriftRadius[i] * vec2(\n cos(t * uNucleiDrift + uNucleiDriftPhase[i]),\n sin(t * uNucleiDrift + uNucleiDriftPhase[i] * 1.13)\n );\n vec2 diff = p - posI;\n // Anisotropic Gaussian: rotate diff into the nucleus's local frame\n // (major axis along uNucleiAngle), then scale the major-axis component by\n // 1/elongation so the squared distance describes an ellipse. Defaults\n // 1.0/0.0 reduce to the isotropic dot(diff, diff).\n float ca = cos(uNucleiAngle[i]);\n float sa = sin(uNucleiAngle[i]);\n vec2 local = vec2( ca * diff.x + sa * diff.y,\n -sa * diff.x + ca * diff.y);\n float along = local.x / max(uNucleiElong[i], 0.01);\n float across = local.y;\n float d2 = along * along + across * across;\n float r = max(uNucleiRadius[i], 0.01);\n float w = exp(-uSoftmaxBeta * d2 / (r * r));\n accumBias += w * uNucleiPaletteBias[i];\n accumValue += w * uNucleiValueBias[i];\n accumW += w;\n }\n paletteId = accumBias / max(accumW, 1e-4);\n valueMod = accumValue / max(accumW, 1e-4);\n\n // Palette drift — subtle global paletteId shift\n paletteId += 0.04 * sin(t * uPaletteDrift * 6.2831) * uPaletteDrift * 20.0;\n paletteId = clamp(paletteId, 0.0, 1.0);\n}\n\n// ── Flow field ────────────────────────────────────────────────────────────\nvec2 flowField(vec2 p, float t) {\n vec2 dir = vec2(1.0, 0.0);\n if (uFlowPattern == 1) {\n // radial\n dir = normalize(p - uFlowFocal + 1e-4);\n } else if (uFlowPattern == 2) {\n // swirl — tangent to radial\n vec2 rad = normalize(p - uFlowFocal + 1e-4);\n dir = vec2(-rad.y, rad.x);\n } else if (uFlowPattern == 3) {\n // diagonal\n float a = radians(uFlowAngle);\n dir = vec2(cos(a), sin(a));\n } else if (uFlowPattern == 4) {\n // multi — curl-noise driven\n float n = fbm(p * 2.0 + t * 0.02);\n float a = n * 6.2831;\n dir = vec2(cos(a), sin(a));\n }\n // curl — perturb by noise. Radial gets much less curl so rays stay clean.\n if (uFlowCurl > 0.0) {\n float n = fbm(p * 3.0) - 0.5;\n float curlAmt = uFlowCurl;\n if (uFlowPattern == 1) curlAmt *= 0.25; // radial: preserve ray clarity\n if (uFlowPattern == 2) curlAmt *= 0.55; // swirl: allow moderate curl\n float a = atan(dir.y, dir.x) + n * 3.14159 * curlAmt;\n dir = vec2(cos(a), sin(a));\n }\n // cursor influence — swirl around the cursor position\n if (uCursorStrength > 0.001) {\n vec2 toCur = uCursor - p;\n float d = length(toCur);\n float r = max(uCursorRadius, 0.01);\n float w = exp(-(d * d) / (r * r * 0.5));\n // swirl tangent\n vec2 tangent = vec2(-toCur.y, toCur.x) / max(d, 1e-4);\n float a0 = atan(dir.y, dir.x);\n float a1 = atan(tangent.y, tangent.x);\n // blend angle\n float da = a1 - a0;\n da = atan(sin(da), cos(da)); // wrap to [-pi, pi]\n float a = a0 + da * w * uCursorStrength;\n dir = vec2(cos(a), sin(a));\n }\n return dir;\n}\n\n// ── Color utils ───────────────────────────────────────────────────────────\nconst vec3 W_LUMA = vec3(0.2126, 0.7152, 0.0722);\n\nvec3 hueShift(vec3 c, float degrees) {\n float a = radians(degrees);\n float co = cos(a), si = sin(a);\n mat3 m = mat3(\n 0.299 + 0.701 * co + 0.168 * si,\n 0.587 - 0.587 * co + 0.330 * si,\n 0.114 - 0.114 * co - 0.497 * si,\n\n 0.299 - 0.299 * co - 0.328 * si,\n 0.587 + 0.413 * co + 0.035 * si,\n 0.114 - 0.114 * co + 0.292 * si,\n\n 0.299 - 0.300 * co + 1.250 * si,\n 0.587 - 0.588 * co - 1.050 * si,\n 0.114 + 0.886 * co - 0.203 * si\n );\n return m * c;\n}\n\nvec3 brokenColorJitter(vec3 c, float hueSeed, float valueSeed, float strength) {\n float amt = clamp(uBrokenColor * strength, 0.0, 1.0);\n if (amt <= 0.001) return c;\n float hueDeg = (hueSeed - 0.5) * 32.0 * amt;\n float valueMul = 1.0 + (valueSeed - 0.5) * 0.28 * amt;\n return max(hueShift(c, hueDeg) * valueMul, vec3(0.0));\n}\n\nvec3 saturate3(vec3 c, float amt) {\n float l = dot(c, W_LUMA);\n return mix(vec3(l), c, amt);\n}\n\n// ACES approximation\nvec3 aces(vec3 x) {\n float a = 2.51;\n float b = 0.03;\n float c = 2.43;\n float d = 0.59;\n float e = 0.14;\n return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0.0, 1.0);\n}\n\n// ── Medium overlays ───────────────────────────────────────────────────────\n\n// A quick re-computation of base color for edge-mask sampling\nvec3 sampleBase(vec2 p, float t) {\n vec2 pw = domainWarp(p, t);\n float id; float vm;\n nucleiField(pw, t, id, vm);\n vec3 c = samplePalette(id);\n c *= 1.0 + uValueVariance * vm;\n return c;\n}\n\nvec3 mediumWatercolor(vec3 col, vec2 p, float t) {\n // Wet-edge cauliflowers via luma-gradient magnitude\n float eps = 0.004;\n vec3 cx1 = sampleBase(p + vec2(eps, 0.0), t);\n vec3 cx2 = sampleBase(p - vec2(eps, 0.0), t);\n vec3 cy1 = sampleBase(p + vec2(0.0, eps), t);\n vec3 cy2 = sampleBase(p - vec2(0.0, eps), t);\n float gx = dot(cx1 - cx2, W_LUMA);\n float gy = dot(cy1 - cy2, W_LUMA);\n float edge = sqrt(gx * gx + gy * gy) / (2.0 * eps);\n float mask = smoothstep(0.0, 2.5, edge);\n col *= mix(1.0, 0.78, mask * uWetEdge);\n\n // Granulation — pigment settles in paper tooth\n float paper = 0.5 * vnoise(p * 160.0) + 0.5 * vnoise(p * 360.0);\n float pigLoad = 1.0 - dot(col, W_LUMA);\n col *= 1.0 - uGranulation * pigLoad * (paper - 0.5);\n\n // Wash banding — faint horizontal wet gradient\n float band = fbm(vec2(p.x * 1.5, p.y * 0.4));\n col *= 1.0 + 0.04 * (band - 0.5);\n return col;\n}\n\nvec3 mediumPastel(vec3 col, vec2 p, float t) {\n vec2 flow = flowField(p, t);\n vec2 perp = vec2(-flow.y, flow.x);\n float along = dot(p, flow) * uStrokeScale;\n float across = dot(p, perp) * uStrokeScale;\n across += 0.03 * (vnoise(p * 260.0) - 0.5);\n\n float aniso = mix(1.0, 0.18, uStrokeAnisotropy);\n float stroke = fbm(vec2(along * aniso, across));\n col *= mix(1.0, 0.82 + 0.32 * stroke, uStrokeAmount);\n\n // Pastel tooth — tiny high-frequency grain\n float tooth = vnoise(p * 800.0);\n col *= 1.0 - 0.08 * uStrokeAmount * (tooth - 0.5);\n return col;\n}\n\n// ── Curved swept brushstroke primitive ────────────────────────────────────\n// A stroke is a curved spine from A to B with quadratic bulge K (sideways offset\n// at midpoint). Width varies along length via a shape profile. Edge is ragged\n// (bristle-modulated), ends are rounded blobs, inside has streak modulation.\n//\n// For pixel p, we invert an approximate projection onto the curved spine:\n// 1) project p onto straight AB axis -> along0, cross0\n// 2) at parameter along0, spine offset = 4·K·along0·(1-along0) perpendicular\n// 3) cross = cross0 - spineOffset, refine along one iteration\n// Coverage blends paint atop col based on per-stroke color sampled from the\n// underlying base at spine midpoint — so overlapping strokes from different\n// palette regions meet at hard, ragged demarcations.\n\nstruct StrokeHit {\n float coverage; // 0..1\n vec3 color;\n float alongT; // 0..1 along spine, for internal modulation\n float crossN; // cross distance / current half-width, signed\n float edgeN; // distance to edge in half-widths (0 = at edge, 1 = at spine)\n};\n\nStrokeHit noHit() { return StrokeHit(0.0, vec3(0.0), 0.0, 0.0, 0.0); }\n\nvec2 rotateDir(vec2 dir, float angle) {\n float ca = cos(angle), sa = sin(angle);\n return vec2(dir.x * ca - dir.y * sa, dir.x * sa + dir.y * ca);\n}\n\nvec2 safeDir(vec2 dir) {\n float len = length(dir);\n return len > 1e-4 ? dir / len : vec2(1.0, 0.0);\n}\n\n// Shape profile along the stroke. type:\n// 0 tapered — thin-fat-thin (classic brush)\n// 1 load-drag — fat start, tapers to a point\n// 2 dab — ellipse-like, round center\n// 3 even — near-constant, slight end taper\nfloat strokeShape(float t, int type) {\n t = clamp(t, 0.0, 1.0);\n if (type == 1) {\n // loaded at t=0, tapering\n return pow(1.0 - t, 0.55) * smoothstep(0.0, 0.08, t);\n } else if (type == 2) {\n // dab / blob\n float d = t - 0.5;\n return exp(-d * d * 12.0);\n } else if (type == 3) {\n // mostly even, slight end softening\n return smoothstep(0.0, 0.08, t) * smoothstep(1.0, 0.92, t) * 0.95 + 0.05;\n }\n // 0 tapered\n return smoothstep(0.0, 0.22, t) * smoothstep(1.0, 0.78, t);\n}\n\n// A single curved stroke.\n// a, b — endpoints\n// halfW — base half-width (world units)\n// bulge — signed perpendicular midpoint offset, in world units\n// shapeType — 0..3\n// bristleFreq — spatial frequency of edge raggedness\n// bristleAmp — 0..0.5 fraction of halfW chewed away at edge extrema\n// streakSeed — uniqueness seed for internal streaks\n// colAtMid — pre-sampled color at midpoint\nStrokeHit curvedStroke(vec2 p, vec2 a, vec2 b, float halfW,\n float bulge, int shapeType,\n float bristleFreq, float bristleAmp,\n float streakSeed, vec3 colAtMid) {\n vec2 ab = b - a;\n float L = length(ab);\n if (L < 1e-5) return noHit();\n vec2 tang = ab / L;\n vec2 norm = vec2(-tang.y, tang.x);\n\n vec2 rel = p - a;\n float along0 = dot(rel, tang) / L; // straight projection 0..1 along AB\n float cross0 = dot(rel, norm); // signed cross\n\n // Spine sideways offset due to bulge (parabolic)\n float bend = 4.0 * bulge * along0 * (1.0 - along0);\n float cross1 = cross0 - bend;\n\n // One refinement step: as the spine bends, the closest-point along shifts.\n // Spine tangent differs from straight tangent; first-order correction:\n float dBend = 4.0 * bulge * (1.0 - 2.0 * along0); // d(bend)/d(along)\n float along1 = along0 + (cross1 * dBend) / (L * (1.0 + dBend * dBend / (L * L)));\n\n // Bristle-ragged edge: half-width gets chewed by 1D noise along the spine\n float edgeNoise = fbm(vec2(along1 * bristleFreq, streakSeed * 7.3)) - 0.5;\n float edgeNoise2 = fbm(vec2(along1 * bristleFreq * 2.3, streakSeed * 3.1 + 17.0)) - 0.5;\n float edgeMod = 1.0 - bristleAmp * (0.6 + 0.4 * edgeNoise) * (0.5 + edgeNoise2);\n\n // Width profile along the stroke\n float shape = strokeShape(along1, shapeType);\n float halfWNow = halfW * shape * edgeMod;\n\n // Inside-segment coverage\n float cov = 0.0;\n if (along1 >= 0.0 && along1 <= 1.0 && halfWNow > 1e-6) {\n float cn = abs(cross1) / halfWNow;\n // razor-hard edge with tiny aa\n cov = 1.0 - smoothstep(0.88, 1.02, cn);\n }\n\n // End-cap blobs (rounded tips, not perpendicular cuts)\n float capA = 0.0, capB = 0.0;\n {\n vec2 capCenterA = a + norm * (bulge * 0.0); // at a\n vec2 capCenterB = a + tang * L + norm * bend * 0.0 + norm * 0.0; // at b; bend is 0 at endpoints\n capCenterB = b;\n float endShapeA = strokeShape(0.02, shapeType);\n float endShapeB = strokeShape(0.98, shapeType);\n float rA = halfW * endShapeA * (0.9 + 0.2 * fbm(vec2(streakSeed * 13.0)));\n float rB = halfW * endShapeB * (0.9 + 0.2 * fbm(vec2(streakSeed * 19.0 + 5.0)));\n float dA = length(p - capCenterA);\n float dB = length(p - capCenterB);\n capA = 1.0 - smoothstep(rA * 0.85, rA * 1.05, dA);\n capB = 1.0 - smoothstep(rB * 0.85, rB * 1.05, dB);\n // Only apply caps if we're BEYOND the segment; otherwise the segment wins.\n capA *= (along1 < 0.05) ? 1.0 : 0.0;\n capB *= (along1 > 0.95) ? 1.0 : 0.0;\n }\n\n float coverage = max(cov, max(capA, capB));\n if (coverage < 0.002) return noHit();\n\n // Edge distance (for impasto later): 0 at edge, 1 at spine\n float edgeDist = halfWNow > 1e-6 ? clamp(1.0 - abs(cross1) / halfWNow, 0.0, 1.0) : 0.0;\n\n return StrokeHit(\n coverage,\n colAtMid,\n clamp(along1, 0.0, 1.0),\n halfWNow > 1e-6 ? cross1 / halfWNow : 0.0,\n edgeDist\n );\n}\n\n// Composite stroke over col with internal streaking + impasto edge highlight.\n// streakAmp — 0..0.2 how much internal streaks darken/lighten\n// impastoAmp — 0..1 edge catch-light strength\n// hardness — 0..1 how crisp the compositing transition is (1 = razor, 0 = creamy)\nvoid paintOver(inout vec3 col, StrokeHit s, float streakFreq, float streakAmp,\n float impastoAmp, float hardness, float streakSeed) {\n if (s.coverage < 0.002) return;\n float strokeOpacity = clamp(uStrokeAmount, 0.0, 1.0);\n if (strokeOpacity <= 0.001) return;\n vec3 c = s.color;\n\n // Internal streaks — fbm along spine, modulated by cross position. Gives\n // the loaded-brush look: some bristles carry more pigment than others.\n float streakA = fbm(vec2(s.alongT * streakFreq, s.crossN * 2.7 + streakSeed));\n float streakB = fbm(vec2(s.alongT * streakFreq * 0.6 + streakSeed * 3.7, s.crossN * 4.1));\n float streak = 0.6 * (streakA - 0.5) + 0.4 * (streakB - 0.5);\n c *= 1.0 + streak * streakAmp * 2.0;\n\n // Subtle value variance across width (hollow-center catch-light)\n float crossShade = smoothstep(0.0, 0.4, s.edgeN) * (1.0 - smoothstep(0.65, 1.0, s.edgeN));\n c *= 1.0 + crossShade * 0.05;\n\n // Impasto edge highlight — bright rim on one side of the stroke\n float rim = smoothstep(0.85, 1.0, 1.0 - s.edgeN) * step(0.0, s.crossN);\n c += impastoAmp * rim * vec3(0.18, 0.15, 0.11);\n // Shadow on the other side (darker, cooler)\n float shadow = smoothstep(0.85, 1.0, 1.0 - s.edgeN) * step(0.0, -s.crossN);\n c -= impastoAmp * shadow * 0.25 * vec3(0.10, 0.09, 0.07);\n\n float softLimit = mix(0.35, 0.98, hardness);\n float alpha = smoothstep(0.0, 1.0 - softLimit, s.coverage) * strokeOpacity;\n col = mix(col, c, alpha);\n}\n\n// Best-of-9-neighbor placement: sample 3x3 surrounding cells and take the\n// stroke that covers this pixel most. Breaks the grid by per-cell jitter and\n// sparse density via noise thresholding.\nStrokeHit bestOil(vec2 p, float cellSize, float lenMul, float halfWMul,\n float jitterAmt, float density, int shapeType,\n float bristleAmp, vec2 flow, float t, float seed) {\n vec2 cell = floor(p / cellSize);\n\n StrokeHit best = noHit();\n // 3x3 neighborhood\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cc = cell + vec2(float(dx), float(dy));\n vec2 hh = hash22(cc + seed) - 0.5;\n // Density gate — noise threshold; sparse placement.\n float gate = hash21(cc * 1.7 + seed * 0.3);\n if (gate > density) continue;\n\n vec2 center = (cc + 0.5 + hh * jitterAmt) * cellSize;\n\n // Per-stroke direction: consume the layer-provided flow, then add only\n // deterministic local perturbation so alternate stroke layers stay live.\n vec2 f = safeDir(flow);\n float angJ = (hash21(cc + seed + 11.0) - 0.5) * 0.9; // +/- 0.45 rad\n float localCurl = (fbm(center * (2.6 + seed * 0.11) + seed * 1.9) - 0.5) * 0.55 * uFlowCurl;\n vec2 dir = rotateDir(f, angJ + localCurl);\n\n float lenV = cellSize * lenMul * (0.65 + 0.55 * hash21(cc + seed + 23.0));\n float halfW = cellSize * halfWMul * (0.70 + 0.55 * hash21(cc + seed + 41.0));\n float bulge = (hash21(cc + seed + 53.0) - 0.5) * lenV * 0.35;\n\n vec2 a = center - dir * (lenV * 0.5);\n vec2 b = center + dir * (lenV * 0.5);\n\n vec3 colMid = brokenColorJitter(\n sampleBase(center, t),\n hash21(cc + seed + 89.0),\n hash21(cc * 2.3 + seed + 97.0),\n 1.0\n );\n\n StrokeHit h = curvedStroke(p, a, b, halfW, bulge, shapeType,\n 7.0, bristleAmp,\n hash21(cc + seed + 67.0), colMid);\n if (h.coverage > best.coverage) best = h;\n }\n }\n return best;\n}\n\n// ── Crayon / oil-pastel — paper tooth × wax pigment ───────────────────────\n// Crayon is not strokes. It's pigment crumbs dragged across paper tooth.\n// Model: heavy 2D tooth noise at multiple scales, anisotropically stretched\n// along flow direction, multiplied into the base color. Add a slow \"waxy\n// film\" that slightly unifies hues, and occasional darker \"pressed\" spots\n// where the crayon dug in. NO straight segments.\nvec3 mediumOil_crayon(vec3 col, vec2 p, float t) {\n vec2 flow = flowField(p, t);\n float ang = atan(flow.y, flow.x);\n float ca = cos(-ang), sa = sin(-ang);\n vec2 pr = vec2(p.x * ca - p.y * sa, p.x * sa + p.y * ca);\n\n // Anisotropic tooth — squished along flow, coarse cross flow.\n float aniso = mix(0.45, 0.95, uStrokeAnisotropy);\n float scale = max(uStrokeScale * 1.6, 180.0);\n\n float t1 = vnoise(vec2(pr.x * scale * aniso, pr.y * scale));\n float t2 = vnoise(vec2(pr.x * scale * aniso * 0.4, pr.y * scale * 0.4) + 11.0);\n float t3 = vnoise(vec2(pr.x * scale * aniso * 2.1, pr.y * scale * 2.1) + 23.0);\n float tooth = 0.55 * t1 + 0.30 * t2 + 0.15 * t3;\n // Center at 0, amplify\n tooth = (tooth - 0.5) * 1.4;\n\n // Multiplicative darkening where tooth is low (pigment skipped paper valleys)\n float lay = 1.0 + tooth * 0.32 * uStrokeAmount;\n vec3 result = col * lay;\n\n // Occasional pressed-in crumbs — rare darker crumbs\n float crumbs = smoothstep(0.78, 0.95, vnoise(pr * scale * 3.0));\n result *= 1.0 - crumbs * 0.18 * uStrokeAmount;\n\n // Waxy highlight film — slight lightening on tooth peaks\n float waxy = smoothstep(0.55, 0.85, t1);\n result += waxy * 0.04 * vec3(1.0);\n\n // Paper tooth overlay (subtler than oil's canvas)\n float paperTooth = vnoise(p * 340.0) - 0.5;\n result *= 1.0 + paperTooth * 0.14 * uCanvasGrain;\n\n // Broken-color pigment: stable wax/pigment patches, not temporal flicker.\n vec2 pigmentCell = floor(pr * max(scale * 0.18, 32.0));\n float pigmentMask = smoothstep(0.28, 0.82, vnoise(pr * scale * 0.21 + 19.0));\n result = brokenColorJitter(\n result,\n hash21(pigmentCell + 17.0),\n hash21(pigmentCell * 2.1 + 31.0),\n 0.45 + 0.55 * pigmentMask\n );\n\n // Crayon is saturation-amplified\n result = saturate3(result, 1.12);\n\n return result;\n}\n\nvec3 mediumOil(vec3 col, vec2 p, float t) {\n // Mode knobs (uStrokeMode):\n // 0 oil — balanced modern-abstract/palette-knife hybrid\n // 1 knife — palette-knife impasto: razor edges, heavy bristle/shadow\n // 2 crayon — soft-edged wax smudges on tooth (no straight segments)\n // 3 brushwork — thick bristle brush\n int mode = uStrokeMode;\n\n // Per-mode parameters\n int shapeType = 0; // tapered\n float bristleAmp = 0.25; // 0..0.5\n float streakFreq = 9.0;\n float streakAmp = 0.09;\n float impastoAmp = 0.9;\n float hardness = 0.80; // edge compositing\n float toothScale = 240.0;\n float toothAmp = 0.09;\n float pigmentSat = 1.03;\n float densityBig = 0.65;\n float densityMed = 0.78;\n float densitySml = 0.90;\n\n if (mode == 1) { // palette knife\n shapeType = 3; // flat, even\n bristleAmp = 0.12;\n streakFreq = 4.0; streakAmp = 0.05;\n impastoAmp = 1.6;\n hardness = 0.95;\n toothAmp = 0.04;\n densityBig = 0.80; densityMed = 0.88; densitySml = 0.70;\n } else if (mode == 2) { // crayon — handled specially below\n return mediumOil_crayon(col, p, t);\n } else if (mode == 3) { // thick brushwork\n shapeType = 0; // tapered\n bristleAmp = 0.32;\n streakFreq = 14.0; streakAmp = 0.14;\n impastoAmp = 1.2;\n hardness = 0.85;\n toothAmp = 0.07;\n }\n\n // Scales & multipliers from uniforms\n float baseScale = max(uStrokeScale * 0.006, 0.008);\n // Three layers: big gestural, medium body, small dabs\n float sBig = baseScale * 2.4;\n float sMed = baseScale * 1.1;\n float sSml = baseScale * 0.45;\n\n float lenMulBig = mix(2.2, 3.8, uStrokeAnisotropy);\n float widMulBig = mix(0.55, 0.32, uStrokeAnisotropy);\n float lenMulMed = mix(2.0, 3.4, uStrokeAnisotropy);\n float widMulMed = mix(0.50, 0.30, uStrokeAnisotropy);\n float lenMulSml = mix(1.6, 2.6, uStrokeAnisotropy);\n float widMulSml = mix(0.45, 0.32, uStrokeAnisotropy);\n\n float jitterAmt = 0.75; // large jitter — no grid\n vec2 flow = flowField(p, t);\n\n vec3 result = col;\n\n // Layer 1 — big gestural strokes (sparse, shaping)\n StrokeHit hBig = bestOil(p, sBig, lenMulBig, widMulBig, jitterAmt * 0.55,\n densityBig, shapeType, bristleAmp, flow, t, 1.3);\n paintOver(result, hBig, streakFreq * 0.7, streakAmp,\n uImpasto * impastoAmp * uStrokeAmount, hardness, 1.3);\n\n // Layer 2 — medium body strokes\n StrokeHit hMed = bestOil(p + vec2(11.3, 3.7), sMed, lenMulMed, widMulMed,\n jitterAmt, densityMed, shapeType, bristleAmp, flow, t, 2.7);\n paintOver(result, hMed, streakFreq, streakAmp,\n uImpasto * impastoAmp * uStrokeAmount, hardness, 2.7);\n\n // Layer 3 — small dabs (more frequent, smaller)\n int smlShape = (mode == 1) ? 2 : shapeType; // knife uses dabs for sparkle\n StrokeHit hSml = bestOil(p + vec2(-5.1, 8.4), sSml, lenMulSml, widMulSml,\n jitterAmt * 1.3, densitySml, smlShape,\n bristleAmp * 0.85, flow, t, 4.1);\n paintOver(result, hSml, streakFreq * 1.4, streakAmp * 0.8,\n uImpasto * impastoAmp * 0.65 * uStrokeAmount, hardness, 4.1);\n\n // Layer 4 — fill dabs (very dense, very small) — covers bald spots\n float sFill = baseScale * 0.22;\n float lenMulFill = mix(1.4, 2.0, uStrokeAnisotropy);\n float widMulFill = mix(0.50, 0.38, uStrokeAnisotropy);\n int fillShape = (mode == 1) ? 3 : 2; // knife=even, others=dab (round fills)\n StrokeHit hFill = bestOil(p + vec2(3.9, -6.2), sFill, lenMulFill, widMulFill,\n jitterAmt * 1.5, 0.95, fillShape,\n bristleAmp * 0.6, flow, t, 8.9);\n paintOver(result, hFill, streakFreq * 1.8, streakAmp * 0.6,\n uImpasto * impastoAmp * 0.4 * uStrokeAmount, hardness * 0.9, 8.9);\n\n // Optional crosshatch layer\n if (uStrokeLayers == 2) {\n vec2 flow2 = vec2(-flow.y, flow.x);\n StrokeHit hX = bestOil(p + vec2(7.3, -2.1), sMed, lenMulMed * 0.9, widMulMed,\n jitterAmt, densityMed * 0.7, shapeType, bristleAmp, flow2, t, 6.5);\n paintOver(result, hX, streakFreq, streakAmp * 0.85,\n uImpasto * impastoAmp * 0.55 * uStrokeAmount, hardness, 6.5);\n }\n\n // Canvas tooth — linen weave\n float tooth1 = vnoise(p * toothScale);\n float tooth2 = vnoise(p * toothScale * vec2(0.6, 2.4) + 37.0);\n float tooth = (0.6 * tooth1 + 0.4 * tooth2) - 0.5;\n result *= 1.0 + tooth * toothAmp * uCanvasGrain;\n\n // Pigment saturation boost\n result = saturate3(result, pigmentSat);\n\n return result;\n}\n\n// ── Main ──────────────────────────────────────────────────────────────────\nvoid main() {\n // Normalized 0..1 coordinates for nuclei, domain warp, and medium sampling.\n vec2 uv = vUv;\n vec2 pN = uv;\n\n float t = uTime;\n\n // Warp in pN space\n vec2 p_warp = domainWarp(pN, t);\n\n // Composition\n float paletteId; float valueMod;\n nucleiField(p_warp, t, paletteId, valueMod);\n vec3 col = samplePalette(paletteId);\n col *= 1.0 + uValueVariance * valueMod;\n\n // Breath — slow global luminance wobble\n float breath = sin(t * 6.2831 / max(uBreathPeriod, 1.0));\n col *= 1.0 + uBreathDepth * breath * 0.5;\n\n // Medium\n if (uMedium == 1) col = mediumPastel(col, pN, t);\n else if (uMedium == 2) col = mediumWatercolor(col, pN, t);\n else if (uMedium == 3) col = mediumOil(col, pN, t);\n\n // Saturation trim\n col = saturate3(col, uSaturation);\n\n // Tonemap + film grain\n col = aces(col);\n float grain = hash21(gl_FragCoord.xy + t * 17.0);\n col += (grain - 0.5) * uPaperGrain;\n\n col = clamp(col * 0.985 + 0.008, 0.0, 1.0);\n fragColor = vec4(col * uAlpha, uAlpha);\n}\n";
@@ -144,14 +144,14 @@ var R = {
144
144
  knife: 1,
145
145
  crayon: 2,
146
146
  chunky: 3
147
- }, H = .22, U = .18, W = .992;
148
- function G(e) {
147
+ }, H = .22, U = .18, W = .992, G = .001;
148
+ function K(e) {
149
149
  return e.mode === "capture" ? !0 : e.initStrategy === "eager";
150
150
  }
151
- function K(e) {
151
+ function q(e) {
152
152
  return typeof e.preserveDrawingBuffer == "boolean" ? e.preserveDrawingBuffer : e.mode === "capture";
153
153
  }
154
- function q(e, t, n) {
154
+ function J(e, t, n) {
155
155
  let r = e.createShader(t);
156
156
  if (e.shaderSource(r, n), e.compileShader(r), !e.getShaderParameter(r, e.COMPILE_STATUS)) {
157
157
  let t = e.getShaderInfoLog(r) ?? "unknown";
@@ -159,7 +159,7 @@ function q(e, t, n) {
159
159
  }
160
160
  return r;
161
161
  }
162
- function J(e, t, n) {
162
+ function Y(e, t, n) {
163
163
  let r = e.createProgram();
164
164
  if (e.attachShader(r, t), e.attachShader(r, n), e.linkProgram(r), !e.getProgramParameter(r, e.LINK_STATUS)) {
165
165
  let t = e.getProgramInfoLog(r) ?? "unknown";
@@ -167,9 +167,25 @@ function J(e, t, n) {
167
167
  }
168
168
  return r;
169
169
  }
170
- var Y = /* @__PURE__ */ "uTime.uPalette.uStopCount.uNucleiCount.uNucleiPos.uNucleiRadius.uNucleiPaletteBias.uNucleiValueBias.uNucleiDriftRadius.uNucleiDriftPhase.uNucleiElong.uNucleiAngle.uSoftmaxBeta.uValueVariance.uWarpAmount.uWarpScale.uWarpDrift.uWarpMode.uNoiseOctaves.uMedium.uFlowPattern.uFlowFocal.uFlowAngle.uFlowCurl.uCursor.uCursorStrength.uCursorRadius.uStrokeAmount.uStrokeScale.uStrokeAnisotropy.uStrokeLayers.uStrokeMode.uWetEdge.uGranulation.uImpasto.uBrokenColor.uCanvasGrain.uNucleiDrift.uPaletteDrift.uBreathDepth.uBreathPeriod.uSaturation.uPaperGrain.uAlpha".split(".");
170
+ var ee = /* @__PURE__ */ "uTime.uPalette.uStopCount.uNucleiCount.uNucleiPos.uNucleiRadius.uNucleiPaletteBias.uNucleiValueBias.uNucleiDriftRadius.uNucleiDriftPhase.uNucleiElong.uNucleiAngle.uSoftmaxBeta.uValueVariance.uWarpAmount.uWarpScale.uWarpDrift.uWarpMode.uNoiseOctaves.uMedium.uFlowPattern.uFlowFocal.uFlowAngle.uFlowCurl.uCursor.uCursorStrength.uCursorRadius.uStrokeAmount.uStrokeScale.uStrokeAnisotropy.uStrokeLayers.uStrokeMode.uWetEdge.uGranulation.uImpasto.uBrokenColor.uCanvasGrain.uNucleiDrift.uPaletteDrift.uBreathDepth.uBreathPeriod.uSaturation.uPaperGrain.uAlpha".split(".");
171
171
  function X(e, t, n = {}) {
172
- let r = K(n), i = t, a = n.mode !== "capture", o = typeof window < "u" && window.matchMedia ? window.matchMedia("(prefers-reduced-motion: reduce)").matches : !1, s = performance.now(), c = {
172
+ let r = q(n), i = t, a = /* @__PURE__ */ new Set();
173
+ n.mode === "capture" && a.add("manual");
174
+ let o = () => a.size === 0, s = typeof window < "u" && window.matchMedia ? window.matchMedia("(prefers-reduced-motion: reduce)").matches : !1, c = performance.now(), l = 0, u = null;
175
+ function d(e) {
176
+ let t = o();
177
+ a.add(e), t && !o() && (cancelAnimationFrame(l), l = 0);
178
+ }
179
+ function f(e) {
180
+ let t = !o();
181
+ a.delete(e), t && o() && u && (c = performance.now() - 1e3, u());
182
+ }
183
+ let p = typeof document < "u";
184
+ function m() {
185
+ document.hidden ? d("tab-hidden") : f("tab-hidden");
186
+ }
187
+ p && document.addEventListener("visibilitychange", m);
188
+ let h = {
173
189
  x: .5,
174
190
  y: .5,
175
191
  targetX: .5,
@@ -177,21 +193,21 @@ function X(e, t, n = {}) {
177
193
  strength: 0,
178
194
  targetStrength: 0,
179
195
  radius: .25
180
- }, l = null, u = !1;
181
- function d(e, t, n = .8) {
182
- c.targetX = e, c.targetY = t, c.targetStrength = n;
196
+ }, g = null, _ = !1;
197
+ function b(e, t, n = .8) {
198
+ h.targetX = e, h.targetY = t, h.targetStrength = n, g?.wake();
183
199
  }
184
- function f() {
185
- c.targetStrength = 0;
200
+ function x() {
201
+ h.targetStrength = 0, g?.wake();
186
202
  }
187
- function p(e) {
188
- c.radius = e;
203
+ function S(e) {
204
+ h.radius = e, g?.wake();
189
205
  }
190
- function m(e) {
191
- o = e;
206
+ function C(e) {
207
+ s = e, g?.wake();
192
208
  }
193
- function h() {
194
- if (l || u) return;
209
+ function w() {
210
+ if (g || _) return;
195
211
  let t = e.getContext("webgl2", {
196
212
  antialias: !1,
197
213
  alpha: !0,
@@ -199,12 +215,12 @@ function X(e, t, n = {}) {
199
215
  preserveDrawingBuffer: r
200
216
  });
201
217
  if (!t) throw Error("[Aurora] WebGL2 unavailable");
202
- let n = q(t, t.VERTEX_SHADER, v), d = q(t, t.FRAGMENT_SHADER, y), f = J(t, n, d);
203
- t.useProgram(f);
204
- let p = t.createVertexArray();
205
- t.bindVertexArray(p);
206
- let m = t.createBuffer();
207
- t.bindBuffer(t.ARRAY_BUFFER, m), t.bufferData(t.ARRAY_BUFFER, new Float32Array([
218
+ let n = J(t, t.VERTEX_SHADER, v), a = J(t, t.FRAGMENT_SHADER, y), d = Y(t, n, a);
219
+ t.useProgram(d);
220
+ let f = t.createVertexArray();
221
+ t.bindVertexArray(f);
222
+ let p = t.createBuffer();
223
+ t.bindBuffer(t.ARRAY_BUFFER, p), t.bufferData(t.ARRAY_BUFFER, new Float32Array([
208
224
  -1,
209
225
  -1,
210
226
  3,
@@ -212,19 +228,19 @@ function X(e, t, n = {}) {
212
228
  -1,
213
229
  3
214
230
  ]), t.STATIC_DRAW);
215
- let h = t.getAttribLocation(f, "aPos");
216
- t.enableVertexAttribArray(h), t.vertexAttribPointer(h, 2, t.FLOAT, !1, 0, 0);
217
- let g = {};
218
- for (let e of Y) g[e] = t.getUniformLocation(f, e);
219
- function _() {
231
+ let m = t.getAttribLocation(d, "aPos");
232
+ t.enableVertexAttribArray(m), t.vertexAttribPointer(m, 2, t.FLOAT, !1, 0, 0);
233
+ let b = {};
234
+ for (let e of ee) b[e] = t.getUniformLocation(d, e);
235
+ function x() {
220
236
  let n = Math.min(window.devicePixelRatio || 1, 2), r = e.clientWidth || e.parentElement?.clientWidth || 1, i = e.clientHeight || e.parentElement?.clientHeight || 1, a = Math.max(1, Math.floor(r * n)), o = Math.max(1, Math.floor(i * n));
221
- e.width = a, e.height = o, t.viewport(0, 0, a, o), t.useProgram(f);
237
+ e.width = a, e.height = o, t.viewport(0, 0, a, o), t.useProgram(d);
222
238
  }
223
- let b = new ResizeObserver(() => _());
224
- b.observe(e), requestAnimationFrame(() => {
225
- _(), requestAnimationFrame(_);
239
+ let S = new ResizeObserver(() => x());
240
+ S.observe(e), requestAnimationFrame(() => {
241
+ x(), requestAnimationFrame(x);
226
242
  });
227
- let x = {
243
+ let C = {
228
244
  palette: new Float32Array(24),
229
245
  pos: new Float32Array(12),
230
246
  rad: new Float32Array(6),
@@ -235,71 +251,68 @@ function X(e, t, n = {}) {
235
251
  elong: new Float32Array(6),
236
252
  angle: new Float32Array(6)
237
253
  };
238
- function S(e) {
239
- i = e, t.useProgram(f), j(e.palette, 8, x.palette), t.uniform3fv(g.uPalette, x.palette), t.uniform1i(g.uStopCount, Math.min(e.palette.length, 8));
254
+ function w(e) {
255
+ i = e, t.useProgram(d), j(e.palette, 8, C.palette), t.uniform3fv(b.uPalette, C.palette), t.uniform1i(b.uStopCount, Math.min(e.palette.length, 8));
240
256
  let n = Math.min(e.nuclei.length, 6);
241
- t.uniform1i(g.uNucleiCount, n);
257
+ t.uniform1i(b.uNucleiCount, n);
242
258
  for (let t = 0; t < n; t++) {
243
259
  let n = e.nuclei[t];
244
- x.pos[t * 2 + 0] = n.x, x.pos[t * 2 + 1] = 1 - n.y, x.rad[t] = n.radius, x.pb[t] = n.paletteBias, x.vb[t] = n.valueBias, x.dr[t] = n.driftRadius, x.dp[t] = n.driftPhase, x.elong[t] = n.elongation ?? 1, x.angle[t] = -(n.angle ?? 0) * Math.PI / 180;
260
+ C.pos[t * 2 + 0] = n.x, C.pos[t * 2 + 1] = 1 - n.y, C.rad[t] = n.radius, C.pb[t] = n.paletteBias, C.vb[t] = n.valueBias, C.dr[t] = n.driftRadius, C.dp[t] = n.driftPhase, C.elong[t] = n.elongation ?? 1, C.angle[t] = -(n.angle ?? 0) * Math.PI / 180;
245
261
  }
246
- for (let e = n; e < 6; e++) x.pos[e * 2 + 0] = 0, x.pos[e * 2 + 1] = 0, x.rad[e] = 0, x.pb[e] = 0, x.vb[e] = 0, x.dr[e] = 0, x.dp[e] = 0, x.elong[e] = 1, x.angle[e] = 0;
247
- t.uniform2fv(g.uNucleiPos, x.pos), t.uniform1fv(g.uNucleiRadius, x.rad), t.uniform1fv(g.uNucleiPaletteBias, x.pb), t.uniform1fv(g.uNucleiValueBias, x.vb), t.uniform1fv(g.uNucleiDriftRadius, x.dr), t.uniform1fv(g.uNucleiDriftPhase, x.dp), t.uniform1fv(g.uNucleiElong, x.elong), t.uniform1fv(g.uNucleiAngle, x.angle), t.uniform1f(g.uSoftmaxBeta, e.softmaxBeta), t.uniform1f(g.uValueVariance, e.valueVariance), t.uniform1f(g.uWarpAmount, e.warpAmount), t.uniform1f(g.uWarpScale, e.warpScale), t.uniform1f(g.uWarpDrift, e.warpDrift), t.uniform1i(g.uWarpMode, B[e.warpMode]), t.uniform1i(g.uNoiseOctaves, e.noiseOctaves), t.uniform1i(g.uMedium, R[e.medium]), t.uniform1i(g.uFlowPattern, z[e.flow.pattern]), t.uniform2f(g.uFlowFocal, e.flow.focalX, 1 - e.flow.focalY), t.uniform1f(g.uFlowAngle, e.flow.angle), t.uniform1f(g.uFlowCurl, e.flow.curl), t.uniform2f(g.uCursor, c.x, 1 - c.y), t.uniform1f(g.uCursorStrength, c.strength), t.uniform1f(g.uCursorRadius, c.radius), t.uniform1f(g.uStrokeAmount, e.strokeAmount), t.uniform1f(g.uStrokeScale, e.strokeScale), t.uniform1f(g.uStrokeAnisotropy, e.strokeAnisotropy), t.uniform1i(g.uStrokeLayers, e.strokeLayers), t.uniform1i(g.uStrokeMode, V[e.strokeMode]), t.uniform1f(g.uWetEdge, e.wetEdge), t.uniform1f(g.uGranulation, e.granulation), t.uniform1f(g.uImpasto, e.impasto), t.uniform1f(g.uBrokenColor, e.brokenColor), t.uniform1f(g.uCanvasGrain, e.canvasGrain), t.uniform1f(g.uNucleiDrift, e.nucleiDrift), t.uniform1f(g.uPaletteDrift, e.paletteDrift), t.uniform1f(g.uBreathDepth, e.breathDepth), t.uniform1f(g.uBreathPeriod, e.breathPeriod), t.uniform1f(g.uSaturation, e.saturation), t.uniform1f(g.uPaperGrain, e.paperGrain), t.uniform1f(g.uAlpha, e.alpha);
248
- }
249
- S(i), _(), t.clearColor(0, 0, 0, 0), t.disable(t.DEPTH_TEST), t.enable(t.BLEND), t.blendFunc(t.ONE, t.ONE_MINUS_SRC_ALPHA);
250
- let C = 0;
251
- function w() {
252
- c.x += (c.targetX - c.x) * H, c.y += (c.targetY - c.y) * H, c.strength += (c.targetStrength - c.strength) * U, c.targetStrength *= W;
262
+ for (let e = n; e < 6; e++) C.pos[e * 2 + 0] = 0, C.pos[e * 2 + 1] = 0, C.rad[e] = 0, C.pb[e] = 0, C.vb[e] = 0, C.dr[e] = 0, C.dp[e] = 0, C.elong[e] = 1, C.angle[e] = 0;
263
+ t.uniform2fv(b.uNucleiPos, C.pos), t.uniform1fv(b.uNucleiRadius, C.rad), t.uniform1fv(b.uNucleiPaletteBias, C.pb), t.uniform1fv(b.uNucleiValueBias, C.vb), t.uniform1fv(b.uNucleiDriftRadius, C.dr), t.uniform1fv(b.uNucleiDriftPhase, C.dp), t.uniform1fv(b.uNucleiElong, C.elong), t.uniform1fv(b.uNucleiAngle, C.angle), t.uniform1f(b.uSoftmaxBeta, e.softmaxBeta), t.uniform1f(b.uValueVariance, e.valueVariance), t.uniform1f(b.uWarpAmount, e.warpAmount), t.uniform1f(b.uWarpScale, e.warpScale), t.uniform1f(b.uWarpDrift, e.warpDrift), t.uniform1i(b.uWarpMode, B[e.warpMode]), t.uniform1i(b.uNoiseOctaves, e.noiseOctaves), t.uniform1i(b.uMedium, R[e.medium]), t.uniform1i(b.uFlowPattern, z[e.flow.pattern]), t.uniform2f(b.uFlowFocal, e.flow.focalX, 1 - e.flow.focalY), t.uniform1f(b.uFlowAngle, e.flow.angle), t.uniform1f(b.uFlowCurl, e.flow.curl), t.uniform2f(b.uCursor, h.x, 1 - h.y), t.uniform1f(b.uCursorStrength, h.strength), t.uniform1f(b.uCursorRadius, h.radius), t.uniform1f(b.uStrokeAmount, e.strokeAmount), t.uniform1f(b.uStrokeScale, e.strokeScale), t.uniform1f(b.uStrokeAnisotropy, e.strokeAnisotropy), t.uniform1i(b.uStrokeLayers, e.strokeLayers), t.uniform1i(b.uStrokeMode, V[e.strokeMode]), t.uniform1f(b.uWetEdge, e.wetEdge), t.uniform1f(b.uGranulation, e.granulation), t.uniform1f(b.uImpasto, e.impasto), t.uniform1f(b.uBrokenColor, e.brokenColor), t.uniform1f(b.uCanvasGrain, e.canvasGrain), t.uniform1f(b.uNucleiDrift, e.nucleiDrift), t.uniform1f(b.uPaletteDrift, e.paletteDrift), t.uniform1f(b.uBreathDepth, e.breathDepth), t.uniform1f(b.uBreathPeriod, e.breathPeriod), t.uniform1f(b.uSaturation, e.saturation), t.uniform1f(b.uPaperGrain, e.paperGrain), t.uniform1f(b.uAlpha, e.alpha);
253
264
  }
254
- function T(e) {
255
- t.useProgram(f), t.uniform2f(g.uCursor, c.x, 1 - c.y), t.uniform1f(g.uCursorStrength, c.strength), t.uniform1f(g.uCursorRadius, c.radius), t.uniform1f(g.uTime, e), t.clear(t.COLOR_BUFFER_BIT), t.drawArrays(t.TRIANGLES, 0, 3);
265
+ w(i), x(), t.clearColor(0, 0, 0, 0), t.disable(t.DEPTH_TEST), t.enable(t.BLEND), t.blendFunc(t.ONE, t.ONE_MINUS_SRC_ALPHA);
266
+ function T() {
267
+ h.x += (h.targetX - h.x) * H, h.y += (h.targetY - h.y) * H, h.strength += (h.targetStrength - h.strength) * U, h.targetStrength *= W;
256
268
  }
257
- function E() {
258
- if (!a) return;
259
- let e = o ? 3.7 : (performance.now() - s) / 1e3;
260
- w(), T(e), C = requestAnimationFrame(E);
269
+ function E(e) {
270
+ t.useProgram(d), t.uniform2f(b.uCursor, h.x, 1 - h.y), t.uniform1f(b.uCursorStrength, h.strength), t.uniform1f(b.uCursorRadius, h.radius), t.uniform1f(b.uTime, e), t.clear(t.COLOR_BUFFER_BIT), t.drawArrays(t.TRIANGLES, 0, 3);
261
271
  }
262
- a && (C = requestAnimationFrame(E));
263
- function D(e) {
264
- T(e);
272
+ function D() {
273
+ return s ? !1 : i.nucleiDrift !== 0 || i.paletteDrift !== 0 || i.breathDepth !== 0 || i.warpDrift !== 0 ? !0 : h.targetStrength > G || h.strength > G || Math.abs(h.x - h.targetX) > G || Math.abs(h.y - h.targetY) > G;
265
274
  }
266
275
  function O() {
267
- a = !1, cancelAnimationFrame(C);
276
+ if (!o()) return;
277
+ let e = s ? 3.7 : (performance.now() - c) / 1e3;
278
+ T(), E(e), l = D() ? requestAnimationFrame(O) : 0;
268
279
  }
280
+ u = O, o() && (l = requestAnimationFrame(O));
269
281
  function k() {
270
- a || (a = !0, s = performance.now() - 1e3, E());
282
+ o() && !l && (l = requestAnimationFrame(O));
271
283
  }
272
- function A() {
273
- a = !1, cancelAnimationFrame(C), b.disconnect(), t.deleteProgram(f), t.deleteShader(n), t.deleteShader(d), t.deleteBuffer(m), t.deleteVertexArray(p);
284
+ function A(e) {
285
+ E(e);
286
+ }
287
+ function M() {
288
+ cancelAnimationFrame(l), l = 0, u = null, S.disconnect(), t.deleteProgram(d), t.deleteShader(n), t.deleteShader(a), t.deleteBuffer(p), t.deleteVertexArray(f);
274
289
  let e = t.getExtension("WEBGL_lose_context");
275
290
  e && e.loseContext();
276
291
  }
277
- l = {
278
- setConfig: S,
279
- renderAt: D,
280
- pause: O,
281
- resume: k,
282
- dispose: A
292
+ g = {
293
+ setConfig: w,
294
+ renderAt: A,
295
+ wake: k,
296
+ dispose: M
283
297
  };
284
298
  }
285
- return G(n) && h(), {
286
- arm: h,
299
+ function T() {
300
+ p && document.removeEventListener("visibilitychange", m), a.clear();
301
+ }
302
+ return K(n) && w(), {
303
+ arm: w,
287
304
  update: (e) => {
288
- i = e, l?.setConfig(e);
305
+ i = e, g?.setConfig(e), g?.wake();
289
306
  },
290
- setCursor: d,
291
- clearCursor: f,
292
- setCursorRadius: p,
293
- setReducedMotion: m,
294
- pause: () => {
295
- a = !1, l?.pause();
296
- },
297
- resume: () => {
298
- a = !0, l?.resume();
299
- },
300
- renderAt: (e) => l?.renderAt(e),
307
+ setCursor: b,
308
+ clearCursor: x,
309
+ setCursorRadius: S,
310
+ setReducedMotion: C,
311
+ pause: (e = "manual") => d(e),
312
+ resume: (e = "manual") => f(e),
313
+ renderAt: (e) => g?.renderAt(e),
301
314
  dispose: () => {
302
- l ? l.dispose() : u = !0;
315
+ g ? g.dispose() : _ = !0, T();
303
316
  }
304
317
  };
305
318
  }
@@ -310,7 +323,7 @@ function Z(e) {
310
323
  }
311
324
  //#endregion
312
325
  //#region src/components/custom/aurora/composables/useAurora.ts
313
- function ee(e) {
326
+ function te(e) {
314
327
  if (typeof window > "u") return () => {};
315
328
  if (typeof window.requestIdleCallback == "function") {
316
329
  let t = window.requestIdleCallback(() => e(), { timeout: 2e3 });
@@ -369,12 +382,12 @@ function Q(e, t, n = {}, r = {}) {
369
382
  return;
370
383
  }
371
384
  p = i(e, {
372
- pause: () => s?.pause(),
373
- resume: () => s?.resume()
374
- });
385
+ pause: () => s?.pause("off-screen"),
386
+ resume: () => s?.resume("off-screen")
387
+ }, { pauseWhenHidden: !1 });
375
388
  let r = p.isIntersecting;
376
389
  l = _(r, (e) => {
377
- !e || v || u || (u = ee(() => {
390
+ !e || v || u || (u = te(() => {
378
391
  u = null, r.value && C();
379
392
  }));
380
393
  }, { immediate: !0 });
@@ -400,7 +413,7 @@ function $(e) {
400
413
  }
401
414
  //#endregion
402
415
  //#region src/components/custom/aurora/Aurora.vue
403
- var te = /* @__PURE__ */ e(/* @__PURE__ */ c({
416
+ var ne = /* @__PURE__ */ e(/* @__PURE__ */ c({
404
417
  __name: "Aurora",
405
418
  props: {
406
419
  config: { default: () => r },
@@ -441,7 +454,7 @@ var te = /* @__PURE__ */ e(/* @__PURE__ */ c({
441
454
  }), [["__scopeId", "data-v-80ea8f7d"]]);
442
455
  //#endregion
443
456
  //#region src/components/custom/aurora/composables/useCursorInteraction.ts
444
- function ne(e, t, n) {
457
+ function re(e, t, n) {
445
458
  let r = Z(t), i = n.hitFraction ?? .35, a = null, o = null;
446
459
  function s(e, t) {
447
460
  let n = t.getBoundingClientRect();
@@ -538,4 +551,4 @@ function ne(e, t, n) {
538
551
  }), { isDragging: () => a };
539
552
  }
540
553
  //#endregion
541
- export { te as Aurora, r as DEFAULT_AURORA_CONFIG, t as MAX_NUCLEI, n as MAX_STOPS, X as createAurora, L as cssToOklch, j as flattenPalette, P as hexToOklchStop, N as oklchStopToHex, A as oklchToLinear, M as paletteToCssGradient, $ as resolveRenderMode, Q as useAurora, ne as useCursorInteraction };
554
+ export { ne as Aurora, r as DEFAULT_AURORA_CONFIG, t as MAX_NUCLEI, n as MAX_STOPS, X as createAurora, L as cssToOklch, j as flattenPalette, P as hexToOklchStop, N as oklchStopToHex, A as oklchToLinear, M as paletteToCssGradient, $ as resolveRenderMode, Q as useAurora, re as useCursorInteraction };
package/dist/badge.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./badge-BbxVKZfw.js";
1
+ import { n as e, t } from "./badge-x46my_Fo.js";
2
2
  export { e as Badge, t as badgeVariants };
@@ -24,6 +24,7 @@ var u = /* @__PURE__ */ n({
24
24
  return (u, f) => (i(), t(o(c), {
25
25
  as: n.as,
26
26
  "as-child": n.asChild,
27
+ "data-size": n.size,
27
28
  class: r(o(e)(o(d)({
28
29
  variant: n.variant,
29
30
  size: n.size
@@ -34,6 +35,7 @@ var u = /* @__PURE__ */ n({
34
35
  }, 8, [
35
36
  "as",
36
37
  "as-child",
38
+ "data-size",
37
39
  "class"
38
40
  ]));
39
41
  }
package/dist/button.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./button-BlOW34DT.js";
1
+ import { n as e, t } from "./button-C0aHmBbt.js";
2
2
  export { e as Button, t as buttonVariants };
package/dist/card.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, n, o as r, r as i, t as a } from "./CardFooter-Yi0xtLLd.js";
1
+ import { a as e, i as t, n, o as r, r as i, t as a } from "./CardFooter-CSGcJkqa.js";
2
2
  export { r as Card, n as CardContent, i as CardDescription, a as CardFooter, e as CardHeader, t as CardTitle };
package/dist/carousel.js CHANGED
@@ -3,7 +3,7 @@ import { t } from "./createLucideIcon-Bn9a1b70.js";
3
3
  import { t as n } from "./chevron-down-DILQA1t6.js";
4
4
  import { t as r } from "./chevron-right-fS7fal2t.js";
5
5
  import { t as i } from "./chevron-up-BtYjYQOS.js";
6
- import { n as a } from "./button-BlOW34DT.js";
6
+ import { n as a } from "./button-C0aHmBbt.js";
7
7
  import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createVNode as f, defineComponent as p, mergeProps as m, normalizeClass as h, onMounted as g, openBlock as _, ref as v, renderList as y, renderSlot as b, resolveDynamicComponent as x, toDisplayString as S, unref as C, watch as w, withCtx as T } from "vue";
8
8
  import { createInjectionState as E } from "@vueuse/core";
9
9
  import D from "embla-carousel-vue";
@@ -1,2 +1,2 @@
1
- import { n as e, r as t, t as n } from "./CollapsibleContent-DHRuXE3P.js";
1
+ import { n as e, r as t, t as n } from "./CollapsibleContent-CVMOcYlV.js";
2
2
  export { t as Collapsible, n as CollapsibleContent, e as CollapsibleTrigger };
package/dist/command.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./CommandShortcut-_INFUMu6.js";
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./CommandShortcut-DWT19a2Y.js";
2
2
  export { r as Command, t as CommandDialog, s as CommandEmpty, a as CommandGroup, e as CommandInput, n as CommandItem, o as CommandList, i as CommandSeparator, c as CommandShortcut };
@@ -10,6 +10,18 @@
10
10
  */
11
11
  import { type AuroraConfig, type AuroraInstance } from "../presets";
12
12
  export type AuroraRuntimeMode = "live" | "capture";
13
+ /**
14
+ * The three independent reasons the RAF loop may be suspended. The runtime
15
+ * tracks them in a `Set<SuspendReason>` rather than one boolean, so the loop
16
+ * runs IFF the set is empty and each reason is cleared ONLY by the source that
17
+ * set it. This makes resume-while-still-suspended structurally unreachable — a
18
+ * `resume("tab-hidden")` cannot lift an `"off-screen"` suspension.
19
+ *
20
+ * - `"tab-hidden"` — the runtime's own `document.visibilitychange` owner.
21
+ * - `"off-screen"` — viewport-intersection, driven by `useIntersectionPause`.
22
+ * - `"manual"` — the public `pause()`/`resume()` API (and capture-mode seed).
23
+ */
24
+ export type SuspendReason = "tab-hidden" | "off-screen" | "manual";
13
25
  /**
14
26
  * When the expensive WebGL path (context creation, shader compile + GPU link,
15
27
  * first uniform upload, rAF arm) actually runs.
@@ -51,4 +63,15 @@ export interface AuroraRuntimeOptions {
51
63
  */
52
64
  onInitError?: (err: Error) => void;
53
65
  }
54
- export declare function createAurora(canvas: HTMLCanvasElement, initial: AuroraConfig, options?: AuroraRuntimeOptions): AuroraInstance;
66
+ /**
67
+ * The concrete `createAurora` return shape. It IS an {@link AuroraInstance}
68
+ * (structurally assignable — every member matches) but widens `pause`/`resume`
69
+ * to carry an optional {@link SuspendReason}, defaulting to `"manual"`. The
70
+ * Vue wrapper passes `"off-screen"` for the intersection seam; a bare
71
+ * `pause()`/`resume()` reads identically to the `AuroraInstance` contract.
72
+ */
73
+ export interface AuroraRuntime extends Omit<AuroraInstance, "pause" | "resume"> {
74
+ pause(reason?: SuspendReason): void;
75
+ resume(reason?: SuspendReason): void;
76
+ }
77
+ export declare function createAurora(canvas: HTMLCanvasElement, initial: AuroraConfig, options?: AuroraRuntimeOptions): AuroraRuntime;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * <GlassDialogNative> — the native-`<dialog>` glass pilot (AQ.W6 §Design 5).
3
+ *
4
+ * A real `<dialog class="glass-top-layer">` top-layer surface. Entry/exit is
5
+ * PURE CSS from the `.glass-top-layer` grammar (`@starting-style` + `overlay` +
6
+ * `allow-discrete` + a glass `::backdrop`; animations.css §TOP-LAYER) — no
7
+ * per-frame JS, no `useSpringMount`. Light-dismiss is the native `closedby="any"`
8
+ * with a ≤ 12-LOC backdrop-click shim as the feature-detected fallback for
9
+ * engines without `HTMLDialogElement.closedBy`.
10
+ *
11
+ * DISPOSITION (W8 overfitting audit): this is the simple-confirm/settings PILOT
12
+ * only — one heading, optional short form, a close action. reka-ui `Dialog` is
13
+ * UNCHANGED and stays the default for every compound focus-trap case (nested
14
+ * focus zones, async content, the drag-dismiss `spring` opt-in). The pilot ships
15
+ * gated to a demo story (its consumer) pending the muster J.W6 ≥2-consumer
16
+ * adoption; it is NOT on the public barrel or a flat subpath yet (no overfit
17
+ * surface). `commandfor`/`command` (Baseline LIMITED) is the PREFERRED trigger
18
+ * wiring where supported; the JS `showModal()`/`close()` path (exposed below)
19
+ * is the kept default for non-supporting targets.
20
+ *
21
+ * Baseline: `<dialog>` + `showModal` = Widely; `dialog-closedby` = Newly
22
+ * (≤ 20-LOC shim fallback); `invoker-commands` (`commandfor`) = LIMITED
23
+ * (progressive — the JS open path stays default).
24
+ */
25
+ type __VLS_Props = {
26
+ /** Light-dismiss on backdrop/Esc — `closedby="any"`. Default true. */
27
+ lightDismiss?: boolean;
28
+ /** id so a sibling `<button commandfor=… command="show-modal">` can
29
+ * target this dialog (the declarative-open path). */
30
+ id?: string;
31
+ /** `aria-labelledby` target — the id of the consumer's heading. */
32
+ labelledby?: string;
33
+ /** Class merged onto the `<dialog>` surface. */
34
+ class?: string;
35
+ };
36
+ declare function showModal(): void;
37
+ declare function close(returnValue?: string): void;
38
+ declare var __VLS_1: {
39
+ close: typeof close;
40
+ };
41
+ type __VLS_Slots = {} & {
42
+ default?: (props: typeof __VLS_1) => any;
43
+ };
44
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
45
+ showModal: typeof showModal;
46
+ close: typeof close;
47
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
48
+ lightDismiss: boolean;
49
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
50
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
51
+ declare const _default: typeof __VLS_export;
52
+ export default _default;
53
+ type __VLS_WithSlots<T, S> = T & {
54
+ new (): {
55
+ $slots: S;
56
+ };
57
+ };
@@ -0,0 +1 @@
1
+ export { default as GlassDialogNative } from "./GlassDialogNative.vue";
@@ -19,16 +19,26 @@ export interface UseLayerTransitionReturn {
19
19
  leavingLayer: Ref<string | null>;
20
20
  }
21
21
  /**
22
- * Coordinates simultaneous crossfade + FLIP size animation for
23
- * grid-stacked layer containers. Reusable at any nesting level.
22
+ * Coordinates the crossfade + size animation between grid-stacked dock layer
23
+ * panes. Reusable at any nesting level (the inner `<DockLayerGroup>` pair AND
24
+ * the outer GlassDock collapsed↔expanded pair).
24
25
  *
25
- * Algorithm on activeLayer change:
26
- * 1. Capture current container size
27
- * 2. Pin container to that size
28
- * 3. Swap classes: old layer leaving (absolute, fading out),
29
- * new layer active (relative, fading in)
30
- * 4. nextTick: measure new natural size, re-pin to old
31
- * 5. Animate to new size via CSS transition
32
- * 6. On transitionend(size), clear inline size
26
+ * AQ.W6 §Design 7 — the swap FORKS on View-Transitions support:
27
+ *
28
+ * - **Native path** (`document.startViewTransition` present): the layer swap is
29
+ * wrapped in `startViewTransition(() => mutate())`. The browser snapshots the
30
+ * container + panes (tagged `view-transition-name` in `dock.css`) and morphs
31
+ * the size + crossfades the pane content with ZERO `getBoundingClientRect`
32
+ * reads. No pin/measure/re-pin dance, no inline size, no rAF.
33
+ *
34
+ * - **Fallback path** (no `startViewTransition`): the existing axis-aware FLIP
35
+ * runs verbatim, KEPT as the sole feature-detected fallback (no alias — one
36
+ * path or the other runs per swap, never both):
37
+ * 1. Capture current container size
38
+ * 2. Pin container to that size
39
+ * 3. Swap classes: old layer → leaving, new layer → active
40
+ * 4. nextTick: measure new natural size, re-pin to old
41
+ * 5. Animate to new size via CSS transition
42
+ * 6. On transitionend(size), clear inline size
33
43
  */
34
44
  export declare function useLayerTransition(options: UseLayerTransitionOptions): UseLayerTransitionReturn;
@@ -40,14 +40,35 @@ type __VLS_Props = {
40
40
  * as "inside the dock".
41
41
  */
42
42
  keepDockOpen?: boolean;
43
+ /**
44
+ * AQ.W6 — opt into the native `interestfor` + `popover="hint"` path
45
+ * when the browser supports interest invokers. Default `false` →
46
+ * reka-ui `HoverCard` (the unchanged default). When `true` AND the
47
+ * engine supports interest invokers, the trigger carries
48
+ * `interestfor` (an implicit anchor) and the panel renders as a
49
+ * `popover="hint"` top-layer surface driven by the `.glass-top-layer`
50
+ * grammar. When `true` but unsupported, it falls straight through to
51
+ * the reka-ui HoverCard — zero behaviour change.
52
+ *
53
+ * Baseline: `interest-invokers` + `popover-hint` = LIMITED →
54
+ * progressive-enhancement only; reka-ui stays the default path. No
55
+ * polyfill (substrate cannot drag one).
56
+ */
57
+ native?: boolean;
43
58
  };
44
- declare var __VLS_14: {}, __VLS_16: {}, __VLS_30: {};
59
+ declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_20: {}, __VLS_22: {}, __VLS_36: {};
45
60
  type __VLS_Slots = {} & {
46
- trigger?: (props: typeof __VLS_14) => any;
61
+ trigger?: (props: typeof __VLS_1) => any;
62
+ } & {
63
+ default?: (props: typeof __VLS_3) => any;
64
+ } & {
65
+ content?: (props: typeof __VLS_5) => any;
66
+ } & {
67
+ trigger?: (props: typeof __VLS_20) => any;
47
68
  } & {
48
- default?: (props: typeof __VLS_16) => any;
69
+ default?: (props: typeof __VLS_22) => any;
49
70
  } & {
50
- content?: (props: typeof __VLS_30) => any;
71
+ content?: (props: typeof __VLS_36) => any;
51
72
  };
52
73
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
53
74
  "update:open": (open: boolean) => any;
@@ -60,6 +81,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
60
81
  closeDelay: number;
61
82
  hoverOpenDelay: number;
62
83
  keepDockOpen: boolean;
84
+ native: boolean;
63
85
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
64
86
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
65
87
  declare const _default: typeof __VLS_export;