Files
design-v3/iteration-2/00-ux-review.md
T
Joshua KingandClaude Opus 5 d9ed1898b9 Add the Extrudex Design System v3 bundle
Tokens (light + dark, neumorphism, 54/54 WCAG AA contrast pairs), the
self-hosted JetBrains Mono fonts, and interactive mockups of every screen
across three iterations. Iteration 3 is final: phone, tablet and desktop
tiers, device preview, and "empty spool weight" terminology. The build
scripts regenerate the screens byte-identically from source.

Implementation is tracked in Maestro feature UI Refresh - V3.0
(224b72a1-8d84-4970-97ea-5dafa4d8ea3b).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 11:31:50 -04:00

14 KiB
Raw Blame History

Iteration 2: navigation, data display and interaction

2026-09-18. Builds on iteration 1 (../screens/, left unchanged for comparison). Same Design System v3 tokens; the new components are in source/components.css. Open screens/index.html first: it's the flow map, with eight guided flows that deep-link into each state.


1. What was wrong with iteration 1

# Where Problem Why it matters Iteration 2 fix
1 Nav, Dashboard "Prints" and "All prints →" linked to #. Dead ends. You lose trust in a nav item the first time it does nothing. A real Prints page (history + attention queue, as on dev)
2 Filament → Edit Edit navigated to a separate page You lose your place, filter and scroll every time Detail panel opens over the list; Esc/back returns you to where you were
3 Dashboard, Printers A spool in "Running low" or an AMS slot wasn't clickable The most natural next click went nowhere Every spool, print and holder opens the same panel, on any page
4 Dashboard Reported numbers but never said what to do The kill criterion is daily use, so the home screen has to hand you today's jobs "Needs you" queue, each item one click from its fix
5 Everywhere Almost every value was an uppercase chip (status, provenance, warnings) Nothing stands out when everything is loud, so a legend box was needed Chip/label hierarchy (§5.1); provenance became quiet text with a tooltip
6 Filament table Tare, source, gross, value, location and two actions in every row, 2–3 lines each Too dense to scan 105 rows Stock / Weights column sets; the full breakdown moves to the panel
7 All pages No freshness, loading, empty or error state The app polls every 10 s; stale data shown as live is the worst failure "Live · updated 3s ago" in the header, an offline banner with the data's age, skeletons, empty states
8 Filament "P1S · AMS 1 · slot 2" Invented. The schema stores the holder, not the tray position Holders show fill ("3 / 4") and contents; tray position listed under Future
9 Mobile Nav squeezed into icon rows; no reachable primary action Weighing happens at the shelf, on a phone Bottom tab bar with badges, a floating + button, the panel as a full-screen sheet
10 Every page A large proposal banner on top of every screen Pushed content down; it read as part of the app A small "Mockup" pill bottom-left, with the legend and demo controls inside
11 Printers One card per section in three stacked sections Two-thirds of the width empty; the lost printer was mid-page Urgency order (lost → printing → idle) in one row, plus a "Jump to" strip
12 Printers ↔ Dashboard "Open printer" landed at the top of the page You had to find the right card yourself 04-printers.html#printer=3 scrolls to that card and highlights it

2. Navigation model

┌ Rail (desktop) / tab bar (phone) ─────────────────────────────┐
│ Dashboard · Filament · Prints [3] · Printers [1]              │  ← badges = work waiting
│ Manage: Lists · Labels [4] · Access (admin)                   │  ← kept on dev, not redesigned
└───────────────────────────────────────────────────────────────┘
Top bar on every page:  [ Search… ⌘K ]   ● Live · updated 3s ago   [◐]
  • Four destinations, ranked by how often they're used. Manage items are second-tier and grouped separately. Access is labeled "admin".
  • Badges only for work waiting: Prints = prints missing a spool or weight (amber); Printers = disconnected printers (red). No badge for totals, so a badge always means "go here".
  • One page header pattern: title, a one-line summary with the key numbers, one primary button on the right, everything else under "More ▾".
  • Deep links for every state, so browser Back, bookmarks and sharing all work:
URL Opens
02-filament.html?f=low&q=black Filament, Low view, filtered
…#spool=47 · #spool=47&tab=weigh · &tab=edit&state=conflict Spool panel, on a tab, optionally in a demo state
03-prints.html?tab=needs · #print=210 Prints tab / print panel
04-printers.html#printer=3 · #load=p3-lite Scroll to printer / load a holder
?palette=weigh%20black Palette open with a query (demo hook)

