// Shared helpers: cursor, audio, crosses bg // Exports to window: Cursor, useAudio, CrossesBg, Chrome, FloatingCross const { useState, useEffect, useRef, useMemo, useCallback } = React; // ==== AUDIO ENGINE ==== let _audioCtx = null; function getCtx() { if (!_audioCtx) { _audioCtx = new (window.AudioContext || window.webkitAudioContext)(); } if (_audioCtx.state === 'suspended') _audioCtx.resume(); return _audioCtx; } function play808(freq = 55, dur = 0.35, vol = 0.25) { try { const ctx = getCtx(); const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.type = 'sine'; osc.frequency.setValueAtTime(freq * 3, ctx.currentTime); osc.frequency.exponentialRampToValueAtTime(freq, ctx.currentTime + 0.08); gain.gain.setValueAtTime(vol, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + dur); osc.connect(gain).connect(ctx.destination); osc.start(); osc.stop(ctx.currentTime + dur); } catch (e) {} } function playClick() { try { const ctx = getCtx(); // short noise burst const buffer = ctx.createBuffer(1, ctx.sampleRate * 0.08, ctx.sampleRate); const data = buffer.getChannelData(0); for (let i = 0; i < data.length; i++) { data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / data.length, 3); } const src = ctx.createBufferSource(); src.buffer = buffer; const gain = ctx.createGain(); gain.gain.value = 0.12; const filter = ctx.createBiquadFilter(); filter.type = 'highpass'; filter.frequency.value = 2000; src.connect(filter).connect(gain).connect(ctx.destination); src.start(); } catch (e) {} } function playCrackle() { try { const ctx = getCtx(); const buffer = ctx.createBuffer(1, ctx.sampleRate * 0.3, ctx.sampleRate); const data = buffer.getChannelData(0); for (let i = 0; i < data.length; i++) { data[i] = (Math.random() > 0.985) ? (Math.random() * 2 - 1) * 0.7 : 0; } const src = ctx.createBufferSource(); src.buffer = buffer; const gain = ctx.createGain(); gain.gain.value = 0.18; src.connect(gain).connect(ctx.destination); src.start(); } catch (e) {} } function playHover() { try { const ctx = getCtx(); const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.type = 'square'; osc.frequency.value = 1800; gain.gain.setValueAtTime(0.03, ctx.currentTime); gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + 0.04); osc.connect(gain).connect(ctx.destination); osc.start(); osc.stop(ctx.currentTime + 0.04); } catch (e) {} } window.TP_Audio = { play808, playClick, playCrackle, playHover, getCtx }; // ==== CURSOR ==== function Cursor() { const cursorRef = useRef(null); const trailRef = useRef(null); const posRef = useRef({ x: 0, y: 0 }); const trailPosRef = useRef({ x: 0, y: 0 }); const [clicking, setClicking] = useState(false); useEffect(() => { const onMove = (e) => { posRef.current = { x: e.clientX, y: e.clientY }; if (cursorRef.current) { cursorRef.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px) translate(-50%, -50%)`; } }; const onDown = () => { setClicking(true); TP_Audio.playClick(); }; const onUp = () => setClicking(false); window.addEventListener('mousemove', onMove); window.addEventListener('mousedown', onDown); window.addEventListener('mouseup', onUp); let raf; const loop = () => { trailPosRef.current.x += (posRef.current.x - trailPosRef.current.x) * 0.18; trailPosRef.current.y += (posRef.current.y - trailPosRef.current.y) * 0.18; if (trailRef.current) { trailRef.current.style.transform = `translate(${trailPosRef.current.x}px, ${trailPosRef.current.y}px) translate(-50%, -50%)`; } raf = requestAnimationFrame(loop); }; loop(); return () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mousedown', onDown); window.removeEventListener('mouseup', onUp); cancelAnimationFrame(raf); }; }, []); const crossSvg = ( ); return ( <>
{crossSvg}
{crossSvg}
); } // ==== CHROME (top bar) ==== function Chrome({ nicheScore, screen }) { const [time, setTime] = useState(''); useEffect(() => { const upd = () => { const d = new Date(); const pad = (n) => String(n).padStart(2, '0'); setTime(`${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`); }; upd(); const t = setInterval(upd, 1000); return () => clearInterval(t); }, []); return (
REC ТЕМНЫЙ.ПРИНЦ.EXE
SCR / {screen} NICHE {String(nicheScore).padStart(3, '0')}% {time}
); } // ==== FLOATING CROSSES BG ==== function CrossesBg({ count = 24, seed = 0 }) { const crosses = useMemo(() => { const arr = []; let s = seed || 1; const rnd = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; }; for (let i = 0; i < count; i++) { arr.push({ left: rnd() * 100, top: rnd() * 100, size: 10 + rnd() * 40, rot: (rnd() - 0.5) * 40, opacity: 0.08 + rnd() * 0.35, char: rnd() > 0.7 ? '†︎' : (rnd() > 0.5 ? '✟︎' : '✝︎'), }); } return arr; }, [count, seed]); return (
{crosses.map((c, i) => ( {c.char} ))}
); } Object.assign(window, { Cursor, Chrome, CrossesBg, play808, playClick, playCrackle, playHover }); // ==== BG VIDEO ==== function BgVideo({ src = 'assets/overdose.mp4', opacity = 0.35, blur = 0 }) { const ref = useRef(null); useEffect(() => { const v = ref.current; if (!v) return; v.muted = true; // ensure muted for autoplay policy v.play().catch(() => {}); }, []); return (