Initial Commit

Commit pertama, memindahkan repository dari github ke gitea.
This commit is contained in:
dicky arya pratama committed 2026-11-04 17:18:53 +07:00
commit 13a47fbebf
41 files changed
+12327

No files matched your search

+113
View File
@@ -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>
);
}