- Guard drawPlayhead on session.duration > 0 in PlayerTimeline - Move floating controls pill from bottom: 24px to 48px - Add playerControlsVisible prop to VideoPlayer; captions slide up 160px when controls visible - Replace web Fullscreen API with Tauri getCurrentWindow().setFullscreen() (WKWebView compat) - Add core:window:allow-set-fullscreen and core:window:allow-is-fullscreen permissions - Tie PlayerTimeline visibility to showPlayerControls; remove unused proximity logic Co-authored-by: Cursor <cursoragent@cursor.com>
4.2 KiB
4.2 KiB
v0.2.0 Player Mode — Implementation Summary
Task Description
Implemented all 9 tasks from the v0.2.0 Player Mode implementation plan using subagent-driven development (SDD). This is the execution phase following the design spec and plan created in an earlier session.
Changes Made
11 commits (bd96da4..7e838dc)
| Commit | Description |
|---|---|
bd96da4 |
Task 1: appMode preference (clipper/player) with persistence |
d9f5874 |
Task 2: PiP, fullscreen, playbackRate helpers in playback module |
bb5fa4b |
Task 3: SpeedSelector popup component |
f717687 |
Task 4: PlayerControls floating overlay (frosted glass, seek bar, all controls) |
56686a3 |
Task 5: PlayerTimeline simplified waveform component |
d36138c |
Task 6: Player/Clipper mode switching with auto-hide UI in App.svelte |
199ad1c |
Task 6 fix: transport shortcuts fallback via runTransportAction for Player mode |
3e219b7 |
Task 7: Conditional CC rendering, click-to-play, bindable captionsEnabled |
2472dec |
Task 7 fix: bind captionsEnabled between App and VideoPlayer |
1a86a34 |
Task 8: FLIP transitions (fly/fade + CSS grid transition) |
7e838dc |
Task 9: Version bump 0.1.3 → 0.2.0 |
Files (17 changed, +1327 −92)
New files:
src/lib/components/PlayerControls.svelte— floating overlay with seek bar, play/pause, skip, volume, speed, CC, PiP, fullscreensrc/lib/components/PlayerTimeline.svelte— simplified waveform-only timelinesrc/lib/components/SpeedSelector.svelte— playback speed popup (0.5x–2x)tests/lib/components/SpeedSelector.test.ts— 3 component teststests/lib/stores/preferences.test.ts— 3 preference teststests/lib/transport/playback.test.ts— 10 playback helper tests
Modified files:
src/App.svelte— mode switching, auto-hide, keyboard shortcuts, layout conditionalssrc/app.css— grid transitions, player-mode positioningsrc/lib/components/VideoPlayer.svelte— bindable captionsEnabled, click-to-play, conditional CCsrc/lib/stores/preferences.svelte.ts— appMode field + persistencesrc/lib/transport/playback.ts— PiP, fullscreen, playbackRate exportsvite.config.ts— svelteTesting() plugin for Svelte 5 component tests
Key Architecture Decisions
- Single always-mounted VideoPlayer — video element stays in DOM across mode switches, avoiding destruction/recreation
- Proximity-based auto-hide — controls: any mouse move + 3s timeout; toolbar: 50px from top; timeline: 80px from bottom
- Transport fallback —
dispatchTransport()falls back torunTransportAction()when TransportControls is null (Player mode) - CSS Grid transitions —
.contentanimates grid-template changes for smooth layout shifts - Polling for PiP/fullscreen state — PlayerControls polls
isPiPActive()/isFullscreenActive()at 500ms
Bugs Found & Fixed
- Transport shortcuts no-op in Player mode — TransportControls not rendered →
transportControlsnull → all playback shortcuts broken. Fixed withrunTransportActionfallback. - captionsEnabled not bound — App.svelte and VideoPlayer had separate
captionsEnabledstates. Fixed withbind:captionsEnabled.
Lessons Learned
- When a component that handles keyboard dispatch is conditionally rendered, always provide a fallback path for the keyboard handler
- Svelte 5 bindable props require explicit
$bindable()wrapper and typed$props()destructuring - Svelte 5 component testing in vitest/jsdom needs
svelteTesting()plugin in vite config (not documented in the plan) - Timer-based click/double-click discrimination (250ms delay) is the standard pattern for video players
Test Results
- 8 test files, 47 tests passing
- svelte-check: 0 errors (1 pre-existing a11y warning — missing tabindex on slider role)
Follow-up Items
- Add
tabindex="0"to PlayerControls seek bar slider role (a11y warning) - Remove dead
handleVideoClick()function in VideoPlayer.svelte (unused, superseded byhandleVideoClickWithDelay) - Consider event-based PiP/fullscreen state updates instead of 500ms polling
- Visual QA with
npm run tauri devfor transition smoothness