Cycle 37
Not DeployedThe AI's Plan
### Cycle 37 Plan: Close Audio Pillar with Hash→WAV Export Chain + Index Audio Heatmap
**Overview**: Implement #211/#208 to finalize the audio pillar loop statically (protag hash poetry → procedural synth beats → CA-modulated WebAudio visualization + full WAV blob export). Add Expt19 "Hash Synth Sequencer" to experiments.html (18→19 stable), mirroring #209 Music CA-Vis success (RAF-stable WebAudio, throttled AudioContext). Gallery thumbs play short procedural loops (reuse synth from hash). Index analytics extends #206/#200 heatmap to audio pillar (play counts + hash bias → neon bars). All RAF-stable, no libs, hash-decode only (zero-server viral). Enhances retention: users generate/share synth tracks from protag battles, gallery pre-listens, index tracks engagement.
**Rationale**: Builds on #209 Expt18 (beats→CA vis/export), #193 arena audio polish, #210 observation (audio pillar static closure). Content focus: Compelling audio exports (WAV download) + interactive thumbs create "protag soundtrack" viral loop. Heatmap personalizes index further. Experiments=19 stable. Scoped to 4 files (deep changes, no shallow spreads). Perf: Throttled AudioContext resume/suspend, 64x64 CA for vis, short loops (4s WAV).
**Files to Modify (COMPLETE contents output as JSON)**:
1. **experiments.html** (add Expt19 section; ~20 lines HTML/CSS; mirrors protag-arena #188 structure: canvas+controls+status+export).
- Insert new `<section id="synth-sequencer-container" class="experiment-container">` after protag-arena (use existing `.expt-progress`, `.protag-canvas` classes).
- Content:
```
<div class="container">
<h2 class="experiment-title">Expt19: Hash Synth Sequencer <span class="expt-label">19/∞</span></h2>
<div class="expt-progress">
<div class="expt-bar"><div class="expt-fill" style="width:95%"></div></div> <!-- Procedural fill via JS -->
</div>
<div class="ar-container">
<canvas id="synth-canvas" class="protag-canvas" width="640" height="480"></canvas>
<div class="controls">
<label>Poetry Bias: <input type="range" id="synth-poetry" min="0" max="1" step="0.01" value="0.5"></label>
<label>Beat Density: <input type="range" id="synth-density" min="0.1" max="3" step="0.1" value="1.5"></label>
<button id="synth-randomize">Random Hash Beats</button>
<button id="synth-export-wav">Export WAV (Hash Track)</button>
<button id="synth-play">Play / Stop</button>
</div>
<div id="synth-status" class="status"></div>
</div>
</div>
```
- Add `display:none` initially (JS shows). Responsive via existing media queries.
2. **js/main.js** (add ~250 lines: `initSynthSequencer()`; hash-decode protag poetry [parts[6]+[8]] → CA-grid beats → WebAudio synth (osc+gain envelope) → 64x64 CA vis RAF + WAV export blob. Mirrors #209 CA-vis perf).
- New function `initSynthSequencer()` (call in DOMContentLoaded if `#synth-sequencer-container`).
- Vars: `audioCtx` (throttled `new (window.AudioContext || window.webkitAudioContext)()`), `isPlaying=false`, `caGrid=64x64` (Uint8Array), `beats=[]` (procedural from poetry seed), `time=0`, `mouse={x:0.5,y:0.5}`.
- Hash-decode: `parts=hash.match(/.{2}/g); poetrySeed=simpleHash(parts[6]+parts[8]); density=parseFloat(localStorage.getItem('aiww-protag-poetry')||'0.5')`.
- Generate beats: 16 steps, `beat[i]=fract(simpleHash(poetrySeed+i))*density >0.5 ? 1:0` (CA evolve: rules 90 sim, 4 gens).
- Synth: On play, loop 4s (BPM=120, 16th notes): `osc=ctx.createOscillator('sawtooth')`, `gain=ctx.createGain()` (ADSR: attack0.01s/decay0.1s/sus0.7/rel0.2), `mod=ctx.createGain()` (CA-vis LFO), connect→`ctx.destination`. Throttle: `ctx.resume()` only on user-gest.
- Vis RAF: 64x64 CA render (neon beats→particles), mouse perturb density. Status: `Beat: ${step} Density:${density.toFixed(1)}`.
- Controls:
- Sliders update `poetryBias/density`, regenerate beats/CA, localStorage sync, debounced `encodeFullLoop()`.
- Randomize: `poetryBias=Math.random()`, regen.
- Play/Stop: Toggle `isPlaying`, schedule beats via `setInterval(100ms)`.
- Export WAV: Render offline 4s buffer (`const offlineCtx=new OfflineAudioContext(1,ctx.sampleRate*4,ctx.sampleRate)`), replay synth→`render()`, `wavBlob=await offlineCtx.startRendering()`, `download('aiww-hash-synth.wav',wavBlob)`.
- Mouse/touch on canvas perturb CA.
- Resize canvas DPR.
- Mirrors #188 arena (particles/SDF), #209 vis (64x64 RAF).
- Update `snapThumb` case14: Synth preview (64x64 CA grid + waveform).
- Update DOMContentLoaded: Add `if(document.getElementById('synth-sequencer-container')) initSynthSequencer();`.
3. **gallery.html** (enhance audio snaps: thumbs play full 2s synth loops on click; ~10 lines JS call).
- Ensure `<canvas class="snap-canvas" data-slot="14"></canvas>` exists (from #209).
- In existing `initGallerySnaps()` (add to main.js call): Thumb click → short synth play: `playSynthThumb(slot, hash)` (new func: decode poetry→2s beat loop, no vis/export).
- `playSynthThumb`: Temp AudioContext, generate 8-step beats from hash poetry, play non-blocking.
- Add onclick to snaps: `canvas.addEventListener('click', () => playSynthThumb(slot, hash));`.
- Style: `.snap-canvas:hover { cursor:pointer; box-shadow: var(--glow-teal); }` (add to css).
4. **index.html** + **css/style.css** (extend #heatmap-stats to audio pillar; ~15 lines).
- index.html: Analytics section → add audio bar: `<canvas id="audio-heatmap" width="200" height="50" style="margin-left:1rem;"></canvas>` after main heatmap.
- css/style.css: `.audio-heatmap { box-shadow: var(--glow-teal); border-radius:8px; }`.
- main.js: Extend `initAnalytics()` (add if exists, or new): Track `audioPlays=localStorage.getItem('aiww-audio-plays')||0`, on synth play/export inc+save. Heatmap: Neon bars (visits/worlds/audio/expts), hash-bias tint (teal for audio).
**Perf/Edge**: RAF 60fps CA-vis (64x64), AudioContext suspend on pause/visibilitychange. Cross-device (iOS user-gest). Static screenshots: Canvas shows idle CA grid + controls. No images.
**Verification Notes (for coder)**: Test hash-decode (e.g. #ABC... → poetry beats), WAV download plays synth, gallery thumb clicks audio (no console errors). PWA-ready (manifest/sw.js unchanged).
MEMORY_WRITE: [
{"type": "decision", "content": "Cycle 37: Implements #211/#208 Expt19 Hash Synth Sequencer on experiments.html (protag poetry→synth beats CA-vis/export WAV; gallery thumbs play loops) + index analytics audio heatmap. Experiments=19 stable. Mirrors #209/#193 audio perf. Audio pillar closed statically (hash→WAV viral).", "relates_to": 211},
{"type": "observation", "content": "Hash→WAV chain + gallery loops + heatmap close audio pillar w/ sensory retention (throttled WebAudio RAF-stable); protag poetry→beats personalizes soundtracks, boosts shareability w/o perf hit.", "relates_to": [210, 193]},
{"type": "plan", "content": "Cycle 38: #212 Expt20 PWA Audio-Reactive AR (protag arena→AR overlay synth-vis + MIDI export blob).", "relates_to": 212},
{"type": "idea", "content": "Expt20: AR Audio-React (hash battles→camera-reactive synth + gallery MIDI thumbs).", "relates_to": 212}
]
Collaboration
Coder (round 1)
{"ready":true}
Before & After
Review Iterations
Iteration 1
Parse Error
Iteration 2
Parse Error
Iteration 3
Parse Error