3. Core flows (most frequent first)

Flow Steps in iteration 2 Iteration 1
Morning check Dashboard → "Needs you" → Review 3 → Use suggestion ×2, type 1 weight Not possible; no queue
Attribute a print Prints › Needs attention: suggestion shown inline → Use. Or batch-select → one spool Not designed
Weigh a spool Row ⚖ Weigh, or palette weigh copper → type reading → see before → after → Save Open the form, find the weigh box, save the whole form
Weigh several Filament › Low → Start weighing → Save & weigh next (j/k also steps) One at a time, reopening the form each time
Load a spool Printers → holder + Load → filter stored spools → pick → Load Not designed
Move / unload Panel › Move: storage or any holder; full holders disabled with the reason Only by typing a location
Add a spool + Add spool (header, FAB, palette) → panel with 5-part name preview Separate page
Handle a 409 Panel › Edit: side-by-side you-opened / now / your-edit → reapply or discard Same content, but on a separate page
Tare unknown Tare unknown view → Weigh tab explains, offers spool type or weigh-empty Only a hint under the form field
Find anything / or ⌘K → spools, prints, printers and actions in one list Filament search only

4. Interaction patterns

Panel (drawer) vs page. Use a page for a collection and a panel for one thing. The panel sits on the right (520 px) and becomes a full-screen sheet under 860 px. Tabs: Overview · Weigh · Move · Edit for spools; a single view for prints, with the fix at the top when something is missing.

  • Opens with the heading focused (or the tab's main input), traps Tab, and returns focus to the row that opened it.
  • Esc, the ✕, clicking the backdrop or browser Back closes it.
  • ↑ / ↓ buttons and j / k step through the list it was opened from. The footer's Save & weigh next does the same while weighing.
  • Unsaved changes: closing Edit with changes shows an inline "Discard unsaved changes?" bar, not a browser confirm().

Command palette. / or ⌘K from anywhere. Empty, it shows actions (Add spool, Weigh a spool…, Prints needing attention, Switch theme) plus Go to. Typing matches color, brand, #id, location, job name, gcode path or printer. The weigh prefix turns the list into "Weigh which spool?". ↑↓ ↵ Esc all work. It uses the ARIA combobox + listbox pattern.

Row actions. A whole row is clickable and focusable (↵ opens it). The most common action (⚖ Weigh) is visible on the row; the rest sit in a ⋯ menu, which is always visible so touch and keyboard users can reach it. Destructive items are last, after a separator, in red.

Confirmation. Only for destructive actions, and it says the consequence: "Its print history stays… This can't be undone." Everything else saves directly and confirms with a toast that names what changed ("Weighed Copper · Sunlu: 97 g → 58 g"), with a View link. There's no fake Undo, because the API has none.

Batch. Batch attribution follows dev's AttributionQueue (select → attribute to one spool). The weigh session is the batch pattern for weighing.

Keyboard map. / ⌘K palette · ↵ open row · Esc close · j k next and previous in the panel · Tab stays inside the panel while it's open.


5. Data display rules

5.1 Three visual tiers, used for nothing else

Tier Looks like Used for Examples
State Colored dot/shape + bold word What something is doing ● Running · ● Finished · ◆ Unknown · ■ Failed · ○ Idle · ◆ Reconnecting
Needs action Amber/red text with ! or ⚠, or an amber meter Something you should do ! no spool · ⚠ 97 g · ? tare unknown
Provenance Small gray icon + lowercase word, tooltip explains Where a number came from ✎ typed · ▦ sliced · ⎘ recalled · ⚖ weighed bare · ◇ community · ≈ estimated

Each state has its own shape (dot, diamond, square, ring), so status never relies on color alone. Chips (pills) remain only for view counts, filters and the "Future, not built" marker.

5.2 Numbers

  • Grams: 1,000 g with thousands separators, always a space before the unit. Totals over 1 kg: 95.72 kg. Money: $1,721.18.
  • Right-aligned tabular numbers in tables; the unit is never dropped.
  • Net is the default. "Remaining" always means net filament. Gross appears only with its tare beside it (262 g tare + 812 g = 1,074 g), so the three can't be confused.
  • Unknown is written out (unknown, no duration, — only for "not applicable yet"). A missing tare is never 0.
  • Durations: 3h 12m. An upper bound is ≤ 3h 12m in amber, with the gap count beneath.

5.3 Time

Today and yesterday are relative words plus a clock time (Today 08:37, Yesterday 21:48); older dates are 16 Sep 10:20. Freshness is relative (updated 3s ago, last contact 6m ago), because the question it answers is "can I trust this?".

5.4 Meters

The remaining meter carries a tick at the 200 g line, so "how close to low" reads without a number. The fill turns amber below it.

5.5 Progressive disclosure

Where Shows Moves to the panel
Filament row Spool, remaining meter, location or tare/gross (column set), value Full tare/gross breakdown, source, spool type, label, version, prints from this spool
Print row Job, state, duration, grams + source, spool, cost Job key, why the source matters, per-color table, use type, archive
Printer card State, now/last job, camera, holder contents Connection details (collapsed)

5.6 System states on every list

Loading → skeletons of the real layout (never a spinner over an empty page). Empty → what's missing and one action ("Clear filters"). Stale → header dot turns amber, and a banner gives the data's age and says saving is paused. All-done → "✓ Nothing needs you right now."


6. Accessibility of the new pieces

  • Panel: role="dialog", aria-modal, labeled by its heading, focus trap, focus returned on close.
  • Palette: role="combobox" + listbox with aria-activedescendant.
  • Tabs and segmented controls use aria-selected/aria-pressed and show a raised fill plus bold text, not shadow alone.
  • Sortable headers use aria-sort with a visible ▲/▼/↕.
  • Meters use role="meter" with min, max and now.
  • Toasts sit in an aria-live="polite" region. The offline banner is role="alert".
  • Skip link, and focus rings on every interactive element (including rows).
  • Motion (drawer slide, highlight flash, skeleton shimmer) turns off under prefers-reduced-motion.
  • All contrast pairs are unchanged from v3 (54/54 pass). No new colors were introduced.

7. Things I fixed for honesty

  • Tray positions removed (see §1 #8). The Move flow chooses a holder, and full holders are disabled with the reason.
  • "Loaded filament: recorded by Extrudex, not read from the printer" on every printer card.
  • API gaps are labeled where they bite: spool location history (spool_location_event has no read endpoint) and weight source on /api/prints.
  • The weigh flow shows before → after and refuses, with the reason, a reading below tare or above a full spool (the same two checks dev does).

8. Not redesigned in this iteration

Lists (taxonomy), Labels, Access administration, the Add/Edit printer form, and the phone scan session (/s/:id, /c/:id). They keep their dev screens. The nav links to them show a toast saying so.

9. New open questions

  1. Suggested spool acceptance. On dev a suggestion is "not confirmed or charged" until accepted. Iteration 2 puts Use one click away. Is one click enough confirmation for a deduction, or should it ask? 1a. On click is fine as long as it's accurate. It can always be manually updated if it was an error.
  2. Weigh session order. It follows the current list order (least remaining first). Would shelf order be better? That needs location to be structured, not free text. 2a. Weight would be best, but the location should also be visible, that way I can see the rolls that are lowest and use them first.
  3. Default landing page. Dashboard, or straight to Prints › Needs attention when it's non-empty? 3a. Dashboard
  4. Badge scope. Should Filament get a badge for "tare unknown", or does that become nagging, since most tares resolve from a spool type? 4a. Yes, this is good. It identifies an assumed weight and could be off.
  5. Palette actions. Worth adding "Load ‹spool› into ‹holder›" and "Attribute ‹print› to ‹spool›" as typed commands? 5a. Makes sense to me.

10. Extra implementation tasks from iteration 2 (titles only, smallest first)

  1. Add a freshness indicator driven by the last successful poll
  2. Show an offline banner with the data's age when polling fails
  3. Add a 200 g tick to the remaining meter
  4. Replace provenance chips with icon + text labels and tooltips
  5. Make spool rows and holder contents open a detail panel
  6. Deep-link panel state in the URL (#spool=, #print=, &tab=)
  7. Add Stock / Weights column sets to Filament
  8. Add saved views with counts to Filament (All, Low, Loaded, In storage, Tare unknown)
  9. Add a Weigh tab with a live before/after preview
  10. Add a weigh session (Save & weigh next)
  11. Add a Move tab that picks a holder, disabling full ones
  12. Add "+ Load" on printer holders with a stored-spool picker
  13. Add a Needs attention tab to Prints with inline suggestion acceptance
  14. Add nav badges for prints needing attention and disconnected printers
  15. Add a "Needs you" queue to the Dashboard
  16. Add a ⌘K command palette over spools, prints, printers and actions
  17. Add a mobile bottom tab bar and a floating Add button
  18. Order printer cards by urgency and support #printer= scroll-to