summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2026-07-26 23:13:10 +0200
committercashmere <cashmere@autistici.org>2026-07-26 23:13:10 +0200
commit607f9717ae44efe8f135b6c79ed85a583f3d2d1d (patch)
tree1ee36e343355f6362e5a4ec74e256daf71080e53
parent2f5ff9fefbd968387edb1394377e26ea7df03cd5 (diff)
downloadopencut-607f9717ae44efe8f135b6c79ed85a583f3d2d1d.tar.gz
docs: add roadmap and session notes
Captures the freeze-duration-prompt task, GPU/CPU rendering state, prioritized roadmap (strip landing/branding, disable unfinished domains, self-contained project files, voice-over, versioning, desktop binary), and known pre-existing breakage.
-rw-r--r--notes/roadmap.md119
1 files changed, 119 insertions, 0 deletions
diff --git a/notes/roadmap.md b/notes/roadmap.md
new file mode 100644
index 00000000..5e2b4e86
--- /dev/null
+++ b/notes/roadmap.md
@@ -0,0 +1,119 @@
+# Roadmap & session notes
+
+Working notes for the fork's development direction. Captured 2026-07-26
+(last commit `2f5ff9fe`; everything below "Done" is committed).
+
+## Done
+
+- Freeze frame at playhead (snowflake button), composite canvas capture.
+- Freeze frame is a single undo step (`BatchCommand` + `ShiftSplitRemainderCommand`).
+- `MediaPreview` no longer crashes on image assets without `url` (thumbnail → placeholder fallback).
+- Test suite runs on NixOS/bun 1.3 via `bunfig.toml` preload mock of `opencut-wasm`.
+- Root `justfile` wraps common commands; `just` is in the nix devshell.
+
+Pending verification: freeze + single Ctrl+Z is unit-tested but never
+smoke-tested by hand in a running browser.
+
+## Tomorrow: freeze-duration prompt
+
+Replace the hardcoded 3 s (`mediaTimeFromSeconds({ seconds: 3 })` in the
+`freeze-frame` handler, `apps/web/src/actions/use-editor-actions.ts`) with a
+small dialog asking for the duration before capture. Notes:
+
+- Dialog components live in `apps/web/src/components/ui/` (shadcn-style radix).
+- Keep the value a `MediaTime` (`mediaTimeFromSeconds`); validate > 0.
+- Nice touch: remember the last-used duration in a zustand UI store
+ (`*-store.ts`, UI/preference state only — never document state).
+- The action is invoked from the toolbar button and (if bound) the shortcuts
+ UI; the prompt should appear for both paths, so put it in the handler, not
+ the toolbar.
+
+## GPU vs CPU: what actually runs where (as of 2026-07-26)
+
+Investigated `apps/web/src/services/renderer/` + `core/managers/renderer-manager.ts`.
+
+**GPU (wgpu/WebGPU, via the Rust `opencut-wasm` package):**
+
+- Final compositing of EVERY frame, preview and export alike
+ (`CanvasRenderer.render` → resolve → build frame descriptor → upload
+ textures → wasm `renderFrame`). The preview canvas literally is the wasm
+ compositor's canvas.
+- Effect passes (WGSL shaders) via `gpuRenderer.applyEffect`.
+- Mask feathering via `gpuRenderer.applyMaskFeather`.
+
+**Hardware-accelerated (WebCodecs, platform-dependent, via mediabunny):**
+
+- Video decode for playback/thumbnails.
+- Video encode on export.
+
+**CPU:**
+
+- Scene graph resolve, layout, animation sampling.
+- Text/sticker/graphic rasterization into 2d canvases (then uploaded as GPU
+ textures).
+- Audio mixing (`AudioBuffer`), waveform/thumbnail generation.
+
+**No CPU compositing fallback exists.** Without WebGPU: a "degraded" banner
+shows, effects and mask feather are silently skipped, and `initCompositor`
+throws — the preview cannot render at all. This matters for the Linux/BSD
+first-class goal: WebGPU on Linux is Chrome-only today (Firefox behind a
+flag), and effectively absent on BSD. Browser-first-class on those platforms
+would need a fallback compositor (Canvas2d or WebGL) — a significant piece of
+work. The GPUI desktop app sidesteps it entirely (native GPU).
+
+## Roadmap (priority order, owner's call)
+
+1. **Strip the landing page.** App should open straight into the editor /
+ project list. The marketing front page is dead weight.
+2. **Strip upstream-branded links**: Discord link, "Send feedback" button.
+3. **Disable (or remove) sounds, stickers, effects** — unfinished or buggy
+ upstream. Prefer disabling behind a flag/registry skip first; delete once
+ proven unnecessary. Effects are GPU shader passes + a registry
+ (`registerDefaultEffects`); stickers and sounds each live in their own
+ domain folders, so excision is mechanically easy.
+4. **Project import/export as one self-contained file.** Project JSON +
+ all media bundled in a single archive. Storage layer
+ (`services/storage/`) already serializes projects (versioned migrations);
+ media lives in IndexedDB as `File`s, so export = project JSON + media
+ blobs into a zip; import = reverse through the same migration pipeline.
+5. **Voice-over recording.** `MediaRecorder` (mic) → audio `MediaAsset` →
+ drop on timeline at playhead. The audio pipeline (assets, tracks,
+ waveform) already exists; this is mostly UI + recording plumbing.
+6. **Git-like project versioning.** Named snapshots + history per project.
+ The save manager and versioned storage are the natural foundation;
+ snapshot blobs could reuse the export format from (4). Hardest and most
+ novel item — design note needed before code.
+7. **Self-contained binary, first-class Linux + BSD.** `apps/desktop` (GPUI)
+ is the vehicle but is a hello-world scaffold today; porting the editor is
+ a large effort. Caveat: GPUI's Linux support is young; BSD support is
+ unproven — spike before committing. Browser version stays regardless
+ (editing in a browser is a feature, not a compromise).
+
+## Deprioritized / parked
+
+- Default keybinding for freeze frame — not wanted; the shortcuts UI already
+ lets users bind it. A fuller "dynamic keybinding" feature is mostly
+ already upstream (persisted keybindings store + shortcuts UI).
+- Per-clip (non-composite) freeze capture — owner unconvinced; parked.
+ Would need a single-element render pass in the GPU renderer.
+
+## Known pre-existing breakage (cleanup someday)
+
+- `keybindings/__tests__/persistence.test.ts` imports
+ `isActionWithOptionalArgs`, which does not exist anywhere — dead test file.
+- Mask tests need a canvas 2d context bun doesn't provide (DOM-dependent).
+- `custom mask point insertion` test asserts zero handles; code computes
+ ±0.1 — stale test or stale code, never ran in CI to catch it.
+- `resolve.test.ts` passes fractional ticks into the validated `mediaTime()`
+ constructor — test bug.
+- `eslint/rules/__tests__/prefer-object-params.test.mjs` uses `.only`,
+ blocked when `CI` is set.
+- `apps/web/drizzle.config.ts` points at the stale schema path
+ `./src/lib/db/schema.ts` (real one: `src/db/schema.ts`).
+
+## Vision principles (owner's words, condensed)
+
+- Unix philosophy: do one thing well. Open the editor, do your stuff, move on.
+- Offline-first, privacy-first: projects and media stay local (IndexedDB).
+- First-class Linux and BSD.
+- Keep the browser editor — editing projects in a browser is a feature.