@agent-native/toolkit 0.201.1 → 0.202.0-nightly-20261006033736

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 (229) hide show
  1. package/agent-native.eject.json +39 -12
  2. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/components.js +292 -23
  4. package/dist/app/agentkit/react/components.js.map +1 -1
  5. package/dist/app/agentkit/react/context.d.ts +5 -0
  6. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  7. package/dist/app/agentkit/react/context.js +5 -0
  8. package/dist/app/agentkit/react/context.js.map +1 -1
  9. package/dist/app/agentkit/react/styles.css +78 -3
  10. package/dist/app/auth/AuthPage.d.ts.map +1 -1
  11. package/dist/app/auth/AuthPage.js +7 -14
  12. package/dist/app/auth/AuthPage.js.map +1 -1
  13. package/dist/app/auth/server.d.ts +6 -0
  14. package/dist/app/auth/server.d.ts.map +1 -0
  15. package/dist/app/auth/server.js +19 -0
  16. package/dist/app/auth/server.js.map +1 -0
  17. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  18. package/dist/app/chat/AgentKitAssistantChat.js +164 -83
  19. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  20. package/dist/app/chat/AgentSidebar.d.ts +2 -1
  21. package/dist/app/chat/AgentSidebar.d.ts.map +1 -1
  22. package/dist/app/chat/AgentSidebar.js +2 -2
  23. package/dist/app/chat/AgentSidebar.js.map +1 -1
  24. package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
  25. package/dist/app/chat/agentkit-chat/guided-questions.js +13 -3
  26. package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
  27. package/dist/app/chat/chat/surface-types.d.ts +2 -0
  28. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  29. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  30. package/dist/app/i18n/catalogs/ar-SA.js +41 -0
  31. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  32. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  33. package/dist/app/i18n/catalogs/de-DE.js +41 -0
  34. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  35. package/dist/app/i18n/catalogs/en-US.d.ts +41 -0
  36. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  37. package/dist/app/i18n/catalogs/en-US.js +41 -0
  38. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  39. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  40. package/dist/app/i18n/catalogs/es-ES.js +41 -0
  41. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  42. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  43. package/dist/app/i18n/catalogs/fr-FR.js +41 -0
  44. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  45. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  46. package/dist/app/i18n/catalogs/hi-IN.js +41 -0
  47. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  48. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  49. package/dist/app/i18n/catalogs/ja-JP.js +41 -0
  50. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  51. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  52. package/dist/app/i18n/catalogs/ko-KR.js +41 -0
  53. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  54. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  55. package/dist/app/i18n/catalogs/pt-BR.js +41 -0
  56. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  57. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  58. package/dist/app/i18n/catalogs/zh-CN.js +41 -0
  59. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  60. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  61. package/dist/app/i18n/catalogs/zh-TW.js +41 -0
  62. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  63. package/dist/app/shared/StarfieldBackground.d.ts +1 -6
  64. package/dist/app/shared/StarfieldBackground.d.ts.map +1 -1
  65. package/dist/app/shared/StarfieldBackground.js +1 -368
  66. package/dist/app/shared/StarfieldBackground.js.map +1 -1
  67. package/dist/app/shared/WaveBackground.d.ts +5 -0
  68. package/dist/app/shared/WaveBackground.d.ts.map +1 -0
  69. package/dist/app/shared/WaveBackground.js +34 -0
  70. package/dist/app/shared/WaveBackground.js.map +1 -0
  71. package/dist/app/shared/WebGlWaveBackground.d.ts +9 -0
  72. package/dist/app/shared/WebGlWaveBackground.d.ts.map +1 -0
  73. package/dist/app/shared/WebGlWaveBackground.js +433 -0
  74. package/dist/app/shared/WebGlWaveBackground.js.map +1 -0
  75. package/dist/app/shared/index.d.ts +1 -0
  76. package/dist/app/shared/index.d.ts.map +1 -1
  77. package/dist/app/shared/index.js +1 -0
  78. package/dist/app/shared/index.js.map +1 -1
  79. package/dist/app/shared/ocean/bloom-blur.wgsl +43 -0
  80. package/dist/app/shared/ocean/bloom-blur.wgsl.js +1 -0
  81. package/dist/app/shared/ocean/bloom-bright.wgsl +21 -0
  82. package/dist/app/shared/ocean/bloom-bright.wgsl.js +1 -0
  83. package/dist/app/shared/ocean/bloom-composite.wgsl +40 -0
  84. package/dist/app/shared/ocean/bloom-composite.wgsl.js +1 -0
  85. package/dist/app/shared/ocean/brand-colors.d.ts +9 -0
  86. package/dist/app/shared/ocean/brand-colors.d.ts.map +1 -0
  87. package/dist/app/shared/ocean/brand-colors.js +45 -0
  88. package/dist/app/shared/ocean/brand-colors.js.map +1 -0
  89. package/dist/app/shared/ocean/camera.d.ts +5 -0
  90. package/dist/app/shared/ocean/camera.d.ts.map +1 -0
  91. package/dist/app/shared/ocean/camera.js +24 -0
  92. package/dist/app/shared/ocean/camera.js.map +1 -0
  93. package/dist/app/shared/ocean/hero-ocean-background.d.ts +8 -0
  94. package/dist/app/shared/ocean/hero-ocean-background.d.ts.map +1 -0
  95. package/dist/app/shared/ocean/hero-ocean-background.js +186 -0
  96. package/dist/app/shared/ocean/hero-ocean-background.js.map +1 -0
  97. package/dist/app/shared/ocean/ifft-stage.wgsl +36 -0
  98. package/dist/app/shared/ocean/ifft-stage.wgsl.js +1 -0
  99. package/dist/app/shared/ocean/initial-spectrum.wgsl +36 -0
  100. package/dist/app/shared/ocean/initial-spectrum.wgsl.js +1 -0
  101. package/dist/app/shared/ocean/noise.wgsl +24 -0
  102. package/dist/app/shared/ocean/noise.wgsl.js +1 -0
  103. package/dist/app/shared/ocean/normal-foam.wgsl +32 -0
  104. package/dist/app/shared/ocean/normal-foam.wgsl.js +1 -0
  105. package/dist/app/shared/ocean/ocean-colors.d.ts +6 -0
  106. package/dist/app/shared/ocean/ocean-colors.d.ts.map +1 -0
  107. package/dist/app/shared/ocean/ocean-colors.js +6 -0
  108. package/dist/app/shared/ocean/ocean-colors.js.map +1 -0
  109. package/dist/app/shared/ocean/ocean-common.wgsl +15 -0
  110. package/dist/app/shared/ocean/ocean-common.wgsl.js +1 -0
  111. package/dist/app/shared/ocean/ocean-graph.d.ts +12 -0
  112. package/dist/app/shared/ocean/ocean-graph.d.ts.map +1 -0
  113. package/dist/app/shared/ocean/ocean-graph.js +16 -0
  114. package/dist/app/shared/ocean/ocean-graph.js.map +1 -0
  115. package/dist/app/shared/ocean/particles.wgsl +139 -0
  116. package/dist/app/shared/ocean/particles.wgsl.js +1 -0
  117. package/dist/app/shared/ocean/present.wgsl +40 -0
  118. package/dist/app/shared/ocean/present.wgsl.js +1 -0
  119. package/dist/app/shared/ocean/renderer.d.ts +66 -0
  120. package/dist/app/shared/ocean/renderer.d.ts.map +1 -0
  121. package/dist/app/shared/ocean/renderer.js +535 -0
  122. package/dist/app/shared/ocean/renderer.js.map +1 -0
  123. package/dist/app/shared/ocean/spectrum.wgsl +35 -0
  124. package/dist/app/shared/ocean/spectrum.wgsl.js +1 -0
  125. package/dist/app/shared/ocean/tuning.d.ts +48 -0
  126. package/dist/app/shared/ocean/tuning.d.ts.map +1 -0
  127. package/dist/app/shared/ocean/tuning.js +74 -0
  128. package/dist/app/shared/ocean/tuning.js.map +1 -0
  129. package/dist/app/shared/ocean/webgpu-support.d.ts +3 -0
  130. package/dist/app/shared/ocean/webgpu-support.d.ts.map +1 -0
  131. package/dist/app/shared/ocean/webgpu-support.js +13 -0
  132. package/dist/app/shared/ocean/webgpu-support.js.map +1 -0
  133. package/dist/app/sharing/AccessRequestApprovalPage.d.ts +23 -0
  134. package/dist/app/sharing/AccessRequestApprovalPage.d.ts.map +1 -0
  135. package/dist/app/sharing/AccessRequestApprovalPage.js +95 -0
  136. package/dist/app/sharing/AccessRequestApprovalPage.js.map +1 -0
  137. package/dist/app/sharing/AccessRequestsSection.d.ts +5 -0
  138. package/dist/app/sharing/AccessRequestsSection.d.ts.map +1 -0
  139. package/dist/app/sharing/AccessRequestsSection.js +47 -0
  140. package/dist/app/sharing/AccessRequestsSection.js.map +1 -0
  141. package/dist/app/sharing/ResourceAccessScreen.d.ts +53 -0
  142. package/dist/app/sharing/ResourceAccessScreen.d.ts.map +1 -0
  143. package/dist/app/sharing/ResourceAccessScreen.js +132 -0
  144. package/dist/app/sharing/ResourceAccessScreen.js.map +1 -0
  145. package/dist/app/sharing/ShareButton.d.ts.map +1 -1
  146. package/dist/app/sharing/ShareButton.js +4 -2
  147. package/dist/app/sharing/ShareButton.js.map +1 -1
  148. package/dist/app/sharing/ShareDialog.d.ts.map +1 -1
  149. package/dist/app/sharing/ShareDialog.js +7 -5
  150. package/dist/app/sharing/ShareDialog.js.map +1 -1
  151. package/dist/app/sharing/index.d.ts +2 -0
  152. package/dist/app/sharing/index.d.ts.map +1 -1
  153. package/dist/app/sharing/index.js +2 -0
  154. package/dist/app/sharing/index.js.map +1 -1
  155. package/dist/app/styles/agent-native.css +21 -1
  156. package/dist/app/styles/tokens/agent-kit.css +3 -1
  157. package/dist/composer/AgentSuggestionBar.d.ts +1 -1
  158. package/dist/composer/AgentSuggestionBar.d.ts.map +1 -1
  159. package/dist/composer/AgentSuggestionBar.js +75 -6
  160. package/dist/composer/AgentSuggestionBar.js.map +1 -1
  161. package/package.json +14 -4
  162. package/src/app/agentkit/react/components.tsx +492 -60
  163. package/src/app/agentkit/react/context.tsx +10 -0
  164. package/src/app/agentkit/react/lifecycle.spec.tsx +487 -1
  165. package/src/app/agentkit/react/styles.css +78 -3
  166. package/src/app/auth/AuthPage.spec.tsx +11 -7
  167. package/src/app/auth/AuthPage.tsx +16 -35
  168. package/src/app/auth/server.spec.ts +68 -0
  169. package/src/app/auth/server.ts +29 -0
  170. package/src/app/chat/AgentKitAssistantChat.spec.tsx +287 -290
  171. package/src/app/chat/AgentKitAssistantChat.tsx +219 -116
  172. package/src/app/chat/AgentSidebar.tsx +3 -0
  173. package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +85 -0
  174. package/src/app/chat/agentkit-chat/guided-questions.tsx +12 -5
  175. package/src/app/chat/chat/surface-types.ts +2 -0
  176. package/src/app/i18n/catalogs/ar-SA.ts +44 -0
  177. package/src/app/i18n/catalogs/de-DE.ts +55 -0
  178. package/src/app/i18n/catalogs/en-US.ts +46 -0
  179. package/src/app/i18n/catalogs/es-ES.ts +53 -0
  180. package/src/app/i18n/catalogs/fr-FR.ts +53 -0
  181. package/src/app/i18n/catalogs/hi-IN.ts +47 -0
  182. package/src/app/i18n/catalogs/ja-JP.ts +54 -0
  183. package/src/app/i18n/catalogs/ko-KR.ts +50 -0
  184. package/src/app/i18n/catalogs/pt-BR.ts +52 -0
  185. package/src/app/i18n/catalogs/zh-CN.ts +42 -0
  186. package/src/app/i18n/catalogs/zh-TW.ts +43 -0
  187. package/src/app/shared/StarfieldBackground.tsx +4 -423
  188. package/src/app/shared/WaveBackground.spec.tsx +104 -0
  189. package/src/app/shared/WaveBackground.tsx +60 -0
  190. package/src/app/shared/WebGlWaveBackground.spec.tsx +106 -0
  191. package/src/app/shared/WebGlWaveBackground.tsx +499 -0
  192. package/src/app/shared/index.ts +1 -0
  193. package/src/app/shared/ocean/bloom-blur.wgsl +43 -0
  194. package/src/app/shared/ocean/bloom-bright.wgsl +21 -0
  195. package/src/app/shared/ocean/bloom-composite.wgsl +40 -0
  196. package/src/app/shared/ocean/brand-colors.ts +49 -0
  197. package/src/app/shared/ocean/camera.ts +28 -0
  198. package/src/app/shared/ocean/hero-ocean-background.spec.tsx +369 -0
  199. package/src/app/shared/ocean/hero-ocean-background.tsx +238 -0
  200. package/src/app/shared/ocean/ifft-stage.wgsl +36 -0
  201. package/src/app/shared/ocean/initial-spectrum.wgsl +36 -0
  202. package/src/app/shared/ocean/noise.wgsl +24 -0
  203. package/src/app/shared/ocean/normal-foam.wgsl +32 -0
  204. package/src/app/shared/ocean/ocean-colors.ts +11 -0
  205. package/src/app/shared/ocean/ocean-common.wgsl +15 -0
  206. package/src/app/shared/ocean/ocean-graph.ts +29 -0
  207. package/src/app/shared/ocean/particles.wgsl +139 -0
  208. package/src/app/shared/ocean/present.wgsl +40 -0
  209. package/src/app/shared/ocean/renderer.spec.ts +100 -0
  210. package/src/app/shared/ocean/renderer.ts +693 -0
  211. package/src/app/shared/ocean/spectrum.wgsl +35 -0
  212. package/src/app/shared/ocean/tuning.ts +131 -0
  213. package/src/app/shared/ocean/webgpu-support.ts +12 -0
  214. package/src/app/sharing/AccessRequestApprovalPage.spec.tsx +276 -0
  215. package/src/app/sharing/AccessRequestApprovalPage.tsx +307 -0
  216. package/src/app/sharing/AccessRequestsSection.tsx +163 -0
  217. package/src/app/sharing/ResourceAccessScreen.spec.tsx +235 -0
  218. package/src/app/sharing/ResourceAccessScreen.tsx +331 -0
  219. package/src/app/sharing/ShareButton.spec.tsx +171 -5
  220. package/src/app/sharing/ShareButton.tsx +15 -2
  221. package/src/app/sharing/ShareDialog.spec.tsx +71 -2
  222. package/src/app/sharing/ShareDialog.tsx +24 -2
  223. package/src/app/sharing/index.ts +2 -0
  224. package/src/app/styles/agent-native.css +21 -1
  225. package/src/app/styles/agent-native.spec.ts +16 -3
  226. package/src/app/styles/tokens/agent-kit.css +3 -1
  227. package/src/composer/AgentSuggestionBar.overflow.spec.tsx +277 -0
  228. package/src/composer/AgentSuggestionBar.tsx +113 -8
  229. package/src/wgsl-env.d.ts +6 -0
