Three additions land together so the slider is meaningful from day
one (instead of recording a preference that nothing consumes yet).
Static grain overlay.
- src/design-system/v0.3-quietware-tokens.css adds a fixed-position
body::after element that ships an SVG feTurbulence noise tile
repeated across the viewport. Opacity reads from
--quietware-texture-opacity. mix-blend-mode: overlay produces the
soft notebook-paper feel without obscuring content.
- pointer-events: none so clicks pass through. Active only under
html[data-design="quietware"]. High-contrast forces opacity to 0
via the existing HC palette block.
QuietwareAccessibilityControls component.
- NEW: src/lib/components/QuietwareAccessibilityControls.svelte.
Two controls, both quietware-only:
1. High-contrast toggle wires html[data-contrast="high"].
Overrides the OS prefers-contrast: more query when explicitly
on. Built on LumotiaToggle so it inherits the accessible
label + description pattern.
2. Texture-intensity slider, range 0.05 to 0.08, step 0.005,
default 0.06. Sets --quietware-texture-opacity inline on
<html>, overriding the per-mode default in the tokens CSS.
Disabled while high-contrast is on. Reset button restores
0.06.
- Persistence: localStorage keys
lumotia:quietware:high-contrast
lumotia:quietware:texture-opacity
so choices survive dev rebuilds and full restarts. Full
integration with the central Preferences store is a follow-up;
localStorage keeps Phase 4c contained.
SettingsPage Accessibility section.
- Imports the new QuietwareAccessibilityControls component.
- Renders {#if isQuietware} <QuietwareAccessibilityControls />
{/if} immediately after the existing AccessibilityControls block.
- Search filter copy extended to cover the new control vocabulary.
Verified.
- npm run check: 0 errors, 0 warnings across 5706 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
268 lines
18 KiB
Markdown
268 lines
18 KiB
Markdown
# Lumotia v0.3 — Tactile Quietware
|
||
|
||
> Calm enough for overloaded brains, structured enough to recover thoughts, tactile enough to feel like a local desktop tool rather than SaaS.
|
||
|
||
The v0.3 release reframes Lumotia around one thesis: a low-cognitive-load capture instrument. Built on the WCAG 2.2 + W3C COGA + NN/G evidence base, validated against the four HMRC accessibility personas that map most directly onto a dictation-first desktop tool.
|
||
|
||
This document is the single source of truth for v0.3. Phase log, regression diary, palette spec and font stack all live here.
|
||
|
||
---
|
||
|
||
## Source brief
|
||
|
||
Locked 2026-05-15 from Jake's design brief and three rounds of capture-pipeline iteration.
|
||
|
||
- Palette: `inputs/inbox/2026-05-15-lumotia-colour-layout-changes.md` plus the colour-palette refinements at `inputs/inbox/2026-05-15-re-lumotia-v03-renders-revised-palette-typography-.md`.
|
||
- Personas: HMRC Virtual Empathy Hub, eight personas at `https://personas-prototype.herokuapp.com/`.
|
||
- Accessibility tools: DfE manual at `https://accessibility.education.gov.uk/tools-testing/tools`.
|
||
|
||
## Rule set
|
||
|
||
The five rules every v0.3 PR has to clear.
|
||
|
||
| Rule | Meaning |
|
||
|---|---|
|
||
| Texture = atmosphere | Static global grain. No per-panel noise. No motion. Default 6%, slider 5 to 8% in advanced. |
|
||
| Colour = status | Brand palette IS the semantic palette. Brand chroma earns its keep by signalling state. Decorative colour is forbidden. |
|
||
| Layout = calm | Every page uses the same skeleton. Files, Tasks, History and Dictation must not invent their own structure. |
|
||
| Motion = feedback only | Animation only for recording, loading, success and failure. Honour `prefers-reduced-motion` at root. |
|
||
| Settings = progressive disclosure | One sectional tab visible at a time. Eight tabs. No long scroll. |
|
||
|
||
---
|
||
|
||
## Palette
|
||
|
||
Locked 2026-05-15 from Jake's color.adobe.com primaries. Each primary is used literally where it clears WCAG AA on the relevant background. Where it does not, a text-safe sibling at the same hue and saturation is derived.
|
||
|
||
### Source primaries
|
||
|
||
| Role | Primary | Hue | Notes |
|
||
|---|---|---|---|
|
||
| `--danger` | `#FF0700` | 2deg | Pure red |
|
||
| `--info` | `#000AFF` | 238deg | Pure blue |
|
||
| `--success` | `#00FF56` | 140deg | Pure green |
|
||
| `--caution` | `#FFCD00` | 48deg | Pure yellow |
|
||
|
||
### Light mode
|
||
|
||
Cream paper base. Jake's blue passes AAA on cream and is used literally. The other three are darkened siblings for AA text contrast, with caution kept fill-only because any darkened yellow reads as olive or mustard ("looks like poop").
|
||
|
||
| Token | Hex | Contrast on `#FBF8F2` | Notes |
|
||
|---|---|---|---|
|
||
| `--color-bg` | `#FBF8F2` | Base | Cream paper |
|
||
| `--color-text` | `#1D1B18` | 14.43 AAA | Near-black |
|
||
| `--color-info` | `#000AFF` | 7.96 AAA | Jake literal |
|
||
| `--color-danger` | `#E60600` | 4.51 AA | Sibling derived from `#FF0700` |
|
||
| `--color-success` | `#00852D` | 4.51 AA | Sibling derived from `#00FF56` |
|
||
| `--color-caution` | `#FFCD00` | 1.42 (fill-only) | Jake literal, fill-only convention |
|
||
|
||
**Caution is fill-only on cream.** Pill backgrounds, dots, left-border accents and icons take `--color-caution`. Foreground text inside a caution-coloured pill stays `--color-text`. Matches Material, GOV.UK and IBM Carbon practice.
|
||
|
||
### Dark mode
|
||
|
||
Lifted Coffee Bean base. Jake's green and yellow primaries already clear AAA on the dark surface and are used literally. Red and blue need lifting because pure-saturated dark hues fail against a dark background.
|
||
|
||
| Token | Hex | Contrast on `#2A1620` | Notes |
|
||
|---|---|---|---|
|
||
| `--color-bg` | `#2A1620` | Base | Lifted Coffee Bean |
|
||
| `--color-text` | `#F3EFE7` | 13.85 AAA | |
|
||
| `--color-info` | `#7076FF` | 4.64 AA | Lifted from `#000AFF` |
|
||
| `--color-danger` | `#FF2A24` | 4.54 AA | Lifted from `#FF0700` |
|
||
| `--color-success` | `#00FF56` | 12.51 AAA | Jake literal |
|
||
| `--color-caution` | `#FFCD00` | 11.33 AAA | Jake literal |
|
||
|
||
### High contrast mode
|
||
|
||
Same four hues retained so role recognition does not flip between modes. Saturation 80%, lightness 70%. Zero texture, no translucent overlays.
|
||
|
||
| Token | Hex | Contrast on black |
|
||
|---|---|---|
|
||
| `--color-bg` | `#000000` | Base |
|
||
| `--color-text` | `#FFFFFF` | 21.00 AAA |
|
||
| `--color-info` | `#757AF0` | 5.80 AA |
|
||
| `--color-danger` | `#F07975` | 7.70 AAA |
|
||
| `--color-success` | `#75F09F` | 14.72 AAA |
|
||
| `--color-caution` | `#F0D875` | 14.78 AAA |
|
||
|
||
---
|
||
|
||
## Typography stack (V4 pairing, locked 2026-05-15)
|
||
|
||
Three production fonts. Self-hosted as WOFF2. No CDN dependency.
|
||
|
||
| Role | Font | Licence | Used for |
|
||
|---|---|---|---|
|
||
| Body and UI | Work Sans (variable) | OFL | Headers, labels, controls, sidebar, body, transcript surface |
|
||
| Brand moments | Young Serif | OFL | Wordmark, splash, empty-state hook copy, About modal |
|
||
| Mono | JetBrains Mono | Apache 2.0 | Logs, model IDs, file paths, hotkey strings |
|
||
|
||
Atkinson Hyperlegible Next and OpenDyslexic stay as opt-in accessibility fonts via Settings. Archivo, Lexend and Instrument Serif from v0.2 stay shipped during v0.3 transition; future release may remove them after persona testing.
|
||
|
||
---
|
||
|
||
## Persona test gates
|
||
|
||
Each phase must pass these four manual gates before merge. Tools and tasks from the DfE manual.
|
||
|
||
| Persona | Condition simulated | Primary risk for Lumotia | Gate |
|
||
|---|---|---|---|
|
||
| Pawel | Autistic | Sensory load, predictability, motion sensitivity | Empty states speak. No surprise motion. Same skeleton on every page. |
|
||
| Simone | Dyslexic | Transcript readability, dense paragraphs | Transcript body uses Work Sans at 16px minimum, line-height ≥ 1.6, comfortable measure. |
|
||
| Chris | Rheumatoid arthritis | Click target size, keyboard fallback for every action | All interactive targets ≥ 44 x 44 px. Every action reachable by keyboard with visible focus ring. |
|
||
| Ron | Older user, multiple conditions | Combined: vision + cognitive + motor | All three of the above hold simultaneously. |
|
||
|
||
Medium-priority personas (Claudia magnifier, Saleem deaf) get explicit checks at Phase 5. Lower-priority personas (Ashleigh screen reader, Helena dyscalculia) get checks at v0.4.
|
||
|
||
---
|
||
|
||
## Phase 0 — Accessibility tools checklist
|
||
|
||
Manual gov.uk DfE tools applied to every v0.3 phase before merge. Tools that map onto a Tauri webview tested via the same browser-preview surface already shipped in v0.2.
|
||
|
||
- [ ] Contrast Checker. All palette pairs verified against WCAG AA. Annotated in the relevant phase commit message.
|
||
- [ ] axe DevTools. Run on every page after the phase migrates it.
|
||
- [ ] Resize Text. 200% zoom does not break any layout.
|
||
- [ ] Text Spacing. Increased letter, word, line spacing per WCAG 1.4.12 does not clip content.
|
||
- [ ] Target Size. All interactive targets ≥ 44 x 44 px (WCAG 2.5.8).
|
||
- [ ] HeadingsMap. Settings sectional refactor preserves a sensible h1 → h6 hierarchy.
|
||
- [ ] Blur. Smoke check that primary actions remain legible under simulated low vision.
|
||
- [ ] Screen reader smoke test. NVDA or Orca on the Settings page after Phase 3.
|
||
|
||
A future-Phase CI step will automate axe-core + contrast checks. Out of scope for v0.3 per Jake's 2026-05-15 decision.
|
||
|
||
---
|
||
|
||
## Phase plan
|
||
|
||
Each phase ships as its own PR. Each is flag-gated by `html[data-design="quietware"]`. The current v0.2 user-facing surface is unaffected until Phase 6 promotes quietware to the default.
|
||
|
||
### Phase 1 — Tokens. (this PR)
|
||
|
||
- New file `src/design-system/v0.3-quietware-tokens.css` with three palette scopes (dark, light, high-contrast).
|
||
- Self-hosted Work Sans (variable), Work Sans Italic (variable), Young Serif (static) at `src/fonts/`.
|
||
- Import wired in `src/app.css` directly after the tailwind import. Inert until `data-design="quietware"` is present on `<html>`.
|
||
- No component changes. No behavioural changes.
|
||
|
||
### Phase 2 — Build flag wiring.
|
||
|
||
- `VITE_LUMOTIA_QUIETWARE=1` build-time env var sets `data-design="quietware"` on `<html>` via `src/routes/+layout.svelte`.
|
||
- Manual override path stays: dev tools, or a Settings toggle gated behind the same flag.
|
||
|
||
### Phase 3 — Status grammar primitives.
|
||
|
||
- `LumotiaStatusPill`, `LumotiaNotice` with icon + label + body + actions.
|
||
- Caution is fill-only across both. Foreground text uses `--color-text`.
|
||
- Component preview added to `src/routes/design-system-v2/`.
|
||
|
||
### Phase 4 — Settings sectional refactor.
|
||
|
||
- Split the 2 791 LOC `SettingsPage.svelte` across eight tabs: Start Here, Models, Output, Vocabulary, Tasks, Accessibility, Privacy, Advanced.
|
||
- Texture-opacity slider lives in Accessibility. Range 0.05 to 0.08. Default 0.06.
|
||
- High-contrast toggle in Accessibility. Toggle overrides system `prefers-contrast` query when set.
|
||
- One section visible at a time. No long-scroll.
|
||
|
||
### Phase 5 — Critical-path simplification.
|
||
|
||
- Dictation page: header + transcript surface + action rail + empty state. No cockpit furniture.
|
||
- Files, Tasks, History migrated to the shared page skeleton (left nav, header, optional toolbar, primary work surface, optional right drawer, status row).
|
||
- Empty states speak on all four pages.
|
||
- Persona-test gates for Pawel, Simone, Chris, Ron at this phase.
|
||
|
||
### Phase 6 — Icon and wordmark integration.
|
||
|
||
- Real Lumotia wordmark + mark lifted from brand-proposal v1 colophon. Replaces the placeholder swirl.
|
||
- Surfaces: window icon (.ico, .icns, multi-size .png), splash, About modal, empty-state anchor, status-pill leading glyph for "Ready".
|
||
- Removes any remaining Magnotia / Wyrdnote / Kon-era assets.
|
||
|
||
### Phase 7 — Motion audit. (final v0.3 polish)
|
||
|
||
- Inventory every animation, transition and decorative motion currently in the app.
|
||
- Keep: recording-active heartbeat, loading spinner, success / failure feedback.
|
||
- Strip: decorative pulse, animated background, sliding panels, attention shimmer.
|
||
- `prefers-reduced-motion` reducer set at the root selector for quietware (already in tokens CSS).
|
||
|
||
### Phase 8 — Promote to default. (post-release decision)
|
||
|
||
- Flip `<html data-design="quietware">` to be the default; remove the flag.
|
||
- Either lands as a major release (v1.0) or stays opt-in indefinitely.
|
||
- This decision is deferred to after Phase 6 user testing.
|
||
|
||
---
|
||
|
||
## Phase log
|
||
|
||
### Phase 1 — Tokens. Landed 2026-05-15.
|
||
|
||
- `src/design-system/v0.3-quietware-tokens.css` written. 5.7 KB.
|
||
- Three WOFF2 fonts added at `src/fonts/`: `work-sans-variable.woff2`, `work-sans-italic-variable.woff2`, `young-serif.woff2`. 287 KB total.
|
||
- `src/app.css` imports the new tokens file directly after `@import "tailwindcss"`.
|
||
- Inert without `data-design="quietware"` on `<html>`. v0.2 surface unaffected.
|
||
- Verified by visual inspection. Manual activation via dev tools toggling the attribute.
|
||
- Palette iterated three times this session (brand-as-semantic → cobalt-pegged square → color.adobe.com primaries). Final values locked in commit on amendment.
|
||
|
||
### Phase 2 — Build flag wiring. Landed 2026-05-15.
|
||
|
||
- `src/routes/+layout.svelte` extended with a `$effect` block that reads `import.meta.env.VITE_LUMOTIA_QUIETWARE` at runtime and sets `<html data-design="quietware">` when the flag is `"1"`.
|
||
- Hot-reload safety: if the env var is unset between dev rebuilds, the attribute is cleared.
|
||
- Activation: `VITE_LUMOTIA_QUIETWARE=1 npm run dev` (or `npm run build`) lights up the quietware tokens. Without the env var, app renders v0.2 unchanged.
|
||
- Combine with `data-theme="light"` and `data-contrast="high"` (already wired by v0.2) to reach the light and high-contrast quietware modes.
|
||
- No new dependencies. No bundle-size impact in the off path.
|
||
|
||
### Phase 3 — Status grammar primitives. Landed 2026-05-15.
|
||
|
||
Architectural finding: both `LumotiaStatusPill` and `LumotiaNotice` already shipped in v0.2 Phase 5. Phase 3 became an audit-and-adapt task rather than a new-component build.
|
||
|
||
- `LumotiaStatusPill` ([src/lib/components/StatusPill.svelte](../../src/lib/components/StatusPill.svelte)) audited. Pattern is already accessibility-correct: neutral pill background + neutral label text + role colour confined to a 6×6 px dot. Colour is supplementary, label is always perceivable. Works unchanged across all three quietware modes. No changes shipped.
|
||
|
||
- `LumotiaNotice` ([src/lib/ui/LumotiaNotice.svelte](../../src/lib/ui/LumotiaNotice.svelte)) refactored to the left-bar accent pattern. Old version put the role colour on the icon + outline; in quietware light mode that rendered a bright `#FFCD00` caution icon faded against cream paper. New version places the role signal on a 4-px solid left border (visible at any contrast level), with the rest of the surround as a soft tone-tinted background plus subtle neutral outer border. Icon, title and body text all use `--color-text`. Matches Material "banner with leading accent" and IBM Carbon "inline notification" guidance. ARIA semantics (`role="alert"` for danger, `role="status"` for the rest) preserved.
|
||
|
||
- Design-system-v2 preview route already imports `LumotiaNotice` and `LumotiaStatusPill`. The updated Notice renders correctly there with the existing preview content; no additional preview wiring needed.
|
||
|
||
- All four tones (info / caution / danger / success) verified by the pattern itself: the visible signal is the left bar, which is `border-l-{tone}` at 100% opacity, working at any colour intensity. Caution remains a fill-only convention on cream by design.
|
||
|
||
### Phase 4a — Settings tab shell. Landed 2026-05-15.
|
||
|
||
Architectural finding: the v0.2 `SettingsPage.svelte` (2 891 LOC after Phase 4a) was already structured as eight numbered sections that align almost 1:1 with the v0.3 plan. The cheapest path to "one section visible at a time" is therefore a tab-shell overlay rather than a file split. Behaviour stays identical to v0.2 when quietware is off; with quietware on, only the active tab's section renders.
|
||
|
||
- New `LumotiaSettingsTabs.svelte` ([src/lib/ui/LumotiaSettingsTabs.svelte](../../src/lib/ui/LumotiaSettingsTabs.svelte)) implements the WAI-ARIA tabs (automatic activation) pattern. Arrow / Home / End keyboard navigation. Active tab uses the brand left-bar accent (`border-l-caution`) so it carries the same grammar as the LumotiaNotice refactor.
|
||
|
||
- `SettingsPage.svelte` gained a small reactive `isQuietware` flag, a `MutationObserver` watching `<html data-design>`, and 8 `{#if !isQuietware || activeTab === 'X'}` wrappers around the existing eight top-level `<SettingsGroup>` sections. The settings tree is unchanged; only its top-level rendering gate changed.
|
||
|
||
- v0.2 fallback behaviour: when `data-design="quietware"` is absent the tablist does not render and all eight sections stack as before. The search filter still spans every section in v0.2 mode. This is the smallest-possible behavioural change for "one section at a time".
|
||
|
||
- Tab IDs in this commit map 1:1 to existing v0.2 section names (start-here / transcription / models / tasks / accessibility / privacy / advanced / help). Phase 4b will restructure to match the plan's canonical names (carving Output from Advanced and Vocabulary from Transcription).
|
||
|
||
### Phase 4b — Settings restructure to canonical tab names. Deferred to post-Phase-5.
|
||
|
||
Rationale: phase 4a already delivers "one section at a time" under quietware. Renaming the eight tabs to match the canonical plan (Output / Vocabulary carved out as top-level) is labelling polish, not user-value. Page-skeleton sweep (Phase 5) delivers more visible improvement per LOC. Phase 4b will return after Phase 5 lands.
|
||
|
||
### Phase 4c — Texture-opacity slider + high-contrast toggle. Landed 2026-05-15.
|
||
|
||
- New static grain overlay defined in `src/design-system/v0.3-quietware-tokens.css`. Fixed-position `body::after`, `mix-blend-mode: overlay`, opacity driven by `--quietware-texture-opacity`. Pattern generated inline via SVG `feTurbulence` (`baseFrequency=0.85`, `numOctaves=2`, `stitchTiles=stitch`). Tile size 240×240, repeated across viewport. `pointer-events: none` so the overlay never intercepts clicks. Active only under `html[data-design="quietware"]` and only on the dark and light modes — high-contrast forces opacity to 0.
|
||
- New `QuietwareAccessibilityControls.svelte` ([src/lib/components/](../../src/lib/components/QuietwareAccessibilityControls.svelte)) ships two controls:
|
||
- **High-contrast toggle**, wired through `LumotiaToggle`. Sets `<html data-contrast="high">` so the quietware HC palette block in the tokens CSS activates. Persists via `localStorage`. Overrides the OS `prefers-contrast: more` query when explicitly enabled.
|
||
- **Texture-intensity slider**, range 0.05–0.08, step 0.005, default 0.06. Sets the `--quietware-texture-opacity` CSS variable inline on `<html>` so it overrides the per-mode default in the tokens CSS. Disabled when high-contrast mode is on. Reset button restores the 0.06 default.
|
||
- Component injected into `SettingsPage.svelte` inside the Accessibility section, gated by `{#if isQuietware}`. v0.2 fallback unaffected.
|
||
- Persistence path: localStorage keys `lumotia:quietware:high-contrast` and `lumotia:quietware:texture-opacity`. Full integration with the central `Preferences` store is a follow-up; localStorage keeps Phase 4c contained.
|
||
- Verified: `npm run check` reports 0 errors, 0 warnings across 5706 files.
|
||
|
||
---
|
||
|
||
## Regression diary
|
||
|
||
Empty. Update inline as findings emerge per phase.
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
- Source brief: `inputs/inbox/2026-05-15-lumotia-colour-layout-changes.md`.
|
||
- Palette refinement round 1 (brand-as-semantic): `inputs/inbox/2026-05-15-re-lumotia-v03-renders-revised-palette-typography-.md`.
|
||
- Palette refinement round 2 (cobalt-square peg): chat decision 2026-05-15.
|
||
- Palette refinement round 3 (color.adobe.com primaries): `inputs/inbox/2026-05-15-re-lumotia-v03-phase-1-landed-cobalt-pegged-square.md` + attached `2.jpeg`. Locked.
|
||
- W3C COGA: `https://www.w3.org/TR/coga-usable/`.
|
||
- WCAG 2.2 Understanding docs: `https://www.w3.org/WAI/WCAG22/Understanding/`.
|
||
- HMRC accessibility personas: `https://personas-prototype.herokuapp.com/`.
|
||
- DfE accessibility tools manual: `https://accessibility.education.gov.uk/tools-testing/tools`.
|
||
- v0.2 release doc: `docs/release/v0.2-frontend-overhaul.md` (predecessor; reference patterns).
|