diff --git a/.gitignore b/.gitignore index 068efc1..c085593 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ cmd/desktop/build/ cmd/desktop/Oikos desktop /eval + +# Local tooling artifacts (Playwright MCP session logs, stray screenshots) +.playwright-mcp/ +config-screen.png diff --git a/VERSION b/VERSION index c5523bd..7cca771 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.17.0 +0.17.1 diff --git a/plans/2026-07-18-session-review-three-sessions.md b/plans/done/2026-07-18-session-review-three-sessions.md similarity index 100% rename from plans/2026-07-18-session-review-three-sessions.md rename to plans/done/2026-07-18-session-review-three-sessions.md diff --git a/plans/2026-07-20-desktop-mascot.md b/plans/done/2026-07-20-desktop-mascot.md similarity index 100% rename from plans/2026-07-20-desktop-mascot.md rename to plans/done/2026-07-20-desktop-mascot.md diff --git a/plans/2026-07-20-session-review-ten-sessions.md b/plans/done/2026-07-20-session-review-ten-sessions.md similarity index 100% rename from plans/2026-07-20-session-review-ten-sessions.md rename to plans/done/2026-07-20-session-review-ten-sessions.md diff --git a/plans/2026-07-21-chat-full-polish.md b/plans/done/2026-07-21-chat-full-polish.md similarity index 100% rename from plans/2026-07-21-chat-full-polish.md rename to plans/done/2026-07-21-chat-full-polish.md diff --git a/plans/2026-07-29-health-check-reality-and-knowledge-graph.md b/plans/done/2026-07-29-health-check-reality-and-knowledge-graph.md similarity index 100% rename from plans/2026-07-29-health-check-reality-and-knowledge-graph.md rename to plans/done/2026-07-29-health-check-reality-and-knowledge-graph.md diff --git a/plans/2026-07-30-session-review-plan-drift-and-dead-activity-panel.md b/plans/done/2026-07-30-session-review-plan-drift-and-dead-activity-panel.md similarity index 100% rename from plans/2026-07-30-session-review-plan-drift-and-dead-activity-panel.md rename to plans/done/2026-07-30-session-review-plan-drift-and-dead-activity-panel.md diff --git a/plans/done/2026-08-03-cyberspace-style-adoption.md b/plans/done/2026-08-03-cyberspace-style-adoption.md new file mode 100644 index 0000000..68c4b96 --- /dev/null +++ b/plans/done/2026-08-03-cyberspace-style-adoption.md @@ -0,0 +1,503 @@ +# 2026-08-03 — Adopt cyberspace.online terminal aesthetic + dithered images + +**Status:** Implemented in v0.16.0 (`757ef2f`). Shipped as a **full theme +replacement** (Terracotta/Carbon → cyberspace BBS/terminal style), not the +opt-in addition originally drafted below — the operator chose full replacement +during execution (see decision `theme.replace_with_cyberspace`). The `` +Atkinson-dithering component and the warm-cream/JetBrains-Mono look landed as +drafted; only the "opt-in vs replace" scope changed. + +Adopt the look of https://cyberspace.online/ (a BBS / "social media +de-imagined" terminal aesthetic) as a **new, opt-in theme family** in oikos, +with **both light and dark variants**, plus a reusable **``** +component that renders images to a `` with Atkinson dithering (the +"kinda dithered" image style). The existing Terracotta/Carbon themes stay the +default; this adds, it does not replace. + +--- + +## TL;DR + +1. Add a third theme family — **"Cyberspace Dark"** and **"Cyberspace Light"** — + wired through the same `--background` / `--foreground` / … token layer every + component already uses, so nothing in the UI tree changes; only the tokens + get new values. Square corners (`--radius: 0`), warm cream-on-black, mono + everything. +2. Extend `web/src/lib/stores/theme.svelte.ts` from a 2-state `'light'|'dark'` + toggle to a named-theme model, keeping `.dark` class behavior for + compatibility. +3. Self-host JetBrains Mono (body) + a pixel/terminal face (VT323 or Departure + Mono) for the logo/headings accents, replacing the Google Fonts ``. +4. Build `web/src/lib/components/RasterImage.svelte`: draws any image to a + `` reduced to a 2-color (theme `fg`/`bg`) palette via **Atkinson + dithering**, with an `` fallback and a skeleton placeholder — exactly + the cyberspace pattern. Re-renders when the theme changes (palette flips). +5. Optional cosmetic idioms (terminal-box focus ring, braille spinner, `` + strike lists) as small additive utilities, not a redesign. + +The whole thing is **non-breaking and incremental**: each step ships behind the +existing theme picker, so Terracotta/Carbon users see nothing until they opt in. + +--- + +## 1. Extracted style spec (source of truth from cyberspace.online) + +Captured from the live site's SSR HTML + inline boot script. This is the +reference the tokens below are derived from. + +### 1.1 Color model + +Cyberspace defines **exactly three colors per theme** — `fg`, `bg`, `fgDim` — +applied to CSS custom properties. Everything else (borders, primary, cards) is +*derived* from those three. There are 11 named themes total; the two we care +about: + +| Theme | `fg` (text) | `bg` (canvas) | `fgDim` (muted) | +|---------|--------------|---------------|-----------------| +| Dark | `#efe5c0` | `#000000` | `#a89984` | +| Light | `#000000` | `#efe5c0` | `#3a3a3a` | + +Note the elegance: **light and dark are exact inverses** — they share the same +warm cream (`#efe5c0`, a Gruvbox-ish paper tone) and just swap which side of it +is ink vs. paper. The muted tone `#a89984` is straight out of the Gruvbox +palette. This is why both themes read as "the same site" despite opposite +polarity. + +Boot-time fallback (the site's original/GRiD theme) is amber `#FF9810` on +`#120900` — useful as a *third* optional accent if we ever want a true-phosphor +variant. + +### 1.2 Type + +- **Body / mono:** JetBrains Mono (self-hosted `.woff2`, Regular). +- **Boot + logo accents:** Departure Mono (self-hosted `.woff2`). A quirky + monospace; VT323 (Google, free) is a close, easy substitute. +- **Stylized wordmark** (`ᑕ¥βєяรקค¢є`, class `.font-vt`): a terminal/pixel face. + Rule lives in their external `entry.*.css` (not in the SSR dump); VT323 is the + safe assumption. + +cyberspace sets `font-mono` on the root wrapper — the **entire UI is +monospace**. There is no proportional body face. Headings use the same mono +family at larger size / normal weight. + +### 1.3 Layout & component idioms + +- **Left rail nav:** fixed, icon-only when minimized (~80px), expands on click. + Square buttons, Phosphor icons, uppercase `text-xs` labels. +- **`.terminal-box`:** the universal card. Bordered (`border border-border`), + **square corners** (`rounded-none` everywhere — `--radius` is effectively 0), + and on focus/emphasis gets `ring-2 ring-fg` (a 2px ring in the foreground + color). +- **Emphasis by inversion:** active/primary state is `bg-fg text-bg` — fill with + foreground ink, text becomes the canvas color. No separate "accent" hue; the + accent *is* fg. +- **Strikethrough as a feature list:** `Ads Videos …` — crossed-out + `` elements spell out what the product removes. Cheap, on-brand. +- **Braille spinner:** `BrailleSpinner` component animates braille block chars + (`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`) for loading states instead of a circle. +- **Max content width** `max-w-4xl`, centered; generous vertical rhythm; thin + 2px scrollbars colored `--color-border`. +- Borders are `1px solid` in a border color derived from `fg`/`fgDim` at low + alpha (their `--color-border` is not literally in the dump, but every + bordered surface uses it, and it tracks `fg`). + +### 1.4 The dithered image (`RasterImage`) — what we actually know + +From the SSR HTML the component is unambiguous about its *shape*, silent on its +*algorithm* (the dither JS is in an external `/_nuxt/*.js` bundle not present in +the page dump): + +- Renders a **``** as primary output, with an **`` fallback** as a + sibling. Parent selectors `[&>canvas]:max-w-full [&>canvas]:h-auto` and + `[&>img]:…` size both responsively. +- Emits a **`.raster-image-skeleton`** placeholder (empty div, `background: + var(--color-bg)`) during SSR/before hydration — no flash of the raw photo. +- Scoped styles (`data-v-4d61df89`): `.raster-image { display:block }`, + `.raster-image-skeleton { display:block; background:var(--color-bg) }`. + +**Inferred technique** (standard for this look): Canvas 2D → `drawImage` → +`getImageData` → per-pixel luminance reduction to a 2-color palette (`fg`/`bg`) +with an **error-diffusion** pass (Atkinson or Floyd–Steinberg) → `putImageData`. +This produces the characteristic speckled 1-bit halftone. Target is almost +certainly the theme's own fg/bg, which is *why* the dithered art recolors +correctly when you flip themes. + +We will implement Atkinson (see §4) — it's the classic Mac/BBS dither, slightly +softer than Floyd–Steinberg, and matches "kinda dithered" precisely. + +--- + +## 2. Recommended approach: opt-in theme family (not a rebrand) + +oikos today = Art-Nouveau / terracotta / rounded / serif-heading (Inknut +Antiqua), floating-window desktop shell. cyberspace = BBS / mono / square / +cream-on-black. These are **opposite poles**; a flat rebrand would discard the +existing art direction and rework every component's rounding/spacing. + +**Decision: add cyberspace as a new theme family, selectable in the existing +theme picker.** This is low-risk, reversible, and lets the dithered images + +terminal idioms land incrementally. The full-rebrand alternative is documented +in §7 for if you later decide to make it the default. + +Because every oikos component consumes colors through the Tailwind v4 token +layer (`--background`, `--foreground`, `--card`, `--border`, `--primary`, …) +defined in `web/src/app.css` `@theme inline`, a new theme is **just a new set +of values for those same custom properties** — zero component edits required +for the recolor. That indirection is the whole reason this is cheap. + +--- + +## 3. Theme token additions (`web/src/app.css`) + +Add two new blocks alongside the existing `:root` (Terracotta) and `.dark` +(Carbon). They set the *same* token names to cyberspace's values, plus pin +`--radius: 0` for square corners and remap fonts (see §5). + +Driven by a `data-theme` attribute on `` (set by the store, §6), so all +four states — Terracotta, Carbon, Cyberspace Dark, Cyberspace Light — coexist: + +```css +/* ── Cyberspace Dark (cream on black) ── */ +:root[data-theme='cyber-dark'] { + --radius: 0px; + --background: #000000; + --foreground: #efe5c0; + --card: #000000; /* cyberspace has no card tint; cards are just bordered bg */ + --card-foreground: #efe5c0; + --popover: #000000; + --popover-foreground: #efe5c0; + --primary: #efe5c0; /* emphasis = fg ink */ + --primary-foreground: #000000; /* inverted */ + --secondary: #1a1a1a; + --secondary-foreground: #efe5c0; + --muted: #141414; + --muted-foreground: #a89984; /* fgDim */ + --accent: #efe5c0; + --accent-foreground: #000000; + --destructive: #cc241d; /* Gruvbox red, sits in the same palette */ + --destructive-foreground: #efe5c0; + --border: color-mix(in oklab, #efe5c0 22%, transparent); /* fg-derived hairline */ + --input: color-mix(in oklab, #efe5c0 28%, transparent); + --ring: #efe5c0; /* the ring-2 ring-fg look */ + --sidebar: #000000; + --sidebar-foreground: #efe5c0; + --sidebar-primary: #efe5c0; + --sidebar-primary-foreground: #000000; + --sidebar-accent: #1a1a1a; + --sidebar-accent-foreground: #efe5c0; + --sidebar-border: color-mix(in oklab, #efe5c0 22%, transparent); + --sidebar-ring: #efe5c0; + --chart-1: #efe5c0; --chart-2: #a89984; --chart-3: #fabd2f; + --chart-4: #b8bb26; --chart-5: #83a598; /* Gruvbox for charts */ + --success: #b8bb26; --warning: #fabd2f; + + /* oikos semantic aliases (app.css :root block) */ + --bg: var(--background); --bg-surface: var(--card); --bg-deeper: #050505; + --bg-hover: var(--secondary); --bg-active: var(--accent); + --text: var(--foreground); --text-muted: var(--muted-foreground); + --accent-blue: #83a598; --accent-green: var(--success); + --accent-red: var(--destructive); --accent-orange: var(--warning); + + /* terminal face for this theme only (see §5) */ + --font-sans: 'JetBrains Mono', ui-monospace, Menlo, monospace; + --font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace; + --font-heading: 'VT323', 'JetBrains Mono', monospace; /* pixel wordmark feel */ +} + +/* ── Cyberspace Light (black on cream paper) — exact inverse ── */ +:root[data-theme='cyber-light'] { + --radius: 0px; + --background: #efe5c0; + --foreground: #000000; + --card: #efe5c0; + --card-foreground: #000000; + --popover: #efe5c0; + --popover-foreground: #000000; + --primary: #000000; + --primary-foreground: #efe5c0; + --secondary: #e0d6b0; + --secondary-foreground: #000000; + --muted: #e6dcc0; + --muted-foreground: #3a3a3a; /* fgDim */ + --accent: #000000; + --accent-foreground: #efe5c0; + --destructive: #9d0006; + --destructive-foreground: #efe5c0; + --border: color-mix(in oklab, #000000 22%, transparent); + --input: color-mix(in oklab, #000000 28%, transparent); + --ring: #000000; + --sidebar: #efe5c0; + --sidebar-foreground: #000000; + --sidebar-primary: #000000; + --sidebar-primary-foreground: #efe5c0; + --sidebar-accent: #e0d6b0; + --sidebar-accent-foreground: #000000; + --sidebar-border: color-mix(in oklab, #000000 22%, transparent); + --sidebar-ring: #000000; + --chart-1: #000000; --chart-2: #3a3a3a; --chart-3: #b57614; + --chart-4: #79740e; --chart-5: #076678; + --success: #79740e; --warning: #b57614; + + --bg: var(--background); --bg-surface: var(--card); --bg-deeper: #e6dcc0; + --bg-hover: var(--secondary); --bg-active: var(--accent); + --text: var(--foreground); --text-muted: var(--muted-foreground); + --accent-blue: #076678; --accent-green: var(--success); + --accent-red: var(--destructive); --accent-orange: var(--warning); + + --font-sans: 'JetBrains Mono', ui-monospace, Menlo, monospace; + --font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace; + --font-heading: 'VT323', 'JetBrains Mono', monospace; +} +``` + +Two notes: + +- **`.dark` vs `data-theme`.** The current store flips `.dark` on ``. To + keep Carbon working unchanged, leave `.dark` logic alone and layer + `data-theme` on top: when a cyberspace theme is active the store sets + `data-theme` and **removes** `.dark` (cyberspace themes are self-contained — + they set both polarities explicitly). See §6. +- **Borders from `fg`.** cyberspace's hairline tracks the foreground, not a + fixed gray. `color-mix(in oklab, 22%, transparent)` reproduces that and + auto-flips between the two themes. Tune the % after visual review. + +--- + +## 4. The dithered image component (`RasterImage.svelte`) + +**File:** `web/src/lib/components/RasterImage.svelte` (sibling of the existing +`Spinner.svelte`). + +### 4.1 API + +```svelte + + +``` + +- `src`, `alt` — as ``. +- `width` — render width in CSS px; canvas is sized to this × natural aspect. + Downscaling before dithering is what sells the "lo-fi" look (defaults ~256– + 320). Expose `scale` (0–1) to control. +- Reads the active theme's `--foreground` / `--background` via + `getComputedStyle(document.documentElement)` so the dither palette **follows + the theme** (cream/black in cyber-dark, black/cream in cyber-light, and + perfectly sensible in Terracotta/Carbon too). + +### 4.2 Behavior + +1. Show `.raster-image-skeleton` (empty, `background: var(--background)`) until + the source image loads — matches cyberspace's no-flash placeholder. +2. On load: create an offscreen canvas at `width × (h/w*width)`, `drawImage` + (with `imageSmoothingEnabled = true` for the downscale), pull + `getImageData`. +3. Run **Atkinson dithering** to 2 colors: + - For each pixel: luminance `Y = 0.299R + 0.587G + 0.114B`. + - Threshold at 128 (+ optional `bias`), snap to either `fg` or `bg`. + - Push **1/8 of the quantization error** to each of 6 neighbors (Atkinson's + kernel): right, below-left, below, below-right, and two pixels down on the + next-next row. (Atkinson diffuses less than Floyd–Steinberg → softer, more + "screen-printed" — exactly the cyberspace feel.) + - Write `fg`/`bg` (read from CSS vars at render time) into the buffer. +4. `putImageData`. Canvas is the visible output; the loaded `` is kept as + `aria-hidden` fallback for no-JS / copy-image / accessibility. +5. **Re-dither on theme change**: subscribe to the theme store; when it flips, + re-read `--foreground`/`--background` and re-run steps 3–4 (cheap — the + decoded `ImageBitmap` is cached, only the palette pass reruns). This is the + detail that makes the art flip polarity with the theme toggle. +6. **Respect `prefers-reduced-data` / reduced motion?** Dithering is not motion, + but offer a `plain` prop to skip the canvas and render the raw `` for + users who want crisp photos (e.g. entity detail screens where legibility + beats aesthetic). + +### 4.3 Reference dither kernel (Atkinson) + +``` + * → 1/8 1/8 +1/8 1/8 1/8 (current pixel = *) + 1/8 1/8 (* is at top-left of this 4×? — see standard Atkinson spread) +``` + +Spread pattern (error e from pixel at (x,y) distributed): + +``` + px x+1 (1/8) x+2 (1/8) +x-1 (1/8) x (1/8) x+1 (1/8) + x+1 (1/8) x+2 (1/8) [next row offsets] +``` + +Concretely, 6 neighbors each get `e/8`: `(x+1,y)`, `(x+2,y)`, `(x-1,y+1)`, +`(x,y+1)`, `(x+1,y+1)`, `(x,y+2)`. (Clamp at edges — drop, don't wrap.) + +### 4.4 Where to use it + +- Entity icons / host thumbnails in the KB and entity desktop (the obvious win). +- Mascot or login/Config background art (`ConfigBackground.svelte` already + exists — a dithered backdrop there would be striking). +- Any user-uploaded image in chat/knowledge where we want the "de-imagined" + tone. Keep it **opt-in per call site** via the `plain` prop — don't dither + diagrams/screenshots that need to stay readable. + +### 4.5 Cross-origin caveat + +`getImageData` throws on tainted canvases. If `src` is cross-origin and the +server doesn't send CORS headers, fall back to the plain `` (log once). +For self-hosted assets (the common case here) it's a non-issue. + +--- + +## 5. Fonts: self-host JetBrains Mono + VT323 + +cyberspace self-hosts both faces as `.woff2`. oikos currently pulls DM Sans / +DM Mono / Inknut Antiqua from Google Fonts via a `` in +`web/index.html:10`. + +- Drop `JetBrainsMono-Regular.woff2` and `VT323-Regular.woff2` under + `web/static/fonts/` (or `web/public/fonts/` — match where static assets are + served from; check `vite.config`). +- Add `@font-face` blocks at the top of `app.css` with `font-display: swap`. +- For the cyberspace themes only, the `--font-sans`/`--font-mono`/`--font-heading` + overrides in §3 remap the families — Terracotta/Carbon keep DM Sans/Inknut + untouched. This is the key trick: **font choice is part of the theme**, not a + global swap, so the two art directions don't fight. +- Leave the Google Fonts `` in place for now (Terracotta/Carbon still need + it); add a follow-up to self-host those too if we want to kill the external + request entirely. Out of scope for this plan. + +VT323 vs Departure Mono: VT323 is free on Google Fonts and trivial to self-host; +Departure Mono is the authentic cyberspace face but needs a license check. +**Recommend VT323** to start; swap to Departure Mono later if you want exact +fidelity. + +--- + +## 6. Theme store changes (`web/src/lib/stores/theme.svelte.ts`) + +Current: `Theme = 'light' | 'dark'`, flips `.dark` class. Extend to a named set +while preserving the existing API (callers of `toggleTheme`/`getTheme` keep +working): + +```ts +export type ThemeName = 'terracotta' | 'carbon' | 'cyber-dark' | 'cyber-light' +// Back-compat aliases used by existing callers: +// 'light' -> 'terracotta', 'dark' -> 'carbon' +``` + +- Store key stays `oikos-theme`; migrate old `'light'`/`'dark'` values on read. +- `applyClass` becomes `applyTheme`: sets `data-theme` on `` and toggles + `.dark` **only** for `carbon` (so Terracotta and both cyberspace themes run + with no `.dark`). This is important: the `.dark` block in `app.css` must not + layer on top of the cyberspace token blocks — cyberspace sets its own + polarities. +- Update `THEME_LABELS` to the four names; update whatever UI surfaces the + picker (search for `THEME_LABELS` / `toggleTheme` usages — likely + `Settings.svelte` or the desktop shell's chrome) to a 4-option control instead + of a binary toggle. + +**Watch out:** any code that assumes `document.documentElement.classList.contains('dark')` +≡ "dark colors" will be wrong for `cyber-dark`. Audit `grep -rn "classList.*dark\|\.dark" web/src` and prefer reading `getTheme()`/`data-theme` instead. + +--- + +## 7. Optional cosmetic idioms (additive utilities) + +Small, theme-aware utilities in `app.css` — usable in any theme but idiomatic +for cyberspace: + +- `.terminal-box` — `{ border:1px solid var(--border); border-radius:0 }` plus a + `.terminal-box:focus-within { box-shadow: 0 0 0 2px var(--ring) }` to mirror + the `ring-2 ring-fg` focus. Lets cards opt into the terminal look without a + component rewrite. +- `.braille-spinner` — keyframe cycling `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏` as `::after` content, colored + `var(--muted-foreground)`. Alternative to `Spinner.svelte` for loading states + under cyberspace themes. +- `.font-vt` — `{ font-family: var(--font-heading) }` so the wordmark class + cyberspace uses maps to our heading var (VT323 under cyber themes, Inknut + under Terracotta). Drop-in for any stylized title. +- `.strike-list` — `li > s { color: var(--muted-foreground) }` convenience for + the crossed-out feature-list pattern in marketing/empty states. + +None of these are required for the theme to work; they're palette for the +"de-imagined" voice where we want it. + +--- + +## 8. Implementation order (incremental, each step shippable) + +1. **Fonts** (§5) — self-host JetBrains Mono + VT323, `@font-face` in app.css. + No visual change yet (only cyberspace themes reference them). +2. **Tokens** (§3) — add the two `:root[data-theme='cyber-*']` blocks. +3. **Store** (§6) — extend `theme.svelte.ts` to named themes + `data-theme`; + update the picker UI. **At this point both cyberspace themes are live and + fully recolor the whole app** — the cheapest milestone, biggest visible win. +4. **`RasterImage.svelte`** (§4) — build + wire into entity icons and + `ConfigBackground`. This is the "dithered image" deliverable. +5. **Idioms** (§7) — terminal-box, braille spinner, etc., applied opportunistically. + +Each step is independently mergeable. Step 3 alone satisfies "light + dark +cyberspace themes"; step 4 satisfies "dithered images." + +--- + +## 9. Verification + +- `cd web && npm run build` (or the repo's build command — confirm in + `web/package.json`) — Tailwind v4 must accept the new `data-theme` selectors + and `color-mix()` (both standard; no config change expected). +- `npm run check` / `svelte-check` for the store + component TS. +- Manual: cycle all four themes in the picker; confirm no `.dark` bleed on + `cyber-light`; confirm `RasterImage` re-dithers on theme flip; confirm + `prefers-reduced-data`/`plain` prop shows crisp image; confirm cross-origin + `src` degrades to `` without console errors. +- Lighthouse / a11y: 1-bit dithered images still need a real `alt` (kept on the + fallback ``); contrast on `#a89984`-on-black passes WCAG AA for body text + (ratio ≈ 7.4:1) — fine. + +--- + +## 10. Alternatives considered + +- **Full rebrand (replace Terracotta/Carbon).** Highest visual payoff, highest + cost: every component's rounding/serif/spacing was authored for the Art +ouveau + direction; square + mono would need a component-level sweep, not just tokens. + Defer unless you want cyberspace as *the* oikos look — then do it as a + follow-up that deletes Terracotta/Carbon and makes `cyber-dark` the sole + default. +- **CSS-only image dither (filters / SVG turbulence).** Cheaper, but can't do + true 1-bit error diffusion or recolor to theme fg/bg. Rejected — the canvas + pass is the whole point and is ~60 lines. +- **Ordered (Bayer) dither instead of Atkinson.** More regular/grid-like + ("newspaper halftone"). Atkinson is softer and more terminal-like; keep + Bayer as a `algorithm='bayer'` prop option later if wanted. +- **Server-side dithering.** Could pre-dither icons at ingest. Rejected for + now — client canvas keeps one source of truth (the original image) and lets + the palette follow the live theme, which a baked asset can't. + +--- + +## 11. Non-goals / out of scope + +- Replicating cyberspace's sidebar-rail *layout* (oikos uses a floating-window + desktop shell; the rail is a different app model). We take the *visual* + language, not the IA. +- Porting the 9 other novelty themes (C64, Matrix, VT320, …). Two (light/dark) + satisfy the request; the token model makes adding more trivial later. +- Removing the Google Fonts dependency for Terracotta/Carbon (follow-up). +- Licensing/redistributing Departure Mono (use VT323 unless cleared). + +--- + +## 12. Risks + +- **`.dark` coupling.** Existing code may equate `.dark` with "dark UI". + Mitigation: audit in step 3; the grep is small. +- **Dither perf on large images.** Atkinson is O(n) and runs on a downscaled + canvas (≤~320px wide), so per-image cost is negligible; but batch-rendering + many entity icons on first paint could jank. Mitigation: dither lazily (on + intersection) and cache the result on the element. +- **Tainted canvas** on cross-origin images → silent fallback to `` + (already handled in the design). +- **Token drift.** If a component hardcodes a color instead of using a token, + it won't recolor under cyberspace. This is the same risk Carbon already has; + no new exposure, just more visible under a stronger theme. diff --git a/plans/2026-08-03-nomos-chat-changes-review.md b/plans/done/2026-08-03-nomos-chat-changes-review.md similarity index 100% rename from plans/2026-08-03-nomos-chat-changes-review.md rename to plans/done/2026-08-03-nomos-chat-changes-review.md diff --git a/plans/2026-08-03-nomos-chat-reliability-and-ux-audit.md b/plans/done/2026-08-03-nomos-chat-reliability-and-ux-audit.md similarity index 100% rename from plans/2026-08-03-nomos-chat-reliability-and-ux-audit.md rename to plans/done/2026-08-03-nomos-chat-reliability-and-ux-audit.md diff --git a/plans/2026-08-03-nomos-chat-working-visibility.md b/plans/done/2026-08-03-nomos-chat-working-visibility.md similarity index 100% rename from plans/2026-08-03-nomos-chat-working-visibility.md rename to plans/done/2026-08-03-nomos-chat-working-visibility.md diff --git a/plans/index.md b/plans/index.md index 1070583..c114a45 100644 --- a/plans/index.md +++ b/plans/index.md @@ -17,13 +17,8 @@ went sideways, open an investigation. | 2026-07-14 | [Activity gaps](2026-07-14-activity-gaps.md) | In Progress | | 2026-07-14 | [Activity timeline](2026-07-14-activity-timeline.md) | In Progress | | 2026-07-17 | [Codebase review, lint audit, and documentation maintenance](2026-07-17-codebase-review-and-cleanup.md) | Report delivered — doc/tooling fixes applied; code refactors pending | -| 2026-07-18 | [Session review: three recent sessions](2026-07-18-session-review-three-sessions.md) | Implemented in v0.7.12 — P0.1/P0.2/P1.3/P1.4/P1.5/P1.6/P1.8/P2.10; P1.7 and P2.9 deferred (retry cap covers) | -| 2026-07-20 | [Desktop mascot ("Cluck")](2026-07-20-desktop-mascot.md) | Implemented in v0.8.0 — see deviation note; physics/window-interaction follow-ups tracked separately | -| 2026-07-20 | [Session review: past 10 sessions](2026-07-20-session-review-ten-sessions.md) | Implemented in v0.7.13 — all P0/P1/P2 items landed | | 2026-07-20 | [Mascot physics/window-interaction audit](2026-07-20-mascot-physics-audit.md) | P0–P2 implemented; P3 ("cool stuff") ideas open | | 2026-07-21 | [Frontend as OS + Apps — architecture audit & refactor](2026-07-21-frontend-os-apps-architecture.md) | Planned — Phase 1 ready | -| 2026-08-03 | [Nomos chat: reliability & predictability audit](2026-08-03-nomos-chat-reliability-and-ux-audit.md) | In Progress — F1–F7 shipped in v0.15.0; F8 + follow-ups open | -| 2026-08-03 | [Nomos chat: working-visibility, message queue, generation-aware timeline](2026-08-03-nomos-chat-working-visibility.md) | Implemented in v0.17.0 — F1–F4 shipped; model-efficiency + F8 follow-ups open | ## Done @@ -61,6 +56,16 @@ See [`done/`](done/) for executed plans: | 2026-07-14 | [Post-fix session remainders: empty responses & plan drift](done/2026-07-14-post-fix-session-remainders.md) | | 2026-07-15 | [Plan-first and iteration](done/2026-07-15-plan-first-and-iteration.md) | | 2026-07-15 | [WhatsApp session audit](done/2026-07-15-whatsapp-session-audit.md) | +| 2026-07-18 | [Session review: three recent sessions](done/2026-07-18-session-review-three-sessions.md) | +| 2026-07-20 | [Desktop mascot ("Cluck")](done/2026-07-20-desktop-mascot.md) | +| 2026-07-20 | [Session review: past 10 sessions](done/2026-07-20-session-review-ten-sessions.md) | +| 2026-07-21 | [Chat window full polish](done/2026-07-21-chat-full-polish.md) | +| 2026-07-29 | [Make health reflect reality + complete the knowledge graph](done/2026-07-29-health-check-reality-and-knowledge-graph.md) | +| 2026-07-30 | [Session review: plan drift & dead activity panel](done/2026-07-30-session-review-plan-drift-and-dead-activity-panel.md) | +| 2026-08-03 | [Nomos chat changes review (P0/P1/P2)](done/2026-08-03-nomos-chat-changes-review.md) | +| 2026-08-03 | [Nomos chat: reliability & predictability audit](done/2026-08-03-nomos-chat-reliability-and-ux-audit.md) | +| 2026-08-03 | [Adopt cyberspace.online terminal aesthetic + dithered images](done/2026-08-03-cyberspace-style-adoption.md) | +| 2026-08-03 | [Nomos chat: working-visibility, message queue, generation-aware timeline](done/2026-08-03-nomos-chat-working-visibility.md) | ## Conventions