Architecture Overview
nque is split into three cooperating layers.
┌─────────────────────────────────────────────────────────────┐
│ React 19 frontend (src/) │
│ components · Zustand slices · lib/tauri.ts · lib/events.ts │
└───────────────▲───────────────────────────────┬─────────────┘
│ invoke(command) │ emit/listen(event)
┌───────────────┴───────────────────────────────▼─────────────┐
│ Tauri 2 shell (src-tauri/) │
│ lib.rs wiring · commands.rs · window management │
└───────────────▲─────────────────────────────────────────────┘
│ plain Rust calls
┌───────────────┴─────────────────────────────────────────────┐
│ Cargo workspace crates (crates/) │
│ shared · ocr (ingest) · classify · show (construct/filter) │
└─────────────────────────────────────────────────────────────┘
Frontend
A React SPA built with Vite, styled with Tailwind CSS 4 and shadcn/ui, with all
global state in Zustand. It never talks to the filesystem directly; it calls
Tauri commands through thin wrappers in src/lib/tauri.ts and subscribes to
events via src/lib/events.ts. See Frontend and
State management.
Tauri shell
src-tauri/ owns the app lifecycle, the window definitions, and the
invoke_handler that registers every command. It contains almost no business
logic: it resolves native dialogs, marshals arguments, moves blocking work onto
a blocking thread, and emits progress events. See Backend.
Domain crates
The real logic lives in a Cargo workspace under crates/:
| Crate | Responsibility |
|---|---|
shared | Small cross-crate pure utilities. |
ocr | Ingest — PDF → text (native text layer, else render + OCR). |
classify | Classify — line-level heading, stage-direction, and dialog rules. |
show | Construct + filter — build the show tree, clean it, save/load it. |
Keeping the pipeline in plain Rust crates (not src-tauri) makes it testable
without a Tauri runtime and reusable outside the desktop app.
Data flow of a PDF import
- Frontend calls
import_pdf_show. - Tauri opens a file dialog and reads the PDF bytes.
ocr::pipeline::extract_textprobes the text layer and extracts or OCRs.show::pipeline::build_show_from_textclassifies, constructs, and filters.- Progress is emitted as
ocr-import-progressevents throughout. - The resulting
ShowFileis returned and loaded into the store.
Continue with Processing pipelines.