North Star: 「些細でも経験値、今日自分頑張ったなと自分を肯定できる感覚」
Every trivial task gets visualized as accumulation. The user closes the app feeling validated, never judged. All design decisions are evaluated against this north star.
- What this is: Personal task tracker + LiveEditor archive whose centerpiece is an Activity Heatmap visualizing every completed task as warm density over a year.
- Who it's for: Solo, taste-driven productivity users who want quiet self-affirmation, not KPI grading or social comparison. Single-user (no team features).
- Space/industry: Personal productivity. Adjacent: Things 3, Bear, Linear, Reflect, Tana, Cron. Distant: Notion (too much), Todoist (KPI guilt), Asana (team).
- Project type: Hybrid —
(main)/*is the dashboard app,/loginand/sign-upare auth, marketing surfaces may follow. Web + Electron (macOS only).
- Direction: Warm Cathedral — industrial-utilitarian craft warmed by daylight. The Heatmap year is the stained-glass window; accumulated days make the room glow.
- Decoration level: Intentional — paper-grain noise on backgrounds (≤2% opacity), no decorative blobs, no gradient orbs. Visual weight lives in the Heatmap; chrome stays quiet.
- Mood: Quiet pride. A workshop with a real window, not fluorescent tubes. Studio Ghibli morning, not corporate dashboard.
- NOT: Linear (cold completionism), Notion (feature bloat), Things 3 (precious minimalism), Todoist (KPI scoring), gamified RPG (badges/SFX/confetti).
- Reference touchstones: Apple Activity Rings (closing-the-loop emotional payoff), Strava personal heatmap (accumulation without judgment), Studio Ghibli morning light, Tana / Reflect (personal-tool craft).
corelive ships an opinionated concept — the North Star and Warm Cathedral. That concept owns every default and preset, so a fresh install is complete and concept-faithful before the user touches a single setting. But the default is a starting point, not a ceiling — every aesthetic and UX item is meant to be tuned to the user's own taste.
The rule: ship the concept-faithful default first and make it sufficient on its own, then expose the knob so the user can change it. Good defaults are never an excuse to withhold a setting.
- The default is always concept-faithful — someone who never opens settings still gets the full intended experience, no setup required to feel complete.
- Everything is configurable — themes, sound, motion, copy, layout, density, all of it. If it's a design or UX choice, the user can configure it their way. Configuration is a first-class, discoverable capability, not a buried or grudging afterthought.
This holds for design, features, and UX alike. The concept owns the default; the user owns every item they want to change.
Never deviable: the North Star itself — self-affirmation over judgment. "Configure everything" means every aesthetic and UX item (theme, sound, motion, layout, copy, density) — a louder theme, an optional sound, a denser layout are all fair game. It does not mean an option that grades, shames, or guilts (no opt-in streak-shame, no KPI-percentage mode). Style is infinitely yours to tune; the emotional contract is not.
Instances. Sound palette — default is silence (on-concept); every soft cue is configurable per moment, off until the user turns it on. Theme system — Warm Cathedral is the default; the colored families are user-selectable, and a stock shadcn Default light/dark pair heads the palette list for anyone who wants the un-opinionated look. Next customization? Same shape: ship the concept default, make it sufficient, then let the user tune it.
Stock shadcn/ui + Tailwind system stacks — no web fonts (2026-09-05). Nothing is loaded from Google Fonts or Vercel Fonts, and nothing overrides Tailwind's --font-* defaults: font-sans is the platform UI stack (ui-sans-serif, system-ui, …), font-mono the platform monospace stack. There is no serif display tier — display copy is the same sans, set larger or italic. The former three-font stack (Newsreader / Inter Tight / Geist Mono, 2026-05-10 → 2026-09-05) is retired; its reasoning stays in the Decisions Log as history.
- Body / UI:
font-sans(system stack). Do not load a web font for it and do not override--font-sans. - Data / Code:
font-mono(system stack) withfont-variant-numeric: tabular-numsfor counts and dates. - LiveEditor: the writing surface keeps its Mono / Sans / Serif setting — the three stock Tailwind stacks, user-owned per "Presets First, Then Options".
| Tier | Size | Face | Weight | Notes |
|---|---|---|---|---|
| Hero | clamp(40px, 5vw, 64px) |
Sans | 600 | Marketing/empty-state moments |
| H1 | 36px | Sans | 600 | Section headers, dialog titles |
| H2 | 24px | Sans | 500 | Subsection |
| H3 | 18px | Sans | 600 | Card headers, group labels |
| Body | 15px | Sans | 400 | Default reading size |
| Small | 13px | Sans | 400 | Secondary copy, footers |
| Caption | 12px | Sans | 500 | text-transform: uppercase, letter-spacing: 0.05em |
| Data | 13px | Mono | 500 | font-variant-numeric: tabular-nums for counts/dates |
OKLCH color space throughout. Departing deliberately from the current cold-neutral baseline to introduce warmth via small chroma values (0.005–0.015) on neutrals plus an amber-warm accent.
- Restrained chromatic accent: amber-warm is the only saturated color in chrome. Heatmap cells get the chromatic stage.
- Warm neutrals: every solid neutral surface carries OKLCH chroma ≥0.016 (light) / ≥0.026 (dark) — the golden-hour warm-up (2026-06-03) that pushed the whole UI off clinical white toward late-afternoon light. Earlier values (0.005–0.015) read as "Linear cold". Exception: dark
--border/--inputstay translucent white (oklch(1 0 0 / 8–12%)); they composite over the warm coal background, so the rendered line reads warm without carrying its own chroma. - Temperature gradient over lightness gradient for the Heatmap — the eureka. Cooler-empty → hotter-full, not lighter → darker.
| Token | Value | Role |
|---|---|---|
--background |
oklch(0.975 0.016 80) |
Golden-hour paper (warmed off white) |
--card / surface |
oklch(0.972 0.018 78) |
Sand-lit elevated surface |
--popover |
oklch(0.972 0.018 78) |
Same as card |
--foreground |
oklch(0.18 0.015 30) |
Deep warm charcoal (not pure black) |
--muted-foreground |
oklch(0.5 0.026 56) |
Earthy taupe for secondary copy (5.6:1 on card, AA) |
--border |
oklch(0.908 0.022 76) |
Warm dawn gray |
--input |
oklch(0.908 0.022 76) |
Form input border |
--ring |
oklch(0.56 0.16 50) |
Focus ring = primary amber |
--primary |
oklch(0.56 0.16 50) |
Amber CTA |
--primary-foreground |
oklch(0.99 0 0) |
Paper text on amber |
--secondary |
oklch(0.942 0.024 78) |
Quiet button bg |
--secondary-foreground |
oklch(0.18 0.015 30) |
Same as foreground |
--accent |
oklch(0.942 0.024 78) |
Hover surfaces |
--accent-foreground |
oklch(0.18 0.015 30) |
|
--muted |
oklch(0.942 0.024 78) |
Disabled/quiet bg |
--destructive |
oklch(0.6 0.20 25) |
Clay red, retuned warmer than the default oklch destructive |
--primary/--ringdarkened L0.62 → L0.56 (2026-06-11, WCAG AA). White--primary-foregroundon the old lighter amber was only 3.75:1 — below the AA 4.5:1 floor for CTA text. L0.56 lifts white-on-amber to 4.81:1 while staying brand amber (hue 50, chroma 0.16).--sidebar-primary/--sidebar-ringmove with it;--chart-1stays L0.62 (data-viz fill, no overlaid text). Dark mode already passed (dark ink on lifted amber, 6.93:1). Locked bycathedral-contrast.test.ts.
Dark mode is a redesign of the surfaces, not a saturation reduction. The warm undertone (chroma 0.026–0.028 on hue 40–66, raised in the 2026-06-03 golden-hour warm-up from 0.012–0.015) makes the coal glow like embers rather than slate.
| Token | Value | Role |
|---|---|---|
--background |
oklch(0.172 0.026 40) |
Ember coal, warm ochre undertone |
--card / surface |
oklch(0.235 0.028 44) |
Warm coal |
--popover |
oklch(0.235 0.028 44) |
|
--foreground |
oklch(0.96 0.005 75) |
Warm white |
--muted-foreground |
oklch(0.74 0.026 66) |
Warm fog (7.3:1 on card, AA) |
--border |
oklch(1 0 0 / 8%) |
Soft glow boundary |
--input |
oklch(1 0 0 / 12%) |
|
--ring |
oklch(0.7 0.16 55) |
Focus ring slightly brighter than primary in dark |
--primary |
oklch(0.7 0.16 55) |
Amber lifted for dark contrast |
--primary-foreground |
oklch(0.16 0.012 35) |
Background on amber |
--secondary |
oklch(0.285 0.026 44) |
|
--accent |
oklch(0.285 0.026 44) |
|
--muted |
oklch(0.285 0.026 44) |
|
--destructive |
oklch(0.7 0.19 25) |
Clay red lifted |
This is the project's most consequential color decision. Departs from GitHub's green ramp to a warm temperature gradient (paper → dawn → amber → terracotta). Chroma and hue move; lightness moves only enough to stay readable.
| Level | Light | Dark | Meaning |
|---|---|---|---|
| 0 (empty) | oklch(0.96 0.008 80) paper |
oklch(0.22 0.012 40) warm coal |
Rest, not failure |
| 1 | oklch(0.89 0.06 75) first dawn light |
oklch(0.32 0.06 50) ember |
Started the day |
| 2 | oklch(0.78 0.11 70) amber |
oklch(0.45 0.10 55) copper |
Productive |
| 3 | oklch(0.65 0.14 60) honey |
oklch(0.58 0.13 60) brass |
Full day |
| 4 | oklch(0.55 0.16 40) terracotta |
oklch(0.70 0.15 65) warm sun |
Cathedral lit |
- success:
oklch(0.65 0.13 145)moss — confirmations only, NEVER as primary CTA - warning:
oklch(0.7 0.14 80)caution amber - error:
oklch(0.6 0.20 25)(light) /oklch(0.7 0.19 25)(dark) — clay red - info:
oklch(0.6 0.10 230)slate blue — rare, advisory only
Warm Cathedral is the soul of the product; the colored families are optional self-expression layered on top of it without ever touching it. The ten rules below govern how themes are added, derived, and applied.
- The default is sacred. Warm Cathedral light + dark are the untouched default, byte-for-byte. Every other theme is derived, static, or layered; none may alter the cathedral tokens. The cathedral pair stays hand-authored in
src/globals.css(never machine-generated) — brand safety over DRY. - 14 themes, 7 families. The stock shadcn Default (neutral, listed first in the picker) + Warm Cathedral (the applied default) + five colored families — Harbor (calm blue), Grove (forest green), Rose Tea (dusty rose), Iris (soft violet), Graphite (near-neutral slate) — each in
{light, dark}. - The registry is the single source of truth.
src/lib/themes/registry.tsholds every theme as a discriminated union:PreservedTheme(cathedral — metadata only),StaticTheme(the stock shadcn Default pair — literal tokens emitted verbatim), orDerivedTheme(a colored family's accent L/C/H, a neutral tint, and a 5-stop heatmap hue path).THEMES, the picker, anduseThemeAxisall derive from it — never edit them directly. - Colored families are generated, the default is not. A build-time generator (
scripts/generate-theme-css.ts) reads the registry and emits static CSS tosrc/lib/themes/generated.css, one:root[data-theme='id']block per derived or static theme (specificity0,2,0, so it beats the cathedral:rootregardless of@importorder). The generator skips everypreservetheme — cathedral is never emitted. WCAG math (culori) runs at build/test time only; it is never shipped in the client bundle.pnpm theme:generateregenerates;theme:checkfails CI if the committed CSS is stale. - Derivation is systematic, identity is preserved. A derived family tints its neutral surfaces toward the family hue at the cathedral lightness ladder (so AA is L-driven and always holds); the accent is the family's own L/C/H; fixed-identity tokens —
--destructive,--chart-1…5— are emitted as the cathedral value unchanged for every theme; foregrounds are contrast-computed for WCAG AA, never hand-picked. - Graphite is the temperature=pride proof. Its accent is nearly desaturated (chroma ~0.02), so the only real chroma on screen is the heatmap bloom. A near-monochrome chrome with a glowing heatmap is the purest statement of the north star: the year you accumulated is the color.
- The picker is two-axis. Settings and the sidebar quick-switch both pick a family and a mode independently. Each family card previews the family's real tokens (surface · accent · text · heatmap ramp) as a composite swatch reconstructed at runtime from the registry — never a single hex dot, never the culori library.
- System belongs to the default only.
Systemis OS-managed and maps only to the Warm Cathedral light/dark pair (it is a light↔dark axis, not a palette). Colored families expose Light/Dark only; choosing a colored family while on System collapses to an explicit id. - Theme toggle = crossfade. Switching theme crossfades rather than hard-cutting (Motion table, "Theme toggle"). The whole UI — page background/text plus component surfaces (cards, sidebar, popovers) — crossfades together (200ms
ease-out, gated behindmotion-safe:—prefers-reduced-motionusers get an instant change). To keep hover/focus instant, the fade is scoped to a transienttheme-transitionclass that<ThemeTransition>puts on<html>only for the switch window. Decided 2026-06-11 (design-review #5): broadened from body-only to all surfaces. - Theme lives in the web, applied as
data-theme. Persistence is 100% weblocalStorage(storageKey="corelive-theme"); next-themes setsdata-themeon<html>. Tailwinddark:is keyed to the app'sdata-theme(@custom-variant darkon[data-theme$=dark]), never the OSprefers-color-scheme. The Electron shell reads nothing native (its vestigialappearance.theme/accentColorwere removed). An unknown or stale stored id self-heals to the default on mount (ThemeAllowlistGuard).
Family signatures (accent hue; full seeds live in the registry):
| Family | Accent hue | Character | Heatmap rest → apex hue |
|---|---|---|---|
| Warm Cathedral | ~50 (amber) | the default craft | 80 → 40 (light) |
| Harbor | 250 | calm blue | 235 → 42 |
| Grove | 145 | forest green | 140 → 42 |
| Rose Tea | 18 | dusty rose | 25 → 38 |
| Iris | 292 | soft violet | 300 → 45 |
| Graphite | 250 (~0 chroma) | near-neutral slate | 250 → 42 |
Accepted hue collisions (both AA-pass, separable by chroma/lightness, flagged in-code for design-review): Grove accent 145 lands exactly on the fixed --chart-2 token (oklch(0.65 0.13 145)) and beside the app's success-green (--color-success, hue ≈149), and a green theme also dilutes green's "success-everywhere" semantic; Rose Tea accent 18 sits near the fixed --destructive (hue 25). Both ship as deliberate taste calls — the family signature is worth more than perfect hue isolation.
The heatmap's temperature = pride. The hot end blooms warm on every theme, forever — it is a CI-enforced invariant, not a guideline.
Adding a colored family must never let the heatmap's payoff drift back toward a "GitHub-green work-grid." The guarantee has three tiers, strongest first. For every registered theme, src/lib/themes/generate-theme-css.test.ts asserts the five heatmap stops (--hm-0 rest → --hm-4 apex):
- The two hottest stops bloom warm (CI-locked seed constraint — the load-bearing gate).
--hm-3and--hm-4hue ∈ [20, 70], regardless of where the family rests. Per-stop hue is the only thing aheatmapHuesseed actually controls, so this is what makes "more completions = hotter" read the same across families. A seed that keeps a cool body all the way up (e.g. green[145, 145, 145, 145, 42]) fails the build — the cool rest with a single warm apex is the GitHub-green failure mode. - Lightness moves monotonically and chroma intensifies toward the apex (structural — holds by construction). Light mode rests palest and deepens to the apex; dark mode rests darkest and brightens to it; the fullest day is the most saturated cell. The generator reuses the cathedral L/C ladder verbatim for every family, so the test here guards against a generator regression, not a bad seed — a seed cannot move L or C.
- The cool rest stops stay the family's hue (intentional, unconstrained).
--hm-0…--hm-2carry the family color — Grove rests green, Iris rests violet — and are deliberately not forced warm. In a real contribution grid most cells are low-intensity, so a family genuinely reads in its own hue at the cool end, by design. The rest hue is the family's; the payoff hue is the project's.
Per-theme WCAG AA gates ride alongside (fg/bg ≥ 7, muted-fg/card ≥ 4.5, primary-fg/primary ≥ 4.5). A new family that cools its hot end, breaks the L/C ramp, or fails AA fails the build — the north-star payoff cannot regress by accident.
- Base unit: 4px
- Density: Comfortable (between Things 3 and Linear)
- Scale:
2xs(4) xs(8) sm(12) md(16) lg(24) xl(32) 2xl(48) 3xl(64) 4xl(96) - Card padding:
lg(24px) - Section spacing:
2xl(48px) between major sections;xl(32px) within sections
- Cell size: 12px minimum, 32px maximum (per Heatmap Cathedral plan, eng review D6 lock)
- Cell gap: 3px (light theme), 4px (dark theme — needs slightly more breathing room)
- Approach: Hybrid — grid-disciplined for app surfaces, editorial moments for hero / empty states
- Grid: 12-column, 24px gutter
- Max content width: 1180px (intentionally tighter than the 1200px convention; the few px signal restraint)
- Border radius:
- sm: 4px (chips, small badges)
- md: 8px (buttons, inputs)
- lg: 12px (cards, dialogs)
- xl: 16px (large modals, hero cards)
- full: 9999px (avatar, pill badges)
- Heatmap container: full content-width, the home page centerpiece — never demoted to sidebar
- Sidebar: 248px, top-aligned navigation, Caption-style section labels
Intentional choreography. Most motion is in the 150–250ms range. The one motion moment that earns extended duration is the completion celebration — the only place where the design "performs" for the user.
- Approach: Intentional (between minimal-functional and expressive)
- Easing:
- enter:
ease-out - exit:
ease-in - move:
ease-in-out - celebration:
cubic-bezier(0.16, 1, 0.3, 1)(gentle overshoot)
- enter:
- Duration:
- micro: 50–100ms (focus rings, color shifts)
- short: 150–250ms (hover, fade)
- medium: 250–400ms (modal, page transition)
- long: 400–700ms (cell completion fill, the hero motion)
| Action | Motion | Duration | Easing |
|---|---|---|---|
| Task completion → Heatmap cell fill | radial-sweep fill | 400ms | ease-out |
| Task completion → checkbox fill | amber fill (checkbox only, NOT row) | ~200ms | ease-out |
| Hover lift (cell, card, button) | translateY(-1px) + scale(1.04) |
150ms | ease-out |
| Page transition | fade | 200ms | ease-out |
| Modal / Dialog | scale(0.96 → 1) + fade |
250ms | celebration easing |
| Tooltip | fade + 4px slide-up | 100ms | ease-out |
| Theme toggle | crossfade (whole UI, surfaces) | 200ms | ease-out |
Checkbox completion fill (2026-06-04, opt-in-feedback feature). Checking a task plays a soft amber fill on the CHECKBOX (not the whole row) over ~200ms
ease-out— short tier, deliberately NOT the heatmap's radial-sweep geometry or celebration easing. The heatmap-cell fill stays the single performative "hero" moment (400ms); the checkbox fill is the quiet, repeatable acknowledgment of the app's most-frequent gesture, and that restraint is what lets it fire on every check without fatigue. Gated behindmotion-safe:—prefers-reduced-motionusers get an instant, motionless state change. On an optimistic-update rollback the state snaps back instantly (no reverse-celebration).
- Bounce springs (any
cubic-bezierwith overshoot >1.05 except modals) - Confetti, particle bursts, screen-flash
- SFX, haptics — EXCEPT the configurable Electron shortcut opening cue below
- Scroll-driven hero animations
- Loading spinners that exceed 3s without progress text
Task sound palette retired (2026-09-06). Task creation, completion, and clearing no longer have playback consumers. Their toggles, master switch, timbre picker, volume slider, and four audio assets are removed. The shared settings page contains Tasks and Appearance; Sound is an Electron-only section.
Shortcut opening cue (2026-07-23; user-approved default-ON exception). This Electron-only utility cue is independent of task completion: one of ten brief, non-melodic keyboard textures plays only when a global shortcut actually transitions LiveEditor from hidden to shown. The default
Shuffle allmode avoids repeating the immediately previous texture; people can instead pin any one cue and preview choices from Sound settings. It does not play when the shortcut hides a window, targets an already-visible window, or fails to open one. It defaults ON because an off-screen native shortcut needs quiet spatial confirmation, remains independently configurable under Sound, and never counts as a reward or completion celebration.
The product talks like a quiet companion, not a coach. Microcopy is one of the few places where the north star comes through directly.
GitHub: 8 contributions on May 9, 2026
Things 3: 8 completed
corelive: 8 things done — good day (English) / 今日は 8 個 — お疲れさま (Japanese)
The praise is one short phrase appended to the count. Not saccharine, not corporate.
- Empty Heatmap day on hover: "rest day" / "休息日" — never "0 tasks", never "missed".
- New user, never any data: "your year starts here" / "ここから始まる一年" — invitational.
Instead of "5-day streak" (creates fragility), display "shown up 18 days this month" — additive, generous, never decreases without explanation.
- "Productivity" (loaded category word)
- "Crush your tasks", "ship faster", "10x"
- "You missed a day" / 「途切れました」
- Percent-completion KPIs in primary UI ("47% complete today")
The full color system maps onto the existing shadcn/ui tokens. Migration is per-token, not per-component. Every shadcn primitive in src/components/ui/ keeps working — only the underlying CSS variables change.
- Button (primary): amber bg, paper-white text, 8px radius, hover lifts 1px
- Card: surface bg, 1px soft border, 12px radius, no shadow by default (shadow only when elevated/dragging)
- Input: transparent bg in light mode, white-on-white feel; focus ring uses
--ring(amber) - Badge: pill (full radius), Caption typography (12px / 500 uppercase)
- Tooltip: popover bg, 4px slide-up entrance, 13px sans; max 2 lines, no markdown
- Heatmap cell:
<rect>with explicit fill from--hm-0…--hm-4(resolved per active theme; the component reads them via theHEATMAP_LEVEL_TOKENSsource-of-truth insrc/lib/heatmap-intensity.ts), role=button when count>0, focus ring identical to other interactive elements
| Date | Decision | Rationale |
|---|---|---|
| 2026-05-10 | DESIGN.md created from /design-consultation (dry-run, OpenAI verification pending) |
First codified design system; supersedes implicit shadcn/ui defaults |
| 2026-05-10 | Aesthetic: Warm Cathedral (vs cold Linear / Things baseline) | Aligns with north star "self-affirmation feeling"; differentiates from productivity category convergence |
| 2026-05-10 | Heatmap recolored from green to warm temperature gradient | Eureka: temperature carries the "personal pride" signal that green carries "GitHub work" — orthogonal axis to North Star |
| 2026-05-10 | Newsreader serif for display (vs Inter / Geist / DM Sans) | Productivity apps 100% converge on geometric sans; a serif says "craft" within 0.3s of page load |
| 2026-05-10 | Inter Tight (not Inter) for body | Inter alone is the AI default; Tight is denser and pairs with Newsreader's character |
| 2026-05-10 | Geist Mono for data/code (vs JetBrains Mono) | Warmer character, tabular-nums, fewer false-positive associations with terminal/code |
| 2026-05-10 | Streak counter replaced with "shown-up days this month" | Eliminates streak-guilt; empty days = rest, never failure; aligns with "self-affirmation" |
| 2026-05-10 | Tooltip copy as quiet praise, not raw stats | Each hover delivers a small affirmation moment — north star delivered at the interaction layer |
| 2026-05-10 | Cell size: 12px min / 32px max | Locked by Heatmap Cathedral eng review D6 |
| 2026-05-10 | OKLCH color space throughout | Perceptually even gradient steps; current globals.css already uses oklch — alignment, not migration |
| 2026-05-27 | Startup-window settings ("On launch") — Sunrise framing + quiet-companion microcopy | Choosing the boot window reads as "waking up for me," not "is it broken?"; the last enabled toggle locks with "At least one window opens at launch" — gentle guidance, never an error; north star: control, not KPI guilt |
| 2026-06-04 | Completion feedback: checkbox amber fill (~200ms ease-out, NOT the heatmap hero) always-on + opt-in completion sound (default OFF) | The app's most-repeated gesture returned nothing; a quiet, design-sanctioned fill turns each check into self-affirmation without gamification. Motion stays subordinate to the heatmap hero so it repeats without fatigue; sound is opt-in so it is a deliberate choice, never default SFX (north star: self-affirmation, not dopamine hits) |
| 2026-06-10 | Theme system expanded to 12 themes / 6 families (Warm Cathedral default + Harbor / Grove / Rose Tea / Iris / Graphite) via registry → build-time generator → static CSS; cathedral stays the untouched, hand-authored default | Self-expression without diluting the default craft; the generator keeps every colored family systematic and WCAG-AA-gated, while the cathedral stays hand-authored for brand safety; culori runs build-only so the client bundle is unaffected |
| 2026-06-10 | Heatmap "temperature = pride" locked as a CI invariant across ALL themes — the two hottest stops (--hm-3/--hm-4 hue ∈ [20, 70]) are the seed gate; the L/C ramp is reused from cathedral (structural); cool rest stops stay family-hued by design |
The north-star payoff must survive every future family — a green Grove still blooms warm at the hot end yet rests green by design; the build fails if a new theme cools its hot end, breaks the L/C ramp, or drops AA |
| 2026-06-10 | System maps only to the default Warm Cathedral light/dark pair; colored families are explicit Light/Dark |
System means "follow my OS light↔dark," not a palette choice — keeps the two-axis (family × mode) mental model clean |
| 2026-06-11 | Two hue collisions accepted (Grove accent 145 ≈ --chart-2 145 / --success 149; Rose Tea accent 18 ≈ --destructive 25), separable by chroma/lightness, AA-pass, flagged in-code |
The family signature is worth more than perfect hue isolation; surfaced for design-review rather than silently compromised |
| 2026-06-11 | Theme toggle is a whole-UI crossfade (page + card/sidebar/popover surfaces, 200ms ease-out, motion-safe), scoped to a transient theme-transition class so hover/focus stay instant; Electron native appearance.theme / accentColor removed |
Reduced-motion-safe transition, broadened from body-only to all surfaces (design-review #5 decided 2026-06-11); the native theme copy had zero readers and could only drift from the real web-persisted value |
| 2026-06-13 | "Presets First, Then Options" codified as a cross-cutting principle — the concept owns every default/preset; an out-of-concept option is allowed only as an opt-in deviation layered on a sufficient on-concept default. Applies to design, features, and UX | Generalizes the opt-in sound palette's logic into a reusable governance rule, so future customization (themes, sound, motion, copy) follows one shape: ship the concept default, make it sufficient, then let options ride on top. The North Star itself stays non-deviable — style is optional, the emotional contract (self-affirmation, never judgment) is not |
| 2026-06-25 | "Presets First, Then Options" reframed away from "zero configuration" — the concept-faithful default is now an explicit starting point, not a ceiling, and every aesthetic/UX item is configurable (theme, sound, motion, copy, layout, density) as a first-class, discoverable capability rather than a buried opt-in deviation. Title kept (referenced by code + this log); body carries the shift | Direction change from "the app just works without config" to "great defaults AND everything is yours to tune" — the user wants to configure every item their way. The good-defaults discipline stays (ship the concept default first, make it sufficient, then expose the knob); the North Star stays non-deviable — total configurability covers style/UX only, never opting into judgment (no streak-shame, no KPI mode). Amends the 2026-06-13 opt-in-deviation framing above |
| 2026-06-26 | LiveEditor writing surface disables the native browser spellcheck red underlines (spellCheck={false} on the capture textarea, #128) |
Quick-capture must feel calm and un-graded; the red "misspelled" squiggles make unfinished / mixed-language fragments read as corrected, fighting the north-star calm-capture voice. Only the correction overlay is suppressed — typing / IME / save are untouched. One shared editor covers every LiveEditor surface (web + Floating + LiveEditor windows) |
| 2026-07-23 | Electron shortcut opening cue offers ten brief keyboard textures (typewriter + electrostatic-capacitive / Realforce-inspired), defaults to non-repeating Shuffle all, plays only when Floating Navigator or LiveEditor actually opens, and defaults ON as an explicit exception to the earned-moment palette's default OFF |
This is functional spatial confirmation for an otherwise off-screen global-shortcut result, not a reward. A quiet varied default plus fixed-choice and preview controls makes the texture genuinely configurable while keeping it independent, narrowly triggered, non-melodic, and subordinate to the work itself |
| 2026-09-05 | /write is a public, no-login writing surface — a stranger types before any account exists (keeps and note live on the device), and the sign-in CTA sits in the footer, never as a wall. /live-editor stays the Electron panel's protected route |
Roadmap 2026-09 (Approach C, eng review D14): user #2 is created by removing the login wall so a stranger can run the keep loop within 60 seconds of landing, not by handing a DMG to a named person; a new route is public by construction (src/proxy.ts only protects its static list), so /live-editor, the proxy and electron/ stay untouched — zero panel risk, nothing to rip out later |
| 2026-09-05 | Today Ember: one heatmap cell above the editor, lit or unlit only (level tokens 0 and 4, no 1–3 ramp — it is a lamp, not a grade). A keep sweeps it in 400ms (radial clip-path plus a brightness(1.35 -> 1) flare, so a keep on an already-lit cell still reads as a ripple rather than a no-op); an undo snaps back with no reverse motion. Unreachable counts say so instead of showing 0 |
Design review DR6 under the non-deviable "never grade, never shame" rule: the year's intensity ramp would turn the day into a score, while --hm-0 / --hm-4 guarantee the first keep visibly lights the cell in every theme. Removed the same day — see the next row |
| 2026-09-05 | Today Ember removed the same day it shipped: no count sits above the editor, at 0 or at N (ember-sweep keyframe and the one-day heatmap query went with it) |
Cut as unnecessary. The reward stays where the criterion puts it — the line clears where you pressed and the year heatmap fills — without a number over the editor |
| 2026-09-05 | Typography reverted to the stock shadcn/ui + Tailwind system font stacks: no web fonts, no @theme font override, no serif display tier (Newsreader / Inter Tight / Geist Mono retired; the LiveEditor Mono / Sans / Serif setting now maps to the stock font-* utilities) |
User call (2026-09-05): shadcn defaults everywhere; nothing to download, nothing to differentiate on faces — the room is the heatmap, not the type |
| 2026-09-05 | Palette list gains a stock shadcn neutral Default light/dark family, listed FIRST (tokens verbatim from ui.shadcn.com/r/colors/neutral.json, registered as a StaticTheme, heatmap ramp reused from Warm Cathedral); Warm Cathedral stays the applied default for a fresh install and the only family offering System |
User call (2026-09-05): lead the picker with the un-opinionated pair; keep the brand pair as what a fresh install actually gets |
| 2026-09-05 | LiveEditor textarea shows no focus line (no ring and no border-color change on focus); the general "focus ring uses --ring" Input rule does not apply to it, while the resting 1px --border stays |
User call (2026-09-05): the writing surface is the whole panel, so the caret is the focus cue and a --ring frame around the panel read as a purple box on Iris dark. Deliberate WCAG 2.4.7 trade-off, documented in code next to the class list |
| 2026-09-05 | Floating Navigator retired into a minimal login shell (/login-shell; fixed 300×400 with native traffic lights; no keep-on-top, startup-window or ⌘3 surfaces); after sign-in the main process closes it and shows LiveEditor, and the panel's category follows the one shared selection (Follow-OFF users get a one-time reset) |
A window whose only job is sign-in carries no other chrome; native traffic lights keep it closable even in accessory (hidden-dock) mode, and one shared category selection retires a Follow toggle that lost its meaning once the navigator's list was gone |
| 2026-09-06 | Today Ember restored as the opt-in Show Today Ember switch under Settings > Tasks, shared by the web LiveEditor and desktop panel; default OFF, remembered on this device and synced across open windows |
User request: keep the current uncluttered editor by default while allowing the one-cell kept-today feedback. Enabling retains the original lit/unlit colors, 400ms sweep, compact panel cut, and reduced-motion behavior |
This DESIGN.md describes the target system. Migration from current state (cold-neutral oklch + GitHub green Heatmap) is per-token in src/globals.css. No component code changes are required for the color/spacing migration. Typography loads nothing: the stock Tailwind font-sans / font-mono stacks are the defaults (no next/font, no @theme font override). Still open:
- A type-scale utility component or CSS layer for the Hero / H1 / H2 / H3 / Body / Small / Caption / Data tiers
The Heatmap palette is defined by the --hm-0…--hm-4 tokens. The stock Default family carries the Warm Cathedral ramp verbatim in its registry tokens (shadcn ships no heatmap). For the default Warm Cathedral, edit them directly in src/globals.css (light and dark). For a colored family, change its heatmapHues seed in src/lib/themes/registry.ts and run pnpm theme:generate (the generator rewrites src/lib/themes/generated.css). Either way no ContributionGraph.tsx change is required — the component resolves the tokens through the HEATMAP_LEVEL_TOKENS source-of-truth.
Streak and tooltip copy changes are scoped to ContributionGraph.tsx and any future StreakBadge component (deferred to the Heatmap Cathedral plan, decision D12 / Electron-only).