- CommandHistory + 4 command classes + backend CRUD endpoints - Full mouse interactions: drag-place, move, resize, delete, undo/redo - Requirements TL-02, TL-03, TL-06 marked complete - Progress: 86% (12/14 plans)
7.6 KiB
7.6 KiB
phase, plan, subsystem, tags, dependency_graph, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
| phase | plan | subsystem | tags | dependency_graph | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | duration | completed | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 04-timeline-editor | 02 | ui |
|
|
|
|
|
|
|
9min | 2026-04-06 |
Phase 04 Plan 02: Block Interactions + Command Pattern Summary
Command-pattern block editing with drag-from-palette, move/resize/delete interactions, undo/redo (50 steps), overlap prevention, snap-to-beat, and backend CRUD endpoints.
Performance
- Duration: ~9 min
- Started: 2026-04-06T23:35:38Z
- Completed: 2026-04-06T23:44:50Z
- Tasks: 2
- Files modified: 5 (3 created, 3 modified)
Accomplishments
CommandHistoryclass: 50-step max, execute/undo/redo, redo cleared on new action (branching protection)- 4 command classes:
PlaceBlockCommand,MoveBlockCommand,ResizeBlockCommand,DeleteBlockCommand— each with backend sync via fire-and-forget fetch - REST API: POST/PATCH/DELETE
/api/shows/{show_id}/tracks/{device_id}/blockswith auto-create track if missing - Full mouse interaction: hitTest with 8px resize zones, live drag preview, overlap rejection, snap-to-beat on release
- Keyboard: Delete key removes selected block, Ctrl+Z undo, Ctrl+Shift+Z / Ctrl+Y redo
- Drag-and-drop from animation palette to canvas with ghost block preview
Task Commits
- Task 1: Command pattern + history + backend block CRUD -
658c92f(feat) - Task 2: Wire mouse interactions into TimelineCanvas -
7e18ac6(feat)
Files Created/Modified
lightsync/frontend/timeline/history.js— CommandHistory class (execute, undo, redo, canUndo, canRedo, maxSteps=50)lightsync/frontend/timeline/commands.js— PlaceBlockCommand, MoveBlockCommand, ResizeBlockCommand, DeleteBlockCommand + setCurrentShowId() + syncBlock()lightsync/api/timeline.py— Block CRUD FastAPI router (POST/PATCH/DELETE)lightsync/frontend/timeline/timeline.js— hitTest, _hasOverlap, snapToBeat, _setupInteractions, _startMove, _startResize, handleDrop added; CommandHistory + 4 command imports wiredlightsync/frontend/app.js— dragstart/dragover/dragleave/drop listeners for palette-to-canvas draglightsync/main.py— timeline router registered with prefix="/api"
Decisions Made
| Decision | Rationale |
|---|---|
| Revert-then-command pattern in _startMove | Live drag updates block.timestamp for visual feedback; mouseup reverts to oldTimestamp, then MoveBlockCommand.execute() sets final value — history always has correct before/after state |
| Document-level mousemove/mouseup during drag | Canvas-only listeners lose events when mouse moves fast outside canvas bounds |
| Ghost preview via _dragState.trackIdx + time | Decoupled from raw pixels — render() computes screen position, maintaining coordinate abstraction |
| setCurrentShowId() module-level function | Commands need showId for backend sync but shouldn't be coupled to app state — module-level var injected by app.js |
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] Plan's _startMove had duplicated/contradictory draft code
- Found during: Task 2 implementation
- Issue: The plan's
_startMoveaction block contained two conflicting implementations (onDrag/onUp followed by onDrag2/onUp2) with a comment "IMPORTANT: The executor MUST implement it cleanly as a single version" - Fix: Implemented clean single version following the stated logic: record old, live-update during drag, revert + command on mouseup
- Files modified:
lightsync/frontend/timeline/timeline.js - Committed in:
7e18ac6
Total deviations: 1 auto-fixed (Rule 1 - Bug) Impact on plan: Fix was necessary — the draft code in the plan would not compile/run correctly as-is. Clean implementation follows exact logic specified in the IMPORTANT note.
Issues Encountered
- Circular import warning during
python -c "from lightsync.api.timeline import router"— same pattern as existingshows.py. Not a bug:import lightsync.main as stateat module level causes partially-initialized module error on isolated import, but works correctly at runtime when app bootstraps normally. Docker build and startup confirmed clean.
Known Stubs
None — block placement, move, resize, delete are all fully wired. Backend CRUD endpoints accept and persist mutations. Undo/redo history tracks all operations.
Self-Check
lightsync/frontend/timeline/history.jsexists: YES (658c92f)lightsync/frontend/timeline/commands.jsexports 4 command classes: YES (658c92f)lightsync/api/timeline.pyhas POST/PATCH/DELETE routes: YES (658c92f)lightsync/main.pyincludes timeline router: YES (658c92f)lightsync/frontend/timeline/timeline.jshas hitTest, _startMove, _startResize, handleDrop: YES (7e18ac6)lightsync/frontend/app.jshas dragstart/dragover/drop: YES (7e18ac6)- Docker build: SUCCESS (fa66387)
- App startup: CLEAN (no errors, uvicorn running)
Self-Check: PASSED
Next Phase Readiness
- Block placement and editing is fully functional — timeline is now interactive
- Plan 04-03 (block inspector panel) can wire into
timeline._onSelectBlockcallback andtimeline.selectedBlock - Plan 04-04 (playback/live engine) reads cues from
timeline.tracks[*].cueswhich are now populated by user interactions - No blockers
Phase: 04-timeline-editor Completed: 2026-04-06