---
name: Actions, utils, types
type: architecture-map-page
slice: 01-frontend
last_verified: 2026/05/09
---

# Actions, utils, types

> **Where you are:** [Architecture map](../README.md) → [Frontend](README.md) → Actions, utils, types

**Plain English summary.** Helpers that are not components and not state. The single Svelte action (`bionicReading`), 16 utility modules under `src/lib/utils/`, and the `app.ts` type module that everyone imports.

## Actions

### `src/lib/actions/bionicReading.ts` (74 LOC)

Svelte action that toggles "bionic reading" rendering on a node. Walks the text nodes via `TreeWalker`, replaces them with bolded prefix + plain suffix spans. A `MutationObserver` reapplies on text changes (disconnects while mutating to avoid infinite loop). `stripBionic` undoes by unwrapping `<b>` tags and normalising adjacent text nodes.

Used in DictationPage and the viewer. Wired to `preferences.accessibility.bionicReading`.

## Utils

### `runtime.ts` (45 LOC)

Exports `hasTauriRuntime()`. Probes for `window.__TAURI_INTERNALS__` or `window.isTauri` to short circuit Tauri calls in browser preview mode. Used everywhere as the gate before `invoke()`.

### `osInfo.ts` (110 LOC)

Caches OS info via `invoke("os_info")` (or similar; check `lib.rs`). Exposes `loadOsInfo`, `isMac`, `isLinux`, `modKeyLabel` synchronously after `loadOsInfo` resolves. Drives whether the shell renders custom or native chrome.

### `errors.ts` (8 LOC)

`errorMessage(e)` returns a string from `Error | unknown`. Tiny.

### `storage.ts` (8 LOC)

`parseStoredJson<T>(key, fallback)` wraps `JSON.parse(localStorage.getItem(key))` with try/catch. Used by `settingsMigrations`, `page.svelte.ts`, and the viewer handoff.

### `settingsMigrations.ts` (134 LOC)

Versioned migrations for `lumotia_settings`. Holds `CURRENT_SETTINGS_VERSION = 1`. Envelope shape: `{ version: number, data: T }`. Reads bare unversioned blobs as v0. `loadSettingsWithMigration(key, defaults)` walks the chain and toasts on corruption.

### `frontmatter.ts` (148 LOC)

Builds YAML frontmatter for transcript markdown export.

- `deriveAutoTags(text, profile)`. Heuristic auto tags.
- `buildFrontmatter(transcript)`. Returns the YAML block.
- `buildMarkdown(transcript)`. Joins frontmatter + body.
- `normaliseTag(s)`. Lowercase, replace whitespace.

### `saveMarkdown.ts` (132 LOC)

Save dialog + write file dance. `suggestedFilename(item)` builds `<slug>-<YYYY-MM-DD>.md`. `saveTranscriptAsMarkdown(item)` opens `@tauri-apps/plugin-dialog`, then writes via `invoke`. `exportTranscriptsToDir(items)` for bulk export.

### `export.ts` (125 LOC)

Generic export helpers used by DictationPage and FilesPage. Format choice: plain text, markdown, JSON. Falls through to clipboard or save dialog.

### `taskExtractor.ts` (224 LOC)

`extractTasks(text)` uses regex heuristics for "TODO:", "Action:", "I need to ...", numbered lists, etc. Falls back when LLM extraction is unavailable.

### `textMeasure.ts` (166 LOC)

Canvas-based pre-wrap text measurement. `measurePreWrap(text, font, lineHeight, width)` returns the rendered height. `clampTextLines(text, n)` trims to N lines plus ellipsis. Used by HistoryPage virtual scroll and DictationPage textarea sizing.

### `accessibilityTypography.ts` (41 LOC)

Reads `--font-family-body`, `--font-size-body`, `--line-height-body`, `--letter-spacing-body` from `<html>` and returns numeric values. `pretextFontShorthand`, `bodyPretextLineHeight`, `transcriptPretextFont`, `transcriptPretextLineHeight` are the public helpers.

### `virtualList.ts` (49 LOC)

`buildCumulativeOffsets(heights)` and `findVisibleRange(offsets, scrollTop, viewportHeight, overscan)`. Pure. Used by HistoryPage and `VirtualSegmentList`.

### `time.ts` (46 LOC)

`pad(n)`, `formatTime(seconds)`, `formatDuration(seconds)`, `formatTimestamp(iso)`. Display helpers.

### `sounds.ts` (101 LOC)

Loads the start/stop/complete cue sounds via `<audio>` and exposes `playStartCue()`, `playStopCue()`, `playCompleteCue()`. Volume from `settings.soundCueVolume`. Honours `settings.soundCues` flag.

### `hotkeyValidity.ts` (149 LOC)

Validates a hotkey combo against per-OS rules (no Cmd alone on macOS, no single letters, etc). Used by `HotkeyRecorder.svelte`.

### `constants.js` (30 LOC)

The shared scalars:
- Timing: `FEEDBACK_TIMEOUT_MS`, `HOTKEY_FEEDBACK_MS`, `HISTORY_MAX_ENTRIES = 100`, `MAX_PCM_SAMPLES = 4_800_000` (5 min @ 16 kHz), `SIDEBAR_MAX_TASKS = 30`, `CHUNK_INTERVAL_MS = 3000`, `MIN_CHUNK_SAMPLES = 8000`.
- Buckets: `BUCKET_COLORS`, `BUCKET_DOT_COLORS` (`inbox` / `today` / `soon` / `later`).
- Effort: `EFFORT_LABELS`, `EFFORT_ORDER`.
- Playback: `PLAYBACK_SPEEDS = [0.5, 1, 1.5, 2, 3, 5]`.

Note: this is `.js`, not `.ts`. Other utils are `.ts`.

## Types

### `src/lib/types/app.ts` (408 LOC)

Single source of truth for shared shapes. Contains:
- `PageState`, `SettingsState`, `Preferences`, `AccessibilityPreferences`.
- `Profile`, `Template`, `TaskList`, `TaskBucket`, `TaskEntry`, `TaskDraft`, `TaskUpdate`, `TaskDto`, `EnergyLevel`.
- `TranscriptDto`, `TranscriptEntry`, `TranscriptWriteEntry`, `TranscriptMetaPatch`, `Segment`, `ViewerSegment`.
- `DailyCompletionCount`, `ToastSeverity`, `FontFamily`, `ReduceMotion`.

### `src/lib/shims.d.ts`

Single ambient declaration file. Worth verifying the contents are still needed (Svelte 5 + SvelteKit ship most ambient types now). README debt note 7.

## Watch outs

- `constants.js` is JS, not TS. If you migrate, the JSDoc shapes in `BUCKET_COLORS` need to align with Tailwind class strings; type-only objects still need a runtime export.
- `taskExtractor.ts` is a regex heuristic. The LLM path (`extract_tasks_from_transcript_cmd`) is the better signal; the heuristic is the offline fallback.
- `osInfo.ts` caches forever. If you need to handle a hot OS detection retry (you should not), invalidate the cache yourself.
- `textMeasure.ts` uses an offscreen `<canvas>`. Costs are real for long transcripts; results are cached per (text, font, line-height, width) tuple in HistoryPage.
- `frontmatter.ts` and `saveMarkdown.ts` overlap. The former produces the body; the latter handles the I/O. Keep them split.

## See also

- [Stores](stores.md). Many utils are imported by stores.
- [Components](components.md). The components that consume these helpers.
- [App shell and styling](app-shell-and-styling.md). CSS variables consumed by the typography utils.
