docs(04-01): complete timeline canvas foundation plan — SUMMARY, STATE, ROADMAP updated
- SUMMARY: timeline canvas with per-device tracks, waveform, beat marks, playback cursor - STATE: plan advanced to 2/4, progress 79%, decisions and metrics recorded - ROADMAP: Phase 4 progress updated (1/4 plans complete, In Progress) - Requirements TL-01, TL-05 marked complete
This commit is contained in:
@@ -90,7 +90,7 @@ Plans:
|
||||
**Plans**: 4 plans
|
||||
|
||||
Plans:
|
||||
- [ ] 04-01: Timeline canvas — per-device tracks, time axis, block rendering, playback cursor
|
||||
- [x] 04-01: Timeline canvas — per-device tracks, time axis, block rendering, playback cursor
|
||||
- [ ] 04-02: Block interactions — drag-and-place, move, resize, delete; command pattern undo/redo (min 20 steps)
|
||||
- [ ] 04-03: Beat detection + snap — librosa beat_track + plp + onset_detect in ProcessPoolExecutor, beat mark overlay, snap-to-beat, calibration offset UI
|
||||
- [ ] 04-04: Block editor — animation library panel, color picker, parameter controls per block, changes reflected in show file
|
||||
@@ -155,7 +155,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
|
||||
| 1. Foundation | 4/4 | Complete | 2026-04-05 |
|
||||
| 2. Audio Engine | 3/3 | Complete | 2026-04-06 |
|
||||
| 3. Communication Protocol | 3/3 | Complete | 2026-04-06 |
|
||||
| 4. Timeline Editor | 0/4 | Not started | - |
|
||||
| 4. Timeline Editor | 1/4 | In Progress| |
|
||||
| 5. Live Show Execution | 0/3 | Not started | - |
|
||||
| 6. AI Sync | 0/3 | Not started | - |
|
||||
| 7. Microcontroller Firmware | 0/3 | Not started | - |
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.0
|
||||
milestone_name: milestone
|
||||
status: verifying
|
||||
stopped_at: Phase 4 UI-SPEC approved
|
||||
last_updated: "2026-04-06T23:11:05.583Z"
|
||||
status: executing
|
||||
stopped_at: Completed 04-timeline-editor/04-01-PLAN.md
|
||||
last_updated: "2026-04-06T23:35:19.480Z"
|
||||
last_activity: 2026-04-06
|
||||
progress:
|
||||
total_phases: 7
|
||||
completed_phases: 3
|
||||
total_plans: 10
|
||||
completed_plans: 10
|
||||
total_plans: 14
|
||||
completed_plans: 11
|
||||
percent: 0
|
||||
---
|
||||
|
||||
@@ -21,13 +21,13 @@ progress:
|
||||
See: .planning/PROJECT.md (updated 2026-04-05)
|
||||
|
||||
**Core value:** Load a song, build a synchronized light show, play it back live — with precise control over every effect on every device.
|
||||
**Current focus:** Phase 03 — communication-protocol
|
||||
**Current focus:** Phase 04 — timeline-editor
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 4
|
||||
Plan: Not started
|
||||
Status: Phase complete — ready for verification
|
||||
Phase: 04 (timeline-editor) — EXECUTING
|
||||
Plan: 2 of 4
|
||||
Status: Ready to execute
|
||||
Last activity: 2026-04-06
|
||||
|
||||
Progress: [░░░░░░░░░░] 0%
|
||||
@@ -62,6 +62,7 @@ Progress: [░░░░░░░░░░] 0%
|
||||
| Phase 03-communication-protocol P01 | 4min | 2 tasks | 8 files |
|
||||
| Phase 03-communication-protocol P02 | 3min | 1 tasks | 10 files |
|
||||
| Phase 03-communication-protocol P03 | 2min | 2 tasks | 3 files |
|
||||
| Phase 04-timeline-editor P01 | 4min | 2 tasks | 5 files |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
@@ -98,6 +99,8 @@ Recent decisions affecting current work:
|
||||
- [Phase 03-communication-protocol]: FireAnimation lazy-initializes heat array per led_count to support variable strip lengths
|
||||
- [Phase 03-communication-protocol]: asyncio.run() test pattern chosen over pytest-asyncio — not installed, plan provided this fallback
|
||||
- [Phase 03-communication-protocol]: UDPSender stopped before registry.save() in shutdown — orderly teardown, no sends after socket close
|
||||
- [Phase 04-timeline-editor]: Beats API uses 'beats' field not 'beat_times' — loadBeats() handles both with fallback
|
||||
- [Phase 04-timeline-editor]: TimelineCanvas auto-scroll at 80%/20% threshold — standard DAW follow behavior
|
||||
|
||||
### Pending Todos
|
||||
|
||||
@@ -111,8 +114,8 @@ None yet.
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-06T23:11:05.576Z
|
||||
Stopped at: Phase 4 UI-SPEC approved
|
||||
Resume file: .planning/phases/04-timeline-editor/04-UI-SPEC.md
|
||||
Last session: 2026-04-06T23:35:19.475Z
|
||||
Stopped at: Completed 04-timeline-editor/04-01-PLAN.md
|
||||
Resume file: None
|
||||
|
||||
Next action: `/gsd:plan-phase 1`
|
||||
|
||||
83
.planning/phases/04-timeline-editor/04-01-SUMMARY.md
Normal file
83
.planning/phases/04-timeline-editor/04-01-SUMMARY.md
Normal file
@@ -0,0 +1,83 @@
|
||||
---
|
||||
phase: 04-timeline-editor
|
||||
plan: 01
|
||||
subsystem: frontend-canvas
|
||||
tags: [canvas, timeline, daw-ui, audio, waveform]
|
||||
dependency_graph:
|
||||
requires: [Phase 03 communication protocol — UDP sender, animation encoders]
|
||||
provides: [TimelineCanvas class, timeline rendering foundation]
|
||||
affects: [lightsync/frontend, lightsync/models/show.py]
|
||||
tech_stack:
|
||||
added: [HTML5 Canvas 2D API, ES module import/export, requestAnimationFrame render loop]
|
||||
patterns: [HiDPI canvas with devicePixelRatio, coordinate system with HEADER_WIDTH/TIME_AXIS_HEIGHT offsets, layer-ordered canvas render]
|
||||
key_files:
|
||||
created:
|
||||
- lightsync/frontend/timeline/timeline.js
|
||||
modified:
|
||||
- lightsync/models/show.py
|
||||
- lightsync/frontend/index.html
|
||||
- lightsync/frontend/style.css
|
||||
- lightsync/frontend/app.js
|
||||
decisions:
|
||||
- beats API returns 'beats' field (not 'beat_times') — loadBeats() uses data.beats with data.beat_times as fallback
|
||||
- Auto-scroll threshold at 80% canvas width, cursor repositioned to 20% — smooth follow during playback
|
||||
- Empty state messages rendered inside canvas (not DOM overlay) — avoids z-index issues
|
||||
metrics:
|
||||
duration: 4min
|
||||
completed: 2026-04-06
|
||||
tasks: 2
|
||||
files: 5
|
||||
---
|
||||
|
||||
# Phase 04 Plan 01: Timeline Canvas Foundation Summary
|
||||
|
||||
**One-liner:** HTML5 canvas DAW timeline with per-device tracks, waveform background, beat marks, and realtime playback cursor synced to audio.currentTime via requestAnimationFrame.
|
||||
|
||||
## What Was Built
|
||||
|
||||
- **CueModel.duration** (float = 4.0) — block length in seconds, Pydantic default handles old show files
|
||||
- **AnalysisBlock.calibration_offset** (float = 0.03) — compensates librosa latency bias, applied when rendering beat marks
|
||||
- **TimelineCanvas class** (`lightsync/frontend/timeline/timeline.js`) — 280+ line canvas engine:
|
||||
- Coordinate system: `timeToX()`, `xToTime()`, `trackIndexToY()`, `yToTrackIndex()`
|
||||
- HiDPI rendering via `devicePixelRatio` in `_resizeCanvas()`
|
||||
- Layer render order: background → track banding → waveform → beat marks → cue blocks → drag ghost → headers → time axis → cursor
|
||||
- Auto-scroll: cursor triggers viewport shift when it reaches 80% of canvas width
|
||||
- Mouse wheel horizontal scroll
|
||||
- Empty state messages for no-devices and no-audio cases
|
||||
- **HTML layout restructured** — main-area now contains toolbar → canvas → inspector strip; ANIMATIONS panel moved to sidebar
|
||||
- **CSS added** — timeline toolbar, canvas fill, inspector strip, snap button active state
|
||||
- **app.js wired** — imports TimelineCanvas, creates instance, wires zoom/beat-offset/snap controls, populates animation palette dynamically
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| beats API 'beats' field (not 'beat_times') | API returns `{"beats": [...]}` — plan expected `beat_times` — auto-fixed (Rule 1) |
|
||||
| Auto-scroll at 80%/20% threshold | Standard DAW follow behavior — keeps cursor in view without jerky jumps |
|
||||
| Empty state in canvas | Simpler than DOM overlay, no z-index conflicts with toolbar/inspector |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] beats API field name mismatch**
|
||||
- **Found during:** Task 2 implementation
|
||||
- **Issue:** Plan specified `data.beat_times` but `/api/audio/beats` returns `{"beats": [...]}` (from `analyze()` in `beats.py`)
|
||||
- **Fix:** `loadBeats()` uses `data.beats || data.beat_times || []` — handles both field names
|
||||
- **Files modified:** `lightsync/frontend/timeline/timeline.js`
|
||||
- **Commit:** efa6123
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — timeline renders live data from `/api/devices`, `/api/audio/waveform`, and `/api/audio/beats`. Cue blocks will be empty (`track.cues = []`) until Plan 04-02 adds block drag-and-drop, but that is expected for this phase.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- `lightsync/frontend/timeline/timeline.js` exists: YES (efa6123)
|
||||
- `lightsync/models/show.py` has `duration: float = 4.0`: YES (454fddc)
|
||||
- `lightsync/models/show.py` has `calibration_offset: float = 0.03`: YES (454fddc)
|
||||
- `lightsync/frontend/index.html` has `id="timeline-canvas"`: YES
|
||||
- `lightsync/frontend/style.css` has `#timeline-canvas`, `.block-inspector`: YES
|
||||
- `lightsync/frontend/app.js` imports TimelineCanvas: YES
|
||||
- Docker build and startup: CLEAN (no errors)
|
||||
- Python model import test: PASSED (`CueModel(timestamp=1.0).duration == 4.0`)
|
||||
Reference in New Issue
Block a user