SatsAmp/DESIGN.md
avi bc6396a570 feat: directory search, favorites, motion system, home button, transport fix
- radio-browser.info directory search (debounced, ~58k stations) with
  codec/bitrate/country metadata and save-to-stations action
- station favorites (star) persisted in StationRepository; Starred
  section pinned in Stations; active-station row highlight
- motion system (Motion.kt): shared-axis nav transitions, hub hop,
  metadata rise, play/pause pop; LocalReduceMotion honors system
  'remove animations'
- AppHomeButton (launcher icon) top-left on every surface + SatsAmp
  wordmark on the hub; home pops the stack back to the player
- transport row: add missing Next button, conventional order
  stop · prev · play · next
- WaveGraphic center glow: wider, fainter, no perceptible disc edge
- StreamMetadata: strip unsubstituted {{template}} residue
- PRODUCT.md + DESIGN.md (impeccable design context); .gitignore for
  re-downloadable skill engine binaries
2026-09-08 00:37:33 -05:00

120 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: SatsAmp
description: Android radio player with a glass-on-charcoal surface system and four user-selectable AA-verified accents.
colors:
base-top: "#23232B"
base-bottom: "#1B1B22"
panel-dark: "#202029"
paper-top: "#F2F1F7"
paper-bottom: "#E7E5F0"
panel-light: "#FBFAFE"
text-primary-dark: "#FFFFFF"
text-secondary-dark: "#D9D9DE"
text-muted-dark: "#8C8C96"
text-primary-light: "#1B1B22"
violet-fill: "#7C4DFF"
violet-text: "#A78BFF"
blue-fill: "#4C7DFF"
blue-text: "#93B4FF"
green-fill: "#1FA855"
green-text: "#5BD98A"
orange-fill: "#F97316"
orange-text: "#FFB37E"
violet-fill-light: "#6A3DE0"
blue-fill-light: "#2563EB"
green-fill-light: "#0C7A38"
orange-fill-light: "#C2570A"
ink-on-fill: "#141419"
success: "#34C759"
error: "#EF4444"
warning: "#F59E0B"
typography:
display:
fontFamily: "System default (Roboto)"
fontWeight: 700
title:
fontFamily: "System default (Roboto)"
fontWeight: 600
body:
fontFamily: "System default (Roboto)"
fontWeight: 400
caption:
fontFamily: "System default (Roboto)"
fontSize: "12sp"
fontWeight: 400
rounded:
card: "20dp"
input: "14dp"
surface: "12dp"
full: "circle"
components:
button-accent:
backgroundColor: "{colors.violet-fill}"
textColor: "#FFFFFF"
rounded: "{rounded.input}"
save-button:
backgroundColor: "{colors.success}"
textColor: "#FFFFFF"
rounded: "{rounded.full}"
glass-card:
backgroundColor: "rgba(255,255,255,0.06)"
textColor: "{colors.text-primary-dark}"
rounded: "{rounded.card}"
input-glass:
backgroundColor: "rgba(255,255,255,0.09)"
textColor: "{colors.text-primary-dark}"
rounded: "{rounded.input}"
---
## Overview
SatsAmp is a personal Android radio player (Kotlin + Jetpack Compose, Material 3) whose surface language is translucent glass panels over a charcoal gradient (dark) or paper gradient (light), lit by a soft radial accent glow. The user picks one of four accents — violet, blue, green, orange — and one of System/Dark/Light modes at runtime; every screen must resolve through the token set, never through hardcoded colors. Accessibility is a hard floor: every accent/mode combination is AA-verified.
The normative source of truth is `app/src/main/java/com/rada/ui/theme/Tokens.kt` (`UiTokens`, `tokensFor()`), mirrored by `design/glass-radio-theme.css` for web demos. `Theme.kt` bridges the tokens into the M3 `ColorScheme` and provides `LocalTokens`; the M3 scheme is derived, not independent.
## Colors
**Eight real themes** = 4 accents × dark/light, each a `UiTokens` instance of 21 roles read via `LocalTokens.current`:
- **Base:** dark charcoal gradient `#23232B → #1B1B22` with solid panel `#202029`; light paper gradient `#F2F1F7 → #E7E5F0` with panel `#FBFAFE`.
- **Glass layers (dark):** fill `rgba(255,255,255,0.06)`, strong fill `0.09`, decorative border `0.10`, interactive border `0.36` (≥3:1 per WCAG 1.4.11). Light mode inverts to translucent white over paper (`0.62`/`0.78`) with ink borders.
- **textSafe:** a ~90% opaque base-colored overlay always placed under text sitting on glass. Text never touches bare glass.
- **Text:** dark mode white / `#D9D9DE` / `#8C8C96` (muted is the caption floor, ≥4.5:1); light mode `#1B1B22` at 100% / 80% / 62%.
- **Accents:** dark-mode fills violet `#7C4DFF`, blue `#4C7DFF`, green `#1FA855`, orange `#F97316`; light-mode fills are deepened (`#6A3DE0`, `#2563EB`, `#0C7A38`, `#C2570A`) to hold contrast on paper. Each accent defines fill, hover fill, `accentOnFill` (white for violet, ink `#141419` for blue/green/orange in dark — this flip is the AA mechanism), `accentText` for text/icons on surfaces, and `accentSoft` (~16% alpha) for active-state backfills.
- **Status:** success `#34C759` (save/confirm), error `#EF4444`, warning `#F59E0B` — mode-independent constants.
## Typography
System default font (Roboto), no bundled typefaces. Hierarchy comes from `MaterialTheme.typography` M3 roles; weight emphasis clusters at SemiBold/Bold for titles and controls. Only four local `fontSize` overrides exist (12–13sp captions) — prefer M3 roles over new overrides.
## Layout
Single-activity Compose app with bottom navigation across library / stations / streams / player surfaces. Full-bleed `GlassBackground` (base gradient + one radial accent glow anchored upper-right, alpha 0.10–0.14) sits under all content. Panels, not page sections, carry grouping; content scrolls over the fixed background.
## Elevation & Depth
No shadow vocabulary — depth is tonal layering: base gradient → radial glow → translucent glass fill → `textSafe` overlay → content. Compose has no backdrop blur without a library, so "glass" means the translucent layer plus a 1px inner highlight border. Do not introduce `shadowElevation` to fake depth; add a tonal layer instead.
## Shapes
Two named radii: `SatsAmpGlass.rCard` = 20dp (cards, sheets) and `rInput` = 14dp (inputs, small buttons). `CircleShape` is reserved for playback controls, avatars, and record/save FABs. New surfaces should use a named radius, not a new one-off value.
## Components
- **Accent button** — `accentFill` background, `accentOnFill` label, 14dp radius, `accentFillHover` on press.
- **Glass card** — translucent fill + decorative border + 20dp radius; text goes on the `textSafe` overlay.
- **Input field** — `glassFillStrong`, 14dp radius, `borderInteractive` when focused (`focusRing` = `accentText`).
- **Save/record control** — `success` green, circular; the one fixed-color control by design (it reads the same in every accent).
- **Active nav/tab state** — `accentSoft` backfill + `accentText` icon/label, never a filled accent.
**Motion system** (`ui/theme/Motion.kt`): one shared vocabulary — `MotionArrival` (0.16,1,0.3,1) for entrances, `MotionExit` (M3 emphasized-accelerate) for faster exits, `MotionStandard` for state; duration budget 130 feedback / 220 state / 340 view / 140 exit. Navigation is shared-axis (details slide in from the right ±¼ travel, hub hops scale-settle 0.94→1); metadata changes rise ⅓-line in and fast-fade out; `LocalReduceMotion` (system animator scale = 0) reduces every path to a short opacity cut.
## Do's and Don'ts
- **Do** read colors via `LocalTokens.current` or the derived M3 scheme; every new screen must be correct in all 8 theme combinations.
- **Do** place `textSafe` under any text on glass, and keep `textMuted`-equivalent contrast ≥4.5:1.
- **Do** follow the active accent for anything tinted — buttons, glows, active states, brush gradients (use `SatsAmpGradients.accentBrush()`, not the static gradients).
- **Don't** use `SatsAmpGradients.primary`/`primaryHorizontal` or the fixed `PremiumBlue/Cyan/Pink` brand colors — they are violet-locked legacy and break non-violet themes; prefer `accentBrush()`.
- **Don't** pull from the legacy terminal palette (`TerminalGreen`, `TerminalGold`, …) in `Color.kt`; it belongs to no shipped surface.
- **Don't** use `PremiumError` `#EF4444` as text on light backgrounds without darkening — it fails AA on paper (known gap; fix or pair with an icon when used on light).
- **Don't** introduce one-off radii (ad-hoc 12/16dp already exist in places); extend the named set deliberately if the system genuinely needs a new step.