--- name: handover-2026-04-19 type: reference tags: [handover, session, lumotia] description: Session handover — 2026/04/19 dogfood polish + cross-platform window chrome --- # Lumotia Handover — 2026/04/19 *Originally written when the product was named Kon (and briefly Corbie); references rewritten in the 2026-04-30 rebrand sweep.* Second dogfood sprint. Four phases: (1) fix bugs surfaced on first real use, (2) redesign History for cognitive-load hygiene, (3) resolve broken window resize/drag on Linux Wayland, (4) clean up microphone picker. ## What shipped this session ### Cross-window preferences sync - `preferences.svelte.js` emits `lumotia:preferences-changed` Tauri event on update. - Main / viewer / float layouts listen and call `applyExternalPreferences` without re-emit, so theme and font changes propagate live across sibling windows. - Echo suppressed via source window label check. ### Hotkey recorder - Root cause of "can't change hotkey": button-level `onkeydown` relied on post-click keyboard focus, which webkit2gtk on Linux does not guarantee. - Fix: `document.addEventListener("keydown", ..., { capture: true })` inside a `$effect` gated by `recording`. Beats any descendant handler. Escape now cancels. ### History page redesign (research-backed) - Compact row now shows the **title** (or "Untitled"), not body-preview text — metadata already lives in the row columns (date, duration, source icon). - Expanded row gets an inline title input (replaces the old Rename prompt modal). - **Edit** button opens the viewer window in `edit` mode (editable textarea, debounced save to localStorage + storage-event sync back to main history). - **Export .md** copies a full YAML-frontmatter markdown document to the clipboard — paste into Obsidian. - **Tags**: `$lib/utils/frontmatter.js` exposes `deriveAutoTags` (currently returns `[]`), `buildFrontmatter`, `serialiseFrontmatter`, `buildMarkdown`. Manual tags stored as `item.manualTags`, rendered as removable chips in the expanded row with `+ add tag` input. - Header tag chip bar (cap 7, click to filter, × to clear), plus `tag:xyz` search syntax. - Global **Starred** filter toggle in the History header. - Research memo found all five previous auto-tag families redundant with existing row UI — kept the derivation hook for the post-Task-7 `topic:*` content tag from lumotia-llm. - Duplicate-transcript render fix: expanded `

