diff --git a/compiler/ds-codegen/src/js_emitter.rs b/compiler/ds-codegen/src/js_emitter.rs index 73f0728..bd44a51 100644 --- a/compiler/ds-codegen/src/js_emitter.rs +++ b/compiler/ds-codegen/src/js_emitter.rs @@ -3400,6 +3400,7 @@ const DS = (() => { } function _playTone(freq, durationMs, type) { + if (!freq || freq <= 0 || !durationMs || durationMs <= 0) return; var ctx = _ensureAudio(); var osc = ctx.createOscillator(); var gain = ctx.createGain(); @@ -3414,6 +3415,7 @@ const DS = (() => { } function _playNoise(durationMs, vol) { + if (!durationMs || durationMs <= 0) return; var ctx = _ensureAudio(); var bufSize = ctx.sampleRate * (durationMs / 1000); var buf = ctx.createBuffer(1, bufSize, ctx.sampleRate); diff --git a/examples/beats-viewer.ds b/examples/beats-viewer.ds new file mode 100644 index 0000000..40c0962 --- /dev/null +++ b/examples/beats-viewer.ds @@ -0,0 +1,72 @@ +-- DreamStack Beats Viewer (Spectator) +-- Watches the step sequencer live via streaming relay. +-- Shows the beat grid state from a different browser tab. +-- +-- Run with: +-- Tab 1: cargo run -p ds-stream (relay on :9100) +-- Tab 2: dreamstack dev examples/step-sequencer.ds (player) +-- Tab 3: dreamstack dev examples/beats-viewer.ds --port 3001 (viewer) + +import { Badge } from "../registry/components/badge" + +-- Connect to the beats stream +let beats = stream from "ws://localhost:9100/stream/beats" + +view viewer = column [ + text "๐Ÿ‘๏ธ Beats Spectator" { variant: "title" } + text "Watching the step sequencer live via relay" { variant: "subtitle" } + + row [ + Badge { label: "LIVE ๐Ÿ”ด", variant: "error" } + Badge { label: "BPM: {beats.bpm}", variant: "info" } + Badge { label: "Step: {beats.step}", variant: "warning" } + ] + + -- Playhead indicator + row [ + text " " { variant: "muted" } + for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] -> + text (if i == beats.step then "โ–ผ" else "ยท") { variant: "muted" } + ] + + -- Kick row (read-only) + row [ + text "KICK " { variant: "caption" } + for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] -> + text (if beats.kick then "โ—" else "โ—‹") { + variant: (if i == beats.step then "warning" else "muted") + } + ] + + -- Snare row + row [ + text "SNRE " { variant: "caption" } + for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] -> + text (if beats.snare then "โ—" else "โ—‹") { + variant: (if i == beats.step then "warning" else "muted") + } + ] + + -- HiHat row + row [ + text "HHAT " { variant: "caption" } + for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] -> + text (if beats.hihat then "โ—" else "โ—‹") { + variant: (if i == beats.step then "warning" else "muted") + } + ] + + -- Bass row + row [ + text "BASS " { variant: "caption" } + for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] -> + text (if beats.bass then "โ—" else "โ—‹") { + variant: (if i == beats.step then "warning" else "muted") + } + ] + + when beats.playing -> text "โ–ถ Playing" { variant: "muted" } + else -> text "โธ Paused" { variant: "muted" } + + text "View-only โ€ข beat pattern received via relay" { variant: "muted" } +] diff --git a/examples/game-pong.ds b/examples/game-pong.ds index 72ff504..8815026 100644 --- a/examples/game-pong.ds +++ b/examples/game-pong.ds @@ -65,6 +65,10 @@ every 33 -> bvy = if ballX > 604 then -2 else bvy every 33 -> play_tone(if ballX < 26 then (if ballY > p1y then (if ballY < p1y + 80 then 880 else 0) else 0) else 0, 60) every 33 -> play_tone(if ballX > 566 then (if ballY > p2y then (if ballY < p2y + 80 then 660 else 0) else 0) else 0, 60) +-- Sound effects: scoring +every 33 -> play_tone(if ballX < -8 then 220 else 0, 200, "sawtooth") +every 33 -> play_tone(if ballX > 604 then 440 else 0, 200, "sawtooth") + -- Stream for viewers stream pong on "ws://localhost:9100/peer/pong" { mode: signal,