@@ -0,0 +1,60 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+
3
+ import { HeroOceanBackground } from "./ocean/hero-ocean-background.js";
4
+ import { probeWebgpuSupport } from "./ocean/webgpu-support.js";
5
+ import { WebGlWaveBackground } from "./WebGlWaveBackground.js";
6
+
7
+ type Background = "probing" | "ocean-loading" | "ocean" | "fallback";
8
+
9
+ export interface WaveBackgroundProps {
10
+ className?: string;
11
+ }
12
+
13
+ export function WaveBackground({ className = "" }: WaveBackgroundProps) {
14
+ const [background, setBackground] = useState<Background>("probing");
15
+
16
+ useEffect(() => {
17
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)");
18
+ if (reduced?.matches) {
19
+ setBackground("fallback");
20
+ return;
21
+ }
22
+
23
+ let cancelled = false;
24
+ void probeWebgpuSupport().then((support) => {
25
+ if (!cancelled) {
26
+ setBackground(support === "supported" ? "ocean-loading" : "fallback");
27
+ }
28
+ });
29
+
30
+ const demoteToFallback = () => {
31
+ if (!cancelled) setBackground("fallback");
32
+ };
33
+ reduced?.addEventListener("change", demoteToFallback);
34
+ return () => {
35
+ cancelled = true;
36
+ reduced?.removeEventListener("change", demoteToFallback);
37
+ };
38
+ }, []);
39
+
40
+ const handleOceanError = useCallback(() => setBackground("fallback"), []);
41
+ const handleOceanReady = useCallback(() => setBackground("ocean"), []);
42
+
43
+ return (
44
+ <>
45
+ {background !== "ocean" ? (
46
+ <WebGlWaveBackground
47
+ className={className}
48
+ style={{ opacity: "var(--b-hero-shader-opacity, 0.3)" }}
49
+ />
50
+ ) : null}
51
+ {background === "ocean-loading" || background === "ocean" ? (
52
+ <HeroOceanBackground
53
+ className={className}
54
+ onError={handleOceanError}
55
+ onReady={handleOceanReady}
56
+ />
57
+ ) : null}
58
+ </>
59
+ );
60
+ }
@@ -0,0 +1,106 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { act, cleanup, render } from "@testing-library/react";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+
6
+ import { WebGlWaveBackground } from "./WebGlWaveBackground.js";
7
+
8
+ let intersectionObserver: TestIntersectionObserver | undefined;
9
+
10
+ class TestIntersectionObserver {
11
+ constructor(private readonly callback: IntersectionObserverCallback) {
12
+ intersectionObserver = this;
13
+ }
14
+
15
+ observe = vi.fn();
16
+ disconnect = vi.fn();
17
+ unobserve = vi.fn();
18
+ takeRecords = () => [];
19
+
20
+ notify(isIntersecting: boolean) {
21
+ this.callback(
22
+ [{ isIntersecting } as IntersectionObserverEntry],
23
+ this as unknown as IntersectionObserver,
24
+ );
25
+ }
26
+ }
27
+
28
+ afterEach(() => {
29
+ cleanup();
30
+ vi.restoreAllMocks();
31
+ vi.unstubAllGlobals();
32
+ intersectionObserver = undefined;
33
+ });
34
+
35
+ describe("WebGlWaveBackground", () => {
36
+ it("stops requesting frames while outside the viewport", () => {
37
+ let nextFrameId = 0;
38
+ const callbacks = new Map<number, FrameRequestCallback>();
39
+ const requestFrame = vi.fn((callback: FrameRequestCallback) => {
40
+ const id = ++nextFrameId;
41
+ callbacks.set(id, callback);
42
+ return id;
43
+ });
44
+ const cancelFrame = vi.fn((id: number) => callbacks.delete(id));
45
+ const gl = {
46
+ ARRAY_BUFFER: 34962,
47
+ COMPILE_STATUS: 35713,
48
+ FRAGMENT_SHADER: 35632,
49
+ LINK_STATUS: 35714,
50
+ STATIC_DRAW: 35044,
51
+ TRIANGLES: 4,
52
+ VERTEX_SHADER: 35633,
53
+ attachShader: vi.fn(),
54
+ bindBuffer: vi.fn(),
55
+ bufferData: vi.fn(),
56
+ compileShader: vi.fn(),
57
+ createBuffer: vi.fn(() => ({})),
58
+ createProgram: vi.fn(() => ({})),
59
+ createShader: vi.fn(() => ({})),
60
+ deleteBuffer: vi.fn(),
61
+ deleteProgram: vi.fn(),
62
+ deleteShader: vi.fn(),
63
+ drawArrays: vi.fn(),
64
+ enableVertexAttribArray: vi.fn(),
65
+ getAttribLocation: vi.fn(() => 0),
66
+ getExtension: vi.fn(() => ({ loseContext: vi.fn() })),
67
+ getProgramParameter: vi.fn(() => true),
68
+ getShaderParameter: vi.fn(() => true),
69
+ getUniformLocation: vi.fn(() => ({})),
70
+ linkProgram: vi.fn(),
71
+ shaderSource: vi.fn(),
72
+ uniform1f: vi.fn(),
73
+ uniform2f: vi.fn(),
74
+ uniform3f: vi.fn(),
75
+ useProgram: vi.fn(),
76
+ vertexAttribPointer: vi.fn(),
77
+ viewport: vi.fn(),
78
+ } as unknown as WebGLRenderingContext;
79
+
80
+ vi.stubGlobal("IntersectionObserver", TestIntersectionObserver);
81
+ vi.stubGlobal("requestAnimationFrame", requestFrame);
82
+ vi.stubGlobal("cancelAnimationFrame", cancelFrame);
83
+ vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockImplementation(
84
+ (() => gl) as typeof HTMLCanvasElement.prototype.getContext,
85
+ );
86
+
87
+ render(<WebGlWaveBackground />);
88
+
89
+ expect(intersectionObserver).toBeDefined();
90
+ act(() => intersectionObserver?.notify(false));
91
+ expect(requestFrame).not.toHaveBeenCalled();
92
+
93
+ act(() => intersectionObserver?.notify(true));
94
+ expect(requestFrame).toHaveBeenCalledTimes(1);
95
+
96
+ act(() => callbacks.get(1)?.(40));
97
+ expect(requestFrame).toHaveBeenCalledTimes(2);
98
+
99
+ const cancelledCallback = callbacks.get(2);
100
+ act(() => intersectionObserver?.notify(false));
101
+ expect(cancelFrame).toHaveBeenCalledWith(2);
102
+
103
+ act(() => cancelledCallback?.(80));
104
+ expect(requestFrame).toHaveBeenCalledTimes(2);
105
+ });
106
+ });
@@ -0,0 +1,499 @@
1
+ import { useEffect, useRef } from "react";
2
+ import type { CSSProperties } from "react";
3
+
4
+ const vertexShader = `
5
+ attribute vec2 position;
6
+ void main() {
7
+ gl_Position = vec4(position, 0.0, 1.0);
8
+ }
9
+ `;
10
+
11
+ const fragmentShader = `
12
+ precision highp float;
13
+
14
+ uniform float iTime;
15
+ uniform vec2 iResolution;
16
+ uniform vec3 uPointer;
17
+ uniform vec3 uFgColor;
18
+ uniform vec3 uBgColor;
19
+ uniform float uBrightness;
20
+ uniform float uTransparent;
21
+
22
+ #define S(a, b, t) smoothstep(a, b, t)
23
+
24
+ const float WAVE_COUNT = 5.;
25
+ const float WAVE_SCALE = 5.5;
26
+ const float FLOW_ANGLE = 119.;
27
+ const float WARP = 0.35;
28
+ const float SPEED = 0.65;
29
+ const float FOCUS_FOLLOW = 0.65;
30
+ const vec2 FOCUS = vec2(0., -0.05);
31
+ const float SPREAD = 1.2;
32
+ const float DOT_DENSITY = 131.;
33
+ const float DOT_SCALE = 1.35;
34
+ const float GLOW = 1.;
35
+ const float SEED = 56.;
36
+ const float VIGNETTE = 1.7;
37
+ const float TONE_GAMMA = 2.6;
38
+ const float FADE_IN_SECONDS = 0.7;
39
+
40
+ float N21(vec2 p) {
41
+ p += SEED;
42
+ vec3 a = fract(vec3(p.xyx) * vec3(213.897, 653.453, 253.098));
43
+ a += dot(a, a.yzx + 79.76);
44
+ return fract((a.x + a.y) * a.z);
45
+ }
46
+
47
+ float valueNoise(vec2 p) {
48
+ vec2 cell = floor(p);
49
+ vec2 f = fract(p);
50
+ float a = N21(cell);
51
+ float b = N21(cell + vec2(1., 0.));
52
+ float c = N21(cell + vec2(0., 1.));
53
+ float d = N21(cell + vec2(1., 1.));
54
+ vec2 u = f * f * (3. - 2. * f);
55
+ return mix(a, b, u.x) + (c - a) * u.y * (1. - u.x) + (d - b) * u.x * u.y;
56
+ }
57
+
58
+ float waveField(vec2 p, float t) {
59
+ float angle = radians(FLOW_ANGLE);
60
+ vec2 dir = vec2(cos(angle), sin(angle));
61
+ vec2 perp = vec2(-dir.y, dir.x);
62
+ vec2 warpUv = p * 1.1 + vec2(t * 0.14, t * 0.1);
63
+ float n1 = valueNoise(warpUv);
64
+ float n2 = valueNoise(warpUv + 5.2);
65
+ vec2 warped = p + (vec2(n1, n2) - 0.5) * WARP;
66
+ float along = dot(warped, dir);
67
+ float across = dot(warped, perp);
68
+ float field = 0.;
69
+ float weight = 0.;
70
+ for (float i = 0.; i < WAVE_COUNT; i += 1.) {
71
+ float amp = 1. / (1. + i * 0.8);
72
+ float freq = WAVE_SCALE * (1. + i * 0.55);
73
+ float drift = t * (1. + i * 0.23) + i * 2.399963;
74
+ float cross = sin(across * freq * 0.45 - drift * 0.7);
75
+ field += amp * sin(along * freq + drift + cross * 1.3);
76
+ weight += amp;
77
+ }
78
+ return clamp(field / max(weight, 0.001) * 0.5 + 0.5, 0., 1.);
79
+ }
80
+
81
+ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
82
+ vec2 uv = (fragCoord - iResolution.xy * .5) / iResolution.y;
83
+ vec2 pointerUv = (uPointer.xy - iResolution.xy * .5) / iResolution.y;
84
+ float t = iTime * SPEED;
85
+ float cellSize = 1. / DOT_DENSITY;
86
+ vec2 cell = floor(uv / cellSize);
87
+ vec2 cellCenter = (cell + 0.5) * cellSize;
88
+ vec2 cellUv = (uv - cellCenter) / cellSize;
89
+ float tone = waveField(cellCenter, t);
90
+ vec2 focus = FOCUS + (pointerUv - FOCUS) * FOCUS_FOLLOW * uPointer.z;
91
+ float distFromFocus = length(cellCenter - focus) / SPREAD;
92
+ tone *= exp(-1.6 * distFromFocus * distFromFocus);
93
+ tone = pow(clamp(tone, 0., 1.), TONE_GAMMA);
94
+ float radius = sqrt(tone) * 0.5 * DOT_SCALE;
95
+ float px = (1. / iResolution.y) / cellSize;
96
+ float edge = max(px * 1.2, 0.004);
97
+ float dist = length(cellUv);
98
+ float dotMask = step(0.0001, tone) * (1. - S(radius - edge, radius + edge, dist));
99
+ float glowTerm = (1. - S(radius, radius + GLOW * 0.9, dist)) * GLOW * tone;
100
+ float value = clamp(dotMask + glowTerm * 0.6, 0., 1.);
101
+ value *= clamp(1. - dot(uv, uv) * VIGNETTE, 0., 1.);
102
+ value *= S(0., FADE_IN_SECONDS, iTime);
103
+ vec3 lit = mix(uBgColor, uFgColor, value);
104
+ lit += (uFgColor - uBgColor) * value * tone * (uBrightness - 1.);
105
+ if (uTransparent > 0.5) {
106
+ float alpha = clamp(value, 0., 1.);
107
+ vec3 waveColor = uBgColor + (uFgColor - uBgColor) * (1. + tone * (uBrightness - 1.));
108
+ fragColor = vec4(clamp(waveColor, 0., 1.) * alpha, alpha);
109
+ } else {
110
+ fragColor = vec4(clamp(lit, 0., 1.), 1.);
111
+ }
112
+ }
113
+
114
+ void main() {
115
+ mainImage(gl_FragColor, gl_FragCoord.xy);
116
+ }
117
+ `;
118
+
119
+ let shaderEpoch = 0;
120
+
121
+ export interface WebGlWaveBackgroundProps {
122
+ className?: string;
123
+ frameRate?: number;
124
+ transparent?: boolean;
125
+ style?: CSSProperties;
126
+ }
127
+
128
+ function hexToRgb01(hex: string): [number, number, number] | null {
129
+ const normalized = hex.trim().replace(/^#/, "");
130
+ if (!/^(?:[\da-f]{3}|[\da-f]{6})$/i.test(normalized)) return null;
131
+ const full =
132
+ normalized.length === 3
133
+ ? normalized
134
+ .split("")
135
+ .map((part) => `${part}${part}`)
136
+ .join("")
137
+ : normalized;
138
+ const value = Number.parseInt(full, 16);
139
+ return [
140
+ ((value >> 16) & 255) / 255,
141
+ ((value >> 8) & 255) / 255,
142
+ (value & 255) / 255,
143
+ ];
144
+ }
145
+
146
+ export function WebGlWaveBackground({
147
+ className = "",
148
+ frameRate = 30,
149
+ transparent = false,
150
+ style,
151
+ }: WebGlWaveBackgroundProps) {
152
+ const containerRef = useRef<HTMLDivElement>(null);
153
+ const canvasRef = useRef<HTMLCanvasElement>(null);
154
+ const rafRef = useRef<number>(0);
155
+
156
+ useEffect(() => {
157
+ const canvasRaw = canvasRef.current;
158
+ const containerRaw = containerRef.current;
159
+ if (!canvasRaw || !containerRaw) return;
160
+ const canvas: HTMLCanvasElement = canvasRaw;
161
+ const container: HTMLElement = containerRaw;
162
+
163
+ const glRaw = canvas.getContext("webgl", {
164
+ alpha: transparent,
165
+ antialias: false,
166
+ preserveDrawingBuffer: false,
167
+ });
168
+ if (!glRaw) return;
169
+ const gl: WebGLRenderingContext = glRaw;
170
+
171
+ function compileShader(type: number, src: string) {
172
+ const shader = gl.createShader(type);
173
+ if (!shader) return null;
174
+ gl.shaderSource(shader, src);
175
+ gl.compileShader(shader);
176
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
177
+ console.error(gl.getShaderInfoLog(shader));
178
+ gl.deleteShader(shader);
179
+ return null;
180
+ }
181
+ return shader;
182
+ }
183
+
184
+ const vs = compileShader(gl.VERTEX_SHADER, vertexShader);
185
+ const fs = compileShader(gl.FRAGMENT_SHADER, fragmentShader);
186
+ if (!vs || !fs) return;
187
+
188
+ const program = gl.createProgram();
189
+ if (!program) return;
190
+ gl.attachShader(program, vs);
191
+ gl.attachShader(program, fs);
192
+ gl.linkProgram(program);
193
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
194
+ console.error(gl.getProgramInfoLog(program));
195
+ gl.deleteProgram(program);
196
+ gl.deleteShader(vs);
197
+ gl.deleteShader(fs);
198
+ return;
199
+ }
200
+ gl.useProgram(program);
201
+
202
+ const buf = gl.createBuffer();
203
+ if (!buf) {
204
+ gl.deleteProgram(program);
205
+ gl.deleteShader(vs);
206
+ gl.deleteShader(fs);
207
+ return;
208
+ }
209
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
210
+ gl.bufferData(
211
+ gl.ARRAY_BUFFER,
212
+ new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),
213
+ gl.STATIC_DRAW,
214
+ );
215
+ const pos = gl.getAttribLocation(program, "position");
216
+ gl.enableVertexAttribArray(pos);
217
+ gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
218
+
219
+ const uTime = gl.getUniformLocation(program, "iTime");
220
+ const uRes = gl.getUniformLocation(program, "iResolution");
221
+ const uPointer = gl.getUniformLocation(program, "uPointer");
222
+ const uFgColor = gl.getUniformLocation(program, "uFgColor");
223
+ const uBgColor = gl.getUniformLocation(program, "uBgColor");
224
+ const uBrightness = gl.getUniformLocation(program, "uBrightness");
225
+ const uTransparent = gl.getUniformLocation(program, "uTransparent");
226
+ const reducedMotionQuery =
227
+ typeof window.matchMedia === "function"
228
+ ? window.matchMedia("(prefers-reduced-motion: reduce)")
229
+ : null;
230
+ let reducedMotion = reducedMotionQuery?.matches ?? false;
231
+
232
+ let dpr = 1;
233
+ let isVisible = false;
234
+ let visibilityObserver: IntersectionObserver | null = null;
235
+ let hasPointer = false;
236
+ let pointerX = 0;
237
+ let pointerY = 0;
238
+ let pointerStrength = 0;
239
+ let targetX = 0;
240
+ let targetY = 0;
241
+ let targetStrength = 0;
242
+
243
+ function readDarkMode() {
244
+ const root = document.documentElement;
245
+ if (root.classList.contains("dark")) return true;
246
+ if (root.classList.contains("light")) return false;
247
+ const dataTheme = root.getAttribute("data-theme");
248
+ if (dataTheme === "dark") return true;
249
+ if (dataTheme === "light") return false;
250
+ return (
251
+ window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false
252
+ );
253
+ }
254
+
255
+ function readTheme() {
256
+ const dark = readDarkMode();
257
+ const fallback = dark
258
+ ? {
259
+ bg: [10 / 255, 10 / 255, 10 / 255] as [number, number, number],
260
+ fg: [174 / 255, 173 / 255, 172 / 255] as [number, number, number],
261
+ brightness: 3,
262
+ }
263
+ : {
264
+ bg: [250 / 255, 249 / 255, 245 / 255] as [number, number, number],
265
+ fg: [0, 103 / 255, 127 / 255] as [number, number, number],
266
+ brightness: 1.15,
267
+ };
268
+ const styles = window.getComputedStyle(container);
269
+ const customBg = hexToRgb01(styles.getPropertyValue("--b-bg-page"));
270
+ const customFg = hexToRgb01(
271
+ styles.getPropertyValue("--b-hero-shader-fg"),
272
+ );
273
+ const customBrightness = Number.parseFloat(
274
+ styles.getPropertyValue("--b-hero-shader-brightness"),
275
+ );
276
+ return {
277
+ bg: customBg ?? fallback.bg,
278
+ fg: customFg ?? fallback.fg,
279
+ brightness: Number.isFinite(customBrightness)
280
+ ? customBrightness
281
+ : fallback.brightness,
282
+ };
283
+ }
284
+
285
+ let theme = readTheme();
286
+
287
+ function easePointer(allowPointer: boolean) {
288
+ if (!allowPointer) {
289
+ pointerStrength = 0;
290
+ return;
291
+ }
292
+ pointerX += (targetX - pointerX) * 0.12;
293
+ pointerY += (targetY - pointerY) * 0.12;
294
+ pointerStrength += (targetStrength - pointerStrength) * 0.08;
295
+ if (pointerStrength < 0.001 && targetStrength === 0) {
296
+ pointerStrength = 0;
297
+ }
298
+ }
299
+
300
+ function draw(timeSeconds: number, allowPointer = !reducedMotion) {
301
+ easePointer(allowPointer);
302
+ gl.uniform1f(uTime, timeSeconds);
303
+ gl.uniform2f(uRes, canvas.width, canvas.height);
304
+ gl.uniform3f(uPointer, pointerX, pointerY, pointerStrength);
305
+ gl.uniform3f(uFgColor, theme.fg[0], theme.fg[1], theme.fg[2]);
306
+ gl.uniform3f(uBgColor, theme.bg[0], theme.bg[1], theme.bg[2]);
307
+ gl.uniform1f(uBrightness, theme.brightness);
308
+ gl.uniform1f(uTransparent, transparent ? 1 : 0);
309
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
310
+ }
311
+
312
+ function resize() {
313
+ const w = container.clientWidth;
314
+ const h = container.clientHeight;
315
+ dpr = Math.min(window.devicePixelRatio, 1.5);
316
+ canvas.width = w * dpr;
317
+ canvas.height = h * dpr;
318
+ canvas.style.width = w + "px";
319
+ canvas.style.height = h + "px";
320
+ gl.viewport(0, 0, canvas.width, canvas.height);
321
+ if (!hasPointer) {
322
+ pointerX = targetX = canvas.width * 0.5;
323
+ pointerY = targetY = canvas.height * 0.5;
324
+ }
325
+ }
326
+
327
+ function handlePointerMove(event: PointerEvent | MouseEvent) {
328
+ const rect = container.getBoundingClientRect();
329
+ if (rect.width <= 0 || rect.height <= 0) return;
330
+
331
+ const x = event.clientX - rect.left;
332
+ const y = event.clientY - rect.top;
333
+ const inside = x >= 0 && x <= rect.width && y >= 0 && y <= rect.height;
334
+
335
+ hasPointer = true;
336
+ targetX = x * dpr;
337
+ targetY = (rect.height - y) * dpr;
338
+ targetStrength = inside ? 1 : 0;
339
+ }
340
+
341
+ function fadePointer() {
342
+ targetStrength = 0;
343
+ }
344
+
345
+ resize();
346
+ window.addEventListener("resize", resize);
347
+ const resizeObserver =
348
+ typeof ResizeObserver === "undefined" ? null : new ResizeObserver(resize);
349
+ resizeObserver?.observe(container);
350
+ window.addEventListener("pointermove", handlePointerMove, {
351
+ passive: true,
352
+ });
353
+ window.addEventListener("mousemove", handlePointerMove, {
354
+ passive: true,
355
+ });
356
+ document.addEventListener("pointerleave", fadePointer, {
357
+ passive: true,
358
+ });
359
+ window.addEventListener("blur", fadePointer);
360
+
361
+ const observer = new MutationObserver(() => {
362
+ theme = readTheme();
363
+ if (reducedMotion) draw(20, false);
364
+ });
365
+ observer.observe(document.documentElement, {
366
+ attributes: true,
367
+ attributeFilter: ["class", "data-theme"],
368
+ });
369
+
370
+ if (!shaderEpoch) shaderEpoch = performance.now();
371
+ const startTime = shaderEpoch;
372
+ let lastFrame = 0;
373
+ const frameBudget = 1000 / Math.max(1, frameRate);
374
+ const reducedMotionStaticTime = 20;
375
+
376
+ function render(now: number) {
377
+ rafRef.current = 0;
378
+ if (reducedMotion || !isVisible) return;
379
+ if (now - lastFrame >= frameBudget) {
380
+ lastFrame = now;
381
+ draw((now - startTime) * 0.001);
382
+ }
383
+ if (isVisible && !reducedMotion) {
384
+ rafRef.current = requestAnimationFrame(render);
385
+ }
386
+ }
387
+
388
+ function startAnimation() {
389
+ if (!reducedMotion && isVisible && !rafRef.current) {
390
+ rafRef.current = requestAnimationFrame(render);
391
+ }
392
+ }
393
+
394
+ function stopAnimation() {
395
+ if (rafRef.current) {
396
+ cancelAnimationFrame(rafRef.current);
397
+ rafRef.current = 0;
398
+ }
399
+ }
400
+
401
+ function updateVisibility(visible: boolean) {
402
+ isVisible = visible;
403
+ if (visible) startAnimation();
404
+ else stopAnimation();
405
+ }
406
+
407
+ function checkViewport() {
408
+ const rect = container.getBoundingClientRect();
409
+ updateVisibility(rect.bottom >= 0 && rect.top <= window.innerHeight);
410
+ }
411
+
412
+ if (typeof IntersectionObserver === "undefined") {
413
+ window.addEventListener("scroll", checkViewport, {
414
+ capture: true,
415
+ passive: true,
416
+ });
417
+ window.addEventListener("resize", checkViewport);
418
+ checkViewport();
419
+ } else {
420
+ visibilityObserver = new IntersectionObserver(
421
+ ([entry]) => updateVisibility(entry?.isIntersecting ?? false),
422
+ { threshold: 0 },
423
+ );
424
+ visibilityObserver.observe(container);
425
+ }
426
+
427
+ function handleReducedMotionChange() {
428
+ reducedMotion = reducedMotionQuery?.matches ?? false;
429
+ if (reducedMotion) {
430
+ stopAnimation();
431
+ lastFrame = 0;
432
+ draw(reducedMotionStaticTime, false);
433
+ } else {
434
+ startAnimation();
435
+ }
436
+ }
437
+
438
+ draw(
439
+ reducedMotion
440
+ ? reducedMotionStaticTime
441
+ : (performance.now() - startTime) * 0.001,
442
+ !reducedMotion,
443
+ );
444
+ if (reducedMotionQuery) {
445
+ reducedMotionQuery.addEventListener("change", handleReducedMotionChange);
446
+ }
447
+ if (!reducedMotion) startAnimation();
448
+
449
+ return () => {
450
+ stopAnimation();
451
+ if (reducedMotionQuery) {
452
+ reducedMotionQuery.removeEventListener(
453
+ "change",
454
+ handleReducedMotionChange,
455
+ );
456
+ }
457
+ observer.disconnect();
458
+ resizeObserver?.disconnect();
459
+ visibilityObserver?.disconnect();
460
+ if (!visibilityObserver) {
461
+ window.removeEventListener("scroll", checkViewport, true);
462
+ window.removeEventListener("resize", checkViewport);
463
+ }
464
+ window.removeEventListener("resize", resize);
465
+ window.removeEventListener("pointermove", handlePointerMove);
466
+ window.removeEventListener("mousemove", handlePointerMove);
467
+ document.removeEventListener("pointerleave", fadePointer);
468
+ window.removeEventListener("blur", fadePointer);
469
+ gl.deleteProgram(program);
470
+ gl.deleteShader(vs);
471
+ gl.deleteShader(fs);
472
+ gl.deleteBuffer(buf);
473
+ gl.getExtension("WEBGL_lose_context")?.loseContext();
474
+ };
475
+ }, [frameRate, transparent]);
476
+
477
+ return (
478
+ <div
479
+ ref={containerRef}
480
+ aria-hidden="true"
481
+ className={className}
482
+ style={{
483
+ width: "100%",
484
+ height: "100%",
485
+ pointerEvents: "none",
486
+ ...style,
487
+ }}
488
+ data-agent-native-wave
489
+ data-agent-native-starfield
490
+ data-agent-native-wave-transparent={transparent ? "true" : undefined}
491
+ data-agent-native-starfield-transparent={transparent ? "true" : undefined}
492
+ >
493
+ <canvas
494
+ ref={canvasRef}
495
+ style={{ display: "block", width: "100%", height: "100%" }}
496
+ />
497
+ </div>
498
+ );
499
+ }
@@ -16,4 +16,5 @@ export * from "./PrimitiveButton.js";
16
16
  export * from "./RouteTransitionIndicator.js";
17
17
  export * from "./RuntimeConfigNotice.js";
18
18
  export * from "./StarfieldBackground.js";
19
+ export * from "./WaveBackground.js";
19
20
  export * from "./Turnstile.js";