|
| 1 | +# Spec: 03-ui-coherence |
| 2 | + |
| 3 | +**Project:** ProjectToooT — macOS 2026 Native DAW |
| 4 | +**Module:** ToooT_UI + ProjectToooTApp |
| 5 | +**Track:** Main (largest split — start immediately, runs alongside 01 and 02) |
| 6 | + |
| 7 | +## Goal |
| 8 | + |
| 9 | +Stabilize and integrate all ToooT_UI views into a coherent, fully functional DAW workspace. Every major view must open, render correctly, respond to user input, and stay wired to the engine. No crashes on view switch. WWDC target: full DAW feature parity in a single session. |
| 10 | + |
| 11 | +## Background |
| 12 | + |
| 13 | +See `requirements.md` §5 (User Experience & Interface), `memory/project_status.md` §Working Features and §Stubs. |
| 14 | + |
| 15 | +Interview finding: "broken UI" is all views simultaneously — Metal grid, Piano Roll, Envelope Editor, Automation, Spatial Visualizer. This is an integration coherence problem, not isolated component bugs. |
| 16 | + |
| 17 | +## What to Build |
| 18 | + |
| 19 | +Work through these views in priority order (each must be stable before moving to the next): |
| 20 | + |
| 21 | +### 1. TrackerWorkspace Layout |
| 22 | +- Window management: persistent layout state across launches |
| 23 | +- Navigation between views (pattern grid ↔ piano roll ↔ envelope ↔ automation ↔ spatial) without state loss |
| 24 | +- Toolbar / transport controls always visible and functional |
| 25 | + |
| 26 | +### 2. Metal Pattern Grid |
| 27 | +- Verify 120Hz ProMotion via `MTKView` (not timer-based redraws — use display link) |
| 28 | +- GPU-instanced cell rendering: thousands of cells, minimal CPU overhead |
| 29 | +- Arrow navigation, note entry (Z–M keyboard layout), Cmd+C/V row copy-paste, Cmd+D duplicate — all must work |
| 30 | +- Playhead animation must read **only** from `sharedState.playheadPosition` (L25) — never derive from `samplesProcessed` |
| 31 | + |
| 32 | +### 3. Piano Roll |
| 33 | +- Drag-to-paint note entry: erase mode on existing notes, paint mode on empty space |
| 34 | +- Multi-touch trackpad support |
| 35 | +- Visual velocity feedback per note |
| 36 | +- Stable undo/redo integration (50 levels) |
| 37 | + |
| 38 | +### 4. Envelope Editor |
| 39 | +- Volume / pan / pitch envelope types |
| 40 | +- Drag existing points, click background to add, right-click to delete |
| 41 | +- Points must bind bidirectionally to engine envelope state |
| 42 | + |
| 43 | +### 5. Automation Editor |
| 44 | +- Draggable Bezier curves for all automatable parameters |
| 45 | +- Implemented via SwiftUI `Canvas` + `DragGesture` |
| 46 | +- Binds to `EngineSharedState` parameter slots |
| 47 | + |
| 48 | +### 6. Spatial Visualizer |
| 49 | +- 3D source positioning via drag |
| 50 | +- **Bidirectional:** dragging in UI must update `SpatialManager` / PHASE in real-time |
| 51 | +- `SpatialManager` position changes (e.g., from automation) must reflect in UI |
| 52 | + |
| 53 | +### 7. Mixer |
| 54 | +- Real-time level meters wired to render output (read from `EngineSharedState` snapshot) |
| 55 | +- AUv3 insert rack visible: Stereo Wide + Pro Reverb slots |
| 56 | + |
| 57 | +### 8. Video Sync |
| 58 | +- `ScreenCaptureKit` feed displayed |
| 59 | +- Sequencer playhead hard-synced to video playback position (`AVFoundation` timecode) |
| 60 | + |
| 61 | +## UI/UX Philosophy (Apple Silicon Performance) |
| 62 | + |
| 63 | +- **Metal-first rendering:** Pattern grid and any timeline component must use Metal (`MTKView`) — no CoreGraphics fallback in hot paths |
| 64 | +- **ProMotion-adaptive:** Tie render loop to `CADisplayLink` / `MTKView` preferred frame rate (120Hz on ProMotion displays, graceful fallback) |
| 65 | +- **One atomic bridge:** `EngineSharedState` is the only legal read path from UI to engine — take a snapshot per frame, never dereference live audio-thread pointers from `@MainActor` code |
| 66 | +- **SwiftUI for controls, Metal for grids:** SwiftUI `Canvas` + gestures for Automation Bezier; Metal instanced rendering for the tracker grid and piano roll keys |
| 67 | +- **Playhead as truth:** All animations derive from `sharedState.playheadPosition` (L25) — a `Float` written by the render block as `Float(row) + Float(tick)/Float(ticksPerRow)` |
| 68 | + |
| 69 | +## Critical Rules (Must Not Violate) |
| 70 | + |
| 71 | +| Rule | Source | |
| 72 | +|---|---| |
| 73 | +| Never write UI-owned BPM/tempo to engine during playback | L21 | |
| 74 | +| Playhead position = `sharedState.playheadPosition` only | L25 | |
| 75 | +| Tremolo/vibrato: transient display values only, never stored in view model | L24 | |
| 76 | +| All `@MainActor` UI must use `EngineSharedState` snapshot — no direct audio struct access | Swift 6 | |
| 77 | +| StereoWide reads both channels from a scratch copy before computing newL/newR | L23 | |
| 78 | + |
| 79 | +## Constraints |
| 80 | + |
| 81 | +- **Swift 6 strict concurrency** — all UI code must be `@MainActor`; no `@unchecked Sendable` |
| 82 | +- **No timer-based redraws** — use display link or `onChange` driven by `EngineSharedState` published snapshot |
| 83 | +- **Undo/Redo must survive view switches** — 50-level stack must not be scoped to a single view |
| 84 | + |
| 85 | +## Success Criteria |
| 86 | + |
| 87 | +- [ ] All 8 views open without crashing |
| 88 | +- [ ] Metal grid renders at 120Hz; playhead animates smoothly during playback |
| 89 | +- [ ] Piano Roll: paint/erase notes, undo/redo works |
| 90 | +- [ ] Envelope Editor: add/move/delete points, changes persist |
| 91 | +- [ ] Automation: Bezier curves draggable, bound to engine params |
| 92 | +- [ ] Spatial Visualizer: drag source → PHASE position updates in real-time |
| 93 | +- [ ] Mixer: meters move during playback; AUv3 rack visible |
| 94 | +- [ ] Video Sync: playhead tracks video timecode |
| 95 | +- [ ] No Swift 6 concurrency warnings in ToooT_UI module |
| 96 | + |
| 97 | +## Dependencies |
| 98 | + |
| 99 | +**Needs from other splits:** |
| 100 | +- `EngineSharedState` snapshot API (stable after 01-audio-engine-perf, but can work against current version) |
| 101 | +- Lossless save/load (02-io-save-load) for "Save Project" menu item |
| 102 | + |
| 103 | +**Provides to other splits:** |
| 104 | +- Stable `TrackerWorkspace` scaffold that 04-neural-ane-acceleration's synthesis UI slots into |
0 commit comments