From dca9cb75938e933d6a9f9784f633037d52d4574c Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Tue, 23 Jun 2026 14:37:53 +0200 Subject: [PATCH] docs: update CLAUDE.md with visual refresh + UX overhaul changes New sections: ChatInput capsule, semantic colors, custom icons, glass-lens app icon, text selection, flat sidebar profile. Updated: typography (W300), blob sizes, top bar layout, icon system. Added full bugs-fixed section for 2026-06-23 design session. --- CLAUDE.md | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8fc1ec5..6df8c25 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,7 +48,7 @@ settings/ SettingsScreen, SettingsViewModel, SettingsComponents, SecurityS ui/ theme/ Color (P3), Theme (multi-theme), Type, Oklab, Dither theme/themes/ AccentScheme, AmberTheme, BlauTheme, MonoTheme, AuroraTheme, ThemeRegistry - icon/ KaizenIcons (central registry, Lucide base, custom override layer) + icon/ KaizenIcons (central registry, Lucide base, custom override layer), KaizenCustomIcons (hand-drawn 1.0px stroke) shape/ SquircleShape (superellipse), KaizenShapes (token system) effect/ GlassSurface (frosted glass), Shadow (multi-layer stack) motion/ Motion (easing curves, spring specs, duration tokens) @@ -75,7 +75,7 @@ Full spec: `DESIGN.md`. 4. **Multi-layer shadows** — `ShadowStack` with 2–4 overlapping layers (`KaizenShadows.level0..4`). Dark mode multiplies alphas ×1.8. Replaces all `Modifier.shadow()`. 5. **4-theme system** — Amber/Blau/Mono/Aurora. Each theme = `KaizenAccentScheme` (primary + 4 blob colors). Neutrals are theme-independent. `LocalKaizenAccent` CompositionLocal. Theme selection wired end-to-end: `SettingsViewModel.selectedTheme` → `MainActivity` → `KaizenTheme(themeId=...)`. No server sync (web stores in localStorage, app stores locally). Appearance (Light/Dark/System) also wired end-to-end. 6. **Sensor-reactive motion** — `rememberTiltState()` provides smoothed tilt `Offset(-1..1)`. Uses `TYPE_GAME_ROTATION_VECTOR` (fused, no drift), `SENSOR_DELAY_UI` (~15 Hz, sufficient for parallax). Auto-disables on battery saver, reduced motion, background, extreme tilt. -7. **KaizenIcons** (`ui/icon/KaizenIcons.kt`) — centralized icon registry, same architecture as Google's Luminous Symbols. Lucide (1.5px stroke, same library as web frontend) as base, with a custom override layer for brand-critical icons. Every UI component references `KaizenIcons.Send`, `KaizenIcons.Lock`, etc. — never a library directly. Zero Material Icon imports remain. To add a custom icon: create an `ImageVector` literal (hand-drawn SVG converted to Compose path data) and swap the getter in `KaizenIcons.kt` — all usages update instantly, no call-site changes. Icons grouped semantically: Navigation, Chat (incl. `AudioLines` for call feature), Modes, Conversation, Files, Search, Settings, Scroll. `com.composables:icons-lucide-android:1.0.0`. +7. **KaizenIcons** (`ui/icon/KaizenIcons.kt`) — centralized icon registry, same architecture as Google's Luminous Symbols. Lucide (1.5px stroke, same library as web frontend) as base, with a custom override layer (`KaizenCustomIcons.kt`) for the highest-visibility touchpoints. Custom icons use 1.0px stroke to match the lighter W300 typography. Currently custom: Menu, Plus, Mic, AudioLines, SlidersHorizontal, Globe, Image. Every UI component references `KaizenIcons.Send`, `KaizenIcons.Lock`, etc. — never a library directly. Zero Material Icon imports remain. `com.composables:icons-lucide-android:1.0.0`. **Motion tokens** (`ui/motion/Motion.kt`): `EaseSpring` (overshoot), `EaseSmooth` (expo-out), `EaseEmphasized` (M3), `SpringSnappy/Default/Gentle`. All durations centralised in `Durations` object. @@ -83,15 +83,19 @@ Full spec: `DESIGN.md`. **Theme switching fully wired:** All 7 files that previously imported hardcoded `Amber`/`AmberDeep`/`OnAmber`/`BlobX` now read from `LocalKaizenAccent.current`. Changing theme in Settings immediately updates: message bubbles, send button, orb, mesh background blobs, sidebar highlights, model sheet, stream blocks, login screen, settings toggles. No hardcoded amber imports remain outside `Color.kt` and theme definitions. -**Floating bar scrims:** Top bar and bottom dock have soft transparent gradient scrims. Bottom dock: 0% → 25% → 55% alpha when keyboard closed, 50% → 85% when keyboard open. Mesh background bleeds through — no opaque block. +**Floating bar scrims:** Top bar has soft transparent gradient scrim. Bottom dock is the ChatInput capsule itself (no separate scrim needed). -**Unified top bar:** Sidebar trigger (menu icon) and model name merged into a single `GlassSurface` pill (38dp, `KaizenShapes.pill`). Menu icon (17dp, muted) → 3dp dot divider → model name (13sp Medium, 180dp max with ellipsis). No chevron — pill is self-evidently tappable. Matches the TokenBadge glass language on the right. +**Unified top bar:** Sidebar trigger (menu icon) and model name merged into a single `GlassSurface` pill (38dp, `KaizenShapes.pill`). Menu icon (17dp, muted) → 3dp dot divider → model name (13sp W300, 180dp max with ellipsis). No chevron — pill is self-evidently tappable. Right side: PenLine "New Chat" button → TokenBadge. -**MeshBackground** (`chat/Background.kt`) — `animateBlobs` parameter: blob drift animation (22s cycle) only runs on empty state (`messages.isEmpty()`), frozen at midpoint during chat to save GPU. Blobs remain visible as static background. +**ChatInput capsule:** Single-row Gemini-style input — Plus | TextField | Tune | Mic | Send/Call. 64dp min height, pill shape (34dp radius), level4 shadow, high opacity (0.92/0.97). Mode pills hidden by default, expandable via tune icon (SlidersHorizontal) with slide animation inside the same GlassSurface card. Replaces the old two-row layout + separate floating pills row. + +**MeshBackground** (`chat/Background.kt`) — `animateBlobs` parameter: blob drift animation (22s cycle) only runs on empty state (`messages.isEmpty()`), frozen at midpoint during chat to save GPU. Blobs remain visible as static background. Blobs are 400-460dp (large, fill entire screen on S25 Ultra), alpha 0.36-0.48 (dark) with light-mode factor 0.78 (was 0.65). Vignette 0.35 alpha. **KaizenOrb** (`chat/Background.kt`) uses `rememberTiltState()` from `ui/sensor/` instead of inline sensor code. Breath animation uses `Durations.ORB_BREATH` / `ORB_BREATH_STREAMING` from `ui/motion/`. -**Typography** — Inter Variable (`res/font/inter_variable.ttf`, 859 KB, SIL OFL). Full type scale from DESIGN.md §8: `displayLarge` (32sp/W600) through `labelSmall` (11sp/W500). All 9 weight axes registered (W100–W900). Negative tracking at display sizes, positive at label sizes. `@OptIn(ExperimentalTextApi::class)` for `FontVariation.Settings`. +**Typography** — Inter Variable (`res/font/inter_variable.ttf`, 859 KB, SIL OFL). Full type scale from DESIGN.md §8: `displayLarge` (32sp/W600) through `labelSmall` (11sp/W500). All 9 weight axes registered (W100–W900). Negative tracking at display sizes, positive at label sizes. `@OptIn(ExperimentalTextApi::class)` for `FontVariation.Settings`. **Visual refresh (2026-06-23):** Body text W400→W300 for airier feel (inspired by Gemini's Neural Expressive). Headings scaled up: H1 26sp/W600, H2 22sp/W600, H3 18sp/W500. User bubble text, input field, hero all W300. Labels/pills stay W400-W500 for legibility. + +**Semantic Colors** — `KaizenSemanticColors` object in `Color.kt`: `error`, `errorDeep`, `success`, `successBright`, `indigo`, `linkLight/Dark`, `dropdownDark/Light`. Single source of truth for status/action colors — no `Color(0xFF...)` for these outside `Color.kt`. Syntax highlighting colors (Dracula theme) and glass-surface tints (Slate) intentionally stay local. **Oklab** (`ui/theme/Oklab.kt`) — Double-precision matrix math for accurate sRGB↔Oklab round-trips. Used by theme picker's Oklab gradient swatches and `generateGradientStops()`. Forward LMS matrix corrected to Björn Ottosson reference. @@ -148,7 +152,7 @@ The `/api/v1/chat` stream embeds control sections via sentinel code points (from ### App icon -Adaptive icon: amber orb with multi-layer radial gradients (body, depth shadow, specular highlight, warm bounce light, crisp rim). Light mode: warm off-white background. Dark mode: Obsidian gradient. Monochrome layer for Android 13+ themed icons. Splash screen uses orb foreground (API 31+). Vector-only — no raster WebPs. +Adaptive icon: translucent glass-lens orb (8 layers — subtle amber tint at 50-60% alpha, light speculars, thin rims). Matches the in-app KaizenOrb aesthetic (glass, not opaque paint). Light mode: neutral off-white background (#F6F7F9). Dark mode: Obsidian gradient (#0F1520). Monochrome layer for Android 13+ themed icons. Splash screen uses orb foreground via `windowSplashScreenAnimatedIcon` (API 31+). Vector-only — no raster WebPs. ### Offline-first cache layer (Room) — added 2026-06-21 @@ -279,6 +283,15 @@ All committed on `main`. Compile-verified on Mac (`./gradlew :app:compileDebugKo | `8f72afd` | **Edit and resend user messages** — SquarePen icon on user messages, removes message + all after it, puts text back in input field | | `b2df7e9` | **Modern message action icons** — ClipboardCopy (copy), SquarePen (edit), RotateCcw (regenerate), 36dp touch target, 20dp icons | | `421b29e` | **ReasoningBlock + SourceCards redesign** — accent-tinted background + gradient borders, KaizenShapes.md (16dp radius), domain instead of full URL in source cards | +| `75ca8c0` | **Visual refresh** — body text W400→W300 (airier), headings scaled up (H1 26sp, H2 22sp, H3 18sp), `animateItem()` on messages (350ms fade-in, spring placement), blobs 20% larger + better distribution, higher alpha on OLED, light-mode factor 0.65→0.78, distinct `primaryDeep` per theme | +| `38678a2` | **KaizenSemanticColors** — extracted ~25 hardcoded `Color(0xFF...)` into semantic tokens (error, success, indigo, link, dropdown). Single source of truth in `Color.kt` | +| `0f6e55d` | **NetworkImageCache upgrade** — disk cache (`cacheDir/img`), shared `KaizenApi.imageClient` (reuses connection pool), 32MB size-based memory limit, Crossfade animation on load | +| `3c6a891` | **Custom 1.0px icons** — `KaizenCustomIcons.kt` with hand-drawn Menu, Plus, Mic, AudioLines, SlidersHorizontal, Globe, Image. Thinner stroke matches W300 typography | +| `ad98b9f` | **App icon + splash redesign** — translucent glass-lens orb (was opaque plastic "Spiegelei"). Neutral backgrounds matching app colors | +| `4958ca8` | **Single-row ChatInput** — Gemini-style capsule: Plus \| TextField \| Tune \| Mic \| Send/Call. Mode pills hidden by default, expandable via tune icon inside the same card. New Chat button (PenLine) in top bar | +| `1c9491e` | **Text selection** — `SelectionContainer` on user + assistant messages. Long-press to select, copy, share | +| `1c9491e` | **Markdown spacing** — heading spacing 18→24/20dp, list items 8dp gap + muted bullets, blockquote 12dp inset | +| `430d5b6` | **Flat sidebar user row** — removed heavy card (background, border, shadow), replaced with flat row + thin separator | **Earlier UI/feel work (Phase 0 prototype → feel-first):** - Liquid glass styling, floating panels, glassmorphic sidebar @@ -286,7 +299,7 @@ All committed on `main`. Compile-verified on Mac (`./gradlew :app:compileDebugKo - Mesh gradient background with dithered blobs - Phase-aware haptics (click → thinkingStart → responseStart → responseEnd) - Tablet/landscape optimization (width capping) -- Dynamic keyboard handling: `WindowInsets.ime` offset (NOT `imePadding()` — that inflates the dock; NOT `adjustResize` — hides the dock with edge-to-edge). Mode pills hide when keyboard open. `windowSoftInputMode=adjustNothing` in manifest. +- Dynamic keyboard handling: `WindowInsets.ime` offset (NOT `imePadding()` — that inflates the dock; NOT `adjustResize` — hides the dock with edge-to-edge). `windowSoftInputMode=adjustNothing` in manifest. - Settings screen with SettingsViewModel ### Bugs fixed (2026-06-19/20/21) @@ -337,6 +350,22 @@ All committed on `main`. Compile-verified on Mac (`./gradlew :app:compileDebugKo - **No edit/resend for user messages** — only copy + delete were available. Fix: SquarePen button removes message + successors, puts text back in input. - **`webSearchProvider` not sent by app** — Vertex's Google vs Enterprise search toggle was missing. Fix: added `webSearchProvider` to `ChatRequest`, dropdown pill in mode pills row (only visible for `vertex:` models with search active). +### Visual refresh + UX overhaul (2026-06-23 — design session) + +- **Typography too heavy** — W400 body everywhere looked dense. Fix: W300 for body/input/hero, W600/W500 for headings (inspired by Gemini's Neural Expressive thinner Roboto Flex). +- **Headings too small** — H1 22sp, H2 19sp, H3 17sp. Fix: H1 26sp, H2 22sp, H3 18sp with proper line-height. +- **Messages pop in without animation** — no entry/exit transition. Fix: `animateItem()` on LazyColumn (350ms fade-in, spring placement, 200ms fade-out). +- **Themes washed out / blobs too small** — bottom half of screen had no color, light mode barely visible. Fix: blobs 20% larger (400-460dp), better full-screen distribution, higher alpha (0.48 peak), light factor 0.65→0.78, `primaryDeep` distinct per theme. +- **Hardcoded colors scattered** — ~25 `Color(0xFF...)` across 10 files. Fix: `KaizenSemanticColors` object in `Color.kt`. +- **Image cache had no disk persistence** — images re-downloaded every app restart. Fix: file-based disk cache in `cacheDir/img`, shared `KaizenApi.imageClient`, 32MB size-based memory limit, Crossfade on load. +- **App icon still old "Spiegelei"** — opaque plastic orb didn't match glass-lens in-app orb. Fix: redesigned to translucent glass-lens with neutral backgrounds. +- **Mode pills floating separately above input** — two disconnected UI elements, ugly scrim. Fix: pills moved inside ChatInput card, hidden by default, expandable via tune icon. +- **ChatInput was two-row layout** — wasted vertical space. Fix: single-row Gemini-style capsule (64dp, 34dp radius, level4 shadow). +- **No "New Chat" button** — only accessible via sidebar. Fix: PenLine icon in top bar. +- **Text not selectable** — couldn't select/copy text from messages. Fix: `SelectionContainer` on user + assistant messages. +- **Sidebar profile was heavy card** — background, border, shadow. Fix: flat row with thin separator. +- **Custom icons too thick** — Lucide 1.5px at 16-19dp looked chunky next to W300 text. Fix: 7 custom `ImageVector` icons at 1.0px stroke in `KaizenCustomIcons.kt`. + ## What's NOT done yet (app, priority order) ### 1. Remaining visual/UX gaps (daily-drive blockers)