Rust core vs TypeScript frontend split #3

Closed
opened 2026-10-06 03:55:51 +00:00 by crowmaki · 1 comment
Owner

Part of #1

Question

Which responsibilities live in the Tauri Rust side (SQLite, render worker, ComfyUI client, file I/O, atlas composition, export) and which in SvelteKit/TS? What does the command/event boundary between them look like?

Part of #1 ## Question Which responsibilities live in the Tauri Rust side (SQLite, render worker, ComfyUI client, file I/O, atlas composition, export) and which in SvelteKit/TS? What does the command/event boundary between them look like?
Author
Owner

Resolution

Crates. A Cargo workspace:

  • studio-core has no Tauri or specta dependency. It holds the domain model, SQLite, OSF import, Lock snapshot rules, staleness, Atlas composition, the prompt composer, the slot budget, the render queue and worker, the ComfyUI client, ffmpeg calls, and export (FCPXML, CSV, folder layout).
  • src-tauri is a thin adapter.

Database. Only Rust opens the .studio file. The frontend changes state only through named domain commands.

Frontend. Svelte 5 holds view state, interaction, and the Board paint canvas, including its local stroke undo until a save.

Boundary.

  • taurpc procedures for commands. DTOs are defined in src-tauri and mapped from studio-core view-shaped read models, so the core stays free of specta.
  • Coarse changed { kind, ids } invalidation events, after which the UI refetches what it is showing.
  • tauri::ipc::Channel for per-job progress. Events stay app-wide broadcasts only.
  • Commands return a typed error enum.
  • Long non-render operations (OSF import, export) are async commands with a progress Channel.

Undo. App-level undo is a Rust command log, per Project, kept in memory, and cleared when the Project closes. It covers authored edits only: merges, retags, Setup and Shot edits, Line ranges, circling, Board saves, and Location folders. Locking, queuing or rendering, generating, and importing media are append-only provenance and never undoable. Cancelling a queued or in-flight job is a separate, explicit queue command.

Media. One custom studio: scheme, registered with the async variant:

  • studio://blob/<id> serves blobs from SQLite.
  • studio://rendition/<id> serves Renditions with Range/206 support, chunked.

URLs carry ids, not paths, and the webview gets no file scope. Content-hash cache headers suit Atlases.

ffmpeg. An unmodified LGPL build ships as a Tauri sidecar and is called only by Rust. It handles posters and thumbnails, audio extraction and decoding, and remuxing. It never encodes Renditions; ComfyUI does that.

Pixels. Rust produces every stored or derived image, deterministic and byte-stable:

  • Boards are flattened from separately stored sketch and Annotation layer PNGs.
  • Atlases are built with the image crate.
  • Tile crops are cut from the original import, with the UI only drawing rectangles.

Sessions. One Project per process, with possibly several windows that all receive the same events. The core holds a single ProjectSession (connection, undo stack, worker). The worker belongs to the session.

Handed on:

  • Render worker scheduling: job cancellation, and what happens to the queue when the Project closes and reopens.
  • Shipped workflow roster and slot contracts: Rendition codecs must play in WebView2 (H.264/AAC), or ffmpeg makes proxies.

Recorded as ADR-0003 (docs/adr/0003-rust-core-owns-the-domain.md).

Facts (Tauri 2.12):

  • The asset handler and the custom-scheme streaming example both support Range on WebView2.
  • tauri-specta is still at rc.25.
  • The Tauri docs recommend Channels for progress.
## Resolution **Crates.** A Cargo workspace: - `studio-core` has no Tauri or specta dependency. It holds the domain model, SQLite, OSF import, Lock snapshot rules, staleness, Atlas composition, the prompt composer, the slot budget, the render queue and worker, the ComfyUI client, ffmpeg calls, and export (FCPXML, CSV, folder layout). - `src-tauri` is a thin adapter. **Database.** Only Rust opens the `.studio` file. The frontend changes state only through named domain commands. **Frontend.** Svelte 5 holds view state, interaction, and the Board paint canvas, including its local stroke undo until a save. **Boundary.** - `taurpc` procedures for commands. DTOs are defined in `src-tauri` and mapped from `studio-core` view-shaped read models, so the core stays free of specta. - Coarse `changed { kind, ids }` invalidation events, after which the UI refetches what it is showing. - `tauri::ipc::Channel` for per-job progress. Events stay app-wide broadcasts only. - Commands return a typed error enum. - Long non-render operations (OSF import, export) are async commands with a progress Channel. **Undo.** App-level undo is a Rust command log, per Project, kept in memory, and cleared when the Project closes. It covers authored edits only: merges, retags, Setup and Shot edits, Line ranges, circling, Board saves, and Location folders. Locking, queuing or rendering, generating, and importing media are append-only provenance and never undoable. Cancelling a queued or in-flight job is a separate, explicit queue command. **Media.** One custom `studio:` scheme, registered with the async variant: - `studio://blob/<id>` serves blobs from SQLite. - `studio://rendition/<id>` serves Renditions with Range/206 support, chunked. URLs carry ids, not paths, and the webview gets no file scope. Content-hash cache headers suit Atlases. **ffmpeg.** An unmodified LGPL build ships as a Tauri sidecar and is called only by Rust. It handles posters and thumbnails, audio extraction and decoding, and remuxing. It never encodes Renditions; ComfyUI does that. **Pixels.** Rust produces every stored or derived image, deterministic and byte-stable: - Boards are flattened from separately stored sketch and Annotation layer PNGs. - Atlases are built with the `image` crate. - Tile crops are cut from the original import, with the UI only drawing rectangles. **Sessions.** One Project per process, with possibly several windows that all receive the same events. The core holds a single `ProjectSession` (connection, undo stack, worker). The worker belongs to the session. **Handed on:** - Render worker scheduling: job cancellation, and what happens to the queue when the Project closes and reopens. - Shipped workflow roster and slot contracts: Rendition codecs must play in WebView2 (H.264/AAC), or ffmpeg makes proxies. Recorded as ADR-0003 (`docs/adr/0003-rust-core-owns-the-domain.md`). Facts (Tauri 2.12): - The asset handler and the custom-scheme streaming example both support Range on WebView2. - tauri-specta is still at rc.25. - The Tauri docs recommend Channels for progress.
Sign in to join this conversation.
No description provided.