From 2e312849a6111bbdd20a33a0c2fb400143d00338 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Tue, 13 Jan 2026 20:35:30 +0530 Subject: [PATCH] docs(02): plan backing track seek controls Create executable plan for Phase 2 with 3 tasks: - Add state for position/duration in milliseconds - Wire slider to reflect current position - Implement functional handleSeek with SessionTrackSeekMs() Plan: .planning/phases/02-backing-track-seek-controls/02-01-PLAN.md Updates: ROADMAP.md (Phase 2: 0/1 planned), STATE.md (Phase 2 current) Co-Authored-By: Claude Sonnet 4.5 --- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 12 +- .../02-01-PLAN.md | 249 ++++++++++++++++++ 3 files changed, 258 insertions(+), 9 deletions(-) create mode 100644 .planning/phases/02-backing-track-seek-controls/02-01-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 4b4acc9bd..b126222fb 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -39,10 +39,10 @@ Plans: **Goal**: Make the seek bar functional with drag-to-position capability **Depends on**: Phase 1 **Research**: Unlikely (building on Phase 1, same API patterns) -**Plans**: TBD +**Plans**: 1 plan Plans: -- [ ] TBD during phase planning +- [ ] 02-01: Wire slider to position state, implement drag-to-seek with SessionTrackSeekMs() ### Phase 3: Backing Track Finalization **Goal**: Complete Backing Track with error handling, edge cases, and performance optimization @@ -99,7 +99,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. Backing Track Playback Monitoring | 1/1 | Complete | 2026-01-13 | -| 2. Backing Track Seek Controls | 0/TBD | Not started | - | +| 2. Backing Track Seek Controls | 0/1 | Planned | - | | 3. Backing Track Finalization | 0/TBD | Not started | - | | 4. JamTrack Research & Design | 0/TBD | Not started | - | | 5. JamTrack Implementation | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 4a35da77f..9cb80182f 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,14 +5,14 @@ See: .planning/PROJECT.md (updated 2026-01-13) **Core value:** Modernize media opening features (Backing Track, JamTrack, Metronome) from legacy jQuery/Rails to React patterns in jam-ui -**Current focus:** Phase 1 — Backing Track Playback Monitoring +**Current focus:** Phase 2 — Backing Track Seek Controls ## Current Position -Phase: 1 of 7 (Backing Track Playback Monitoring) +Phase: 2 of 7 (Backing Track Seek Controls) Plan: 1 of 1 in current phase -Status: Phase complete -Last activity: 2026-01-13 — Completed 01-01-PLAN.md +Status: Plan created, ready to execute +Last activity: 2026-01-13 — Created 02-01-PLAN.md Progress: ██░░░░░░░░ 14% @@ -52,6 +52,6 @@ None yet. ## Session Continuity -Last session: 2026-01-13T14:53:53Z -Stopped at: Completed 01-01-PLAN.md (Phase 1 complete) +Last session: 2026-01-13 +Stopped at: Created 02-01-PLAN.md (Phase 2 planned, ready to execute) Resume file: None diff --git a/.planning/phases/02-backing-track-seek-controls/02-01-PLAN.md b/.planning/phases/02-backing-track-seek-controls/02-01-PLAN.md new file mode 100644 index 000000000..939ffc50e --- /dev/null +++ b/.planning/phases/02-backing-track-seek-controls/02-01-PLAN.md @@ -0,0 +1,249 @@ +--- +phase: 02-backing-track-seek-controls +type: execute +--- + + +Make the backing track seek bar functional by wiring it to real playback position and implementing drag-to-position capability using jamClient.SessionTrackSeekMs(). + +Purpose: Complete the player's seek functionality, matching the legacy web implementation's behavior while using modern React patterns. This builds directly on Phase 1's monitoring foundation. + +Output: Backing track player with a fully functional seek slider that reflects current position and allows users to seek to any position by dragging. + + + +@./.claude/get-shit-done/workflows/execute-phase.md +@./.claude/get-shit-down/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/01-backing-track-playback-monitoring/01-01-SUMMARY.md +@jam-ui/src/components/client/JKSessionBackingTrackPlayer.js + +**Codebase conventions:** +- React functional components with hooks (React 16.13.1) +- camelCase for functions and variables +- Single quotes for strings (Prettier enforced) +- 2-space indentation + +**Legacy implementation reference:** +- web/app/assets/javascripts/playbackControls.js: Slider calculation (lines 142-150, 403-410) +- jamClient method: SessionTrackSeekMs(positionMs) - Seeks to specific position in milliseconds +- Formula: `positionMs = (sliderValue / sliderMax) * durationMs` +- Slider updates during playback: `xPos = (timeMs / durationMs) * sliderWidth` + +**Phase 1 foundation:** +- formatTime utility converts milliseconds to M:SS (lines 25-31) +- Polling useEffect updates currentTime and duration every 500ms (lines 50-83) +- Duration state available in milliseconds (before formatting) +- currentTime state available (formatted as M:SS) + +**Current state:** +- Seek slider hardcoded: min="0" max="100" value="0" (lines 256-269 popup, 352-364 modal) +- handleSeek is placeholder: console.log('Seek to:', e.target.value) (line 147) +- Slider doesn't reflect current position +- Dragging slider has no effect + +**Vision:** +- Slider value reflects current playback position (moves as track plays) +- Dragging slider seeks to that position immediately +- Slider range is 0 to duration in milliseconds +- Works during playback and when paused + + + + + + Task 1: Add state for position in milliseconds + jam-ui/src/components/client/JKSessionBackingTrackPlayer.js + Add state to track current position in milliseconds (separate from formatted currentTime string). This allows the slider to use numeric values while still displaying formatted time. + +Implementation: +- Add state after line 21: `const [currentPositionMs, setCurrentPositionMs] = useState(0);` +- Add state after line 21: `const [durationMs, setDurationMs] = useState(0);` +- Modify initialization useEffect (lines 33-48) to set both: + ```javascript + const durationInMs = jamClient.SessionGetTracksPlayDurationMs(); + setDurationMs(durationInMs); + setDuration(formatTime(durationInMs)); + setCurrentPositionMs(0); + ``` +- Modify polling useEffect (lines 50-83) to set both: + ```javascript + const positionMs = jamClient.SessionCurrrentPlayPosMs(); + const durationInMs = jamClient.SessionGetTracksPlayDurationMs(); + setCurrentPositionMs(positionMs); + setCurrentTime(formatTime(positionMs)); + setDurationMs(durationInMs); + setDuration(formatTime(durationInMs)); + ``` +- Modify handleStop (lines 101-109) to reset position: `setCurrentPositionMs(0);` + +This separates concerns: formatted strings for display, milliseconds for slider calculations. + Check state initialization: +- Open backing track player +- Verify durationMs state is set (use React DevTools) +- Click play, verify currentPositionMs increments every 500ms +- Click stop, verify currentPositionMs resets to 0 + State exists for currentPositionMs and durationMs, properly updated by initialization and polling useEffects + + + + Task 2: Wire slider to reflect current position + jam-ui/src/components/client/JKSessionBackingTrackPlayer.js + Update the seek slider inputs to use real values from state instead of hardcoded values. + +Popup version (lines 256-269): +```javascript + +``` + +Modal version (lines 352-364): +```javascript + +``` + +Key changes: +- max={durationMs || 100} - Use actual duration, fallback to 100 if not loaded +- value={currentPositionMs} - Reflects current position (updates via polling) +- Keep onChange={handleSeek} (will implement in Task 3) + +This makes the slider "live" - it will automatically move as playback progresses due to the polling useEffect updating currentPositionMs. + Play backing track: +- Verify slider knob moves smoothly from left to right as track plays +- Slider should be at ~20% when currentTime shows ~1:00 of a 5:00 track +- Pause playback, verify slider stops moving +- Resume playback, verify slider continues moving +- Slider fills completely when track finishes + Slider visually reflects current playback position, moves during playback, accurate to within 500ms + + + + Task 3: Implement functional handleSeek + jam-ui/src/components/client/JKSessionBackingTrackPlayer.js + Replace the placeholder handleSeek function (line 147) with functional implementation that calls jamClient.SessionTrackSeekMs(). + +Implementation: +```javascript +const handleSeek = async (e) => { + const seekPositionMs = parseInt(e.target.value); + + try { + // Update local state immediately for responsive UI + setCurrentPositionMs(seekPositionMs); + setCurrentTime(formatTime(seekPositionMs)); + + // Seek the native client to the new position + await jamClient.SessionTrackSeekMs(seekPositionMs); + } catch (error) { + console.error('Error seeking:', error); + } +}; +``` + +Pattern explanation: +- Get seekPositionMs from slider value (already in milliseconds due to Task 2) +- Update state immediately (optimistic update for responsive UX) +- Call jamClient.SessionTrackSeekMs(seekPositionMs) to seek native player +- Error handling: log but don't crash + +Note: The polling useEffect will sync the actual position within 500ms, correcting any drift. + +IMPORTANT: Remove the placeholder console.log line entirely. + Test seek functionality: +- Open backing track, click play +- Drag slider to middle (e.g., 2:30 of 5:00 track) +- Verify playback jumps to that position (audio changes) +- Verify time display updates to match slider position +- Drag slider while paused - should work identically +- Drag to end, verify track near completion +- Drag to beginning, verify track restarts +- Check console for errors (should be none) + Seek slider fully functional, dragging seeks to position, works during playback and when paused, no console errors + + + + + +Before declaring phase complete: +- [ ] Open backing track player, verify slider starts at far left (0:00) +- [ ] Click play, verify slider moves smoothly from left to right +- [ ] Verify slider position matches time display (e.g., ~40% at 2:00 of 5:00 track) +- [ ] Drag slider to middle while playing, verify playback jumps and audio changes +- [ ] Verify time display updates to match dragged position +- [ ] Pause playback, drag slider, verify seeking works when paused +- [ ] Drag to very end, verify track near completion (within 1 second) +- [ ] Drag to beginning (far left), verify track restarts from 0:00 +- [ ] Check browser console for errors (should be none) +- [ ] Verify both modal and popup versions work identically + + + + +- currentPositionMs and durationMs state exists and updates correctly +- Seek slider value reflects real playback position (live updates) +- Slider range is 0 to actual duration in milliseconds +- handleSeek calls jamClient.SessionTrackSeekMs() with correct position +- Seeking works during playback and when paused +- Audio playback position changes when slider is dragged +- Time display updates to match slider position +- No console errors during seek operations +- Functional parity with legacy web seek behavior + + + +After completion, create `.planning/phases/02-backing-track-seek-controls/02-01-SUMMARY.md`: + +# Phase 2 Plan 1: Backing Track Seek Controls Summary + +**Functional seek slider with drag-to-position capability using jamClient.SessionTrackSeekMs()** + +## Accomplishments + +- Added currentPositionMs and durationMs state for numeric slider calculations +- Wired slider to reflect live playback position via polling updates +- Implemented handleSeek with jamClient.SessionTrackSeekMs() integration +- Slider now functional during both playback and pause + +## Files Created/Modified + +- `jam-ui/src/components/client/JKSessionBackingTrackPlayer.js` - Added position state, wired slider, implemented seek + +## Decisions Made + +- Separate state for milliseconds (slider calculations) vs formatted strings (display) +- Optimistic UI update before jamClient call for responsive UX +- Polling useEffect auto-corrects position drift within 500ms +- Works identically during playback and when paused (no special handling needed) + +## Issues Encountered + +(None expected - straightforward slider integration) + +## Next Phase Readiness + +Phase 3 (Backing Track Finalization) can now proceed. The player has complete core functionality (play/pause/stop, time display, seek). Phase 3 will add: +- Comprehensive error handling (jamClient failures, file not found, invalid formats) +- Edge cases (seek beyond duration, rapid seeks, seek during stop transition) +- Performance optimization (reduce polling frequency when not visible, cleanup on unmount) +- UI polish (loading states, disabled states during transitions) +