@elyri/motion 0.0.0-stage → 0.0.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.
- package/LICENSE +21 -0
- package/README.md +70 -2
- package/dist/chunk-A7JCTGZO.js +230 -0
- package/dist/chunk-A7JCTGZO.js.map +1 -0
- package/dist/core.cjs +238 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +77 -0
- package/dist/core.d.ts +77 -0
- package/dist/core.js +3 -0
- package/dist/core.js.map +1 -0
- package/dist/index.cjs +4288 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +1118 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +532 -0
- package/dist/index.d.ts +532 -0
- package/dist/index.js +4029 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -3
- package/src/components/animations/CountUp/CountUp.css +4 -0
- package/src/components/animations/CountUp/CountUp.tsx +100 -0
- package/src/components/animations/CountUp/index.ts +2 -0
- package/src/components/animations/FadeIn/FadeIn.css +43 -0
- package/src/components/animations/FadeIn/FadeIn.tsx +72 -0
- package/src/components/animations/FadeIn/index.ts +2 -0
- package/src/components/animations/Magnetic/Magnetic.css +11 -0
- package/src/components/animations/Magnetic/Magnetic.tsx +107 -0
- package/src/components/animations/Magnetic/index.ts +2 -0
- package/src/components/animations/ScaleIn/ScaleIn.css +24 -0
- package/src/components/animations/ScaleIn/ScaleIn.tsx +65 -0
- package/src/components/animations/ScaleIn/index.ts +2 -0
- package/src/components/animations/Spotlight/Spotlight.css +93 -0
- package/src/components/animations/Spotlight/Spotlight.tsx +100 -0
- package/src/components/animations/Spotlight/index.ts +2 -0
- package/src/components/animations/Tilt/Tilt.css +35 -0
- package/src/components/animations/Tilt/Tilt.tsx +123 -0
- package/src/components/animations/Tilt/index.ts +2 -0
- package/src/components/animations/index.ts +12 -0
- package/src/components/backgrounds/Aurora/Aurora.css +33 -0
- package/src/components/backgrounds/Aurora/Aurora.tsx +147 -0
- package/src/components/backgrounds/Aurora/index.ts +2 -0
- package/src/components/backgrounds/Caustics/Caustics.css +34 -0
- package/src/components/backgrounds/Caustics/Caustics.tsx +142 -0
- package/src/components/backgrounds/Caustics/index.ts +2 -0
- package/src/components/backgrounds/Contours/Contours.css +42 -0
- package/src/components/backgrounds/Contours/Contours.tsx +147 -0
- package/src/components/backgrounds/Contours/index.ts +2 -0
- package/src/components/backgrounds/DotField/DotField.css +44 -0
- package/src/components/backgrounds/DotField/DotField.tsx +135 -0
- package/src/components/backgrounds/DotField/index.ts +2 -0
- package/src/components/backgrounds/DragonScales/DragonScales.css +44 -0
- package/src/components/backgrounds/DragonScales/DragonScales.tsx +250 -0
- package/src/components/backgrounds/DragonScales/index.ts +2 -0
- package/src/components/backgrounds/Filaments/Filaments.css +38 -0
- package/src/components/backgrounds/Filaments/Filaments.tsx +138 -0
- package/src/components/backgrounds/Filaments/index.ts +2 -0
- package/src/components/backgrounds/FlipTiles/FlipTiles.css +44 -0
- package/src/components/backgrounds/FlipTiles/FlipTiles.tsx +368 -0
- package/src/components/backgrounds/FlipTiles/index.ts +2 -0
- package/src/components/backgrounds/Halo/Halo.css +43 -0
- package/src/components/backgrounds/Halo/Halo.tsx +122 -0
- package/src/components/backgrounds/Halo/index.ts +2 -0
- package/src/components/backgrounds/MeshGradient/MeshGradient.css +43 -0
- package/src/components/backgrounds/MeshGradient/MeshGradient.tsx +195 -0
- package/src/components/backgrounds/MeshGradient/index.ts +2 -0
- package/src/components/backgrounds/PixelVortex/PixelVortex.css +44 -0
- package/src/components/backgrounds/PixelVortex/PixelVortex.tsx +278 -0
- package/src/components/backgrounds/PixelVortex/index.ts +2 -0
- package/src/components/backgrounds/Planet/Planet.css +39 -0
- package/src/components/backgrounds/Planet/Planet.tsx +736 -0
- package/src/components/backgrounds/Planet/index.ts +2 -0
- package/src/components/backgrounds/SilkWaves/SilkWaves.css +44 -0
- package/src/components/backgrounds/SilkWaves/SilkWaves.tsx +144 -0
- package/src/components/backgrounds/SilkWaves/index.ts +2 -0
- package/src/components/backgrounds/Velvet/Velvet.css +35 -0
- package/src/components/backgrounds/Velvet/Velvet.tsx +246 -0
- package/src/components/backgrounds/Velvet/index.ts +2 -0
- package/src/components/backgrounds/index.ts +26 -0
- package/src/components/index.ts +4 -0
- package/src/components/media/AsciiImage/AsciiImage.css +16 -0
- package/src/components/media/AsciiImage/AsciiImage.tsx +366 -0
- package/src/components/media/AsciiImage/index.ts +2 -0
- package/src/components/media/index.ts +2 -0
- package/src/components/text/GradientText/GradientText.css +32 -0
- package/src/components/text/GradientText/GradientText.tsx +27 -0
- package/src/components/text/GradientText/index.ts +2 -0
- package/src/components/text/Marquee/Marquee.css +91 -0
- package/src/components/text/Marquee/Marquee.tsx +130 -0
- package/src/components/text/Marquee/index.ts +2 -0
- package/src/components/text/ParticleText/ParticleText.css +16 -0
- package/src/components/text/ParticleText/ParticleText.tsx +279 -0
- package/src/components/text/ParticleText/index.ts +2 -0
- package/src/components/text/RotatingText/RotatingText.css +133 -0
- package/src/components/text/RotatingText/RotatingText.tsx +112 -0
- package/src/components/text/RotatingText/index.ts +2 -0
- package/src/components/text/ScrambleText/ScrambleText.css +48 -0
- package/src/components/text/ScrambleText/ScrambleText.tsx +141 -0
- package/src/components/text/ScrambleText/index.ts +2 -0
- package/src/components/text/ScrollMarquee/ScrollMarquee.css +33 -0
- package/src/components/text/ScrollMarquee/ScrollMarquee.tsx +110 -0
- package/src/components/text/ScrollMarquee/index.ts +2 -0
- package/src/components/text/ScrollReveal/ScrollReveal.css +51 -0
- package/src/components/text/ScrollReveal/ScrollReveal.tsx +186 -0
- package/src/components/text/ScrollReveal/index.ts +2 -0
- package/src/components/text/SplitReveal/SplitReveal.css +52 -0
- package/src/components/text/SplitReveal/SplitReveal.tsx +127 -0
- package/src/components/text/SplitReveal/index.ts +2 -0
- package/src/components/text/Typewriter/Typewriter.css +37 -0
- package/src/components/text/Typewriter/Typewriter.tsx +80 -0
- package/src/components/text/Typewriter/index.ts +2 -0
- package/src/components/text/WaveText/WaveText.css +28 -0
- package/src/components/text/WaveText/WaveText.tsx +52 -0
- package/src/components/text/WaveText/index.ts +2 -0
- package/src/components/text/index.ts +20 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4029 @@
|
|
|
1
|
+
import { usePrefersReducedMotion, cn, useShaderCanvas, hexToLinearRgb, useColorScheme, splitTextUnits } from './chunk-A7JCTGZO.js';
|
|
2
|
+
export { ReducedMotionProvider, cn, hexToLinearRgb, splitTextUnits, useColorScheme, usePrefersReducedMotion, useShaderCanvas } from './chunk-A7JCTGZO.js';
|
|
3
|
+
import { useRef, useState, useEffect, useLayoutEffect, useMemo } from 'react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var group = (value) => value.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
7
|
+
var easeOutCubic = (progress) => 1 - (1 - progress) ** 3;
|
|
8
|
+
function CountUp({
|
|
9
|
+
className,
|
|
10
|
+
to,
|
|
11
|
+
from = 0,
|
|
12
|
+
duration = 1200,
|
|
13
|
+
decimals = 0,
|
|
14
|
+
separator = false,
|
|
15
|
+
prefix,
|
|
16
|
+
suffix,
|
|
17
|
+
once = true
|
|
18
|
+
}) {
|
|
19
|
+
const elementRef = useRef(null);
|
|
20
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
21
|
+
const [value, setValue] = useState(from);
|
|
22
|
+
const [isIntersecting, setIsIntersecting] = useState(false);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const element = elementRef.current;
|
|
25
|
+
if (!element || prefersReducedMotion) return;
|
|
26
|
+
const observer = new IntersectionObserver(
|
|
27
|
+
([entry]) => {
|
|
28
|
+
if (entry.isIntersecting) {
|
|
29
|
+
setIsIntersecting(true);
|
|
30
|
+
if (once) observer.disconnect();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!once) setIsIntersecting(false);
|
|
34
|
+
},
|
|
35
|
+
{ threshold: 0.1 }
|
|
36
|
+
);
|
|
37
|
+
observer.observe(element);
|
|
38
|
+
return () => observer.disconnect();
|
|
39
|
+
}, [once, prefersReducedMotion]);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!isIntersecting || prefersReducedMotion) return;
|
|
42
|
+
let frame = 0;
|
|
43
|
+
const startedAt = performance.now();
|
|
44
|
+
const tick = (now) => {
|
|
45
|
+
const progress = duration > 0 ? Math.min((now - startedAt) / duration, 1) : 1;
|
|
46
|
+
setValue(from + (to - from) * easeOutCubic(progress));
|
|
47
|
+
if (progress < 1) frame = requestAnimationFrame(tick);
|
|
48
|
+
};
|
|
49
|
+
frame = requestAnimationFrame(tick);
|
|
50
|
+
return () => cancelAnimationFrame(frame);
|
|
51
|
+
}, [isIntersecting, from, to, duration, prefersReducedMotion]);
|
|
52
|
+
const fixed = (prefersReducedMotion ? to : value).toFixed(decimals);
|
|
53
|
+
const [integer, fraction] = fixed.split(".");
|
|
54
|
+
const grouped = separator ? group(integer) : integer;
|
|
55
|
+
const display = fraction ? `${grouped}.${fraction}` : grouped;
|
|
56
|
+
return /* @__PURE__ */ jsxs("span", { ref: elementRef, className: cn("elyri-count-up", className), children: [
|
|
57
|
+
prefix,
|
|
58
|
+
display,
|
|
59
|
+
suffix
|
|
60
|
+
] });
|
|
61
|
+
}
|
|
62
|
+
function FadeIn({
|
|
63
|
+
children,
|
|
64
|
+
className,
|
|
65
|
+
direction = "up",
|
|
66
|
+
delay = 0,
|
|
67
|
+
duration = 600,
|
|
68
|
+
distance = 24,
|
|
69
|
+
once = true
|
|
70
|
+
}) {
|
|
71
|
+
const elementRef = useRef(null);
|
|
72
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
73
|
+
const [isIntersecting, setIsIntersecting] = useState(false);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const element = elementRef.current;
|
|
76
|
+
if (!element || prefersReducedMotion) return;
|
|
77
|
+
const observer = new IntersectionObserver(
|
|
78
|
+
([entry]) => {
|
|
79
|
+
if (entry.isIntersecting) {
|
|
80
|
+
setIsIntersecting(true);
|
|
81
|
+
if (once) observer.disconnect();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!once) setIsIntersecting(false);
|
|
85
|
+
},
|
|
86
|
+
{ threshold: 0.1 }
|
|
87
|
+
);
|
|
88
|
+
observer.observe(element);
|
|
89
|
+
return () => observer.disconnect();
|
|
90
|
+
}, [once, prefersReducedMotion]);
|
|
91
|
+
const style = {
|
|
92
|
+
"--elyri-fade-in-delay": `${delay}ms`,
|
|
93
|
+
"--elyri-fade-in-duration": `${duration}ms`,
|
|
94
|
+
"--elyri-fade-in-distance": `${distance}px`
|
|
95
|
+
};
|
|
96
|
+
const isVisible = prefersReducedMotion || isIntersecting;
|
|
97
|
+
return /* @__PURE__ */ jsx(
|
|
98
|
+
"div",
|
|
99
|
+
{
|
|
100
|
+
ref: elementRef,
|
|
101
|
+
className: cn("elyri-fade-in", `elyri-fade-in--${direction}`, isVisible && "elyri-fade-in--visible", className),
|
|
102
|
+
style,
|
|
103
|
+
children
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
var easeOutCubic2 = (progress) => 1 - (1 - progress) ** 3;
|
|
108
|
+
function Magnetic({ children, className, strength = 0.35, range = 120, resetDuration = 400 }) {
|
|
109
|
+
const elementRef = useRef(null);
|
|
110
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
const element = elementRef.current;
|
|
113
|
+
if (!element || prefersReducedMotion) return;
|
|
114
|
+
let moveFrame = 0;
|
|
115
|
+
let resetFrame = 0;
|
|
116
|
+
let offset = { x: 0, y: 0 };
|
|
117
|
+
let pointer = null;
|
|
118
|
+
const setOffset = (x, y) => {
|
|
119
|
+
offset = { x, y };
|
|
120
|
+
element.style.setProperty("--elyri-magnetic-x", `${x}px`);
|
|
121
|
+
element.style.setProperty("--elyri-magnetic-y", `${y}px`);
|
|
122
|
+
};
|
|
123
|
+
const startReset = () => {
|
|
124
|
+
if (resetFrame || !offset.x && !offset.y) return;
|
|
125
|
+
const from = { ...offset };
|
|
126
|
+
const startedAt = performance.now();
|
|
127
|
+
const step = (now) => {
|
|
128
|
+
const progress = Math.min((now - startedAt) / resetDuration, 1);
|
|
129
|
+
const remaining = 1 - easeOutCubic2(progress);
|
|
130
|
+
setOffset(from.x * remaining, from.y * remaining);
|
|
131
|
+
resetFrame = progress < 1 ? requestAnimationFrame(step) : 0;
|
|
132
|
+
};
|
|
133
|
+
resetFrame = requestAnimationFrame(step);
|
|
134
|
+
};
|
|
135
|
+
const handlePointerMove = (event) => {
|
|
136
|
+
pointer = { x: event.clientX, y: event.clientY };
|
|
137
|
+
if (moveFrame) return;
|
|
138
|
+
moveFrame = requestAnimationFrame(() => {
|
|
139
|
+
moveFrame = 0;
|
|
140
|
+
if (!pointer) return;
|
|
141
|
+
const rect = element.getBoundingClientRect();
|
|
142
|
+
const dx = pointer.x - (rect.left + rect.width / 2);
|
|
143
|
+
const dy = pointer.y - (rect.top + rect.height / 2);
|
|
144
|
+
const inside = Math.abs(dx) <= rect.width / 2 + range && Math.abs(dy) <= rect.height / 2 + range;
|
|
145
|
+
if (inside) {
|
|
146
|
+
cancelAnimationFrame(resetFrame);
|
|
147
|
+
resetFrame = 0;
|
|
148
|
+
const overflowX = Math.max(0, Math.abs(dx) - rect.width / 2);
|
|
149
|
+
const overflowY = Math.max(0, Math.abs(dy) - rect.height / 2);
|
|
150
|
+
const proximity = 1 - Math.min(Math.max(overflowX, overflowY) / range, 1);
|
|
151
|
+
setOffset(dx * strength * proximity, dy * strength * proximity);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
startReset();
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
window.addEventListener("pointermove", handlePointerMove, { passive: true });
|
|
158
|
+
document.documentElement.addEventListener("pointerleave", startReset);
|
|
159
|
+
return () => {
|
|
160
|
+
window.removeEventListener("pointermove", handlePointerMove);
|
|
161
|
+
document.documentElement.removeEventListener("pointerleave", startReset);
|
|
162
|
+
cancelAnimationFrame(moveFrame);
|
|
163
|
+
cancelAnimationFrame(resetFrame);
|
|
164
|
+
};
|
|
165
|
+
}, [prefersReducedMotion, range, strength, resetDuration]);
|
|
166
|
+
return /* @__PURE__ */ jsx("div", { ref: elementRef, className: cn("elyri-magnetic", className), children });
|
|
167
|
+
}
|
|
168
|
+
function ScaleIn({ children, className, from = 0.9, delay = 0, duration = 600, once = true }) {
|
|
169
|
+
const elementRef = useRef(null);
|
|
170
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
171
|
+
const [isIntersecting, setIsIntersecting] = useState(false);
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
const element = elementRef.current;
|
|
174
|
+
if (!element || prefersReducedMotion) return;
|
|
175
|
+
const observer = new IntersectionObserver(
|
|
176
|
+
([entry]) => {
|
|
177
|
+
if (entry.isIntersecting) {
|
|
178
|
+
setIsIntersecting(true);
|
|
179
|
+
if (once) observer.disconnect();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (!once) setIsIntersecting(false);
|
|
183
|
+
},
|
|
184
|
+
{ threshold: 0.1 }
|
|
185
|
+
);
|
|
186
|
+
observer.observe(element);
|
|
187
|
+
return () => observer.disconnect();
|
|
188
|
+
}, [once, prefersReducedMotion]);
|
|
189
|
+
const style = {
|
|
190
|
+
"--elyri-scale-in-from": from,
|
|
191
|
+
"--elyri-scale-in-delay": `${delay}ms`,
|
|
192
|
+
"--elyri-scale-in-duration": `${duration}ms`
|
|
193
|
+
};
|
|
194
|
+
const isVisible = prefersReducedMotion || isIntersecting;
|
|
195
|
+
return /* @__PURE__ */ jsx(
|
|
196
|
+
"div",
|
|
197
|
+
{
|
|
198
|
+
ref: elementRef,
|
|
199
|
+
className: cn("elyri-scale-in", isVisible && "elyri-scale-in--visible", className),
|
|
200
|
+
style,
|
|
201
|
+
children
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
function Spotlight({
|
|
206
|
+
children,
|
|
207
|
+
className,
|
|
208
|
+
color = "#7c8cff",
|
|
209
|
+
size = 240,
|
|
210
|
+
glow = true,
|
|
211
|
+
borderGlow = true,
|
|
212
|
+
radius = 16
|
|
213
|
+
}) {
|
|
214
|
+
const elementRef = useRef(null);
|
|
215
|
+
const frameRef = useRef(0);
|
|
216
|
+
const pointerRef = useRef(null);
|
|
217
|
+
const itemsRef = useRef([]);
|
|
218
|
+
useEffect(
|
|
219
|
+
() => () => {
|
|
220
|
+
cancelAnimationFrame(frameRef.current);
|
|
221
|
+
},
|
|
222
|
+
[]
|
|
223
|
+
);
|
|
224
|
+
const handlePointerMove = (event) => {
|
|
225
|
+
pointerRef.current = { x: event.clientX, y: event.clientY };
|
|
226
|
+
if (frameRef.current) return;
|
|
227
|
+
frameRef.current = requestAnimationFrame(() => {
|
|
228
|
+
frameRef.current = 0;
|
|
229
|
+
const element = elementRef.current;
|
|
230
|
+
const pointer = pointerRef.current;
|
|
231
|
+
if (!element || !pointer) return;
|
|
232
|
+
const rect = element.getBoundingClientRect();
|
|
233
|
+
element.style.setProperty("--elyri-spotlight-x", `${pointer.x - rect.left}px`);
|
|
234
|
+
element.style.setProperty("--elyri-spotlight-y", `${pointer.y - rect.top}px`);
|
|
235
|
+
for (const item of itemsRef.current) {
|
|
236
|
+
const itemRect = item.getBoundingClientRect();
|
|
237
|
+
item.style.setProperty("--elyri-spotlight-x", `${pointer.x - itemRect.left}px`);
|
|
238
|
+
item.style.setProperty("--elyri-spotlight-y", `${pointer.y - itemRect.top}px`);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
};
|
|
242
|
+
const handlePointerEnter = (event) => {
|
|
243
|
+
itemsRef.current = Array.from(
|
|
244
|
+
event.currentTarget.querySelectorAll(".elyri-spotlight__item")
|
|
245
|
+
);
|
|
246
|
+
handlePointerMove(event);
|
|
247
|
+
};
|
|
248
|
+
const style = {
|
|
249
|
+
"--elyri-spotlight-color": color,
|
|
250
|
+
"--elyri-spotlight-size": `${size}px`,
|
|
251
|
+
"--elyri-spotlight-radius": `${radius}px`
|
|
252
|
+
};
|
|
253
|
+
return /* @__PURE__ */ jsx(
|
|
254
|
+
"div",
|
|
255
|
+
{
|
|
256
|
+
ref: elementRef,
|
|
257
|
+
className: cn(
|
|
258
|
+
"elyri-spotlight",
|
|
259
|
+
glow && "elyri-spotlight--glow",
|
|
260
|
+
borderGlow && "elyri-spotlight--border",
|
|
261
|
+
className
|
|
262
|
+
),
|
|
263
|
+
style,
|
|
264
|
+
onPointerEnter: handlePointerEnter,
|
|
265
|
+
onPointerMove: handlePointerMove,
|
|
266
|
+
children: /* @__PURE__ */ jsx("div", { className: "elyri-spotlight__content", children })
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
var RESET_DURATION = 400;
|
|
271
|
+
var easeOutCubic3 = (progress) => 1 - (1 - progress) ** 3;
|
|
272
|
+
function Tilt({ children, className, max = 10, perspective = 800, glare = true }) {
|
|
273
|
+
const elementRef = useRef(null);
|
|
274
|
+
const moveFrameRef = useRef(0);
|
|
275
|
+
const resetFrameRef = useRef(0);
|
|
276
|
+
const rotationRef = useRef({ x: 0, y: 0 });
|
|
277
|
+
const pointerRef = useRef(null);
|
|
278
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
279
|
+
const [isActive, setIsActive] = useState(false);
|
|
280
|
+
useEffect(
|
|
281
|
+
() => () => {
|
|
282
|
+
cancelAnimationFrame(moveFrameRef.current);
|
|
283
|
+
cancelAnimationFrame(resetFrameRef.current);
|
|
284
|
+
},
|
|
285
|
+
[]
|
|
286
|
+
);
|
|
287
|
+
const setRotation = (x, y) => {
|
|
288
|
+
rotationRef.current = { x, y };
|
|
289
|
+
const element = elementRef.current;
|
|
290
|
+
if (!element) return;
|
|
291
|
+
element.style.setProperty("--elyri-tilt-rotate-x", `${x}deg`);
|
|
292
|
+
element.style.setProperty("--elyri-tilt-rotate-y", `${y}deg`);
|
|
293
|
+
};
|
|
294
|
+
const handlePointerMove = (event) => {
|
|
295
|
+
if (prefersReducedMotion) return;
|
|
296
|
+
cancelAnimationFrame(resetFrameRef.current);
|
|
297
|
+
resetFrameRef.current = 0;
|
|
298
|
+
pointerRef.current = { x: event.clientX, y: event.clientY };
|
|
299
|
+
setIsActive(true);
|
|
300
|
+
if (moveFrameRef.current) return;
|
|
301
|
+
moveFrameRef.current = requestAnimationFrame(() => {
|
|
302
|
+
moveFrameRef.current = 0;
|
|
303
|
+
const element = elementRef.current;
|
|
304
|
+
const pointer = pointerRef.current;
|
|
305
|
+
if (!element || !pointer) return;
|
|
306
|
+
const rect = element.getBoundingClientRect();
|
|
307
|
+
if (!rect.width || !rect.height) return;
|
|
308
|
+
const ratioX = (pointer.x - rect.left) / rect.width;
|
|
309
|
+
const ratioY = (pointer.y - rect.top) / rect.height;
|
|
310
|
+
setRotation((0.5 - ratioY) * 2 * max, (ratioX - 0.5) * 2 * max);
|
|
311
|
+
element.style.setProperty("--elyri-tilt-glare-x", `${ratioX * 100}%`);
|
|
312
|
+
element.style.setProperty("--elyri-tilt-glare-y", `${ratioY * 100}%`);
|
|
313
|
+
});
|
|
314
|
+
};
|
|
315
|
+
const handlePointerEnd = () => {
|
|
316
|
+
cancelAnimationFrame(moveFrameRef.current);
|
|
317
|
+
moveFrameRef.current = 0;
|
|
318
|
+
cancelAnimationFrame(resetFrameRef.current);
|
|
319
|
+
resetFrameRef.current = 0;
|
|
320
|
+
pointerRef.current = null;
|
|
321
|
+
setIsActive(false);
|
|
322
|
+
const from = { ...rotationRef.current };
|
|
323
|
+
if (prefersReducedMotion || !from.x && !from.y) return;
|
|
324
|
+
const startedAt = performance.now();
|
|
325
|
+
const step = (now) => {
|
|
326
|
+
const progress = Math.min((now - startedAt) / RESET_DURATION, 1);
|
|
327
|
+
const remaining = 1 - easeOutCubic3(progress);
|
|
328
|
+
setRotation(from.x * remaining, from.y * remaining);
|
|
329
|
+
if (progress < 1) resetFrameRef.current = requestAnimationFrame(step);
|
|
330
|
+
};
|
|
331
|
+
resetFrameRef.current = requestAnimationFrame(step);
|
|
332
|
+
};
|
|
333
|
+
return /* @__PURE__ */ jsxs(
|
|
334
|
+
"div",
|
|
335
|
+
{
|
|
336
|
+
ref: elementRef,
|
|
337
|
+
className: cn("elyri-tilt", isActive && "elyri-tilt--active", className),
|
|
338
|
+
style: { "--elyri-tilt-perspective": `${perspective}px` },
|
|
339
|
+
onPointerMove: handlePointerMove,
|
|
340
|
+
onPointerLeave: handlePointerEnd,
|
|
341
|
+
onPointerCancel: handlePointerEnd,
|
|
342
|
+
children: [
|
|
343
|
+
children,
|
|
344
|
+
glare && /* @__PURE__ */ jsx("span", { className: "elyri-tilt__glare", "aria-hidden": "true" })
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
var DEFAULT_COLORS = ["#3cffb0", "#2a8cff", "#c04dff"];
|
|
350
|
+
var FRAGMENT_SHADER = `
|
|
351
|
+
precision highp float;
|
|
352
|
+
|
|
353
|
+
uniform vec2 uResolution;
|
|
354
|
+
uniform float uTime;
|
|
355
|
+
uniform vec2 uPointer;
|
|
356
|
+
uniform vec3 uColor1;
|
|
357
|
+
uniform vec3 uColor2;
|
|
358
|
+
uniform vec3 uColor3;
|
|
359
|
+
uniform float uIntensity;
|
|
360
|
+
uniform float uStars;
|
|
361
|
+
|
|
362
|
+
float hash(vec2 p) {
|
|
363
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
364
|
+
p += dot(p, p + 45.32);
|
|
365
|
+
return fract(p.x * p.y);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
float noise(vec2 p) {
|
|
369
|
+
vec2 i = floor(p);
|
|
370
|
+
vec2 f = fract(p);
|
|
371
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
372
|
+
return mix(
|
|
373
|
+
mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x),
|
|
374
|
+
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x),
|
|
375
|
+
u.y
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
float fbm(vec2 p) {
|
|
380
|
+
float v = 0.0;
|
|
381
|
+
float a = 0.5;
|
|
382
|
+
for (int i = 0; i < 4; i++) {
|
|
383
|
+
v += a * noise(p);
|
|
384
|
+
p = p * 2.03 + vec2(17.1, 9.2);
|
|
385
|
+
a *= 0.5;
|
|
386
|
+
}
|
|
387
|
+
return v;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
vec3 aces(vec3 x) {
|
|
391
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
void main() {
|
|
395
|
+
vec2 uv = gl_FragCoord.xy / uResolution.y;
|
|
396
|
+
vec2 pointer = vec2(uPointer.x, uResolution.y - uPointer.y) / uResolution.y;
|
|
397
|
+
float t = uTime;
|
|
398
|
+
|
|
399
|
+
// \u591C\u7A7A\u5E95\u8272\uFF1A\u5730\u5E73\u7EBF\u9644\u8FD1\u7565\u5E26\u5E18\u5E95\u8272\u7684\u5FAE\u5149
|
|
400
|
+
vec3 color = mix(vec3(0.002, 0.004, 0.012), vec3(0.006, 0.01, 0.03), uv.y);
|
|
401
|
+
color += uColor1 * 0.025 * exp(-uv.y * 5.0);
|
|
402
|
+
|
|
403
|
+
// \u661F\u7A7A
|
|
404
|
+
vec2 grid = uv * 55.0;
|
|
405
|
+
vec2 cell = floor(grid);
|
|
406
|
+
float rnd = hash(cell);
|
|
407
|
+
vec2 offset = vec2(hash(cell + 3.1), hash(cell + 7.7)) - 0.5;
|
|
408
|
+
float starDist = length(fract(grid) - 0.5 - offset * 0.7);
|
|
409
|
+
float twinkle = 0.6 + 0.4 * sin(t * (1.5 + rnd * 3.0) + rnd * 40.0);
|
|
410
|
+
float star = step(0.93, rnd) * exp(-starDist * starDist * 180.0) * twinkle * smoothstep(0.1, 0.6, uv.y);
|
|
411
|
+
color += vec3(0.8, 0.85, 1.0) * star * uStars;
|
|
412
|
+
|
|
413
|
+
vec3 aurora = vec3(0.0);
|
|
414
|
+
for (int i = 0; i < 4; i++) {
|
|
415
|
+
float fi = float(i);
|
|
416
|
+
float x = uv.x * (0.6 + fi * 0.15) + fi * 3.7;
|
|
417
|
+
float curve = 0.42 + fi * 0.09 + (fbm(vec2(x * 1.2 - t * 0.05 * (1.0 + fi * 0.3), fi * 5.3 + t * 0.03)) - 0.5) * 0.45;
|
|
418
|
+
float d = uv.y - curve;
|
|
419
|
+
float body = d > 0.0 ? exp(-d * (3.5 + fi)) : exp(d * 40.0);
|
|
420
|
+
float rays = fbm(vec2(x * 28.0 + curve * 6.0, t * 0.35 + fi));
|
|
421
|
+
rays = 0.25 + 1.5 * rays * rays;
|
|
422
|
+
float flow = 0.6 + 0.4 * sin(x * 3.0 - t * 0.4 + fi * 1.7);
|
|
423
|
+
vec3 c = mix(uColor1, uColor2, smoothstep(0.0, 0.3, d));
|
|
424
|
+
c = mix(c, uColor3, smoothstep(0.12, 0.55, d) * (0.55 + 0.45 * sin(fi * 2.1 + x * 0.8 + t * 0.1)));
|
|
425
|
+
aurora += c * body * rays * flow * (0.5 - fi * 0.08);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
vec2 dp = uv - pointer;
|
|
429
|
+
aurora *= 1.0 + 0.7 * exp(-dot(dp, dp) * 6.0);
|
|
430
|
+
color += aurora * uIntensity;
|
|
431
|
+
|
|
432
|
+
vec2 vc = gl_FragCoord.xy / uResolution - 0.5;
|
|
433
|
+
color *= 1.0 - dot(vc, vc) * 0.9;
|
|
434
|
+
color = pow(aces(color * 1.2), vec3(1.0 / 2.2));
|
|
435
|
+
color += (hash(gl_FragCoord.xy + fract(t)) - 0.5) / 255.0;
|
|
436
|
+
|
|
437
|
+
gl_FragColor = vec4(color, 1.0);
|
|
438
|
+
}
|
|
439
|
+
`;
|
|
440
|
+
function Aurora({
|
|
441
|
+
children,
|
|
442
|
+
className,
|
|
443
|
+
colors = DEFAULT_COLORS,
|
|
444
|
+
speed = 1,
|
|
445
|
+
intensity = 1,
|
|
446
|
+
stars = true,
|
|
447
|
+
interactive = true
|
|
448
|
+
}) {
|
|
449
|
+
const [bottom = DEFAULT_COLORS[0], middle = DEFAULT_COLORS[1], top = DEFAULT_COLORS[2]] = colors;
|
|
450
|
+
const canvasRef = useShaderCanvas({
|
|
451
|
+
fragmentShader: FRAGMENT_SHADER,
|
|
452
|
+
speed,
|
|
453
|
+
interactive,
|
|
454
|
+
onDraw: ({ gl, uniform }) => {
|
|
455
|
+
gl.uniform3fv(uniform("uColor1"), hexToLinearRgb(bottom));
|
|
456
|
+
gl.uniform3fv(uniform("uColor2"), hexToLinearRgb(middle));
|
|
457
|
+
gl.uniform3fv(uniform("uColor3"), hexToLinearRgb(top));
|
|
458
|
+
gl.uniform1f(uniform("uIntensity"), Math.max(0, intensity));
|
|
459
|
+
gl.uniform1f(uniform("uStars"), stars ? 1 : 0);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("elyri-aurora", className), style: { "--elyri-aurora-color": bottom }, children: [
|
|
463
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-aurora__canvas", "aria-hidden": "true" }),
|
|
464
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-aurora__content", children })
|
|
465
|
+
] });
|
|
466
|
+
}
|
|
467
|
+
var FRAGMENT_SHADER2 = `
|
|
468
|
+
precision highp float;
|
|
469
|
+
|
|
470
|
+
uniform vec2 uResolution;
|
|
471
|
+
uniform float uTime;
|
|
472
|
+
uniform vec2 uPointer;
|
|
473
|
+
uniform vec3 uBase;
|
|
474
|
+
uniform vec3 uHighlight;
|
|
475
|
+
uniform float uDensity;
|
|
476
|
+
uniform float uRipple;
|
|
477
|
+
|
|
478
|
+
float hash(vec2 p) {
|
|
479
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
480
|
+
p += dot(p, p + 45.32);
|
|
481
|
+
return fract(p.x * p.y);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
vec2 hash2(vec2 p) {
|
|
485
|
+
p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
|
|
486
|
+
return fract(sin(p) * 43758.5453);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
float cellEdge(vec2 p, float t) {
|
|
490
|
+
vec2 i = floor(p);
|
|
491
|
+
vec2 f = fract(p);
|
|
492
|
+
float f1 = 8.0;
|
|
493
|
+
float f2 = 8.0;
|
|
494
|
+
for (int y = -1; y <= 1; y++) {
|
|
495
|
+
for (int x = -1; x <= 1; x++) {
|
|
496
|
+
vec2 g = vec2(float(x), float(y));
|
|
497
|
+
vec2 o = 0.5 + 0.4 * sin(t * 0.8 + 6.2831 * hash2(i + g));
|
|
498
|
+
float d = length(g + o - f);
|
|
499
|
+
if (d < f1) {
|
|
500
|
+
f2 = f1;
|
|
501
|
+
f1 = d;
|
|
502
|
+
} else if (d < f2) {
|
|
503
|
+
f2 = d;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return f2 - f1;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
float caustic(vec2 p, float t) {
|
|
511
|
+
p += 0.25 * vec2(sin(p.y * 1.3 + t * 0.7), cos(p.x * 1.1 - t * 0.6));
|
|
512
|
+
float a = exp(-cellEdge(p, t) * 9.0);
|
|
513
|
+
float b = exp(-cellEdge(p * 1.7 + vec2(3.1, 7.4), t * 1.3) * 9.0);
|
|
514
|
+
return a * 0.7 + b * 0.45 + a * b * 1.5;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
vec3 aces(vec3 x) {
|
|
518
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
void main() {
|
|
522
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
523
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
524
|
+
float t = uTime;
|
|
525
|
+
vec2 p = frag / minRes * 4.0 * uDensity;
|
|
526
|
+
|
|
527
|
+
// \u6307\u9488\u5904\u8361\u5F00\u7684\u6C34\u6CE2
|
|
528
|
+
vec2 dp = (frag - uPointer) / minRes;
|
|
529
|
+
float r = length(dp);
|
|
530
|
+
p += dp / (r + 1e-4) * sin(r * 38.0 - t * 4.0) * 0.06 * exp(-r * 5.0) * uRipple;
|
|
531
|
+
|
|
532
|
+
vec3 caus = vec3(
|
|
533
|
+
caustic(p + vec2(0.014, 0.0), t),
|
|
534
|
+
caustic(p, t),
|
|
535
|
+
caustic(p - vec2(0.014, 0.0), t)
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
float depth = frag.y / uResolution.y;
|
|
539
|
+
vec3 color = mix(uBase * 0.35, uBase * 0.025, depth);
|
|
540
|
+
|
|
541
|
+
// \u659C\u5C04\u5149\u675F
|
|
542
|
+
float x = frag.x / minRes + depth * 0.35;
|
|
543
|
+
float rays = (0.5 + 0.5 * sin(x * 9.0 + sin(x * 3.1 + t * 0.3) * 2.0 + t * 0.2)) * (0.5 + 0.5 * sin(x * 17.0 - t * 0.35));
|
|
544
|
+
color += uHighlight * 0.12 * rays * rays * (1.0 - depth) * (1.0 - depth);
|
|
545
|
+
|
|
546
|
+
float focus = 0.6 + 0.8 * exp(-dot(dp, dp) * 3.0) * uRipple;
|
|
547
|
+
color += uHighlight * caus * 0.5 * mix(1.0, 0.3, depth) * focus;
|
|
548
|
+
|
|
549
|
+
vec2 vc = frag / uResolution - 0.5;
|
|
550
|
+
color *= 1.0 - dot(vc, vc) * 1.1;
|
|
551
|
+
color = pow(aces(color * 1.2), vec3(1.0 / 2.2));
|
|
552
|
+
color += (hash(frag + fract(t)) - 0.5) / 255.0;
|
|
553
|
+
|
|
554
|
+
gl_FragColor = vec4(color, 1.0);
|
|
555
|
+
}
|
|
556
|
+
`;
|
|
557
|
+
function Caustics({
|
|
558
|
+
children,
|
|
559
|
+
className,
|
|
560
|
+
color = "#0a6fa8",
|
|
561
|
+
highlightColor = "#c8fbff",
|
|
562
|
+
density = 1,
|
|
563
|
+
speed = 1,
|
|
564
|
+
interactive = true
|
|
565
|
+
}) {
|
|
566
|
+
const canvasRef = useShaderCanvas({
|
|
567
|
+
fragmentShader: FRAGMENT_SHADER2,
|
|
568
|
+
speed,
|
|
569
|
+
interactive,
|
|
570
|
+
onDraw: ({ gl, uniform }) => {
|
|
571
|
+
gl.uniform3fv(uniform("uBase"), hexToLinearRgb(color));
|
|
572
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
573
|
+
gl.uniform1f(uniform("uDensity"), Math.max(0.2, density));
|
|
574
|
+
gl.uniform1f(uniform("uRipple"), interactive ? 1 : 0);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("elyri-caustics", className), style: { "--elyri-caustics-color": color }, children: [
|
|
578
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-caustics__canvas", "aria-hidden": "true" }),
|
|
579
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-caustics__content", children })
|
|
580
|
+
] });
|
|
581
|
+
}
|
|
582
|
+
var FRAGMENT_SHADER3 = `
|
|
583
|
+
precision highp float;
|
|
584
|
+
|
|
585
|
+
uniform vec2 uResolution;
|
|
586
|
+
uniform float uTime;
|
|
587
|
+
uniform vec2 uPointer;
|
|
588
|
+
uniform vec3 uLine;
|
|
589
|
+
uniform vec3 uHighlight;
|
|
590
|
+
uniform vec3 uBg;
|
|
591
|
+
uniform float uLevels;
|
|
592
|
+
uniform float uDpr;
|
|
593
|
+
|
|
594
|
+
const float SCALE = 2.4;
|
|
595
|
+
|
|
596
|
+
float hash(vec2 p) {
|
|
597
|
+
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
598
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
599
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
float noise(vec2 p) {
|
|
603
|
+
vec2 i = floor(p);
|
|
604
|
+
vec2 f = fract(p);
|
|
605
|
+
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
|
|
606
|
+
return mix(mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x), mix(hash(i + vec2(0.0, 1.0)), hash(i + 1.0), u.x), u.y);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
float fbm(vec2 p) {
|
|
610
|
+
float v = 0.0;
|
|
611
|
+
float a = 0.5;
|
|
612
|
+
mat2 rot = mat2(0.8, -0.6, 0.6, 0.8);
|
|
613
|
+
for (int i = 0; i < 3; i++) {
|
|
614
|
+
v += a * noise(p);
|
|
615
|
+
p = rot * p * 2.03 + 17.1;
|
|
616
|
+
a *= 0.5;
|
|
617
|
+
}
|
|
618
|
+
return v;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
float terrain(vec2 p, vec2 hill, float t) {
|
|
622
|
+
vec2 warp = vec2(noise(p * 0.55 + vec2(t * 0.08, 3.1)), noise(p * 0.55 + vec2(7.7, -t * 0.07)));
|
|
623
|
+
float h = fbm(p + warp * 1.3 + vec2(t * 0.035, -t * 0.025));
|
|
624
|
+
vec2 d = p - hill;
|
|
625
|
+
return h + 0.2 * exp(-dot(d, d) * 1.6);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
void main() {
|
|
629
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
630
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
631
|
+
float px = SCALE / minRes;
|
|
632
|
+
vec2 p = frag * px;
|
|
633
|
+
vec2 hill = uPointer * px;
|
|
634
|
+
float t = uTime;
|
|
635
|
+
|
|
636
|
+
float h = terrain(p, hill, t);
|
|
637
|
+
float hx = terrain(p + vec2(px, 0.0), hill, t);
|
|
638
|
+
float hy = terrain(p + vec2(0.0, px), hill, t);
|
|
639
|
+
|
|
640
|
+
float f = h * uLevels;
|
|
641
|
+
float slope = max(length(vec2(hx - h, hy - h)) * uLevels, 1e-5);
|
|
642
|
+
float fr = fract(f);
|
|
643
|
+
float dist = min(fr, 1.0 - fr) / slope;
|
|
644
|
+
|
|
645
|
+
float index = floor(f + 0.5);
|
|
646
|
+
float major = 1.0 - step(0.5, abs(mod(index, 5.0)));
|
|
647
|
+
float halfWidth = mix(0.5, 0.95, major) * uDpr;
|
|
648
|
+
float line = 1.0 - smoothstep(halfWidth - 0.6, halfWidth + 0.6, dist);
|
|
649
|
+
|
|
650
|
+
// \u7EBF\u95F4\u8DDD\u5C0F\u4E8E\u6570\u50CF\u7D20\u65F6\u6DE1\u51FA\uFF0C\u907F\u514D\u9661\u5761\u5904\u7CCA\u6210\u4E00\u7247
|
|
651
|
+
line *= smoothstep(2.5 * uDpr, 6.0 * uDpr, 1.0 / slope);
|
|
652
|
+
|
|
653
|
+
float radius = 240.0 * uDpr;
|
|
654
|
+
vec2 dp = frag - uPointer;
|
|
655
|
+
float near = exp(-dot(dp, dp) / (radius * radius));
|
|
656
|
+
|
|
657
|
+
vec2 q = (frag - 0.5 * uResolution) / (0.5 * uResolution);
|
|
658
|
+
float mask = mix(0.4, 1.0, 1.0 - smoothstep(0.45, 1.4, length(q)));
|
|
659
|
+
|
|
660
|
+
float alpha = line * mix(0.32, 0.7, major) * (1.0 + 0.9 * near) * mask;
|
|
661
|
+
vec3 lineColor = mix(uLine, uHighlight, clamp(near * 1.2, 0.0, 1.0));
|
|
662
|
+
vec3 color = mix(uBg, lineColor, clamp(alpha, 0.0, 1.0));
|
|
663
|
+
|
|
664
|
+
color = pow(color, vec3(1.0 / 2.2));
|
|
665
|
+
color += (hash(frag + fract(t)) - 0.5) / 255.0;
|
|
666
|
+
|
|
667
|
+
gl_FragColor = vec4(color, 1.0);
|
|
668
|
+
}
|
|
669
|
+
`;
|
|
670
|
+
function Contours({
|
|
671
|
+
children,
|
|
672
|
+
className,
|
|
673
|
+
color = "#8a90a6",
|
|
674
|
+
highlightColor = "#f08a4b",
|
|
675
|
+
density = 1,
|
|
676
|
+
speed = 1,
|
|
677
|
+
interactive = true
|
|
678
|
+
}) {
|
|
679
|
+
const scheme = useColorScheme();
|
|
680
|
+
const canvasRef = useShaderCanvas({
|
|
681
|
+
fragmentShader: FRAGMENT_SHADER3,
|
|
682
|
+
speed,
|
|
683
|
+
interactive,
|
|
684
|
+
onDraw: ({ gl, uniform, dpr }) => {
|
|
685
|
+
gl.uniform3fv(uniform("uLine"), hexToLinearRgb(color));
|
|
686
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
687
|
+
gl.uniform3fv(uniform("uBg"), hexToLinearRgb(scheme === "light" ? "#f9f9f7" : "#0a0b0f"));
|
|
688
|
+
gl.uniform1f(uniform("uLevels"), 18 * Math.max(0.2, density));
|
|
689
|
+
gl.uniform1f(uniform("uDpr"), dpr);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
return /* @__PURE__ */ jsxs(
|
|
693
|
+
"div",
|
|
694
|
+
{
|
|
695
|
+
className: cn("elyri-contours", className),
|
|
696
|
+
"data-scheme": scheme,
|
|
697
|
+
style: { "--elyri-contours-color": color },
|
|
698
|
+
children: [
|
|
699
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-contours__canvas", "aria-hidden": "true" }),
|
|
700
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-contours__content", children })
|
|
701
|
+
]
|
|
702
|
+
}
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
var FRAGMENT_SHADER4 = `
|
|
706
|
+
precision highp float;
|
|
707
|
+
|
|
708
|
+
uniform vec2 uResolution;
|
|
709
|
+
uniform float uTime;
|
|
710
|
+
uniform vec2 uPointer;
|
|
711
|
+
uniform vec3 uDot;
|
|
712
|
+
uniform vec3 uHighlight;
|
|
713
|
+
uniform vec3 uBg;
|
|
714
|
+
uniform float uGap;
|
|
715
|
+
uniform float uDpr;
|
|
716
|
+
|
|
717
|
+
float hash(vec2 p) {
|
|
718
|
+
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
719
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
720
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
float noise(vec2 p) {
|
|
724
|
+
vec2 i = floor(p);
|
|
725
|
+
vec2 f = fract(p);
|
|
726
|
+
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
|
|
727
|
+
return mix(mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x), mix(hash(i + vec2(0.0, 1.0)), hash(i + 1.0), u.x), u.y);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
void main() {
|
|
731
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
732
|
+
float gap = uGap * uDpr;
|
|
733
|
+
float radius = 170.0 * uDpr;
|
|
734
|
+
float t = uTime;
|
|
735
|
+
vec2 cell = floor(frag / gap);
|
|
736
|
+
|
|
737
|
+
float best = 0.0;
|
|
738
|
+
float bestTint = 0.0;
|
|
739
|
+
for (int j = -1; j <= 1; j++) {
|
|
740
|
+
for (int i = -1; i <= 1; i++) {
|
|
741
|
+
vec2 id = cell + vec2(float(i), float(j));
|
|
742
|
+
vec2 center = (id + 0.5) * gap;
|
|
743
|
+
|
|
744
|
+
vec2 away = center - uPointer;
|
|
745
|
+
float d = length(away);
|
|
746
|
+
float lens = exp(-d * d / (radius * radius));
|
|
747
|
+
center += away / max(d, 1.0) * lens * gap * 0.32;
|
|
748
|
+
|
|
749
|
+
// \u4E24\u5C42\u566A\u58F0\uFF1A\u5927\u5C3A\u5EA6\u7684\u300C\u98CE\u300D+ \u5C0F\u5C3A\u5EA6\u7684\u7EC6\u788E\u8D77\u4F0F
|
|
750
|
+
float wave = noise(id * 0.075 + vec2(t * 0.11, -t * 0.07)) * 0.65
|
|
751
|
+
+ noise(id * 0.21 - vec2(t * 0.05, t * 0.09)) * 0.35;
|
|
752
|
+
wave = smoothstep(0.3, 0.85, wave);
|
|
753
|
+
|
|
754
|
+
float r = max(gap * (0.055 + 0.075 * wave + 0.1 * lens), 0.7 * uDpr);
|
|
755
|
+
float cover = 1.0 - smoothstep(r - 0.8, r + 0.8, length(frag - center));
|
|
756
|
+
float alpha = cover * clamp(0.22 + 0.5 * wave + 0.55 * lens, 0.0, 1.0);
|
|
757
|
+
if (alpha > best) {
|
|
758
|
+
best = alpha;
|
|
759
|
+
bestTint = clamp(wave * wave * 0.55 + lens * 0.95, 0.0, 1.0);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// \u56DB\u5468\u6E10\u9690\uFF0C\u89C6\u7EBF\u805A\u7126\u5728\u4E2D\u592E
|
|
765
|
+
vec2 q = (frag - 0.5 * uResolution) / (0.5 * uResolution);
|
|
766
|
+
float mask = mix(0.18, 1.0, 1.0 - smoothstep(0.3, 1.3, length(q)));
|
|
767
|
+
|
|
768
|
+
vec3 dotColor = mix(uDot, uHighlight, bestTint);
|
|
769
|
+
vec3 color = mix(uBg, dotColor, best * mask);
|
|
770
|
+
|
|
771
|
+
// \u6307\u9488\u4E0B\u65B9\u6781\u6DE1\u7684\u5149\u6655
|
|
772
|
+
float glow = exp(-dot(frag - uPointer, frag - uPointer) / (radius * radius * 2.5));
|
|
773
|
+
color += uHighlight * glow * 0.035;
|
|
774
|
+
|
|
775
|
+
color = pow(color, vec3(1.0 / 2.2));
|
|
776
|
+
color += (hash(frag + fract(t)) - 0.5) / 255.0;
|
|
777
|
+
|
|
778
|
+
gl_FragColor = vec4(color, 1.0);
|
|
779
|
+
}
|
|
780
|
+
`;
|
|
781
|
+
function DotField({
|
|
782
|
+
children,
|
|
783
|
+
className,
|
|
784
|
+
color = "#8a90a6",
|
|
785
|
+
highlightColor = "#7c6cff",
|
|
786
|
+
gap = 22,
|
|
787
|
+
speed = 1,
|
|
788
|
+
interactive = true
|
|
789
|
+
}) {
|
|
790
|
+
const scheme = useColorScheme();
|
|
791
|
+
const canvasRef = useShaderCanvas({
|
|
792
|
+
fragmentShader: FRAGMENT_SHADER4,
|
|
793
|
+
speed,
|
|
794
|
+
interactive,
|
|
795
|
+
onDraw: ({ gl, uniform, dpr }) => {
|
|
796
|
+
gl.uniform3fv(uniform("uDot"), hexToLinearRgb(color));
|
|
797
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
798
|
+
gl.uniform3fv(uniform("uBg"), hexToLinearRgb(scheme === "light" ? "#fafafb" : "#0a0a0e"));
|
|
799
|
+
gl.uniform1f(uniform("uGap"), Math.max(8, gap));
|
|
800
|
+
gl.uniform1f(uniform("uDpr"), dpr);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
return /* @__PURE__ */ jsxs(
|
|
804
|
+
"div",
|
|
805
|
+
{
|
|
806
|
+
className: cn("elyri-dot-field", className),
|
|
807
|
+
"data-scheme": scheme,
|
|
808
|
+
style: { "--elyri-dot-field-color": color, "--elyri-dot-field-gap": `${Math.max(8, gap)}px` },
|
|
809
|
+
children: [
|
|
810
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-dot-field__canvas", "aria-hidden": "true" }),
|
|
811
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-dot-field__content", children })
|
|
812
|
+
]
|
|
813
|
+
}
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
var FRAGMENT_SHADER5 = `
|
|
817
|
+
precision highp float;
|
|
818
|
+
|
|
819
|
+
uniform vec2 uResolution;
|
|
820
|
+
uniform float uTime;
|
|
821
|
+
uniform vec2 uPointer;
|
|
822
|
+
uniform float uScale;
|
|
823
|
+
uniform vec3 uBase;
|
|
824
|
+
uniform vec3 uHighlight;
|
|
825
|
+
uniform float uFlare;
|
|
826
|
+
uniform float uScheme;
|
|
827
|
+
|
|
828
|
+
const float R = 0.92;
|
|
829
|
+
const float D = 0.30;
|
|
830
|
+
const float B = 0.8697;
|
|
831
|
+
const float ROW = 0.5;
|
|
832
|
+
const float BEVEL = 0.075;
|
|
833
|
+
const float TAU = 6.28318;
|
|
834
|
+
|
|
835
|
+
float hash(vec2 p) {
|
|
836
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
837
|
+
p += dot(p, p + 45.32);
|
|
838
|
+
return fract(p.x * p.y);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
float sdScale(vec2 p) {
|
|
842
|
+
p = abs(p);
|
|
843
|
+
return ((p.y - B) * D > p.x * B) ? length(p - vec2(0.0, B)) : length(p - vec2(-D, 0.0)) - R;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
float scaleHeight(vec2 q) {
|
|
847
|
+
float inner = clamp(-sdScale(q) / BEVEL, 0.0, 1.0);
|
|
848
|
+
float bevel = sqrt(1.0 - (1.0 - inner) * (1.0 - inner));
|
|
849
|
+
vec2 d = vec2(q.x / 0.62, (q.y - 0.35) / 0.75);
|
|
850
|
+
float dome = 0.14 * (1.0 - dot(d, d));
|
|
851
|
+
float keel = 0.035 * exp(-q.x * q.x / 0.03) * smoothstep(-0.1, B, q.y);
|
|
852
|
+
return bevel * (0.07 + dome + keel);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// \u5F00\u5408\uFF1A\u4E00\u9053\u6CE2\u6CBF\u8EAB\u4F53\u65B9\u5411\u63A8\u8FDB\uFF0C\u7ECF\u8FC7\u7684\u9CDE\u7247\u4F9D\u6B21\u5F20\u5F00\u518D\u5408\u62E2
|
|
856
|
+
float openAmount(vec2 c) {
|
|
857
|
+
return uFlare * smoothstep(0.15, 1.0, sin(c.y * 0.45 - uTime * 1.3 + c.x * 0.3));
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// \u5F20\u5F00\u65F6\u9CDE\u7247\u7ED5\u6839\u90E8\u7FD8\u8D77\uFF0C\u900F\u89C6\u4E0A\u8868\u73B0\u4E3A\u9CDE\u5C16\u4F38\u957F\u3001\u7565\u5FAE\u53D8\u5BBD
|
|
861
|
+
vec2 warp(vec2 q, float o) {
|
|
862
|
+
return vec2(q.x / (1.0 + 0.05 * o), (q.y + 0.2) / (1.0 + 0.2 * o) - 0.2);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
vec3 aces(vec3 x) {
|
|
866
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
void main() {
|
|
870
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
871
|
+
// \u5F62\u72B6\u7A7A\u95F4\u7684 y\uFF08\u9CDE\u5C16\u65B9\u5411\uFF09\u5BF9\u5E94\u5C4F\u5E55 x\uFF0C\u5B9E\u73B0\u4FA7\u5411\u6392\u5217
|
|
872
|
+
vec2 p = frag.yx / uScale;
|
|
873
|
+
float px = 1.0 / uScale;
|
|
874
|
+
float t = uTime;
|
|
875
|
+
|
|
876
|
+
// \u4ECE\u5DE6\u5230\u53F3\u67E5\u627E\u7B2C\u4E00\u7247\u8986\u76D6\u5F53\u524D\u50CF\u7D20\u7684\u9CDE\uFF0C\u5E76\u8BB0\u5F55\u5230\u538B\u5728\u4E0A\u9762\u7684\u9CDE\u7247\u8FB9\u7F18\u7684\u8DDD\u79BB\u3002
|
|
877
|
+
// \u9634\u5F71\u4E0E\u7F1D\u9699\u6563\u5149\u6309\u6BCF\u7247\u4E0A\u65B9\u9CDE\u5206\u522B\u8BA1\u7B97\u540E\u53D6\u6700\u5927\u503C\uFF0C\u907F\u514D\u5728\u4E24\u7247\u5F20\u5F00\u7A0B\u5EA6\u4E0D\u540C\u7684\u9CDE\u4E4B\u95F4\u51FA\u73B0\u63A5\u7F1D
|
|
878
|
+
float j0 = floor(p.y / ROW);
|
|
879
|
+
vec2 center = vec2(0.0);
|
|
880
|
+
vec2 cell = vec2(0.0);
|
|
881
|
+
float sd = -1.0;
|
|
882
|
+
float cover = 1.0;
|
|
883
|
+
float shade = 0.0;
|
|
884
|
+
float gap = 0.0;
|
|
885
|
+
float open = 0.0;
|
|
886
|
+
float above = 1.0;
|
|
887
|
+
float aboveShade = 0.0;
|
|
888
|
+
float aboveGap = 0.0;
|
|
889
|
+
float found = 0.0;
|
|
890
|
+
for (int dj = -2; dj <= 2; dj++) {
|
|
891
|
+
float j = j0 + float(dj);
|
|
892
|
+
float offset = mod(j, 2.0) * 0.5;
|
|
893
|
+
float i0 = floor(p.x - offset + 0.5);
|
|
894
|
+
float rowMin = 1.0;
|
|
895
|
+
float rowShade = 0.0;
|
|
896
|
+
float rowGap = 0.0;
|
|
897
|
+
for (int di = -1; di <= 1; di++) {
|
|
898
|
+
vec2 id = vec2(i0 + float(di), j);
|
|
899
|
+
vec2 c = vec2(id.x + offset, j * ROW);
|
|
900
|
+
float o = openAmount(c);
|
|
901
|
+
float d = sdScale(warp(p - c, o));
|
|
902
|
+
if (found < 0.5 && d < 0.0) {
|
|
903
|
+
found = 1.0;
|
|
904
|
+
center = c;
|
|
905
|
+
cell = id;
|
|
906
|
+
sd = d;
|
|
907
|
+
open = o;
|
|
908
|
+
cover = above;
|
|
909
|
+
shade = aboveShade;
|
|
910
|
+
gap = aboveGap;
|
|
911
|
+
}
|
|
912
|
+
rowMin = min(rowMin, d);
|
|
913
|
+
// \u4E0A\u65B9\u9CDE\u7247\u5F20\u5F00\u65F6\u6295\u4E0B\u66F4\u5BBD\u7684\u9634\u5F71\uFF0C\u4E0B\u65B9\u900F\u51FA\u6563\u5C04\u5149
|
|
914
|
+
rowShade = max(rowShade, 1.0 - smoothstep(0.0, 0.16 + 0.3 * o, d));
|
|
915
|
+
rowGap = max(rowGap, (1.0 - smoothstep(0.0, 0.1 + 0.25 * o, d)) * o);
|
|
916
|
+
}
|
|
917
|
+
if (found < 0.5) {
|
|
918
|
+
above = min(above, rowMin);
|
|
919
|
+
aboveShade = max(aboveShade, rowShade);
|
|
920
|
+
aboveGap = max(aboveGap, rowGap);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
vec2 q = warp(p - center, open);
|
|
925
|
+
float seed = hash(cell);
|
|
926
|
+
float seed2 = hash(cell + 17.31);
|
|
927
|
+
|
|
928
|
+
float e = 0.006;
|
|
929
|
+
vec2 grad = vec2(
|
|
930
|
+
scaleHeight(q + vec2(e, 0.0)) - scaleHeight(q - vec2(e, 0.0)),
|
|
931
|
+
scaleHeight(q + vec2(0.0, e)) - scaleHeight(q - vec2(0.0, e))
|
|
932
|
+
) / (2.0 * e);
|
|
933
|
+
vec3 ns = normalize(vec3(-grad, 1.0));
|
|
934
|
+
|
|
935
|
+
// \u6BCF\u7247\u9CDE\u5404\u81EA\u7565\u5FAE\u503E\u659C\uFF0C\u518D\u53E0\u4E00\u9053\u6CBF\u8EAB\u4F53\u65B9\u5411\u6EDA\u52A8\u7684\u8D77\u4F0F\uFF0C\u8BA9\u53CD\u5149\u6761\u5728\u9CDE\u95F4\u6D41\u52A8
|
|
936
|
+
float wave = sin(center.y * 0.35 - t * 0.9 + sin(center.x * 0.2 + t * 0.25) * 1.2);
|
|
937
|
+
ns = normalize(ns + vec3((seed - 0.5) * 0.22, (seed2 - 0.5) * 0.22 + wave * 0.1 - open * 0.45, 0.0));
|
|
938
|
+
vec3 n = vec3(ns.y, ns.x, ns.z);
|
|
939
|
+
|
|
940
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
941
|
+
vec3 V = vec3(0.0, 0.0, 1.0);
|
|
942
|
+
vec3 toLight = vec3(uPointer - frag, minRes * 0.6);
|
|
943
|
+
float dist = length(toLight);
|
|
944
|
+
vec3 L = toLight / dist;
|
|
945
|
+
float atten = 1.0 / (1.0 + 1.5 * pow(dist / minRes, 2.0));
|
|
946
|
+
float NdotH = max(dot(n, normalize(L + V)), 0.0);
|
|
947
|
+
float NdotV = max(n.z, 0.0);
|
|
948
|
+
float soft = pow(NdotH, 24.0) * atten;
|
|
949
|
+
float ao = mix(0.04, 1.0, 1.0 - shade);
|
|
950
|
+
float fres = 0.35 + 0.65 * pow(1.0 - NdotV, 2.0);
|
|
951
|
+
|
|
952
|
+
// \u7EBF\u5F62\u706F\u5E26\uFF1A\u4E3B\u706F\u5E26\u7A7F\u8FC7\u5149\u6E90\u4F4D\u7F6E\u5E76\u7F13\u6162\u8F6C\u52A8\uFF0C\u526F\u706F\u5E26\u53EA\u843D\u5728\u671D\u5411\u4E00\u4FA7\u7684\u5012\u89D2\u4E0A
|
|
953
|
+
vec3 Rf = reflect(-V, n);
|
|
954
|
+
vec2 toL = (uPointer - frag) / minRes;
|
|
955
|
+
float a = 0.7 + 0.45 * sin(t * 0.17);
|
|
956
|
+
vec2 dir = vec2(cos(a), sin(a));
|
|
957
|
+
float s1 = dot(Rf.xy, dir) - dot(toL, dir) * 1.3 + 0.12 * sin(t * 0.5 + seed * TAU);
|
|
958
|
+
float line1 = exp(-s1 * s1 / 0.0022);
|
|
959
|
+
float band1 = exp(-s1 * s1 / 0.09);
|
|
960
|
+
float s2 = dot(Rf.xy, vec2(-dir.y, dir.x)) - 0.85 - 0.15 * sin(t * 0.33);
|
|
961
|
+
float line2 = exp(-s2 * s2 / 0.01);
|
|
962
|
+
|
|
963
|
+
// \u672C\u4F53\u8FD1\u9ED1\uFF0C\u53EA\u5728\u671D\u5411\u5149\u6E90\u7684\u533A\u57DF\u6CDB\u51FA\u4E00\u5C42\u67D4\u548C\u7684\u5E95\u8272\uFF0C\u4EAE\u5EA6\u4E3B\u8981\u6765\u81EA\u53CD\u5149\u6761
|
|
964
|
+
vec3 bloom = mix(uBase, uHighlight, 0.35);
|
|
965
|
+
vec3 color = uBase * (0.006 + 0.5 * soft * mix(0.6, 1.1, seed)) * ao;
|
|
966
|
+
color += bloom * band1 * 0.3 * atten * ao;
|
|
967
|
+
color += uHighlight * line1 * 1.4 * fres * (0.3 + atten) * ao;
|
|
968
|
+
color += uHighlight * line2 * 0.18 * fres * ao;
|
|
969
|
+
|
|
970
|
+
// \u53CC\u7EBF\u9CDE\u7F18\uFF1A\u4E0A\u5C42\u9CDE\u7684\u8FB9\u4E0E\u88AB\u538B\u4F4F\u7684\u4E0B\u5C42\u9CDE\u7684\u8FB9\u5404\u4E00\u9053\u7EC6\u4EAE\u7EBF\uFF0C\u4E2D\u95F4\u7559\u4E00\u6761\u6697\u7F1D
|
|
971
|
+
float rimLight = (0.07 + 0.6 * soft + band1 * 0.9) * (1.0 + 1.2 * open);
|
|
972
|
+
float r1 = (sd + 1.6 * px) / (1.4 * px);
|
|
973
|
+
float r2 = (cover - 1.8 * px) / (1.4 * px);
|
|
974
|
+
color += uHighlight * exp(-r1 * r1) * rimLight * 0.9;
|
|
975
|
+
color += uHighlight * exp(-r2 * r2) * rimLight * 0.35;
|
|
976
|
+
|
|
977
|
+
color += mix(uBase, uHighlight, 0.2) * gap * 0.35 * (0.3 + atten + band1);
|
|
978
|
+
|
|
979
|
+
color += uHighlight * 0.03 * exp(-pow(length(frag - uPointer) / (minRes * 0.4), 2.0));
|
|
980
|
+
|
|
981
|
+
vec2 vc = frag / uResolution - 0.5;
|
|
982
|
+
float vig = dot(vc, vc);
|
|
983
|
+
|
|
984
|
+
if (uScheme > 0.5) {
|
|
985
|
+
// \u6D45\u8272\uFF1A\u5148\u8272\u8C03\u6620\u5C04\uFF0C\u518D\u505A\u4EAE\u6697\u955C\u50CF\uFF0C\u4FDD\u7559\u8272\u76F8 \u2014\u2014 \u9ED1\u66DC\u77F3\u9CDE\u9762\u7FFB\u8F6C\u6210\u6D45\u8272\u9CDE\u9762\uFF0C\u53CD\u5149\u6761\u8F6C\u4E3A\u6DF1\u8272\u9CDE\u7F18
|
|
986
|
+
vec3 c = pow(aces(color * 1.3), vec3(1.0 / 2.2));
|
|
987
|
+
float lum = dot(c, vec3(0.2126, 0.7152, 0.0722));
|
|
988
|
+
color = clamp(c + (1.0 - 2.0 * lum), 0.0, 1.0) * (1.0 - vig * 0.35);
|
|
989
|
+
} else {
|
|
990
|
+
color *= 1.0 - vig * 1.5;
|
|
991
|
+
color = pow(aces(color * 1.3), vec3(1.0 / 2.2));
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
color += (hash(frag + fract(t)) - 0.5) / 255.0;
|
|
995
|
+
|
|
996
|
+
gl_FragColor = vec4(color, 1.0);
|
|
997
|
+
}
|
|
998
|
+
`;
|
|
999
|
+
function DragonScales({
|
|
1000
|
+
children,
|
|
1001
|
+
className,
|
|
1002
|
+
color = "#7b3fe4",
|
|
1003
|
+
highlightColor = "#e7a6ff",
|
|
1004
|
+
scaleSize = 110,
|
|
1005
|
+
speed = 1,
|
|
1006
|
+
flare = 0,
|
|
1007
|
+
interactive = true,
|
|
1008
|
+
scheme: forcedScheme
|
|
1009
|
+
}) {
|
|
1010
|
+
const detectedScheme = useColorScheme();
|
|
1011
|
+
const scheme = forcedScheme ?? detectedScheme;
|
|
1012
|
+
const canvasRef = useShaderCanvas({
|
|
1013
|
+
fragmentShader: FRAGMENT_SHADER5,
|
|
1014
|
+
speed,
|
|
1015
|
+
interactive,
|
|
1016
|
+
onDraw: ({ gl, uniform, dpr }) => {
|
|
1017
|
+
gl.uniform1f(uniform("uScale"), Math.max(8, scaleSize) * dpr);
|
|
1018
|
+
gl.uniform3fv(uniform("uBase"), hexToLinearRgb(color));
|
|
1019
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
1020
|
+
gl.uniform1f(uniform("uFlare"), Math.min(Math.max(flare, 0), 1));
|
|
1021
|
+
gl.uniform1f(uniform("uScheme"), scheme === "light" ? 1 : 0);
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
return /* @__PURE__ */ jsxs(
|
|
1025
|
+
"div",
|
|
1026
|
+
{
|
|
1027
|
+
className: cn("elyri-dragon-scales", className),
|
|
1028
|
+
"data-scheme": scheme,
|
|
1029
|
+
style: { "--elyri-dragon-scales-color": color },
|
|
1030
|
+
children: [
|
|
1031
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-dragon-scales__canvas", "aria-hidden": "true" }),
|
|
1032
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-dragon-scales__content", children })
|
|
1033
|
+
]
|
|
1034
|
+
}
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
var FRAGMENT_SHADER6 = `
|
|
1038
|
+
precision highp float;
|
|
1039
|
+
|
|
1040
|
+
uniform vec2 uResolution;
|
|
1041
|
+
uniform float uTime;
|
|
1042
|
+
uniform vec2 uPointer;
|
|
1043
|
+
uniform vec3 uColor;
|
|
1044
|
+
uniform vec3 uHighlight;
|
|
1045
|
+
uniform vec3 uBg;
|
|
1046
|
+
uniform float uAmplitude;
|
|
1047
|
+
uniform float uDpr;
|
|
1048
|
+
uniform float uScheme;
|
|
1049
|
+
|
|
1050
|
+
const int COUNT = 7;
|
|
1051
|
+
|
|
1052
|
+
float hash(vec2 p) {
|
|
1053
|
+
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
1054
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
1055
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
vec3 shade(vec3 bg, vec3 light) {
|
|
1059
|
+
if (uScheme > 0.5) {
|
|
1060
|
+
float amount = max(max(light.r, light.g), light.b);
|
|
1061
|
+
vec3 tint = light / max(amount, 1e-4);
|
|
1062
|
+
return bg * exp(-amount * 1.4 * (1.0 - tint * 0.82));
|
|
1063
|
+
}
|
|
1064
|
+
return bg + 1.0 - exp(-light);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
float glow(float d, float w) {
|
|
1068
|
+
return exp(-d * d / (w * w)) + 0.22 * exp(-abs(d) / (w * 5.0)) + 0.035 * exp(-abs(d) / 0.05);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
float threadY(float x, float fi, float t, vec2 m) {
|
|
1072
|
+
float ph = fi * 1.7;
|
|
1073
|
+
float env = exp(-x * x * 1.1);
|
|
1074
|
+
float pluck = exp(-pow((x - m.x) / 0.35, 2.0));
|
|
1075
|
+
float amp = (0.05 + 0.09 * pow(sin(fi * 1.3 + 0.5), 2.0)) * uAmplitude + pluck * 0.05;
|
|
1076
|
+
return env * (amp * sin(x * (2.1 + fi * 0.09) + t * (1.0 + 0.12 * fi) + ph) + 0.028 * uAmplitude * sin(x * 4.3 - t * 0.7 + ph * 2.0))
|
|
1077
|
+
+ m.y * 0.22 * pluck;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
void main() {
|
|
1081
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
1082
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
1083
|
+
vec2 uv = (frag - 0.5 * uResolution) / minRes;
|
|
1084
|
+
vec2 m = (uPointer - 0.5 * uResolution) / minRes;
|
|
1085
|
+
float t = uTime * 0.35;
|
|
1086
|
+
float hx = 0.5 * uResolution.x / minRes;
|
|
1087
|
+
|
|
1088
|
+
float w = 0.9 * uDpr / minRes;
|
|
1089
|
+
float shift = 1.6 * uDpr / minRes;
|
|
1090
|
+
float e = 0.002;
|
|
1091
|
+
float fade = smoothstep(hx * 1.02, hx * 0.3, abs(uv.x));
|
|
1092
|
+
|
|
1093
|
+
vec3 light = vec3(0.0);
|
|
1094
|
+
for (int i = 0; i < COUNT; i++) {
|
|
1095
|
+
float fi = float(i);
|
|
1096
|
+
float y = threadY(uv.x, fi, t, m);
|
|
1097
|
+
float dy = (threadY(uv.x + e, fi, t, m) - y) / e;
|
|
1098
|
+
float s = (uv.y - y) / sqrt(1.0 + dy * dy);
|
|
1099
|
+
|
|
1100
|
+
float ph = fi * 1.7;
|
|
1101
|
+
float pulse = pow(0.5 + 0.5 * sin(uv.x * 1.6 - t * 1.4 + ph * 2.3), 6.0);
|
|
1102
|
+
float energy = (0.22 + 1.1 * pulse) * fade * (0.6 + 0.4 * sin(fi * 2.1 + 1.0) * sin(fi * 2.1 + 1.0));
|
|
1103
|
+
vec3 tint = mix(uColor, uHighlight, 0.5 + 0.5 * sin(uv.x * 1.2 + ph + t * 0.3));
|
|
1104
|
+
|
|
1105
|
+
vec3 g = vec3(glow(s - shift, w), glow(s, w), glow(s + shift, w));
|
|
1106
|
+
light += tint * g * energy;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
vec3 color = pow(clamp(shade(uBg, light), 0.0, 1.0), vec3(1.0 / 2.2));
|
|
1110
|
+
color += (hash(frag + fract(t)) - 0.5) / 255.0;
|
|
1111
|
+
|
|
1112
|
+
gl_FragColor = vec4(color, 1.0);
|
|
1113
|
+
}
|
|
1114
|
+
`;
|
|
1115
|
+
function Filaments({
|
|
1116
|
+
children,
|
|
1117
|
+
className,
|
|
1118
|
+
color = "#5b8cff",
|
|
1119
|
+
highlightColor = "#d46bff",
|
|
1120
|
+
amplitude = 1,
|
|
1121
|
+
speed = 1,
|
|
1122
|
+
interactive = true
|
|
1123
|
+
}) {
|
|
1124
|
+
const scheme = useColorScheme();
|
|
1125
|
+
const canvasRef = useShaderCanvas({
|
|
1126
|
+
fragmentShader: FRAGMENT_SHADER6,
|
|
1127
|
+
speed,
|
|
1128
|
+
interactive,
|
|
1129
|
+
onDraw: ({ gl, uniform, dpr }) => {
|
|
1130
|
+
gl.uniform3fv(uniform("uColor"), hexToLinearRgb(color));
|
|
1131
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
1132
|
+
gl.uniform3fv(uniform("uBg"), hexToLinearRgb(scheme === "light" ? "#f7f7fa" : "#06060a"));
|
|
1133
|
+
gl.uniform1f(uniform("uAmplitude"), Math.max(0, amplitude));
|
|
1134
|
+
gl.uniform1f(uniform("uDpr"), dpr);
|
|
1135
|
+
gl.uniform1f(uniform("uScheme"), scheme === "light" ? 1 : 0);
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
return /* @__PURE__ */ jsxs(
|
|
1139
|
+
"div",
|
|
1140
|
+
{
|
|
1141
|
+
className: cn("elyri-filaments", className),
|
|
1142
|
+
"data-scheme": scheme,
|
|
1143
|
+
style: { "--elyri-filaments-color": color },
|
|
1144
|
+
children: [
|
|
1145
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-filaments__canvas", "aria-hidden": "true" }),
|
|
1146
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-filaments__content", children })
|
|
1147
|
+
]
|
|
1148
|
+
}
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
var PATTERNS = ["wave", "ripple", "drift"];
|
|
1152
|
+
var FRAGMENT_SHADER7 = `
|
|
1153
|
+
precision highp float;
|
|
1154
|
+
|
|
1155
|
+
uniform vec2 uResolution;
|
|
1156
|
+
uniform float uTime;
|
|
1157
|
+
uniform vec2 uPointer;
|
|
1158
|
+
uniform float uScale;
|
|
1159
|
+
uniform vec3 uColor;
|
|
1160
|
+
uniform vec3 uHighlight;
|
|
1161
|
+
uniform vec3 uFront;
|
|
1162
|
+
uniform vec3 uFloor;
|
|
1163
|
+
uniform float uPattern;
|
|
1164
|
+
uniform float uScheme;
|
|
1165
|
+
uniform float uSamples;
|
|
1166
|
+
|
|
1167
|
+
const float PI = 3.14159265;
|
|
1168
|
+
const float HALF = 0.45;
|
|
1169
|
+
const float BEVEL = 0.055;
|
|
1170
|
+
const float FLOOR_Z = -0.45;
|
|
1171
|
+
const float TILT = 0.42;
|
|
1172
|
+
const vec3 KEY = vec3(-0.5, -0.42, 0.757);
|
|
1173
|
+
|
|
1174
|
+
float hash(vec2 p) {
|
|
1175
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
1176
|
+
p += dot(p, p + 45.32);
|
|
1177
|
+
return fract(p.x * p.y);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
float noise(vec2 p) {
|
|
1181
|
+
vec2 i = floor(p);
|
|
1182
|
+
vec2 f = fract(p);
|
|
1183
|
+
f = f * f * (3.0 - 2.0 * f);
|
|
1184
|
+
return mix(
|
|
1185
|
+
mix(hash(i), hash(i + vec2(1.0, 0.0)), f.x),
|
|
1186
|
+
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), f.x),
|
|
1187
|
+
f.y
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// \u7ED5\u5355\u4F4D\u8F74 k \u65CB\u8F6C a \u5F27\u5EA6\uFF08Rodrigues\uFF09
|
|
1192
|
+
mat3 rotAxis(vec3 k, float a) {
|
|
1193
|
+
float s = sin(a);
|
|
1194
|
+
float c = cos(a);
|
|
1195
|
+
float oc = 1.0 - c;
|
|
1196
|
+
return mat3(
|
|
1197
|
+
oc * k.x * k.x + c, oc * k.x * k.y + k.z * s, oc * k.z * k.x - k.y * s,
|
|
1198
|
+
oc * k.x * k.y - k.z * s, oc * k.y * k.y + c, oc * k.y * k.z + k.x * s,
|
|
1199
|
+
oc * k.z * k.x + k.y * s, oc * k.y * k.z - k.x * s, oc * k.z * k.z + c
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
mat3 transposeM(mat3 m) {
|
|
1204
|
+
return mat3(
|
|
1205
|
+
m[0][0], m[1][0], m[2][0],
|
|
1206
|
+
m[0][1], m[1][1], m[2][1],
|
|
1207
|
+
m[0][2], m[1][2], m[2][2]
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// 0\u21921 \u7684\u6B20\u963B\u5C3C\u5F39\u7C27\uFF1A\u8D77\u6B65\u96F6\u901F\u5EA6\uFF0C\u7EA6 7% \u7684\u56DE\u5F39\u540E\u7A33\u5B9A
|
|
1212
|
+
float spring(float x) {
|
|
1213
|
+
x = clamp(x, 0.0, 1.0);
|
|
1214
|
+
float k = exp(-6.0 * x) * (cos(7.0 * x) + 6.0 / 7.0 * sin(7.0 * x));
|
|
1215
|
+
return 1.0 - k * (1.0 - smoothstep(0.8, 1.0, x));
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// \u5355\u4E2A\u7ACB\u65B9\u4F53\u7684\u59FF\u6001\uFF1A\u6EDA\u52A8\u8F74\u4E0E\u89D2\u5EA6\u3001\u6EDA\u52A8\u65F6\u7684\u6536\u7F29\u4E0E\u8DC3\u8D77\u3001\u6307\u9488\u5904\u7684\u5347\u8D77
|
|
1219
|
+
void cubeAt(vec2 c, vec2 pw, out mat3 inv, out vec4 geo, out float open) {
|
|
1220
|
+
float h = hash(c);
|
|
1221
|
+
float h2 = hash(c + 17.31);
|
|
1222
|
+
vec3 axis;
|
|
1223
|
+
float f;
|
|
1224
|
+
if (uPattern < 0.5) {
|
|
1225
|
+
float a = 0.35 + 0.3 * sin(uTime * 0.045);
|
|
1226
|
+
axis = vec3(0.0, 1.0, 0.0);
|
|
1227
|
+
f = uTime * 0.15 - dot(c, vec2(cos(a), sin(a))) * 0.1 + h * 0.035;
|
|
1228
|
+
} else if (uPattern < 1.5) {
|
|
1229
|
+
axis = abs(c.x) >= abs(c.y) ? vec3(0.0, c.x < 0.0 ? -1.0 : 1.0, 0.0) : vec3(c.y < 0.0 ? 1.0 : -1.0, 0.0, 0.0);
|
|
1230
|
+
f = uTime * 0.14 - length(c) * 0.12 + h * 0.03;
|
|
1231
|
+
} else {
|
|
1232
|
+
axis = h2 < 0.5 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
|
1233
|
+
f = uTime * 0.07 + noise(c * 0.16 + vec2(uTime * 0.015, -uTime * 0.01)) * 2.2 + h * 0.05;
|
|
1234
|
+
}
|
|
1235
|
+
// \u6BCF\u4E2A\u5468\u671F\u6EDA\u4E24\u6B21\uFF1A\u5148\u628A\u5F3A\u8C03\u8272\u4FA7\u9762\u7FFB\u4E0A\u6765\uFF0C\u505C\u7559\u7247\u523B\uFF0C\u518D\u6EDA\u56DE\u9ED1\u66DC\u77F3\u9762
|
|
1236
|
+
float fl = floor(f);
|
|
1237
|
+
float fr = f - fl;
|
|
1238
|
+
float roll = spring(fr / 0.2) + spring((fr - 0.26) / 0.2);
|
|
1239
|
+
float ang = PI * 0.5 * (2.0 * mod(fl, 2.0) + roll);
|
|
1240
|
+
open = abs(sin(2.0 * ang));
|
|
1241
|
+
|
|
1242
|
+
// \u8F6C\u5230 45\xB0 \u65F6\u5BF9\u89D2\u7EBF\u6700\u957F\uFF0C\u6309\u6295\u5F71\u5BBD\u5EA6\u6536\u7F29\uFF0C\u4FDD\u8BC1\u4E0E\u90BB\u5C45\u59CB\u7EC8\u4E0D\u76F8\u4EA4
|
|
1243
|
+
float reach = HALF * (abs(cos(ang)) + abs(sin(ang)));
|
|
1244
|
+
float s = min(1.0, 0.49 / reach);
|
|
1245
|
+
vec2 toP = c - pw;
|
|
1246
|
+
float lift = 0.3 * exp(-dot(toP, toP) / 5.0);
|
|
1247
|
+
|
|
1248
|
+
inv = rotAxis(axis, -ang);
|
|
1249
|
+
geo = vec4(c, lift + (1.0 - s) * 0.7, HALF * s);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// \u5C04\u7EBF\u4E0E\u4EE5\u539F\u70B9\u4E3A\u4E2D\u5FC3\u7684\u7ACB\u65B9\u4F53\u6C42\u4EA4\uFF0C\u8FD4\u56DE\u6700\u8FD1\u4EA4\u70B9\u8DDD\u79BB\uFF08\u672A\u547D\u4E2D\u4E3A -1\uFF09\u4E0E\u5C40\u90E8\u6CD5\u7EBF
|
|
1253
|
+
float boxHit(vec3 ro, vec3 rd, float rad, out vec3 n) {
|
|
1254
|
+
rd = mix(rd, vec3(1e-6), step(abs(rd), vec3(1e-6)));
|
|
1255
|
+
vec3 m = 1.0 / rd;
|
|
1256
|
+
vec3 k = abs(m) * rad;
|
|
1257
|
+
vec3 t1 = -m * ro - k;
|
|
1258
|
+
vec3 t2 = -m * ro + k;
|
|
1259
|
+
float tN = max(max(t1.x, t1.y), t1.z);
|
|
1260
|
+
float tF = min(min(t2.x, t2.y), t2.z);
|
|
1261
|
+
n = vec3(0.0);
|
|
1262
|
+
if (tN > tF || tF < 0.0) return -1.0;
|
|
1263
|
+
n = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz);
|
|
1264
|
+
return tN;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// \u73AF\u5883\u5149\uFF1A\u53EA\u4FDD\u7559\u4E00\u5C42\u6781\u5F31\u7684\u5747\u5300\u8865\u5149\uFF0C\u4E0D\u518D\u6709\u626B\u8FC7\u753B\u9762\u7684\u706F\u5E26\u53CD\u5149
|
|
1268
|
+
vec3 envLight(vec3 R) {
|
|
1269
|
+
return vec3(0.008 + 0.02 * smoothstep(-0.1, 0.4, R.z));
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
vec3 aces(vec3 x) {
|
|
1273
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
vec2 sampleOffset(int s) {
|
|
1277
|
+
if (uSamples < 1.5) return vec2(0.0);
|
|
1278
|
+
if (uSamples < 2.5) return s == 0 ? vec2(-0.25) : vec2(0.25);
|
|
1279
|
+
if (s == 0) return vec2(-0.125, -0.375);
|
|
1280
|
+
if (s == 1) return vec2(0.375, -0.125);
|
|
1281
|
+
if (s == 2) return vec2(0.125, 0.375);
|
|
1282
|
+
return vec2(-0.375, 0.125);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
void main() {
|
|
1286
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
1287
|
+
vec2 center = 0.5 * uResolution;
|
|
1288
|
+
float halfW = 0.5 * max(uResolution.x, uResolution.y) / uScale;
|
|
1289
|
+
|
|
1290
|
+
// \u7565\u5E26\u4FEF\u89D2\u7684\u900F\u89C6\u76F8\u673A\uFF1A\u5C4F\u5E55\u5411\u4E0B\u5BF9\u5E94\u4E16\u754C +y\uFF0C\u76F8\u673A\u4ECE +y \u4E00\u4FA7\u659C\u770B\uFF0C\u80FD\u770B\u5230\u7ACB\u65B9\u4F53\u671D\u5411\u89C2\u8005\u7684\u4FA7\u9762
|
|
1291
|
+
float D = halfW * 2.0;
|
|
1292
|
+
vec3 ro = vec3(0.0, D * sin(TILT), D * cos(TILT));
|
|
1293
|
+
vec3 fw = -normalize(ro);
|
|
1294
|
+
vec3 dn = vec3(0.0, cos(TILT), -sin(TILT));
|
|
1295
|
+
|
|
1296
|
+
vec2 puv = (uPointer - center) / uScale;
|
|
1297
|
+
vec3 prd = normalize(fw * D + vec3(puv.x, 0.0, 0.0) + dn * puv.y);
|
|
1298
|
+
vec2 pw = (ro + prd * ((HALF - ro.z) / prd.z)).xy;
|
|
1299
|
+
|
|
1300
|
+
vec2 cuv = (frag - center) / uScale;
|
|
1301
|
+
vec3 crd = normalize(fw * D + vec3(cuv.x, 0.0, 0.0) + dn * cuv.y);
|
|
1302
|
+
vec2 base = floor((ro + crd * (-ro.z / crd.z)).xy + 0.5);
|
|
1303
|
+
|
|
1304
|
+
vec3 L = normalize(KEY);
|
|
1305
|
+
// \u4E3B\u5149\u6E90\u7684\u955C\u9762\u9AD8\u5149\u989C\u8272
|
|
1306
|
+
vec3 specCol = mix(vec3(1.0), uHighlight, 0.35);
|
|
1307
|
+
float amb = mix(0.03, 0.45, uScheme);
|
|
1308
|
+
|
|
1309
|
+
// \u5468\u56F4 3\xD73 \u4E2A\u7ACB\u65B9\u4F53\u7684\u59FF\u6001\u53EA\u7B97\u4E00\u6B21\uFF0C\u4F9B\u6240\u6709\u91C7\u6837\u4E0E\u9634\u5F71\u590D\u7528
|
|
1310
|
+
mat3 invs[9];
|
|
1311
|
+
vec4 geos[9];
|
|
1312
|
+
float opens[9];
|
|
1313
|
+
float seeds[9];
|
|
1314
|
+
vec3 localL[9];
|
|
1315
|
+
for (int k = 0; k < 9; k++) {
|
|
1316
|
+
int row = k / 3;
|
|
1317
|
+
vec2 c = base + vec2(float(k - row * 3) - 1.0, float(row) - 1.0);
|
|
1318
|
+
mat3 inv;
|
|
1319
|
+
vec4 geo;
|
|
1320
|
+
float open;
|
|
1321
|
+
cubeAt(c, pw, inv, geo, open);
|
|
1322
|
+
invs[k] = inv;
|
|
1323
|
+
geos[k] = geo;
|
|
1324
|
+
opens[k] = open;
|
|
1325
|
+
seeds[k] = hash(c + 5.17);
|
|
1326
|
+
// \u5149\u6E90\u65B9\u5411\u662F\u5E38\u91CF\uFF0C\u63D0\u524D\u8F6C\u5230\u5404\u7ACB\u65B9\u4F53\u5C40\u90E8\u7A7A\u95F4\uFF0C\u7701\u53BB\u6BCF\u6B21\u91C7\u6837\u91CD\u590D\u7684\u77E9\u9635\u4E58\u6CD5
|
|
1327
|
+
localL[k] = inv * L;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
vec3 acc = vec3(0.0);
|
|
1331
|
+
for (int s = 0; s < 4; s++) {
|
|
1332
|
+
if (float(s) >= uSamples) break;
|
|
1333
|
+
vec2 uv = (frag + sampleOffset(s) - center) / uScale;
|
|
1334
|
+
vec3 rd = normalize(fw * D + vec3(uv.x, 0.0, 0.0) + dn * uv.y);
|
|
1335
|
+
|
|
1336
|
+
float tMin = 1e9;
|
|
1337
|
+
int hitK = -1;
|
|
1338
|
+
vec3 hitN = vec3(0.0);
|
|
1339
|
+
vec3 hitP = vec3(0.0);
|
|
1340
|
+
mat3 hitInv = mat3(1.0);
|
|
1341
|
+
float hitSize = HALF;
|
|
1342
|
+
float hitSeed = 0.0;
|
|
1343
|
+
for (int k = 0; k < 9; k++) {
|
|
1344
|
+
vec3 lro = invs[k] * (ro - geos[k].xyz);
|
|
1345
|
+
vec3 lrd = invs[k] * rd;
|
|
1346
|
+
vec3 n;
|
|
1347
|
+
float t = boxHit(lro, lrd, geos[k].w, n);
|
|
1348
|
+
if (t > 0.0 && t < tMin) {
|
|
1349
|
+
tMin = t;
|
|
1350
|
+
hitK = k;
|
|
1351
|
+
hitN = n;
|
|
1352
|
+
hitP = lro + lrd * t;
|
|
1353
|
+
hitInv = invs[k];
|
|
1354
|
+
hitSize = geos[k].w;
|
|
1355
|
+
hitSeed = seeds[k];
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
bool hit = hitK >= 0;
|
|
1360
|
+
float tFloor = (FLOOR_Z - ro.z) / rd.z;
|
|
1361
|
+
float tHit = hit ? tMin : tFloor;
|
|
1362
|
+
vec3 wp = ro + rd * tHit;
|
|
1363
|
+
|
|
1364
|
+
// \u7ACB\u65B9\u4F53\u6CD5\u7EBF\uFF1A\u68F1\u8FB9\u4E00\u5708\u5411\u5916\u503E\u659C\uFF0C\u5F62\u6210\u5706\u6DA6\u7684\u5012\u89D2\uFF1B\u6BCF\u5757\u9876\u9762\u6781\u8F7B\u5FAE\u9519\u5F00\uFF0C\u50CF\u624B\u5DE5\u94FA\u8D34
|
|
1365
|
+
vec3 n = vec3(0.0, 0.0, 1.0);
|
|
1366
|
+
float bevel = 0.0;
|
|
1367
|
+
if (hit) {
|
|
1368
|
+
vec3 b = (1.0 - smoothstep(0.0, BEVEL, hitSize - abs(hitP))) * (1.0 - abs(hitN));
|
|
1369
|
+
bevel = max(max(b.x, b.y), b.z);
|
|
1370
|
+
vec3 jitter = (vec3(hitSeed, fract(hitSeed * 7.13), fract(hitSeed * 3.71)) - 0.5) * 0.04 * (1.0 - abs(hitN));
|
|
1371
|
+
n = normalize(transposeM(hitInv) * normalize(hitN + sign(hitP) * b * 1.2 + jitter));
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// \u4E3B\u5149\u6E90\u7684\u6295\u5F71\uFF1A\u5411\u5149\u6E90\u65B9\u5411\u68C0\u6D4B\u5176\u4F59\u7ACB\u65B9\u4F53\uFF0C\u547D\u4E2D\u5373\u63D0\u524D\u9000\u51FA
|
|
1375
|
+
float shadow = 1.0;
|
|
1376
|
+
vec3 sp = wp + n * 0.003;
|
|
1377
|
+
for (int k = 0; k < 9; k++) {
|
|
1378
|
+
if (k == hitK) continue;
|
|
1379
|
+
vec3 tmp;
|
|
1380
|
+
float ts = boxHit(invs[k] * (sp - geos[k].xyz), localL[k], geos[k].w, tmp);
|
|
1381
|
+
if (ts > 0.0) {
|
|
1382
|
+
shadow = 0.0;
|
|
1383
|
+
break;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
vec3 V = -rd;
|
|
1388
|
+
float diffK = max(dot(n, L), 0.0) * shadow;
|
|
1389
|
+
float NdHk = max(dot(n, normalize(L + V)), 0.0);
|
|
1390
|
+
|
|
1391
|
+
vec3 color;
|
|
1392
|
+
if (hit) {
|
|
1393
|
+
float fres = pow(1.0 - max(dot(n, V), 0.0), 5.0);
|
|
1394
|
+
vec3 env = envLight(reflect(rd, n));
|
|
1395
|
+
|
|
1396
|
+
vec3 edge = uHighlight * (0.03 + 0.4 * diffK)
|
|
1397
|
+
+ mix(uHighlight, vec3(1.0), 0.3 + 0.7 * fres) * env * 1.4
|
|
1398
|
+
+ specCol * pow(NdHk, 48.0) * shadow * 0.8;
|
|
1399
|
+
|
|
1400
|
+
vec3 face;
|
|
1401
|
+
if (abs(hitN.z) > 0.5) {
|
|
1402
|
+
face = uFront * (amb + 0.55 * diffK)
|
|
1403
|
+
+ env * (0.12 + 0.88 * fres) * mix(1.0, 0.45, uScheme)
|
|
1404
|
+
+ specCol * pow(NdHk, 900.0) * shadow * 0.4;
|
|
1405
|
+
} else {
|
|
1406
|
+
face = uColor * (amb * 0.6 + 0.02 + 0.7 * diffK)
|
|
1407
|
+
+ mix(uColor, vec3(1.0), fres) * env * 0.8
|
|
1408
|
+
+ mix(uColor, specCol, 0.5) * (pow(NdHk, 40.0) * shadow * 0.5);
|
|
1409
|
+
}
|
|
1410
|
+
color = mix(face, edge, bevel * 0.5);
|
|
1411
|
+
} else {
|
|
1412
|
+
// \u69FD\u5E95\uFF1A\u7D27\u8D34\u7ACB\u65B9\u4F53\u5904\u538B\u6697\uFF0C\u6EDA\u52A8\u4E2D\u7684\u7ACB\u65B9\u4F53\u4E0B\u65B9\u900F\u51FA\u5F3A\u8C03\u8272\u8F89\u5149
|
|
1413
|
+
float ao = 1.0;
|
|
1414
|
+
float glow = 0.0;
|
|
1415
|
+
for (int k = 0; k < 9; k++) {
|
|
1416
|
+
vec2 dv = wp.xy - geos[k].xy;
|
|
1417
|
+
float d2 = dot(dv, dv);
|
|
1418
|
+
// \u8D85\u8FC7\u6B64\u8DDD\u79BB ao \u5DF2\u9971\u548C\u3001\u8F89\u5149\u5DF2\u8870\u51CF\u5230\u770B\u4E0D\u89C1\uFF0C\u8DF3\u8FC7\u4EE5\u7701\u7B97\u529B
|
|
1419
|
+
if (d2 > 1.5) continue;
|
|
1420
|
+
vec2 q = abs(dv) - geos[k].w;
|
|
1421
|
+
ao *= mix(0.2, 1.0, smoothstep(0.0, 0.3, length(max(q, 0.0))));
|
|
1422
|
+
glow += opens[k] * exp(-d2 / 0.18);
|
|
1423
|
+
}
|
|
1424
|
+
color = uFloor * (amb + 0.45 * diffK) * ao
|
|
1425
|
+
+ uColor * (glow * 0.5 * (0.4 + 0.6 * ao));
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// \u8FDC\u5904\u6E10\u9690\u8FDB\u96FE\u91CC\uFF0C\u62C9\u5F00\u7EB5\u6DF1
|
|
1429
|
+
float fog = smoothstep(D * 0.95, D * 1.5, tHit);
|
|
1430
|
+
color = mix(color, uFloor * mix(0.4, 0.9, uScheme), fog * 0.8);
|
|
1431
|
+
|
|
1432
|
+
acc += aces(color * mix(1.3, 1.05, uScheme));
|
|
1433
|
+
}
|
|
1434
|
+
vec3 color = acc / uSamples;
|
|
1435
|
+
|
|
1436
|
+
vec2 vc = frag / uResolution - 0.5;
|
|
1437
|
+
color *= 1.0 - dot(vc, vc) * mix(1.1, 0.3, uScheme);
|
|
1438
|
+
color = pow(color, vec3(1.0 / 2.2));
|
|
1439
|
+
color += (hash(frag + fract(uTime)) - 0.5) / 255.0;
|
|
1440
|
+
|
|
1441
|
+
gl_FragColor = vec4(color, 1.0);
|
|
1442
|
+
}
|
|
1443
|
+
`;
|
|
1444
|
+
function FlipTiles({
|
|
1445
|
+
children,
|
|
1446
|
+
className,
|
|
1447
|
+
color = "#4f6bff",
|
|
1448
|
+
highlightColor = "#b8c4ff",
|
|
1449
|
+
tileSize = 72,
|
|
1450
|
+
speed = 1,
|
|
1451
|
+
pattern = "wave",
|
|
1452
|
+
interactive = true
|
|
1453
|
+
}) {
|
|
1454
|
+
const scheme = useColorScheme();
|
|
1455
|
+
const canvasRef = useShaderCanvas({
|
|
1456
|
+
fragmentShader: FRAGMENT_SHADER7,
|
|
1457
|
+
speed,
|
|
1458
|
+
interactive,
|
|
1459
|
+
// 每像素要跑 9 次立方体求交与阴影射线,属于重填充率着色器:内部按 1.5× 渲染,
|
|
1460
|
+
// 视觉上几乎无损,但相比 2× 能省下约 44% 的像素量
|
|
1461
|
+
maxDpr: 1.5,
|
|
1462
|
+
onDraw: ({ gl, uniform, dpr }) => {
|
|
1463
|
+
const light = scheme === "light";
|
|
1464
|
+
gl.uniform1f(uniform("uScale"), Math.max(24, tileSize) * dpr);
|
|
1465
|
+
gl.uniform3fv(uniform("uColor"), hexToLinearRgb(color));
|
|
1466
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
1467
|
+
gl.uniform3fv(uniform("uFront"), hexToLinearRgb(light ? "#ececf1" : "#0c0c12"));
|
|
1468
|
+
gl.uniform3fv(uniform("uFloor"), hexToLinearRgb(light ? "#c6c6d0" : "#040406"));
|
|
1469
|
+
gl.uniform1f(uniform("uPattern"), Math.max(0, PATTERNS.indexOf(pattern)));
|
|
1470
|
+
gl.uniform1f(uniform("uScheme"), light ? 1 : 0);
|
|
1471
|
+
gl.uniform1f(uniform("uSamples"), 2);
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
return /* @__PURE__ */ jsxs(
|
|
1475
|
+
"div",
|
|
1476
|
+
{
|
|
1477
|
+
className: cn("elyri-flip-tiles", className),
|
|
1478
|
+
"data-scheme": scheme,
|
|
1479
|
+
style: { "--elyri-flip-tiles-color": color },
|
|
1480
|
+
children: [
|
|
1481
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-flip-tiles__canvas", "aria-hidden": "true" }),
|
|
1482
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-flip-tiles__content", children })
|
|
1483
|
+
]
|
|
1484
|
+
}
|
|
1485
|
+
);
|
|
1486
|
+
}
|
|
1487
|
+
var DEFAULT_COLORS2 = ["#8fb4ff", "#e7c6ff"];
|
|
1488
|
+
var FRAGMENT_SHADER8 = `
|
|
1489
|
+
precision highp float;
|
|
1490
|
+
|
|
1491
|
+
uniform vec2 uResolution;
|
|
1492
|
+
uniform float uTime;
|
|
1493
|
+
uniform vec2 uPointer;
|
|
1494
|
+
uniform vec3 uColor1;
|
|
1495
|
+
uniform vec3 uColor2;
|
|
1496
|
+
uniform float uSize;
|
|
1497
|
+
uniform float uInteractive;
|
|
1498
|
+
uniform vec3 uBg;
|
|
1499
|
+
uniform float uScheme;
|
|
1500
|
+
|
|
1501
|
+
float hash(vec2 p) {
|
|
1502
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
1503
|
+
p += dot(p, p + 45.32);
|
|
1504
|
+
return fract(p.x * p.y);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// \u6DF1\u8272\u4E0B\u5149\u7EBF\u53E0\u52A0\u53D1\u4EAE\uFF1B\u6D45\u8272\u4E0B\u6539\u4E3A\u6309\u8272\u76F8\u5438\u6536\u5E95\u8272\uFF0C\u50CF\u58A8\u8272\u7EC6\u7EBF\u843D\u5728\u7EB8\u9762\u4E0A
|
|
1508
|
+
vec3 shade(vec3 bg, vec3 light) {
|
|
1509
|
+
if (uScheme > 0.5) {
|
|
1510
|
+
float amount = max(max(light.r, light.g), light.b);
|
|
1511
|
+
vec3 tint = light / max(amount, 1e-4);
|
|
1512
|
+
return bg * exp(-amount * 1.6 * (1.0 - tint * 0.8));
|
|
1513
|
+
}
|
|
1514
|
+
return bg + 1.0 - exp(-light * 1.4);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
void main() {
|
|
1518
|
+
vec2 res = uResolution;
|
|
1519
|
+
vec2 p = (gl_FragCoord.xy - 0.5 * res) / res.y;
|
|
1520
|
+
vec2 pointer = (vec2(uPointer.x, res.y - uPointer.y) - 0.5 * res) / res.y;
|
|
1521
|
+
p -= pointer * 0.06 * uInteractive;
|
|
1522
|
+
float t = uTime;
|
|
1523
|
+
|
|
1524
|
+
float r = length(p);
|
|
1525
|
+
float a = atan(p.y, p.x);
|
|
1526
|
+
|
|
1527
|
+
float radius = 0.3 * uSize;
|
|
1528
|
+
radius += 0.010 * sin(a * 3.0 + t * 0.5) + 0.006 * sin(a * 5.0 - t * 0.8);
|
|
1529
|
+
float d = abs(r - radius);
|
|
1530
|
+
|
|
1531
|
+
float line = exp(-d * d * 60000.0);
|
|
1532
|
+
float glow = exp(-d * 22.0) * 0.28 + exp(-d * 6.0) * 0.05;
|
|
1533
|
+
|
|
1534
|
+
// \u4E24\u675F\u9AD8\u5149\u6CBF\u5706\u5468\u4EE5\u4E0D\u540C\u901F\u5EA6\u6D41\u52A8
|
|
1535
|
+
float f1 = pow(0.5 + 0.5 * cos(a - t * 0.45), 6.0);
|
|
1536
|
+
float f2 = pow(0.5 + 0.5 * cos(a + 2.4 + t * 0.28), 10.0);
|
|
1537
|
+
float flow = 0.12 + f1 + 0.6 * f2;
|
|
1538
|
+
|
|
1539
|
+
vec3 tint = mix(uColor1, uColor2, 0.5 + 0.5 * sin(a + t * 0.2));
|
|
1540
|
+
vec3 light = tint * (line * 1.1 + glow) * flow;
|
|
1541
|
+
// \u5708\u5185\u6781\u6DE1\u7684\u96FE\u5149
|
|
1542
|
+
light += uColor1 * 0.015 * exp(-r * r / (radius * radius) * 1.5);
|
|
1543
|
+
|
|
1544
|
+
vec3 color = pow(clamp(shade(uBg, light), 0.0, 1.0), vec3(1.0 / 2.2));
|
|
1545
|
+
color += (hash(gl_FragCoord.xy + fract(t)) - 0.5) / 255.0;
|
|
1546
|
+
|
|
1547
|
+
gl_FragColor = vec4(color, 1.0);
|
|
1548
|
+
}
|
|
1549
|
+
`;
|
|
1550
|
+
function Halo({
|
|
1551
|
+
children,
|
|
1552
|
+
className,
|
|
1553
|
+
colors = DEFAULT_COLORS2,
|
|
1554
|
+
size = 1,
|
|
1555
|
+
speed = 1,
|
|
1556
|
+
interactive = true
|
|
1557
|
+
}) {
|
|
1558
|
+
const [first = DEFAULT_COLORS2[0], second = DEFAULT_COLORS2[1]] = colors;
|
|
1559
|
+
const scheme = useColorScheme();
|
|
1560
|
+
const canvasRef = useShaderCanvas({
|
|
1561
|
+
fragmentShader: FRAGMENT_SHADER8,
|
|
1562
|
+
speed,
|
|
1563
|
+
interactive,
|
|
1564
|
+
onDraw: ({ gl, uniform }) => {
|
|
1565
|
+
gl.uniform3fv(uniform("uColor1"), hexToLinearRgb(first));
|
|
1566
|
+
gl.uniform3fv(uniform("uColor2"), hexToLinearRgb(second));
|
|
1567
|
+
gl.uniform1f(uniform("uSize"), Math.max(0.1, size));
|
|
1568
|
+
gl.uniform1f(uniform("uInteractive"), interactive ? 1 : 0);
|
|
1569
|
+
gl.uniform3fv(uniform("uBg"), hexToLinearRgb(scheme === "light" ? "#f8f8fa" : "#010102"));
|
|
1570
|
+
gl.uniform1f(uniform("uScheme"), scheme === "light" ? 1 : 0);
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
return /* @__PURE__ */ jsxs(
|
|
1574
|
+
"div",
|
|
1575
|
+
{
|
|
1576
|
+
className: cn("elyri-halo", className),
|
|
1577
|
+
"data-scheme": scheme,
|
|
1578
|
+
style: { "--elyri-halo-color": first },
|
|
1579
|
+
children: [
|
|
1580
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-halo__canvas", "aria-hidden": "true" }),
|
|
1581
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-halo__content", children })
|
|
1582
|
+
]
|
|
1583
|
+
}
|
|
1584
|
+
);
|
|
1585
|
+
}
|
|
1586
|
+
var DEFAULT_COLORS3 = ["#6e6af0", "#f472b6", "#fbbf77", "#38bdf8"];
|
|
1587
|
+
var FRAGMENT_SHADER9 = `
|
|
1588
|
+
precision highp float;
|
|
1589
|
+
|
|
1590
|
+
uniform vec2 uResolution;
|
|
1591
|
+
uniform float uTime;
|
|
1592
|
+
uniform vec2 uPointer;
|
|
1593
|
+
uniform vec3 uColor0;
|
|
1594
|
+
uniform vec3 uColor1;
|
|
1595
|
+
uniform vec3 uColor2;
|
|
1596
|
+
uniform vec3 uColor3;
|
|
1597
|
+
uniform vec3 uBase;
|
|
1598
|
+
uniform float uGrain;
|
|
1599
|
+
|
|
1600
|
+
float hash(vec2 p) {
|
|
1601
|
+
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
1602
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
1603
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
vec3 toOklab(vec3 c) {
|
|
1607
|
+
float l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b;
|
|
1608
|
+
float m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b;
|
|
1609
|
+
float s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b;
|
|
1610
|
+
l = pow(max(l, 0.0), 1.0 / 3.0);
|
|
1611
|
+
m = pow(max(m, 0.0), 1.0 / 3.0);
|
|
1612
|
+
s = pow(max(s, 0.0), 1.0 / 3.0);
|
|
1613
|
+
return vec3(
|
|
1614
|
+
0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s,
|
|
1615
|
+
1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s,
|
|
1616
|
+
0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
vec3 fromOklab(vec3 c) {
|
|
1621
|
+
float l = c.x + 0.3963377774 * c.y + 0.2158037573 * c.z;
|
|
1622
|
+
float m = c.x - 0.1055613458 * c.y - 0.0638541728 * c.z;
|
|
1623
|
+
float s = c.x - 0.0894841775 * c.y - 1.2914855480 * c.z;
|
|
1624
|
+
l = l * l * l;
|
|
1625
|
+
m = m * m * m;
|
|
1626
|
+
s = s * s * s;
|
|
1627
|
+
return vec3(
|
|
1628
|
+
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
1629
|
+
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
1630
|
+
-0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
float noise(vec2 p) {
|
|
1635
|
+
vec2 i = floor(p);
|
|
1636
|
+
vec2 f = fract(p);
|
|
1637
|
+
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
|
|
1638
|
+
return mix(mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x), mix(hash(i + vec2(0.0, 1.0)), hash(i + 1.0), u.x), u.y);
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
float fbm(vec2 p) {
|
|
1642
|
+
float v = 0.0;
|
|
1643
|
+
float a = 0.5;
|
|
1644
|
+
mat2 rot = mat2(1.6, 1.2, -1.2, 1.6);
|
|
1645
|
+
for (int i = 0; i < 4; i++) {
|
|
1646
|
+
v += a * noise(p);
|
|
1647
|
+
p = rot * p + vec2(11.3, 7.9);
|
|
1648
|
+
a *= 0.5;
|
|
1649
|
+
}
|
|
1650
|
+
return v;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
float blob(vec2 uv, vec2 center) {
|
|
1654
|
+
vec2 d = uv - center;
|
|
1655
|
+
return exp(-dot(d, d) * 3.2);
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
void main() {
|
|
1659
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
1660
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
1661
|
+
vec2 half_ = 0.5 * uResolution / minRes;
|
|
1662
|
+
vec2 uv = (frag - 0.5 * uResolution) / minRes;
|
|
1663
|
+
vec2 pointer = (uPointer - 0.5 * uResolution) / minRes;
|
|
1664
|
+
float t = uTime * 0.1;
|
|
1665
|
+
|
|
1666
|
+
// \u6307\u9488\u6F29\u6DA1\uFF1A\u7ED5\u6307\u9488\u65CB\u8F6C\u91C7\u6837\u5750\u6807\uFF0C\u8D8A\u9760\u8FD1\u8F6C\u5F97\u8D8A\u591A\uFF0C\u8272\u5F69\u88AB\u5377\u8FDB\u53BB
|
|
1667
|
+
vec2 dm = uv - pointer;
|
|
1668
|
+
float swirl = exp(-dot(dm, dm) / 0.07);
|
|
1669
|
+
float angle = swirl * 1.1;
|
|
1670
|
+
uv = pointer + mat2(cos(angle), sin(angle), -sin(angle), cos(angle)) * dm * (1.0 - swirl * 0.12);
|
|
1671
|
+
|
|
1672
|
+
// \u4E24\u7EA7\u57DF\u626D\u66F2\u7684\u6D41\u573A\uFF1Aq \u7F13\u6162\u6F02\u79FB\uFF0Cr \u5728 q \u7684\u57FA\u7840\u4E0A\u518D\u626D\u4E00\u6B21\uFF0C\u5F97\u5230\u6DB2\u4F53\u822C\u7684\u5377\u6D41
|
|
1673
|
+
vec2 p = uv * 1.5;
|
|
1674
|
+
vec2 q = vec2(fbm(p + vec2(0.0, t)), fbm(p + vec2(5.2, 1.3) - t * 0.8));
|
|
1675
|
+
vec2 r = vec2(fbm(p + 2.6 * q + vec2(1.7, 9.2) + t * 1.2), fbm(p + 2.6 * q + vec2(8.3, 2.8) - t));
|
|
1676
|
+
vec2 w = uv + (r - 0.5) * 0.9 + (q - 0.5) * 0.3;
|
|
1677
|
+
|
|
1678
|
+
float tb = uTime * 0.12;
|
|
1679
|
+
vec2 p0 = half_ * vec2(-0.55 + 0.35 * sin(tb * 0.63), -0.45 + 0.35 * cos(tb * 0.51));
|
|
1680
|
+
vec2 p1 = half_ * vec2(0.55 + 0.30 * cos(tb * 0.57 + 1.0), -0.35 + 0.40 * sin(tb * 0.71 + 2.0));
|
|
1681
|
+
vec2 p2 = half_ * vec2(0.45 + 0.35 * sin(tb * 0.49 + 3.0), 0.50 + 0.30 * cos(tb * 0.61 + 1.5));
|
|
1682
|
+
vec2 p3 = half_ * vec2(-0.50 + 0.35 * cos(tb * 0.67 + 4.0), 0.45 + 0.35 * sin(tb * 0.53 + 0.5));
|
|
1683
|
+
|
|
1684
|
+
float w0 = blob(w, p0);
|
|
1685
|
+
float w1 = blob(w, p1);
|
|
1686
|
+
float w2 = blob(w, p2);
|
|
1687
|
+
float w3 = blob(w, p3);
|
|
1688
|
+
float wb = 0.05;
|
|
1689
|
+
|
|
1690
|
+
vec3 lab = (toOklab(uColor0) * w0 + toOklab(uColor1) * w1 + toOklab(uColor2) * w2 + toOklab(uColor3) * w3 + toOklab(uBase) * wb)
|
|
1691
|
+
/ (w0 + w1 + w2 + w3 + wb);
|
|
1692
|
+
|
|
1693
|
+
// \u7F0E\u9762\u6D41\u5149\uFF1A\u6CBF\u6D41\u573A\u7B49\u503C\u7EBF\u7684\u67D4\u548C\u4EAE\u5E26\u968F\u65F6\u95F4\u6ED1\u8FC7\uFF0C\u8C37\u5E95\u5FAE\u6697\uFF0C\u5E26\u51FA\u4E1D\u7EF8\u822C\u7684\u5C42\u6B21
|
|
1694
|
+
float band = sin((r.x * 1.4 - r.y + q.x * 0.6) * 11.0 + t * 3.0);
|
|
1695
|
+
float gloss = smoothstep(0.15, 1.0, band);
|
|
1696
|
+
lab.x += gloss * gloss * 0.06 - (1.0 - smoothstep(-1.0, 0.1, band)) * 0.025;
|
|
1697
|
+
lab.x += swirl * 0.025;
|
|
1698
|
+
// \u9AD8\u5149\u5904\u7565\u964D\u9971\u548C\uFF0C\u50CF\u5149\u6253\u5728\u7EC7\u7269\u8868\u9762
|
|
1699
|
+
lab.yz *= 1.0 - gloss * gloss * 0.12;
|
|
1700
|
+
|
|
1701
|
+
vec3 color = pow(clamp(fromOklab(lab), 0.0, 1.0), vec3(1.0 / 2.2));
|
|
1702
|
+
|
|
1703
|
+
// \u80F6\u7247\u9897\u7C92 + \u6296\u52A8\uFF0C\u6D88\u9664\u5927\u9762\u79EF\u6E10\u53D8\u7684\u8272\u5E26
|
|
1704
|
+
float n = hash(frag + fract(uTime * 7.31) * 113.0) - 0.5;
|
|
1705
|
+
color += n * (uGrain * 0.07 + 1.0 / 255.0);
|
|
1706
|
+
|
|
1707
|
+
gl_FragColor = vec4(color, 1.0);
|
|
1708
|
+
}
|
|
1709
|
+
`;
|
|
1710
|
+
function MeshGradient({
|
|
1711
|
+
children,
|
|
1712
|
+
className,
|
|
1713
|
+
style,
|
|
1714
|
+
colors = DEFAULT_COLORS3,
|
|
1715
|
+
grain = 0.35,
|
|
1716
|
+
speed = 1,
|
|
1717
|
+
interactive = true
|
|
1718
|
+
}) {
|
|
1719
|
+
const scheme = useColorScheme();
|
|
1720
|
+
const [c0 = DEFAULT_COLORS3[0], c1 = DEFAULT_COLORS3[1], c2 = DEFAULT_COLORS3[2], c3 = DEFAULT_COLORS3[3]] = colors;
|
|
1721
|
+
const canvasRef = useShaderCanvas({
|
|
1722
|
+
fragmentShader: FRAGMENT_SHADER9,
|
|
1723
|
+
speed,
|
|
1724
|
+
interactive,
|
|
1725
|
+
onDraw: ({ gl, uniform }) => {
|
|
1726
|
+
gl.uniform3fv(uniform("uColor0"), hexToLinearRgb(c0));
|
|
1727
|
+
gl.uniform3fv(uniform("uColor1"), hexToLinearRgb(c1));
|
|
1728
|
+
gl.uniform3fv(uniform("uColor2"), hexToLinearRgb(c2));
|
|
1729
|
+
gl.uniform3fv(uniform("uColor3"), hexToLinearRgb(c3));
|
|
1730
|
+
gl.uniform3fv(uniform("uBase"), hexToLinearRgb(scheme === "light" ? "#f7f7fa" : "#0b0b12"));
|
|
1731
|
+
gl.uniform1f(uniform("uGrain"), Math.max(0, grain));
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1734
|
+
return /* @__PURE__ */ jsxs(
|
|
1735
|
+
"div",
|
|
1736
|
+
{
|
|
1737
|
+
className: cn("elyri-mesh-gradient", className),
|
|
1738
|
+
"data-scheme": scheme,
|
|
1739
|
+
style: {
|
|
1740
|
+
"--elyri-mesh-gradient-c0": c0,
|
|
1741
|
+
"--elyri-mesh-gradient-c1": c1,
|
|
1742
|
+
"--elyri-mesh-gradient-c2": c2,
|
|
1743
|
+
"--elyri-mesh-gradient-c3": c3,
|
|
1744
|
+
...style
|
|
1745
|
+
},
|
|
1746
|
+
children: [
|
|
1747
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-mesh-gradient__canvas", "aria-hidden": "true" }),
|
|
1748
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-mesh-gradient__content", children })
|
|
1749
|
+
]
|
|
1750
|
+
}
|
|
1751
|
+
);
|
|
1752
|
+
}
|
|
1753
|
+
var FRAGMENT_SHADER10 = `
|
|
1754
|
+
precision highp float;
|
|
1755
|
+
|
|
1756
|
+
uniform vec2 uResolution;
|
|
1757
|
+
uniform float uTime;
|
|
1758
|
+
uniform vec2 uPointer;
|
|
1759
|
+
uniform vec3 uColor;
|
|
1760
|
+
uniform vec3 uHighlight;
|
|
1761
|
+
uniform float uCell;
|
|
1762
|
+
uniform float uFollow;
|
|
1763
|
+
uniform sampler2D uVideo;
|
|
1764
|
+
uniform float uHasVideo;
|
|
1765
|
+
uniform vec2 uVideoSize;
|
|
1766
|
+
uniform float uScheme;
|
|
1767
|
+
uniform float uSeam;
|
|
1768
|
+
|
|
1769
|
+
float hash(vec2 p) {
|
|
1770
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
1771
|
+
p += dot(p, p + 45.32);
|
|
1772
|
+
return fract(p.x * p.y);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
float noise(vec2 p) {
|
|
1776
|
+
vec2 i = floor(p);
|
|
1777
|
+
vec2 f = fract(p);
|
|
1778
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
1779
|
+
return mix(
|
|
1780
|
+
mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x),
|
|
1781
|
+
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x),
|
|
1782
|
+
u.y
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
float fbm(vec2 p) {
|
|
1787
|
+
float v = 0.0;
|
|
1788
|
+
float a = 0.5;
|
|
1789
|
+
mat2 m = mat2(1.6, 1.2, -1.2, 1.6);
|
|
1790
|
+
for (int i = 0; i < 5; i++) {
|
|
1791
|
+
v += a * noise(p);
|
|
1792
|
+
p = m * p;
|
|
1793
|
+
a *= 0.5;
|
|
1794
|
+
}
|
|
1795
|
+
return v;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
// \u706B\u7130\u70ED\u5EA6\u573A\uFF1A\u57DF\u626D\u66F2\u7684\u566A\u58F0\u7F13\u6162\u4E0A\u5347\uFF0C\u9760\u8FD1\u7126\u70B9\u5904\u66F4\u4EAE
|
|
1799
|
+
float heat(vec2 p, vec2 focus, float t) {
|
|
1800
|
+
vec2 q = vec2(
|
|
1801
|
+
fbm(p * 1.4 + vec2(0.0, t * 0.18)),
|
|
1802
|
+
fbm(p * 1.4 + vec2(5.2, 1.3) - t * 0.12)
|
|
1803
|
+
);
|
|
1804
|
+
float n = fbm(p * 2.0 + q * 1.7 + vec2(0.0, t * 0.3));
|
|
1805
|
+
vec2 d = p - focus;
|
|
1806
|
+
float glow = exp(-dot(d, d) * 1.6);
|
|
1807
|
+
return n * n * 1.8 * (0.3 + 0.9 * glow);
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
vec3 aces(vec3 x) {
|
|
1811
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
void main() {
|
|
1815
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
1816
|
+
float cell = max(uCell, 2.0);
|
|
1817
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
1818
|
+
float t = uTime;
|
|
1819
|
+
|
|
1820
|
+
// \u4EE5\u706F\u73E0\u4E2D\u5FC3\u91C7\u6837\uFF0C\u6574\u9897\u706F\u73E0\u540C\u8272
|
|
1821
|
+
vec2 id = floor(frag / cell);
|
|
1822
|
+
vec2 center = (id + 0.5) * cell;
|
|
1823
|
+
vec2 vc = frag / uResolution - 0.5;
|
|
1824
|
+
float grain = (0.86 + 0.2 * hash(id)) * (0.95 + 0.1 * hash(id + floor(t * 10.0) * vec2(7.13, 3.71)));
|
|
1825
|
+
vec3 color;
|
|
1826
|
+
|
|
1827
|
+
if (uHasVideo > 0.5) {
|
|
1828
|
+
// cover \u94FA\u6EE1\uFF1A\u6309\u5BBD\u9AD8\u6BD4\u88C1\u5207\u89C6\u9891
|
|
1829
|
+
vec2 uv = center / uResolution - 0.5;
|
|
1830
|
+
float screenAspect = uResolution.x / uResolution.y;
|
|
1831
|
+
float videoAspect = uVideoSize.x / max(uVideoSize.y, 1.0);
|
|
1832
|
+
if (screenAspect > videoAspect) uv.y *= videoAspect / screenAspect;
|
|
1833
|
+
else uv.x *= screenAspect / videoAspect;
|
|
1834
|
+
color = texture2D(uVideo, uv + 0.5).rgb * grain * 1.1;
|
|
1835
|
+
// \u6DF1\u8272\u538B\u6697\u56DB\u89D2\uFF0C\u6D45\u8272\u63D0\u4EAE\u56DB\u89D2
|
|
1836
|
+
color = mix(color * (1.0 - dot(vc, vc) * 0.6), mix(color, vec3(1.0), dot(vc, vc) * 0.8), uScheme);
|
|
1837
|
+
} else {
|
|
1838
|
+
vec2 p = (center - 0.5 * uResolution) / minRes;
|
|
1839
|
+
vec2 focus = mix(vec2(0.0, 0.1), (uPointer - 0.5 * uResolution) / minRes, 0.5 * uFollow);
|
|
1840
|
+
float h = heat(p, focus, t) * grain;
|
|
1841
|
+
color = uColor * h * 1.3 + uHighlight * pow(max(h - 0.55, 0.0), 2.0) * 2.2;
|
|
1842
|
+
color += uColor * 0.012;
|
|
1843
|
+
color *= 1.0 - dot(vc, vc) * 0.9;
|
|
1844
|
+
color = pow(aces(color), vec3(1.0 / 2.2));
|
|
1845
|
+
if (uScheme > 0.5) {
|
|
1846
|
+
// \u6D45\u8272\uFF1A\u4EAE\u6697\u955C\u50CF\u5E76\u4FDD\u7559\u8272\u76F8 \u2014\u2014 \u6DF1\u5E95\u4EAE\u7130\u7FFB\u8F6C\u4E3A\u6D45\u5E95\u6DF1\u7130
|
|
1847
|
+
float lum = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
|
1848
|
+
color = clamp(color + (1.0 - 2.0 * lum), 0.0, 1.0);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// \u8272\u9636\u91CF\u5316\uFF0C\u6A21\u62DF LED \u9A71\u52A8\u7684\u6709\u9650\u7070\u5EA6
|
|
1853
|
+
color = floor(color * 14.0 + hash(id + 3.1)) / 14.0;
|
|
1854
|
+
|
|
1855
|
+
// \u706F\u73E0\u5F62\u72B6\uFF1A\u65B9\u5F62\u53D1\u5149\u70B9\uFF1B\u95F4\u9699\u6DF1\u8272\u65F6\u4FDD\u7559\u5C11\u8BB8\u6F0F\u5149\uFF0C\u6D45\u8272\u65F6\u4E3A\u6D45\u7070\u5E95\u677F
|
|
1856
|
+
vec2 f = fract(frag / cell) - 0.5;
|
|
1857
|
+
float d = max(abs(f.x), abs(f.y));
|
|
1858
|
+
vec3 gap = mix(color * 0.2, mix(color, vec3(0.96), 0.7), uScheme);
|
|
1859
|
+
color = mix(gap, color, smoothstep(0.5, 0.28, d));
|
|
1860
|
+
|
|
1861
|
+
// \u62FC\u63A5\u5C4F\u63A5\u7F1D\uFF1A\u6BCF 16\xD710 \u9897\u706F\u73E0\u4E00\u5757\uFF0C\u63A5\u7F1D + \u7F1D\u4E0B\u65B9\u7684\u9634\u5F71
|
|
1862
|
+
if (uSeam > 0.0) {
|
|
1863
|
+
vec2 pp = mod(frag, vec2(16.0, 10.0) * cell);
|
|
1864
|
+
float seam = max(1.0 - smoothstep(uSeam - 1.0, uSeam + 1.0, pp.x), 1.0 - smoothstep(uSeam - 1.0, uSeam + 1.0, pp.y));
|
|
1865
|
+
float shade = max(1.0 - smoothstep(uSeam, uSeam + cell * 1.5, pp.x), 1.0 - smoothstep(uSeam, uSeam + cell * 1.5, pp.y));
|
|
1866
|
+
color *= 1.0 - mix(0.45, 0.15, uScheme) * shade;
|
|
1867
|
+
vec3 seamColor = mix(vec3(0.018, 0.016, 0.015), vec3(0.86, 0.855, 0.85), uScheme) + color * 0.06;
|
|
1868
|
+
color = mix(color, seamColor, seam);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
gl_FragColor = vec4(color, 1.0);
|
|
1872
|
+
}
|
|
1873
|
+
`;
|
|
1874
|
+
function PixelVortex({
|
|
1875
|
+
children,
|
|
1876
|
+
className,
|
|
1877
|
+
videoSrc,
|
|
1878
|
+
color = "#ff4d12",
|
|
1879
|
+
highlightColor = "#ffd9b0",
|
|
1880
|
+
cellSize = 4,
|
|
1881
|
+
seams = false,
|
|
1882
|
+
seamWidth = 5,
|
|
1883
|
+
speed = 1,
|
|
1884
|
+
interactive = true
|
|
1885
|
+
}) {
|
|
1886
|
+
const scheme = useColorScheme();
|
|
1887
|
+
const [video, setVideo] = useState(null);
|
|
1888
|
+
const [videoReady, setVideoReady] = useState(false);
|
|
1889
|
+
const textureRef = useRef(null);
|
|
1890
|
+
useEffect(() => {
|
|
1891
|
+
if (!videoSrc) return;
|
|
1892
|
+
const el = document.createElement("video");
|
|
1893
|
+
el.crossOrigin = "anonymous";
|
|
1894
|
+
el.muted = true;
|
|
1895
|
+
el.loop = true;
|
|
1896
|
+
el.playsInline = true;
|
|
1897
|
+
el.preload = "auto";
|
|
1898
|
+
let disposed = false;
|
|
1899
|
+
const tryPlay = () => {
|
|
1900
|
+
if (disposed || document.hidden) return;
|
|
1901
|
+
el.play().catch(() => {
|
|
1902
|
+
});
|
|
1903
|
+
};
|
|
1904
|
+
const handleReady = () => {
|
|
1905
|
+
if (disposed) return;
|
|
1906
|
+
setVideo(el);
|
|
1907
|
+
setVideoReady(true);
|
|
1908
|
+
};
|
|
1909
|
+
const handleError = () => {
|
|
1910
|
+
if (disposed) return;
|
|
1911
|
+
setVideoReady(false);
|
|
1912
|
+
setVideo(null);
|
|
1913
|
+
};
|
|
1914
|
+
const handlePause = () => tryPlay();
|
|
1915
|
+
const handleVisibility = () => {
|
|
1916
|
+
if (document.hidden) el.pause();
|
|
1917
|
+
else tryPlay();
|
|
1918
|
+
};
|
|
1919
|
+
el.addEventListener("loadeddata", handleReady);
|
|
1920
|
+
el.addEventListener("canplay", handleReady);
|
|
1921
|
+
el.addEventListener("error", handleError);
|
|
1922
|
+
el.addEventListener("pause", handlePause);
|
|
1923
|
+
document.addEventListener("visibilitychange", handleVisibility);
|
|
1924
|
+
el.src = videoSrc;
|
|
1925
|
+
tryPlay();
|
|
1926
|
+
return () => {
|
|
1927
|
+
disposed = true;
|
|
1928
|
+
el.removeEventListener("loadeddata", handleReady);
|
|
1929
|
+
el.removeEventListener("canplay", handleReady);
|
|
1930
|
+
el.removeEventListener("error", handleError);
|
|
1931
|
+
el.removeEventListener("pause", handlePause);
|
|
1932
|
+
document.removeEventListener("visibilitychange", handleVisibility);
|
|
1933
|
+
el.pause();
|
|
1934
|
+
el.removeAttribute("src");
|
|
1935
|
+
el.load();
|
|
1936
|
+
setVideoReady(false);
|
|
1937
|
+
setVideo(null);
|
|
1938
|
+
};
|
|
1939
|
+
}, [videoSrc]);
|
|
1940
|
+
const canvasRef = useShaderCanvas({
|
|
1941
|
+
fragmentShader: FRAGMENT_SHADER10,
|
|
1942
|
+
speed,
|
|
1943
|
+
interactive,
|
|
1944
|
+
onDraw: ({ gl, uniform, dpr }) => {
|
|
1945
|
+
gl.uniform3fv(uniform("uColor"), hexToLinearRgb(color));
|
|
1946
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
1947
|
+
gl.uniform1f(uniform("uCell"), Math.max(2, cellSize) * dpr);
|
|
1948
|
+
gl.uniform1f(uniform("uFollow"), interactive ? 1 : 0);
|
|
1949
|
+
gl.uniform1f(uniform("uScheme"), scheme === "light" ? 1 : 0);
|
|
1950
|
+
gl.uniform1f(uniform("uSeam"), seams ? Math.max(0.5, seamWidth) * dpr : 0);
|
|
1951
|
+
const hasVideo = video != null && videoReady;
|
|
1952
|
+
gl.uniform1f(uniform("uHasVideo"), hasVideo ? 1 : 0);
|
|
1953
|
+
if (!hasVideo || !video) return;
|
|
1954
|
+
if (textureRef.current?.gl !== gl) {
|
|
1955
|
+
const texture = gl.createTexture();
|
|
1956
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
1957
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
1958
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
1959
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
1960
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
1961
|
+
textureRef.current = { gl, texture };
|
|
1962
|
+
}
|
|
1963
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
1964
|
+
gl.bindTexture(gl.TEXTURE_2D, textureRef.current.texture);
|
|
1965
|
+
if (video.readyState >= video.HAVE_CURRENT_DATA && video.videoWidth > 0) {
|
|
1966
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, video);
|
|
1967
|
+
}
|
|
1968
|
+
gl.uniform1i(uniform("uVideo"), 0);
|
|
1969
|
+
gl.uniform2f(uniform("uVideoSize"), video.videoWidth, video.videoHeight);
|
|
1970
|
+
}
|
|
1971
|
+
});
|
|
1972
|
+
return /* @__PURE__ */ jsxs(
|
|
1973
|
+
"div",
|
|
1974
|
+
{
|
|
1975
|
+
className: cn("elyri-pixel-vortex", className),
|
|
1976
|
+
"data-scheme": scheme,
|
|
1977
|
+
style: { "--elyri-pixel-vortex-color": color },
|
|
1978
|
+
children: [
|
|
1979
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-pixel-vortex__canvas", "aria-hidden": "true" }),
|
|
1980
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-pixel-vortex__content", children })
|
|
1981
|
+
]
|
|
1982
|
+
}
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1985
|
+
var PLANET_PRESETS = {
|
|
1986
|
+
mars: { color: "#c1532b", terrainColor: "#4e1e12", atmosphereColor: "#f2a57c", atmosphere: 0.6 },
|
|
1987
|
+
jupiter: { color: "#ecdcc0", terrainColor: "#a86a3a", atmosphereColor: "#d9cdb8", atmosphere: 0.3 },
|
|
1988
|
+
earth: { color: "#3f5a2a", terrainColor: "#0a2744", atmosphereColor: "#6fa8ff", atmosphere: 0.55 }
|
|
1989
|
+
};
|
|
1990
|
+
var COMMON = `
|
|
1991
|
+
precision highp float;
|
|
1992
|
+
|
|
1993
|
+
#define PI 3.14159265
|
|
1994
|
+
#define HALF 8
|
|
1995
|
+
|
|
1996
|
+
uniform vec2 uResolution;
|
|
1997
|
+
uniform float uTime;
|
|
1998
|
+
uniform vec2 uPointer;
|
|
1999
|
+
uniform vec3 uSurface;
|
|
2000
|
+
uniform vec3 uTerrain;
|
|
2001
|
+
uniform vec3 uAtmosphere;
|
|
2002
|
+
uniform float uDensity;
|
|
2003
|
+
uniform float uStars;
|
|
2004
|
+
uniform float uHorizon;
|
|
2005
|
+
uniform float uSun;
|
|
2006
|
+
uniform vec2 uSunPos;
|
|
2007
|
+
uniform float uSunFixed;
|
|
2008
|
+
|
|
2009
|
+
const float ALT = 0.15;
|
|
2010
|
+
const float FL = 1.25;
|
|
2011
|
+
const float H = 0.0045;
|
|
2012
|
+
const float RT = 1.0 + 10.0 * H;
|
|
2013
|
+
const float SUN_I = 5.0;
|
|
2014
|
+
const float SUN_R = 0.012;
|
|
2015
|
+
|
|
2016
|
+
float hash12(vec2 p) {
|
|
2017
|
+
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
2018
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
2019
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
float hash13(vec3 p) {
|
|
2023
|
+
p = fract(p * 0.1031);
|
|
2024
|
+
p += dot(p, p.zyx + 31.32);
|
|
2025
|
+
return fract((p.x + p.y) * p.z);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
vec3 hash33(vec3 p) {
|
|
2029
|
+
p = fract(p * vec3(0.1031, 0.1030, 0.0973));
|
|
2030
|
+
p += dot(p, p.yxz + 33.33);
|
|
2031
|
+
return fract((p.xxy + p.yxx) * p.zyx);
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
float noise2(vec2 p) {
|
|
2035
|
+
vec2 i = floor(p);
|
|
2036
|
+
vec2 f = fract(p);
|
|
2037
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
2038
|
+
return mix(
|
|
2039
|
+
mix(hash12(i), hash12(i + vec2(1.0, 0.0)), u.x),
|
|
2040
|
+
mix(hash12(i + vec2(0.0, 1.0)), hash12(i + vec2(1.0, 1.0)), u.x),
|
|
2041
|
+
u.y
|
|
2042
|
+
);
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
float noise3(vec3 x) {
|
|
2046
|
+
vec3 i = floor(x);
|
|
2047
|
+
vec3 f = fract(x);
|
|
2048
|
+
vec3 u = f * f * (3.0 - 2.0 * f);
|
|
2049
|
+
return mix(
|
|
2050
|
+
mix(mix(hash13(i), hash13(i + vec3(1, 0, 0)), u.x), mix(hash13(i + vec3(0, 1, 0)), hash13(i + vec3(1, 1, 0)), u.x), u.y),
|
|
2051
|
+
mix(mix(hash13(i + vec3(0, 0, 1)), hash13(i + vec3(1, 0, 1)), u.x), mix(hash13(i + vec3(0, 1, 1)), hash13(i + vec3(1, 1, 1)), u.x), u.y),
|
|
2052
|
+
u.z
|
|
2053
|
+
);
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
float lod(float freqTimesFootprint) {
|
|
2057
|
+
return 1.0 - smoothstep(0.25, 0.6, freqTimesFootprint);
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
float fbm3(vec3 p, float fp, int octaves) {
|
|
2061
|
+
float s = 0.0;
|
|
2062
|
+
float a = 0.5;
|
|
2063
|
+
float f = 1.0;
|
|
2064
|
+
for (int i = 0; i < 8; i++) {
|
|
2065
|
+
float w = lod(f * fp);
|
|
2066
|
+
if (i >= octaves || w <= 0.0) break;
|
|
2067
|
+
s += a * w * (noise3(p * f + float(i) * 7.13) - 0.5);
|
|
2068
|
+
a *= 0.55;
|
|
2069
|
+
f *= 2.02;
|
|
2070
|
+
}
|
|
2071
|
+
return s;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
float chapman(float X, float h, float coschi) {
|
|
2075
|
+
float c = sqrt(X + h);
|
|
2076
|
+
if (coschi >= 0.0) return c / (c * coschi + 1.0) * exp(-h);
|
|
2077
|
+
float x0 = sqrt(1.0 - coschi * coschi) * (X + h);
|
|
2078
|
+
return 2.0 * sqrt(x0) * exp(min(X - x0, 40.0)) - c / (1.0 - c * coschi) * exp(-h);
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
vec3 stars(vec3 rd, float pixAngle) {
|
|
2082
|
+
vec2 a = vec2(atan(rd.x, -rd.z), asin(clamp(rd.y, -1.0, 1.0)));
|
|
2083
|
+
vec3 col = vec3(0.0);
|
|
2084
|
+
for (int layer = 0; layer < 2; layer++) {
|
|
2085
|
+
float scale = layer == 0 ? 70.0 : 190.0;
|
|
2086
|
+
float seed = float(layer) * 17.0;
|
|
2087
|
+
vec2 g = a * scale;
|
|
2088
|
+
vec2 cell = floor(g);
|
|
2089
|
+
if (hash12(cell + seed) > uStars * (layer == 0 ? 0.22 : 0.2)) continue;
|
|
2090
|
+
vec2 pos = 0.2 + 0.6 * vec2(hash12(cell + seed + 3.1), hash12(cell + seed + 7.7));
|
|
2091
|
+
float px = length(fract(g) - pos) / scale / pixAngle;
|
|
2092
|
+
float h = hash12(cell + seed + 5.3);
|
|
2093
|
+
float mag = layer == 0 ? 0.05 + 2.0 * pow(h, 8.0) : 0.015 + 0.05 * h;
|
|
2094
|
+
float tw = 0.7 + 0.3 * sin(uTime * (0.8 + 2.5 * h) + h * 40.0);
|
|
2095
|
+
vec3 tint = mix(vec3(0.62, 0.74, 1.0), vec3(1.0, 0.82, 0.64), hash12(cell + seed + 9.9));
|
|
2096
|
+
col += tint * mag * tw * exp(-px * px * 1.4);
|
|
2097
|
+
}
|
|
2098
|
+
vec2 q = a * vec2(2.2, 3.4);
|
|
2099
|
+
float neb = noise2(q) * 0.55 + noise2(q * 2.1 + 4.0) * 0.3 + noise2(q * 4.3 + 9.0) * 0.15;
|
|
2100
|
+
float band = exp(-pow((a.y + 0.35 * a.x + 0.05) * 2.6, 2.0));
|
|
2101
|
+
col += mix(vec3(0.05, 0.04, 0.12), vec3(0.1, 0.05, 0.07), neb) * smoothstep(0.35, 0.85, neb) * band * 0.12 * uStars;
|
|
2102
|
+
return col;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
vec3 aces(vec3 x) {
|
|
2106
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
2107
|
+
}
|
|
2108
|
+
`;
|
|
2109
|
+
var RELIEF = `
|
|
2110
|
+
vec4 noised(vec3 x) {
|
|
2111
|
+
vec3 i = floor(x);
|
|
2112
|
+
vec3 w = fract(x);
|
|
2113
|
+
vec3 u = w * w * w * (w * (w * 6.0 - 15.0) + 10.0);
|
|
2114
|
+
vec3 du = 30.0 * w * w * (w * (w - 2.0) + 1.0);
|
|
2115
|
+
float a = hash13(i);
|
|
2116
|
+
float b = hash13(i + vec3(1, 0, 0));
|
|
2117
|
+
float c = hash13(i + vec3(0, 1, 0));
|
|
2118
|
+
float d = hash13(i + vec3(1, 1, 0));
|
|
2119
|
+
float e = hash13(i + vec3(0, 0, 1));
|
|
2120
|
+
float f = hash13(i + vec3(1, 0, 1));
|
|
2121
|
+
float g = hash13(i + vec3(0, 1, 1));
|
|
2122
|
+
float h = hash13(i + vec3(1, 1, 1));
|
|
2123
|
+
float k1 = b - a;
|
|
2124
|
+
float k2 = c - a;
|
|
2125
|
+
float k3 = e - a;
|
|
2126
|
+
float k4 = a - b - c + d;
|
|
2127
|
+
float k5 = a - c - e + g;
|
|
2128
|
+
float k6 = a - b - e + f;
|
|
2129
|
+
float k7 = -a + b + c - d + e - f - g + h;
|
|
2130
|
+
return vec4(
|
|
2131
|
+
a + k1 * u.x + k2 * u.y + k3 * u.z + k4 * u.x * u.y + k5 * u.y * u.z + k6 * u.z * u.x + k7 * u.x * u.y * u.z,
|
|
2132
|
+
du * vec3(
|
|
2133
|
+
k1 + k4 * u.y + k6 * u.z + k7 * u.y * u.z,
|
|
2134
|
+
k2 + k5 * u.z + k4 * u.x + k7 * u.z * u.x,
|
|
2135
|
+
k3 + k6 * u.x + k5 * u.y + k7 * u.x * u.y
|
|
2136
|
+
)
|
|
2137
|
+
);
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
vec4 terrain(vec3 p, float fp) {
|
|
2141
|
+
vec4 s = vec4(0.0);
|
|
2142
|
+
vec3 dsum = vec3(0.0);
|
|
2143
|
+
float a = 0.5;
|
|
2144
|
+
float f = 1.0;
|
|
2145
|
+
for (int i = 0; i < 10; i++) {
|
|
2146
|
+
float w = lod(f * fp);
|
|
2147
|
+
if (w <= 0.0) break;
|
|
2148
|
+
vec4 n = noised(p * f + float(i) * vec3(3.1, 7.7, 1.3));
|
|
2149
|
+
vec3 g = n.yzw * f;
|
|
2150
|
+
dsum += g * a;
|
|
2151
|
+
float k = a * w / (1.0 + 0.35 * dot(dsum, dsum));
|
|
2152
|
+
s.x += k * (n.x - 0.5);
|
|
2153
|
+
s.yzw += k * g;
|
|
2154
|
+
a *= 0.5;
|
|
2155
|
+
f *= 2.03;
|
|
2156
|
+
}
|
|
2157
|
+
return s;
|
|
2158
|
+
}
|
|
2159
|
+
`;
|
|
2160
|
+
var MARS_SURFACE = `
|
|
2161
|
+
uniform float uCraters;
|
|
2162
|
+
|
|
2163
|
+
const float BUMP = 0.06;
|
|
2164
|
+
|
|
2165
|
+
float craterProfile(float x) {
|
|
2166
|
+
return 0.8 * (smoothstep(0.0, 1.0, x) - 1.0) + 0.3 * exp(-10.0 * (x - 1.0) * (x - 1.0));
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
float craterLayer(vec3 p, float scale, float fp, float seed, inout vec3 grad) {
|
|
2170
|
+
vec3 g = p * scale + seed;
|
|
2171
|
+
vec3 cell = floor(g);
|
|
2172
|
+
vec3 r = hash33(cell + seed);
|
|
2173
|
+
if (r.x > 0.75 * uCraters) return 0.0;
|
|
2174
|
+
vec3 c = cell + 0.3 + 0.4 * hash33(cell * 1.7 + seed + 11.0);
|
|
2175
|
+
float R = mix(0.07, 0.18, r.y * r.y);
|
|
2176
|
+
vec3 d = g - c;
|
|
2177
|
+
float dist = length(d);
|
|
2178
|
+
float x = dist / R;
|
|
2179
|
+
if (x > 1.6) return 0.0;
|
|
2180
|
+
float w = 1.0 - smoothstep(0.1, 0.4, fp * scale / R);
|
|
2181
|
+
float depth = uCraters * mix(0.5, 1.0, r.z) * w;
|
|
2182
|
+
float dh = (craterProfile(x + 0.01) - craterProfile(x - 0.01)) / 0.02;
|
|
2183
|
+
grad += dh * d / max(dist, 1e-4) * depth * 0.8;
|
|
2184
|
+
return craterProfile(x) * w;
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
vec3 shadeSurface(vec3 n, float ndv, float pix, vec3 sun, vec3 beta, float X) {
|
|
2188
|
+
float fp = pix / max(sqrt(ndv), 0.12);
|
|
2189
|
+
|
|
2190
|
+
float ang = -uTime * 0.01;
|
|
2191
|
+
float cs = cos(ang);
|
|
2192
|
+
float sn = sin(ang);
|
|
2193
|
+
mat3 spin = mat3(1.0, 0.0, 0.0, 0.0, cs, sn, 0.0, -sn, cs);
|
|
2194
|
+
vec3 q = spin * n;
|
|
2195
|
+
|
|
2196
|
+
vec4 ter = terrain(q * 4.0 + 2.0, fp * 4.0);
|
|
2197
|
+
vec3 grad = ter.yzw * 4.0 * BUMP;
|
|
2198
|
+
float crater = 0.0;
|
|
2199
|
+
crater += craterLayer(q, 5.0, fp, 1.3, grad);
|
|
2200
|
+
crater += craterLayer(q, 11.0, fp, 7.9, grad);
|
|
2201
|
+
crater += craterLayer(q, 23.0, fp, 4.1, grad);
|
|
2202
|
+
crater += craterLayer(q, 47.0, fp, 9.6, grad);
|
|
2203
|
+
crater += craterLayer(q, 97.0, fp, 5.7, grad);
|
|
2204
|
+
crater += craterLayer(q, 199.0, fp, 2.2, grad);
|
|
2205
|
+
grad = grad * spin;
|
|
2206
|
+
grad -= dot(grad, n) * n;
|
|
2207
|
+
vec3 nb = normalize(n - grad);
|
|
2208
|
+
|
|
2209
|
+
float big = fbm3(q * 1.7 + 4.0, fp * 1.7, 8);
|
|
2210
|
+
float mid = fbm3(q * 9.0 + 1.0, fp * 9.0, 8);
|
|
2211
|
+
float fine = fbm3(q * 70.0 + 3.0, fp * 70.0, 8);
|
|
2212
|
+
vec3 albedo = mix(uSurface, uTerrain, smoothstep(-0.12, 0.22, big + 0.35 * mid + 0.15 * fine));
|
|
2213
|
+
albedo *= 0.8 + 0.7 * (mid + 0.5) * 0.6 + 2.0 * ter.x + 0.5 * fine;
|
|
2214
|
+
albedo *= 1.0 + 0.3 * crater;
|
|
2215
|
+
albedo = max(albedo, 0.0);
|
|
2216
|
+
|
|
2217
|
+
float ngl = dot(n, sun);
|
|
2218
|
+
float mu0 = max(dot(nb, sun), 0.0);
|
|
2219
|
+
float lsl = mu0 / (mu0 + ndv + 1e-3);
|
|
2220
|
+
float brdf = mix(mu0, lsl, 0.35) * smoothstep(-0.03, 0.08, ngl);
|
|
2221
|
+
vec3 sunT = exp(-beta * H * chapman(X, 0.0, ngl));
|
|
2222
|
+
vec3 sky = uAtmosphere * uDensity * 0.05 * smoothstep(-0.3, 0.4, ngl);
|
|
2223
|
+
return albedo * (SUN_I * 0.9 * sunT * brdf + sky + 0.004);
|
|
2224
|
+
}
|
|
2225
|
+
`;
|
|
2226
|
+
var JUPITER_SURFACE = `
|
|
2227
|
+
const vec3 AXIS = vec3(0.0, 0.2955, -0.9553);
|
|
2228
|
+
const vec3 EAST0 = vec3(1.0, 0.0, 0.0);
|
|
2229
|
+
const vec3 MERIDIAN0 = vec3(0.0, 0.9553, 0.2955);
|
|
2230
|
+
const float FLOW_T = 24.0;
|
|
2231
|
+
|
|
2232
|
+
vec3 spinAxis(vec3 p, float a) {
|
|
2233
|
+
float c = cos(a);
|
|
2234
|
+
float s = sin(a);
|
|
2235
|
+
return p * c + cross(AXIS, p) * s + AXIS * dot(AXIS, p) * (1.0 - c);
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
vec3 fromLatLon(float lat, float lon) {
|
|
2239
|
+
return cos(lat) * (cos(lon) * MERIDIAN0 + sin(lon) * EAST0) + sin(lat) * AXIS;
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
vec2 harmonic(float lat, float k, float a, float ph, float fpLat) {
|
|
2243
|
+
float w = a * lod(k * fpLat / (2.0 * PI));
|
|
2244
|
+
return w * vec2(sin(k * lat + ph), k * cos(k * lat + ph));
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
vec2 bandField(float lat, float fpLat) {
|
|
2248
|
+
return harmonic(lat, 61.0, 1.0, 0.9, fpLat)
|
|
2249
|
+
+ harmonic(lat, 107.0, 0.55, 2.4, fpLat)
|
|
2250
|
+
+ harmonic(lat, 211.0, 0.3, 4.1, fpLat)
|
|
2251
|
+
+ harmonic(lat, 409.0, 0.16, 1.7, fpLat);
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
float jet(float lat) {
|
|
2255
|
+
return 0.00011 * (61.0 * cos(61.0 * lat + 0.9) + 0.55 * 107.0 * cos(107.0 * lat + 2.4));
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
vec2 cloudPhase(vec3 p, float lat, float t, float seed, float fp) {
|
|
2259
|
+
vec3 q = spinAxis(p, -jet(lat) * t);
|
|
2260
|
+
q += AXIS * dot(q, AXIS) * 2.0;
|
|
2261
|
+
q += seed * vec3(1.7, 9.2, 4.3);
|
|
2262
|
+
float wx = fbm3(q * 7.0, fp * 14.0, 5);
|
|
2263
|
+
float wy = fbm3(q * 7.0 + 5.2, fp * 14.0, 5);
|
|
2264
|
+
float detail = fbm3(q * 30.0 + vec3(wx, wy, wx - wy) * 9.0, fp * 60.0, 7);
|
|
2265
|
+
return vec2(wx, detail);
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
vec2 vortexFrame(vec3 p, float lat0, float lon0, vec2 radii) {
|
|
2269
|
+
vec3 c = fromLatLon(lat0, lon0);
|
|
2270
|
+
vec3 east = normalize(cross(AXIS, c));
|
|
2271
|
+
vec3 north = cross(c, east);
|
|
2272
|
+
vec3 d = p - c;
|
|
2273
|
+
return vec2(dot(d, east), dot(d, north)) / radii;
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
vec2 vortex(vec2 v, float spin, float seed, float fp) {
|
|
2277
|
+
float r = length(v);
|
|
2278
|
+
float ang = spin * uTime + 2.4 * (1.0 - smoothstep(0.0, 1.1, r));
|
|
2279
|
+
float c = cos(ang);
|
|
2280
|
+
float s = sin(ang);
|
|
2281
|
+
vec2 w = mat2(c, -s, s, c) * v;
|
|
2282
|
+
float tex = fbm3(vec3(w * 2.4, r * 6.0 + seed), fp * 6.0, 6);
|
|
2283
|
+
float mask = 1.0 - smoothstep(0.6, 1.0, r + tex * 0.5);
|
|
2284
|
+
return vec2(mask, tex);
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
float vortexPush(vec2 v, float radiusY) {
|
|
2288
|
+
float r = length(v);
|
|
2289
|
+
return v.y / max(r, 1e-3) * radiusY * 0.7 * (1.0 - smoothstep(0.9, 2.6, r)) * smoothstep(0.0, 0.9, r);
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
vec3 shadeSurface(vec3 n, float ndv, float pix, vec3 sun, vec3 beta, float X) {
|
|
2293
|
+
float fp = pix / max(sqrt(ndv), 0.12);
|
|
2294
|
+
float fpLat = pix / max(ndv, 0.03);
|
|
2295
|
+
|
|
2296
|
+
float lat = asin(clamp(dot(n, AXIS), -1.0, 1.0));
|
|
2297
|
+
|
|
2298
|
+
float cyc = uTime / FLOW_T;
|
|
2299
|
+
float phA = fract(cyc);
|
|
2300
|
+
float phB = fract(cyc + 0.5);
|
|
2301
|
+
float wA = 1.0 - abs(2.0 * phA - 1.0);
|
|
2302
|
+
vec2 A = cloudPhase(n, lat, phA * FLOW_T, mod(floor(cyc), 61.0), fp);
|
|
2303
|
+
vec2 B = cloudPhase(n, lat, phB * FLOW_T, mod(floor(cyc + 0.5), 61.0) + 0.5, fp);
|
|
2304
|
+
vec2 cl = (A * wA + B * (1.0 - wA)) / sqrt(wA * wA + (1.0 - wA) * (1.0 - wA));
|
|
2305
|
+
|
|
2306
|
+
const vec2 GRS_R = vec2(0.05, 0.028);
|
|
2307
|
+
vec2 grs = vortexFrame(n, 0.6, -0.1 + 0.03 * sin(uTime * 0.021), GRS_R);
|
|
2308
|
+
float push = vortexPush(grs, GRS_R.y);
|
|
2309
|
+
const vec2 OVAL_R = vec2(0.013, 0.0085);
|
|
2310
|
+
vec2 ovals[5];
|
|
2311
|
+
for (int i = 0; i < 5; i++) {
|
|
2312
|
+
float fi = float(i);
|
|
2313
|
+
float lon = fi * 0.085 - 0.3 + 0.02 * sin(uTime * 0.017 + fi * 1.9);
|
|
2314
|
+
ovals[i] = vortexFrame(n, 0.545 + 0.003 * sin(fi * 2.3), lon, OVAL_R);
|
|
2315
|
+
push += vortexPush(ovals[i], OVAL_R.y);
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
float latB = lat + cl.x * 0.02 + push;
|
|
2319
|
+
vec2 band = bandField(latB, fpLat);
|
|
2320
|
+
float soft = 0.25 + abs(band.y) * fpLat;
|
|
2321
|
+
float belt = smoothstep(-soft, soft, band.x - 0.1);
|
|
2322
|
+
float edge = 1.0 - abs(2.0 * belt - 1.0);
|
|
2323
|
+
|
|
2324
|
+
float hue = 0.5 + 0.5 * sin(latB * 17.0 + 1.7);
|
|
2325
|
+
vec3 beltCol = mix(uTerrain, uTerrain * vec3(1.25, 0.9, 0.62), hue);
|
|
2326
|
+
vec3 zoneCol = mix(uSurface, uSurface * vec3(1.0, 0.9, 0.72), 1.0 - hue);
|
|
2327
|
+
vec3 albedo = mix(zoneCol, beltCol, belt);
|
|
2328
|
+
albedo *= 1.0 + cl.y * (1.6 + 2.4 * edge) + 0.1 * band.x;
|
|
2329
|
+
float festoon = smoothstep(0.05, 0.2, cl.y) * edge;
|
|
2330
|
+
albedo = mix(albedo, albedo * vec3(0.5, 0.62, 0.78), festoon * 0.55);
|
|
2331
|
+
|
|
2332
|
+
float rg = length(grs);
|
|
2333
|
+
vec2 gv = vortex(grs, 0.18, 3.0, fp / GRS_R.y);
|
|
2334
|
+
float collar = exp(-pow((rg - 1.1) / 0.22, 2.0));
|
|
2335
|
+
albedo = mix(albedo, zoneCol * (1.1 + cl.y), collar * 0.75);
|
|
2336
|
+
vec3 red = uTerrain * vec3(1.7, 0.66, 0.4);
|
|
2337
|
+
red *= (0.7 + 0.4 * smoothstep(0.0, 0.85, rg)) * (1.0 + 1.8 * gv.y);
|
|
2338
|
+
albedo = mix(albedo, red, gv.x);
|
|
2339
|
+
|
|
2340
|
+
for (int i = 0; i < 5; i++) {
|
|
2341
|
+
float r = length(ovals[i]);
|
|
2342
|
+
if (r < 1.6) {
|
|
2343
|
+
vec2 o = vortex(ovals[i], -0.4, float(i) * 3.1, fp / OVAL_R.y);
|
|
2344
|
+
albedo *= 1.0 - 0.35 * exp(-pow((r - 1.0) / 0.18, 2.0));
|
|
2345
|
+
albedo = mix(albedo, uSurface * (1.08 + 1.4 * o.y) * (0.9 + 0.15 * smoothstep(0.0, 0.7, r)), o.x * 0.92);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
albedo = max(albedo, 0.0);
|
|
2349
|
+
|
|
2350
|
+
float ngl = dot(n, sun);
|
|
2351
|
+
float mu0 = max(ngl, 0.0);
|
|
2352
|
+
float brdf = mu0 * smoothstep(-0.02, 0.1, ngl) + 0.015 * smoothstep(-0.12, 0.04, ngl);
|
|
2353
|
+
vec3 sunT = exp(-beta * H * chapman(X, 0.0, ngl));
|
|
2354
|
+
vec3 sky = uAtmosphere * uDensity * 0.05 * smoothstep(-0.3, 0.4, ngl);
|
|
2355
|
+
return albedo * (SUN_I * 0.9 * sunT * brdf + sky + 0.004);
|
|
2356
|
+
}
|
|
2357
|
+
`;
|
|
2358
|
+
var EARTH_SURFACE = `
|
|
2359
|
+
uniform float uCityLights;
|
|
2360
|
+
|
|
2361
|
+
const float CLOUD_H = 0.0016;
|
|
2362
|
+
const vec3 CITY_WARM = vec3(1.0, 0.5, 0.16);
|
|
2363
|
+
const vec3 CITY_COOL = vec3(1.0, 0.86, 0.66);
|
|
2364
|
+
|
|
2365
|
+
mat3 spinX(float a) {
|
|
2366
|
+
float c = cos(a);
|
|
2367
|
+
float s = sin(a);
|
|
2368
|
+
return mat3(1.0, 0.0, 0.0, 0.0, c, s, 0.0, -s, c);
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
vec3 cloudWarp(vec3 p, float fp) {
|
|
2372
|
+
vec3 s = p * 1.8 + vec3(0.0, 0.0, uTime * 0.0035);
|
|
2373
|
+
return vec3(fbm3(s + 1.3, fp * 1.8, 4), fbm3(s + 7.1, fp * 1.8, 4), fbm3(s + 4.4, fp * 1.8, 4));
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
float cloudCover(vec3 p, vec3 w, float fp) {
|
|
2377
|
+
float t = uTime * 0.006;
|
|
2378
|
+
float big = fbm3(p * 3.2 + w * 2.4 + vec3(t, 0.0, -t), fp * 3.2, 6);
|
|
2379
|
+
float puff = fbm3(p * 21.0 + w * 5.0 - vec3(0.0, t, t) * 3.0, fp * 21.0, 6);
|
|
2380
|
+
float c = big + 0.4 * puff * smoothstep(-0.15, 0.1, big);
|
|
2381
|
+
return smoothstep(0.03, 0.26, c + 0.02);
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
// \u6BCF\u4E2A\u683C\u5B50\u81F3\u591A\u4E00\u5EA7\u805A\u843D\uFF0C\u4F4D\u7F6E\u5728\u683C\u5185\u5B8C\u5168\u968F\u673A\uFF1B\u67E5 2x2x2 \u90BB\u683C\u907F\u514D\u88AB\u683C\u5B50\u8FB9\u754C\u622A\u65AD
|
|
2385
|
+
float settlements(vec3 q, float scale, float fp, float P, float seed) {
|
|
2386
|
+
vec3 g = q * scale + seed * 17.0;
|
|
2387
|
+
vec3 base = floor(g - 0.5);
|
|
2388
|
+
float f2 = fp * scale * fp * scale * 0.25;
|
|
2389
|
+
float sum = 0.0;
|
|
2390
|
+
for (int i = 0; i < 8; i++) {
|
|
2391
|
+
float fi = float(i);
|
|
2392
|
+
vec3 cell = base + vec3(mod(fi, 2.0), mod(floor(fi * 0.5), 2.0), floor(fi * 0.25));
|
|
2393
|
+
vec3 r = hash33(cell + seed);
|
|
2394
|
+
float w = smoothstep(r.x, r.x + 0.15, P);
|
|
2395
|
+
if (w <= 0.0) continue;
|
|
2396
|
+
vec3 d = g - cell - hash33(cell * 1.7 + seed + 5.0);
|
|
2397
|
+
d -= dot(d, q) * q;
|
|
2398
|
+
float s2 = mix(0.03, 0.14, r.y * r.y);
|
|
2399
|
+
s2 *= s2;
|
|
2400
|
+
float t2 = s2 + f2;
|
|
2401
|
+
sum += w * exp(-dot(d, d) / t2) * s2 / t2 * (0.5 + 0.5 * r.z);
|
|
2402
|
+
}
|
|
2403
|
+
return sum;
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
vec3 cityLights(vec3 q, float fp, float P) {
|
|
2407
|
+
float metro = settlements(q, 40.0, fp, P * 0.75, 1.0);
|
|
2408
|
+
float town = settlements(q, 170.0, fp, P * 0.45 + min(metro, 1.0) * 0.4, 2.0);
|
|
2409
|
+
float t = min(metro, 1.0);
|
|
2410
|
+
// \u8857\u533A\u9897\u7C92\uFF1A\u5E02\u4E2D\u5FC3\u8FDE\u6210\u4E00\u7247\uFF0C\u8D8A\u5F80\u90CA\u533A\u8D8A\u7834\u788E
|
|
2411
|
+
float grain = 0.6 * noise3(q * 1800.0) + 0.4 * noise3(q * 700.0 + 3.1);
|
|
2412
|
+
float lo = 0.72 - 0.55 * t;
|
|
2413
|
+
float mask = mix(0.2 + 0.6 * t, smoothstep(lo, lo + 0.2, grain), lod(fp * 1800.0));
|
|
2414
|
+
vec3 tint = mix(CITY_WARM, CITY_COOL, t * t * 0.8);
|
|
2415
|
+
return tint * metro * mask * 1.1 + CITY_WARM * min(town, 1.5) * 0.35;
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
vec3 shadeSurface(vec3 n, float ndv, float pix, vec3 sun, vec3 beta, float X) {
|
|
2419
|
+
float fp = pix / max(sqrt(ndv), 0.12);
|
|
2420
|
+
|
|
2421
|
+
mat3 spin = spinX(-uTime * 0.008);
|
|
2422
|
+
vec3 q = spin * n;
|
|
2423
|
+
|
|
2424
|
+
vec3 cw = vec3(fbm3(q * 1.2 + 3.7, fp * 1.2, 4), fbm3(q * 1.2 + 9.1, fp * 1.2, 4), fbm3(q * 1.2 + 5.3, fp * 1.2, 4));
|
|
2425
|
+
float cont = fbm3(q * 1.9 + cw * 1.4 + 0.7, fp * 1.9, 6);
|
|
2426
|
+
vec4 ter = terrain(q * 7.0 + 2.0, fp * 7.0);
|
|
2427
|
+
float e = cont + 0.3 * ter.x - 0.035;
|
|
2428
|
+
float aa = fp * 4.0 + 5e-4;
|
|
2429
|
+
float land = smoothstep(-aa, aa, e);
|
|
2430
|
+
float alt = max(e, 0.0);
|
|
2431
|
+
float mtn = smoothstep(0.02, 0.14, alt + 0.15 * ter.x);
|
|
2432
|
+
|
|
2433
|
+
vec3 grad = ter.yzw * 7.0 * 0.022 * (0.35 + 2.0 * mtn) * land;
|
|
2434
|
+
grad = grad * spin;
|
|
2435
|
+
grad -= dot(grad, n) * n;
|
|
2436
|
+
vec3 nb = normalize(n - grad);
|
|
2437
|
+
|
|
2438
|
+
float mid = fbm3(q * 14.0 + 1.0, fp * 14.0, 6);
|
|
2439
|
+
float dry = 0.0;
|
|
2440
|
+
float snow = 0.0;
|
|
2441
|
+
vec3 ground = uTerrain;
|
|
2442
|
+
if (land > 0.0) {
|
|
2443
|
+
float fine = fbm3(q * 60.0 + 3.0, fp * 60.0, 5);
|
|
2444
|
+
float moist = fbm3(q * 2.6 + 8.0, fp * 2.6, 6) + 0.15 * exp(-alt * 25.0);
|
|
2445
|
+
dry = 1.0 - smoothstep(-0.12, 0.02, moist + 0.25 * mid);
|
|
2446
|
+
float wet = smoothstep(-0.02, 0.12, moist + 0.2 * mid);
|
|
2447
|
+
vec3 grass = uSurface * vec3(1.9, 1.55, 1.0) + vec3(0.02, 0.012, 0.0);
|
|
2448
|
+
vec3 la = mix(grass, uSurface, wet);
|
|
2449
|
+
la = mix(la, vec3(0.36, 0.25, 0.13) * (0.85 + 0.4 * mid), dry);
|
|
2450
|
+
la = mix(la, vec3(0.1, 0.085, 0.07), mtn * 0.8);
|
|
2451
|
+
snow = smoothstep(0.17, 0.22, alt + 0.06 * fine + 0.04 * mid + 0.1 * abs(q.x));
|
|
2452
|
+
la = mix(la, vec3(0.8), snow);
|
|
2453
|
+
la *= max(0.85 + 0.5 * fine + 0.25 * mid, 0.2);
|
|
2454
|
+
ground = la;
|
|
2455
|
+
}
|
|
2456
|
+
float depth = max(-e, 0.0);
|
|
2457
|
+
vec3 ocean = mix(uTerrain, uTerrain * vec3(0.6, 2.4, 2.0) + vec3(0.0, 0.02, 0.02), exp(-depth * 60.0));
|
|
2458
|
+
ocean *= 0.9 + 0.4 * mid;
|
|
2459
|
+
vec3 albedo = mix(ocean, ground, land);
|
|
2460
|
+
|
|
2461
|
+
float ngl = dot(n, sun);
|
|
2462
|
+
float mu0 = max(dot(nb, sun), 0.0);
|
|
2463
|
+
float lsl = mu0 / (mu0 + ndv + 1e-3);
|
|
2464
|
+
float day = smoothstep(-0.03, 0.08, ngl);
|
|
2465
|
+
float brdf = mix(mu0, lsl, 0.25) * day;
|
|
2466
|
+
vec3 sunT = exp(-beta * H * chapman(X, 0.0, ngl));
|
|
2467
|
+
vec3 sky = uAtmosphere * uDensity * 0.05 * smoothstep(-0.3, 0.4, ngl);
|
|
2468
|
+
|
|
2469
|
+
mat3 cspin = spinX(-uTime * 0.0095);
|
|
2470
|
+
vec3 c = cspin * n;
|
|
2471
|
+
vec3 w = cloudWarp(c, fp);
|
|
2472
|
+
float cov = cloudCover(c, w, fp);
|
|
2473
|
+
vec3 sunTan = sun - ngl * n;
|
|
2474
|
+
sunTan = cspin * (sunTan * inversesqrt(max(dot(sunTan, sunTan), 1e-6)));
|
|
2475
|
+
float shade = 1.0;
|
|
2476
|
+
float relief = 1.0;
|
|
2477
|
+
if (ngl > -0.06) {
|
|
2478
|
+
float reach = CLOUD_H * sqrt(max(1.0 - ngl * ngl, 0.0)) / max(ngl, 0.05);
|
|
2479
|
+
shade = 1.0 - 0.75 * cloudCover(c + sunTan * reach, w, fp);
|
|
2480
|
+
relief = clamp(1.0 - 2.2 * (cloudCover(c + sunTan * 0.006, w, fp) - cov), 0.3, 1.25);
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
vec3 color = albedo * (SUN_I * 0.9 * sunT * brdf * shade + sky + 0.004);
|
|
2484
|
+
|
|
2485
|
+
if (land < 1.0) {
|
|
2486
|
+
vec3 v = normalize(vec3(0.0, 1.0 + ALT, 0.0) - n);
|
|
2487
|
+
float wind = fbm3(q * vec3(10.0, 10.0, 34.0) + 4.2, fp * 34.0, 5);
|
|
2488
|
+
float alpha = mix(0.1, 0.3, smoothstep(-0.18, 0.18, wind));
|
|
2489
|
+
float a2 = alpha * alpha;
|
|
2490
|
+
vec3 hv = normalize(sun + v);
|
|
2491
|
+
float nh = max(dot(n, hv), 0.0);
|
|
2492
|
+
float nl = max(ngl, 0.0);
|
|
2493
|
+
float nv = max(dot(n, v), 1e-3);
|
|
2494
|
+
float dd = nh * nh * (a2 - 1.0) + 1.0;
|
|
2495
|
+
float k = alpha * 0.5;
|
|
2496
|
+
float G = nl / (nl * (1.0 - k) + k) * nv / (nv * (1.0 - k) + k);
|
|
2497
|
+
float F = 0.02 + 0.98 * pow(1.0 - max(dot(v, hv), 0.0), 5.0);
|
|
2498
|
+
float spec = a2 / (PI * dd * dd) * G * F / (4.0 * nv) * day;
|
|
2499
|
+
float Fv = 0.02 + 0.98 * pow(1.0 - nv, 5.0);
|
|
2500
|
+
vec3 skyRefl = uAtmosphere * uDensity * 0.35 * smoothstep(-0.2, 0.35, ngl) * Fv;
|
|
2501
|
+
color += (SUN_I * 0.9 * sunT * spec * shade + skyRefl) * (1.0 - land);
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
float night = (1.0 - smoothstep(-0.08, -0.01, ngl)) * uCityLights;
|
|
2505
|
+
vec3 lights = vec3(0.0);
|
|
2506
|
+
if (night > 0.0 && land > 0.0) {
|
|
2507
|
+
float pop = fbm3(q * 4.3 + 13.0, fp * 4.3, 5) + 0.35 * fbm3(q * 17.0 + 2.0, fp * 17.0, 4);
|
|
2508
|
+
float P = smoothstep(-0.02, 0.2, pop + 0.12 * exp(-alt * 22.0) - 0.25 * dry - 0.3 * mtn - 0.5 * snow);
|
|
2509
|
+
lights = cityLights(q, fp, P) * land * night;
|
|
2510
|
+
color += lights;
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
float ngc = ngl + 0.055;
|
|
2514
|
+
vec3 sunTc = exp(-beta * H * chapman(X, CLOUD_H / H, ngl));
|
|
2515
|
+
float cBrdf = mix(max(ngc, 0.0), ngc / (abs(ngc) + ndv + 1e-3), 0.3) * smoothstep(0.0, 0.1, ngc) * relief;
|
|
2516
|
+
vec3 cloud = vec3(0.78) * (SUN_I * 0.9 * sunTc * max(cBrdf, 0.0) + sky * 2.0 + 0.004);
|
|
2517
|
+
cloud += lights * 0.12;
|
|
2518
|
+
return mix(color, cloud, cov);
|
|
2519
|
+
}
|
|
2520
|
+
`;
|
|
2521
|
+
var MAIN = `
|
|
2522
|
+
void main() {
|
|
2523
|
+
vec2 frag = gl_FragCoord.xy;
|
|
2524
|
+
vec2 uv = (frag - 0.5 * uResolution) / uResolution.y;
|
|
2525
|
+
vec2 ptr = uPointer / uResolution;
|
|
2526
|
+
float pixAngle = 1.0 / (uResolution.y * FL);
|
|
2527
|
+
|
|
2528
|
+
float D = 1.0 + ALT;
|
|
2529
|
+
float dip = acos(1.0 / D);
|
|
2530
|
+
float yaw = (ptr.x - 0.5) * 0.04;
|
|
2531
|
+
float pitch = dip + atan((0.5 - uHorizon) / FL) + (ptr.y - 0.5) * 0.015;
|
|
2532
|
+
vec3 ro = vec3(0.0, D, 0.0);
|
|
2533
|
+
vec3 fw = vec3(sin(yaw) * cos(pitch), -sin(pitch), -cos(yaw) * cos(pitch));
|
|
2534
|
+
vec3 right = normalize(cross(fw, vec3(0.0, 1.0, 0.0)));
|
|
2535
|
+
vec3 up = cross(right, fw);
|
|
2536
|
+
vec3 rd = normalize(uv.x * right + uv.y * up + FL * fw);
|
|
2537
|
+
|
|
2538
|
+
vec2 sunRef = mix(ptr, uSunPos, uSunFixed);
|
|
2539
|
+
float az = -0.85 + (sunRef.x - 0.5) * 1.2;
|
|
2540
|
+
float el = -0.24 - (sunRef.y - 0.5) * 0.3;
|
|
2541
|
+
vec3 sun = normalize(vec3(sin(az) * cos(el), sin(el), -cos(az) * cos(el)));
|
|
2542
|
+
|
|
2543
|
+
vec3 beta = uAtmosphere * 7.0 * uDensity + 1e-4;
|
|
2544
|
+
float X = 1.0 / H;
|
|
2545
|
+
|
|
2546
|
+
float b = dot(ro, rd);
|
|
2547
|
+
float tc = -b;
|
|
2548
|
+
float impact = sqrt(max(dot(ro, ro) - b * b, 0.0));
|
|
2549
|
+
float coverage = clamp(0.5 - (impact - 1.0) / (tc * pixAngle), 0.0, 1.0);
|
|
2550
|
+
float disc = b * b - dot(ro, ro) + 1.0;
|
|
2551
|
+
float tPlanet = disc > 0.0 ? -b - sqrt(disc) : tc;
|
|
2552
|
+
|
|
2553
|
+
float mu = dot(rd, sun);
|
|
2554
|
+
float sunAng = sqrt(max(2.0 * (1.0 - mu), 0.0));
|
|
2555
|
+
vec3 space = stars(rd, pixAngle);
|
|
2556
|
+
space += vec3(1.0, 0.96, 0.9) * 60.0 * smoothstep(SUN_R, SUN_R * 0.75, sunAng) * uSun;
|
|
2557
|
+
|
|
2558
|
+
vec3 background = space;
|
|
2559
|
+
if (coverage > 0.0) {
|
|
2560
|
+
vec3 n = normalize(ro + rd * tPlanet);
|
|
2561
|
+
float ndv = max(dot(n, -rd), 0.0);
|
|
2562
|
+
vec3 surface = shadeSurface(n, ndv, tPlanet * pixAngle, sun, beta, X);
|
|
2563
|
+
background = mix(space, surface, coverage);
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
vec3 inscatter = vec3(0.0);
|
|
2567
|
+
vec3 trans = vec3(1.0);
|
|
2568
|
+
float bA = b * b - dot(ro, ro) + RT * RT;
|
|
2569
|
+
if (bA > 0.0) {
|
|
2570
|
+
float t0 = max(-b - sqrt(bA), 0.0);
|
|
2571
|
+
float t1 = mix(-b + sqrt(bA), tPlanet, coverage);
|
|
2572
|
+
float tm = clamp(tc, t0, t1);
|
|
2573
|
+
float jitter = fract(52.9829189 * fract(dot(frag, vec2(0.06711056, 0.00583715))));
|
|
2574
|
+
float du = 1.0 / float(HALF);
|
|
2575
|
+
float od = 0.0;
|
|
2576
|
+
vec3 scat = vec3(0.0);
|
|
2577
|
+
for (int i = 0; i < 2 * HALF; i++) {
|
|
2578
|
+
bool near = i < HALF;
|
|
2579
|
+
float u = ((near ? float(HALF - 1 - i) : float(i - HALF)) + jitter) * du;
|
|
2580
|
+
float len = near ? tm - t0 : t1 - tm;
|
|
2581
|
+
float t = near ? tm - len * u * u : tm + len * u * u;
|
|
2582
|
+
vec3 p = ro + rd * t;
|
|
2583
|
+
float r = length(p);
|
|
2584
|
+
float h = max(r - 1.0, 0.0) / H;
|
|
2585
|
+
float dens = exp(-h) * 2.0 * u * len * du;
|
|
2586
|
+
float odSun = H * chapman(X, h, dot(p, sun) / r);
|
|
2587
|
+
scat += dens * exp(-beta * (od + 0.5 * dens + odSun));
|
|
2588
|
+
od += dens;
|
|
2589
|
+
}
|
|
2590
|
+
trans = exp(-beta * od);
|
|
2591
|
+
float g = 0.76;
|
|
2592
|
+
float phaseR = 3.0 / (16.0 * PI) * (1.0 + mu * mu);
|
|
2593
|
+
float phaseM = (1.0 - g * g) / (4.0 * PI * pow(1.0 + g * g - 2.0 * g * mu, 1.5));
|
|
2594
|
+
inscatter = SUN_I * 7.0 * beta * scat * mix(phaseR, phaseM, 0.4 - 0.25 * coverage);
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
vec3 color = inscatter + trans * background;
|
|
2598
|
+
|
|
2599
|
+
vec3 toCenter = -normalize(ro);
|
|
2600
|
+
float sunCos = dot(sun, toCenter);
|
|
2601
|
+
float clearance = acos(clamp(sunCos, -1.0, 1.0)) - asin(1.0 / D);
|
|
2602
|
+
float sunImpact = D * sqrt(max(1.0 - sunCos * sunCos, 0.0));
|
|
2603
|
+
float hs = max(sunImpact - 1.0, 0.0) / H;
|
|
2604
|
+
vec3 sunTrans = sunCos > 0.0 ? exp(-beta * H * 2.0 * sqrt(X + hs) * exp(-hs)) : vec3(1.0);
|
|
2605
|
+
float sunVis = smoothstep(-SUN_R, SUN_R * 2.0, clearance);
|
|
2606
|
+
vec2 sunUv = vec2(dot(sun, right), dot(sun, up)) / max(dot(sun, fw), 1e-3) * FL;
|
|
2607
|
+
vec2 sd = uv - sunUv;
|
|
2608
|
+
float glow = 0.9 * exp(-sunAng * 30.0) + 0.1 * exp(-sunAng * 7.0) + 0.015 * exp(-sunAng * 2.0);
|
|
2609
|
+
float streak = exp(-abs(sd.y) * 110.0) * exp(-abs(sd.x) * 3.0) * 0.08 * step(0.0, dot(sun, fw));
|
|
2610
|
+
color += vec3(1.0, 0.93, 0.85) * sunTrans * sunVis * (glow + streak) * uSun;
|
|
2611
|
+
|
|
2612
|
+
color *= 1.0 - 0.35 * dot(uv * vec2(0.6, 1.0), uv * vec2(0.6, 1.0));
|
|
2613
|
+
color = pow(aces(color * 0.9), vec3(1.0 / 2.2));
|
|
2614
|
+
color += (hash12(frag + fract(uTime)) - 0.5) / 255.0;
|
|
2615
|
+
|
|
2616
|
+
gl_FragColor = vec4(color, 1.0);
|
|
2617
|
+
}
|
|
2618
|
+
`;
|
|
2619
|
+
var SHADERS = {
|
|
2620
|
+
mars: COMMON + RELIEF + MARS_SURFACE + MAIN,
|
|
2621
|
+
jupiter: COMMON + JUPITER_SURFACE + MAIN,
|
|
2622
|
+
earth: COMMON + RELIEF + EARTH_SURFACE + MAIN
|
|
2623
|
+
};
|
|
2624
|
+
function Planet({
|
|
2625
|
+
children,
|
|
2626
|
+
className,
|
|
2627
|
+
planet = "mars",
|
|
2628
|
+
color,
|
|
2629
|
+
terrainColor,
|
|
2630
|
+
atmosphereColor,
|
|
2631
|
+
atmosphere,
|
|
2632
|
+
craters = 0.6,
|
|
2633
|
+
cityLights = true,
|
|
2634
|
+
stars = 0.6,
|
|
2635
|
+
horizon = 0.62,
|
|
2636
|
+
speed = 1,
|
|
2637
|
+
sun = false,
|
|
2638
|
+
sunPosition,
|
|
2639
|
+
interactive = true
|
|
2640
|
+
}) {
|
|
2641
|
+
const preset = PLANET_PRESETS[planet] ?? PLANET_PRESETS.mars;
|
|
2642
|
+
const surfaceColor = color ?? preset.color;
|
|
2643
|
+
const darkColor = terrainColor ?? preset.terrainColor;
|
|
2644
|
+
const airColor = atmosphereColor ?? preset.atmosphereColor;
|
|
2645
|
+
const density = atmosphere ?? preset.atmosphere;
|
|
2646
|
+
const canvasRef = useShaderCanvas({
|
|
2647
|
+
fragmentShader: SHADERS[planet] ?? SHADERS.mars,
|
|
2648
|
+
speed,
|
|
2649
|
+
interactive,
|
|
2650
|
+
onDraw: ({ gl, uniform }) => {
|
|
2651
|
+
const clamp01 = (value) => Math.min(1, Math.max(0, value));
|
|
2652
|
+
gl.uniform3fv(uniform("uSurface"), hexToLinearRgb(surfaceColor));
|
|
2653
|
+
gl.uniform3fv(uniform("uTerrain"), hexToLinearRgb(darkColor));
|
|
2654
|
+
gl.uniform3fv(uniform("uAtmosphere"), hexToLinearRgb(airColor));
|
|
2655
|
+
gl.uniform1f(uniform("uDensity"), clamp01(density));
|
|
2656
|
+
gl.uniform1f(uniform("uCraters"), clamp01(craters));
|
|
2657
|
+
gl.uniform1f(uniform("uCityLights"), cityLights ? 1 : 0);
|
|
2658
|
+
gl.uniform1f(uniform("uStars"), clamp01(stars));
|
|
2659
|
+
gl.uniform1f(uniform("uHorizon"), Math.min(0.95, Math.max(0.05, horizon)));
|
|
2660
|
+
gl.uniform1f(uniform("uSun"), sun ? 1 : 0);
|
|
2661
|
+
gl.uniform2f(uniform("uSunPos"), clamp01(sunPosition?.x ?? 0.5), clamp01(sunPosition?.y ?? 0.5));
|
|
2662
|
+
gl.uniform1f(uniform("uSunFixed"), sunPosition ? 1 : 0);
|
|
2663
|
+
}
|
|
2664
|
+
});
|
|
2665
|
+
return /* @__PURE__ */ jsxs(
|
|
2666
|
+
"div",
|
|
2667
|
+
{
|
|
2668
|
+
className: cn("elyri-planet", className),
|
|
2669
|
+
"data-planet": planet,
|
|
2670
|
+
style: {
|
|
2671
|
+
"--elyri-planet-color": surfaceColor,
|
|
2672
|
+
"--elyri-planet-atmosphere": airColor,
|
|
2673
|
+
"--elyri-planet-horizon": `${horizon * 100}%`
|
|
2674
|
+
},
|
|
2675
|
+
children: [
|
|
2676
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-planet__canvas", "aria-hidden": "true" }),
|
|
2677
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-planet__content", children })
|
|
2678
|
+
]
|
|
2679
|
+
}
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
var FRAGMENT_SHADER11 = `
|
|
2683
|
+
precision highp float;
|
|
2684
|
+
|
|
2685
|
+
uniform vec2 uResolution;
|
|
2686
|
+
uniform float uTime;
|
|
2687
|
+
uniform vec2 uPointer;
|
|
2688
|
+
uniform vec3 uBase;
|
|
2689
|
+
uniform vec3 uHighlight;
|
|
2690
|
+
uniform float uFolds;
|
|
2691
|
+
uniform float uScheme;
|
|
2692
|
+
|
|
2693
|
+
float hash(vec2 p) {
|
|
2694
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
2695
|
+
p += dot(p, p + 45.32);
|
|
2696
|
+
return fract(p.x * p.y);
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
float silk(vec2 p, float t) {
|
|
2700
|
+
vec2 q = p;
|
|
2701
|
+
q.x += 0.55 * sin(q.y * 1.3 + t * 0.3);
|
|
2702
|
+
q.y += 0.45 * sin(q.x * 1.1 - t * 0.25);
|
|
2703
|
+
q.x += 0.2 * sin(q.y * 2.3 - t * 0.2);
|
|
2704
|
+
return sin(q.x * 1.6 + q.y * 0.9 + t * 0.2) * 0.5
|
|
2705
|
+
+ sin(q.x * 0.7 - q.y * 1.9 - t * 0.15) * 0.35
|
|
2706
|
+
+ sin((q.x + q.y) * 2.7 + t * 0.35) * 0.12;
|
|
2707
|
+
}
|
|
2708
|
+
|
|
2709
|
+
vec3 aces(vec3 x) {
|
|
2710
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
void main() {
|
|
2714
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
2715
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
2716
|
+
vec2 p = frag / minRes * 2.6 * uFolds;
|
|
2717
|
+
float t = uTime;
|
|
2718
|
+
|
|
2719
|
+
float e = 0.01;
|
|
2720
|
+
float h = silk(p, t);
|
|
2721
|
+
vec2 grad = vec2(silk(p + vec2(e, 0.0), t) - silk(p - vec2(e, 0.0), t), silk(p + vec2(0.0, e), t) - silk(p - vec2(0.0, e), t)) / (2.0 * e);
|
|
2722
|
+
vec3 n = normalize(vec3(-grad * 0.55, 1.0));
|
|
2723
|
+
|
|
2724
|
+
vec3 V = vec3(0.0, 0.0, 1.0);
|
|
2725
|
+
vec3 toLight = vec3(uPointer - frag, minRes * 0.7);
|
|
2726
|
+
float dist = length(toLight);
|
|
2727
|
+
vec3 L = toLight / dist;
|
|
2728
|
+
vec3 H = normalize(L + V);
|
|
2729
|
+
float atten = 1.0 / (1.0 + 1.2 * pow(dist / minRes, 2.0));
|
|
2730
|
+
float NdotL = max(dot(n, L), 0.0);
|
|
2731
|
+
float NdotH = max(dot(n, H), 0.0);
|
|
2732
|
+
float NdotV = max(n.z, 0.0);
|
|
2733
|
+
float fres = pow(1.0 - NdotV, 3.0);
|
|
2734
|
+
|
|
2735
|
+
// \u8936\u76B1\u8C37\u5E95\u66F4\u6697
|
|
2736
|
+
float cavity = mix(0.35, 1.0, smoothstep(-1.0, 0.8, h));
|
|
2737
|
+
|
|
2738
|
+
vec3 color = uBase * (0.015 + 0.45 * NdotL * NdotL * atten) * cavity;
|
|
2739
|
+
color += mix(uBase, uHighlight, 0.5) * pow(NdotH, 14.0) * 0.45 * atten * cavity;
|
|
2740
|
+
color += uHighlight * pow(NdotH, 90.0) * 1.1 * atten;
|
|
2741
|
+
|
|
2742
|
+
// \u7EBF\u5F62\u706F\u5E26\u5728\u8936\u76B1\u4E0A\u5F62\u6210\u7684\u7F0E\u9762\u4EAE\u7EBF
|
|
2743
|
+
vec3 Rf = reflect(-V, n);
|
|
2744
|
+
vec2 toL = (uPointer - frag) / minRes;
|
|
2745
|
+
float a = -0.5 + 0.3 * sin(t * 0.13);
|
|
2746
|
+
vec2 dir = vec2(cos(a), sin(a));
|
|
2747
|
+
float s = dot(Rf.xy, dir) - dot(toL, dir) * 1.1;
|
|
2748
|
+
color += uHighlight * (exp(-s * s / 0.004) * 0.9 + exp(-s * s / 0.08) * 0.12) * (0.4 + atten) * cavity;
|
|
2749
|
+
color += mix(uBase, uHighlight, 0.3) * fres * 0.25 * cavity;
|
|
2750
|
+
|
|
2751
|
+
vec2 vc = frag / uResolution - 0.5;
|
|
2752
|
+
float vig = dot(vc, vc);
|
|
2753
|
+
|
|
2754
|
+
if (uScheme > 0.5) {
|
|
2755
|
+
// \u6D45\u8272\uFF1A\u5148\u8272\u8C03\u6620\u5C04\uFF0C\u518D\u505A\u4EAE\u6697\u955C\u50CF\uFF0C\u4FDD\u7559\u8272\u76F8 \u2014\u2014 \u6DF1\u5E95\u4EAE\u7EB9\u7FFB\u8F6C\u4E3A\u6D45\u5E95\u6DF1\u7EB9
|
|
2756
|
+
vec3 c = pow(aces(color * 1.1), vec3(1.0 / 2.2));
|
|
2757
|
+
float lum = dot(c, vec3(0.2126, 0.7152, 0.0722));
|
|
2758
|
+
color = clamp(c + (1.0 - 2.0 * lum), 0.0, 1.0) * (1.0 - vig * 0.35);
|
|
2759
|
+
} else {
|
|
2760
|
+
color *= 1.0 - vig * 1.2;
|
|
2761
|
+
color = pow(aces(color * 1.1), vec3(1.0 / 2.2));
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
color += (hash(frag + fract(t)) - 0.5) / 255.0;
|
|
2765
|
+
|
|
2766
|
+
gl_FragColor = vec4(color, 1.0);
|
|
2767
|
+
}
|
|
2768
|
+
`;
|
|
2769
|
+
function SilkWaves({
|
|
2770
|
+
children,
|
|
2771
|
+
className,
|
|
2772
|
+
color = "#9a6424",
|
|
2773
|
+
highlightColor = "#ffe3b0",
|
|
2774
|
+
folds = 1,
|
|
2775
|
+
speed = 1,
|
|
2776
|
+
interactive = true
|
|
2777
|
+
}) {
|
|
2778
|
+
const scheme = useColorScheme();
|
|
2779
|
+
const canvasRef = useShaderCanvas({
|
|
2780
|
+
fragmentShader: FRAGMENT_SHADER11,
|
|
2781
|
+
speed,
|
|
2782
|
+
interactive,
|
|
2783
|
+
onDraw: ({ gl, uniform }) => {
|
|
2784
|
+
gl.uniform3fv(uniform("uBase"), hexToLinearRgb(color));
|
|
2785
|
+
gl.uniform3fv(uniform("uHighlight"), hexToLinearRgb(highlightColor));
|
|
2786
|
+
gl.uniform1f(uniform("uFolds"), Math.max(0.2, folds));
|
|
2787
|
+
gl.uniform1f(uniform("uScheme"), scheme === "light" ? 1 : 0);
|
|
2788
|
+
}
|
|
2789
|
+
});
|
|
2790
|
+
return /* @__PURE__ */ jsxs(
|
|
2791
|
+
"div",
|
|
2792
|
+
{
|
|
2793
|
+
className: cn("elyri-silk-waves", className),
|
|
2794
|
+
"data-scheme": scheme,
|
|
2795
|
+
style: { "--elyri-silk-waves-color": color },
|
|
2796
|
+
children: [
|
|
2797
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-silk-waves__canvas", "aria-hidden": "true" }),
|
|
2798
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-silk-waves__content", children })
|
|
2799
|
+
]
|
|
2800
|
+
}
|
|
2801
|
+
);
|
|
2802
|
+
}
|
|
2803
|
+
var TRAIL = 24;
|
|
2804
|
+
var TRAIL_STEP_MS = 40;
|
|
2805
|
+
var TRAIL_FADE_S = 1.6;
|
|
2806
|
+
var trailData = new Float32Array(TRAIL * 3);
|
|
2807
|
+
var FRAGMENT_SHADER12 = `
|
|
2808
|
+
precision highp float;
|
|
2809
|
+
|
|
2810
|
+
#define TRAIL ${TRAIL}
|
|
2811
|
+
#define PI 3.14159265
|
|
2812
|
+
|
|
2813
|
+
uniform vec2 uResolution;
|
|
2814
|
+
uniform float uTime;
|
|
2815
|
+
uniform vec2 uPointer;
|
|
2816
|
+
uniform vec3 uBase;
|
|
2817
|
+
uniform vec3 uSheen;
|
|
2818
|
+
uniform float uFolds;
|
|
2819
|
+
uniform float uFuzz;
|
|
2820
|
+
uniform float uVignette;
|
|
2821
|
+
uniform vec3 uTrail[TRAIL];
|
|
2822
|
+
|
|
2823
|
+
float hash(vec2 p) {
|
|
2824
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
2825
|
+
p += dot(p, p + 45.32);
|
|
2826
|
+
return fract(p.x * p.y);
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
float noise(vec2 p) {
|
|
2830
|
+
vec2 i = floor(p);
|
|
2831
|
+
vec2 f = fract(p);
|
|
2832
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
2833
|
+
return mix(
|
|
2834
|
+
mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x),
|
|
2835
|
+
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x),
|
|
2836
|
+
u.y
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
// \u5706\u6DA6\u7684\u8936\u80CC + \u6536\u7D27\u7684\u6298\u75D5\uFF1A|sin| \u5728\u96F6\u70B9\u5904\u5F62\u6210 V \u5F62\u8C37\uFF0Ck \u63A7\u5236\u8C37\u5E95\u9510\u5EA6
|
|
2841
|
+
float fold(float s, float k) {
|
|
2842
|
+
return sqrt(s * s + k);
|
|
2843
|
+
}
|
|
2844
|
+
|
|
2845
|
+
float drape(vec2 p, float t) {
|
|
2846
|
+
// \u8936\u76B1\u6CBF x \u5206\u5E03\u3001\u987A y \u5782\u4E0B\uFF0C\u5E76\u968F\u9AD8\u5EA6\u7F13\u6162\u6446\u52A8
|
|
2847
|
+
float sway = 0.28 * sin(p.y * 0.5 + t * 0.3) + 0.12 * sin(p.y * 1.15 - t * 0.23 + p.x * 0.3);
|
|
2848
|
+
float x = p.x + sway;
|
|
2849
|
+
float s1 = sin(x * 1.35 + 0.6 * sin(x * 0.37 + t * 0.08));
|
|
2850
|
+
float s2 = sin(x * 2.7 + p.y * 0.28 - t * 0.18 + 1.3);
|
|
2851
|
+
float h = 0.62 * fold(s1, 0.012) + 0.26 * fold(s2, 0.03);
|
|
2852
|
+
// \u8936\u80CC\u4E0A\u7684\u659C\u5411\u7EC6\u76B1
|
|
2853
|
+
h += 0.05 * sin(p.x * 4.0 - p.y * 5.5 + t * 0.25) * s1 * s1;
|
|
2854
|
+
h += 0.25 * noise(p * 0.5 + vec2(t * 0.04, -t * 0.03));
|
|
2855
|
+
return h;
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
float pressAt(vec2 frag, float minRes) {
|
|
2859
|
+
float s = 0.0;
|
|
2860
|
+
for (int i = 0; i < TRAIL - 1; i++) {
|
|
2861
|
+
vec3 a = uTrail[i];
|
|
2862
|
+
vec3 b = uTrail[i + 1];
|
|
2863
|
+
float w = min(a.z, b.z);
|
|
2864
|
+
if (w <= 0.0) continue;
|
|
2865
|
+
vec2 pa = frag - a.xy;
|
|
2866
|
+
vec2 ba = b.xy - a.xy;
|
|
2867
|
+
float k = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-3), 0.0, 1.0);
|
|
2868
|
+
vec2 d = (pa - ba * k) / minRes;
|
|
2869
|
+
s = max(s, w * exp(-dot(d, d) * 600.0));
|
|
2870
|
+
}
|
|
2871
|
+
return s;
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
vec3 aces(vec3 x) {
|
|
2875
|
+
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
void main() {
|
|
2879
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
|
2880
|
+
float minRes = min(uResolution.x, uResolution.y);
|
|
2881
|
+
vec2 uv = frag / minRes;
|
|
2882
|
+
float t = uTime;
|
|
2883
|
+
|
|
2884
|
+
// \u659C\u5411\u7EA6 16\xB0 \u7684\u5782\u5760
|
|
2885
|
+
mat2 rot = mat2(0.96, 0.28, -0.28, 0.96);
|
|
2886
|
+
vec2 p = rot * uv * 2.2 * uFolds;
|
|
2887
|
+
|
|
2888
|
+
// \u4E2D\u5FC3\u5DEE\u5206\u6C42\u6CD5\u7EBF\uFF0C\u6B65\u957F\u8DB3\u591F\u5C0F\u4EE5\u4FDD\u7559\u6298\u75D5\u7684\u9510\u5229\u8FB9\u7F18
|
|
2889
|
+
float e = 0.004;
|
|
2890
|
+
vec2 ex = vec2(e, 0.0);
|
|
2891
|
+
vec2 ey = vec2(0.0, e);
|
|
2892
|
+
float h = drape(p, t);
|
|
2893
|
+
vec2 grad = vec2(drape(p + ex, t) - drape(p - ex, t), drape(p + ey, t) - drape(p - ey, t)) / (2.0 * e);
|
|
2894
|
+
// \u68AF\u5EA6\u8F6C\u56DE\u5C4F\u5E55\u5750\u6807\u7CFB
|
|
2895
|
+
grad = grad * rot;
|
|
2896
|
+
vec3 n = normalize(vec3(-grad * 0.75, 1.0));
|
|
2897
|
+
float NdotV = max(n.z, 1e-3);
|
|
2898
|
+
|
|
2899
|
+
float pressed = pressAt(frag, minRes);
|
|
2900
|
+
// \u7ED2\u6BDB\uFF1A\u50CF\u7D20\u7EA7\u7684\u7EA4\u7EF4\u4EAE\u70B9\uFF0C\u6CBF\u5782\u5760\u65B9\u5411\u7565\u62C9\u957F\uFF1B\u5927\u5757\u788E\u7ED2\u660E\u6697\u4E0E\u4E4B\u540C\u6B65\u53D7 uFuzz \u63A7\u5236
|
|
2901
|
+
vec2 fp = rot * frag;
|
|
2902
|
+
float fiber = 0.55 * hash(floor(fp)) + 0.45 * hash(floor(vec2(fp.x * 0.5, fp.y * 0.2)) + 31.0);
|
|
2903
|
+
float nap = 1.0 + (noise(p * 0.9 + 3.1) - 0.5) * 0.7 * uFuzz;
|
|
2904
|
+
float fuzz = mix(1.0, 0.45 + 1.1 * fiber, uFuzz);
|
|
2905
|
+
float ao = mix(0.4, 1.0, smoothstep(0.1, 0.8, h));
|
|
2906
|
+
|
|
2907
|
+
// \u4E3B\u5149\uFF1A\u5DE6\u4E0A\u65B9\u56FA\u5B9A\u67D4\u5149\uFF0C\u4FDD\u8BC1\u5F62\u4F53\u7A33\u5B9A\u53EF\u8BFB\uFF1B\u8F85\u5149\uFF1A\u8DDF\u968F\u6307\u9488\u7684\u70B9\u5149
|
|
2908
|
+
vec2 ptr = uPointer / minRes;
|
|
2909
|
+
vec2 toPtr = ptr - uv;
|
|
2910
|
+
vec3 lights[2];
|
|
2911
|
+
lights[0] = normalize(vec3(-0.45, -0.55, 0.7));
|
|
2912
|
+
lights[1] = normalize(vec3(toPtr, 0.55));
|
|
2913
|
+
float power[2];
|
|
2914
|
+
power[0] = 1.5;
|
|
2915
|
+
power[1] = 1.6 / (1.0 + 3.0 * dot(toPtr, toPtr));
|
|
2916
|
+
|
|
2917
|
+
// Charlie \u7ED2\u9762\u5206\u5E03\uFF1A\u6B63\u5BF9\u5149\u5904\u5438\u5149\uFF0C\u63A0\u5C04\u89D2\u6563\u5C04\u51FA\u67D4\u5149
|
|
2918
|
+
const float INV_A = 1.0 / 0.38;
|
|
2919
|
+
vec3 color = uBase * 0.03 * ao;
|
|
2920
|
+
for (int i = 0; i < 2; i++) {
|
|
2921
|
+
vec3 L = lights[i];
|
|
2922
|
+
vec3 H = normalize(L + vec3(0.0, 0.0, 1.0));
|
|
2923
|
+
float NdotL = max(dot(n, L), 0.0);
|
|
2924
|
+
float NdotH = max(dot(n, H), 0.0);
|
|
2925
|
+
float sin2 = max(1.0 - NdotH * NdotH, 0.0078125);
|
|
2926
|
+
float D = (2.0 + INV_A) * pow(sin2, INV_A * 0.5) / (2.0 * PI);
|
|
2927
|
+
float vis = 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV) + 1e-3);
|
|
2928
|
+
vec3 diffuse = uBase * (0.08 + 0.55 * NdotL) * ao;
|
|
2929
|
+
vec3 sheen = uSheen * D * vis * NdotL * nap * mix(fuzz, 1.0, pressed) * (1.0 - 0.85 * pressed);
|
|
2930
|
+
// \u538B\u5012\u7684\u7ED2\u6BDB\uFF1A\u987A\u6BDB\u65B9\u5411\u51FA\u73B0\u4E00\u70B9\u7F0E\u9762\u822C\u7684\u5149\u6CFD
|
|
2931
|
+
vec3 gloss = mix(uBase, uSheen, 0.6) * pow(NdotH, 40.0) * 0.35 * pressed;
|
|
2932
|
+
color += (diffuse * (1.0 - 0.3 * pressed) + sheen + gloss) * power[i];
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
vec2 vc = frag / uResolution - 0.5;
|
|
2936
|
+
color *= max(1.0 - dot(vc, vc) * 1.2 * uVignette, 0.0);
|
|
2937
|
+
color = pow(aces(color * 1.2), vec3(1.0 / 2.2));
|
|
2938
|
+
color += (hash(frag + fract(t)) - 0.5) / 255.0;
|
|
2939
|
+
|
|
2940
|
+
gl_FragColor = vec4(color, 1.0);
|
|
2941
|
+
}
|
|
2942
|
+
`;
|
|
2943
|
+
function Velvet({
|
|
2944
|
+
children,
|
|
2945
|
+
className,
|
|
2946
|
+
color = "#6a1230",
|
|
2947
|
+
sheenColor = "#ffb3c8",
|
|
2948
|
+
folds = 1,
|
|
2949
|
+
fuzz = 0.4,
|
|
2950
|
+
vignette = 0.5,
|
|
2951
|
+
speed = 1,
|
|
2952
|
+
interactive = true
|
|
2953
|
+
}) {
|
|
2954
|
+
const trailRef = useRef([]);
|
|
2955
|
+
const canvasRef = useShaderCanvas({
|
|
2956
|
+
fragmentShader: FRAGMENT_SHADER12,
|
|
2957
|
+
speed,
|
|
2958
|
+
interactive,
|
|
2959
|
+
onDraw: ({ gl, uniform, dpr }) => {
|
|
2960
|
+
const now = performance.now();
|
|
2961
|
+
trailData.fill(0);
|
|
2962
|
+
trailRef.current.forEach((point, i) => {
|
|
2963
|
+
const life = Math.max(0, 1 - (now - point.t) / 1e3 / TRAIL_FADE_S);
|
|
2964
|
+
trailData[i * 3] = point.x * dpr;
|
|
2965
|
+
trailData[i * 3 + 1] = point.y * dpr;
|
|
2966
|
+
trailData[i * 3 + 2] = life * life;
|
|
2967
|
+
});
|
|
2968
|
+
gl.uniform3fv(uniform("uBase"), hexToLinearRgb(color));
|
|
2969
|
+
gl.uniform3fv(uniform("uSheen"), hexToLinearRgb(sheenColor));
|
|
2970
|
+
gl.uniform1f(uniform("uFolds"), Math.max(0.2, folds));
|
|
2971
|
+
gl.uniform1f(uniform("uFuzz"), Math.min(1, Math.max(0, fuzz)));
|
|
2972
|
+
gl.uniform1f(uniform("uVignette"), Math.min(1, Math.max(0, vignette)));
|
|
2973
|
+
gl.uniform3fv(uniform("uTrail"), trailData);
|
|
2974
|
+
}
|
|
2975
|
+
});
|
|
2976
|
+
useEffect(() => {
|
|
2977
|
+
trailRef.current = [];
|
|
2978
|
+
if (!interactive) return;
|
|
2979
|
+
const handlePointerMove = (event) => {
|
|
2980
|
+
const rect = canvasRef.current?.getBoundingClientRect();
|
|
2981
|
+
if (!rect) return;
|
|
2982
|
+
const x = event.clientX - rect.left;
|
|
2983
|
+
const y = event.clientY - rect.top;
|
|
2984
|
+
const trail = trailRef.current;
|
|
2985
|
+
const now = performance.now();
|
|
2986
|
+
const last = trail[trail.length - 1];
|
|
2987
|
+
if (last && now - last.t < TRAIL_STEP_MS) {
|
|
2988
|
+
last.x = x;
|
|
2989
|
+
last.y = y;
|
|
2990
|
+
return;
|
|
2991
|
+
}
|
|
2992
|
+
trail.push({ x, y, t: now });
|
|
2993
|
+
if (trail.length > TRAIL) trail.shift();
|
|
2994
|
+
};
|
|
2995
|
+
window.addEventListener("pointermove", handlePointerMove, { passive: true });
|
|
2996
|
+
return () => window.removeEventListener("pointermove", handlePointerMove);
|
|
2997
|
+
}, [interactive, canvasRef]);
|
|
2998
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("elyri-velvet", className), style: { "--elyri-velvet-color": color }, children: [
|
|
2999
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-velvet__canvas", "aria-hidden": "true" }),
|
|
3000
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "elyri-velvet__content", children })
|
|
3001
|
+
] });
|
|
3002
|
+
}
|
|
3003
|
+
var DEFAULT_CHARACTERS = " .:-=+*#%@";
|
|
3004
|
+
var SCRAMBLE_WINDOW = 0.08;
|
|
3005
|
+
var FRAME_INTERVAL = 1e3 / 40;
|
|
3006
|
+
var SHIMMER_PERIOD = 4.5;
|
|
3007
|
+
var SHIMMER_WIDTH = 0.07;
|
|
3008
|
+
function AsciiImage({
|
|
3009
|
+
src,
|
|
3010
|
+
alt = "",
|
|
3011
|
+
className,
|
|
3012
|
+
columns = 100,
|
|
3013
|
+
characters = DEFAULT_CHARACTERS,
|
|
3014
|
+
colored = false,
|
|
3015
|
+
color,
|
|
3016
|
+
invert = false,
|
|
3017
|
+
animated = true,
|
|
3018
|
+
duration = 1200,
|
|
3019
|
+
shimmer = true,
|
|
3020
|
+
flicker = 0.01,
|
|
3021
|
+
interactive = true,
|
|
3022
|
+
radius = 90
|
|
3023
|
+
}) {
|
|
3024
|
+
const rootRef = useRef(null);
|
|
3025
|
+
const canvasRef = useRef(null);
|
|
3026
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3027
|
+
const scheme = useColorScheme();
|
|
3028
|
+
const [image, setImage] = useState(null);
|
|
3029
|
+
const [failed, setFailed] = useState(false);
|
|
3030
|
+
const [width, setWidth] = useState(0);
|
|
3031
|
+
const [inView, setInView] = useState(false);
|
|
3032
|
+
const playedRef = useRef(false);
|
|
3033
|
+
useEffect(() => {
|
|
3034
|
+
let disposed = false;
|
|
3035
|
+
const img = new Image();
|
|
3036
|
+
img.crossOrigin = "anonymous";
|
|
3037
|
+
img.decoding = "async";
|
|
3038
|
+
img.onload = () => {
|
|
3039
|
+
if (disposed) return;
|
|
3040
|
+
const probe = document.createElement("canvas").getContext("2d");
|
|
3041
|
+
try {
|
|
3042
|
+
probe?.drawImage(img, 0, 0, 1, 1);
|
|
3043
|
+
probe?.getImageData(0, 0, 1, 1);
|
|
3044
|
+
} catch {
|
|
3045
|
+
setFailed(true);
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
setFailed(false);
|
|
3049
|
+
setImage(img);
|
|
3050
|
+
};
|
|
3051
|
+
img.onerror = () => {
|
|
3052
|
+
if (!disposed) setFailed(true);
|
|
3053
|
+
};
|
|
3054
|
+
img.src = src;
|
|
3055
|
+
return () => {
|
|
3056
|
+
disposed = true;
|
|
3057
|
+
};
|
|
3058
|
+
}, [src]);
|
|
3059
|
+
useEffect(() => {
|
|
3060
|
+
const root = rootRef.current;
|
|
3061
|
+
if (!root) return;
|
|
3062
|
+
const resize = new ResizeObserver(([entry]) => setWidth(Math.round(entry.contentRect.width)));
|
|
3063
|
+
const intersection = new IntersectionObserver(([entry]) => setInView(entry.isIntersecting));
|
|
3064
|
+
resize.observe(root);
|
|
3065
|
+
intersection.observe(root);
|
|
3066
|
+
return () => {
|
|
3067
|
+
resize.disconnect();
|
|
3068
|
+
intersection.disconnect();
|
|
3069
|
+
};
|
|
3070
|
+
}, []);
|
|
3071
|
+
useEffect(() => {
|
|
3072
|
+
const root = rootRef.current;
|
|
3073
|
+
const canvas = canvasRef.current;
|
|
3074
|
+
const ctx = canvas?.getContext("2d");
|
|
3075
|
+
if (!root || !canvas || !ctx || !image || !width || !image.naturalWidth) return;
|
|
3076
|
+
const style2 = getComputedStyle(root);
|
|
3077
|
+
const ramp = Array.from(characters || DEFAULT_CHARACTERS);
|
|
3078
|
+
const cols = Math.min(400, Math.max(8, Math.round(columns)));
|
|
3079
|
+
const font = (size) => `${style2.fontWeight} ${size}px ${style2.fontFamily}`;
|
|
3080
|
+
ctx.font = font(100);
|
|
3081
|
+
const cellW = width / cols;
|
|
3082
|
+
const fontSize = cellW * 100 / ctx.measureText("M").width;
|
|
3083
|
+
const cellH = fontSize;
|
|
3084
|
+
const rows = Math.max(1, Math.round(cols * image.naturalHeight / image.naturalWidth * (cellW / cellH)));
|
|
3085
|
+
const height = rows * cellH;
|
|
3086
|
+
const sampler = document.createElement("canvas");
|
|
3087
|
+
sampler.width = cols;
|
|
3088
|
+
sampler.height = rows;
|
|
3089
|
+
const sctx = sampler.getContext("2d", { willReadFrequently: true });
|
|
3090
|
+
if (!sctx) return;
|
|
3091
|
+
sctx.imageSmoothingQuality = "high";
|
|
3092
|
+
sctx.drawImage(image, 0, 0, cols, rows);
|
|
3093
|
+
let data;
|
|
3094
|
+
try {
|
|
3095
|
+
data = sctx.getImageData(0, 0, cols, rows).data;
|
|
3096
|
+
} catch {
|
|
3097
|
+
return;
|
|
3098
|
+
}
|
|
3099
|
+
const light = scheme === "light";
|
|
3100
|
+
const flip = light !== invert;
|
|
3101
|
+
const cells = [];
|
|
3102
|
+
for (let i = 0; i < cols * rows; i++) {
|
|
3103
|
+
const r = data[i * 4];
|
|
3104
|
+
const g = data[i * 4 + 1];
|
|
3105
|
+
const b = data[i * 4 + 2];
|
|
3106
|
+
const a = data[i * 4 + 3] / 255;
|
|
3107
|
+
const lum = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
|
|
3108
|
+
const glyph = Math.min(ramp.length - 1, Math.floor((flip ? 1 - lum : lum) * a * ramp.length));
|
|
3109
|
+
if (!ramp[glyph].trim()) continue;
|
|
3110
|
+
const col = i % cols;
|
|
3111
|
+
const row = Math.floor(i / cols);
|
|
3112
|
+
cells.push({
|
|
3113
|
+
x: col * cellW,
|
|
3114
|
+
y: row * cellH,
|
|
3115
|
+
glyph,
|
|
3116
|
+
r,
|
|
3117
|
+
g,
|
|
3118
|
+
b,
|
|
3119
|
+
// 自上而下显现,并带少许随机错落
|
|
3120
|
+
threshold: row / rows * (1 - SCRAMBLE_WINDOW - 0.2) + Math.random() * 0.2,
|
|
3121
|
+
diagonal: (col / cols + row / rows) / 2
|
|
3122
|
+
});
|
|
3123
|
+
}
|
|
3124
|
+
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
3125
|
+
canvas.width = Math.round(width * dpr);
|
|
3126
|
+
canvas.height = Math.round(height * dpr);
|
|
3127
|
+
canvas.style.height = `${height}px`;
|
|
3128
|
+
const noise = ramp.filter((char) => char.trim());
|
|
3129
|
+
const fill = style2.getPropertyValue("--elyri-ascii-color").trim() || style2.color;
|
|
3130
|
+
const highlight = light ? 0 : 255;
|
|
3131
|
+
const lift = Math.min(3, ramp.length - 1);
|
|
3132
|
+
const flickerRate = Math.min(1, Math.max(0, flicker));
|
|
3133
|
+
const reach = Math.max(1, radius);
|
|
3134
|
+
const motion = !prefersReducedMotion;
|
|
3135
|
+
const lens = motion && interactive;
|
|
3136
|
+
const pointer = { x: 0, y: 0, strength: 0, target: 0, tx: 0, ty: 0 };
|
|
3137
|
+
const draw = (progress, time) => {
|
|
3138
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
3139
|
+
ctx.clearRect(0, 0, width, height);
|
|
3140
|
+
ctx.font = font(fontSize);
|
|
3141
|
+
ctx.textBaseline = "top";
|
|
3142
|
+
ctx.fillStyle = fill;
|
|
3143
|
+
const band = motion && shimmer ? time / SHIMMER_PERIOD % 1 * 1.8 - 0.4 : -10;
|
|
3144
|
+
for (const cell of cells) {
|
|
3145
|
+
let char = ramp[cell.glyph];
|
|
3146
|
+
if (progress < 1) {
|
|
3147
|
+
if (progress < cell.threshold) continue;
|
|
3148
|
+
if (progress < cell.threshold + SCRAMBLE_WINDOW) char = noise[Math.floor(Math.random() * noise.length)];
|
|
3149
|
+
}
|
|
3150
|
+
const offset = (cell.diagonal - band) / SHIMMER_WIDTH;
|
|
3151
|
+
let boost = offset > -3 && offset < 3 ? Math.exp(-offset * offset) : 0;
|
|
3152
|
+
let x = cell.x;
|
|
3153
|
+
let y = cell.y;
|
|
3154
|
+
if (pointer.strength > 0.01) {
|
|
3155
|
+
const dx = x + cellW / 2 - pointer.x;
|
|
3156
|
+
const dy = y + cellH / 2 - pointer.y;
|
|
3157
|
+
const d = Math.hypot(dx, dy);
|
|
3158
|
+
if (d < reach) {
|
|
3159
|
+
const t = (1 - d / reach) * pointer.strength;
|
|
3160
|
+
const push = t * t * cellW * 2.2;
|
|
3161
|
+
if (d > 0.01) {
|
|
3162
|
+
x += dx / d * push;
|
|
3163
|
+
y += dy / d * push;
|
|
3164
|
+
}
|
|
3165
|
+
boost = Math.max(boost, t);
|
|
3166
|
+
if (Math.random() < t * 0.35) char = noise[Math.floor(Math.random() * noise.length)];
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
if (boost > 0.05) char = ramp[Math.min(ramp.length - 1, cell.glyph + Math.round(boost * lift))];
|
|
3170
|
+
if (flickerRate && Math.random() < flickerRate) char = noise[Math.floor(Math.random() * noise.length)];
|
|
3171
|
+
ctx.globalAlpha = 0.82 + 0.18 * boost;
|
|
3172
|
+
if (colored) {
|
|
3173
|
+
const mix = boost * 0.6;
|
|
3174
|
+
ctx.fillStyle = `rgb(${cell.r + (highlight - cell.r) * mix},${cell.g + (highlight - cell.g) * mix},${cell.b + (highlight - cell.b) * mix})`;
|
|
3175
|
+
}
|
|
3176
|
+
ctx.fillText(char, x, y);
|
|
3177
|
+
}
|
|
3178
|
+
ctx.globalAlpha = 1;
|
|
3179
|
+
};
|
|
3180
|
+
if (!motion) {
|
|
3181
|
+
draw(1, 0);
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
3184
|
+
const reveal = animated && !playedRef.current;
|
|
3185
|
+
if (!inView) {
|
|
3186
|
+
draw(reveal ? 0 : 1, 0);
|
|
3187
|
+
return;
|
|
3188
|
+
}
|
|
3189
|
+
const continuous = shimmer || flickerRate > 0 || lens;
|
|
3190
|
+
const start = performance.now();
|
|
3191
|
+
let frame = 0;
|
|
3192
|
+
let last = 0;
|
|
3193
|
+
const tick = (now) => {
|
|
3194
|
+
frame = requestAnimationFrame(tick);
|
|
3195
|
+
if (now - last < FRAME_INTERVAL) return;
|
|
3196
|
+
const dt = last ? Math.min((now - last) / 1e3, 0.1) : 0;
|
|
3197
|
+
last = now;
|
|
3198
|
+
const progress = reveal ? Math.min(1, (now - start) / Math.max(1, duration)) : 1;
|
|
3199
|
+
if (progress >= 1) playedRef.current = true;
|
|
3200
|
+
const ease = 1 - Math.exp(-dt * 12);
|
|
3201
|
+
pointer.x += (pointer.tx - pointer.x) * ease;
|
|
3202
|
+
pointer.y += (pointer.ty - pointer.y) * ease;
|
|
3203
|
+
pointer.strength += (pointer.target - pointer.strength) * (1 - Math.exp(-dt * 6));
|
|
3204
|
+
draw(progress, (now - start) / 1e3);
|
|
3205
|
+
if (!continuous && progress >= 1) cancelAnimationFrame(frame);
|
|
3206
|
+
};
|
|
3207
|
+
frame = requestAnimationFrame(tick);
|
|
3208
|
+
const handlePointerMove = (event) => {
|
|
3209
|
+
const rect = canvas.getBoundingClientRect();
|
|
3210
|
+
const x = event.clientX - rect.left;
|
|
3211
|
+
const y = event.clientY - rect.top;
|
|
3212
|
+
const inside = x >= -reach && y >= -reach && x <= rect.width + reach && y <= rect.height + reach;
|
|
3213
|
+
if (inside && pointer.target === 0 && pointer.strength < 0.01) {
|
|
3214
|
+
pointer.x = x;
|
|
3215
|
+
pointer.y = y;
|
|
3216
|
+
}
|
|
3217
|
+
pointer.tx = x;
|
|
3218
|
+
pointer.ty = y;
|
|
3219
|
+
pointer.target = inside ? 1 : 0;
|
|
3220
|
+
};
|
|
3221
|
+
const handlePointerLeave = () => {
|
|
3222
|
+
pointer.target = 0;
|
|
3223
|
+
};
|
|
3224
|
+
if (lens) {
|
|
3225
|
+
window.addEventListener("pointermove", handlePointerMove, { passive: true });
|
|
3226
|
+
document.documentElement.addEventListener("pointerleave", handlePointerLeave);
|
|
3227
|
+
}
|
|
3228
|
+
return () => {
|
|
3229
|
+
cancelAnimationFrame(frame);
|
|
3230
|
+
window.removeEventListener("pointermove", handlePointerMove);
|
|
3231
|
+
document.documentElement.removeEventListener("pointerleave", handlePointerLeave);
|
|
3232
|
+
};
|
|
3233
|
+
}, [
|
|
3234
|
+
image,
|
|
3235
|
+
width,
|
|
3236
|
+
columns,
|
|
3237
|
+
characters,
|
|
3238
|
+
colored,
|
|
3239
|
+
color,
|
|
3240
|
+
invert,
|
|
3241
|
+
scheme,
|
|
3242
|
+
animated,
|
|
3243
|
+
duration,
|
|
3244
|
+
shimmer,
|
|
3245
|
+
flicker,
|
|
3246
|
+
interactive,
|
|
3247
|
+
radius,
|
|
3248
|
+
inView,
|
|
3249
|
+
prefersReducedMotion
|
|
3250
|
+
]);
|
|
3251
|
+
const style = color ? { "--elyri-ascii-color": color } : void 0;
|
|
3252
|
+
return /* @__PURE__ */ jsx("div", { ref: rootRef, className: cn("elyri-ascii-image", className), style, children: failed ? /* @__PURE__ */ jsx("img", { className: "elyri-ascii-image__fallback", src, alt }) : /* @__PURE__ */ jsx(
|
|
3253
|
+
"canvas",
|
|
3254
|
+
{
|
|
3255
|
+
ref: canvasRef,
|
|
3256
|
+
className: "elyri-ascii-image__canvas",
|
|
3257
|
+
role: alt ? "img" : void 0,
|
|
3258
|
+
"aria-label": alt || void 0,
|
|
3259
|
+
"aria-hidden": alt ? void 0 : true
|
|
3260
|
+
}
|
|
3261
|
+
) });
|
|
3262
|
+
}
|
|
3263
|
+
function GradientText({ children, className, colors, animated = true, speed = 0.5 }) {
|
|
3264
|
+
const style = {
|
|
3265
|
+
...colors?.length ? { "--elyri-gradient-colors": colors.join(", ") } : null,
|
|
3266
|
+
"--elyri-gradient-speed": speed
|
|
3267
|
+
};
|
|
3268
|
+
return /* @__PURE__ */ jsx("span", { className: cn("elyri-gradient-text", animated && "elyri-gradient-text--animated", className), style, children });
|
|
3269
|
+
}
|
|
3270
|
+
function Marquee({
|
|
3271
|
+
children,
|
|
3272
|
+
className,
|
|
3273
|
+
direction = "left",
|
|
3274
|
+
duration = 20,
|
|
3275
|
+
repeat = 2,
|
|
3276
|
+
gap = 0,
|
|
3277
|
+
infinite = true,
|
|
3278
|
+
pauseOnHover = true
|
|
3279
|
+
}) {
|
|
3280
|
+
const rootRef = useRef(null);
|
|
3281
|
+
const trackRef = useRef(null);
|
|
3282
|
+
const [paused, setPaused] = useState(false);
|
|
3283
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3284
|
+
const minCopies = Math.max(2, Math.floor(repeat));
|
|
3285
|
+
const [copies, setCopies] = useState(minCopies);
|
|
3286
|
+
const vertical = direction === "up" || direction === "down";
|
|
3287
|
+
const reverse = direction === "right" || direction === "down";
|
|
3288
|
+
useEffect(() => {
|
|
3289
|
+
const root = rootRef.current;
|
|
3290
|
+
const track = trackRef.current;
|
|
3291
|
+
if (!root || !track) return;
|
|
3292
|
+
const measure = () => {
|
|
3293
|
+
const first = track.firstElementChild;
|
|
3294
|
+
if (!first) return;
|
|
3295
|
+
const copySize = vertical ? first.offsetHeight : first.offsetWidth;
|
|
3296
|
+
const rootSize = vertical ? root.clientHeight : root.clientWidth;
|
|
3297
|
+
const trackSize = vertical ? track.offsetHeight : track.offsetWidth;
|
|
3298
|
+
if (!copySize) return;
|
|
3299
|
+
if (vertical && rootSize >= trackSize) {
|
|
3300
|
+
setCopies(minCopies);
|
|
3301
|
+
return;
|
|
3302
|
+
}
|
|
3303
|
+
setCopies(Math.max(minCopies, Math.ceil((rootSize + copySize) / copySize)));
|
|
3304
|
+
};
|
|
3305
|
+
const observer = new ResizeObserver(measure);
|
|
3306
|
+
observer.observe(root);
|
|
3307
|
+
if (track.firstElementChild) observer.observe(track.firstElementChild);
|
|
3308
|
+
return () => observer.disconnect();
|
|
3309
|
+
}, [vertical, minCopies]);
|
|
3310
|
+
useEffect(() => {
|
|
3311
|
+
const node = rootRef.current;
|
|
3312
|
+
if (!node || prefersReducedMotion) return;
|
|
3313
|
+
let inView = true;
|
|
3314
|
+
const sync = () => setPaused(!inView || document.hidden);
|
|
3315
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
3316
|
+
inView = entry.isIntersecting;
|
|
3317
|
+
sync();
|
|
3318
|
+
});
|
|
3319
|
+
observer.observe(node);
|
|
3320
|
+
document.addEventListener("visibilitychange", sync);
|
|
3321
|
+
return () => {
|
|
3322
|
+
observer.disconnect();
|
|
3323
|
+
document.removeEventListener("visibilitychange", sync);
|
|
3324
|
+
};
|
|
3325
|
+
}, [prefersReducedMotion]);
|
|
3326
|
+
return /* @__PURE__ */ jsx(
|
|
3327
|
+
"div",
|
|
3328
|
+
{
|
|
3329
|
+
ref: rootRef,
|
|
3330
|
+
className: cn(
|
|
3331
|
+
"elyri-marquee",
|
|
3332
|
+
vertical && "elyri-marquee--vertical",
|
|
3333
|
+
reverse && "elyri-marquee--reverse",
|
|
3334
|
+
!infinite && "elyri-marquee--once",
|
|
3335
|
+
paused && "elyri-marquee--paused",
|
|
3336
|
+
pauseOnHover && "elyri-marquee--pausable",
|
|
3337
|
+
prefersReducedMotion && "elyri-marquee--static",
|
|
3338
|
+
className
|
|
3339
|
+
),
|
|
3340
|
+
style: {
|
|
3341
|
+
"--elyri-marquee-duration": `${duration}s`,
|
|
3342
|
+
"--elyri-marquee-repeat": copies,
|
|
3343
|
+
"--elyri-marquee-gap": `${gap}px`
|
|
3344
|
+
},
|
|
3345
|
+
children: /* @__PURE__ */ jsx("div", { ref: trackRef, className: "elyri-marquee__track", children: Array.from({ length: copies }, (_, index) => (
|
|
3346
|
+
// 复制份仅用于视觉衔接,对辅助技术隐藏,避免重复朗读
|
|
3347
|
+
/* @__PURE__ */ jsx("div", { className: "elyri-marquee__copy", "aria-hidden": index > 0 ? true : void 0, children }, index)
|
|
3348
|
+
)) })
|
|
3349
|
+
}
|
|
3350
|
+
);
|
|
3351
|
+
}
|
|
3352
|
+
var FRICTION = 0.86;
|
|
3353
|
+
function ParticleText({
|
|
3354
|
+
children,
|
|
3355
|
+
className,
|
|
3356
|
+
color,
|
|
3357
|
+
particleSize = 2,
|
|
3358
|
+
gap = 3,
|
|
3359
|
+
radius = 80,
|
|
3360
|
+
force = 1,
|
|
3361
|
+
assemble = true
|
|
3362
|
+
}) {
|
|
3363
|
+
const rootRef = useRef(null);
|
|
3364
|
+
const canvasRef = useRef(null);
|
|
3365
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3366
|
+
const scheme = useColorScheme();
|
|
3367
|
+
const [ready, setReady] = useState(false);
|
|
3368
|
+
const particlesRef = useRef([]);
|
|
3369
|
+
const padRef = useRef(0);
|
|
3370
|
+
const optionsRef = useRef({ particleSize, force });
|
|
3371
|
+
const wakeRef = useRef(null);
|
|
3372
|
+
useEffect(() => {
|
|
3373
|
+
optionsRef.current = { particleSize, force };
|
|
3374
|
+
wakeRef.current?.();
|
|
3375
|
+
}, [particleSize, force, color, scheme]);
|
|
3376
|
+
useEffect(() => {
|
|
3377
|
+
const root = rootRef.current;
|
|
3378
|
+
const canvas = canvasRef.current;
|
|
3379
|
+
const ctx = canvas?.getContext("2d");
|
|
3380
|
+
if (!root || !canvas || !ctx) return;
|
|
3381
|
+
const style2 = getComputedStyle(root);
|
|
3382
|
+
const interactive = radius > 0 && !prefersReducedMotion;
|
|
3383
|
+
const pointer = { x: 0, y: 0, active: false };
|
|
3384
|
+
let width = 0;
|
|
3385
|
+
let height = 0;
|
|
3386
|
+
let dpr = 1;
|
|
3387
|
+
let visible = false;
|
|
3388
|
+
let running = false;
|
|
3389
|
+
let frame = 0;
|
|
3390
|
+
let buildFrame = 0;
|
|
3391
|
+
let last = 0;
|
|
3392
|
+
let lastColor = "";
|
|
3393
|
+
const build = () => {
|
|
3394
|
+
const w = root.offsetWidth;
|
|
3395
|
+
const h = root.offsetHeight;
|
|
3396
|
+
if (!w || !h) return;
|
|
3397
|
+
const pad = Math.ceil(Math.max(radius, 0) + 16);
|
|
3398
|
+
dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
3399
|
+
width = w + pad * 2;
|
|
3400
|
+
height = h + pad * 2;
|
|
3401
|
+
canvas.width = Math.round(width * dpr);
|
|
3402
|
+
canvas.height = Math.round(height * dpr);
|
|
3403
|
+
canvas.style.width = `${width}px`;
|
|
3404
|
+
canvas.style.height = `${height}px`;
|
|
3405
|
+
canvas.style.left = canvas.style.top = `${-pad}px`;
|
|
3406
|
+
const sampler = document.createElement("canvas");
|
|
3407
|
+
sampler.width = Math.ceil(w);
|
|
3408
|
+
sampler.height = Math.ceil(h);
|
|
3409
|
+
const sctx = sampler.getContext("2d", { willReadFrequently: true });
|
|
3410
|
+
if (!sctx) return;
|
|
3411
|
+
sctx.font = `${style2.fontStyle} ${style2.fontWeight} ${style2.fontSize} ${style2.fontFamily}`;
|
|
3412
|
+
if ("letterSpacing" in sctx) sctx.letterSpacing = style2.letterSpacing === "normal" ? "0px" : style2.letterSpacing;
|
|
3413
|
+
const align = style2.textAlign;
|
|
3414
|
+
const alignRight = align === "right" || align === "end";
|
|
3415
|
+
sctx.textAlign = align === "center" ? "center" : alignRight ? "right" : "left";
|
|
3416
|
+
const originX = align === "center" ? w / 2 : alignRight ? w : 0;
|
|
3417
|
+
const lines = children.split("\n");
|
|
3418
|
+
const lineHeight = h / lines.length;
|
|
3419
|
+
lines.forEach((line, index) => {
|
|
3420
|
+
const m = sctx.measureText(line);
|
|
3421
|
+
const ascent = m.fontBoundingBoxAscent ?? m.actualBoundingBoxAscent;
|
|
3422
|
+
const descent = m.fontBoundingBoxDescent ?? m.actualBoundingBoxDescent;
|
|
3423
|
+
sctx.fillText(line, originX, index * lineHeight + (lineHeight - ascent - descent) / 2 + ascent);
|
|
3424
|
+
});
|
|
3425
|
+
const data = sctx.getImageData(0, 0, sampler.width, sampler.height).data;
|
|
3426
|
+
const step = Math.max(1, gap);
|
|
3427
|
+
const targets = [];
|
|
3428
|
+
for (let y = step / 2; y < sampler.height; y += step) {
|
|
3429
|
+
for (let x = step / 2; x < sampler.width; x += step) {
|
|
3430
|
+
if (data[(Math.floor(y) * sampler.width + Math.floor(x)) * 4 + 3] > 128) targets.push([x + pad, y + pad]);
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
for (let i = targets.length - 1; i > 0; i--) {
|
|
3434
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
3435
|
+
[targets[i], targets[j]] = [targets[j], targets[i]];
|
|
3436
|
+
}
|
|
3437
|
+
const prev = particlesRef.current;
|
|
3438
|
+
const shift = pad - padRef.current;
|
|
3439
|
+
const scatter = assemble && !prefersReducedMotion && prev.length === 0;
|
|
3440
|
+
particlesRef.current = targets.map(([tx, ty], index) => {
|
|
3441
|
+
const k = 0.03 + Math.random() * 0.04;
|
|
3442
|
+
if (prefersReducedMotion) return { x: tx, y: ty, vx: 0, vy: 0, tx, ty, k };
|
|
3443
|
+
const source = prev[index] ?? (prev.length ? prev[Math.floor(Math.random() * prev.length)] : null);
|
|
3444
|
+
if (source) return { x: source.x + shift, y: source.y + shift, vx: source.vx, vy: source.vy, tx, ty, k };
|
|
3445
|
+
if (scatter) return { x: Math.random() * width, y: Math.random() * height, vx: 0, vy: 0, tx, ty, k };
|
|
3446
|
+
return { x: tx, y: ty, vx: 0, vy: 0, tx, ty, k };
|
|
3447
|
+
});
|
|
3448
|
+
padRef.current = pad;
|
|
3449
|
+
lastColor = "";
|
|
3450
|
+
setReady(true);
|
|
3451
|
+
wake();
|
|
3452
|
+
};
|
|
3453
|
+
const tick = (now) => {
|
|
3454
|
+
const dt = Math.min((now - last) / 16.667, 3);
|
|
3455
|
+
last = now;
|
|
3456
|
+
const { particleSize: size, force: strength } = optionsRef.current;
|
|
3457
|
+
const damping = Math.pow(FRICTION, dt);
|
|
3458
|
+
const r2 = radius * radius;
|
|
3459
|
+
const push = Math.max(0, strength) * 3 * dt;
|
|
3460
|
+
let active = false;
|
|
3461
|
+
for (const p of particlesRef.current) {
|
|
3462
|
+
p.vx += (p.tx - p.x) * p.k * dt;
|
|
3463
|
+
p.vy += (p.ty - p.y) * p.k * dt;
|
|
3464
|
+
if (pointer.active) {
|
|
3465
|
+
const dx = p.x - pointer.x;
|
|
3466
|
+
const dy = p.y - pointer.y;
|
|
3467
|
+
const d2 = dx * dx + dy * dy;
|
|
3468
|
+
if (d2 < r2 && d2 > 0.01) {
|
|
3469
|
+
const d = Math.sqrt(d2);
|
|
3470
|
+
const f = (1 - d / radius) * push;
|
|
3471
|
+
p.vx += dx / d * f;
|
|
3472
|
+
p.vy += dy / d * f;
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3475
|
+
p.vx *= damping;
|
|
3476
|
+
p.vy *= damping;
|
|
3477
|
+
p.x += p.vx * dt;
|
|
3478
|
+
p.y += p.vy * dt;
|
|
3479
|
+
if (!active && Math.abs(p.vx) + Math.abs(p.vy) + Math.abs(p.tx - p.x) + Math.abs(p.ty - p.y) > 0.05) {
|
|
3480
|
+
active = true;
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
const fill = style2.getPropertyValue("--elyri-particle-color").trim() || style2.color;
|
|
3484
|
+
if (fill !== lastColor) {
|
|
3485
|
+
lastColor = fill;
|
|
3486
|
+
active = true;
|
|
3487
|
+
}
|
|
3488
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
3489
|
+
ctx.clearRect(0, 0, width, height);
|
|
3490
|
+
ctx.fillStyle = fill;
|
|
3491
|
+
const half = size / 2;
|
|
3492
|
+
for (const p of particlesRef.current) ctx.fillRect(p.x - half, p.y - half, size, size);
|
|
3493
|
+
if (visible && (active || pointer.active)) {
|
|
3494
|
+
frame = requestAnimationFrame(tick);
|
|
3495
|
+
} else {
|
|
3496
|
+
running = false;
|
|
3497
|
+
}
|
|
3498
|
+
};
|
|
3499
|
+
function wake() {
|
|
3500
|
+
if (running || !visible) return;
|
|
3501
|
+
running = true;
|
|
3502
|
+
last = performance.now();
|
|
3503
|
+
frame = requestAnimationFrame(tick);
|
|
3504
|
+
}
|
|
3505
|
+
wakeRef.current = wake;
|
|
3506
|
+
const scheduleBuild = () => {
|
|
3507
|
+
cancelAnimationFrame(buildFrame);
|
|
3508
|
+
buildFrame = requestAnimationFrame(build);
|
|
3509
|
+
};
|
|
3510
|
+
const handlePointerMove = (event) => {
|
|
3511
|
+
const rect = canvas.getBoundingClientRect();
|
|
3512
|
+
const x = event.clientX - rect.left;
|
|
3513
|
+
const y = event.clientY - rect.top;
|
|
3514
|
+
const inside = x >= 0 && y >= 0 && x <= rect.width && y <= rect.height;
|
|
3515
|
+
if (!inside && !pointer.active) return;
|
|
3516
|
+
pointer.x = x;
|
|
3517
|
+
pointer.y = y;
|
|
3518
|
+
pointer.active = inside;
|
|
3519
|
+
wake();
|
|
3520
|
+
};
|
|
3521
|
+
const handlePointerLeave = () => {
|
|
3522
|
+
pointer.active = false;
|
|
3523
|
+
};
|
|
3524
|
+
const intersection = new IntersectionObserver(([entry]) => {
|
|
3525
|
+
visible = entry.isIntersecting;
|
|
3526
|
+
if (visible) wake();
|
|
3527
|
+
});
|
|
3528
|
+
const resize = new ResizeObserver(scheduleBuild);
|
|
3529
|
+
intersection.observe(root);
|
|
3530
|
+
resize.observe(root);
|
|
3531
|
+
document.fonts?.addEventListener("loadingdone", scheduleBuild);
|
|
3532
|
+
if (interactive) {
|
|
3533
|
+
window.addEventListener("pointermove", handlePointerMove, { passive: true });
|
|
3534
|
+
document.documentElement.addEventListener("pointerleave", handlePointerLeave);
|
|
3535
|
+
}
|
|
3536
|
+
build();
|
|
3537
|
+
return () => {
|
|
3538
|
+
cancelAnimationFrame(frame);
|
|
3539
|
+
cancelAnimationFrame(buildFrame);
|
|
3540
|
+
intersection.disconnect();
|
|
3541
|
+
resize.disconnect();
|
|
3542
|
+
document.fonts?.removeEventListener("loadingdone", scheduleBuild);
|
|
3543
|
+
window.removeEventListener("pointermove", handlePointerMove);
|
|
3544
|
+
document.documentElement.removeEventListener("pointerleave", handlePointerLeave);
|
|
3545
|
+
wakeRef.current = null;
|
|
3546
|
+
};
|
|
3547
|
+
}, [children, gap, radius, assemble, prefersReducedMotion]);
|
|
3548
|
+
const style = color ? { "--elyri-particle-color": color } : void 0;
|
|
3549
|
+
return /* @__PURE__ */ jsxs(
|
|
3550
|
+
"span",
|
|
3551
|
+
{
|
|
3552
|
+
ref: rootRef,
|
|
3553
|
+
className: cn("elyri-particle-text", ready && "elyri-particle-text--ready", className),
|
|
3554
|
+
style,
|
|
3555
|
+
children: [
|
|
3556
|
+
/* @__PURE__ */ jsx("span", { className: "elyri-particle-text__label", children }),
|
|
3557
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "elyri-particle-text__canvas", "aria-hidden": "true" })
|
|
3558
|
+
]
|
|
3559
|
+
}
|
|
3560
|
+
);
|
|
3561
|
+
}
|
|
3562
|
+
var CHAR_STAGGER = 30;
|
|
3563
|
+
function RotatingText({
|
|
3564
|
+
words,
|
|
3565
|
+
className,
|
|
3566
|
+
interval = 2500,
|
|
3567
|
+
duration = 500,
|
|
3568
|
+
variant = "flip"
|
|
3569
|
+
}) {
|
|
3570
|
+
const [index, setIndex] = useState(0);
|
|
3571
|
+
const [leaving, setLeaving] = useState(null);
|
|
3572
|
+
const [width, setWidth] = useState();
|
|
3573
|
+
const wordRef = useRef(null);
|
|
3574
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3575
|
+
const [prevWords, setPrevWords] = useState(words);
|
|
3576
|
+
if (prevWords !== words) {
|
|
3577
|
+
setPrevWords(words);
|
|
3578
|
+
setIndex(0);
|
|
3579
|
+
setLeaving(null);
|
|
3580
|
+
}
|
|
3581
|
+
const count = words.length;
|
|
3582
|
+
const current = words[index] ?? words[0] ?? "";
|
|
3583
|
+
useEffect(() => {
|
|
3584
|
+
if (count < 2) return;
|
|
3585
|
+
const timer = window.setInterval(() => {
|
|
3586
|
+
setLeaving(prefersReducedMotion ? null : current);
|
|
3587
|
+
setIndex((value) => (value + 1) % count);
|
|
3588
|
+
}, interval);
|
|
3589
|
+
return () => window.clearInterval(timer);
|
|
3590
|
+
}, [count, current, interval, prefersReducedMotion]);
|
|
3591
|
+
useEffect(() => {
|
|
3592
|
+
if (leaving == null) return;
|
|
3593
|
+
const timer = window.setTimeout(() => setLeaving(null), duration + CHAR_STAGGER * leaving.length);
|
|
3594
|
+
return () => window.clearTimeout(timer);
|
|
3595
|
+
}, [leaving, duration]);
|
|
3596
|
+
useLayoutEffect(() => {
|
|
3597
|
+
const word = wordRef.current;
|
|
3598
|
+
if (word) setWidth(word.offsetWidth);
|
|
3599
|
+
}, [current]);
|
|
3600
|
+
const style = {
|
|
3601
|
+
"--elyri-rotating-text-duration": `${duration}ms`,
|
|
3602
|
+
width: width != null ? `${width}px` : void 0
|
|
3603
|
+
};
|
|
3604
|
+
const renderChars = (word) => Array.from(word).map((char, charIndex) => /* @__PURE__ */ jsx(
|
|
3605
|
+
"span",
|
|
3606
|
+
{
|
|
3607
|
+
className: "elyri-rotating-text__char",
|
|
3608
|
+
style: {
|
|
3609
|
+
"--elyri-rotating-text-index": charIndex,
|
|
3610
|
+
"--elyri-rotating-text-stagger": `${CHAR_STAGGER}ms`
|
|
3611
|
+
},
|
|
3612
|
+
"aria-hidden": "true",
|
|
3613
|
+
children: char === " " ? "\xA0" : char
|
|
3614
|
+
},
|
|
3615
|
+
`${char}-${charIndex}`
|
|
3616
|
+
));
|
|
3617
|
+
return /* @__PURE__ */ jsxs(
|
|
3618
|
+
"span",
|
|
3619
|
+
{
|
|
3620
|
+
className: cn("elyri-rotating-text", variant !== "flip" && `elyri-rotating-text--${variant}`, className),
|
|
3621
|
+
style,
|
|
3622
|
+
"aria-label": current,
|
|
3623
|
+
children: [
|
|
3624
|
+
/* @__PURE__ */ jsx("span", { ref: wordRef, className: "elyri-rotating-text__word elyri-rotating-text__word--entering", children: renderChars(current) }),
|
|
3625
|
+
leaving != null && /* @__PURE__ */ jsx("span", { className: "elyri-rotating-text__word elyri-rotating-text__word--leaving", "aria-hidden": "true", children: renderChars(leaving) })
|
|
3626
|
+
]
|
|
3627
|
+
}
|
|
3628
|
+
);
|
|
3629
|
+
}
|
|
3630
|
+
var DEFAULT_CHARACTERS2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!<>-_\\/[]{}=+*^?#";
|
|
3631
|
+
var isSpace = (char) => /\s/.test(char);
|
|
3632
|
+
function ScrambleText({
|
|
3633
|
+
children,
|
|
3634
|
+
className,
|
|
3635
|
+
trigger = "view",
|
|
3636
|
+
speed = 40,
|
|
3637
|
+
stagger = 60,
|
|
3638
|
+
characters = DEFAULT_CHARACTERS2,
|
|
3639
|
+
accentColor,
|
|
3640
|
+
glow,
|
|
3641
|
+
once = true
|
|
3642
|
+
}) {
|
|
3643
|
+
const elementRef = useRef(null);
|
|
3644
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3645
|
+
const [runId, setRunId] = useState(0);
|
|
3646
|
+
const [frame, setFrame] = useState(null);
|
|
3647
|
+
const chars = useMemo(() => Array.from(children), [children]);
|
|
3648
|
+
useEffect(() => {
|
|
3649
|
+
const element = elementRef.current;
|
|
3650
|
+
if (!element || prefersReducedMotion || trigger !== "view") return;
|
|
3651
|
+
const observer = new IntersectionObserver(
|
|
3652
|
+
([entry]) => {
|
|
3653
|
+
if (!entry.isIntersecting) return;
|
|
3654
|
+
setRunId((id) => id + 1);
|
|
3655
|
+
if (once) observer.disconnect();
|
|
3656
|
+
},
|
|
3657
|
+
{ threshold: 0.1 }
|
|
3658
|
+
);
|
|
3659
|
+
observer.observe(element);
|
|
3660
|
+
return () => observer.disconnect();
|
|
3661
|
+
}, [trigger, once, prefersReducedMotion]);
|
|
3662
|
+
useEffect(() => {
|
|
3663
|
+
if (runId === 0 || prefersReducedMotion) return;
|
|
3664
|
+
const pool = Array.from(characters || DEFAULT_CHARACTERS2);
|
|
3665
|
+
const start = performance.now();
|
|
3666
|
+
const step = () => {
|
|
3667
|
+
const resolved = Math.floor((performance.now() - start) / stagger);
|
|
3668
|
+
if (resolved >= chars.length) {
|
|
3669
|
+
setFrame(null);
|
|
3670
|
+
return true;
|
|
3671
|
+
}
|
|
3672
|
+
setFrame({
|
|
3673
|
+
resolved,
|
|
3674
|
+
chars: chars.map(
|
|
3675
|
+
(char, index) => index < resolved || isSpace(char) ? char : pool[Math.floor(Math.random() * pool.length)]
|
|
3676
|
+
)
|
|
3677
|
+
});
|
|
3678
|
+
return false;
|
|
3679
|
+
};
|
|
3680
|
+
if (step()) return;
|
|
3681
|
+
const timer = setInterval(() => {
|
|
3682
|
+
if (step()) clearInterval(timer);
|
|
3683
|
+
}, speed);
|
|
3684
|
+
return () => clearInterval(timer);
|
|
3685
|
+
}, [runId, chars, characters, speed, stagger, prefersReducedMotion]);
|
|
3686
|
+
const replay = () => {
|
|
3687
|
+
if (!frame && !prefersReducedMotion) setRunId((id) => id + 1);
|
|
3688
|
+
};
|
|
3689
|
+
const hoverHandlers = trigger === "hover" ? { onPointerEnter: replay, onFocus: replay } : null;
|
|
3690
|
+
const style = {
|
|
3691
|
+
...accentColor ? { "--elyri-scramble-accent": accentColor } : null,
|
|
3692
|
+
...glow !== void 0 ? { "--elyri-scramble-glow": Math.max(0, glow) } : null
|
|
3693
|
+
};
|
|
3694
|
+
return /* @__PURE__ */ jsxs("span", { ref: elementRef, className: cn("elyri-scramble-text", className), style, ...hoverHandlers, children: [
|
|
3695
|
+
/* @__PURE__ */ jsx("span", { className: "elyri-scramble-text__sr", children }),
|
|
3696
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: chars.map((char, index) => {
|
|
3697
|
+
const isScrambled = frame !== null && index >= frame.resolved && !isSpace(char);
|
|
3698
|
+
return /* @__PURE__ */ jsxs(
|
|
3699
|
+
"span",
|
|
3700
|
+
{
|
|
3701
|
+
className: cn("elyri-scramble-text__char", isScrambled && "elyri-scramble-text__char--scrambled"),
|
|
3702
|
+
children: [
|
|
3703
|
+
char,
|
|
3704
|
+
isScrambled && /* @__PURE__ */ jsx("span", { className: "elyri-scramble-text__glyph", children: frame.chars[index] })
|
|
3705
|
+
]
|
|
3706
|
+
},
|
|
3707
|
+
index
|
|
3708
|
+
);
|
|
3709
|
+
}) })
|
|
3710
|
+
] });
|
|
3711
|
+
}
|
|
3712
|
+
function ScrollMarquee({
|
|
3713
|
+
children,
|
|
3714
|
+
className,
|
|
3715
|
+
direction = "left",
|
|
3716
|
+
speed = 0.5,
|
|
3717
|
+
rows = 1,
|
|
3718
|
+
repeat = 6,
|
|
3719
|
+
infinite = true
|
|
3720
|
+
}) {
|
|
3721
|
+
const rootRef = useRef(null);
|
|
3722
|
+
const firstCopyRef = useRef(null);
|
|
3723
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3724
|
+
useEffect(() => {
|
|
3725
|
+
const root = rootRef.current;
|
|
3726
|
+
if (!root || prefersReducedMotion) return;
|
|
3727
|
+
let frame = 0;
|
|
3728
|
+
const update = () => {
|
|
3729
|
+
frame = 0;
|
|
3730
|
+
const copyWidth = firstCopyRef.current?.offsetWidth ?? 0;
|
|
3731
|
+
if (!copyWidth) return;
|
|
3732
|
+
const offset = window.scrollY * speed;
|
|
3733
|
+
const shift = infinite ? -(offset % copyWidth) : -Math.min(offset, copyWidth);
|
|
3734
|
+
root.style.setProperty("--elyri-scroll-marquee-shift", `${shift}px`);
|
|
3735
|
+
root.style.setProperty("--elyri-scroll-marquee-copy-width", `${copyWidth}px`);
|
|
3736
|
+
};
|
|
3737
|
+
const onScroll = () => {
|
|
3738
|
+
if (frame) return;
|
|
3739
|
+
frame = requestAnimationFrame(update);
|
|
3740
|
+
};
|
|
3741
|
+
update();
|
|
3742
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
3743
|
+
window.addEventListener("resize", onScroll);
|
|
3744
|
+
return () => {
|
|
3745
|
+
window.removeEventListener("scroll", onScroll);
|
|
3746
|
+
window.removeEventListener("resize", onScroll);
|
|
3747
|
+
if (frame) cancelAnimationFrame(frame);
|
|
3748
|
+
};
|
|
3749
|
+
}, [prefersReducedMotion, speed, rows, repeat, infinite]);
|
|
3750
|
+
const rowCount = Math.max(1, Math.floor(rows));
|
|
3751
|
+
const copyCount = Math.max(1, Math.floor(repeat));
|
|
3752
|
+
const baseDirection = direction === "left" ? 1 : -1;
|
|
3753
|
+
return /* @__PURE__ */ jsx("div", { ref: rootRef, className: cn("elyri-scroll-marquee", className), children: Array.from({ length: rowCount }, (_, rowIndex) => {
|
|
3754
|
+
const dir = rowIndex % 2 === 0 ? baseDirection : -baseDirection;
|
|
3755
|
+
return /* @__PURE__ */ jsx(
|
|
3756
|
+
"div",
|
|
3757
|
+
{
|
|
3758
|
+
className: "elyri-scroll-marquee__row",
|
|
3759
|
+
style: {
|
|
3760
|
+
"--elyri-scroll-marquee-dir": dir,
|
|
3761
|
+
// 向右滚动时先整体左移一份内容宽度,避免左侧露白
|
|
3762
|
+
"--elyri-scroll-marquee-base": dir === 1 ? 0 : -1
|
|
3763
|
+
},
|
|
3764
|
+
children: Array.from({ length: copyCount }, (_2, copyIndex) => /* @__PURE__ */ jsx(
|
|
3765
|
+
"span",
|
|
3766
|
+
{
|
|
3767
|
+
ref: rowIndex === 0 && copyIndex === 0 ? firstCopyRef : void 0,
|
|
3768
|
+
className: "elyri-scroll-marquee__copy",
|
|
3769
|
+
children
|
|
3770
|
+
},
|
|
3771
|
+
copyIndex
|
|
3772
|
+
))
|
|
3773
|
+
},
|
|
3774
|
+
rowIndex
|
|
3775
|
+
);
|
|
3776
|
+
}) });
|
|
3777
|
+
}
|
|
3778
|
+
var LEAD_RATIO = 0.65;
|
|
3779
|
+
var segmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "word" }) : null;
|
|
3780
|
+
var splitWords = (text) => {
|
|
3781
|
+
if (!segmenter) return splitTextUnits(text, "word");
|
|
3782
|
+
const segments = [];
|
|
3783
|
+
let index = 0;
|
|
3784
|
+
let wordPart = 0;
|
|
3785
|
+
let spacePart = 0;
|
|
3786
|
+
let pending = "";
|
|
3787
|
+
for (const { segment: value, isWordLike } of segmenter.segment(text)) {
|
|
3788
|
+
if (/^\s+$/.test(value)) {
|
|
3789
|
+
segments.push({ kind: "space", key: `space-${spacePart++}`, value });
|
|
3790
|
+
continue;
|
|
3791
|
+
}
|
|
3792
|
+
if (isWordLike) {
|
|
3793
|
+
segments.push({ kind: "word", key: `word-${wordPart++}`, units: [{ char: pending + value, index: index++ }] });
|
|
3794
|
+
pending = "";
|
|
3795
|
+
continue;
|
|
3796
|
+
}
|
|
3797
|
+
const last = segments[segments.length - 1];
|
|
3798
|
+
if (!pending && last?.kind === "word") {
|
|
3799
|
+
last.units[0].char += value;
|
|
3800
|
+
} else {
|
|
3801
|
+
pending += value;
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
if (pending) {
|
|
3805
|
+
segments.push({ kind: "word", key: `word-${wordPart}`, units: [{ char: pending, index }] });
|
|
3806
|
+
}
|
|
3807
|
+
return segments;
|
|
3808
|
+
};
|
|
3809
|
+
function ScrollReveal({
|
|
3810
|
+
children,
|
|
3811
|
+
className,
|
|
3812
|
+
by = "word",
|
|
3813
|
+
height = 280,
|
|
3814
|
+
dimOpacity = 0.15,
|
|
3815
|
+
blur = 0
|
|
3816
|
+
}) {
|
|
3817
|
+
const rootRef = useRef(null);
|
|
3818
|
+
const contentRef = useRef(null);
|
|
3819
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3820
|
+
const segments = useMemo(
|
|
3821
|
+
() => by === "word" ? splitWords(children) : splitTextUnits(children, "char"),
|
|
3822
|
+
[children, by]
|
|
3823
|
+
);
|
|
3824
|
+
const count = useMemo(
|
|
3825
|
+
() => segments.reduce((total, segment) => segment.kind === "word" ? total + segment.units.length : total, 0),
|
|
3826
|
+
[segments]
|
|
3827
|
+
);
|
|
3828
|
+
useEffect(() => {
|
|
3829
|
+
const root = rootRef.current;
|
|
3830
|
+
const content = contentRef.current;
|
|
3831
|
+
if (!root || !content || prefersReducedMotion) return;
|
|
3832
|
+
let frame = 0;
|
|
3833
|
+
const update = () => {
|
|
3834
|
+
frame = 0;
|
|
3835
|
+
const travel = content.offsetHeight;
|
|
3836
|
+
if (travel <= 0) return;
|
|
3837
|
+
const { clientHeight, scrollHeight, scrollTop } = root;
|
|
3838
|
+
const range = scrollHeight - clientHeight;
|
|
3839
|
+
if (range <= 0) {
|
|
3840
|
+
root.style.setProperty("--elyri-scroll-reveal-progress", "1");
|
|
3841
|
+
return;
|
|
3842
|
+
}
|
|
3843
|
+
const line = scrollTop + clientHeight * LEAD_RATIO;
|
|
3844
|
+
const tailStart = Math.max(0, range - clientHeight);
|
|
3845
|
+
const tail = Math.min(1, Math.max(0, (scrollTop - tailStart) / clientHeight));
|
|
3846
|
+
const head = scrollTop >= range - 1 ? travel : line + tail * (travel - range - clientHeight * LEAD_RATIO);
|
|
3847
|
+
root.style.setProperty("--elyri-scroll-reveal-progress", String(Math.min(1, Math.max(0, head / travel))));
|
|
3848
|
+
};
|
|
3849
|
+
const onScroll = () => {
|
|
3850
|
+
if (frame) return;
|
|
3851
|
+
frame = requestAnimationFrame(update);
|
|
3852
|
+
};
|
|
3853
|
+
update();
|
|
3854
|
+
root.addEventListener("scroll", onScroll, { passive: true });
|
|
3855
|
+
const observer = new ResizeObserver(onScroll);
|
|
3856
|
+
observer.observe(content);
|
|
3857
|
+
return () => {
|
|
3858
|
+
root.removeEventListener("scroll", onScroll);
|
|
3859
|
+
observer.disconnect();
|
|
3860
|
+
if (frame) cancelAnimationFrame(frame);
|
|
3861
|
+
};
|
|
3862
|
+
}, [prefersReducedMotion, count]);
|
|
3863
|
+
const style = {
|
|
3864
|
+
"--elyri-scroll-reveal-height": `${height}px`,
|
|
3865
|
+
"--elyri-scroll-reveal-dim": dimOpacity,
|
|
3866
|
+
"--elyri-scroll-reveal-blur": `${blur}px`,
|
|
3867
|
+
"--elyri-scroll-reveal-count": count
|
|
3868
|
+
};
|
|
3869
|
+
return /* @__PURE__ */ jsx(
|
|
3870
|
+
"div",
|
|
3871
|
+
{
|
|
3872
|
+
ref: rootRef,
|
|
3873
|
+
className: cn("elyri-scroll-reveal", blur > 0 && "elyri-scroll-reveal--blur", className),
|
|
3874
|
+
style,
|
|
3875
|
+
children: /* @__PURE__ */ jsx("div", { ref: contentRef, className: "elyri-scroll-reveal__content", "aria-label": children, children: segments.map(
|
|
3876
|
+
(segment) => segment.kind === "space" ? segment.value : /* @__PURE__ */ jsx("span", { className: "elyri-scroll-reveal__word", children: segment.units.map((unit) => /* @__PURE__ */ jsx(
|
|
3877
|
+
"span",
|
|
3878
|
+
{
|
|
3879
|
+
className: "elyri-scroll-reveal__unit",
|
|
3880
|
+
style: { "--elyri-scroll-reveal-index": unit.index },
|
|
3881
|
+
"aria-hidden": "true",
|
|
3882
|
+
children: unit.char
|
|
3883
|
+
},
|
|
3884
|
+
unit.index
|
|
3885
|
+
)) }, segment.key)
|
|
3886
|
+
) })
|
|
3887
|
+
}
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
var splitText = (text, by) => {
|
|
3891
|
+
let index = 0;
|
|
3892
|
+
return text.split(/(\s+)/).filter(Boolean).map((part, partIndex) => {
|
|
3893
|
+
if (/^\s+$/.test(part)) return { kind: "space", key: `space-${partIndex}`, value: part };
|
|
3894
|
+
const units = by === "char" ? Array.from(part) : [part];
|
|
3895
|
+
return {
|
|
3896
|
+
kind: "word",
|
|
3897
|
+
key: `word-${partIndex}`,
|
|
3898
|
+
units: units.map((char) => ({ char, index: index++ }))
|
|
3899
|
+
};
|
|
3900
|
+
});
|
|
3901
|
+
};
|
|
3902
|
+
function SplitReveal({
|
|
3903
|
+
children,
|
|
3904
|
+
className,
|
|
3905
|
+
by = "char",
|
|
3906
|
+
delay = 0,
|
|
3907
|
+
stagger = 40,
|
|
3908
|
+
duration = 600,
|
|
3909
|
+
distance = 24,
|
|
3910
|
+
once = true
|
|
3911
|
+
}) {
|
|
3912
|
+
const elementRef = useRef(null);
|
|
3913
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3914
|
+
const [isIntersecting, setIsIntersecting] = useState(false);
|
|
3915
|
+
useEffect(() => {
|
|
3916
|
+
const element = elementRef.current;
|
|
3917
|
+
if (!element || prefersReducedMotion) return;
|
|
3918
|
+
const observer = new IntersectionObserver(
|
|
3919
|
+
([entry]) => {
|
|
3920
|
+
if (entry.isIntersecting) {
|
|
3921
|
+
setIsIntersecting(true);
|
|
3922
|
+
if (once) observer.disconnect();
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
if (!once) setIsIntersecting(false);
|
|
3926
|
+
},
|
|
3927
|
+
{ threshold: 0.1 }
|
|
3928
|
+
);
|
|
3929
|
+
observer.observe(element);
|
|
3930
|
+
return () => observer.disconnect();
|
|
3931
|
+
}, [once, prefersReducedMotion]);
|
|
3932
|
+
const segments = useMemo(() => splitText(children, by), [children, by]);
|
|
3933
|
+
const style = {
|
|
3934
|
+
"--elyri-split-reveal-delay": `${delay}ms`,
|
|
3935
|
+
"--elyri-split-reveal-stagger": `${stagger}ms`,
|
|
3936
|
+
"--elyri-split-reveal-duration": `${duration}ms`,
|
|
3937
|
+
"--elyri-split-reveal-distance": `${distance}px`
|
|
3938
|
+
};
|
|
3939
|
+
const isVisible = prefersReducedMotion || isIntersecting;
|
|
3940
|
+
return /* @__PURE__ */ jsx(
|
|
3941
|
+
"span",
|
|
3942
|
+
{
|
|
3943
|
+
ref: elementRef,
|
|
3944
|
+
className: cn("elyri-split-reveal", isVisible && "elyri-split-reveal--visible", className),
|
|
3945
|
+
style,
|
|
3946
|
+
children: segments.map(
|
|
3947
|
+
(segment) => segment.kind === "space" ? segment.value : /* @__PURE__ */ jsx("span", { className: "elyri-split-reveal__word", children: segment.units.map((unit) => /* @__PURE__ */ jsx(
|
|
3948
|
+
"span",
|
|
3949
|
+
{
|
|
3950
|
+
className: "elyri-split-reveal__unit",
|
|
3951
|
+
style: { "--elyri-split-reveal-index": unit.index },
|
|
3952
|
+
children: unit.char
|
|
3953
|
+
},
|
|
3954
|
+
unit.index
|
|
3955
|
+
)) }, segment.key)
|
|
3956
|
+
)
|
|
3957
|
+
}
|
|
3958
|
+
);
|
|
3959
|
+
}
|
|
3960
|
+
function Typewriter({
|
|
3961
|
+
children,
|
|
3962
|
+
className,
|
|
3963
|
+
speed = 60,
|
|
3964
|
+
startDelay = 200,
|
|
3965
|
+
loop = false,
|
|
3966
|
+
loopDelay = 1200,
|
|
3967
|
+
cursor = true
|
|
3968
|
+
}) {
|
|
3969
|
+
const text = children;
|
|
3970
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3971
|
+
const [count, setCount] = useState(0);
|
|
3972
|
+
useEffect(() => {
|
|
3973
|
+
if (prefersReducedMotion || !text) return;
|
|
3974
|
+
let timer;
|
|
3975
|
+
let typed = 0;
|
|
3976
|
+
const typeNext = (wait) => {
|
|
3977
|
+
timer = setTimeout(() => {
|
|
3978
|
+
typed += 1;
|
|
3979
|
+
setCount(typed);
|
|
3980
|
+
if (typed < text.length) {
|
|
3981
|
+
typeNext(speed);
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3984
|
+
if (loop) {
|
|
3985
|
+
timer = setTimeout(() => {
|
|
3986
|
+
typed = 0;
|
|
3987
|
+
setCount(0);
|
|
3988
|
+
typeNext(speed);
|
|
3989
|
+
}, loopDelay);
|
|
3990
|
+
}
|
|
3991
|
+
}, wait);
|
|
3992
|
+
};
|
|
3993
|
+
timer = setTimeout(() => {
|
|
3994
|
+
typed = 0;
|
|
3995
|
+
setCount(0);
|
|
3996
|
+
typeNext(0);
|
|
3997
|
+
}, startDelay);
|
|
3998
|
+
return () => clearTimeout(timer);
|
|
3999
|
+
}, [text, speed, startDelay, loop, loopDelay, prefersReducedMotion]);
|
|
4000
|
+
const visible = prefersReducedMotion ? text : text.slice(0, count);
|
|
4001
|
+
return /* @__PURE__ */ jsxs("span", { className: cn("elyri-typewriter", className), children: [
|
|
4002
|
+
/* @__PURE__ */ jsx("span", { className: "elyri-typewriter__text", children: visible }),
|
|
4003
|
+
cursor && /* @__PURE__ */ jsx("span", { className: "elyri-typewriter__cursor", "aria-hidden": "true" })
|
|
4004
|
+
] });
|
|
4005
|
+
}
|
|
4006
|
+
function WaveText({ children, className, amplitude = 6, speed = 1200, stagger = 60 }) {
|
|
4007
|
+
const segments = useMemo(() => splitTextUnits(children, "char"), [children]);
|
|
4008
|
+
const style = {
|
|
4009
|
+
"--elyri-wave-text-amplitude": `${amplitude}px`,
|
|
4010
|
+
"--elyri-wave-text-speed": `${speed}ms`,
|
|
4011
|
+
"--elyri-wave-text-stagger": `${stagger}ms`
|
|
4012
|
+
};
|
|
4013
|
+
return /* @__PURE__ */ jsx("span", { className: cn("elyri-wave-text", className), style, "aria-label": children, children: segments.map(
|
|
4014
|
+
(segment) => segment.kind === "space" ? segment.value : /* @__PURE__ */ jsx("span", { className: "elyri-wave-text__word", children: segment.units.map((unit) => /* @__PURE__ */ jsx(
|
|
4015
|
+
"span",
|
|
4016
|
+
{
|
|
4017
|
+
className: "elyri-wave-text__unit",
|
|
4018
|
+
style: { "--elyri-wave-text-index": unit.index },
|
|
4019
|
+
"aria-hidden": "true",
|
|
4020
|
+
children: unit.char
|
|
4021
|
+
},
|
|
4022
|
+
unit.index
|
|
4023
|
+
)) }, segment.key)
|
|
4024
|
+
) });
|
|
4025
|
+
}
|
|
4026
|
+
|
|
4027
|
+
export { AsciiImage, Aurora, Caustics, Contours, CountUp, DotField, DragonScales, FadeIn, Filaments, FlipTiles, GradientText, Halo, Magnetic, Marquee, MeshGradient, ParticleText, PixelVortex, Planet, RotatingText, ScaleIn, ScrambleText, ScrollMarquee, ScrollReveal, SilkWaves, SplitReveal, Spotlight, Tilt, Typewriter, Velvet, WaveText };
|
|
4028
|
+
//# sourceMappingURL=index.js.map
|
|
4029
|
+
//# sourceMappingURL=index.js.map
|