From cd0331d4cef0050c090326354dda09b0295e067f Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Thu, 16 Apr 2026 16:57:29 +0200 Subject: [PATCH] docs: add Tauri + Svelte client design Co-Authored-By: Claude Opus 4.6 --- docs/plans/2026-04-16-client-design.md | 148 +++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 docs/plans/2026-04-16-client-design.md diff --git a/docs/plans/2026-04-16-client-design.md b/docs/plans/2026-04-16-client-design.md new file mode 100644 index 0000000..8bd97ad --- /dev/null +++ b/docs/plans/2026-04-16-client-design.md @@ -0,0 +1,148 @@ +# 8-cut Client Design + +## Goal + +Build a Tauri + Svelte desktop client that connects to the 8-cut server API for remote video editing. Full feature parity with the Qt app. Targets Linux first, then Mac. + +## Architecture + +``` +Tauri app (Rust shell + Svelte webview) +├── mpv sidecar (bundled binary) +│ ├── plays video: http://server/api/stream/{path}?quality=low +│ ├── plays audio: http://server/api/audio/{path} +│ └── controlled via JSON IPC socket +├── Svelte UI +│ ├── File browser +│ ├── Canvas timeline (markers, cursor, play region) +│ ├── Canvas crop overlay +│ ├── Export controls + WebSocket progress +│ └── Settings panel (profile, subprofiles, quality) +└── Rust backend + ├── Spawn/manage mpv process + IPC + ├── Proxy server API calls (avoid CORS) + └── Tauri commands exposed to Svelte frontend +``` + +## Playback + +mpv runs as a sidecar process, controlled via JSON IPC socket. Two streams: +- Video: `http://server/api/stream/{path}?root={root}&quality={quality}` (transcoded, no audio) +- Audio: `http://server/api/audio/{path}?root={root}` (full quality WAV) + +mpv's `--audio-file=` flag syncs both streams with frame-accurate seeking. + +Quality presets: potato (480p), low (720p), medium (1080p), high (original). + +## Features + +### File management +- Browse server video roots (`GET /api/roots`, `GET /api/files`) +- Hide/unhide files per profile (`POST/DELETE /api/hidden/{filename}`) +- Sort by name/size, filter hidden + +### Playback +- Play/pause/resume from pause point +- AB-loop with current spread/clips settings +- Play region adapts to spread changes without restarting +- Quality selector + +### Timeline (Canvas) +- Cursor position, markers, play position indicator +- Click to seek, drag cursor +- Lock mode: cursor locked to marker, double-click jumps to end of clip span +- Autoclip: when paused, auto-adjust clip count to fit pause position + +### Crop & keyframes +- Portrait ratio selector (9:16, 4:5, 1:1, off) +- Crop center slider with live canvas overlay +- Crop keyframes at arbitrary timeline positions +- Subject tracking (triggered server-side) +- Random portrait/square toggles + +### Export +- Configurable: clips, spread, short side, format (MP4/WebP sequence) +- Label + category annotation +- Encoder selection (libx264 / h264_nvenc) +- Subprofiles with folder suffix routing +- Number keys 1-9 for subprofile quick export, E for main +- WebSocket progress (`WS /ws/export`), per-clip completion +- Delete/re-export from marker context menu + +### Profiles +- Profile switcher, markers reload per profile +- Subprofile management (add/remove) + +### Settings +- Server URL (configurable) +- Default quality preset +- All settings persisted client-side via Tauri store + +## Server API endpoints used + +``` +GET /api/roots +GET /api/files?root={root} +GET /api/video/{path}?root={root} +GET /api/stream/{path}?root={root}&quality={quality} +GET /api/audio/{path}?root={root} +GET /api/cache/status/{path}?root={root} +GET /api/markers/{filename}?profile={profile} +GET /api/profiles +GET /api/labels +POST /api/export +GET /api/export/{job_id} +DELETE /api/export?output_path={path} +POST /api/hidden/{filename}?profile={profile} +DELETE /api/hidden/{filename}?profile={profile} +GET /api/hidden?profile={profile} +WS /ws/export +``` + +## Project structure + +``` +client/ +├── src-tauri/ +│ ├── src/ +│ │ ├── main.rs (Tauri entry, app setup) +│ │ ├── mpv.rs (mpv sidecar spawn + IPC) +│ │ ├── commands.rs (Tauri commands for Svelte) +│ │ └── lib.rs +│ ├── Cargo.toml +│ └── tauri.conf.json +├── src/ +│ ├── App.svelte +│ ├── lib/ +│ │ ├── api.ts (server API client) +│ │ ├── mpv.ts (mpv IPC bridge via Tauri commands) +│ │ ├── ws.ts (WebSocket export progress) +│ │ └── stores.ts (Svelte stores: files, markers, settings) +│ ├── components/ +│ │ ├── FileBrowser.svelte +│ │ ├── Timeline.svelte +│ │ ├── CropOverlay.svelte +│ │ ├── ExportPanel.svelte +│ │ ├── SettingsPanel.svelte +│ │ └── ProfileBar.svelte +│ └── main.ts +├── package.json +└── vite.config.ts +``` + +## Implementation order + +1. Scaffold Tauri + Svelte project +2. mpv sidecar: spawn, IPC, basic play/pause/seek +3. API client module + server connection +4. File browser component +5. Video playback: load file → stream URL → mpv +6. Canvas timeline: cursor, seek, markers +7. Export panel + WebSocket progress +8. Crop overlay + keyframes +9. Lock mode, autoclip, play region +10. Profiles, subprofiles, hidden files +11. Keyboard shortcuts +12. Settings persistence +13. Package for Linux (.deb / .AppImage) +14. Package for Mac (.dmg)