@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.
- package/agent-native.eject.json +39 -12
- package/dist/app/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +292 -23
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context.d.ts +5 -0
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +5 -0
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +78 -3
- package/dist/app/auth/AuthPage.d.ts.map +1 -1
- package/dist/app/auth/AuthPage.js +7 -14
- package/dist/app/auth/AuthPage.js.map +1 -1
- package/dist/app/auth/server.d.ts +6 -0
- package/dist/app/auth/server.d.ts.map +1 -0
- package/dist/app/auth/server.js +19 -0
- package/dist/app/auth/server.js.map +1 -0
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +164 -83
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/AgentSidebar.d.ts +2 -1
- package/dist/app/chat/AgentSidebar.d.ts.map +1 -1
- package/dist/app/chat/AgentSidebar.js +2 -2
- package/dist/app/chat/AgentSidebar.js.map +1 -1
- package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/guided-questions.js +13 -3
- package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
- package/dist/app/chat/chat/surface-types.d.ts +2 -0
- package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +41 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +41 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +41 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +41 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +41 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +41 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +41 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +41 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +41 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +41 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +41 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +41 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/shared/StarfieldBackground.d.ts +1 -6
- package/dist/app/shared/StarfieldBackground.d.ts.map +1 -1
- package/dist/app/shared/StarfieldBackground.js +1 -368
- package/dist/app/shared/StarfieldBackground.js.map +1 -1
- package/dist/app/shared/WaveBackground.d.ts +5 -0
- package/dist/app/shared/WaveBackground.d.ts.map +1 -0
- package/dist/app/shared/WaveBackground.js +34 -0
- package/dist/app/shared/WaveBackground.js.map +1 -0
- package/dist/app/shared/WebGlWaveBackground.d.ts +9 -0
- package/dist/app/shared/WebGlWaveBackground.d.ts.map +1 -0
- package/dist/app/shared/WebGlWaveBackground.js +433 -0
- package/dist/app/shared/WebGlWaveBackground.js.map +1 -0
- package/dist/app/shared/index.d.ts +1 -0
- package/dist/app/shared/index.d.ts.map +1 -1
- package/dist/app/shared/index.js +1 -0
- package/dist/app/shared/index.js.map +1 -1
- package/dist/app/shared/ocean/bloom-blur.wgsl +43 -0
- package/dist/app/shared/ocean/bloom-blur.wgsl.js +1 -0
- package/dist/app/shared/ocean/bloom-bright.wgsl +21 -0
- package/dist/app/shared/ocean/bloom-bright.wgsl.js +1 -0
- package/dist/app/shared/ocean/bloom-composite.wgsl +40 -0
- package/dist/app/shared/ocean/bloom-composite.wgsl.js +1 -0
- package/dist/app/shared/ocean/brand-colors.d.ts +9 -0
- package/dist/app/shared/ocean/brand-colors.d.ts.map +1 -0
- package/dist/app/shared/ocean/brand-colors.js +45 -0
- package/dist/app/shared/ocean/brand-colors.js.map +1 -0
- package/dist/app/shared/ocean/camera.d.ts +5 -0
- package/dist/app/shared/ocean/camera.d.ts.map +1 -0
- package/dist/app/shared/ocean/camera.js +24 -0
- package/dist/app/shared/ocean/camera.js.map +1 -0
- package/dist/app/shared/ocean/hero-ocean-background.d.ts +8 -0
- package/dist/app/shared/ocean/hero-ocean-background.d.ts.map +1 -0
- package/dist/app/shared/ocean/hero-ocean-background.js +186 -0
- package/dist/app/shared/ocean/hero-ocean-background.js.map +1 -0
- package/dist/app/shared/ocean/ifft-stage.wgsl +36 -0
- package/dist/app/shared/ocean/ifft-stage.wgsl.js +1 -0
- package/dist/app/shared/ocean/initial-spectrum.wgsl +36 -0
- package/dist/app/shared/ocean/initial-spectrum.wgsl.js +1 -0
- package/dist/app/shared/ocean/noise.wgsl +24 -0
- package/dist/app/shared/ocean/noise.wgsl.js +1 -0
- package/dist/app/shared/ocean/normal-foam.wgsl +32 -0
- package/dist/app/shared/ocean/normal-foam.wgsl.js +1 -0
- package/dist/app/shared/ocean/ocean-colors.d.ts +6 -0
- package/dist/app/shared/ocean/ocean-colors.d.ts.map +1 -0
- package/dist/app/shared/ocean/ocean-colors.js +6 -0
- package/dist/app/shared/ocean/ocean-colors.js.map +1 -0
- package/dist/app/shared/ocean/ocean-common.wgsl +15 -0
- package/dist/app/shared/ocean/ocean-common.wgsl.js +1 -0
- package/dist/app/shared/ocean/ocean-graph.d.ts +12 -0
- package/dist/app/shared/ocean/ocean-graph.d.ts.map +1 -0
- package/dist/app/shared/ocean/ocean-graph.js +16 -0
- package/dist/app/shared/ocean/ocean-graph.js.map +1 -0
- package/dist/app/shared/ocean/particles.wgsl +139 -0
- package/dist/app/shared/ocean/particles.wgsl.js +1 -0
- package/dist/app/shared/ocean/present.wgsl +40 -0
- package/dist/app/shared/ocean/present.wgsl.js +1 -0
- package/dist/app/shared/ocean/renderer.d.ts +66 -0
- package/dist/app/shared/ocean/renderer.d.ts.map +1 -0
- package/dist/app/shared/ocean/renderer.js +535 -0
- package/dist/app/shared/ocean/renderer.js.map +1 -0
- package/dist/app/shared/ocean/spectrum.wgsl +35 -0
- package/dist/app/shared/ocean/spectrum.wgsl.js +1 -0
- package/dist/app/shared/ocean/tuning.d.ts +48 -0
- package/dist/app/shared/ocean/tuning.d.ts.map +1 -0
- package/dist/app/shared/ocean/tuning.js +74 -0
- package/dist/app/shared/ocean/tuning.js.map +1 -0
- package/dist/app/shared/ocean/webgpu-support.d.ts +3 -0
- package/dist/app/shared/ocean/webgpu-support.d.ts.map +1 -0
- package/dist/app/shared/ocean/webgpu-support.js +13 -0
- package/dist/app/shared/ocean/webgpu-support.js.map +1 -0
- package/dist/app/sharing/AccessRequestApprovalPage.d.ts +23 -0
- package/dist/app/sharing/AccessRequestApprovalPage.d.ts.map +1 -0
- package/dist/app/sharing/AccessRequestApprovalPage.js +95 -0
- package/dist/app/sharing/AccessRequestApprovalPage.js.map +1 -0
- package/dist/app/sharing/AccessRequestsSection.d.ts +5 -0
- package/dist/app/sharing/AccessRequestsSection.d.ts.map +1 -0
- package/dist/app/sharing/AccessRequestsSection.js +47 -0
- package/dist/app/sharing/AccessRequestsSection.js.map +1 -0
- package/dist/app/sharing/ResourceAccessScreen.d.ts +53 -0
- package/dist/app/sharing/ResourceAccessScreen.d.ts.map +1 -0
- package/dist/app/sharing/ResourceAccessScreen.js +132 -0
- package/dist/app/sharing/ResourceAccessScreen.js.map +1 -0
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +4 -2
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/app/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/app/sharing/ShareDialog.js +7 -5
- package/dist/app/sharing/ShareDialog.js.map +1 -1
- package/dist/app/sharing/index.d.ts +2 -0
- package/dist/app/sharing/index.d.ts.map +1 -1
- package/dist/app/sharing/index.js +2 -0
- package/dist/app/sharing/index.js.map +1 -1
- package/dist/app/styles/agent-native.css +21 -1
- package/dist/app/styles/tokens/agent-kit.css +3 -1
- package/dist/composer/AgentSuggestionBar.d.ts +1 -1
- package/dist/composer/AgentSuggestionBar.d.ts.map +1 -1
- package/dist/composer/AgentSuggestionBar.js +75 -6
- package/dist/composer/AgentSuggestionBar.js.map +1 -1
- package/package.json +14 -4
- package/src/app/agentkit/react/components.tsx +492 -60
- package/src/app/agentkit/react/context.tsx +10 -0
- package/src/app/agentkit/react/lifecycle.spec.tsx +487 -1
- package/src/app/agentkit/react/styles.css +78 -3
- package/src/app/auth/AuthPage.spec.tsx +11 -7
- package/src/app/auth/AuthPage.tsx +16 -35
- package/src/app/auth/server.spec.ts +68 -0
- package/src/app/auth/server.ts +29 -0
- package/src/app/chat/AgentKitAssistantChat.spec.tsx +287 -290
- package/src/app/chat/AgentKitAssistantChat.tsx +219 -116
- package/src/app/chat/AgentSidebar.tsx +3 -0
- package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +85 -0
- package/src/app/chat/agentkit-chat/guided-questions.tsx +12 -5
- package/src/app/chat/chat/surface-types.ts +2 -0
- package/src/app/i18n/catalogs/ar-SA.ts +44 -0
- package/src/app/i18n/catalogs/de-DE.ts +55 -0
- package/src/app/i18n/catalogs/en-US.ts +46 -0
- package/src/app/i18n/catalogs/es-ES.ts +53 -0
- package/src/app/i18n/catalogs/fr-FR.ts +53 -0
- package/src/app/i18n/catalogs/hi-IN.ts +47 -0
- package/src/app/i18n/catalogs/ja-JP.ts +54 -0
- package/src/app/i18n/catalogs/ko-KR.ts +50 -0
- package/src/app/i18n/catalogs/pt-BR.ts +52 -0
- package/src/app/i18n/catalogs/zh-CN.ts +42 -0
- package/src/app/i18n/catalogs/zh-TW.ts +43 -0
- package/src/app/shared/StarfieldBackground.tsx +4 -423
- package/src/app/shared/WaveBackground.spec.tsx +104 -0
- package/src/app/shared/WaveBackground.tsx +60 -0
- package/src/app/shared/WebGlWaveBackground.spec.tsx +106 -0
- package/src/app/shared/WebGlWaveBackground.tsx +499 -0
- package/src/app/shared/index.ts +1 -0
- package/src/app/shared/ocean/bloom-blur.wgsl +43 -0
- package/src/app/shared/ocean/bloom-bright.wgsl +21 -0
- package/src/app/shared/ocean/bloom-composite.wgsl +40 -0
- package/src/app/shared/ocean/brand-colors.ts +49 -0
- package/src/app/shared/ocean/camera.ts +28 -0
- package/src/app/shared/ocean/hero-ocean-background.spec.tsx +369 -0
- package/src/app/shared/ocean/hero-ocean-background.tsx +238 -0
- package/src/app/shared/ocean/ifft-stage.wgsl +36 -0
- package/src/app/shared/ocean/initial-spectrum.wgsl +36 -0
- package/src/app/shared/ocean/noise.wgsl +24 -0
- package/src/app/shared/ocean/normal-foam.wgsl +32 -0
- package/src/app/shared/ocean/ocean-colors.ts +11 -0
- package/src/app/shared/ocean/ocean-common.wgsl +15 -0
- package/src/app/shared/ocean/ocean-graph.ts +29 -0
- package/src/app/shared/ocean/particles.wgsl +139 -0
- package/src/app/shared/ocean/present.wgsl +40 -0
- package/src/app/shared/ocean/renderer.spec.ts +100 -0
- package/src/app/shared/ocean/renderer.ts +693 -0
- package/src/app/shared/ocean/spectrum.wgsl +35 -0
- package/src/app/shared/ocean/tuning.ts +131 -0
- package/src/app/shared/ocean/webgpu-support.ts +12 -0
- package/src/app/sharing/AccessRequestApprovalPage.spec.tsx +276 -0
- package/src/app/sharing/AccessRequestApprovalPage.tsx +307 -0
- package/src/app/sharing/AccessRequestsSection.tsx +163 -0
- package/src/app/sharing/ResourceAccessScreen.spec.tsx +235 -0
- package/src/app/sharing/ResourceAccessScreen.tsx +331 -0
- package/src/app/sharing/ShareButton.spec.tsx +171 -5
- package/src/app/sharing/ShareButton.tsx +15 -2
- package/src/app/sharing/ShareDialog.spec.tsx +71 -2
- package/src/app/sharing/ShareDialog.tsx +24 -2
- package/src/app/sharing/index.ts +2 -0
- package/src/app/styles/agent-native.css +21 -1
- package/src/app/styles/agent-native.spec.ts +16 -3
- package/src/app/styles/tokens/agent-kit.css +3 -1
- package/src/composer/AgentSuggestionBar.overflow.spec.tsx +277 -0
- package/src/composer/AgentSuggestionBar.tsx +113 -8
- package/src/wgsl-env.d.ts +6 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { readOceanColors } from "./brand-colors.js";
|
|
4
|
+
import type { OceanRenderer } from "./renderer.js";
|
|
5
|
+
import { OCEAN_TUNING } from "./tuning.js";
|
|
6
|
+
|
|
7
|
+
const FADE_IN_MS = 700;
|
|
8
|
+
const RENDERER_INIT_TIMEOUT_MS = 30_000;
|
|
9
|
+
const FIRST_FRAME_TIMEOUT_MS = 6000;
|
|
10
|
+
|
|
11
|
+
export interface HeroOceanBackgroundProps {
|
|
12
|
+
onError: (error: unknown) => void;
|
|
13
|
+
onReady: () => void;
|
|
14
|
+
frameRate?: number;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type PointerTarget = readonly [number, number, number];
|
|
19
|
+
|
|
20
|
+
export function HeroOceanBackground({
|
|
21
|
+
onError,
|
|
22
|
+
onReady,
|
|
23
|
+
frameRate = 30,
|
|
24
|
+
className = "absolute inset-0 z-[-1]",
|
|
25
|
+
}: HeroOceanBackgroundProps) {
|
|
26
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
27
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
28
|
+
const [ready, setReady] = useState(false);
|
|
29
|
+
const onErrorRef = useRef(onError);
|
|
30
|
+
const onReadyRef = useRef(onReady);
|
|
31
|
+
onErrorRef.current = onError;
|
|
32
|
+
onReadyRef.current = onReady;
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const container = containerRef.current;
|
|
36
|
+
const canvas = canvasRef.current;
|
|
37
|
+
if (!container || !canvas) return;
|
|
38
|
+
|
|
39
|
+
let renderer: OceanRenderer | undefined;
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
let rendererFailed = false;
|
|
42
|
+
const cleanups: (() => void)[] = [];
|
|
43
|
+
let firstFrameTimeout: number | undefined;
|
|
44
|
+
let firstFrameStartedAt: number | undefined;
|
|
45
|
+
let firstFrameRemainingMs = FIRST_FRAME_TIMEOUT_MS;
|
|
46
|
+
let waitingForFirstFrame = false;
|
|
47
|
+
const pauseFirstFrameDeadline = () => {
|
|
48
|
+
if (firstFrameTimeout === undefined) return;
|
|
49
|
+
window.clearTimeout(firstFrameTimeout);
|
|
50
|
+
firstFrameTimeout = undefined;
|
|
51
|
+
firstFrameRemainingMs = Math.max(
|
|
52
|
+
0,
|
|
53
|
+
firstFrameRemainingMs -
|
|
54
|
+
(Date.now() - (firstFrameStartedAt ?? Date.now())),
|
|
55
|
+
);
|
|
56
|
+
firstFrameStartedAt = undefined;
|
|
57
|
+
};
|
|
58
|
+
const resumeFirstFrameDeadline = () => {
|
|
59
|
+
if (
|
|
60
|
+
cancelled ||
|
|
61
|
+
rendererFailed ||
|
|
62
|
+
!waitingForFirstFrame ||
|
|
63
|
+
document.hidden ||
|
|
64
|
+
firstFrameTimeout !== undefined
|
|
65
|
+
) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
firstFrameStartedAt = Date.now();
|
|
69
|
+
firstFrameTimeout = window.setTimeout(
|
|
70
|
+
() => failRenderer(new Error("The ocean wave did not draw a frame")),
|
|
71
|
+
firstFrameRemainingMs,
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
const stopFirstFrameDeadline = () => {
|
|
75
|
+
waitingForFirstFrame = false;
|
|
76
|
+
pauseFirstFrameDeadline();
|
|
77
|
+
};
|
|
78
|
+
const rendererInitTimeout = window.setTimeout(() => {
|
|
79
|
+
failRenderer(new Error("The ocean wave renderer did not initialize"));
|
|
80
|
+
}, RENDERER_INIT_TIMEOUT_MS);
|
|
81
|
+
cleanups.push(() => {
|
|
82
|
+
window.clearTimeout(rendererInitTimeout);
|
|
83
|
+
stopFirstFrameDeadline();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const failRenderer = (error: unknown) => {
|
|
87
|
+
if (cancelled || rendererFailed) return;
|
|
88
|
+
rendererFailed = true;
|
|
89
|
+
window.clearTimeout(rendererInitTimeout);
|
|
90
|
+
stopFirstFrameDeadline();
|
|
91
|
+
renderer?.dispose();
|
|
92
|
+
onErrorRef.current(error);
|
|
93
|
+
};
|
|
94
|
+
const handleDocumentVisibility = () => {
|
|
95
|
+
if (document.hidden) pauseFirstFrameDeadline();
|
|
96
|
+
else resumeFirstFrameDeadline();
|
|
97
|
+
};
|
|
98
|
+
document.addEventListener("visibilitychange", handleDocumentVisibility);
|
|
99
|
+
cleanups.push(() =>
|
|
100
|
+
document.removeEventListener(
|
|
101
|
+
"visibilitychange",
|
|
102
|
+
handleDocumentVisibility,
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
let pointerTarget: PointerTarget = [0, 0, 0];
|
|
106
|
+
let lastPointer: readonly [number, number] | undefined;
|
|
107
|
+
|
|
108
|
+
const updatePointer = (clientX: number, clientY: number) => {
|
|
109
|
+
const rect = container.getBoundingClientRect();
|
|
110
|
+
if (rect.width <= 0 || rect.height <= 0) return;
|
|
111
|
+
|
|
112
|
+
const x = clientX - rect.left;
|
|
113
|
+
const y = clientY - rect.top;
|
|
114
|
+
const inside = x >= 0 && x <= rect.width && y >= 0 && y <= rect.height;
|
|
115
|
+
|
|
116
|
+
pointerTarget = [
|
|
117
|
+
(x / rect.width) * 2 - 1,
|
|
118
|
+
1 - (y / rect.height) * 2,
|
|
119
|
+
inside ? 1 : 0,
|
|
120
|
+
];
|
|
121
|
+
renderer?.setPointer(pointerTarget);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const handleMouseMove = (event: MouseEvent) => {
|
|
125
|
+
lastPointer = [event.clientX, event.clientY];
|
|
126
|
+
updatePointer(event.clientX, event.clientY);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const handleScroll = () => {
|
|
130
|
+
if (!lastPointer) return;
|
|
131
|
+
updatePointer(lastPointer[0], lastPointer[1]);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const fadePointer = () => {
|
|
135
|
+
lastPointer = undefined;
|
|
136
|
+
pointerTarget = [pointerTarget[0], pointerTarget[1], 0];
|
|
137
|
+
renderer?.setPointer(pointerTarget);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
document.body.addEventListener("mousemove", handleMouseMove, {
|
|
141
|
+
passive: true,
|
|
142
|
+
});
|
|
143
|
+
document.body.addEventListener("mouseleave", fadePointer, {
|
|
144
|
+
passive: true,
|
|
145
|
+
});
|
|
146
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
147
|
+
window.addEventListener("blur", fadePointer);
|
|
148
|
+
cleanups.push(() => {
|
|
149
|
+
document.body.removeEventListener("mousemove", handleMouseMove);
|
|
150
|
+
document.body.removeEventListener("mouseleave", fadePointer);
|
|
151
|
+
window.removeEventListener("scroll", handleScroll);
|
|
152
|
+
window.removeEventListener("blur", fadePointer);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
void import("./renderer.js")
|
|
156
|
+
.then(({ createRenderer }) => {
|
|
157
|
+
if (cancelled || rendererFailed) return;
|
|
158
|
+
renderer = createRenderer({
|
|
159
|
+
canvas,
|
|
160
|
+
colors: readOceanColors(container),
|
|
161
|
+
fps: frameRate,
|
|
162
|
+
onError: failRenderer,
|
|
163
|
+
});
|
|
164
|
+
renderer.setPointer(pointerTarget);
|
|
165
|
+
|
|
166
|
+
void renderer.ready
|
|
167
|
+
.then(() => {
|
|
168
|
+
if (cancelled || rendererFailed) return;
|
|
169
|
+
window.clearTimeout(rendererInitTimeout);
|
|
170
|
+
waitingForFirstFrame = true;
|
|
171
|
+
resumeFirstFrameDeadline();
|
|
172
|
+
return renderer?.firstFrame;
|
|
173
|
+
})
|
|
174
|
+
.then(() => {
|
|
175
|
+
if (cancelled || rendererFailed) return;
|
|
176
|
+
stopFirstFrameDeadline();
|
|
177
|
+
setReady(true);
|
|
178
|
+
onReadyRef.current();
|
|
179
|
+
})
|
|
180
|
+
.catch(failRenderer);
|
|
181
|
+
|
|
182
|
+
const themeObserver = new MutationObserver(() => {
|
|
183
|
+
renderer?.setColors(readOceanColors(container));
|
|
184
|
+
});
|
|
185
|
+
themeObserver.observe(document.documentElement, {
|
|
186
|
+
attributes: true,
|
|
187
|
+
attributeFilter: ["class", "data-theme"],
|
|
188
|
+
});
|
|
189
|
+
cleanups.push(() => themeObserver.disconnect());
|
|
190
|
+
|
|
191
|
+
const visibility = new IntersectionObserver(
|
|
192
|
+
([entry]) => renderer?.setPaused(!(entry?.isIntersecting ?? true)),
|
|
193
|
+
{ threshold: 0 },
|
|
194
|
+
);
|
|
195
|
+
visibility.observe(container);
|
|
196
|
+
cleanups.push(() => visibility.disconnect());
|
|
197
|
+
})
|
|
198
|
+
.catch((error: unknown) => {
|
|
199
|
+
failRenderer(error);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return () => {
|
|
203
|
+
cancelled = true;
|
|
204
|
+
for (const cleanup of cleanups) cleanup();
|
|
205
|
+
renderer?.dispose();
|
|
206
|
+
};
|
|
207
|
+
}, [frameRate]);
|
|
208
|
+
|
|
209
|
+
const { bottomFadeStartPercent } = OCEAN_TUNING;
|
|
210
|
+
const mask =
|
|
211
|
+
bottomFadeStartPercent >= 100
|
|
212
|
+
? undefined
|
|
213
|
+
: // guard:allow-raw-color - The mask channel requires opaque black, not a theme color.
|
|
214
|
+
`linear-gradient(to bottom, #000 ${bottomFadeStartPercent}%, transparent 100%)`;
|
|
215
|
+
|
|
216
|
+
return (
|
|
217
|
+
<div
|
|
218
|
+
ref={containerRef}
|
|
219
|
+
aria-hidden="true"
|
|
220
|
+
data-agent-native-wave="true"
|
|
221
|
+
// Opacity is inline rather than a class because it animates between 0
|
|
222
|
+
// and a token value; the page background remains visible until the
|
|
223
|
+
// first wave frame is ready.
|
|
224
|
+
className={className}
|
|
225
|
+
style={{
|
|
226
|
+
opacity: ready ? 0.3 : 0,
|
|
227
|
+
transition: `opacity ${FADE_IN_MS}ms ease-out`,
|
|
228
|
+
...(mask ? { maskImage: mask, WebkitMaskImage: mask } : {}),
|
|
229
|
+
}}
|
|
230
|
+
>
|
|
231
|
+
<canvas
|
|
232
|
+
ref={canvasRef}
|
|
233
|
+
className="block h-full w-full"
|
|
234
|
+
style={{ display: "block", height: "100%", width: "100%" }}
|
|
235
|
+
/>
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
struct IfftStageUniforms {
|
|
2
|
+
resolution: f32,
|
|
3
|
+
subtransformSize: f32,
|
|
4
|
+
horizontal: f32,
|
|
5
|
+
};
|
|
6
|
+
@group(0) @binding(0) var<uniform> u: IfftStageUniforms;
|
|
7
|
+
@group(0) @binding(1) var u_input: texture_2d<f32>;
|
|
8
|
+
|
|
9
|
+
@fragment fn fs_main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
10
|
+
let N = i32(u.resolution);
|
|
11
|
+
let horizontal = u.horizontal > 0.5;
|
|
12
|
+
let index = select(position.y - 0.5, position.x - 0.5, horizontal);
|
|
13
|
+
|
|
14
|
+
let evenIndex = floor(index / u.subtransformSize) * (u.subtransformSize * 0.5)
|
|
15
|
+
+ (index % (u.subtransformSize * 0.5));
|
|
16
|
+
|
|
17
|
+
let evenCoord = select(
|
|
18
|
+
vec2i(i32(position.x - 0.5), i32(evenIndex)),
|
|
19
|
+
vec2i(i32(evenIndex), i32(position.y - 0.5)),
|
|
20
|
+
horizontal,
|
|
21
|
+
);
|
|
22
|
+
let oddCoord = select(
|
|
23
|
+
vec2i(i32(position.x - 0.5), i32(evenIndex + u.resolution * 0.5)),
|
|
24
|
+
vec2i(i32(evenIndex + u.resolution * 0.5), i32(position.y - 0.5)),
|
|
25
|
+
horizontal,
|
|
26
|
+
);
|
|
27
|
+
let even = wrapLoad(u_input, evenCoord, N);
|
|
28
|
+
let odd = wrapLoad(u_input, oddCoord, N);
|
|
29
|
+
|
|
30
|
+
let twiddleArg = 2.0 * PI * (index / u.subtransformSize);
|
|
31
|
+
let twiddle = vec2f(cos(twiddleArg), sin(twiddleArg));
|
|
32
|
+
|
|
33
|
+
let outA = even.xy + cmul(twiddle, odd.xy);
|
|
34
|
+
let outB = even.zw + cmul(twiddle, odd.zw);
|
|
35
|
+
return vec4f(outA, outB);
|
|
36
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
struct InitialSpectrumUniforms {
|
|
2
|
+
resolution: f32,
|
|
3
|
+
size: f32,
|
|
4
|
+
windSpeed: f32,
|
|
5
|
+
windAngle: f32,
|
|
6
|
+
amplitude: f32,
|
|
7
|
+
};
|
|
8
|
+
@group(0) @binding(0) var<uniform> u: InitialSpectrumUniforms;
|
|
9
|
+
@group(0) @binding(1) var u_noise: texture_2d<f32>;
|
|
10
|
+
|
|
11
|
+
fn phillips(k: vec2f) -> f32 {
|
|
12
|
+
let kk = dot(k, k);
|
|
13
|
+
if (kk < 1e-8) { return 0.0; }
|
|
14
|
+
let w = vec2f(cos(u.windAngle), sin(u.windAngle));
|
|
15
|
+
let L = (u.windSpeed * u.windSpeed) / G;
|
|
16
|
+
let kdotw = dot(normalize(k), w);
|
|
17
|
+
var ph = u.amplitude * exp(-1.0 / (kk * L * L)) / (kk * kk) * (kdotw * kdotw);
|
|
18
|
+
let l = L * 0.001;
|
|
19
|
+
ph *= exp(-kk * l * l);
|
|
20
|
+
if (kdotw < 0.0) { ph *= 0.07; }
|
|
21
|
+
return ph;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@fragment fn fs_main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
25
|
+
let coord = position.xy - vec2f(0.5);
|
|
26
|
+
let n = select(coord.x - u.resolution, coord.x, coord.x < u.resolution * 0.5);
|
|
27
|
+
let m = select(coord.y - u.resolution, coord.y, coord.y < u.resolution * 0.5);
|
|
28
|
+
let k = (2.0 * PI / u.size) * vec2f(n, m);
|
|
29
|
+
|
|
30
|
+
let rnd = textureLoad(u_noise, vec2u(coord), 0);
|
|
31
|
+
|
|
32
|
+
let h0k = (1.0 / sqrt(2.0)) * vec2f(rnd.x, rnd.y) * sqrt(phillips(k));
|
|
33
|
+
let h0negk = (1.0 / sqrt(2.0)) * vec2f(rnd.z, rnd.w) * sqrt(phillips(-k));
|
|
34
|
+
|
|
35
|
+
return vec4f(h0k, h0negk.x, -h0negk.y);
|
|
36
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const SEED: u32 = 0x6f636561u;
|
|
2
|
+
const RESOLUTION: u32 = 512u;
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
fn mulberryAt(callIndex: u32) -> f32 {
|
|
7
|
+
let state = SEED + 0x6d2b79f5u * (callIndex + 1u);
|
|
8
|
+
var t = state;
|
|
9
|
+
t = (t ^ (t >> 15u)) * (t | 1u);
|
|
10
|
+
t = t ^ (t + ((t ^ (t >> 7u)) * (t | 61u)));
|
|
11
|
+
return f32(t ^ (t >> 14u)) / 4294967296.0;
|
|
12
|
+
}
|
|
13
|
+
fn gaussianPair(callIndex: u32) -> vec2f {
|
|
14
|
+
let u1 = max(mulberryAt(callIndex), 1.17549435e-38);
|
|
15
|
+
let u2 = mulberryAt(callIndex + 1u);
|
|
16
|
+
let magnitude = sqrt(-2.0 * log(u1));
|
|
17
|
+
let angle = 6.283185307179586 * u2;
|
|
18
|
+
return magnitude * vec2f(cos(angle), sin(angle));
|
|
19
|
+
}
|
|
20
|
+
@fragment fn fs_main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
21
|
+
let coord = vec2u(position.xy - vec2f(0.5));
|
|
22
|
+
let base = (coord.y * RESOLUTION + coord.x) * 4u;
|
|
23
|
+
return vec4f(gaussianPair(base), gaussianPair(base + 2u));
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
struct NormalFoamUniforms {
|
|
2
|
+
resolution: f32,
|
|
3
|
+
worldSize: f32,
|
|
4
|
+
displacementScale: f32,
|
|
5
|
+
foamThreshold: f32,
|
|
6
|
+
};
|
|
7
|
+
@group(0) @binding(0) var<uniform> u: NormalFoamUniforms;
|
|
8
|
+
@group(0) @binding(1) var u_displacement: texture_2d<f32>;
|
|
9
|
+
|
|
10
|
+
@fragment fn fs_main(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
11
|
+
let N = i32(u.resolution);
|
|
12
|
+
let coord = vec2i(position.xy - vec2f(0.5));
|
|
13
|
+
let dx = u.worldSize / u.resolution;
|
|
14
|
+
|
|
15
|
+
let r = wrapLoad(u_displacement, coord + vec2i(1, 0), N).xyz * u.displacementScale;
|
|
16
|
+
let l = wrapLoad(u_displacement, coord - vec2i(1, 0), N).xyz * u.displacementScale;
|
|
17
|
+
let t = wrapLoad(u_displacement, coord + vec2i(0, 1), N).xyz * u.displacementScale;
|
|
18
|
+
let b = wrapLoad(u_displacement, coord - vec2i(0, 1), N).xyz * u.displacementScale;
|
|
19
|
+
|
|
20
|
+
let dhdx = (r.y - l.y) / (2.0 * dx);
|
|
21
|
+
let dhdz = (t.y - b.y) / (2.0 * dx);
|
|
22
|
+
let normal = normalize(vec3f(-dhdx, 1.0, -dhdz));
|
|
23
|
+
|
|
24
|
+
let dDxdx = (r.x - l.x) / (2.0 * dx);
|
|
25
|
+
let dDzdz = (t.z - b.z) / (2.0 * dx);
|
|
26
|
+
let dDxdz = (t.x - b.x) / (2.0 * dx);
|
|
27
|
+
let dDzdx = (r.z - l.z) / (2.0 * dx);
|
|
28
|
+
let J = (1.0 + dDxdx) * (1.0 + dDzdz) - dDxdz * dDzdx;
|
|
29
|
+
|
|
30
|
+
let foam = 1.0 - smoothstep(u.foamThreshold, u.foamThreshold + 0.8, J);
|
|
31
|
+
return vec4f(normal, foam);
|
|
32
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OCEAN_TUNING } from "./tuning.js";
|
|
2
|
+
|
|
3
|
+
export interface OceanColors {
|
|
4
|
+
readonly fg: readonly [number, number, number];
|
|
5
|
+
readonly bg: readonly [number, number, number];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_OCEAN_COLORS: OceanColors = {
|
|
9
|
+
fg: OCEAN_TUNING.present.fgColor,
|
|
10
|
+
bg: OCEAN_TUNING.present.bgColor,
|
|
11
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const PI: f32 = 3.141592653589793;
|
|
2
|
+
const G: f32 = 9.81;
|
|
3
|
+
|
|
4
|
+
fn cmul(a: vec2f, b: vec2f) -> vec2f {
|
|
5
|
+
return vec2f(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
fn wrapCoord(coord: vec2i, N: i32) -> vec2u {
|
|
9
|
+
let wrapped = (coord % vec2i(N) + vec2i(N)) % vec2i(N);
|
|
10
|
+
return vec2u(wrapped);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
fn wrapLoad(tex: texture_2d<f32>, coord: vec2i, N: i32) -> vec4f {
|
|
14
|
+
return textureLoad(tex, wrapCoord(coord, N), 0);
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type SimulationTargetName = "spectrum" | "ping" | "pong";
|
|
2
|
+
|
|
3
|
+
export interface IfftStage {
|
|
4
|
+
readonly index: number;
|
|
5
|
+
readonly axisStage: number;
|
|
6
|
+
readonly horizontal: boolean;
|
|
7
|
+
readonly subtransformSize: number;
|
|
8
|
+
readonly input: SimulationTargetName;
|
|
9
|
+
readonly output: Exclude<SimulationTargetName, "spectrum">;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const OCEAN_RESOLUTION = 512 as const;
|
|
13
|
+
const AXIS_STAGES = 9;
|
|
14
|
+
|
|
15
|
+
export function createIfftStageTable(): readonly IfftStage[] {
|
|
16
|
+
return Object.freeze(
|
|
17
|
+
Array.from({ length: AXIS_STAGES * 2 }, (_, index): IfftStage => {
|
|
18
|
+
const output = index % 2 ? "pong" : "ping";
|
|
19
|
+
return Object.freeze({
|
|
20
|
+
index,
|
|
21
|
+
axisStage: index % AXIS_STAGES,
|
|
22
|
+
horizontal: index < AXIS_STAGES,
|
|
23
|
+
subtransformSize: 2 ** ((index % AXIS_STAGES) + 1),
|
|
24
|
+
input: index === 0 ? "spectrum" : output === "ping" ? "pong" : "ping",
|
|
25
|
+
output,
|
|
26
|
+
});
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
struct ParticleUniforms {
|
|
2
|
+
view: mat4x4f,
|
|
3
|
+
projection: mat4x4f,
|
|
4
|
+
viewport: vec4f,
|
|
5
|
+
world: vec4f,
|
|
6
|
+
fade: vec4f,
|
|
7
|
+
oceanColor: vec4f,
|
|
8
|
+
neonColor: vec4f,
|
|
9
|
+
foamColor: vec4f,
|
|
10
|
+
cursor: vec4f,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
struct VertexOut {
|
|
14
|
+
@builtin(position) position: vec4f,
|
|
15
|
+
@location(0) pointCoord: vec2f,
|
|
16
|
+
@location(1) foam: f32,
|
|
17
|
+
@location(2) normal: vec3f,
|
|
18
|
+
@location(3) viewDir: vec3f,
|
|
19
|
+
@location(4) height: f32,
|
|
20
|
+
@location(5) fade: f32,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
@group(0) @binding(0) var<uniform> u: ParticleUniforms;
|
|
24
|
+
@group(0) @binding(1) var u_displacement: texture_2d<f32>;
|
|
25
|
+
@group(0) @binding(2) var u_normalFoam: texture_2d<f32>;
|
|
26
|
+
|
|
27
|
+
fn particleHash(p: vec2u) -> f32 {
|
|
28
|
+
var n = p.x * 374761393u + p.y * 668265263u;
|
|
29
|
+
n = (n ^ (n >> 13u)) * 1274126177u;
|
|
30
|
+
n = n ^ (n >> 16u);
|
|
31
|
+
return f32(n) / 4294967295.0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn quadCorner(vertexIndex: u32) -> vec2f {
|
|
35
|
+
let cornerIndex = array<u32, 6>(0u, 1u, 2u, 2u, 1u, 3u)[vertexIndex % 6u];
|
|
36
|
+
switch (cornerIndex) {
|
|
37
|
+
case 0u: { return vec2f(-1.0, -1.0); }
|
|
38
|
+
case 1u: { return vec2f( 1.0, -1.0); }
|
|
39
|
+
case 2u: { return vec2f(-1.0, 1.0); }
|
|
40
|
+
default: { return vec2f( 1.0, 1.0); }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@vertex fn vs_main(
|
|
45
|
+
@builtin(vertex_index) vertexIndex: u32,
|
|
46
|
+
@builtin(instance_index) instanceIndex: u32,
|
|
47
|
+
) -> VertexOut {
|
|
48
|
+
let resolution = max(1u, u32(u.viewport.w));
|
|
49
|
+
let i = instanceIndex % resolution;
|
|
50
|
+
let j = instanceIndex / resolution;
|
|
51
|
+
let particleRef = vec2f(f32(i), f32(j)) / f32(resolution);
|
|
52
|
+
let texCoord = vec2u(i, j);
|
|
53
|
+
|
|
54
|
+
let disp = textureLoad(u_displacement, texCoord, 0).xyz * u.world.y;
|
|
55
|
+
let nf = textureLoad(u_normalFoam, texCoord, 0);
|
|
56
|
+
|
|
57
|
+
let halfWorld = u.world.x * 0.5;
|
|
58
|
+
let base = vec3f(
|
|
59
|
+
particleRef.x * u.world.x - halfWorld,
|
|
60
|
+
0.0,
|
|
61
|
+
particleRef.y * u.world.x - halfWorld,
|
|
62
|
+
);
|
|
63
|
+
let pos = base + disp;
|
|
64
|
+
|
|
65
|
+
let mv = u.view * vec4f(pos, 1.0);
|
|
66
|
+
let viewDir = -mv.xyz;
|
|
67
|
+
let dist = -mv.z;
|
|
68
|
+
let f = 1.0 - smoothstep(u.fade.x, u.fade.y, dist);
|
|
69
|
+
let fade = pow(clamp(f, 0.0, 1.0), u.fade.z);
|
|
70
|
+
|
|
71
|
+
let projected = u.projection * mv;
|
|
72
|
+
var ndc = projected.xy / projected.w;
|
|
73
|
+
|
|
74
|
+
let aspect = u.viewport.x / max(u.viewport.y, 1.0);
|
|
75
|
+
if (u.cursor.z > 0.0) {
|
|
76
|
+
let cursorDelta = u.cursor.xy - ndc;
|
|
77
|
+
let fieldDelta = cursorDelta * vec2f(aspect, 1.0);
|
|
78
|
+
let cursorDistance = length(fieldDelta);
|
|
79
|
+
let rangeFalloff = 1.0 - smoothstep(0.0, 1.7, cursorDistance);
|
|
80
|
+
let particleId = vec2u(i, j);
|
|
81
|
+
let particleSeed = particleHash(particleId);
|
|
82
|
+
let detached = smoothstep(0.76, 0.998, particleSeed);
|
|
83
|
+
let phase = particleHash(particleId + vec2u(37u, 71u)) * 6.2831855;
|
|
84
|
+
let activity = 0.55 + 0.45 * (0.5 + 0.5 * sin(u.cursor.w * 0.45 + phase));
|
|
85
|
+
let trailProgress = clamp(cursorDistance / 1.7, 0.0, 1.0);
|
|
86
|
+
let trailWidth = mix(0.025, 0.28, trailProgress);
|
|
87
|
+
let jitter = vec2f(
|
|
88
|
+
particleHash(particleId + vec2u(17u, 53u)) - 0.5,
|
|
89
|
+
particleHash(particleId + vec2u(41u, 29u)) - 0.5,
|
|
90
|
+
) * vec2f(trailWidth / aspect, trailWidth);
|
|
91
|
+
let nearFalloff = 1.0 - smoothstep(0.0, 1.0, cursorDistance);
|
|
92
|
+
let baselineResponse = mix(0.004, 0.014, nearFalloff) *
|
|
93
|
+
mix(0.6, 1.0, particleSeed);
|
|
94
|
+
let particleResponse = baselineResponse +
|
|
95
|
+
detached * activity * mix(0.11, 0.82, nearFalloff);
|
|
96
|
+
let attraction = rangeFalloff * particleResponse * u.cursor.z;
|
|
97
|
+
ndc += (u.cursor.xy + jitter - ndc) * attraction;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let corner = quadCorner(vertexIndex);
|
|
101
|
+
let pointSizePx = 2.0 * u.world.z * u.viewport.z;
|
|
102
|
+
let clipOffset = corner * (pointSizePx / u.viewport.xy) * projected.w;
|
|
103
|
+
let clip = vec4f(ndc * projected.w + clipOffset, projected.z, projected.w);
|
|
104
|
+
|
|
105
|
+
var out: VertexOut;
|
|
106
|
+
out.position = clip;
|
|
107
|
+
out.pointCoord = corner * 0.5 + vec2f(0.5);
|
|
108
|
+
out.foam = nf.w;
|
|
109
|
+
out.normal = nf.xyz;
|
|
110
|
+
out.viewDir = viewDir;
|
|
111
|
+
out.height = disp.y;
|
|
112
|
+
out.fade = fade;
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@fragment fn fs_main(in: VertexOut) -> @location(0) vec4f {
|
|
117
|
+
let cc = in.pointCoord - vec2f(0.5);
|
|
118
|
+
let d2 = dot(cc, cc);
|
|
119
|
+
if (d2 > 0.25) {
|
|
120
|
+
discard;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let n = normalize(in.normal);
|
|
124
|
+
let v = normalize(in.viewDir);
|
|
125
|
+
let fresnel = pow(1.0 - clamp(dot(n, v), 0.0, 1.0), 5.0);
|
|
126
|
+
|
|
127
|
+
let foam = clamp(in.foam, 0.0, 1.0);
|
|
128
|
+
let crest = smoothstep(-0.5, 1.5, in.height);
|
|
129
|
+
|
|
130
|
+
var color = u.oceanColor.rgb * 0.5;
|
|
131
|
+
color += u.neonColor.rgb * crest * 0.5;
|
|
132
|
+
color += u.neonColor.rgb * fresnel * 0.15;
|
|
133
|
+
color = mix(color, u.foamColor.rgb, foam);
|
|
134
|
+
var alpha = 0.02 + crest * 0.06 + fresnel * 0.04;
|
|
135
|
+
alpha = mix(alpha, 1.0, foam);
|
|
136
|
+
color *= in.fade;
|
|
137
|
+
alpha *= in.fade;
|
|
138
|
+
return vec4f(color, clamp(alpha, 0.0, 1.0));
|
|
139
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
struct PresentUniforms {
|
|
2
|
+
fgColor: vec4f,
|
|
3
|
+
bgColor: vec4f,
|
|
4
|
+
|
|
5
|
+
brightness: f32,
|
|
6
|
+
_pad: vec3f,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
@group(0) @binding(0) var<uniform> uniforms: PresentUniforms;
|
|
10
|
+
@group(0) @binding(1) var sceneHDR: texture_2d<f32>;
|
|
11
|
+
@group(0) @binding(2) var bloomTexture: texture_2d<f32>;
|
|
12
|
+
@group(0) @binding(3) var linearSampler: sampler;
|
|
13
|
+
|
|
14
|
+
fn LinearTosRGB(value: vec4f) -> vec4f {
|
|
15
|
+
let lt = value.rgb * 12.92;
|
|
16
|
+
let gt = 1.055 * pow(value.rgb, vec3f(0.41666)) - vec3f(0.055);
|
|
17
|
+
let rgb = select(gt, lt, value.rgb <= vec3f(0.0031308));
|
|
18
|
+
return vec4f(rgb, value.a);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@fragment fn fs_main(@location(0) uv: vec2f) -> @location(0) vec4f {
|
|
22
|
+
let scene = textureSample(sceneHDR, linearSampler, uv);
|
|
23
|
+
let bloom = textureSample(bloomTexture, linearSampler, uv);
|
|
24
|
+
let hdr = scene.rgb + bloom.rgb;
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
let tone = clamp(dot(hdr, vec3f(0.2126, 0.7152, 0.0722)), 0.0, 1.0);
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
var color = mix(uniforms.bgColor.rgb, uniforms.fgColor.rgb, tone);
|
|
36
|
+
color += (uniforms.fgColor.rgb - uniforms.bgColor.rgb) * tone * tone
|
|
37
|
+
* (uniforms.brightness - 1.0);
|
|
38
|
+
|
|
39
|
+
return LinearTosRGB(vec4f(clamp(color, vec3f(0.0), vec3f(1.0)), 1.0));
|
|
40
|
+
}
|