From 4dca802f0b49101ed30971f65f514b030100e83c Mon Sep 17 00:00:00 2001 From: Jake Date: Fri, 15 May 2026 13:43:58 +0100 Subject: [PATCH] v0.3 Phase 4c: HC toggle + texture-intensity slider + grain overlay 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 , 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} {/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) --- docs/release/v0.3-tactile-quietware.md | 18 ++- src/design-system/v0.3-quietware-tokens.css | 26 ++++ .../QuietwareAccessibilityControls.svelte | 140 ++++++++++++++++++ src/lib/pages/SettingsPage.svelte | 6 +- 4 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 src/lib/components/QuietwareAccessibilityControls.svelte diff --git a/docs/release/v0.3-tactile-quietware.md b/docs/release/v0.3-tactile-quietware.md index a7d79b5..7789b52 100644 --- a/docs/release/v0.3-tactile-quietware.md +++ b/docs/release/v0.3-tactile-quietware.md @@ -232,17 +232,19 @@ Architectural finding: the v0.2 `SettingsPage.svelte` (2 891 LOC after Phase 4a) - 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. Pending. +### Phase 4b — Settings restructure to canonical tab names. Deferred to post-Phase-5. -- Carve **Output** out of `7. Advanced > Output & Capture` (currently at line 2398 in the pre-Phase-4a file) into its own top-level tab. -- Carve **Vocabulary** out of `2. Transcription > Custom vocabulary` (line 1472 in the pre-Phase-4a file) into its own top-level tab. -- Rename the remainder of `2. Transcription` to be subsumed by **Output** + **Vocabulary**, or kept as legacy section pending content audit. -- Final tab order: Start Here / Models / Output / Vocabulary / Tasks / Accessibility / Privacy / Advanced (eight tabs, matching the plan). +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. Pending. +### Phase 4c — Texture-opacity slider + high-contrast toggle. Landed 2026-05-15. -- Texture-opacity slider in the Accessibility tab, range 0.05–0.08, default 0.06. Persists to existing preferences store. -- High-contrast toggle in the Accessibility tab. Toggle overrides system `prefers-contrast: more` query when set. +- 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 `` 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 `` 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. --- diff --git a/src/design-system/v0.3-quietware-tokens.css b/src/design-system/v0.3-quietware-tokens.css index 653d9e8..e7e0246 100644 --- a/src/design-system/v0.3-quietware-tokens.css +++ b/src/design-system/v0.3-quietware-tokens.css @@ -176,6 +176,32 @@ --quietware-texture-color: rgba(0, 0, 0, 0); } +/* ============================================================ + Static grain overlay. Atmospheric texture across the whole viewport. + Fixed position so it does not scroll. Tile pattern generated inline + via SVG feTurbulence. Opacity driven by --quietware-texture-opacity + (default 0.06 dark / 0.07 light, slider range 0.05 to 0.08 in + advanced settings). mix-blend-mode overlay darkens shadows and + brightens highlights, producing the soft notebook-paper effect. + + pointer-events: none so clicks pass through. z-index 9999 places it + above all content, but content remains fully interactive thanks to + the pointer-events override. + + No texture in high-contrast mode — the [data-contrast="high"] block + above sets --quietware-texture-opacity to 0. + ============================================================ */ +:root[data-design="quietware"] body::after { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + z-index: 9999; + background-image: url("data:image/svg+xml;utf8,"); + opacity: var(--quietware-texture-opacity); + mix-blend-mode: overlay; +} + /* ============================================================ Reduced motion. Honour OS preference; quietware rules require it. ============================================================ */ diff --git a/src/lib/components/QuietwareAccessibilityControls.svelte b/src/lib/components/QuietwareAccessibilityControls.svelte new file mode 100644 index 0000000..33d20eb --- /dev/null +++ b/src/lib/components/QuietwareAccessibilityControls.svelte @@ -0,0 +1,140 @@ + + +
+

Tactile Quietware controls

+ + + + + +
+
+

Texture intensity

+ {(textureOpacity * 100).toFixed(1)}% +
+

+ Strength of the static grain overlay. 5% baseline, 8% upper end. + Slider is disabled when high-contrast mode is active. +

+
+ + +
+
+
diff --git a/src/lib/pages/SettingsPage.svelte b/src/lib/pages/SettingsPage.svelte index e794b5d..a2d2503 100644 --- a/src/lib/pages/SettingsPage.svelte +++ b/src/lib/pages/SettingsPage.svelte @@ -14,6 +14,7 @@ import StatusPill from "$lib/ui/LumotiaStatusPill.svelte"; import ZonePicker from "$lib/components/ZonePicker.svelte"; import AccessibilityControls from "$lib/components/AccessibilityControls.svelte"; + import QuietwareAccessibilityControls from "$lib/components/QuietwareAccessibilityControls.svelte"; import { getPreferences, updatePreferences } from "$lib/stores/preferences.svelte.js"; import { profilesStore, DEFAULT_PROFILE_ID } from "$lib/stores/profiles.svelte.ts"; import { toasts } from "$lib/stores/toasts.svelte.js"; @@ -2164,10 +2165,13 @@
+ {#if isQuietware} + + {/if}
{/if}