SOURCE / PINNED RELEASE
Made of little things.
Soybert 3D
- Release
- 4bf80e758af1…
- Author-recorded commit
- 298fa2d0e8b1…
- License
- LICENSE
- Author’s source reference
- nostr://npub1n8ga89w8h6tvwamxusfyzexw8gjy84yxu9rxgnmk955cxtml4ujswzxydd/wss%3A%2F%2Fgit.napplet.soy%2F/n-9021e1b6a96
Archive hash verified: 7083223a53bbd320…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
/** Short synthesized effects: no media files, downloads, or autoplay. */
export class Sound {
enabled = true;
private context?: AudioContext;
unlock() {
if (!this.enabled) return;
try { this.context ??= new AudioContext(); void this.context.resume().catch(() => undefined); } catch { /* silent fallback */ }
}
play(kind: 'jump' | 'shoot' | 'land' | 'celebrate') {
if (!this.enabled || !this.context || this.context.state !== 'running') return;
const c = this.context, now = c.currentTime;
if (kind === 'shoot') {
const buffer = c.createBuffer(1, c.sampleRate * .19, c.sampleRate);
const channel = buffer.getChannelData(0);
for (let i = 0; i < channel.length; i++) channel[i] = (Math.random() * 2 - 1) * (1 - i / channel.length) ** 3;
const source = c.createBufferSource(); source.buffer = buffer;
const filter = c.createBiquadFilter(); filter.type = 'lowpass'; filter.frequency.value = 1700;
const gain = c.createGain(); gain.gain.value = .27;
source.connect(filter).connect(gain).connect(c.destination); source.start();
source.onended = () => { source.disconnect(); filter.disconnect(); gain.disconnect(); };
}
const notes = kind === 'celebrate' ? [523, 659, 784, 1047] : [kind === 'jump' ? 250 : kind === 'land' ? 90 : 70];
notes.forEach((frequency, i) => {
const oscillator = c.createOscillator(), gain = c.createGain(), start = now + i * .105;
oscillator.type = kind === 'shoot' ? 'triangle' : 'sine';
oscillator.frequency.setValueAtTime(frequency, start);
oscillator.frequency.exponentialRampToValueAtTime(kind === 'jump' ? 580 : frequency * .7, start + .17);
gain.gain.setValueAtTime(.001, start); gain.gain.linearRampToValueAtTime(.12, start + .012); gain.gain.exponentialRampToValueAtTime(.001, start + .2);
oscillator.connect(gain).connect(c.destination); oscillator.start(start); oscillator.stop(start + .22);
oscillator.onended = () => { oscillator.disconnect(); gain.disconnect(); };
});
}
dispose() { void this.context?.close().catch(() => undefined); }
}
