@opencosmos/ui 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/.claude/CLAUDE.md +239 -0
  2. package/README.md +161 -0
  3. package/dist/cli.mjs +151 -0
  4. package/dist/dates.d.mts +20 -0
  5. package/dist/dates.d.ts +20 -0
  6. package/dist/dates.js +240 -0
  7. package/dist/dates.js.map +1 -0
  8. package/dist/dates.mjs +203 -0
  9. package/dist/dates.mjs.map +1 -0
  10. package/dist/dnd.d.mts +126 -0
  11. package/dist/dnd.d.ts +126 -0
  12. package/dist/dnd.js +274 -0
  13. package/dist/dnd.js.map +1 -0
  14. package/dist/dnd.mjs +250 -0
  15. package/dist/dnd.mjs.map +1 -0
  16. package/dist/fontThemes-Dh8mtXES.d.mts +868 -0
  17. package/dist/fontThemes-Dh8mtXES.d.ts +868 -0
  18. package/dist/forms.d.mts +38 -0
  19. package/dist/forms.d.ts +38 -0
  20. package/dist/forms.js +198 -0
  21. package/dist/forms.js.map +1 -0
  22. package/dist/forms.mjs +159 -0
  23. package/dist/forms.mjs.map +1 -0
  24. package/dist/hooks-1b8WaQf1.d.mts +225 -0
  25. package/dist/hooks-CKW8vE9H.d.ts +225 -0
  26. package/dist/hooks.d.mts +3 -0
  27. package/dist/hooks.d.ts +3 -0
  28. package/dist/hooks.js +971 -0
  29. package/dist/hooks.js.map +1 -0
  30. package/dist/hooks.mjs +943 -0
  31. package/dist/hooks.mjs.map +1 -0
  32. package/dist/index-DscTIrZ2.d.mts +29 -0
  33. package/dist/index-DscTIrZ2.d.ts +29 -0
  34. package/dist/index.d.mts +3382 -0
  35. package/dist/index.d.ts +3382 -0
  36. package/dist/index.js +15146 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/index.mjs +14802 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/providers-CXPDMsl7.d.mts +30 -0
  41. package/dist/providers-Dn_Msjvz.d.ts +30 -0
  42. package/dist/providers.d.mts +3 -0
  43. package/dist/providers.d.ts +3 -0
  44. package/dist/providers.js +1885 -0
  45. package/dist/providers.js.map +1 -0
  46. package/dist/providers.mjs +1859 -0
  47. package/dist/providers.mjs.map +1 -0
  48. package/dist/tables.d.mts +10 -0
  49. package/dist/tables.d.ts +10 -0
  50. package/dist/tables.js +248 -0
  51. package/dist/tables.js.map +1 -0
  52. package/dist/tables.mjs +218 -0
  53. package/dist/tables.mjs.map +1 -0
  54. package/dist/tokens.d.mts +1065 -0
  55. package/dist/tokens.d.ts +1065 -0
  56. package/dist/tokens.js +2637 -0
  57. package/dist/tokens.js.map +1 -0
  58. package/dist/tokens.mjs +2555 -0
  59. package/dist/tokens.mjs.map +1 -0
  60. package/dist/utils-CIIM7dAC.d.ts +986 -0
  61. package/dist/utils-Cs04sxth.d.mts +986 -0
  62. package/dist/utils.d.mts +4 -0
  63. package/dist/utils.d.ts +4 -0
  64. package/dist/utils.js +874 -0
  65. package/dist/utils.js.map +1 -0
  66. package/dist/utils.mjs +806 -0
  67. package/dist/utils.mjs.map +1 -0
  68. package/dist/validation-Bj1ye-v_.d.mts +114 -0
  69. package/dist/validation-Bj1ye-v_.d.ts +114 -0
  70. package/dist/webgl.d.mts +104 -0
  71. package/dist/webgl.d.ts +104 -0
  72. package/dist/webgl.js +226 -0
  73. package/dist/webgl.js.map +1 -0
  74. package/dist/webgl.mjs +195 -0
  75. package/dist/webgl.mjs.map +1 -0
  76. package/package.json +267 -0
  77. package/src/cli.ts +206 -0
  78. package/src/component-registry.ts +183 -0
  79. package/src/components/actions/Button.test.tsx +61 -0
  80. package/src/components/actions/Button.tsx +70 -0
  81. package/src/components/actions/Link.tsx +78 -0
  82. package/src/components/actions/Magnetic.tsx +68 -0
  83. package/src/components/actions/Toggle.test.tsx +40 -0
  84. package/src/components/actions/Toggle.tsx +47 -0
  85. package/src/components/actions/ToggleGroup.tsx +70 -0
  86. package/src/components/actions/index.ts +5 -0
  87. package/src/components/backgrounds/FaultyTerminal.tsx +426 -0
  88. package/src/components/backgrounds/OrbBackground.tsx +424 -0
  89. package/src/components/backgrounds/WarpBackground.tsx +358 -0
  90. package/src/components/backgrounds/index.ts +3 -0
  91. package/src/components/blocks/Hero.tsx +142 -0
  92. package/src/components/blocks/social/OpenGraphCard.tsx +243 -0
  93. package/src/components/cursor/SplashCursor.tsx +1315 -0
  94. package/src/components/cursor/TargetCursor.tsx +187 -0
  95. package/src/components/cursor/index.ts +2 -0
  96. package/src/components/data-display/AspectImage.tsx +73 -0
  97. package/src/components/data-display/Avatar.test.tsx +35 -0
  98. package/src/components/data-display/Avatar.tsx +55 -0
  99. package/src/components/data-display/Badge.test.tsx +43 -0
  100. package/src/components/data-display/Badge.tsx +84 -0
  101. package/src/components/data-display/Brand.tsx +123 -0
  102. package/src/components/data-display/Calendar.tsx +70 -0
  103. package/src/components/data-display/Card.test.tsx +92 -0
  104. package/src/components/data-display/Card.tsx +115 -0
  105. package/src/components/data-display/Code.tsx +210 -0
  106. package/src/components/data-display/CollapsibleCodeBlock.tsx +238 -0
  107. package/src/components/data-display/DataTable.tsx +119 -0
  108. package/src/components/data-display/DescriptionList.tsx +41 -0
  109. package/src/components/data-display/GitHubIcon.tsx +44 -0
  110. package/src/components/data-display/Heading.test.tsx +36 -0
  111. package/src/components/data-display/Heading.tsx +83 -0
  112. package/src/components/data-display/StatCard.tsx +195 -0
  113. package/src/components/data-display/Table.tsx +133 -0
  114. package/src/components/data-display/Text.test.tsx +48 -0
  115. package/src/components/data-display/Text.tsx +144 -0
  116. package/src/components/data-display/Timeline.tsx +194 -0
  117. package/src/components/data-display/TreeView.tsx +226 -0
  118. package/src/components/data-display/Typewriter.tsx +119 -0
  119. package/src/components/data-display/VariableWeightText.tsx +130 -0
  120. package/src/components/data-display/index.ts +19 -0
  121. package/src/components/feedback/Alert.test.tsx +44 -0
  122. package/src/components/feedback/Alert.tsx +65 -0
  123. package/src/components/feedback/EmptyState.tsx +113 -0
  124. package/src/components/feedback/Progress.test.tsx +60 -0
  125. package/src/components/feedback/Progress.tsx +30 -0
  126. package/src/components/feedback/ProgressBar.tsx +158 -0
  127. package/src/components/feedback/Skeleton.test.tsx +39 -0
  128. package/src/components/feedback/Skeleton.tsx +45 -0
  129. package/src/components/feedback/Sonner.tsx +28 -0
  130. package/src/components/feedback/Spinner.test.tsx +33 -0
  131. package/src/components/feedback/Spinner.tsx +99 -0
  132. package/src/components/feedback/Stepper.tsx +307 -0
  133. package/src/components/feedback/Toast/Toast.tsx +243 -0
  134. package/src/components/feedback/Toast/index.ts +2 -0
  135. package/src/components/feedback/index.ts +9 -0
  136. package/src/components/forms/Checkbox.test.tsx +40 -0
  137. package/src/components/forms/Checkbox.tsx +31 -0
  138. package/src/components/forms/ColorPicker.tsx +118 -0
  139. package/src/components/forms/Combobox.tsx +96 -0
  140. package/src/components/forms/DragDrop.tsx +440 -0
  141. package/src/components/forms/FileUpload.tsx +252 -0
  142. package/src/components/forms/FilterButton.tsx +65 -0
  143. package/src/components/forms/Form.tsx +197 -0
  144. package/src/components/forms/Input.test.tsx +46 -0
  145. package/src/components/forms/Input.tsx +43 -0
  146. package/src/components/forms/InputOTP.tsx +81 -0
  147. package/src/components/forms/Label.test.tsx +20 -0
  148. package/src/components/forms/Label.tsx +25 -0
  149. package/src/components/forms/RadioGroup.tsx +51 -0
  150. package/src/components/forms/SearchBar.tsx +215 -0
  151. package/src/components/forms/Select.test.tsx +118 -0
  152. package/src/components/forms/Select.tsx +274 -0
  153. package/src/components/forms/Slider.tsx +29 -0
  154. package/src/components/forms/Switch.test.tsx +76 -0
  155. package/src/components/forms/Switch.tsx +30 -0
  156. package/src/components/forms/TextField.tsx +152 -0
  157. package/src/components/forms/Textarea.test.tsx +41 -0
  158. package/src/components/forms/Textarea.tsx +29 -0
  159. package/src/components/forms/ThemeSwitcher.tsx +290 -0
  160. package/src/components/forms/ThemeToggle.tsx +151 -0
  161. package/src/components/forms/index.ts +19 -0
  162. package/src/components/layout/Accordion.test.tsx +66 -0
  163. package/src/components/layout/Accordion.tsx +64 -0
  164. package/src/components/layout/AspectRatio.tsx +7 -0
  165. package/src/components/layout/Carousel.tsx +277 -0
  166. package/src/components/layout/Collapsible.test.tsx +40 -0
  167. package/src/components/layout/Collapsible.tsx +31 -0
  168. package/src/components/layout/Container.test.tsx +45 -0
  169. package/src/components/layout/Container.tsx +99 -0
  170. package/src/components/layout/CustomizerPanel.tsx +400 -0
  171. package/src/components/layout/DatePicker.tsx +57 -0
  172. package/src/components/layout/Footer/Footer.tsx +175 -0
  173. package/src/components/layout/Footer/index.ts +2 -0
  174. package/src/components/layout/GlassSurface.tsx +82 -0
  175. package/src/components/layout/Grid.test.tsx +31 -0
  176. package/src/components/layout/Grid.tsx +130 -0
  177. package/src/components/layout/Header/Header.tsx +450 -0
  178. package/src/components/layout/Header/index.ts +2 -0
  179. package/src/components/layout/PageLayout.tsx +180 -0
  180. package/src/components/layout/PageTemplate.tsx +158 -0
  181. package/src/components/layout/Resizable.tsx +48 -0
  182. package/src/components/layout/ScrollArea.tsx +53 -0
  183. package/src/components/layout/Separator.test.tsx +28 -0
  184. package/src/components/layout/Separator.tsx +29 -0
  185. package/src/components/layout/Sidebar.tsx +171 -0
  186. package/src/components/layout/Stack.test.tsx +41 -0
  187. package/src/components/layout/Stack.tsx +89 -0
  188. package/src/components/layout/glass-surface.css +60 -0
  189. package/src/components/layout/index.ts +18 -0
  190. package/src/components/motion/AnimatedBeam.tsx +159 -0
  191. package/src/components/navigation/Breadcrumb.test.tsx +57 -0
  192. package/src/components/navigation/Breadcrumb.tsx +119 -0
  193. package/src/components/navigation/Breadcrumbs.tsx +221 -0
  194. package/src/components/navigation/Command.tsx +159 -0
  195. package/src/components/navigation/Menubar.tsx +115 -0
  196. package/src/components/navigation/NavLink.tsx +55 -0
  197. package/src/components/navigation/NavigationMenu.tsx +125 -0
  198. package/src/components/navigation/Pagination.tsx +121 -0
  199. package/src/components/navigation/SecondaryNav.tsx +100 -0
  200. package/src/components/navigation/Tabs.test.tsx +47 -0
  201. package/src/components/navigation/Tabs.tsx +60 -0
  202. package/src/components/navigation/TertiaryNav.tsx +90 -0
  203. package/src/components/navigation/index.ts +10 -0
  204. package/src/components/overlays/AlertDialog.test.tsx +69 -0
  205. package/src/components/overlays/AlertDialog.tsx +166 -0
  206. package/src/components/overlays/ContextMenu.tsx +243 -0
  207. package/src/components/overlays/Dialog.test.tsx +79 -0
  208. package/src/components/overlays/Dialog.tsx +158 -0
  209. package/src/components/overlays/Drawer.tsx +128 -0
  210. package/src/components/overlays/Dropdown.tsx +253 -0
  211. package/src/components/overlays/DropdownMenu.tsx +242 -0
  212. package/src/components/overlays/HoverCard.tsx +32 -0
  213. package/src/components/overlays/Modal.tsx +250 -0
  214. package/src/components/overlays/NotificationCenter.tsx +364 -0
  215. package/src/components/overlays/Popover.test.tsx +40 -0
  216. package/src/components/overlays/Popover.tsx +46 -0
  217. package/src/components/overlays/Sheet.tsx +163 -0
  218. package/src/components/overlays/Tooltip.test.tsx +33 -0
  219. package/src/components/overlays/Tooltip.tsx +32 -0
  220. package/src/components/overlays/index.ts +12 -0
  221. package/src/dates.ts +2 -0
  222. package/src/dnd.ts +1 -0
  223. package/src/forms.ts +1 -0
  224. package/src/globals.css +187 -0
  225. package/src/hooks/index.ts +6 -0
  226. package/src/hooks/useForm.ts +247 -0
  227. package/src/hooks/useMotionPreference.test.ts +102 -0
  228. package/src/hooks/useMotionPreference.ts +78 -0
  229. package/src/hooks/useTheme.ts +58 -0
  230. package/src/hooks.ts +9 -0
  231. package/src/index.ts +168 -0
  232. package/src/lib/animations.ts +356 -0
  233. package/src/lib/breadcrumbs.ts +94 -0
  234. package/src/lib/colors.ts +493 -0
  235. package/src/lib/store/customizer.ts +482 -0
  236. package/src/lib/store/index.ts +3 -0
  237. package/src/lib/store/theme.ts +55 -0
  238. package/src/lib/syntax-parser/index.ts +50 -0
  239. package/src/lib/syntax-parser/patterns.ts +64 -0
  240. package/src/lib/syntax-parser/tokenizer.ts +117 -0
  241. package/src/lib/syntax-parser/types.ts +27 -0
  242. package/src/lib/utils.ts +6 -0
  243. package/src/lib/validation.ts +204 -0
  244. package/src/lib/webgl/Color.ts +11 -0
  245. package/src/lib/webgl/Mesh.ts +41 -0
  246. package/src/lib/webgl/Program.ts +118 -0
  247. package/src/lib/webgl/Renderer.ts +51 -0
  248. package/src/lib/webgl/Triangle.ts +27 -0
  249. package/src/lib/webgl/Vec3.ts +18 -0
  250. package/src/lib/webgl/index.ts +13 -0
  251. package/src/nativewind-env.d.ts +1 -0
  252. package/src/providers/ThemeProvider.tsx +461 -0
  253. package/src/providers/index.ts +1 -0
  254. package/src/providers.ts +7 -0
  255. package/src/tables.ts +1 -0
  256. package/src/test/setup.ts +39 -0
  257. package/src/theme.css +158 -0
  258. package/src/tokens.ts +7 -0
  259. package/src/utils.ts +12 -0
  260. package/src/webgl.ts +1 -0
