Initial Commit
Commit pertama, memindahkan repository dari github ke gitea.
This commit is contained in:
commit
13a47fbebf
41 files changed
+12327
No files matched your search
@@ -0,0 +1,113 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Volume2, VolumeX } from "lucide-react";
|
||||
|
||||
export default function CosmicAudioToggle() {
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const audioCtxRef = useRef<AudioContext | null>(null);
|
||||
const masterGainRef = useRef<GainNode | null>(null);
|
||||
const osc1Ref = useRef<OscillatorNode | null>(null);
|
||||
const osc2Ref = useRef<OscillatorNode | null>(null);
|
||||
|
||||
const toggleSound = () => {
|
||||
if (isPlaying) {
|
||||
if (masterGainRef.current && audioCtxRef.current) {
|
||||
masterGainRef.current.gain.setTargetAtTime(
|
||||
0,
|
||||
audioCtxRef.current.currentTime,
|
||||
0.5
|
||||
);
|
||||
setTimeout(() => {
|
||||
setIsPlaying(false);
|
||||
}, 500);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const AudioCtx =
|
||||
window.AudioContext ||
|
||||
(window as unknown as { webkitAudioContext: typeof AudioContext })
|
||||
.webkitAudioContext;
|
||||
const ctx = audioCtxRef.current || new AudioCtx();
|
||||
audioCtxRef.current = ctx;
|
||||
|
||||
if (ctx.state === "suspended") {
|
||||
ctx.resume();
|
||||
}
|
||||
|
||||
const masterGain = ctx.createGain();
|
||||
masterGain.gain.setValueAtTime(0, ctx.currentTime);
|
||||
masterGain.gain.linearRampToValueAtTime(0.08, ctx.currentTime + 1.5);
|
||||
masterGain.connect(ctx.destination);
|
||||
masterGainRef.current = masterGain;
|
||||
|
||||
// Lowpass filter for deep cosmic drone
|
||||
const filter = ctx.createBiquadFilter();
|
||||
filter.type = "lowpass";
|
||||
filter.frequency.setValueAtTime(140, ctx.currentTime);
|
||||
filter.Q.setValueAtTime(2, ctx.currentTime);
|
||||
filter.connect(masterGain);
|
||||
|
||||
// Oscillator 1: 55Hz sub drone
|
||||
const osc1 = ctx.createOscillator();
|
||||
osc1.type = "sine";
|
||||
osc1.frequency.setValueAtTime(55, ctx.currentTime);
|
||||
osc1.connect(filter);
|
||||
osc1.start();
|
||||
osc1Ref.current = osc1;
|
||||
|
||||
// Oscillator 2: 110.2Hz warm harmonic with slight detune
|
||||
const osc2 = ctx.createOscillator();
|
||||
osc2.type = "triangle";
|
||||
osc2.frequency.setValueAtTime(110.3, ctx.currentTime);
|
||||
const osc2Gain = ctx.createGain();
|
||||
osc2Gain.gain.setValueAtTime(0.03, ctx.currentTime);
|
||||
osc2.connect(osc2Gain);
|
||||
osc2Gain.connect(filter);
|
||||
osc2.start();
|
||||
osc2Ref.current = osc2;
|
||||
|
||||
setIsPlaying(true);
|
||||
} catch {
|
||||
// Fallback gracefully if Web Audio is blocked
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (audioCtxRef.current && audioCtxRef.current.state !== "closed") {
|
||||
try {
|
||||
audioCtxRef.current.close();
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={toggleSound}
|
||||
title={isPlaying ? "Mute Deep Space Ambience" : "Enable Deep Space Ambience"}
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-full glass-panel hover:border-indigo-500/40 text-xs font-mono tracking-wider text-slate-300 transition-all duration-300 hover:text-white group"
|
||||
aria-label="Toggle Cosmic Soundscape"
|
||||
>
|
||||
{isPlaying ? (
|
||||
<>
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-500"></span>
|
||||
</span>
|
||||
<Volume2 className="w-3.5 h-3.5 text-cyan-400 group-hover:scale-110 transition-transform" />
|
||||
<span className="hidden sm:inline text-[11px] text-cyan-300">AUDIO: RESONANCE ON</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<VolumeX className="w-3.5 h-3.5 text-slate-400 group-hover:scale-110 transition-transform" />
|
||||
<span className="hidden sm:inline text-[11px] text-slate-400">AUDIO: VOID</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user