` only if compact preview actually truncated. ### Viewer / editor popout - `/viewer` route now reads `lumotia_viewer_mode` from localStorage ("view" | "edit"). - Edit mode renders a plain textarea bound to `item.text`; 400ms debounced save flushes on input, final flush on `onDestroy`. Segment-specific controls (Compact, Starred) hidden in edit mode. - Native title: **"Lumotia - Transcription Editor"**. ### Platform-aware window chrome (Linux fix) **Root cause:** Tauri v2 frameless `decorations: false` on KDE Wayland + webkit2gtk does not honour diagonal corner resize (collapses `NorthEast` etc. to a single axis via GTK's `gtk_window_begin_resize_drag`), and `data-tauri-drag-region` adds noticeable drag latency. Setting `setPointerCapture` ahead of `startResizeDragging` does not help once the compositor has taken over the pointer grab. Verified via Context7 docs + Codex diagnosis — Linux frameless is a known-fragile path. **Fix:** - Linux uses **native KWin/Mutter decorations**. `src-tauri/tauri.linux.conf.json` overlays `decorations: true` + full main window config (title, sizes) — overlays **replace** the windows array, so every field must be present, not just the delta. `src-tauri/src/commands/windows.rs` uses `cfg!(target_os = "linux")` to set decorations per window. - macOS / Windows keep custom chrome. `src/lib/utils/osInfo.js` `isLinux()` gates `` and `` via `useCustomChrome = $state(false)`; flips to `!isLinux()` after `loadOsInfo()` resolves. - Dueling drag-region handlers removed across Titlebar, float page, viewer page — everywhere a manual `startDragging()` lives, the `data-tauri-drag-region` attribute was deleted (they're alternatives per Tauri docs, not combinable). - `ResizeHandles` kept for macOS/Windows frameless: 12 px edges / 20 px corners via CSS vars (`--lumotia-resize-edge`, `--lumotia-resize-corner`), `pointerdown` + `setPointerCapture`, corners with explicit higher z-index. Handles rendered as siblings of the animated layout div so `position: fixed` is viewport-relative rather than captured by the transform containing block. ### Window minimum sizes (evidence-backed) Research pass cited GNOME HIG (1024×600 desktop / 360×294 mobile floors), WCAG 2.2 SC 1.4.10 Reflow (320 CSS px), Raycast 750×474 as a reference for single-pane working width, and consistent A11y principle that nothing should clip in the default configuration. | Window | Was | Now | Rationale | |---|---|---|---| | Main | 1020×540 | **960×600** | Fits 210 px sidebar + ~750 px content; GNOME vertical floor. | | Float | 400×400 | **360×480** | 360 = GNOME mobile floor; 480 fits pills + quick-add + sort + ~6 task rows without scroll. | | Transcript editor | 450×500 | **560×520** | Exceeds WCAG reflow floor; ~60-70 char measure for editing. | ### Microphone picker cleanup - ALSA enumeration was leaking `hw:`, `plughw:`, `front:`, `sysdefault:`, `null` et al into the dropdown. - `SettingsPage.svelte` now renders only sentinel devices (`default`, `pipewire`, `pulse`) + one entry per unique sound card, keyed off the `sysdefault:CARD=X` alias. - `crates/audio/src/capture.rs` reads `/proc/asound/cards` and populates a new `description` field on `DeviceInfo` with the card's full product string (e.g. "Blue Microphones" for Jake's Yeti). Frontend prefers description → CARD=X short name → raw name. ### GPU reporting - `commands/models.rs::get_runtime_capabilities` was hardcoded to `accelerators: vec!["cpu"]` and `supports_gpu: false` for whisper. Updated to `["cpu", "vulkan"]` and whisper `supports_gpu: true`, reflecting that `crates/transcription/Cargo.toml` links transcribe-rs with the `whisper-vulkan` feature unconditionally. - Settings now shows the Vulkan option instead of the "This build is CPU-only" notice. ### Desktop shortcut - `~/Desktop/Lumotia.desktop` launcher with the 128×128 icon, `Terminal=true` so logs are visible and Ctrl+C cleanly stops the run.sh wrapper. ## What's deferred - **Transparent windows (`transparent: true`)** — Tauri issue #13270 reports this smooths drag/resize further on Linux, but it's moot now that Linux uses native decorations. - **File-system export (.md save dialog)** — currently clipboard-only. Needs a Rust `write_text_file` command for plugin-less file writes. - **Bulk select + bulk export** in History. - **LLM-powered content tags** (`topic:*`, `intent:*`) — slots into Task 7 `lumotia-llm` stub once Phase 3 wires real llama-cpp-2. - **Settings UX overhaul** — Jake flagged that current settings feel overwhelming. Proposed: bunch high-traffic settings, hide advanced behind a toggle. Brainstorm + plan deferred to a dedicated session. - **Task 7 (MicroSteps end-to-end)** — storage + Tauri CRUD + lumotia-llm stub + frontend dual-write all landed in an earlier commit chain. The MicroSteps UI was written as the final task 7 step but not yet dogfooded against the stub LLM. Needs manual walkthrough. ## Gotchas discovered today | Issue | Fix | |---|---| | `tauri.linux.conf.json` stripped title and min sizes from main window | Overlay **replaces** the windows array — include every field, not just the delta | | `data-tauri-drag-region` + manual `startDragging()` on the same node caused drag latency | Pick one — we use manual `startDragging` for the button/input early-return logic | | Corner resize collapsed to single axis on KWin Wayland | Native decorations on Linux side-step the whole frameless path | | `animate-float-enter` on the viewer/float layout root created a containing block that broke `position: fixed` on ResizeHandles children | Render ResizeHandles as a sibling of the animated div, not a descendant | | Lumotia binary auto-respawned on file-save while a second run.sh was also launching → two visible instances sharing one Vite server | Do not script `./run.sh` while the user has already launched via the desktop icon; rely on HMR | | `run.sh` leaves `"beforeDevCommand": ""` in tauri.conf.json if its cleanup trap is bypassed (e.g. SIGKILL) | Cleanup trap restores `"npm run dev"` on graceful exit; SIGTERM (not SIGKILL) is the right kill signal | | `/proc/asound/cards` header lines have leading whitespace for 2-digit card ID alignment | Parser trims leading whitespace before checking for leading digit | ## How to resume ``` Picking up Lumotia dogfooding from 2026/04/19. HANDOVER is at HANDOVER.md in the project root. Active priorities: (1) confirm resize/drag/mic cleanup, (2) Task 7 MicroSteps dogfood with lumotia-llm stub, (3) Settings UX brainstorm. ```