import React, { useState, useEffect, useRef } from 'react'; import * as THREE from 'three'; /** * PROJECT: HYPER_FLUX * "The Digital Mercury Engine" * * * ARCHITECTURE: * - Visuals: Pure GLSL Raymarching (SDF) for Metaball liquid physics. * - Material: Procedural Liquid Chrome with iridescence. * - Audio: Granular Glitch Synthesis (Industrial/Cyber). */ // --- 1. THE GLITCH AUDIO ENGINE --- class HyperAudio { constructor() { this.ctx = null; this.master = null; this.isSetup = false; this.frame = 0; } async setup() { if (this.isSetup) return; const AC = window.AudioContext || window.webkitAudioContext; if (!AC) return; this.ctx = new AC(); // Master Bus (Heavy Compression for that "Pumping" sound) this.master = this.ctx.createGain(); this.master.gain.value = 0.5; const comp = this.ctx.createDynamicsCompressor(); comp.threshold.value = -20; comp.ratio.value = 12; comp.attack.value = 0.003; // Bitcrusher effect for texture this.shaper = this.ctx.createWaveShaper(); this.shaper.curve = this.makeDistortionCurve(400); this.master.connect(this.shaper); this.shaper.connect(comp); comp.connect(this.ctx.destination); // Start the "Dark Ambience" this.spawnDrone(55); // A1 this.spawnDrone(110); // A2 this.isSetup = true; } makeDistortionCurve(amount) { const k = typeof amount === 'number' ? amount : 50; const n_samples = 44100; const curve = new Float32Array(n_samples); for (let i = 0; i < n_samples; ++i) { const x = (i * 2) / n_samples - 1; curve[i] = ((3 + k) * x * 20 * (Math.PI / 180)) / (Math.PI + k * Math.abs(x)); } return curve; } spawnDrone(freq) { const osc = this.ctx.createOscillator(); osc.type = 'sawtooth'; osc.frequency.value = freq; const gain = this.ctx.createGain(); gain.gain.value = 0.05; const filter = this.ctx.createBiquadFilter(); filter.type = 'lowpass'; filter.frequency.value = 200; filter.Q.value = 10; osc.connect(filter); filter.connect(gain); gain.connect(this.master); osc.start(); // LFO to modulate filter (The "Wub") const lfo = this.ctx.createOscillator(); lfo.frequency.value = 0.1; const lfoGain = this.ctx.createGain(); lfoGain.gain.value = 100; lfo.connect(lfoGain); lfoGain.connect(filter.frequency); lfo.start(); } triggerGlitch(intensity) { if (!this.ctx) return; const t = this.ctx.currentTime; // Metallic Impact const osc = this.ctx.createOscillator(); osc.frequency.value = 200 + Math.random() * 800; osc.type = 'square'; const mod = this.ctx.createOscillator(); mod.frequency.value = 50 + Math.random() * 50; // Ring mod frequency mod.type = 'sawtooth'; const modGain = this.ctx.createGain(); modGain.gain.value = 500; mod.connect(modGain); modGain.connect(osc.frequency); const gain = this.ctx.createGain(); gain.gain.setValueAtTime(0.5 * intensity, t); gain.gain.exponentialRampToValueAtTime(0.01, t + 0.1); osc.connect(gain); gain.connect(this.master); osc.start(t); mod.start(t); osc.stop(t + 0.15); mod.stop(t + 0.15); } } const audio = new HyperAudio(); // --- 2. RAYMARCHING SHADER (The Visual Engine) --- // This shader implements a Signed Distance Field (SDF) to render liquid metal. const HyperShader = { uniforms: { uTime: { value: 0 }, uResolution: { value: new THREE.Vector2() }, uHandL: { value: new THREE.Vector3(10, 10, 0) }, uHandR: { value: new THREE.Vector3(-10, 10, 0) }, uColorA: { value: new THREE.Color('#ff0055') }, // Neon Pink uColorB: { value: new THREE.Color('#00ffff') } // Cyan }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4(position, 1.0); } `, fragmentShader: ` uniform float uTime; uniform vec2 uResolution; uniform vec3 uHandL; uniform vec3 uHandR; uniform vec3 uColorA; uniform vec3 uColorB; varying vec2 vUv; // --- SDF FUNCTIONS --- // Smooth Union (The "Liquid" effect) float smin(float a, float b, float k) { float h = max(k - abs(a - b), 0.0) / k; return min(a, b) - h * h * k * (1.0 / 4.0); } float sdSphere(vec3 p, float s) { return length(p) - s; } // Noise float hash(float n) { return fract(sin(n) * 43758.5453); } float noise(vec3 x) { vec3 p = floor(x); vec3 f = fract(x); f = f * f * (3.0 - 2.0 * f); float n = p.x + p.y * 57.0 + 113.0 * p.z; return mix(mix(mix(hash(n + 0.0), hash(n + 1.0), f.x), mix(hash(n + 57.0), hash(n + 58.0), f.x), f.y), mix(mix(hash(n + 113.0), hash(n + 114.0), f.x), mix(hash(n + 170.0), hash(n + 171.0), f.x), f.y), f.z); } // --- SCENE MAPPING --- float map(vec3 p) { // Base warping float warp = noise(p * 0.5 + uTime * 0.5) * 0.5; // Central Sphere (The "Core") vec3 pCore = p; pCore.y += sin(uTime) * 0.5; float dCore = sdSphere(pCore, 1.5 + warp); // Hand Magnetic Orbs // Convert normalized screen coords to roughly -5..5 world space logic vec3 hL = vec3(uHandL.x * 0.5, uHandL.y * 0.5, 0.0); vec3 hR = vec3(uHandR.x * 0.5, uHandR.y * 0.5, 0.0); float dHandL = sdSphere(p - hL, 1.2); float dHandR = sdSphere(p - hR, 1.2); // Liquid Merge float d = smin(dCore, dHandL, 1.5); d = smin(d, dHandR, 1.5); return d; } // --- RAYMARCHING --- vec3 calcNormal(vec3 p) { const float eps = 0.001; const vec2 h = vec2(eps,0); return normalize(vec3(map(p+h.xyy) - map(p-h.xyy), map(p+h.yxy) - map(p-h.yxy), map(p+h.yyx) - map(p-h.yyx))); } void main() { // Correct aspect ratio vec2 uv = (vUv - 0.5) * 2.0; uv.x *= uResolution.x / uResolution.y; // Camera setup vec3 ro = vec3(0.0, 0.0, 6.0); // Ray origin vec3 rd = normalize(vec3(uv, -1.0)); // Ray direction // March float t = 0.0; float d = 0.0; int i; for(i = 0; i < 64; i++) { vec3 p = ro + rd * t; d = map(p); if(d < 0.001 || t > 20.0) break; t += d; } // Coloring vec3 col = vec3(0.05, 0.05, 0.1); // Dark Void Background if(t < 20.0) { vec3 p = ro + rd * t; vec3 n = calcNormal(p); vec3 ref = reflect(rd, n); // Lighting vec3 lightPos = vec3(5.0, 5.0, 5.0); vec3 lightDir = normalize(lightPos - p); float diff = max(dot(n, lightDir), 0.0); float spec = pow(max(dot(ref, lightDir), 0.0), 32.0); // Iridescence based on normal float fresnel = pow(1.0 - max(dot(n, -rd), 0.0), 2.0); vec3 baseColor = mix(uColorA, uColorB, n.y * 0.5 + 0.5); // Chrome reflection fake vec3 chrome = vec3(0.5) + 0.5 * cos(vec3(0.0, 2.0, 4.0) + ref.y * 5.0 + uTime); col = baseColor * (diff * 0.5 + 0.5) + chrome * fresnel * 2.0 + vec3(spec); } // Post-processing: Vignette & Glow float dCenter = length(vUv - 0.5); col *= 1.0 - dCenter * 0.5; gl_FragColor = vec4(col, 1.0); } ` }; // --- 3. THE WORLD COMPONENT --- const HyperWorld = ({ lHand, rHand }) => { const mountRef = useRef(null); const materialRef = useRef(null); useEffect(() => { if (!mountRef.current) return; // INIT const scene = new THREE.Scene(); const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); const renderer = new THREE.WebGLRenderer({ antialias: false }); // Antialias off for heavy shader renderer.setSize(window.innerWidth, window.innerHeight); mountRef.current.appendChild(renderer.domElement); // FULLSCREEN QUAD const geo = new THREE.PlaneGeometry(2, 2); const mat = new THREE.ShaderMaterial({ uniforms: HyperShader.uniforms, vertexShader: HyperShader.vertexShader, fragmentShader: HyperShader.fragmentShader }); materialRef.current = mat; const quad = new THREE.Mesh(geo, mat); scene.add(quad); // ANIMATION LOOP const clock = new THREE.Clock(); const animate = () => { requestAnimationFrame(animate); const t = clock.getElapsedTime(); if (materialRef.current) { materialRef.current.uniforms.uTime.value = t; materialRef.current.uniforms.uResolution.value.set(window.innerWidth, window.innerHeight); // Hands are passed via useEffect below, but smooth damping could happen here } renderer.render(scene, camera); }; animate(); // RESIZE const handleResize = () => { renderer.setSize(window.innerWidth, window.innerHeight); if(materialRef.current) { materialRef.current.uniforms.uResolution.value.set(window.innerWidth, window.innerHeight); } }; window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); if(mountRef.current) mountRef.current.innerHTML = ''; }; }, []); // Update Uniforms useEffect(() => { if (!materialRef.current) return; // Convert Hand (0..1) to Shader Space (-10..10 approx) if(lHand) { // Invert X for mirror feel materialRef.current.uniforms.uHandL.value.set((0.5 - lHand.x) * 16, (0.5 - lHand.y) * 10, 0); } else { materialRef.current.uniforms.uHandL.value.set(100, 100, 0); } if(rHand) { materialRef.current.uniforms.uHandR.value.set((0.5 - rHand.x) * 16, (0.5 - rHand.y) * 10, 0); } else { materialRef.current.uniforms.uHandR.value.set(100, 100, 0); } }, [lHand, rHand]); return
; }; // --- APP CONTAINER --- export default function HyperFlux() { const [started, setStarted] = useState(false); const [lHand, setLHand] = useState(null); const [rHand, setRHand] = useState(null); const videoRef = useRef(null); useEffect(() => { if(!started) return; const init = async () => { const s1 = document.createElement('script'); s1.src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js"; const s2 = document.createElement('script'); s2.src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"; document.body.append(s1, s2); await new Promise(r => setTimeout(r, 1000)); const hands = new window.Hands({locateFile: f => `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${f}`}); hands.setOptions({ maxNumHands: 2, modelComplexity: 1, minDetectionConfidence: 0.5 }); let lastY = 0; hands.onResults(res => { let lh = null, rh = null; if(res.multiHandLandmarks) { res.multiHandLandmarks.forEach(lm => { const x = lm[9].x; // Normalized const y = lm[9].y; const z = lm[9].z; // Simple Velocity Check for Glitch Audio const deltaY = Math.abs(y - lastY); if(deltaY > 0.05) audio.triggerGlitch(deltaY * 5); lastY = y; // Assign Left/Right roughly based on screen side if(x > 0.5) lh = {x,y,z}; // Mirrored else rh = {x,y,z}; }); } setLHand(lh); setRHand(rh); }); const cam = new window.Camera(videoRef.current, { onFrame: async () => await hands.send({image: videoRef.current}), width: 640, height: 480 }); cam.start(); await audio.setup(); }; init(); }, [started]); return (WARNING: HIGH GPU USAGE. AUDIO REQUIRED.