# Extrudex — Homepage (Main Hub) UI/UX Specification > **Author:** Sketch (Design Lead) > **Date:** April 20, 2026 > **Version:** 1.0 > **Status:** Ready for Review → Implementation Handoff --- ## 1. Objective **Who is it for?** Workshop operators and print managers who interact with Extrudex primarily on a Raspberry Pi 5 kiosk touchscreen (arm's length, greasy hands, ambient workshop lighting) and secondarily via a mobile PWA browser for remote monitoring. **What task are they completing?** The Homepage serves as the **command center** — the single screen where a user can, at a glance: 1. **Assess the fleet** — See the real-time status of every printer (printing, idle, paused, error, offline). 2. **Spot problems fast** — Instantly identify which machines need attention (errors, paused jobs, low filament). 3. **Take action** — Navigate to a specific printer, spool, or print job with minimal taps. 4. **Monitor inventory** — Get a quick read on filament stock levels and recent consumption. 5. **Recent activity** — See the last few completed or failed prints for situational awareness. **Success metric:** A user walking past the kiosk can determine fleet health in under 2 seconds without touching the screen. --- ## 2. Screen Inventory The Homepage/Main Hub is a **single screen** that serves as the root of the navigation tree. It does not itself contain sub-screens, but it is the gateway to: | Destination Screen | Triggered By | Priority | |---|---|---| | **Printer Detail** | Tapping any printer card | Primary | | **Spool Inventory** | Nav tab "Spools" | Primary | | **Print Jobs** | Nav tab "Prints" | Primary | | **Materials DB** | Nav tab "Materials" | Secondary | | **Settings** | Nav tab "Settings" | Secondary | | **Quick Scan** | Floating action button (FAB) | Primary | The Homepage itself contains these **in-page sections** (not separate screens): 1. **Status Summary Bar** — Fleet-wide health at a glance 2. **Printer Fleet Grid** — Live status cards for each printer 3. **Filament Stock Snapshot** — Inventory overview with low-stock alerts 4. **Recent Activity Feed** — Last 5 print events --- ## 3. Layout Specification ### Page Title **"Extrudex"** — Always visible in the top app bar. No subtitle needed; this is the root screen. ### Navigation Structure **Primary Navigation: Bottom Navigation Bar (Mobile/Kiosk)** Material Design 3 bottom navigation with 5 destinations: | Tab | Icon (Material Symbols) | Label | Badge? | |---|---|---|---| | **Hub** | `dashboard` | Hub | — (active by default) | | **Printers** | `print` | Printers | Error count badge | | **Spools** | `inventory_2` | Spools | Low-stock badge | | **Prints** | `receipt_long` | Prints | — | | **Settings** | `settings` | Settings | — | **Rationale for bottom nav:** - Touch-first: bottom nav is the easiest reach zone on a touchscreen kiosk or phone. - 5 tabs is the MD3 maximum — keeps things scannable. - "Hub" is the homepage; the other four are top-level destinations. - Badges on Printers/Spools draw attention to problems without requiring navigation. **Desktop/Navigation Rail (Future)** On wider screens (browser dashboard), the bottom nav converts to a Material 3 Navigation Rail on the left edge with the same 5 destinations. This is a responsive transformation, not a separate navigation system. ### Main Sections (Top to Bottom) #### A. Top App Bar - **Leading:** Extrudex logo mark (gear icon + "EXTRUDEX" in Inter Bold) - **Trailing:** - Connection status indicator (green dot = SignalR connected, red dot = disconnected) - Clock (kiosk mode — always visible so users know the time without looking at their phone) - **Style:** MD3 medium top app bar, `surface` color background, no elevation (flat) - **Height:** 64px kiosk / 56px mobile #### B. Status Summary Bar A horizontal strip below the app bar showing fleet-wide metrics in a single row: | Metric | Format | Color Logic | |---|---|---| | Printers Active | `4 / 7` | Text only, neutral | | Printers in Error | `1` | Red if > 0, hidden if 0 | | Low Filament Spools | `2` | Yellow if > 0, hidden if 0 | | Prints Today | `12` | Neutral | - **Layout:** Horizontal flex row, evenly spaced, each metric in a compact chip/badge - **Kiosk override:** Larger font (20px), more spacing between metrics - **Mobile:** Compact chips with icons, horizontally scrollable if overflow - **Tap behavior:** Tapping "Printers in Error" navigates to Printers tab filtered to errors. Tapping "Low Filament" navigates to Spools tab filtered to low stock. #### C. Printer Fleet Grid The **heart of the homepage**. A responsive grid of printer status cards. **Card Layout (each printer):** ``` ┌─────────────────────────────┐ │ [Status Dot] Printer Name │ ← Header row │─────────────────────────────│ │ Current Job: Benchy #3 │ ← Job name or "Idle" │ [████████░░] 72% │ ← Progress bar + percentage │ Filament: PLA Silk │ ← Active material │ Remaining: ~142g │ ← Spool remaining │ ETA: 0h 23m │ ← Time remaining │─────────────────────────────│ │ [View Detail →] │ ← Tap target / CTA └─────────────────────────────┘ ``` **Status Dot Colors:** - 🟢 Green (`#4ADE70` kiosk / `#16A34A` light) — Printing / Active - 🟡 Yellow (`#FACC15` kiosk / `#CA8A04` light) — Paused - 🔴 Red (`#F87171` kiosk / `#DC2626` light) — Error / Failed - ⚪ Gray (`#64748B`) — Idle / Offline **Grid Behavior:** - Kiosk (800×480 Pi 5): 2 columns, 3–4 rows (scrollable) - Tablet (768px+): 3 columns - Mobile (< 480px): 1 column, list view **Card Dimensions:** - Kiosk: Full-width within column, min-height 180px - Mobile: Full-width, min-height 140px, slightly denser **Important States:** - **Printing (active):** Progress bar animates, card has subtle left-border accent in green - **Paused:** Yellow left border, progress bar frozen, "PAUSED" badge overlaid - **Error:** Red left border, card background shifts to `error-container` token, error message shown - **Idle:** Gray left border, dimmed progress area, "Ready" label - **Offline:** Fully dimmed card, "OFFLINE" badge, no real-time data #### D. Filament Stock Snapshot A compact section showing inventory health: **Layout:** Horizontal scrolling row of small cards or a mini-list ``` ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ PLA │ │ PETG │ │ TPU │ │ ████████░░ 80% │ │ ████░░░░░ 40% │ │ ██░░░░░░░ 20% │ │ 23 spools │ │ 8 spools │ │ 3 spools ⚠️ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ ``` - Each card shows: Material base name, stock percentage bar, spool count - Cards with < 25% stock get a `⚠️` warning indicator and yellow-tinted background - **Kiosk:** 2–3 cards visible, swipe to see more - **Mobile:** Horizontal scroll carousel - **Tap:** Navigates to Spools tab filtered by that material #### E. Recent Activity Feed The last 5 print events in a compact list: ``` ┌────────────────────────────────────────────────────┐ │ ✓ Benchy #3 · PLA Silk · 23g · 0h45m │ │ ✓ Gear Set v2 · PETG Basic · 87g · 2h12m │ │ ✗ Phone Case · TPU Basic · — · Failed │ │ ✓ Calibration · PLA Basic · 4g · 0h05m │ │ ✓ Bracket x4 · ASA Matte · 156g · 4h30m │ └────────────────────────────────────────────────────┘ ``` - Each row: Status icon, job name, material, weight used, duration - Failed prints show `✗` in red with "Failed" label - **Kiosk:** Larger text, comfortable row height (56px) - **Mobile:** Standard list density (48px rows) - **Tap a row:** Navigates to that print's detail view - **"View All" link:** At bottom, navigates to Prints tab ### Primary CTA **Floating Action Button (FAB):** "Quick Scan" — a prominent FAB in the bottom-right corner with a `qr_code_scanner` icon. This triggers the barcode/USB scanner workflow for spool check-in/check-out. - Kiosk: Extended FAB with label "Scan" + icon, 56×56px minimum - Mobile: Standard FAB, icon only, 56×56px - Positioned above the bottom nav, with 16px margin from edges ### Secondary Actions - Tap any printer card → Printer Detail - Tap any stock card → Spools filtered - Tap any activity row → Print detail - Tap error/low badges in summary bar → Filtered navigation ### Key Components (MD3) | Component | Usage | Notes | |---|---|---| | Bottom Navigation | Primary nav | 5 destinations | | Top App Bar (Medium) | App header | Logo + status + clock | | Cards (Elevated) | Printer status | Real-time content | | Cards (Filled/outlined) | Filament stock | Compact, scrollable | | List | Activity feed | 3-line items | | FAB (Extended/Regular) | Quick Scan | Always accessible | | Badge | Nav tabs, status | Error count, low stock | | Linear Progress Indicator | Print progress | On printer cards | | Chip | Status summary | Compact metrics | ### Important States | State | Visual Treatment | |---|---| | Loading (initial) | Skeleton screens for printer cards, shimmer animation | | SignalR disconnected | Red dot in app bar, banner: "Live updates paused — reconnecting..." | | No printers registered | Empty state illustration + "Add your first printer" CTA | | No spools registered | Stock section shows "No inventory — add spools to start tracking" | | All printers idle | Fleet grid shows all gray cards, summary bar shows "0 active" | | Critical error (printer) | Card pulses red border once, then steady red left border | --- ## 4. UX Rationale ### Why This Layout Supports the Task 1. **Fleet health at a glance:** The Status Summary Bar + Printer Fleet Grid are visible immediately on load. No scrolling required on kiosk to see if something is wrong. Color-coded status dots and left-border accents make the visual scan instantaneous. 2. **Progressive detail:** The homepage gives you "enough" — status, progress, material. You only tap into a printer card when you need details (temps, G-code, history). This avoids information overload while keeping critical data surface-level. 3. **Inventory awareness without navigation:** The Filament Stock Snapshot means operators don't need to leave the homepage to know if they're running low. The warning state (yellow + ⚠️) is visible without interpreting numbers. 4. **Activity context:** The Recent Activity Feed gives "what just happened" situational awareness — useful when returning to the kiosk after being away. It answers "did that print finish?" without requiring navigation. 5. **Scan-first workflow:** The FAB for Quick Scan is always accessible from the homepage, which is the most common action for spool check-in during workshop operations. Placed bottom-right — the natural resting thumb zone. ### Hierarchy (What matters most → least) 1. **Printer errors** (red, draws the eye immediately) 2. **Active printers with progress** (green accent, animated progress bars) 3. **Paused printers** (yellow accent, needs attention) 4. **Low filament warnings** (yellow indicators in stock section) 5. **Idle printers** (gray, calm, no action needed) 6. **Recent activity** (informational, below the fold on mobile) ### Tradeoffs | Decision | Benefit | Cost | Mitigation | |---|---|---|---| | Bottom nav over side nav | Touch-friendly, MD3 standard, always visible | Takes screen space at bottom | Acceptable on touch-first device | | Cards over table | Glanceable, status-colorable, touch-friendly | Less dense (can't see 7 printers at once) | Grid layout maximizes visible count; scroll for 6+ printers | | Summary bar metrics | Fleet health without scrolling | Adds cognitive load if too many metrics | Keep to 4 max, hide zero-value metrics | | Horizontal scroll for stock cards | Saves vertical space, works well for 3–6 materials | Hidden cards require swipe | First 3 most-used materials visible; swipe for rest | | FAB for scan | Always accessible, one-tap | Covers content behind it | Standard FAB behavior; scrolls away on mobile | | No sidebar on kiosk | Maximizes kiosk screen real estate | No persistent deep-nav | Bottom nav is sufficient for 5 top-level destinations | --- ## 5. Visual Direction ### Tone **Modern Industrial/Maker** — Dark mode by default on kiosk. Professional workshop vibe. High contrast. Think: a CNC control panel, not a social media app. The aesthetic should feel like a tool you trust, not an app you browse. ### Dark Mode Palette (Kiosk Default) | Token | Value | Usage | |---|---|---| | `md.sys.color.background` | `#0F172A` | Page background | | `md.sys.color.surface` | `#1E293B` | Card backgrounds, nav bar | | `md.sys.color.surface-container` | `#334155` | Elevated cards, containers | | `md.sys.color.surface-container-high` | `#475569` | Hover/pressed states | | `md.sys.color.primary` | `#60A5FA` | Primary actions, links, active tab | | `md.sys.color.on-primary` | `#0F172A` | Text on primary | | `md.sys.color.primary-container` | `#1E3A5F` | Subtle primary tinted containers | | `md.sys.color.error` | `#F87171` | Error states, failed prints | | `md.sys.color.error-container` | `#450A0A` | Error card backgrounds | | `md.sys.color.on-error` | `#FFFFFF` | Text on error | | `md.sys.color.on-surface` | `#F1F5F9` | Primary text | | `md.sys.color.on-surface-variant` | `#94A3B8` | Secondary text | | `md.sys.color.outline` | `#334155` | Borders, dividers | | `md.sys.color.outline-variant` | `#1E293B` | Subtle borders | ### Light Mode Palette (Dashboard/Future) | Token | Value | Usage | |---|---|---| | `md.sys.color.background` | `#F8FAFC` | Page background | | `md.sys.color.surface` | `#FFFFFF` | Card backgrounds | | `md.sys.color.primary` | `#2563EB` | Primary actions | | `md.sys.color.on-surface` | `#0F172A` | Primary text | | `md.sys.color.on-surface-variant` | `#475569` | Secondary text | ### Typography | Role | Font | Weight | Size (Kiosk) | Size (Mobile) | |---|---|---|---|---| | App Title | Inter | Bold | 22px | 20px | | Card Title (Printer Name) | Inter | SemiBold | 20px | 18px | | Section Heading | Inter | SemiBold | 18px | 16px | | Body Text | Inter | Regular | 18px | 16px | | Metric Value | Inter | Bold | 28px | 24px | | Metric Label | Inter | Medium | 14px | 12px | | Mono Values (weight, time, %) | JetBrains Mono | Medium | 18px | 16px | | Caption / Timestamp | Inter | Regular | 14px | 12px | **Rationale for oversized metrics:** The kiosk is viewed at arm's length or further. A 28px bold metric is legible from 3–4 feet away. Monospace for numeric values ensures columns align and feels "instrument-like." ### Spacing / Density | Token | Kiosk | Mobile | |---|---|---| | Page padding | 24px | 16px | | Card padding | 20px | 16px | | Grid gap | 16px | 12px | | Section gap | 32px | 24px | | Row height (lists) | 56px | 48px | | FAB margin from edge | 16px | 16px | | Touch target minimum | 48px | 44px | ### Component Behavior - **Printer cards:** Update in real-time via SignalR. Progress bar animates smoothly (CSS transition 300ms). Status changes trigger a brief highlight flash (200ms background shift) to draw attention. - **Bottom nav:** Active tab has `primary` color icon + label. Inactive tabs use `on-surface-variant`. Badges are small circles positioned at the icon's top-right. - **FAB:** Elevated with shadow-3. On tap, ripple effect. Extended label appears on kiosk (wider screen), icon-only on mobile. - **Status summary bar:** Metric chips are non-scrolling on kiosk (fits in one row at 800px width), horizontally scrolling on mobile if needed. - **Activity feed:** List items have subtle divider lines (`outline-variant`). Failed items have `error-container` background tint. - **Skeleton loading:** Cards show shimmer placeholder during initial load (1.5s max before content appears). ### Color Usage Guidelines 1. **Color is information, not decoration.** Every colored element must communicate state. 2. **Red = immediate attention.** Only use for errors, failures, disconnections. Never for decoration. 3. **Yellow = needs attention soon.** Paused printers, low filament, warnings. 4. **Green = operating normally.** Active printing, completed, connected. 5. **Blue = interactive.** Links, buttons, active navigation, primary CTAs. 6. **Gray = neutral/idle.** Offline printers, inactive states, secondary info. 7. **Never use color alone to convey meaning.** Always pair with icon + text label (accessibility). --- ## 6. Responsiveness ### Breakpoints | Breakpoint | Width | Layout | |---|---|---| | Kiosk | 480–800px (Pi 5 typical: 800×480) | 2-col grid, bottom nav, extended FAB | | Mobile (compact) | < 480px | 1-col list, bottom nav, standard FAB | | Tablet | 768–1024px | 3-col grid, bottom nav, extended FAB | | Desktop | 1024px+ | 3-col grid, nav rail, extended FAB | ### Layout Changes by Device #### Pi 5 Kiosk (800×480, Landscape) - **Top app bar:** 64px height, clock always visible - **Status summary:** 4 metrics in a single row (fits 800px) - **Printer grid:** 2 columns × N rows, scrollable vertically - **Stock snapshot:** 3 cards visible, no scroll needed (most common materials first) - **Activity feed:** 3 rows visible, "View All" link - **Bottom nav:** Full 5 tabs - **FAB:** Extended with "Scan" label #### Mobile PWA (< 480px, Portrait) - **Top app bar:** 56px height, no clock (use phone clock) - **Status summary:** 2–3 metrics visible, horizontal scroll for more - **Printer grid:** 1 column list view (cards become horizontal list items) - **Stock snapshot:** Horizontal carousel, 2 cards visible - **Activity feed:** 3–5 rows, compact density - **Bottom nav:** 5 tabs (may collapse labels on very narrow screens) - **FAB:** Icon only, standard 56px #### Tablet / Desktop Browser - **Bottom nav → Navigation Rail** (left side, 80px wide) - **Printer grid:** 3 columns - **Stock snapshot:** 4–5 cards visible in row - **Activity feed:** 5 rows - **Additional whitespace** — dashboard mode can breathe more ### Kiosk-Specific Considerations - **No hover states** — all interactions are tap/click only - **No tooltips** — information must be visible inline - **Larger touch targets** — 48px minimum (4px above MD3 default) - **No right-click context menus** — all actions are explicit buttons/links - **Screen wake** — kiosk should not sleep; CSS `animation` on a subtle element to prevent screen burn-in (shift a 1px element every 60s) - **Overshoot scroll** — prevent pull-to-refresh or browser gestures (PWA `overscroll-behavior: none`) --- ## 7. Developer Handoff Notes ### Reusable Components to Build | Component | Type | Props/Inputs | Notes | |---|---|---|---| | `` | Standalone | `printer: Printer`, `status: PrinterStatus`, `job?: PrintJob` | Left-border color computed from status. SignalR drives re-renders. | | `` | Atom | `status: 'active' \| 'paused' \| 'error' \| 'idle' \| 'offline'` | Small colored circle (12px) with aria-label for accessibility | | `` | Atom | `label: string`, `value: string \| number`, `variant: 'default' \| 'error' \| 'warning'` | Used in Status Summary Bar | | `` | Standalone | `material: string`, `percentage: number`, `spoolCount: number`, `lowStock: boolean` | Horizontal scroll child | | `` | List Item | `job: PrintEvent` | 3-line list item with status icon | | `` | Atom | `value: number`, `status: PrinterStatus` | MD3 linear progress, color matches status | | `` | Composite | `printers: Printer[]`, `spools: Spool[]` | Renders metric chips row | | `` | Atom | `connected: boolean` | Green/red dot in app bar | ### Angular Material Components Used - `MatBottomNavigation` (or custom bottom nav — MD3 bottom nav is not yet in Angular Material; implement with `MatTabNav` + custom styling) - `MatCard` → Styled with custom dark tokens - `MatProgressBar` → Custom color per status - `MatFabButton` / `MatMiniFabButton` - `MatBadge` → For nav tab badges - `MatList` → Activity feed - `MatChip` → Status summary metrics - `MatIcon` → Material Symbols throughout - `MatToolbar` → Top app bar ### Interaction Notes 1. **SignalR subscriptions:** The homepage must subscribe to `PrinterHub` on mount. Each printer card re-renders on status/progress push events. Unsubscribe on navigate-away. 2. **Optimistic updates:** Progress bars should animate smoothly — use CSS transitions, not discrete jumps. If SignalR sends a progress update every 5s, interpolate between values. 3. **FAB scan action:** On tap, immediately focus a hidden text input that captures USB HID barcode scanner output ( scanners type characters + Enter). This is a capture-only input — no keyboard should appear on mobile. Use `` or intercept `keydown` globally. 4. **Pull-to-refresh:** Disabled on kiosk. On mobile PWA, consider enabling for manual data refresh. 5. **Navigation:** Use Angular Router with bottom nav tabs bound to routerLinkActive. Highlight active tab. Preserve scroll position when returning to Hub. 6. **Skeleton screens:** On initial load, show 6 skeleton printer cards (matching grid layout). Use `@angular/material` skeleton patterns or custom shimmer CSS. ### Accessibility | Requirement | Implementation | |---|---| | Screen reader | All status indicators have `aria-label` (e.g., "Printer Elegoo-1: Printing, 72% complete") | | Color blindness | Never color-only — always icon + text + color. Status dots have aria-labels | | Keyboard nav | Tab order: top bar → summary metrics → printer cards (grid order) → stock → activity → FAB → bottom nav | | Focus management | After navigation, focus lands on the page title. After FAB tap, focus returns to FAB | | Touch target | 48px minimum on kiosk, 44px minimum on mobile — all interactive elements | | Contrast | All text on dark background meets WCAG AA (4.5:1 for body, 3:1 for large text) | | Motion | Respect `prefers-reduced-motion` — disable progress bar animation and shimmer if set | | Live regions | Printer status changes announced via `aria-live="polite"` on the card region | ### Performance Notes - **OnPush change detection** for all components receiving SignalR data - **TrackBy** on printer grid `*ngFor` to avoid re-rendering unchanged cards - **Virtual scrolling** for activity feed if it grows beyond 20 items (use `@angular/cdk ScrollingModule`) - **Lazy load** Spools, Prints, Materials, Settings tabs — only Hub is eager-loaded - **Image optimization:** Use inline SVG for status icons, not raster images. Logo should be SVG. ### File Structure Suggestion ``` src/app/ ├── pages/ │ └── hub/ │ ├── hub.component.ts │ ├── hub.component.html │ ├── hub.component.scss │ └── hub.component.spec.ts ├── components/ │ ├── printer-card/ │ ├── status-dot/ │ ├── metric-chip/ │ ├── stock-card/ │ ├── activity-item/ │ ├── progress-bar/ │ ├── fleet-summary/ │ └── connection-indicator/ ├── layout/ │ ├── bottom-nav/ │ ├── top-app-bar/ │ └── nav-rail/ └── shared/ └── tokens/ └── _extrudex-tokens.scss ``` --- ## Appendix: Navigation Map ``` ┌──────────────────────────────────────────────────────────────┐ │ EXTRUDEX │ │ │ │ ┌─ Hub (Home) ──────────────────────────────────────────┐ │ │ │ • Fleet Status Grid │ │ │ │ • Filament Snapshot │ │ │ │ • Recent Activity │ │ │ │ • [FAB: Quick Scan] │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ ┌─ Printers ────────┐ ┌─ Spools ─────────────────────┐ │ │ │ Printer List │ │ Spool Inventory │ │ │ │ → Printer Detail │ │ → Spool Detail │ │ │ │ → Job History │ │ → Check-in/Check-out │ │ │ │ → Controls │ │ → Link to Printer │ │ │ └────────────────────┘ └─────────────────────────────┘ │ │ │ │ ┌─ Prints ──────────┐ ┌─ Settings ───────────────────┐ │ │ │ Print Job List │ │ System Configuration │ │ │ │ → Print Detail │ │ Printer Management │ │ │ │ → COGS Report │ │ User Preferences │ │ │ └────────────────────┘ └──────────────────────────────┘ │ │ │ │ ══════════════════════════════════════════════════════════ │ │ [Hub] [Printers] [Spools] [Prints] [Settings] │ │ ══════════════════════════════════════════════════════════ │ └──────────────────────────────────────────────────────────────┘ ``` --- *End of Specification — Ready for Stuart (mockup generation) and Rex (implementation handoff)*