# Extrudex Soft UI (Design System v3) proposal: summary 2026-09-18. This is a proposal only. **Nothing was changed** in the Extrudex repository (still clean at `dev` `321ce0d`) or in CTXD. Nothing was deleted. ## What I built and where it is Everything is in `~/Design/extrudex-v3/`. | File | What it is | |---|---| | `00-understanding.md` | Step 1: every field on each existing screen, every stored printer field, the v2.0 palette, and how CTXD differs from the code | | `design-system-v3.css` | Step 2: the token set. v2.0 base kept, dark and light themes, neumorphism tokens (surfaces, raised and inset pairs, 4 intensity levels, radius scale), state tokens, reference components | | `design-system-v3.md` | Step 2: every changed or added token with its reason, the state matrix, the dark-mode approach, 2 alternative palettes, and contrast tables for both themes (54/54 pass, plus 9 more pairs) | | `fonts/` | JetBrains Mono 400/500/700/800 woff2 (the same `@fontsource` 5.3.0 files the app ships) + OFL license | | `screens/01-dashboard.html` | **New standalone Dashboard**: stock tiles, running low (net + gross, tare unknown shown), net kg by material, recent prints with weight source and upper-bound duration marks, compact printer strip | | `screens/02-filament.html` | Inventory: working search and filters, table/cards toggle, the 5-part name, net remaining vs tare (+ source) vs gross, Edit, Delete with a confirmation dialog | | `screens/03-spool-form.html` | Add/Edit spool with a scenario switcher: **409 conflict**, **400 field errors**, **tare unknown**, **add new**, plus a control-state specimen | | `screens/04-printers.html` | Printers: stored fields only, a "dev today / dev + feature branch" data toggle, the **MQTT dropped** state (A1), and a **Future, not built** section | | `source/` | Build inputs (`build.py` makes each screen self-contained with base64 fonts) and `checks/table.py`, which regenerates the contrast table | Every screen has a Light/Dark toggle (also `?theme=light` or `?theme=dark` in the URL), has no network dependencies, and was checked at 1440 px and 390 px in headless Chrome. ## Decisions that go against DECISIONS.MD or the v2.0 rules 1. **Styling: "tokens verbatim… do not edit a token to suit a component."** v3 changes the *values* of a few v2.0 semantic tokens (`--surface-raised`, `--shadow-raised`, `--focus-ring`, `--radius-sm`, `--radius-md`, `--text-on-accent` in light). This isn't editing a token to suit a component. It's a proposed new *version* of the design system, and each change has a reason in the .md. It still needs your call: adopting it means updating the guide at `pages.ccl` first and then copying it verbatim into `theme.css`, as the rule intends. 2. **v2.0 brand rules "0 radius" and "flat shadows"** are overturned. Soft UI can't exist without them. `--radius-none` stays for tables and code. 3. **Primary buttons changed color, dark theme** (`#8f7ae0` → `#a99af0`), because v2.0's ink-on-accent is **4.32:1** and fails AA. That's a brand-color shift on the most visible control. 4. **CONTEXT scope: "printer status pages… deliberately out until daily use."** The Printers screen was designed because you asked for it. Note that a printers view already exists on `dev`, embedded in Floor. Things I followed even where the code has moved past the docs: - **Weight source** is shown with 4 values (`typed`, `sliced`, `recalled`, `unknown`). DECISIONS.MD lists 3. The schema adds `sliced` and says `recalled` is no longer written. - **Tare origin**: the code (`resolveTare` in `types.ts`) falls back to a **brand** tare, labeled as a guess. DECISIONS.MD says tare comes "from spool_type, never from brand". The mockups never show a brand-derived tare. ## Open questions 1. **Adopt or reject** the two brand-rule changes (radius, shadows) and the lighter primary-button violet? Everything else depends on this. 2. **Floor → Dashboard + Printers.** The proposal splits today's Floor into a stock-first Dashboard and a separate Printers page. Is that the direction, or should Floor stay as one page restyled? 3. **Weight source in `GET /api/prints`.** It's stored but not served, so the Dashboard needs a small API change. OK to add it? 4. **`recalled` vs `sliced`.** Should DECISIONS.MD be updated to say `sliced` exists and `recalled` is legacy? That's a CTXD edit, which I didn't make. 5. **Brand-tare fallback.** Code and DECISIONS.MD disagree. Which one is right? 6. **Serial display.** I masked the middle of serials (`01P09A••••••4821`). Show in full, masked, or hidden? 7. **"Tare unknown only" filter** is new on the Filament page (it helps work down the "weigh it yourself" list). Keep it? 8. **The 409 "reapply my change" button** assumes the client can diff the fields you changed against the new version. Today the form only shows the server's message. Do you want that behavior, or just "reload"? 9. **Alternative palettes** A (warm graphite) and B (slate/teal) are in the .md. Do you want either mocked up? 10. **CTXD is out of date** (Dashboard.tsx, no auth, Bambu only, the design system URL). Should someone refresh CONTEXT.MD? I made no CTXD edits. ## Proposed Maestro tasks (titles only, smallest first; not created) 1. Add `weight_source` to the `GET /api/prints` response 2. Add v3 warning and info status tokens to `theme.css` 3. Add the `--border-control` token and apply it to buttons, inputs and selects 4. Replace the v2.0 focus ring with the v3 2px offset outline 5. Fix primary-button text contrast (4.32:1 → 6.14:1) 6. Show a weight-source chip on each print row 7. Show an upper-bound mark on durations with connection gaps 8. Show "gaps not counted" on prints with null `connection_gaps` 9. Show tare, tare source and gross weight on the Filament table and cards 10. Show "tare unknown" (never 0) wherever gross weight is derived 11. Add the "Tare unknown only" filter to Filament 12. Map spool 400 messages to their fields in SpoolForm 13. Add the 5-part name preview to SpoolForm 14. Add the net/tare/gross scale diagram to SpoolForm 15. Replace the SpoolForm 409 footer text with a conflict panel and reload actions 16. Add a light theme with a stored per-browser toggle 17. Add the neumorphism shadow and radius tokens (after the brand decision) 18. Restyle buttons, inputs and chips with the v3 state matrix 19. Split Floor into a stock-first Dashboard and a Printers page 20. Render the connection-lost state on printer cards (after the printer-connections feature merges) 21. Publish Design System v3 to `pages.ccl` and re-sync `theme.css` verbatim --- # Iteration 2 (2026-09-18): navigation, data display and interaction Everything is in `iteration-2/`. Iteration 1 above is unchanged, for comparison. | File | What it is | |---|---| | `iteration-2/00-ux-review.md` | 12 findings from iteration 1, the navigation model, flows ranked by frequency, interaction patterns, data-display rules, accessibility notes, 5 new questions, 18 more task titles | | `iteration-2/screens/index.html` | **Start here.** Flow map plus 8 guided flows that deep-link into each state | | `iteration-2/screens/01-dashboard.html` | "Needs you" queue first, then stock tiles, recent prints by day, printers and running low. Everything clickable | | `iteration-2/screens/02-filament.html` | Saved views with counts, Stock/Weights columns, grouping, sortable headers, row ⋯ menu, weigh session | | `iteration-2/screens/03-prints.html` | **New.** Needs attention (inline suggestions, grams, batch) · All · Running · Archived | | `iteration-2/screens/04-printers.html` | Urgency order, jump strip, holder fill + Load, stale "last known" state, dev/feature toggle | | `iteration-2/source/` | `data.js` (one shared model), `app.js` (shell, palette, panel, toasts), `components.css`, pages, `build.py` | What's shared across every page: the spool/print/load **panel** (deep-linked, Esc/back closes, j/k steps), the **⌘K palette**, nav **badges** for work waiting, **toasts** after each save, a **freshness** indicator with an offline state, and a phone **tab bar** with a floating Add button. **Corrected from iteration 1:** it showed AMS "slot" positions, which the database doesn't store. Iteration 2 shows holder fill ("3 / 4") instead. Verified: every page and panel state loads with no console errors in headless Chrome, at 1440 px and 390 px, in both themes. There are no network requests, and no new colors (the v3 contrast table still applies). --- # Iteration 3 (2026-09-18): remaining screens, tablet and phone Everything is in `iteration-3/`. Iterations 1 and 2 are unchanged. - **Start here:** `iteration-3/screens/index.html` (flow map, 14 flows) and `iteration-3/screens/devices.html` (every screen in live phone 390 × 844, tablet 820 × 1180 and 1180 × 820 frames). - **New screens:** 05 Lists · 06 Labels · 07 Access · 08 System · 09 Scan: holder · 10 Scan: spool, plus Add/Edit printer, Manage holders and Remove printer panels on Printers. - **Your answers from `iteration-2/00-ux-review.md`, applied:** Change spool (with real grams-returned wording), lightest-first weigh sessions with location, Filament badge for unverified tares, and load/attribute palette commands. - **Responsive:** three tiers (phone < 700, tablet 700–1180 with a compact rail, desktop). Spec in `iteration-3/00-changes.md` §4. - **Findings:** list names are case-sensitive in the schema; audit log, low-filament report and machine tokens have APIs but no screens on `dev`. - **Verified:** all 12 pages and 18 panel/palette states load with no console errors; checked at 390, 820 and 1180 px and desktop, in both themes. No network requests, no new colors. **Terminology update (2026-09-18):** iteration 3's UI now says **"empty spool weight"** everywhere it said "tare" (verified: no rendered text, tooltip, label or placeholder contains "tare"). Code and API names (`tare_grams` etc.) are unchanged. See `iteration-3/00-changes.md` §1b. Open item: GLOSSARY.MD in CTXD still uses "Tare".