···3333### Crate dependency order
34343535```
3636-tala-format → tala-srs → tala-typst (planned) → tala-ui (planned)
3636+tala-format → tala-srs → tala-typst → tala
3737 ↑
3838 tala-cli (consumes both)
3939```
···63636464Binary crate producing the `tala` binary. Two subcommands: `check` (parse + sidecar cross-check) and `review` (stubbed).
65656666-### Planned: `tala-typst`
6666+### `tala-typst`
67676868Render typst source strings to RGBA via the `typst` crate. Requires implementing `typst::World`. Two preambles: authoring (renders full card) and review (blanks replaced by boxes). Font loading must provide at least one valid font family or typst panics.
69697070-### Planned: `tala-ui`
7171-7272-Native Floem UI. **Use `floem = { git = "https://github.com/lapce/floem" }` — do not use the crates.io 0.2 release, it is over a year out of date.** Use floem's re-exported wgpu; do not add wgpu as an independent dependency or you risk duplicate version splits.
73707471## Deck directory layout
7572
···186186 let args = args_of(node)?;
187187 let (named, tags, content_blocks) = collect_args(&args);
188188189189- let id = named.get("id")?.clone();
189189+ // id is optional — empty string signals "needs auto-assignment"
190190+ let id = named.get("id").cloned().unwrap_or_default();
190191 if content_blocks.len() < 2 {
191192 return None;
192193 }
···211212 let args = args_of(node)?;
212213 let (named, tags, content_blocks) = collect_args(&args);
213214214214- let id = named.get("id")?.clone();
215215+ let id = named.get("id").cloned().unwrap_or_default();
215216 let body_span = content_blocks.first()?.clone();
216217217218 // Walk the body ContentBlock for #blank[] calls.
···231232 let args = args_of(node)?;
232233 let (named, tags, _) = collect_args(&args);
233234234234- let id = named.get("id")?.clone();
235235+ let id = named.get("id").cloned().unwrap_or_default();
235236 let src = named.get("src")?.clone();
236237237238 Some(CardEntry {