From 04bc8d96ff9a91448628a78c3e6ef8aeaf5fa8db Mon Sep 17 00:00:00 2001 From: Matei Date: Mon, 8 Jun 2026 15:55:08 -0400 Subject: [PATCH 1/5] =?UTF-8?q?docs(mapgen-studio):=20redesign=20workstrea?= =?UTF-8?q?m=20=E2=80=94=20frame,=20research,=20audit,=20target=20architec?= =?UTF-8?q?ture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Open the MapGen Studio redesign initiative: a top-1%, data-driven React 19 rebuild that decomposes the 3,010-line App.tsx, introduces a native effect-orpc server on Bun, oRPC-native TanStack Query + Zustand on the client, and full canonical shadcn/ui + Tailwind v4 — with behavior parity for map-gen, Deck.gl, recipes, and the live-game control loop. Artifacts: - 00-GOAL.md — framed objective, user decisions, falsifier, parity hard core - research/01-orpc-effect-bun.md, research/02-orpc-tanstack-zustand.md - audit/03-component-architecture, 04-design-system, 05-server-contracts, 06-typescript-rigor - architecture/10-target-architecture.md, 11-slice-plan.md - apps/mapgen-studio/system.md — extracted current design language Co-Authored-By: Claude Opus 4.8 --- apps/mapgen-studio/system.md | 124 ++++ .../mapgen-studio-redesign/00-GOAL.md | 91 +++ .../architecture/10-target-architecture.md | 149 +++++ .../architecture/11-slice-plan.md | 93 +++ .../audit/03-component-architecture.md | 322 +++++++++++ .../audit/04-design-system.md | 230 ++++++++ .../audit/05-server-contracts.md | 158 +++++ .../audit/06-typescript-rigor.md | 144 +++++ .../research/01-orpc-effect-bun.md | 509 ++++++++++++++++ .../research/02-orpc-tanstack-zustand.md | 545 ++++++++++++++++++ 10 files changed, 2365 insertions(+) create mode 100644 apps/mapgen-studio/system.md create mode 100644 docs/projects/mapgen-studio-redesign/00-GOAL.md create mode 100644 docs/projects/mapgen-studio-redesign/architecture/10-target-architecture.md create mode 100644 docs/projects/mapgen-studio-redesign/architecture/11-slice-plan.md create mode 100644 docs/projects/mapgen-studio-redesign/audit/03-component-architecture.md create mode 100644 docs/projects/mapgen-studio-redesign/audit/04-design-system.md create mode 100644 docs/projects/mapgen-studio-redesign/audit/05-server-contracts.md create mode 100644 docs/projects/mapgen-studio-redesign/audit/06-typescript-rigor.md create mode 100644 docs/projects/mapgen-studio-redesign/research/01-orpc-effect-bun.md create mode 100644 docs/projects/mapgen-studio-redesign/research/02-orpc-tanstack-zustand.md diff --git a/apps/mapgen-studio/system.md b/apps/mapgen-studio/system.md new file mode 100644 index 0000000000..83a714e6e5 --- /dev/null +++ b/apps/mapgen-studio/system.md @@ -0,0 +1,124 @@ +# mapgen-studio — Design System (extracted) + +> Extracted from the current codebase (`src/**/*.tsx`, `src/index.css`, `tailwind.config.js`, `src/ui/hooks/useTheme.ts`) on 2026-06-08. +> This captures the **current** design language as-built. It is the baseline the shadcn migration must preserve (density, dark-first palette, border-only depth) while formalizing tokens. + +## 1. Design DNA + +A **dense, dark-first developer tool**. Think pro audio / DAW / data-explorer, not a marketing app. Information density is the point: micro-typography (10–11px), tight 4px spacing rhythm, hairline borders instead of shadows, and a restrained near-monochrome palette with a single cool accent. Map visualization (deck.gl) is the hero; chrome recedes. + +- **Mood**: technical, quiet, high-density, focused. +- **Hierarchy mechanism**: borders + background-tier shifts (not shadow, not color). +- **Personality risk today**: reads as *commodity dark dashboard* — defaults dominate (gray accent, flat focus rings, no motion). The craft work is to make density feel *intentional*, not cramped. + +## 2. Color + +Two hand-maintained palettes (`light` / `dark`) live in **three** places that disagree (see audit): `tailwind.config.js`, `src/index.css` CSS vars, and `src/ui/hooks/useTheme.ts`. The values below are the de-facto source of truth (`useTheme.ts`, matched by hardcoded hex frequency in components). + +### Dark (primary — app defaults to dark) +| Role | Value | Notes | +|---|---|---| +| bg / page | `#0a0a0f` | deck.gl backdrop tint | +| bg / panel | `#141418` | cards, headers | +| bg / panel-alt | `#111114` | | +| bg / nested | `#0f0f12` | inputs, nested cards | +| bg / hover | `#1a1a1f` | | +| bg / active | `#222228` | secondary buttons, tags | +| border / default | `#2a2a32` | **the workhorse hairline** (31 uses) | +| border / subtle | `#222228` | dividers (20 uses) | +| border / strong | `#3a3a44` | input focus border (14 uses) | +| text / primary | `#e8e8ed` | (36 uses — most frequent hex) | +| text / secondary | `#8a8a96` | labels (19 uses) | +| text / muted | `#5a5a66` | placeholders, help (14 uses) | +| accent / interactive | `#4b5563` | primary button, switch-on, active tag (19 uses) | +| accent (system var) | `#5e5ce6` | indigo — declared in CSS but **barely used** | + +### Light +| Role | Value | +|---|---| +| bg / page | `#f5f5f7` | +| bg / panel | `#ffffff` | +| border / default | `#e5e7eb` / `#e5e5e5` (drifts) | +| text / primary | `#1f2937` (26 uses) | +| text / secondary | `#6b7280` (17 uses) | +| accent | `#4b5563` | + +### Semantic / status +- error/destructive: `text-rose-400`, `bg-red-500`, `text-red-600` (inconsistent — rose vs red). +- success: `text-emerald-500`. info: `text-blue-500`. + +**Observation:** the *declared* accent (`#5e5ce6` indigo) is not the *used* accent (`#4b5563` slate). The brand is effectively neutral-slate. This is the single biggest "commodity" tell. + +## 3. Typography + +- **Sans**: Inter (400/500/600/700). **Mono**: JetBrains Mono. Both via Google Fonts `@import` in `index.css` (render-blocking — flag). +- **Scale (actual, by frequency):** + | Token | Size | Uses | Role | + |---|---|---|---| + | — | **11px** | 44 | body / field text / values (the default) | + | — | **10px** | 38 | labels, uppercase eyebrows, captions | + | — | 12px | 7 | section subtitles | + | — | 13px | 4 | | + | text-sm (14px) | 14 | 4 | dialog titles | + | — | 9px | 3 | dense badges | +- **Weights**: `font-medium` (28), `font-semibold` (14). No bold in UI chrome. +- **Pattern**: uppercase + `tracking-wider` + 10px for eyebrow labels (e.g. AppHeader "Config", "Resources"). +- **Type is set in arbitrary `text-[11px]` values**, not a named scale — every size is ad-hoc. + +## 4. Spacing + +- **Base unit: 4px.** Rhythm is tight. +- Scale by frequency: `gap-2`(8px, 47×) ≫ `px-3`(12px, 27×) > `py-2`(8px, 14×) > `gap-1`(4px, 13×) > `gap-1.5`(6px) > `py-2.5`(10px) > `p-2`/`p-2.5`(8/10px). +- **Effective scale: 4, 6, 8, 10, 12, 16 px.** Above 16px is rare (panel padding only). +- Field rows: `py-1` (4px) vertical, `gap-3` label↔input. Cards: `p-2.5` (10px). Nested cards: `p-2` (8px). + +## 5. Radius + +- `rounded` (4px, 28×) = default for inputs/buttons/tags. +- `rounded-lg` (8px, 15×) = cards, dialogs, dropdowns, toasts. +- `rounded-full` (8×) = pill tags, switch track. +- `rounded-md` (6px, 2×) = rare/inconsistent. +- **Effective scale: 4 / 8 / full.** (6px and config's `xl`/`2xl` are noise.) + +## 6. Depth + +- **Border-only.** 148 border utilities vs **7** shadows. Shadows appear only on floating layers (dialog `shadow-xl`, toast `shadow-lg`, dropdown `shadow-lg`). +- Tiering by **background lightness step** (page → panel → nested) + 1px hairline. This is the core depth language. +- `backdrop-blur-sm` (11×) on the floating header/setup bar — glassy chrome over the map. + +## 7. Motion + +- **Minimal.** `transition-colors` (29×) is ~all of it; `transition-transform` (5×) for chevron rotation; one `animate-pulse-subtle` (2s) for running state. +- Durations: 150ms (fast) / 200ms (normal), declared as CSS vars but mostly implicit Tailwind defaults. +- `animate-in fade-in-0 zoom-in-95` strings appear on dialog/toast/tooltip **but no `tailwindcss-animate` plugin is installed** — these classes are dead (no keyframes). Motion is effectively absent on overlays. + +## 8. Component patterns + +| Pattern | Spec (as-built) | +|---|---| +| **Button** | h-8 default / h-7 sm / h-7 icon; `px-3`; `rounded`; `text-sm`/`text-xs`; variants default(slate)/outline/secondary/ghost/link/destructive; CVA-driven. Focus ring `ring-1 ring-gray-400`. | +| **Input / Textarea / Select** | h-7; `text-[11px]`; `px-2.5`; `rounded`; 1px border; focus = border color shift + `ring-1`. Native `` can't search. | +| **Sheet** | `@radix-ui/react-dialog` (side) | mobile/narrow: left RecipePanel + right ExplorePanel as slide-over drawers | the app toggles left/right panels via shortcuts (`toggleLeftPanel`/`toggleRightPanel`, `App.tsx:2551`) — Sheet is the responsive form of that. | +| **Resizable** | `react-resizable-panels` | the 3-pane layout (left panel │ map │ right panel) in `App.tsx` (`leftPanel`/`rightPanel`/deck canvas, ~line 2799-2984) | user-draggable panel widths — currently fixed via `LAYOUT` constants. High-value for a data-explorer. | +| **Skeleton** | (css only) | generation-in-progress / recipe-loading states (see Craft #5) | structured loading instead of opacity pulse. | + +--- + +## 4. rjsf Theming through shadcn + +The JSON-schema form is the **largest single surface** (`features/configOverrides/`): `rjsfWidgets.tsx` (widgets) + `rjsfTemplates.tsx` (field/object/array templates) + `ui/components/fields/` (styles). Today it routes through the hand-rolled primitives and a parallel `getFormTheme()`/`getInputStyles()` class-soup that **duplicates** the primitive styling with its own hardcoded hex. + +**Strategy — make rjsf a thin adapter over shadcn:** + +1. **Widgets → shadcn primitives, drop `lightMode`.** `rjsfWidgets.tsx` already maps `TextWidget/NumberWidget/SelectWidget/CheckboxWidget/SwitchWidget/TextareaWidget/TagSelectWidget` to the `ui/` primitives. Swap each to the shadcn equivalent and **delete the `getLightMode(props)` plumbing and the `lightMode` formContext field** — theming becomes the `.dark` class on ``, so widgets need zero theme awareness. `SelectWidget` should move from native `