SOTCD DJ Bot Setup Documentation
Overview
The DJ Bot is a headless Puppeteer-based automation that runs Strudel (live coding music environment) to generate Acid House audio for the Suns of the Cosmic Dust Twitch stream.
Infrastructure
Host Machine
- IP: 192.168.1.16 (Proxmox LXC container)
- Hostname: SOTCD streaming container
- SSH Access:
ssh -i ~/.ssh/github_ed25519 root@192.168.1.16
Directory Structure
/root/sunsofthecosmicdust/
βββ .env # Twitch credentials (TWITCH_STREAM_KEY, TWITCH_INGEST_URL)
βββ go-live.sh # Main stream launcher script
βββ dj-bot/
β βββ index.js # Puppeteer script that runs Strudel
β βββ package.json # Node.js dependencies
β βββ node_modules/ # Installed dependencies (puppeteer)
βββ website/ # GitHub Pages site (red40mademedoit/sunsofthecosmicdust)
Config Backup Location
- Local workspace:
/home/shdwdev/clawd/sunsofthecosmicdust/ - Remote:
/root/sunsofthecosmicdust/on 192.168.1.16
Dependencies Installed on 192.168.1.16
System Packages
apt-get install -y xvfb fluxbox xterm cmatrix pulseaudio \
libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \
libxrandr2 libgbm1 libasound2Node.js (via NVM)
# NVM installed at ~/.nvm
source ~/.nvm/nvm.sh
nvm install --lts # v24.13.0Puppeteer Chrome
cd ~/sunsofthecosmicdust/dj-bot
npm install
npx puppeteer browsers install chrome
# Chrome installed at: ~/.cache/puppeteer/chrome/linux-*/chrome-linux64/chromeStream Components
1. Xvfb (Virtual Display)
- Display:
:99 - Resolution:
1920x1080x24
2. Fluxbox (Window Manager)
- Runs on display :99
- Provides window management for xterm
3. Visual Layer (Pink & Green Matrix)
- Two xterm instances running cmatrix
- Left side: Green (
-C green) - Right side: Magenta (
-C magenta)
4. DJ Bot (Strudel Audio)
- Headless Chrome via Puppeteer (
headless: true) - Navigates to https://strudel.cc/?panel=repl
- Injects Acid House code into the REPL
- Key Chrome args for audio:
--autoplay-policy=no-user-gesture-required--no-sandbox--disable-setuid-sandbox
5. PulseAudio
- Virtual sink:
virtual_speaker - Monitor source:
virtual_speaker.monitor - Start with:
pulseaudio --start --exit-idle-time=-1 - Create sink:
pactl load-module module-null-sink sink_name=virtual_speaker
6. FFmpeg (Stream Encoder)
- Video: x11grab from :99
- Audio: PulseAudio monitor OR lavfi sine wave (drone fallback)
- Output: RTMP to Twitch
go-live.sh Script Flow
- Load environment variables from
.env - Start Xvfb on :99
- Start Fluxbox window manager
- Launch dual xterm windows with cmatrix (Pink & Green)
- Start DJ Bot (node index.js)
- Start FFmpeg to capture and stream
Troubleshooting
DJ Bot Crashes
- Check
/tmp/dj-bot.logfor errors - Common issue: Missing X server β ensure
headless: truein index.js - Missing Chrome libs β reinstall dependencies
No Audio
- Verify PulseAudio is running:
pulseaudio --check - Check virtual sink exists:
pactl list sinks short - Verify Chrome is outputting to sink:
pactl list sink-inputs
Stream Not Starting
- Check for stale lock file:
rm -f /tmp/.X99-lock - Kill all processes:
pkill -9 ffmpeg xterm fluxbox Xvfb node
Quick Commands
Start Stream (Matrix + Drone Audio)
ssh -i ~/.ssh/github_ed25519 root@192.168.1.16 \
"cd ~/sunsofthecosmicdust && nohup bash go-live.sh > /tmp/sotcd.log 2>&1 &"Stop Stream
ssh -i ~/.ssh/github_ed25519 root@192.168.1.16 \
"pkill -9 ffmpeg xterm fluxbox Xvfb node; rm -f /tmp/.X99-lock"Check Stream Status
ssh -i ~/.ssh/github_ed25519 root@192.168.1.16 "pgrep -a ffmpeg && tail -20 /tmp/sotcd.log"Current Status (2026-02-02)
- β Matrix visuals working (Pink & Green)
- β Drone audio working (55Hz sine wave)
- β DJ Bot Strudel audio: ABANDONED (WebAudio issues - see below)
- β SuperCollider acid house engine: WORKING
- β Multi-genre audio switching: FIXED (v3 with crossfades)
- β Stream bitrates: 6500k for both Twitch & YouTube
Milestone: 15+ Hour Livestream POC (2026-02-02)
Completed 15+ hour continuous Twitch stream documenting full proof-of-concept build. Video cached for archival. Demonstrated working SuperCollider audio pipeline with VB-Cable routing to FFmpeg.
SuperCollider Setup (ShadowMaster - Windows)
Host Machine
- IP: 192.168.1.214
- Hostname: ShadowMaster
- User: shdwadmin
- SSH Access:
ssh shdwadmin@192.168.1.214 -i ~/.ssh/id_ed25519
Directory Structure
C:\Users\shdwadmin\sotcd\
βββ START_CONDUIT.bat # Main launcher (starts SC + Bridge + Hydra)
βββ cosmic_genres.scd # Multi-genre engine with crossfades (v3)
βββ headless_boot.scd # Single-genre adaptive acid
βββ signal_bridge_visual.js # Cosmic data β OSC + WebSocket bridge
βββ hydra_cosmic.js # Hydra visual code
βββ stream_twitch.bat # FFmpeg β Twitch (6500k bitrate)
βββ stream_youtube.bat # FFmpeg β YouTube (6500k bitrate)
βββ kill_stream.bat # Stop all streams
βββ node_modules/ # Node dependencies (osc, ws)
Audio Routing
SuperCollider β VB-Audio Virtual Cable β FFmpeg capture β RTMP
- Server port: 58110 (avoiding Windows Hyper-V reserved 57xxx range)
- Audio device: βCABLE Input (VB-Audio Virtual Cable)β
The Conduit System
START_CONDUIT.bat orchestrates the full stream:
- Launches SuperCollider IDE with
cosmic_genres.scd - Starts Signal Bridge (
signal_bridge_visual.js) - Opens Hydra code + Hydra website for visuals
- User manually runs
stream_twitch.bat/stream_youtube.bat
Signal Bridge pulls real-time cosmic data:
- π USGS Earthquake feed
- βοΈ NOAA Solar X-ray flux
- π¬οΈ Solar wind plasma (density, speed, temp)
- π Planetary positions & moon phase
Data maps to audio parameters via OSC on port 57120.
Working SynthDefs
\acidBass- 303-style acid bass with filter envelope\acid303- Classic squelchy acid line\kick- 4/4 kick drum with pitch sweep\hihat- Hi-hat (white noise + HPF)\dronePad- Ambient pad with reverb\darkDrone- Low rumbling drone\chaosPad- Chaos-modulated pad
Multi-Genre Switching (FIXED 2026-02-02)
v3 now working with smooth transitions:
- 4-second crossfades between genres (patterns overlap)
- Gradual BPM interpolation (5% per tick, no jarring tempo jumps)
- Transition lock prevents rapid genre thrashing
- Signal-based auto-switching:
< 0.33β Ambient (75 BPM)0.33-0.66β Acid House (125 BPM)> 0.66β Dark (85 BPM)
- Manual override: send
/genre ambient|acid|darkvia OSC
Fixes applied 2026-02-02:
START_CONDUIT.batnow loadscosmic_genres.scd(was incorrectly loadingheadless_boot.scd)- Genre switcher rewritten with crossfade overlap instead of hard stops
- BPM smoother routine for gradual tempo changes
- Both stream batch files set to 6500k bitrate
OSC Endpoints (port 57120)
| Address | Range | Description |
|---|---|---|
/signal | 0-1 | Master signal (triggers genre switch) |
/bpm | 60-200 | Target tempo |
/filter | 100-8000 | Filter cutoff frequency |
/chaos | 0-1 | Chaos/modulation amount |
/genre | symbol | Manual genre override (ambient/acid/dark) |
Stream Encoding (FFmpeg)
Both Twitch and YouTube use identical settings:
ffmpeg -f gdigrab -framerate 30 -i desktop \
-f dshow -i audio="CABLE Output (VB-Audio Virtual Cable)" \
-c:v libx264 -preset veryfast -b:v 6500k \
-pix_fmt yuv420p -g 60 \
-c:a aac -b:a 128k -ar 44100 -ac 2 \
-f flv "rtmp://..."WebAudio Suspension Problem
The Issue
Browser WebAudio (used by Strudel) is designed to prevent autoplay abuse. Even with all the βrightβ flags, the AudioContext suspends without real user interaction:
--autoplay-policy=no-user-gesture-requireddoesnβt fully work- AudioContext gets suspended randomly
- Audio plays for a few seconds/bars, then stops
- Not viable for 24/7 unattended streaming
What We Tried
- Puppeteer with headless Chrome
xdotoolto simulate clicks- Various Chrome flags for autoplay
- PulseAudio virtual sink routing
Result
Occasional 2-bar bursts of audio, then silence.
Alternative Approaches (If Revisiting)
| Approach | Pros | Cons |
|---|---|---|
| SuperCollider | Headless-native, pro audio | Learning curve |
| SonicPi | Ruby-based, no browser | Requires display for GUI |
| Node + tone.js | JavaScript, server-side | node-web-audio-api limitations |
| Pre-rendered tracks | Simple, reliable | No live generation |
| Icecast + liquidsoap | Proper radio stack | Complex setup |
Lessons Learned
- Browser WebAudio is hostile to automation by design (anti-autoplay)
- For reliable 24/7 headless audio: use native audio tools, not browsers
Related Resources
- Twitch: https://twitch.tv/sunsofthecosmicdust
- Website: https://red40mademedoit.github.io/sunsofthecosmicdust/
- Strudel: https://strudel.cc/