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
+
+
+