@toriistudio/shader-ui 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  FractalFlower: () => FractalFlower,
34
+ MenuGlitch: () => MenuGlitch,
34
35
  OranoParticles: () => OranoParticles,
35
36
  ShaderArt: () => ShaderArt
36
37
  });
@@ -58,6 +59,7 @@ function useScene({
58
59
  const onCreateRef = (0, import_react.useRef)(onCreate);
59
60
  const onRenderRef = (0, import_react.useRef)(onRender);
60
61
  const onResizeRef = (0, import_react.useRef)(onResize);
62
+ const sizeRef = (0, import_react.useRef)({ width: 0, height: 0 });
61
63
  (0, import_react.useEffect)(() => {
62
64
  onCreateRef.current = onCreate;
63
65
  }, [onCreate]);
@@ -72,43 +74,83 @@ function useScene({
72
74
  const container = containerRef.current;
73
75
  if (!container) return;
74
76
  const resolvedPixelRatio = pixelRatio ?? (typeof window !== "undefined" ? Math.min(window.devicePixelRatio, 2) : 1);
77
+ const initialWidth = container.clientWidth || 1;
78
+ const initialHeight = container.clientHeight || 1;
79
+ sizeRef.current = { width: initialWidth, height: initialHeight };
75
80
  const renderer = new THREE.WebGLRenderer({
76
81
  alpha: true,
77
82
  antialias: true,
78
83
  ...rendererOptions
79
84
  });
80
85
  renderer.setPixelRatio(resolvedPixelRatio);
81
- renderer.setSize(container.clientWidth, container.clientHeight, false);
86
+ renderer.setSize(initialWidth, initialHeight, false);
82
87
  renderer.setClearColor(0, 0);
83
88
  renderer.domElement.style.width = "100%";
84
89
  renderer.domElement.style.height = "100%";
85
90
  container.appendChild(renderer.domElement);
86
91
  const scene = new THREE.Scene();
87
- const camera = new THREE.PerspectiveCamera(
88
- cameraOptions?.fov ?? 55,
89
- container.clientWidth / Math.max(1, container.clientHeight),
90
- cameraOptions?.near ?? 0.1,
91
- cameraOptions?.far ?? 500
92
- );
93
- const [x = 0, y = 0, z = 15] = cameraOptions?.position ?? [];
94
- camera.position.set(x, y, z);
92
+ let camera;
93
+ if (cameraOptions?.type === "orthographic") {
94
+ const halfWidth = initialWidth / 2;
95
+ const halfHeight = initialHeight / 2;
96
+ const orthoCamera = new THREE.OrthographicCamera(
97
+ -halfWidth,
98
+ halfWidth,
99
+ halfHeight,
100
+ -halfHeight,
101
+ cameraOptions?.near ?? 0.1,
102
+ cameraOptions?.far ?? 1e3
103
+ );
104
+ const [, , z = 10] = cameraOptions?.position ?? [];
105
+ orthoCamera.position.set(0, 0, z);
106
+ camera = orthoCamera;
107
+ } else {
108
+ const perspectiveCamera = new THREE.PerspectiveCamera(
109
+ cameraOptions?.fov ?? 55,
110
+ initialWidth / Math.max(1, initialHeight),
111
+ cameraOptions?.near ?? 0.1,
112
+ cameraOptions?.far ?? 500
113
+ );
114
+ const [x = 0, y = 0, z = 15] = cameraOptions?.position ?? [];
115
+ perspectiveCamera.position.set(x, y, z);
116
+ camera = perspectiveCamera;
117
+ }
95
118
  const clock = new THREE.Clock();
96
- const context = { renderer, scene, camera, clock };
119
+ const context = {
120
+ renderer,
121
+ scene,
122
+ camera,
123
+ clock,
124
+ size: { ...sizeRef.current }
125
+ };
97
126
  contextRef.current = context;
98
127
  const teardownCreate = onCreateRef.current?.(context);
128
+ let elapsedTime = 0;
99
129
  let animationFrameId = 0;
100
130
  const renderLoop = () => {
101
- onRenderRef.current?.(context);
131
+ const delta = clock.getDelta();
132
+ elapsedTime += delta;
133
+ context.size = { ...sizeRef.current };
134
+ onRenderRef.current?.(context, delta, elapsedTime);
102
135
  renderer.render(scene, camera);
103
136
  animationFrameId = requestAnimationFrame(renderLoop);
104
137
  };
105
138
  animationFrameId = requestAnimationFrame(renderLoop);
106
139
  const resizeObserver = new ResizeObserver(() => {
107
- const width = container.clientWidth;
108
- const height = container.clientHeight;
140
+ const width = container.clientWidth || 1;
141
+ const height = container.clientHeight || 1;
109
142
  renderer.setSize(width, height, false);
110
- camera.aspect = width / Math.max(1, height);
143
+ sizeRef.current = { width, height };
144
+ if (camera instanceof THREE.PerspectiveCamera) {
145
+ camera.aspect = width / Math.max(1, height);
146
+ } else if (camera instanceof THREE.OrthographicCamera) {
147
+ camera.left = -width / 2;
148
+ camera.right = width / 2;
149
+ camera.top = height / 2;
150
+ camera.bottom = -height / 2;
151
+ }
111
152
  camera.updateProjectionMatrix();
153
+ context.size = { ...sizeRef.current };
112
154
  onResizeRef.current?.(context, { width, height });
113
155
  });
114
156
  resizeObserver.observe(container);
@@ -168,15 +210,14 @@ function ShaderArt({
168
210
  assetsRef.current = null;
169
211
  };
170
212
  }, []);
171
- const handleRender = (0, import_react2.useCallback)((context) => {
172
- shaderUniformsRef.current.iTime.value = context.clock.getElapsedTime();
173
- const canvas = context.renderer.domElement;
174
- shaderUniformsRef.current.iResolution.value.set(
175
- canvas.width,
176
- canvas.height,
177
- 1
178
- );
179
- }, []);
213
+ const handleRender = (0, import_react2.useCallback)(
214
+ (context, _delta, elapsedTime) => {
215
+ shaderUniformsRef.current.iTime.value = elapsedTime;
216
+ const { width: width2, height: height2 } = context.size;
217
+ shaderUniformsRef.current.iResolution.value.set(width2, height2, 1);
218
+ },
219
+ []
220
+ );
180
221
  const { containerRef } = useScene({
181
222
  onCreate: handleCreate,
182
223
  onRender: handleRender
@@ -318,7 +359,12 @@ function FractalFlower({
318
359
  const points = new THREE3.Points(geometry, material);
319
360
  points.frustumCulled = false;
320
361
  scene.add(points);
321
- assetsRef.current = { points, geometry, material, uniforms: uniformValues };
362
+ assetsRef.current = {
363
+ points,
364
+ geometry,
365
+ material,
366
+ uniforms: uniformValues
367
+ };
322
368
  return () => {
323
369
  scene.remove(points);
324
370
  geometry.dispose();
@@ -326,25 +372,29 @@ function FractalFlower({
326
372
  assetsRef.current = null;
327
373
  };
328
374
  },
329
- [attributes.eValues, attributes.kValues, attributes.positions, attributes.rotations]
375
+ [
376
+ attributes.eValues,
377
+ attributes.kValues,
378
+ attributes.positions,
379
+ attributes.rotations
380
+ ]
330
381
  );
331
382
  const handleRender = (0, import_react3.useCallback)(
332
- (context) => {
383
+ (context, delta, elapsedTime) => {
333
384
  const assets = assetsRef.current;
334
385
  if (!assets) return;
335
386
  const uniforms = assets.uniforms;
336
- uniforms.uTime.value = context.clock.getElapsedTime();
337
- const canvas = context.renderer.domElement;
338
- uniforms.uResolution.value.set(canvas.width, canvas.height);
387
+ uniforms.uTime.value = elapsedTime;
388
+ const { width: width2, height: height2 } = context.size;
389
+ uniforms.uResolution.value.set(width2, height2);
339
390
  const basePointSize = Math.max(
340
391
  2,
341
- canvas.height / 400 * (uniforms.uPetalRadius.value * 32)
392
+ height2 / 400 * (uniforms.uPetalRadius.value * 32)
342
393
  );
343
394
  const pointSize = Math.min(basePointSize, 6);
344
395
  uniforms.uPointSize.value = pointSize;
345
396
  const morph = morphRef.current;
346
397
  if (Math.abs(morph.target - morph.progress) > 1e-3) {
347
- const delta = context.clock.getDelta();
348
398
  const direction = Math.sign(morph.target - morph.progress);
349
399
  morph.progress = clamp(
350
400
  morph.progress + direction * delta * MORPH_SPEED,
@@ -495,11 +545,14 @@ function OranoParticles({
495
545
  particlesRef.current = null;
496
546
  };
497
547
  }, []);
498
- const handleRender = (0, import_react4.useCallback)((context) => {
499
- const assets = particlesRef.current;
500
- if (!assets) return;
501
- assets.uniforms.uTime.value = context.clock.getElapsedTime();
502
- }, []);
548
+ const handleRender = (0, import_react4.useCallback)(
549
+ (_context, _delta, elapsedTime) => {
550
+ const assets = particlesRef.current;
551
+ if (!assets) return;
552
+ assets.uniforms.uTime.value = elapsedTime;
553
+ },
554
+ []
555
+ );
503
556
  const { containerRef } = useScene({
504
557
  onCreate: handleCreate,
505
558
  onRender: handleRender
@@ -558,9 +611,473 @@ function OranoParticles({
558
611
  }
559
612
  );
560
613
  }
614
+
615
+ // src/components/MenuGlitch.tsx
616
+ var import_gsap = require("gsap");
617
+ var import_react5 = require("react");
618
+ var THREE5 = __toESM(require("three"));
619
+
620
+ // src/shaders/menu-glitch/fragment.glsl
621
+ var fragment_default4 = "#define M_PI 3.1415926535897932384626433832795\n\nuniform sampler2D tDiffuse;\nuniform sampler2D tGradient;\n\nuniform float uTime;\n\nuniform float uTileProgressVertical;\nuniform float uTileProgressHorizontal;\nuniform float uTileAmplitude;\nuniform vec2 uTileFrequency;\nuniform vec2 uTileOffset;\n\nuniform float uWaveProgress;\nuniform float uWaveAmplitude;\nuniform vec2 uWaveStrength;\n\nuniform float uGradientProgress;\nuniform float uGradientOffset;\nuniform float uGradientAmplitude;\n\nuniform float uBlueProgress;\nuniform float uBlueAmplitude;\n\nuniform float uWhiteTileChances;\nuniform float uWhiteTileFrequency;\nuniform float uWhiteTileStrength;\n\nuniform float uSaturation;\n\nvarying vec2 vUv;\n\n\n// --------------------------------------------------\n// Utilities\n// --------------------------------------------------\n\nfloat random(in vec2 st) {\n return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);\n}\n\nvec2 getTileCoord(vec2 pos, vec2 frequency) {\n vec2 coord = vec2(\n floor(pos.x * frequency.x),\n floor(pos.y * frequency.y)\n );\n\n coord /= frequency;\n return coord;\n}\n\nfloat toSin(float value) {\n return (sin((value - 0.5) * M_PI) + 1.0) * 0.5;\n}\n\n\n// --------------------------------------------------\n// Main\n// --------------------------------------------------\n\nvoid main() {\n\n // ------------------------\n // Tiles\n // ------------------------\n vec2 tileCoord1 = getTileCoord(vUv, uTileFrequency * 1.8942);\n vec2 tileCoord2 = getTileCoord(vUv, uTileFrequency * 1.0);\n vec2 tileCoord3 = getTileCoord(vUv, uTileFrequency * 2.1245);\n\n vec2 tileCoord = tileCoord2 +\n step(random(tileCoord1), 0.5) * (tileCoord3 - tileCoord2);\n\n float tileRandom = random(tileCoord);\n float tileAngle = tileRandom * M_PI * 2.0;\n\n vec2 tileOffset = vec2(sin(tileAngle), cos(tileAngle)) * uTileOffset;\n\n float tileProgress = 1.0 -\n (distance(tileCoord.y, uTileProgressVertical) / (uTileAmplitude * 0.5));\n\n tileProgress = clamp(tileProgress, 0.0, 1.0);\n\n float tileProgressHorizontal = 1.0 -\n (distance(tileCoord.x, uTileProgressHorizontal) / (uTileAmplitude * 0.5));\n tileProgressHorizontal = clamp(tileProgressHorizontal, 0.0, 1.0);\n\n // ------------------------\n // Wave\n // ------------------------\n float waveProgress = 1.0 -\n (distance(vUv.x, uWaveProgress) / (uWaveAmplitude * 0.5));\n\n waveProgress = clamp(waveProgress, 0.0, 1.0);\n\n vec2 waveOffset = toSin(waveProgress) * uWaveStrength;\n\n\n // ------------------------\n // Gradient\n // ------------------------\n float gradientProgress = (tileCoord.x - uGradientProgress) / uGradientAmplitude;\n gradientProgress += (tileRandom - 0.5) * uGradientOffset;\n\n vec4 gradientColor = texture2D(\n tGradient,\n vec2(clamp(gradientProgress, 0.0, 1.0), 0.0)\n );\n\n\n // ------------------------\n // Blue tint\n // ------------------------\n float blueProgress = (tileCoord.x - uBlueProgress) / uBlueAmplitude;\n blueProgress += tileOffset.x;\n blueProgress = clamp(blueProgress, 0.0, 1.0);\n\n\n // ------------------------\n // White flickering tiles\n // ------------------------\n float whiteTileProgress =\n sin(uTime * uWhiteTileFrequency + tileRandom * M_PI * 2.0) * 0.5 + 0.5;\n\n whiteTileProgress =\n clamp(whiteTileProgress - (1.0 - uWhiteTileChances), 0.0, 1.0) *\n (1.0 / uWhiteTileChances) *\n uWhiteTileStrength;\n\n\n // ------------------------\n // Final color pipeline\n // ------------------------\n vec2 uv = vUv;\n\n // Apply tile offset\n uv += tileOffset * tileProgress;\n\n // Apply waves (optional)\n // uv += waveOffset;\n\n // Repeat UV\n uv = mod(uv, vec2(1.0));\n\n // Base color removed so overlay only contains glitch elements\n vec4 color = vec4(0.0);\n\n // Add gradient\n color.rgb += gradientColor.rgb * gradientColor.a * tileProgressHorizontal;\n\n // Add white flicker effect\n color.rgb += vec3(whiteTileProgress) * tileProgressHorizontal;\n\n // Blue tone shift\n vec3 blueColor = vec3((color.r + color.g + color.b) / 3.0) *\n vec3(0.3, 0.5, 1.0);\n\n color.rgb = mix(color.rgb, blueColor, vec3(blueProgress));\n\n // Saturation\n color.rgb *= uSaturation;\n\n float effectAlpha =\n clamp(tileProgressHorizontal * (tileProgress * 0.6 + whiteTileProgress + gradientColor.a), 0.0, 1.0);\n\n // Output\n gl_FragColor = vec4(color.rgb, effectAlpha);\n}\n";
622
+
623
+ // src/shaders/menu-glitch/vertex.glsl
624
+ var vertex_default4 = "varying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n";
625
+
626
+ // src/components/MenuGlitch.tsx
627
+ var import_jsx_runtime4 = require("react/jsx-runtime");
628
+ var GRADIENT_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAABCAYAAAAxWXB3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTVBRkY1OTJDREMyMTFFODhGRjFFRjgxRjM2QjM2MDMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTVBRkY1OTNDREMyMTFFODhGRjFFRjgxRjM2QjM2MDMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFNUFGRjU5MENEQzIxMUU4OEZGMUVGODFGMzZCMzYwMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFNUFGRjU5MUNEQzIxMUU4OEZGMUVGODFGMzZCMzYwMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pksi3ywAAADMSURBVHjarFDLDoMwDDMtUDjtME3TtMcn7f9/hngBCoTSTjsMydixnVZqxTcAX51Quwsad1M80PonWvdCUA7+rrii82eEulcG+hoTdwsrQtRB0UZu3KxrN8OPqIBKgRHxI8qaUTD1RuY2p90V+hOjmWix2uSSeGLPKrDdKc5GHzqZLPWY7XEG+F1PLBktpiuzf8ilkMvqcZfLLqf1ltnu7rLh4G88ZPxh4uUOmjMYO3aPqz8Yve0tGiaDduNr/xn8cWbBY8HLzQd8BBgAgOx+ERYDbIEAAAAASUVORK5CYII=";
629
+ var BASE_TRANSITION_PROGRESS = 0.5;
630
+ var SHOW_BASE_DURATION = 2.72;
631
+ var HIDE_BASE_DURATION = 1.8;
632
+ var SHOW_PRIMARY_DURATION = 1.1;
633
+ var MIN_GLITCH_DURATION = 0.25;
634
+ function MenuGlitch({
635
+ settings,
636
+ onShowDone,
637
+ onHideDone,
638
+ className,
639
+ style,
640
+ width,
641
+ height,
642
+ ...divProps
643
+ }) {
644
+ const diffuseTexture = (0, import_react5.useMemo)(() => createDiffuseTexture(), []);
645
+ const gradientTextureRef = (0, import_react5.useRef)(new THREE5.Texture());
646
+ const sanitizedValues = (0, import_react5.useMemo)(() => {
647
+ const clamp2 = THREE5.MathUtils.clamp;
648
+ return {
649
+ tileAmplitude: Math.max(0.1, settings.tileAmplitude),
650
+ planeScale: Math.max(0.1, settings.planeScale ?? 1),
651
+ tileOffsetX: settings.tileOffset.x,
652
+ tileOffsetY: settings.tileOffset.y,
653
+ tileFrequencyX: Math.max(0.1, settings.tileFrequency.x),
654
+ tileFrequencyY: Math.max(0.1, settings.tileFrequency.y),
655
+ gradientAmplitude: Math.max(0.05, settings.gradientAmplitude),
656
+ gradientOffset: settings.gradientOffset,
657
+ gradientProgress: settings.gradientProgress ?? 1,
658
+ blueAmplitude: Math.max(0.05, settings.blueAmplitude),
659
+ blueProgress: settings.blueProgress ?? 1,
660
+ waveAmplitude: Math.max(0.05, settings.waveAmplitude),
661
+ waveProgress: settings.waveProgress ?? 0.5,
662
+ waveStrengthX: settings.waveStrength.x,
663
+ waveStrengthY: settings.waveStrength.y,
664
+ whiteTileChances: clamp2(settings.whiteTileChances, 0.05, 1),
665
+ whiteTileFrequency: Math.max(0.01, settings.whiteTileFrequency),
666
+ whiteTileStrength: Math.max(0, settings.whiteTileStrength),
667
+ saturation: Math.max(0, settings.saturation),
668
+ duration: Math.max(
669
+ MIN_GLITCH_DURATION,
670
+ settings.duration ?? SHOW_PRIMARY_DURATION
671
+ ),
672
+ debug: settings.debug
673
+ };
674
+ }, [settings]);
675
+ const sanitizedRef = (0, import_react5.useRef)(sanitizedValues);
676
+ sanitizedRef.current = sanitizedValues;
677
+ const sizeRef = (0, import_react5.useRef)({ width: 0, height: 0 });
678
+ const assetsRef = (0, import_react5.useRef)(null);
679
+ const animationVisibleRef = (0, import_react5.useRef)(false);
680
+ const shaderUniforms = (0, import_react5.useRef)({
681
+ tDiffuse: { value: diffuseTexture },
682
+ tGradient: { value: gradientTextureRef.current },
683
+ uTime: { value: 0 },
684
+ uTileProgressVertical: { value: -0.5 },
685
+ uTileProgressHorizontal: { value: -0.5 },
686
+ uTileAmplitude: { value: settings.tileAmplitude },
687
+ uTileOffset: {
688
+ value: new THREE5.Vector2(settings.tileOffset.x, settings.tileOffset.y)
689
+ },
690
+ uTileFrequency: {
691
+ value: new THREE5.Vector2(
692
+ settings.tileFrequency.x,
693
+ settings.tileFrequency.y
694
+ )
695
+ },
696
+ uWaveProgress: { value: settings.waveProgress },
697
+ uWaveAmplitude: { value: settings.waveAmplitude },
698
+ uWaveStrength: {
699
+ value: new THREE5.Vector2(
700
+ settings.waveStrength.x,
701
+ settings.waveStrength.y
702
+ )
703
+ },
704
+ uGradientProgress: { value: settings.gradientProgress },
705
+ uGradientOffset: { value: settings.gradientOffset },
706
+ uGradientAmplitude: { value: settings.gradientAmplitude },
707
+ uBlueProgress: { value: settings.blueProgress },
708
+ uBlueAmplitude: { value: settings.blueAmplitude },
709
+ uWhiteTileChances: { value: settings.whiteTileChances },
710
+ uWhiteTileFrequency: { value: settings.whiteTileFrequency },
711
+ uWhiteTileStrength: { value: settings.whiteTileStrength },
712
+ uSaturation: { value: settings.saturation }
713
+ });
714
+ (0, import_react5.useEffect)(() => {
715
+ let disposed = false;
716
+ const loader = new THREE5.TextureLoader();
717
+ loader.load(
718
+ GRADIENT_DATA_URL,
719
+ (texture) => {
720
+ if (disposed) return;
721
+ texture.wrapS = THREE5.ClampToEdgeWrapping;
722
+ texture.wrapT = THREE5.ClampToEdgeWrapping;
723
+ texture.magFilter = THREE5.LinearFilter;
724
+ texture.minFilter = THREE5.LinearFilter;
725
+ texture.colorSpace = THREE5.SRGBColorSpace;
726
+ gradientTextureRef.current = texture;
727
+ shaderUniforms.current.tGradient.value = texture;
728
+ },
729
+ void 0,
730
+ () => {
731
+ if (disposed) return;
732
+ gradientTextureRef.current = new THREE5.Texture();
733
+ shaderUniforms.current.tGradient.value = gradientTextureRef.current;
734
+ }
735
+ );
736
+ return () => {
737
+ disposed = true;
738
+ };
739
+ }, []);
740
+ const updateMeshScale = (0, import_react5.useCallback)(() => {
741
+ const assets = assetsRef.current;
742
+ if (!assets) return;
743
+ const base = Math.max(
744
+ sizeRef.current.width || 1,
745
+ sizeRef.current.height || 1
746
+ );
747
+ const scale = base * sanitizedRef.current.planeScale;
748
+ assets.mesh.scale.set(scale, scale, 1);
749
+ }, []);
750
+ const updateVisibility = (0, import_react5.useCallback)(() => {
751
+ const mesh = assetsRef.current?.mesh;
752
+ if (!mesh) return;
753
+ mesh.visible = sanitizedRef.current.debug || animationVisibleRef.current;
754
+ }, []);
755
+ const handleCreate = (0, import_react5.useCallback)(
756
+ ({ scene, size }) => {
757
+ const geometry = new THREE5.PlaneGeometry(1, 1);
758
+ const material = new THREE5.ShaderMaterial({
759
+ vertexShader: vertex_default4,
760
+ fragmentShader: fragment_default4,
761
+ uniforms: shaderUniforms.current,
762
+ depthWrite: false,
763
+ depthTest: false,
764
+ transparent: true,
765
+ blending: THREE5.AdditiveBlending
766
+ });
767
+ const mesh = new THREE5.Mesh(geometry, material);
768
+ scene.add(mesh);
769
+ assetsRef.current = { mesh, geometry, material };
770
+ sizeRef.current = size;
771
+ updateMeshScale();
772
+ updateVisibility();
773
+ return () => {
774
+ scene.remove(mesh);
775
+ geometry.dispose();
776
+ material.dispose();
777
+ assetsRef.current = null;
778
+ };
779
+ },
780
+ [updateMeshScale, updateVisibility]
781
+ );
782
+ const handleRender = (0, import_react5.useCallback)(
783
+ (_context, _delta, elapsedTime) => {
784
+ shaderUniforms.current.uTime.value = elapsedTime;
785
+ },
786
+ []
787
+ );
788
+ const handleResize = (0, import_react5.useCallback)(
789
+ (_context, size) => {
790
+ sizeRef.current = size;
791
+ updateMeshScale();
792
+ },
793
+ [updateMeshScale]
794
+ );
795
+ const { containerRef } = useScene({
796
+ camera: { type: "orthographic", position: [0, 0, 10], near: 0.1, far: 100 },
797
+ onCreate: handleCreate,
798
+ onRender: handleRender,
799
+ onResize: handleResize
800
+ });
801
+ const showTimeline = (0, import_react5.useRef)(null);
802
+ const hideTimeline = (0, import_react5.useRef)(null);
803
+ const transitionTimeline = (0, import_react5.useRef)(null);
804
+ const timelineParams = (0, import_react5.useMemo)(
805
+ () => ({
806
+ tileAmplitude: sanitizedValues.tileAmplitude,
807
+ gradientAmplitude: sanitizedValues.gradientAmplitude,
808
+ gradientOffset: sanitizedValues.gradientOffset,
809
+ tileOffsetX: sanitizedValues.tileOffsetX,
810
+ duration: sanitizedValues.duration
811
+ }),
812
+ [
813
+ sanitizedValues.duration,
814
+ sanitizedValues.gradientAmplitude,
815
+ sanitizedValues.gradientOffset,
816
+ sanitizedValues.tileAmplitude,
817
+ sanitizedValues.tileOffsetX
818
+ ]
819
+ );
820
+ const primeShowAnimation = (0, import_react5.useCallback)(() => {
821
+ const uniforms = shaderUniforms.current;
822
+ uniforms.uTileProgressHorizontal.value = 1 + timelineParams.tileAmplitude * 0.5;
823
+ uniforms.uGradientProgress.value = 1 + timelineParams.gradientOffset;
824
+ uniforms.uBlueProgress.value = 1 + timelineParams.tileOffsetX;
825
+ uniforms.uSaturation.value = 1;
826
+ uniforms.uWhiteTileStrength.value = 0;
827
+ }, [
828
+ timelineParams.gradientOffset,
829
+ timelineParams.tileAmplitude,
830
+ timelineParams.tileOffsetX
831
+ ]);
832
+ const buildTimelines = (0, import_react5.useCallback)(() => {
833
+ const uniforms = shaderUniforms.current;
834
+ const glitchDuration = sanitizedRef.current.duration;
835
+ const desiredShowTotal = glitchDuration * (SHOW_BASE_DURATION / SHOW_PRIMARY_DURATION);
836
+ const desiredHideTotal = glitchDuration * (HIDE_BASE_DURATION / SHOW_PRIMARY_DURATION);
837
+ const showScale = desiredShowTotal / SHOW_BASE_DURATION;
838
+ const hideScale = desiredHideTotal / HIDE_BASE_DURATION;
839
+ const showAt = (time) => time / SHOW_BASE_DURATION * desiredShowTotal;
840
+ const hideAt = (time) => time / HIDE_BASE_DURATION * desiredHideTotal;
841
+ showTimeline.current?.kill();
842
+ hideTimeline.current?.kill();
843
+ transitionTimeline.current?.kill();
844
+ const showTl = import_gsap.gsap.timeline({ paused: true });
845
+ showTl.add(() => {
846
+ animationVisibleRef.current = true;
847
+ updateVisibility();
848
+ }, 0);
849
+ showTl.fromTo(
850
+ uniforms.uTileProgressHorizontal,
851
+ { value: 1 + timelineParams.tileAmplitude * 0.5 },
852
+ {
853
+ value: -timelineParams.tileAmplitude * 0.5,
854
+ duration: glitchDuration,
855
+ ease: "sine.inOut"
856
+ },
857
+ 0
858
+ );
859
+ showTl.fromTo(
860
+ uniforms.uGradientProgress,
861
+ { value: 1 + timelineParams.gradientOffset },
862
+ {
863
+ value: -timelineParams.gradientOffset * 0.5 - timelineParams.gradientAmplitude,
864
+ duration: 0.6 * showScale,
865
+ ease: "sine.inOut"
866
+ },
867
+ showAt(0.1)
868
+ );
869
+ showTl.fromTo(
870
+ uniforms.uBlueProgress,
871
+ { value: 1 + timelineParams.tileOffsetX },
872
+ {
873
+ value: -timelineParams.tileOffsetX * 0.5 - timelineParams.gradientAmplitude,
874
+ duration: 0.6 * showScale,
875
+ ease: "sine.inOut"
876
+ },
877
+ showAt(0.125)
878
+ );
879
+ showTl.fromTo(
880
+ uniforms.uSaturation,
881
+ { value: 1 },
882
+ { value: 1.01, duration: 0.52 * showScale, ease: "sine.inOut" },
883
+ 0
884
+ );
885
+ showTl.fromTo(
886
+ uniforms.uSaturation,
887
+ { value: 1 },
888
+ { value: 2.5, duration: 0.1 * showScale, ease: "sine.inOut" },
889
+ showAt(0.32)
890
+ );
891
+ showTl.fromTo(
892
+ uniforms.uSaturation,
893
+ { value: 2.5 },
894
+ { value: 1, duration: 1.8 * showScale, ease: "sine.out" },
895
+ showAt(0.92)
896
+ );
897
+ showTl.fromTo(
898
+ uniforms.uWhiteTileStrength,
899
+ { value: 0 },
900
+ { value: 0.1, duration: 1 * showScale, ease: "sine.inOut" },
901
+ showAt(0.3)
902
+ );
903
+ const hideTl = import_gsap.gsap.timeline({ paused: true });
904
+ hideTl.fromTo(
905
+ uniforms.uWhiteTileStrength,
906
+ { value: 0.1 },
907
+ { value: 0, duration: 1 * hideScale, ease: "sine.inOut" },
908
+ 0
909
+ );
910
+ hideTl.fromTo(
911
+ uniforms.uSaturation,
912
+ { value: 1 },
913
+ { value: 1.5, duration: 0.4 * hideScale, ease: "sine.inOut" },
914
+ hideAt(0.4)
915
+ );
916
+ hideTl.fromTo(
917
+ uniforms.uSaturation,
918
+ { value: 1.5 },
919
+ { value: 1, duration: 1 * hideScale, ease: "sine.inOut" },
920
+ hideAt(0.8)
921
+ );
922
+ hideTl.fromTo(
923
+ uniforms.uBlueProgress,
924
+ {
925
+ value: -timelineParams.tileOffsetX * 0.5 - timelineParams.gradientAmplitude
926
+ },
927
+ {
928
+ value: 1 + timelineParams.tileOffsetX,
929
+ duration: 0.6 * hideScale,
930
+ ease: "sine.inOut"
931
+ },
932
+ hideAt(0.2)
933
+ );
934
+ hideTl.fromTo(
935
+ uniforms.uTileProgressHorizontal,
936
+ { value: -timelineParams.tileAmplitude * 0.5 },
937
+ {
938
+ value: 1 + timelineParams.tileAmplitude * 0.5,
939
+ duration: 0.9 * hideScale,
940
+ ease: "sine.inOut"
941
+ },
942
+ hideAt(0.2)
943
+ );
944
+ hideTl.fromTo(
945
+ uniforms.uGradientProgress,
946
+ {
947
+ value: -timelineParams.gradientOffset * 0.5 - timelineParams.gradientAmplitude
948
+ },
949
+ {
950
+ value: 1 + timelineParams.gradientOffset,
951
+ duration: 0.6 * hideScale,
952
+ ease: "sine.inOut"
953
+ },
954
+ hideAt(0.225)
955
+ );
956
+ hideTl.add(() => {
957
+ animationVisibleRef.current = false;
958
+ updateVisibility();
959
+ onHideDone?.();
960
+ }, hideAt(HIDE_BASE_DURATION));
961
+ showTl.call(
962
+ () => {
963
+ onShowDone?.();
964
+ },
965
+ void 0,
966
+ showAt(0.65)
967
+ );
968
+ showTimeline.current = showTl;
969
+ hideTimeline.current = hideTl;
970
+ }, [onHideDone, onShowDone, timelineParams, updateVisibility]);
971
+ (0, import_react5.useEffect)(() => {
972
+ const uniforms = shaderUniforms.current;
973
+ uniforms.tDiffuse.value = diffuseTexture;
974
+ if (gradientTextureRef.current) {
975
+ uniforms.tGradient.value = gradientTextureRef.current;
976
+ }
977
+ uniforms.uTileAmplitude.value = sanitizedValues.tileAmplitude;
978
+ uniforms.uTileOffset.value.set(
979
+ sanitizedValues.tileOffsetX,
980
+ sanitizedValues.tileOffsetY
981
+ );
982
+ uniforms.uTileFrequency.value.set(
983
+ sanitizedValues.tileFrequencyX,
984
+ sanitizedValues.tileFrequencyY
985
+ );
986
+ uniforms.uWaveAmplitude.value = sanitizedValues.waveAmplitude;
987
+ uniforms.uWaveProgress.value = sanitizedValues.waveProgress;
988
+ uniforms.uWaveStrength.value.set(
989
+ sanitizedValues.waveStrengthX,
990
+ sanitizedValues.waveStrengthY
991
+ );
992
+ uniforms.uGradientProgress.value = sanitizedValues.gradientProgress;
993
+ uniforms.uGradientOffset.value = sanitizedValues.gradientOffset;
994
+ uniforms.uGradientAmplitude.value = sanitizedValues.gradientAmplitude;
995
+ uniforms.uBlueProgress.value = sanitizedValues.blueProgress;
996
+ uniforms.uBlueAmplitude.value = sanitizedValues.blueAmplitude;
997
+ uniforms.uWhiteTileChances.value = sanitizedValues.whiteTileChances;
998
+ uniforms.uWhiteTileFrequency.value = sanitizedValues.whiteTileFrequency;
999
+ uniforms.uWhiteTileStrength.value = sanitizedValues.whiteTileStrength;
1000
+ uniforms.uSaturation.value = sanitizedValues.saturation;
1001
+ uniforms.uTileProgressVertical.value = BASE_TRANSITION_PROGRESS;
1002
+ updateMeshScale();
1003
+ updateVisibility();
1004
+ }, [diffuseTexture, sanitizedValues, updateMeshScale, updateVisibility]);
1005
+ (0, import_react5.useEffect)(() => {
1006
+ buildTimelines();
1007
+ return () => {
1008
+ showTimeline.current?.kill();
1009
+ hideTimeline.current?.kill();
1010
+ transitionTimeline.current?.kill();
1011
+ };
1012
+ }, [buildTimelines]);
1013
+ (0, import_react5.useEffect)(() => {
1014
+ const mesh = assetsRef.current?.mesh;
1015
+ if (mesh) {
1016
+ mesh.visible = sanitizedValues.debug || animationVisibleRef.current;
1017
+ }
1018
+ }, [sanitizedValues.debug]);
1019
+ const lastShowSignal = (0, import_react5.useRef)(settings.showSignal);
1020
+ (0, import_react5.useEffect)(() => {
1021
+ if (settings.showSignal === lastShowSignal.current) {
1022
+ return;
1023
+ }
1024
+ lastShowSignal.current = settings.showSignal;
1025
+ hideTimeline.current?.pause(0);
1026
+ primeShowAnimation();
1027
+ showTimeline.current?.seek(0).play();
1028
+ }, [primeShowAnimation, settings.showSignal]);
1029
+ const lastHideSignal = (0, import_react5.useRef)(settings.hideSignal);
1030
+ (0, import_react5.useEffect)(() => {
1031
+ if (settings.hideSignal === lastHideSignal.current) {
1032
+ return;
1033
+ }
1034
+ lastHideSignal.current = settings.hideSignal;
1035
+ showTimeline.current?.pause(0);
1036
+ hideTimeline.current?.seek(0).play();
1037
+ }, [settings.hideSignal]);
1038
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1039
+ "div",
1040
+ {
1041
+ ref: containerRef,
1042
+ className,
1043
+ style: {
1044
+ width: width ?? "100%",
1045
+ height: height ?? "100%",
1046
+ ...style
1047
+ },
1048
+ ...divProps
1049
+ }
1050
+ );
1051
+ }
1052
+ function createDiffuseTexture() {
1053
+ const size = 256;
1054
+ const data = new Uint8Array(size * size * 4);
1055
+ for (let y = 0; y < size; y += 1) {
1056
+ for (let x = 0; x < size; x += 1) {
1057
+ const i = (y * size + x) * 4;
1058
+ const stripe = Math.sin(y / size * Math.PI * 8) * 0.5 + 0.5;
1059
+ const tint = 0.25 + Math.sin(x / size * Math.PI * 2) * 0.15;
1060
+ const base = THREE5.MathUtils.clamp(stripe * 0.7 + tint, 0, 1);
1061
+ data[i] = base * 255;
1062
+ data[i + 1] = base * 200;
1063
+ data[i + 2] = base * 150;
1064
+ data[i + 3] = 255;
1065
+ }
1066
+ }
1067
+ const texture = new THREE5.DataTexture(data, size, size, THREE5.RGBAFormat);
1068
+ texture.needsUpdate = true;
1069
+ texture.colorSpace = THREE5.SRGBColorSpace;
1070
+ texture.wrapS = THREE5.RepeatWrapping;
1071
+ texture.wrapT = THREE5.RepeatWrapping;
1072
+ texture.magFilter = THREE5.LinearFilter;
1073
+ texture.minFilter = THREE5.LinearMipmapLinearFilter;
1074
+ texture.generateMipmaps = true;
1075
+ return texture;
1076
+ }
561
1077
  // Annotate the CommonJS export names for ESM import in node:
562
1078
  0 && (module.exports = {
563
1079
  FractalFlower,
1080
+ MenuGlitch,
564
1081
  OranoParticles,
565
1082
  ShaderArt
566
1083
  });