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