Quick reference for infrastructure wiring patterns across all 6 game modes.
📦 Import Template
// Core audio
import { audioEngine } from "../audio/AudioEngine"
import { samplePackLoader } from "../audio/SamplePacks"
// UI components
import { ParticleCanvas, type ParticleCanvasHandle } from "../components/ParticleCanvas"
import { UnifiedControlBar } from "../components/UnifiedControlBar"
// Input contexts
import { useGamepad } from "../contexts/GamepadContext"
// Pattern utilities
import {
createPattern,
savePatternToLibrary,
importPatternFromFile,
createShareURL,
copyToClipboard,
} from "../utils/PatternExport"
🎵 Sample Pack Integration
Available Packs
Pack Samples Mode zookick, snare, clap, hihat, chirp, bubble, bell, bass ZooBeats startwinkle, glow, shoot, chime StarDraw gardensprout, bloom, rustle, drop, buzz GardenGrow oceanfish, jellyfish, turtle, octopus, bubble, whale, dolphin OceanDive paintred, orange, yellow, green, blue, purple, white PaintMusic storycharacter, action, setting, happy, sad, exciting StoryTime
Loading Pattern
// In useEffect for audio init:
useEffect (() => {
audioEngine. init (). then (() => {
const ctx = audioEngine. getContext ()
if (ctx) {
samplePackLoader. connect (ctx)
samplePackLoader. loadPack ( "zoo" ) // or star, garden, ocean, paint, story
}
})
return () => samplePackLoader. unloadPack ( "zoo" )
}, [midi])
Playing Samples
const playSample = ( name : string , velocity = 100 ) => {
const buffer = samplePackLoader. getBuffer ( "zoo" , name)
if ( ! buffer || ! audioEngine.ctx) return
const source = audioEngine.ctx. createBufferSource ()
source.buffer = buffer
const gain = audioEngine.ctx. createGain ()
gain.gain.value = velocity / 127
source. connect (gain)
audioEngine. connectToMaster (gain)
source. start ()
}
🎆 Particle Canvas Integration
Setup
const particleRef = useRef < ParticleCanvasHandle >( null )
// In JSX (before UnifiedControlBar):
; < ParticleCanvas ref = {particleRef} className = "mode-particles" />
Emitting Particles
// Single emission
particleRef.current?. emit (x, y, count, "#4CAF50" )
// Burst (multiple colors)
particleRef.current?. burst (x, y, [ "#FFD700" , "#FF6B6B" , "#4ECDC4" ])
Position Calculation from Grid
const emitAt = ( row : number , col : number ) => {
const gridEl = gridRef.current
const cells = gridEl?. querySelectorAll ( ".cell" )
const cell = cells?.[index] as HTMLElement
if ( ! cell || ! particleRef.current) return
const rect = cell. getBoundingClientRect ()
particleRef.current. emit (rect.left + rect.width / 2 , rect.top + rect.height / 2 , 10 , "#FFD700" )
}
💾 Save/Load/Share Integration
Handler Template
// Save
const handleSave = useCallback (() => {
const pattern = createPattern ( "mode" , `Name ${ Date . now () }` , tempo, stateData)
savePatternToLibrary (pattern)
}, [tempo, stateData])
// Load
const handleLoad = useCallback ( async () => {
const pattern = await importPatternFromFile ()
if (pattern?.mode === "mode" && pattern.data) {
// Apply pattern.data to state
}
}, [])
// Share
const handleShare = useCallback ( async () => {
const pattern = createPattern ( "mode" , "Shared" , tempo, stateData)
await copyToClipboard ( createShareURL (pattern))
}, [tempo, stateData])
UnifiedControlBar Props
< UnifiedControlBar
isPlaying = {state.isPlaying}
onPlay = {togglePlay}
onStop = {handleStop}
onClear = {handleClear}
tempo = {state.tempo}
showSaveLoad // Enable save/load buttons
onSave = {handleSave}
onLoad = {handleLoad}
onShare = {handleShare}
>
{ /* Knobs */ }
</ UnifiedControlBar >
📳 Gamepad Haptics Integration
Setup
const { vibrate , pulseOnBeat , supportsHaptics } = useGamepad ()
Usage Patterns
// On note/pad hit
if (supportsHaptics) vibrate ( 60 , 0.7 ) // 60ms, 70% intensity
// On beat (sequencer step)
if (supportsHaptics) pulseOnBeat () // Short 50ms pulse
// Intensity based on velocity
if (supportsHaptics) vibrate ( 50 , velocity / 127 )
⚠️ Critical Rules
LED_THROTTLE :
max_flushes_per_sec : 20
max_leds_per_flush : 10
rule : NEVER BYPASS
HTTPS_REQUIRED : true # Web MIDI needs secure context
BLINKING_LEDS : AVOID
- Use solid LED_COLORS only (GREEN, AMBER, RED, OFF)
- No useLEDBeatFlash unless explicitly requested
🔧 Commands
# Type check
npx tsc --noEmit
# Restart service
sudo systemctl restart magic-music-land
# View logs
journalctl -u magic-music-land -f
# Test endpoint
curl -k https://0rk.de:54545
📊 Integration Status
Mode SamplePack Particles Save/Load Haptics ZooBeats ✅ zoo ✅ ✅ ✅ StarDraw ✅ star ✅ ✅ ✅ GardenGrow ✅ garden ✅ ✅ ✅ OceanDive ✅ ocean ✅ ✅ ✅ PaintMusic ✅ paint ✅ ✅ ✅ StoryTime ✅ story ✅ ✅ ✅
🏗️ File Locations
src/
├── audio/
│ ├── SamplePacks.ts # Procedural sample generation
│ └── SamplePlayer.ts # Sample playback engine
├── components/
│ ├── ParticleCanvas.tsx # WebGL particle system
│ └── UnifiedControlBar.tsx # Transport + save/load buttons
├── contexts/
│ └── GamepadContext.tsx # Haptic feedback
├── utils/
│ └── PatternExport.ts # URL/file pattern export
└── modes/
├── ZooBeats.tsx # Reference implementation
├── StarDraw.tsx
├── GardenGrow.tsx
├── OceanDive.tsx
├── PaintMusic.tsx
└── StoryTime.tsx