@@ -0,0 +1,424 @@
1
+ 'use client';
2
+
3
+ import { Mesh, Program, Renderer, Triangle, Vec3 } from '../../lib/webgl';
4
+ import { useEffect, useRef } from 'react';
5
+ import { cn } from '../../lib/utils';
6
+
7
+ /**
8
+ * Convert hex color to RGB vec3 (0-1 range) for shaders
9
+ */
10
+ function hexToRgb(hex: string): [number, number, number] {
11
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
12
+ if (!result) return [0, 0, 0];
13
+ return [
14
+ parseInt(result[1], 16) / 255,
15
+ parseInt(result[2], 16) / 255,
16
+ parseInt(result[3], 16) / 255,
17
+ ];
18
+ }
19
+
20
+ /**
21
+ * Get CSS variable value from document root
22
+ */
23
+ function getCSSVariable(name: string, fallback: string): string {
24
+ if (typeof window === 'undefined') return fallback;
25
+ const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
26
+ return value || fallback;
27
+ }
28
+
29
+ export interface OrbBackgroundProps {
30
+ className?: string;
31
+ hue?: number;
32
+ hoverIntensity?: number;
33
+ rotateOnHover?: boolean;
34
+ forceHoverState?: boolean;
35
+ /**
36
+ * Background color (hex). If not provided, uses CSS variable --color-background.
37
+ * @default undefined (reads from theme)
38
+ */
39
+ backgroundColor?: string;
40
+ /**
41
+ * Primary orb color (hex). Creates the main vibrant tone.
42
+ * @default '#9c43fe' (purple)
43
+ */
44
+ orbColor1?: string;
45
+ /**
46
+ * Secondary orb color (hex). Adds cool cyan tones.
47
+ * @default '#4cc2e9' (cyan)
48
+ */
49
+ orbColor2?: string;
50
+ /**
51
+ * Tertiary orb color (hex). Provides deep blue accent tones.
52
+ * @default '#101499' (deep blue)
53
+ */
54
+ orbColor3?: string;
55
+ }
56
+
57
+ export function OrbBackground({
58
+ className,
59
+ hue = 0,
60
+ hoverIntensity = 0.2,
61
+ rotateOnHover = true,
62
+ forceHoverState = false,
63
+ backgroundColor,
64
+ orbColor1,
65
+ orbColor2,
66
+ orbColor3,
67
+ }: OrbBackgroundProps) {
68
+ const ctnDom = useRef<HTMLDivElement>(null);
69
+
70
+ const vert = /* glsl */ `
71
+ precision highp float;
72
+ attribute vec2 position;
73
+ attribute vec2 uv;
74
+ varying vec2 vUv;
75
+ void main() {
76
+ vUv = uv;
77
+ gl_Position = vec4(position, 0.0, 1.0);
78
+ }
79
+ `;
80
+
81
+ const frag = /* glsl */ `
82
+ precision highp float;
83
+
84
+ uniform float iTime;
85
+ uniform vec3 iResolution;
86
+ uniform float hue;
87
+ uniform float hover;
88
+ uniform float rot;
89
+ uniform float hoverIntensity;
90
+ uniform vec3 backgroundColor;
91
+ // THEME-AWARE: Orb colors from theme (to revert: change back to const)
92
+ uniform vec3 orbColor1;
93
+ uniform vec3 orbColor2;
94
+ uniform vec3 orbColor3;
95
+ varying vec2 vUv;
96
+
97
+ vec3 rgb2yiq(vec3 c) {
98
+ float y = dot(c, vec3(0.299, 0.587, 0.114));
99
+ float i = dot(c, vec3(0.596, -0.274, -0.322));
100
+ float q = dot(c, vec3(0.211, -0.523, 0.312));
101
+ return vec3(y, i, q);
102
+ }
103
+
104
+ vec3 yiq2rgb(vec3 c) {
105
+ float r = c.x + 0.956 * c.y + 0.621 * c.z;
106
+ float g = c.x - 0.272 * c.y - 0.647 * c.z;
107
+ float b = c.x - 1.106 * c.y + 1.703 * c.z;
108
+ return vec3(r, g, b);
109
+ }
110
+
111
+ vec3 adjustHue(vec3 color, float hueDeg) {
112
+ float hueRad = hueDeg * 3.14159265 / 180.0;
113
+ vec3 yiq = rgb2yiq(color);
114
+ float cosA = cos(hueRad);
115
+ float sinA = sin(hueRad);
116
+ float i = yiq.y * cosA - yiq.z * sinA;
117
+ float q = yiq.y * sinA + yiq.z * cosA;
118
+ yiq.y = i;
119
+ yiq.z = q;
120
+ return yiq2rgb(yiq);
121
+ }
122
+
123
+ vec3 hash33(vec3 p3) {
124
+ p3 = fract(p3 * vec3(0.1031, 0.11369, 0.13787));
125
+ p3 += dot(p3, p3.yxz + 19.19);
126
+ return -1.0 + 2.0 * fract(vec3(
127
+ p3.x + p3.y,
128
+ p3.x + p3.z,
129
+ p3.y + p3.z
130
+ ) * p3.zyx);
131
+ }
132
+
133
+ float snoise3(vec3 p) {
134
+ const float K1 = 0.333333333;
135
+ const float K2 = 0.166666667;
136
+ vec3 i = floor(p + (p.x + p.y + p.z) * K1);
137
+ vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);
138
+ vec3 e = step(vec3(0.0), d0 - d0.yzx);
139
+ vec3 i1 = e * (1.0 - e.zxy);
140
+ vec3 i2 = 1.0 - e.zxy * (1.0 - e);
141
+ vec3 d1 = d0 - (i1 - K2);
142
+ vec3 d2 = d0 - (i2 - K1);
143
+ vec3 d3 = d0 - 0.5;
144
+ vec4 h = max(0.6 - vec4(
145
+ dot(d0, d0),
146
+ dot(d1, d1),
147
+ dot(d2, d2),
148
+ dot(d3, d3)
149
+ ), 0.0);
150
+ vec4 n = h * h * h * h * vec4(
151
+ dot(d0, hash33(i)),
152
+ dot(d1, hash33(i + i1)),
153
+ dot(d2, hash33(i + i2)),
154
+ dot(d3, hash33(i + 1.0))
155
+ );
156
+ return dot(vec4(31.316), n);
157
+ }
158
+
159
+ vec4 extractAlpha(vec3 colorIn) {
160
+ float a = max(max(colorIn.r, colorIn.g), colorIn.b);
161
+ return vec4(colorIn.rgb / (a + 1e-5), a);
162
+ }
163
+
164
+ // THEME-AWARE: Colors now come from uniforms (orbColor1, orbColor2, orbColor3)
165
+ // To revert to hardcoded: uncomment these and remove uniforms above
166
+ // const vec3 baseColor1 = vec3(0.611765, 0.262745, 0.996078);
167
+ // const vec3 baseColor2 = vec3(0.298039, 0.760784, 0.913725);
168
+ // const vec3 baseColor3 = vec3(0.062745, 0.078431, 0.600000);
169
+ const float innerRadius = 0.6;
170
+ const float noiseScale = 0.65;
171
+
172
+ float light1(float intensity, float attenuation, float dist) {
173
+ return intensity / (1.0 + dist * attenuation);
174
+ }
175
+
176
+ float light2(float intensity, float attenuation, float dist) {
177
+ return intensity / (1.0 + dist * dist * attenuation);
178
+ }
179
+
180
+ vec4 draw(vec2 uv) {
181
+ // THEME-AWARE: Use uniform colors instead of hardcoded consts
182
+ vec3 color1 = adjustHue(orbColor1, hue);
183
+ vec3 color2 = adjustHue(orbColor2, hue);
184
+ vec3 color3 = adjustHue(orbColor3, hue);
185
+
186
+ float ang = atan(uv.y, uv.x);
187
+ float len = length(uv);
188
+ float invLen = len > 0.0 ? 1.0 / len : 0.0;
189
+
190
+ float bgLuminance = dot(backgroundColor, vec3(0.299, 0.587, 0.114));
191
+
192
+ float n0 = snoise3(vec3(uv * noiseScale, iTime * 0.5)) * 0.5 + 0.5;
193
+ float r0 = mix(mix(innerRadius, 1.0, 0.4), mix(innerRadius, 1.0, 0.6), n0);
194
+ float d0 = distance(uv, (r0 * invLen) * uv);
195
+ float v0 = light1(1.0, 10.0, d0);
196
+
197
+ v0 *= smoothstep(r0 * 1.05, r0, len);
198
+ float innerFade = smoothstep(r0 * 0.8, r0 * 0.95, len);
199
+ v0 *= mix(innerFade, 1.0, bgLuminance * 0.7);
200
+ float cl = cos(ang + iTime * 2.0) * 0.5 + 0.5;
201
+
202
+ float a = iTime * -1.0;
203
+ vec2 pos = vec2(cos(a), sin(a)) * r0;
204
+ float d = distance(uv, pos);
205
+ float v1 = light2(1.5, 5.0, d);
206
+ v1 *= light1(1.0, 50.0, d0);
207
+
208
+ float v2 = smoothstep(1.0, mix(innerRadius, 1.0, n0 * 0.5), len);
209
+ float v3 = smoothstep(innerRadius, mix(innerRadius, 1.0, 0.5), len);
210
+
211
+ vec3 colBase = mix(color1, color2, cl);
212
+ float fadeAmount = mix(1.0, 0.1, bgLuminance);
213
+
214
+ vec3 darkCol = mix(color3, colBase, v0);
215
+ darkCol = (darkCol + v1) * v2 * v3;
216
+ darkCol = clamp(darkCol, 0.0, 1.0);
217
+
218
+ vec3 lightCol = (colBase + v1) * mix(1.0, v2 * v3, fadeAmount);
219
+ lightCol = mix(backgroundColor, lightCol, v0);
220
+ lightCol = clamp(lightCol, 0.0, 1.0);
221
+
222
+ vec3 finalCol = mix(darkCol, lightCol, bgLuminance);
223
+
224
+ return extractAlpha(finalCol);
225
+ }
226
+
227
+ vec4 mainImage(vec2 fragCoord) {
228
+ vec2 center = iResolution.xy * 0.5;
229
+ float size = min(iResolution.x, iResolution.y);
230
+ vec2 uv = (fragCoord - center) / size * 2.0;
231
+
232
+ float angle = rot;
233
+ float s = sin(angle);
234
+ float c = cos(angle);
235
+ uv = vec2(c * uv.x - s * uv.y, s * uv.x + c * uv.y);
236
+
237
+ uv.x += hover * hoverIntensity * 0.1 * sin(uv.y * 10.0 + iTime);
238
+ uv.y += hover * hoverIntensity * 0.1 * sin(uv.x * 10.0 + iTime);
239
+
240
+ return draw(uv);
241
+ }
242
+
243
+ void main() {
244
+ vec2 fragCoord = vUv * iResolution.xy;
245
+ vec4 col = mainImage(fragCoord);
246
+ gl_FragColor = vec4(col.rgb * col.a, col.a);
247
+ }
248
+ `;
249
+
250
+ useEffect(() => {
251
+ const container = ctnDom.current;
252
+ if (!container) return;
253
+
254
+ // ORIGINAL COLORS: Restored from original implementation
255
+ // Classic gradient: purple → cyan → deep blue
256
+ const bgColor = backgroundColor || getCSSVariable('--color-background', '#000000');
257
+ const color1 = orbColor1 || '#9c43fe'; // Purple (vec3(0.611765, 0.262745, 0.996078))
258
+ const color2 = orbColor2 || '#4cc2e9'; // Cyan (vec3(0.298039, 0.760784, 0.913725))
259
+ const color3 = orbColor3 || '#101499'; // Deep blue (vec3(0.062745, 0.078431, 0.600000))
260
+
261
+ // Convert hex to RGB vec3 for shader
262
+ const bgRgb = hexToRgb(bgColor);
263
+ const color1Rgb = hexToRgb(color1);
264
+ const color2Rgb = hexToRgb(color2);
265
+ const color3Rgb = hexToRgb(color3);
266
+
267
+ const renderer = new Renderer({ alpha: true, premultipliedAlpha: false });
268
+ const gl = renderer.gl;
269
+ gl.clearColor(0, 0, 0, 0);
270
+ container.appendChild(gl.canvas);
271
+
272
+ const geometry = new Triangle(gl);
273
+ const program = new Program(gl, {
274
+ vertex: vert,
275
+ fragment: frag,
276
+ uniforms: {
277
+ iTime: { value: 0 },
278
+ iResolution: {
279
+ value: new Vec3(gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height)
280
+ },
281
+ hue: { value: hue },
282
+ hover: { value: 0 },
283
+ rot: { value: 0 },
284
+ hoverIntensity: { value: hoverIntensity },
285
+ // THEME-AWARE: Pass theme colors to shader
286
+ backgroundColor: { value: new Vec3(...bgRgb) },
287
+ orbColor1: { value: new Vec3(...color1Rgb) },
288
+ orbColor2: { value: new Vec3(...color2Rgb) },
289
+ orbColor3: { value: new Vec3(...color3Rgb) }
290
+ }
291
+ });
292
+
293
+ const mesh = new Mesh(gl, { geometry, program });
294
+
295
+ function resize() {
296
+ if (!container) return;
297
+ const dpr = window.devicePixelRatio || 1;
298
+ const width = container.clientWidth;
299
+ const height = container.clientHeight;
300
+ renderer.setSize(width * dpr, height * dpr);
301
+ gl.canvas.style.width = width + 'px';
302
+ gl.canvas.style.height = height + 'px';
303
+ program.uniforms.iResolution.value.set(gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height);
304
+ }
305
+ window.addEventListener('resize', resize);
306
+ resize();
307
+
308
+ let targetHover = 0;
309
+ let lastTime = 0;
310
+ let currentRot = 0;
311
+ const rotationSpeed = 0.3;
312
+
313
+ const handleMouseMove = (e: MouseEvent) => {
314
+ if (!container) return;
315
+ const rect = container.getBoundingClientRect();
316
+ const x = e.clientX - rect.left;
317
+ const y = e.clientY - rect.top;
318
+ const width = rect.width;
319
+ const height = rect.height;
320
+ const size = Math.min(width, height);
321
+ const centerX = width / 2;
322
+ const centerY = height / 2;
323
+ const uvX = ((x - centerX) / size) * 2.0;
324
+ const uvY = ((y - centerY) / size) * 2.0;
325
+
326
+ if (Math.sqrt(uvX * uvX + uvY * uvY) < 1.0) {
327
+ targetHover = 1;
328
+ } else {
329
+ targetHover = 0;
330
+ }
331
+ };
332
+
333
+ const handleMouseLeave = () => {
334
+ targetHover = 0;
335
+ };
336
+
337
+ window.addEventListener('mousemove', handleMouseMove);
338
+ document.addEventListener('mouseleave', handleMouseLeave);
339
+
340
+ let rafId: number;
341
+ const update = (t: number) => {
342
+ rafId = requestAnimationFrame(update);
343
+ const dt = (t - lastTime) * 0.001;
344
+ lastTime = t;
345
+ program.uniforms.iTime.value = t * 0.001;
346
+ program.uniforms.hue.value = hue;
347
+ program.uniforms.hoverIntensity.value = hoverIntensity;
348
+
349
+ const effectiveHover = forceHoverState ? 1 : targetHover;
350
+ program.uniforms.hover.value += (effectiveHover - program.uniforms.hover.value) * 0.1;
351
+
352
+ if (rotateOnHover && effectiveHover > 0.5) {
353
+ currentRot += dt * rotationSpeed;
354
+ }
355
+ program.uniforms.rot.value = currentRot;
356
+
357
+ renderer.render({ scene: mesh });
358
+ };
359
+ rafId = requestAnimationFrame(update);
360
+
361
+ return () => {
362
+ cancelAnimationFrame(rafId);
363
+ window.removeEventListener('resize', resize);
364
+ window.removeEventListener('mousemove', handleMouseMove);
365
+ document.removeEventListener('mouseleave', handleMouseLeave);
366
+ if (container && gl.canvas.parentNode === container) {
367
+ container.removeChild(gl.canvas);
368
+ }
369
+ // container.removeChild(gl.canvas); // Handled above more safely
370
+ gl.getExtension('WEBGL_lose_context')?.loseContext();
371
+ };
372
+ }, [hue, hoverIntensity, rotateOnHover, forceHoverState, backgroundColor]);
373
+
374
+ return <div ref={ctnDom} className={cn("w-full h-full pointer-events-auto", className)} />;
375
+ }
376
+
377
+ function hslToRgb(h: number, s: number, l: number) {
378
+ let r, g, b;
379
+
380
+ if (s === 0) {
381
+ r = g = b = l;
382
+ } else {
383
+ const hue2rgb = (p: number, q: number, t: number) => {
384
+ if (t < 0) t += 1;
385
+ if (t > 1) t -= 1;
386
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
387
+ if (t < 1 / 2) return q;
388
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
389
+ return p;
390
+ };
391
+
392
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
393
+ const p = 2 * l - q;
394
+ r = hue2rgb(p, q, h + 1 / 3);
395
+ g = hue2rgb(p, q, h);
396
+ b = hue2rgb(p, q, h - 1 / 3);
397
+ }
398
+
399
+ return new Vec3(r, g, b);
400
+ }
401
+
402
+ function hexToVec3(color: string) {
403
+ if (color.startsWith('#')) {
404
+ const r = parseInt(color.slice(1, 3), 16) / 255;
405
+ const g = parseInt(color.slice(3, 5), 16) / 255;
406
+ const b = parseInt(color.slice(5, 7), 16) / 255;
407
+ return new Vec3(r, g, b);
408
+ }
409
+
410
+ const rgbMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
411
+ if (rgbMatch) {
412
+ return new Vec3(parseInt(rgbMatch[1]) / 255, parseInt(rgbMatch[2]) / 255, parseInt(rgbMatch[3]) / 255);
413
+ }
414
+
415
+ const hslMatch = color.match(/hsla?\((\d+),\s*(\d+)%,\s*(\d+)%/);
416
+ if (hslMatch) {
417
+ const h = parseInt(hslMatch[1]) / 360;
418
+ const s = parseInt(hslMatch[2]) / 100;
419
+ const l = parseInt(hslMatch[3]) / 100;
420
+ return hslToRgb(h, s, l);
421
+ }
422
+
423
+ return new Vec3(0, 0, 0);
424
+ }