# Filament Inventory List — Screen Specification

> **Screen ID:** FIL-001  
> **Source of Truth:** [Material Design 3](https://m3.material.io/)  
> **Tone:** Modern Industrial/Maker  
> **Theme:** Dark Mode, High-Contrast  
> **Last Updated:** 2026-04-20

---

## 1. Objective

Provide a single, scannable view of all filament spools in inventory. Users (shop operators) must be able to:

- Rapidly assess stock levels at a glance (which spools are low/critical).
- Search by material type, brand, color, or internal tracking ID.
- Filter by status (Available, In Use, Low Stock, Depleted).
- Navigate to spool detail or initiate the Smart Intake workflow.

This is the **primary landing screen** for both the kiosk and the mobile PWA.

---

## 2. Screen Inventory

| Element | MD3 Component | Notes |
|---------|--------------|-------|
| Top App Bar | `md-top-app-bar` (medium) | Title + search toggle + intake FAB |
| Search Bar | `md-search-bar` | Expandable on tap; collapses to icon on kiosk |
| Filter Chips | `md-chip-set` (filter) | Status filters: All / Available / In Use / Low / Depleted |
| Inventory List | `md-list` (3-line) | Spool cards as list items |
| Low-Stock Badge | `md-badge` | Tonal badge on list items |
| Extended FAB | `md-fab` (extended) | "Smart Intake" CTA |
| Navigation Rail | `md-navigation-rail` | Kiosk only — Inventory / Printers / Jobs / Settings |
| Bottom Navigation | `md-navigation-bar` | Mobile only — same destinations |
| Empty State | Illustration + `md-text-button` | When no spools match filter |

---

## 3. Layout Specification

### Title
**"Filament Inventory"** — displayed in the Top App Bar headline slot.

### Sections

#### A. Top App Bar (56dp mobile / 64dp kiosk)
- **Leading:** Menu icon (kiosk) / Back arrow (mobile, if deep-linked)
- **Title:** "Filament Inventory"
- **Trailing actions:** Search icon (toggles search bar), Overflow menu (Sort by, Export)

#### B. Search Bar (0dp collapsed → 56dp expanded)
- Triggered by search icon tap or pull-down gesture on mobile
- Placeholder: "Search spools, brands, colors…"
- Auto-focus on expand; dismiss on back/clear
- Real-time filtering as user types

#### C. Filter Chip Row (52dp height, horizontal scroll)
- Chips: `All` | `Available` | `In Use` | `Low Stock` | `Depleted`
- Default selection: `All`
- Multi-select disabled — single filter active at a time
- Chip styling: Tonal variants per status color
  - Available: `green` tonal
  - In Use: `blue` tonal (primary)
  - Low Stock: `yellow` tonal (warning)
  - Depleted: `red` tonal (error)

#### D. Inventory List (flex, scrollable)
- Each item is a **3-line list item** with leading/trailing elements:

```
┌──────────────────────────────────────────────────┐
│ [Color Swatch]  PLA Basic - Matte Black           │
│                Bambu Lab • Slot A3 • 842g left    │
│                ▓▓▓▓▓▓▓▓▓▓░░  67%  [Low] badge   │
├──────────────────────────────────────────────────┤
│ [Color Swatch]  PETG Basic - Transparent          │
│                Polymaker • Shelf B2 • 210g left   │
│                ▓▓▓░░░░░░░░░  21%  [Critical] ⚠  │
└──────────────────────────────────────────────────┘
```

- **Leading:** Circular color swatch (40dp) — matches filament color
- **Line 1:** Material name (MaterialBase + Finish + Modifier) — `titleMedium`, `onSurface`
- **Line 2:** Brand • Location • Remaining weight — `bodyMedium`, `onSurfaceVariant`
- **Line 3:** Linear progress indicator + percentage text — `labelSmall`, `onSurfaceVariant`
- **Trailing:** Status badge (tonal chip) + chevron icon
- **Divider:** Full-width between items

**Sort order (default):** Low stock first, then alphabetical by material name.

#### E. Extended FAB (Bottom-end, mobile; Bottom-end, kiosk)
- Label: **"Smart Intake"** + `qr_code_scanner` icon
- Container: `primaryContainer` color
- On tap → navigates to Smart Intake Scan State

#### F. Navigation (Screen-level)
- **Kiosk:** Navigation Rail on leading edge (80dp wide)
  - Destinations: Inventory (active), Printers, Jobs, Settings
- **Mobile:** Bottom Navigation Bar (80dp height)
  - Same destinations

### Primary CTA
**Smart Intake** (Extended FAB) — always visible, anchored bottom-end.

### Secondary Actions
- Tap list item → Spool Detail View
- Overflow → Sort options (Name A-Z, Name Z-A, Weight Low→High, Weight High→Low, Recently Used)
- Overflow → Export inventory (CSV)

### Key Components
- Search bar with real-time filtering
- Filter chip set (single-select)
- 3-line list items with progress indicators
- Color swatch leading element
- Status tonal badges
- Extended FAB

### States
| State | Visual |
|-------|--------|
| **Loading** | `md-circular-progress` centered, list skeleton (shimmer) |
| **Empty (no spools)** | Spool icon illustration + "No spools in inventory" + "Add your first spool" text button |
| **Empty (no filter matches)** | "No spools match your filter" + Clear filter chip button |
| **Error** | Error illustration + "Couldn't load inventory" + Retry button |
| **Low Stock item** | Yellow tonal badge "Low" + progress bar < 25% yellow |
| **Critical item** | Red tonal badge "Critical" + progress bar < 10% red + pulsing dot |
| **Depleted item** | Red tonal badge "Depleted" + progress bar 0% + strikethrough title |

---

## 4. UX Rationale

1. **Progress bars beat numbers alone.** A visual progress indicator communicates remaining spool life faster than parsing "210g / 1000g" — critical in a busy workshop where decisions are made in seconds.

2. **Low stock first (default sort).** Operators need to see what's running out before what's plentiful. This prevents the "surprise empty spool" problem mid-print.

3. **Color swatches as leading elements.** Filament identification is primarily visual — operators scan for color before reading text. The swatch leverages pre-attentive processing.

4. **Single-select filters over multi-select.** Workshop operators don't construct complex queries. They want one quick filter tap. Multi-select adds cognitive load for minimal practical benefit.

5. **Smart Intake FAB, not a menu item.** Intake is the most frequent action (new spools arrive regularly). It deserves the highest-affordance control on screen — a FAB is unmissable.

6. **Search collapses by default.** On kiosk, screen space is precious. The search icon expands the bar only when needed, preserving vertical list space.

7. **Empty states with action.** An empty inventory list should immediately offer the path forward — "Add your first spool" links directly to Smart Intake.

---

## 5. Visual Direction

### Typography (MD3 Type Scale)

| Role | Token | Size | Weight | Line Height |
|------|-------|------|--------|-------------|
| App Bar Title | `titleLarge` | 22sp | 400 | 28sp |
| List Item Line 1 | `titleMedium` | 16sp | 500 | 24sp |
| List Item Line 2 | `bodyMedium` | 14sp | 400 | 20sp |
| List Item Line 3 | `labelSmall` | 11sp | 500 | 16sp |
| Filter Chip Text | `labelLarge` | 14sp | 500 | 20sp |
| FAB Label | `labelLarge` | 14sp | 500 | 20sp |
| Empty State Title | `headlineSmall` | 24sp | 400 | 32sp |
| Empty State Body | `bodyMedium` | 14sp | 400 | 20sp |

### Spacing (MD3 8dp grid)

| Element | Spacing |
|---------|---------|
| App Bar internal padding | 16dp horizontal, 12dp vertical |
| Filter chip row padding | 16dp horizontal, 8dp vertical |
| Chip gap | 8dp |
| List item padding | 16dp horizontal, 12dp vertical (top/bottom of 3-line) |
| List item internal gap | 16dp (leading to content), 16dp (content to trailing) |
| FAB margin | 16dp from edges |
| Content area padding | 0dp (list is edge-to-edge with dividers) |

### Color (MD3 Dark Theme — "Industrial Maker")

Based on a **blue-grey** primary seed for the industrial feel, with **teal** as secondary (maker accent).

| Role | Token | Value (Dark) | Usage |
|------|-------|-------------|-------|
| Background | `surface` | `#1C1B1F` | Screen background |
| On Background | `onSurface` | `#E6E1E5` | Primary text |
| Surface Variant | `surfaceContainer` | `#211F26` | App bar, list items |
| On Surface Variant | `onSurfaceVariant` | `#CAC4D0` | Secondary text, chip outlines |
| Primary | `primary` | `#A8CEDA` | FAB container, active states |
| On Primary | `onPrimary` | `#00303E` | FAB label text |
| Primary Container | `primaryContainer` | `#004D63` | FAB container (tonal), active chip fill |
| On Primary Container | `onPrimaryContainer` | `#A8CEDA` | Active chip text |
| Secondary | `secondary` | `#B1CCC7` | Navigation rail active icon |
| Tertiary | `tertiary` | `#EFB8C8` | Accent (not used here) |
| Error | `error` | `#F2B8B5` | Depleted badge, critical states |
| Error Container | `errorContainer` | `#8C1D18` | Critical badge background |
| On Error Container | `onErrorContainer` | `#F2B8B5` | Critical badge text |
| **Custom: Warning** | — | `#FFD580` | Low stock indicator |
| **Custom: Warning Container** | — | `#5D4200` | Low stock badge background |
| **Custom: Success** | — | `#8BD0A0` | Available badge text |
| **Custom: Success Container** | — | `#00522E` | Available badge background |
| Outline | `outline` | `#938F99` | Dividers, chip outlines |
| Outline Variant | `outlineVariant` | `#49454F` | Subtle borders |

### Color Swatches
Spool color swatches use the actual filament color as a circular filled element (40dp diameter) with a 2dp `outlineVariant` border for visibility on dark backgrounds. For transparent/clear filaments, use a diagonal hatch pattern fill.

---

## 6. Responsiveness

### Kiosk (800×480, Raspberry Pi 5 Touchscreen)

```
┌──────┬──────────────────────────────────────────────┐
│ NAV  │  Filament Inventory          [🔍] [⋮]       │
│ RAIL │──────────────────────────────────────────────│
│      │  [All] [Available] [In Use] [Low] [Depleted] │
│ 📦   │──────────────────────────────────────────────│
│ 🖨️   │  ● PLA Basic - Matte Black                   │
│ 📋   │    Bambu Lab • Slot A3 • 842g                │
│ ⚙️   │    ▓▓▓▓▓▓▓▓▓▓░░  67%               [Low]    │
│      │──────────────────────────────────────────────│
│      │  ● PETG Basic - Transparent                  │
│      │    Polymaker • Shelf B2 • 210g               │
│      │    ▓▓▓░░░░░░░░░  21%             [Critical]  │
│      │──────────────────────────────────────────────│
│      │  ● ABS Basic - White                         │
│      │    eSUN • Slot B1 • 950g                     │
│      │    ▓▓▓▓▓▓▓▓▓▓▓▓  95%           [Available]  │
│      │                                  [+ Smart   │
│      │                                   Intake] ↗  │
└──────┴──────────────────────────────────────────────┘
```

- **Navigation Rail:** 80dp wide, pinned left
- **List area:** 720dp × 420dp usable
- **Visible items:** ~4-5 spools without scrolling
- **Touch targets:** All interactive elements ≥ 48dp (exceeds 44dp minimum for workshop glove use)
- **FAB:** Bottom-right, 16dp margin from rail and screen edge

### Mobile PWA (375×812, e.g., iPhone 14)

```
┌──────────────────────────────────┐
│  Filament Inventory    [🔍] [⋮]  │
│──────────────────────────────────│
│  [All] [Avail] [In Use] [Low] [×]│
│──────────────────────────────────│
│  ● PLA Basic - Matte Black       │
│    Bambu Lab • Slot A3 • 842g    │
│    ▓▓▓▓▓▓▓▓▓▓░░  67%    [Low]   │
│──────────────────────────────────│
│  ● PETG Basic - Transparent      │
│    Polymaker • Shelf B2 • 210g   │
│    ▓▓▓░░░░░░░░░  21%  [Critical] │
│──────────────────────────────────│
│  ● ABS Basic - White             │
│    eSUN • Slot B1 • 950g         │
│    ▓▓▓▓▓▓▓▓▓▓▓▓  95%  [Avail]   │
│──────────────────────────────────│
│                                  │
│              [+ Smart Intake] ↗  │
│──────────────────────────────────│
│  📦     🖨️     📋     ⚙️         │
│ Inventory Printers Jobs Settings │
└──────────────────────────────────┘
```

- **Bottom Navigation:** 80dp, pinned bottom
- **List area:** 375dp × ~600dp usable
- **Visible items:** ~5-6 spools without scrolling
- **FAB:** Floating above bottom nav, right-aligned
- **Filter chips:** Horizontally scrollable when more than screen width

### Key Adaptations
| Property | Kiosk (800×480) | Mobile (375×812) |
|----------|-----------------|-------------------|
| Navigation | Rail (left) | Bottom bar |
| Search | Collapsed icon by default | Same, but swipe-down gesture also expands |
| List item density | Comfortable (3-line, 72dp) | Same density |
| FAB position | Bottom-right, above list | Bottom-right, above nav bar |
| Filter chips | All visible at once | Horizontally scrollable |
| Sort access | Overflow menu | Overflow menu |

---

## 7. Developer Handoff Notes

### Angular Material Components

| UI Element | Angular Material Component | Notes |
|-----------|--------------------------|-------|
| Top App Bar | `<mat-toolbar>` | Use `@angular/material/toolbar`. Medium emphasis variant. |
| Search | Custom wrapper + `<input matInput>` | No native mat-search-bar in Angular Material; implement custom expandable search with `@ViewChild` animation. |
| Filter Chips | `<mat-chip-listbox>` | Use `mat-chip-option` with `selected` binding. Single-select: deselect others on select. |
| List Items | `<mat-list>` + `<mat-list-item>` | 3-line variant with `matListItemTitle`, `matListItemLine`, `matListItemMeta`. |
| Progress Bar | `<mat-progress-bar>` | Use `mode="determinate"` with `[value]` binding. Custom color classes for warning/error thresholds. |
| Badge | `<mat-badge>` | Overlay on list items. Use `matBadgeColor` for status colors. |
| Extended FAB | `<button mat-fab extended>` | Use `@angular/material/button`. `extended` attribute for label. |
| Nav Rail | `<mat-sidenav>` styled as rail | No native nav-rail in Angular Material yet; implement as styled sidenav with icon buttons. |
| Bottom Nav | `<mat-bottom-nav>` or custom | Use `<nav mat-tab-nav-bar>` positioned at bottom as a workaround. |
| Empty State | Custom component | Illustration (SVG) + `<button mat-button>`. |
| Loading | `<mat-spinner>` | Use `mode="indeterminate"` centered in list area. |

### Interaction Notes

1. **Search expansion:** Animate height from 0→56dp with `@angular/animations` (`expandCollapse` trigger, 200ms ease-out).
2. **Filter chip selection:** Single-select logic in component — on chip click, set `selectedChip = chip.value`, deselect all others.
3. **List item tap → navigation:** Use `routerLink="/spools/:id"` on each `mat-list-item`.
4. **FAB → Smart Intake:** Navigates to `/intake/scan`.
5. **Progress bar color:** Dynamically set based on percentage:
   - ≥ 25%: `primary` (teal-blue)
   - 10-24%: Custom `warn-yellow` class
   - < 10%: `warn` (red)
6. **Skeleton loading:** Use `@angular/material` skeleton pattern or custom shimmer CSS animation on list items during initial load.
7. **Pull-to-refresh (mobile):** Implement with Angular CDK `@cdk/drag-drop` or a custom gesture handler to refresh inventory data.
8. **Infinite scroll / pagination:** Load 20 spools initially, load more on scroll-to-bottom.

### Accessibility

| Requirement | Implementation |
|-------------|---------------|
| Screen reader | Each list item: `aria-label="PLA Basic Matte Black, Bambu Lab, Slot A3, 842 grams remaining, 67 percent, Low stock"` |
| Color swatch | `aria-label="Color: Matte Black"` + `role="img"` |
| Progress bar | `aria-valuenow`, `aria-valuemin="0"`, `aria-valuemax="100"`, `aria-label="Remaining filament: 67 percent"` |
| Filter chips | `role="listbox"`, each chip `role="option"` + `aria-selected` |
| Search | `role="search"`, `aria-label="Search filament inventory"` |
| FAB | `aria-label="Smart Intake: scan new spool"` |
| Keyboard nav | Tab through list items, Enter to select. Escape to dismiss search. |
| Focus management | On search expand, auto-focus input. On search collapse, return focus to search icon. |
| Motion reduction | Respect `prefers-reduced-motion` — disable shimmer, use opacity fade for loading. |
| Contrast | All text meets WCAG AA (4.5:1) against dark surface. Verified: `onSurface` (#E6E1E5) on `surface` (#1C1B1F) = 11.2:1 ✓ |

### SignalR Integration

- Subscribe to `SpoolUpdated` hub event on screen init.
- On event: update the corresponding list item in-place (no full refresh).
- On `SpoolAdded`: insert at sorted position with highlight animation (300ms `primaryContainer` background flash).
- On `SpoolDepleted`: move to Depleted filter group, show toast notification.

### Performance Notes

- Use `TrackByFunction` on `*ngFor` to prevent full list re-render on updates.
- Virtual scrolling via `<cdk-virtual-scroll-viewport>` if inventory exceeds 100 spools.
- Debounce search input at 300ms.