diff --git a/docs/superpowers/plans/2026-09-21-video-clipper.md b/docs/superpowers/plans/2026-09-21-video-clipper.md new file mode 100644 index 0000000..3d9003c --- /dev/null +++ b/docs/superpowers/plans/2026-09-21-video-clipper.md @@ -0,0 +1,5884 @@ +# Video Clipper Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Build a macOS GUI app (Tauri v2 + Svelte 5) that lets users paste a video URL, scrub a timeline, mark clips, and export them via ffmpeg — without manually downloading the video first. + +**Architecture:** Rust backend manages subprocess orchestration (yt-dlp, ffmpeg, ffprobe) and communicates with a Svelte 5 frontend via Tauri commands and channels. The frontend provides a Canvas-based timeline with thumbnail strip, waveform, clip markers, and zoom. A hybrid playback model streams video immediately for preview while downloading in the background for export. + +**Tech Stack:** Tauri v2, Svelte 5 (runes), Rust, TypeScript, Vitest, ffmpeg, ffprobe, yt-dlp, deno (for PO token generation) + +## Global Constraints + +- **Platform:** macOS only (MVP) +- **Rust edition:** 2021 +- **Node.js:** v24+ (already installed) +- **Tauri:** v2 latest stable +- **Svelte:** v5 (runes syntax: `$state`, `$derived`, `$effect`) +- **External deps:** ffmpeg, yt-dlp, deno, bgutil-ytdlp-pot-provider (checked at runtime, not bundled) +- **Cookie default:** `--cookies-from-browser firefox` +- **All yt-dlp invocations** must include the user's configured cookie source flags +- **Imports:** Always at top of file, never inline +- **Switch exhaustiveness:** Use `never` check in default case for discriminated unions + +--- + +## File Structure + +``` +gui-video-clipper/ +├── src-tauri/ +│ ├── Cargo.toml +│ ├── tauri.conf.json +│ ├── capabilities/ +│ │ └── default.json +│ ├── build.rs +│ └── src/ +│ ├── lib.rs # Tauri entry, plugin + command registration +│ ├── models.rs # Shared Rust types (VideoMetadata, ExportConfig, etc.) +│ ├── commands/ +│ │ ├── mod.rs # Re-exports all command modules +│ │ ├── dependencies.rs # check_dependencies, install_dependency +│ │ ├── video.rs # resolve_url, start_download, cancel_download +│ │ ├── media_analysis.rs # extract_keyframes, extract_waveform, extract_thumbnails +│ │ └── export.rs # export_clips +│ └── services/ +│ ├── mod.rs # Re-exports all service modules +│ ├── dependency_manager.rs # Dependency check/install logic +│ ├── video_resolver.rs # yt-dlp metadata + stream URL extraction +│ ├── download_manager.rs # Background download + progress parsing +│ ├── keyframe_index.rs # ffprobe keyframe extraction +│ ├── waveform_generator.rs # ffmpeg audio peak extraction +│ ├── thumbnail_extractor.rs # ffmpeg frame extraction + sprite sheet packing +│ └── clip_exporter.rs # ffmpeg lossless/precise/merged export +├── src/ +│ ├── App.svelte # Root component — layout shell +│ ├── main.ts # Svelte mount entry point +│ ├── app.css # Global styles + CSS custom properties +│ ├── vite-env.d.ts +│ └── lib/ +│ ├── stores/ +│ │ ├── videoSession.svelte.ts # Video state (metadata, stream, download progress) +│ │ ├── clips.svelte.ts # Clip CRUD, selection, pending in-point +│ │ └── preferences.svelte.ts # Output dir, cookie source, window bounds +│ ├── components/ +│ │ ├── UrlInput.svelte # URL text field with paste detection +│ │ ├── VideoPlayer.svelte #