Lobby: heavier dice sound

Low thump with a dull knock per bounce, fewer bounces, darker filter and
lower result cues.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJhXuLD2Z6hv3Wqeq9UL9K
This commit is contained in:
Claude
2026-10-23 18:47:35 +00:00
parent 2195ecce94
commit ce24a0ba6f
+33 -19
View File
@@ -30,30 +30,41 @@ const noiseBuffer = (c) => {
return noise return noise
} }
// one "tock" of a die hitting the table // one bounce of a heavy die on a wooden table: a low thump with a dull knock on top
const tock = (c, out, t, strength) => { const tock = (c, out, t, strength) => {
const src = c.createBufferSource() const src = c.createBufferSource()
src.buffer = noiseBuffer(c) src.buffer = noiseBuffer(c)
const f = c.createBiquadFilter() const f = c.createBiquadFilter()
f.type = 'bandpass' f.type = 'bandpass'
f.frequency.value = 900 + Math.random() * 3200 f.frequency.value = 260 + Math.random() * 900
f.Q.value = 1.2 + Math.random() * 2 f.Q.value = 0.7 + Math.random()
const g = c.createGain() const g = c.createGain()
g.gain.setValueAtTime(0.0001, t) g.gain.setValueAtTime(0.0001, t)
g.gain.exponentialRampToValueAtTime(strength, t + 0.003) g.gain.exponentialRampToValueAtTime(strength, t + 0.004)
g.gain.exponentialRampToValueAtTime(0.0001, t + 0.04 + Math.random() * 0.04) g.gain.exponentialRampToValueAtTime(0.0001, t + 0.07 + Math.random() * 0.06)
src.connect(f).connect(g).connect(out) src.connect(f).connect(g).connect(out)
src.start(t, Math.random() * 0.1) src.start(t, Math.random() * 0.1)
src.stop(t + 0.12) src.stop(t + 0.2)
const o = c.createOscillator() // the weight: a sine that drops in pitch
o.type = 'sine'
o.frequency.setValueAtTime(130 + Math.random() * 40, t)
o.frequency.exponentialRampToValueAtTime(48, t + 0.14)
const og = c.createGain()
og.gain.setValueAtTime(0.0001, t)
og.gain.exponentialRampToValueAtTime(strength * 1.1, t + 0.006)
og.gain.exponentialRampToValueAtTime(0.0001, t + 0.16)
o.connect(og).connect(out)
o.start(t)
o.stop(t + 0.2)
} }
const tone = (c, out, t, freq, len, type = 'sine', vol = 0.25) => { const tone = (c, out, t, freq, len, type = 'triangle', vol = 0.25) => {
const o = c.createOscillator() const o = c.createOscillator()
o.type = type o.type = type
o.frequency.value = freq o.frequency.value = freq
const g = c.createGain() const g = c.createGain()
g.gain.setValueAtTime(0.0001, t) g.gain.setValueAtTime(0.0001, t)
g.gain.exponentialRampToValueAtTime(vol, t + 0.015) g.gain.exponentialRampToValueAtTime(vol, t + 0.02)
g.gain.exponentialRampToValueAtTime(0.0001, t + len) g.gain.exponentialRampToValueAtTime(0.0001, t + len)
o.connect(g).connect(out) o.connect(g).connect(out)
o.start(t) o.start(t)
@@ -67,21 +78,24 @@ export function playRoll(n, outcome) {
if (!c) return if (!c) return
const out = c.createGain() const out = c.createGain()
out.gain.value = sound.volume out.gain.value = sound.volume
out.connect(c.destination) const dull = c.createBiquadFilter() // takes the brightness off everything
dull.type = 'lowpass'
dull.frequency.value = 2200
const comp = c.createDynamicsCompressor()
out.connect(dull).connect(comp).connect(c.destination)
const t0 = c.currentTime + 0.02 const t0 = c.currentTime + 0.02
let end = 0 let end = 0
for (let i = 0; i < Math.min(n, 10); i++) { for (let i = 0; i < Math.min(n, 10); i++) {
const start = t0 + i * 0.09 let t = t0 + i * 0.11
let t = start for (let k = 0; k < 5; k++) { // fewer, heavier bounces that die away quickly
for (let k = 0; k < 6; k++) { // bounces get softer and further apart tock(c, out, t, 0.85 * Math.pow(0.55, k) * (0.75 + Math.random() * 0.25))
tock(c, out, t, 0.9 * Math.pow(0.62, k) * (0.7 + Math.random() * 0.3)) t += 0.07 + k * 0.05 + Math.random() * 0.03
t += 0.045 + k * 0.035 + Math.random() * 0.03
} }
end = Math.max(end, t) end = Math.max(end, t)
} }
const t1 = end + 0.12 const t1 = end + 0.1
if (outcome === 'crit_success') { tone(c, out, t1, 784, 0.35, 'sine', 0.22); tone(c, out, t1 + 0.12, 1175, 0.5, 'sine', 0.22); tone(c, out, t1 + 0.12, 1568, 0.5, 'sine', 0.08) } if (outcome === 'crit_success') { tone(c, out, t1, 196, 0.7, 'triangle', 0.3); tone(c, out, t1 + 0.16, 294, 0.8, 'triangle', 0.28); tone(c, out, t1 + 0.16, 392, 0.9, 'sine', 0.12) }
else if (outcome === 'success') tone(c, out, t1, 698, 0.3, 'sine', 0.2) else if (outcome === 'success') { tone(c, out, t1, 147, 0.5, 'triangle', 0.3); tone(c, out, t1, 220, 0.4, 'sine', 0.1) }
else if (outcome === 'failure') tone(c, out, t1, 196, 0.28, 'triangle', 0.22) else if (outcome === 'failure') tone(c, out, t1, 82, 0.55, 'triangle', 0.35)
else if (outcome === 'crit_failure') { tone(c, out, t1, 220, 0.3, 'sawtooth', 0.12); tone(c, out, t1 + 0.18, 147, 0.6, 'sawtooth', 0.14) } else if (outcome === 'crit_failure') { tone(c, out, t1, 98, 0.5, 'sawtooth', 0.14); tone(c, out, t1 + 0.22, 62, 1.0, 'sawtooth', 0.18) }
} }