# Spool Detail View — Screen Specification

> **Screen ID:** FIL-002  
> **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

Present comprehensive, actionable information about a single filament spool. Users (shop operators) must be able to:

- View all spool metadata (material, brand, color, weight, location, dates).
- See real-time remaining weight with visual progress indicator.
- Manage QR code (view, reprint label).
- View consumption history / usage timeline.
- Perform quick actions: edit details, move location, mark depleted, initiate print.
- Navigate back to inventory or forward to related entities (printer, location).

This is the **drill-down screen** from the Filament Inventory List.

---

## 2. Screen Inventory

| Element | MD3 Component | Notes |
|---------|--------------|-------|
| Top App Bar | `md-top-app-bar` (small) | Back nav + title + actions |
| Hero Section | Custom card | Color swatch + material name + status badge |
| Progress Ring | `md-circular-progress` (determinate) | Circular remaining-weight indicator |
| Metrics Grid | CSS Grid in `md-card` | Key metrics in 2-col grid |
| QR Code Card | `md-card` (elevated) | QR display + reprint button |
| Location Section | `md-card` (outlined) | Current location + move action |
| Usage Timeline | `md-list` (2-line) | Recent consumption events |
| Action Row | `md-button` row | Primary + secondary actions |
| Snackbar | `md-snackbar` | Confirmation for destructive actions |
| Dialog | `md-dialog` | Move location, confirm depletion |

---

## 3. Layout Specification

### Title
**Spool detail name** — displayed in the Top App Bar headline slot (material short name, e.g., "PLA Basic — Matte Black").

### Sections

#### A. Top App Bar (64dp)
- **Leading:** Back arrow → returns to Inventory List
- **Title:** Material name (scrolls into collapsed bar on scroll)
- **Trailing actions:** Edit icon (pencil), More (overflow: Delete spool, Transfer data)

#### B. Hero Section (200dp mobile / 180dp kiosk)
A prominent visual header that establishes identity at a glance:

```
┌──────────────────────────────────────────────────┐
│                                                  │
│    ┌──────┐                                      │
│    │ COLOR│   PLA Basic — Matte Black            │
│    │SWATCH│   Bambu Lab                          │
│    │ 80dp │                                     │
│    └──────┘                       [Available]    │
│                                                  │
│         ◉  842g / 1000g                         │
│         67% remaining                            │
│                                                  │
└──────────────────────────────────────────────────┘
```

- **Left:** Large circular color swatch (80dp) with `outlineVariant` border
- **Right of swatch:**
  - Line 1: Full material name (`headlineMedium`) — MaterialBase + Finish + Modifier
  - Line 2: Brand name (`bodyLarge`, `onSurfaceVariant`)
- **Below swatch row:** Status badge (tonal chip, same as inventory)
- **Bottom:** Large circular progress indicator (96dp ring)
  - Track: `surfaceContainerHighest`
  - Indicator: Dynamic color (≥25% primary, 10-24% warning, <10% error)
  - Center text: Remaining weight + percentage (`headlineSmall`)

#### C. Metrics Grid (2-column)

```
┌────────────────────┬────────────────────┐
│  Total Weight      │  Remaining         │
│  1,000g            │  842g (67%)        │
├────────────────────┼────────────────────┤
│  Diameter          │  Density           │
│  1.75mm            │  1.24 g/cm³        │
├────────────────────┼────────────────────┤
│  Date Added        │  Last Used         │
│  Mar 12, 2026      │  Apr 18, 2026      │
└────────────────────┴────────────────────┘
```

- Each cell: Label (`labelMedium`, `onSurfaceVariant`) + Value (`titleMedium`, `onSurface`)
- Grid gap: 1dp `outlineVariant` lines between cells
- Container: `surfaceContainer` background, `rounded-xl` (16dp radius)
- Cell padding: 16dp

#### D. Location Card (Outlined, 72dp)

```
┌──────────────────────────────────────────────────┐
│  📍 AMS Unit 2, Slot A3                    [Move]│
│     Bambu Lab P1S — Left spool holder            │
└──────────────────────────────────────────────────┘
```

- **Leading:** Location pin icon
- **Line 1:** Location name (`titleSmall`, `onSurface`)
- **Line 2:** Printer/host description (`bodySmall`, `onSurfaceVariant`)
- **Trailing:** "Move" text button (`primary`) → opens Move Location dialog

#### E. QR Code Card (Elevated, 200dp × 200dp QR)

```
┌──────────────────────────────────────────────────┐
│              ┌──────────────┐                     │
│              │              │                     │
│              │   QR CODE    │                     │
│              │   (160dp)    │                     │
│              │              │                     │
│              └──────────────┘                     │
│         EXT-2026-PLA-0042                        │
│                                     [Reprint]   │
└──────────────────────────────────────────────────┘
```

- QR code: 160dp × 160dp, white on dark surface
- Below QR: Internal tracking ID in monospace (`labelMedium`, `onSurfaceVariant`)
- Trailing: "Reprint" text button → sends to Bluetooth thermal printer
- Card: `surfaceContainerHigh` background, elevation 1

#### F. Usage Timeline (Expandable section)

```
│  Recent Usage                                     │
│──────────────────────────────────────────────────│
│  📦 Print #1847 — Benchy v3        -32g   Apr 18│
│  📦 Print #1842 — Housing Cap      -18g   Apr 17│
│  📦 Print #1839 — Gear Test        -8g    Apr 16│
│  📦 Added to inventory            +1000g  Mar 12│
│                                                   │
│                           [View Full History →]  │
└───────────────────────────────────────────────────┘
```

- Each entry: 2-line list item
  - Line 1: Print name or event (`bodyMedium`, `onSurface`)
  - Line 2: Weight change + date (`bodySmall`, `onSurfaceVariant`)
- Negative weight: `error` color
- Positive weight: custom `success` color
- Trailing: "View Full History" link → separate screen (future)

#### G. Action Row (Sticky bottom, 64dp)

```
┌──────────────────────────────────────────────────┐
│  [Mark Depleted]     [Move Location]  [Print]    │
└──────────────────────────────────────────────────┘
```

- **Mark Depleted:** Outlined button, `error` color → confirmation dialog
- **Move Location:** Tonal button, `secondary` → Move Location dialog
- **Print:** Filled button, `primary` → Navigate to start print job (pre-select this spool)

On kiosk, these are larger touch targets (56dp height buttons).

### Primary CTA
**Print** (filled button) — the most likely next action after viewing spool details.

### Secondary Actions
- Edit (Top App Bar icon) → Edit spool details form
- Reprint label → Send QR to thermal printer
- Move Location → Dialog with location picker
- Mark Depleted → Confirmation dialog → status update
- Delete spool → Overflow menu → confirmation dialog

### Key Components
- Large circular color swatch
- Determinate circular progress indicator
- 2-column metrics grid
- QR code display card
- Location card with move action
- Usage timeline list
- Sticky bottom action row

### States
| State | Visual |
|-------|--------|
| **Loading** | `md-circular-progress` indeterminate centered, skeleton sections |
| **Available (normal)** | Primary color progress ring, "Available" badge |
| **In Use** | Primary color progress ring, "In Use" badge, pulsing dot |
| **Low Stock** | Warning (yellow) progress ring, "Low Stock" badge |
| **Critical** | Error (red) progress ring, "Critical" badge, pulsing dot |
| **Depleted** | Error (red) progress ring at 0%, "Depleted" badge, strikethrough weight, "Mark Depleted" button becomes "Reactivate" |
| **No Location** | Location card shows "Unassigned" + "Assign" button |
| **QR Missing** | QR card shows "No QR generated" + "Generate" button |
| **Move Dialog** | Bottom sheet (mobile) / Center dialog (kiosk) with location tree/grid selector |

---

## 4. UX Rationale

1. **Hero section for instant recognition.** When an operator scans a spool or taps into it, they need immediate visual confirmation: "Is this the spool I think it is?" The large color swatch + material name + brand answers this in <1 second.

2. **Circular progress over linear.** For a single spool, a circular progress ring is more impactful and glanceable than a linear bar. It works as a "fuel gauge" metaphor that operators intuitively understand.

3. **Metrics grid, not a list.** A 2-column grid presents data-dense information efficiently. Each metric is a quick scan without vertical scrolling. This is the "dashboard gauge" pattern adapted for a single entity.

4. **QR card always visible.** The QR code is the physical-digital bridge. Operators need to see it to verify labels match, and the reprint action is frequent (labels get damaged/lost on spools).

5. **Timeline for consumption context.** "How fast am I going through this spool?" The recent usage list answers this without requiring a separate analytics screen. It's contextual, not analytical.

6. **Sticky action row.** The three most common actions (deplete, move, print) should never be hidden by scroll. Pinning them ensures they're always one tap away.

7. **"Mark Depleted" is destructive but necessary.** It gets an outlined (not filled) style and requires a confirmation dialog to prevent accidental taps — but it's prominent because operators genuinely need this action often.

---

## 5. Visual Direction

### Typography (MD3 Type Scale)

| Role | Token | Size | Weight | Line Height |
|------|-------|------|--------|-------------|
| App Bar Title | `titleLarge` | 22sp | 400 | 28sp |
| Hero Material Name | `headlineMedium` | 28sp | 400 | 36sp |
| Hero Brand | `bodyLarge` | 16sp | 400 | 24sp |
| Progress Center Value | `headlineSmall` | 24sp | 400 | 32sp |
| Progress Center Sub | `labelMedium` | 12sp | 500 | 16sp |
| Metrics Label | `labelMedium` | 12sp | 500 | 16sp |
| Metrics Value | `titleMedium` | 16sp | 500 | 24sp |
| Card Title | `titleSmall` | 14sp | 500 | 20sp |
| Card Body | `bodyMedium` | 14sp | 400 | 20sp |
| Timeline Entry | `bodyMedium` | 14sp | 400 | 20sp |
| Timeline Detail | `bodySmall` | 12sp | 400 | 16sp |
| Action Button | `labelLarge` | 14sp | 500 | 20sp |
| Tracking ID | `labelMedium` (monospace) | 12sp | 500 | 16sp |

### Spacing (MD3 8dp grid)

| Element | Spacing |
|---------|---------|
| Hero section padding | 24dp horizontal, 20dp vertical |
| Swatch to text gap | 16dp |
| Hero to metrics gap | 16dp |
| Metrics grid cell padding | 16dp |
| Metrics grid gap (divider) | 1dp |
| Section gap (between cards) | 12dp |
| Card internal padding | 16dp |
| QR code padding | 24dp (centered) |
| Timeline item padding | 16dp horizontal, 12dp vertical |
| Action row padding | 16dp horizontal, 12dp vertical |
| Action button gap | 12dp |

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

Same base palette as FIL-001. Screen-specific additions:

| Role | Token | Value (Dark) | Usage |
|------|-------|-------------|-------|
| Hero Background | `surfaceContainerLow` | `#1D1B20` | Hero section fill |
| Metrics Background | `surfaceContainer` | `#211F26` | Grid card |
| QR Card Background | `surfaceContainerHigh` | `#2B2930` | Elevated card |
| Location Card Background | `surfaceContainer` | `#211F26` | Outlined card |
| Progress Track | `surfaceContainerHighest` | `#36343B` | Ring background track |
| Depleted Strikethrough | `error` | `#F2B8B5` | Weight text decoration |

### Circular Progress Colors (Dynamic)

| Threshold | Color Token | Visual |
|-----------|------------|--------|
| ≥ 25% | `primary` | `#A8CEDA` (teal-blue) |
| 10–24% | Custom `warning` | `#FFD580` (amber) |
| < 10% | `error` | `#F2B8B5` (red) |
| 0% (Depleted) | `error` | `#F2B8B5` + pulsing animation |

---

## 6. Responsiveness

### Kiosk (800×480)

```
┌──────┬──────────────────────────────────────────────┐
│ NAV  │  ← PLA Basic — Matte Black      [✏] [⋮]     │
│ RAIL │──────────────────────────────────────────────│
│      │  ┌──────┐                                    │
│      │  │SWATCH│  PLA Basic — Matte Black  [Avail]  │
│      │  │ 80dp │  Bambu Lab                        │
│      │  └──────┘                                    │
│      │        ◉  842g / 1000g  (67%)               │
│      │──────────────────────────────────────────────│
│      │  Total: 1000g │ Remaining: 842g │ Diam: 1.75│
│      │  Dens: 1.24   │ Added: Mar 12  │ Last: Apr18│
│      │──────────────────────────────────────────────│
│      │  📍 AMS Unit 2, Slot A3            [Move]   │
│      │──────────────────────────────────────────────│
│      │  [Depleted]  [Move Location]  [Print]        │
└──────┴──────────────────────────────────────────────┘
```

- **Horizontal layout advantage:** Metrics grid uses 3 columns on kiosk to fill width.
- **QR code and timeline:** Accessible via scroll or tab section below the fold.
- **Scrollable content area:** Hero + Metrics + Location fit above fold; QR + Timeline scroll into view.
- **Action row:** Sticky at bottom of scroll area, above Navigation Rail.

### Mobile PWA (375×812)

```
┌──────────────────────────────────┐
│  ← PLA Basic — Matte Black [✏]  │
│──────────────────────────────────│
│  ┌──────┐                        │
│  │SWATCH│  PLA Basic — Matte     │
│  │ 80dp │  Black         [Avail] │
│  └──────┘  Bambu Lab            │
│                                  │
│       ◉  842g / 1000g  (67%)    │
│──────────────────────────────────│
│  Total Weight    │  Remaining    │
│  1,000g          │  842g (67%)   │
│──────────────────────────────────│
│  Diameter        │  Density      │
│  1.75mm          │  1.24 g/cm³   │
│──────────────────────────────────│
│  Date Added      │  Last Used    │
│  Mar 12, 2026    │  Apr 18, 2026 │
│──────────────────────────────────│
│  📍 AMS Unit 2, Slot A3  [Move] │
│──────────────────────────────────│
│  ┌──────────┐                    │
│  │  QR CODE │                    │
│  │  160dp   │  EXT-2026-PLA-0042│
│  └──────────┘         [Reprint] │
│──────────────────────────────────│
│  Recent Usage                    │
│  Print #1847 — Benchy  -32g     │
│  Print #1842 — Housing  -18g    │
│  [View Full History →]          │
│──────────────────────────────────│
│  [Depleted]  [Move]  [Print]    │
│──────────────────────────────────│
│  📦     🖨️     📋     ⚙️         │
└──────────────────────────────────┘
```

- **Vertical scroll layout:** All sections stack vertically.
- **Metrics grid:** 2 columns on mobile (3 on kiosk).
- **Action row:** Sticky at bottom, above bottom navigation.
- **QR code:** Full-width card, scroll into view.

### Key Adaptations

| Property | Kiosk (800×480) | Mobile (375×812) |
|----------|-----------------|-------------------|
| Metrics columns | 3 (compact) | 2 (standard) |
| Hero section height | 180dp (compact) | 200dp (standard) |
| QR card position | Below fold, scroll | Below fold, scroll |
| Action row style | Larger buttons (56dp h) | Standard buttons (40dp h) |
| Timeline items visible | 2-3 | 3-4 |
| Move dialog | Center `mat-dialog` | Bottom sheet (`mat-bottom-sheet`) |

---

## 7. Developer Handoff Notes

### Angular Material Components

| UI Element | Angular Material Component | Notes |
|-----------|--------------------------|-------|
| Top App Bar | `<mat-toolbar>` | Collapsible title on scroll using `@angular/cdk/scrolling` |
| Color Swatch | Custom `div` | Circular, 80dp, `[style.backgroundColor]` binding |
| Circular Progress | `<mat-progress-spinner>` | `mode="determinate"`, `[value]` binding, custom color classes |
| Metrics Grid | CSS Grid inside `<mat-card>` | 2-col (mobile) / 3-col (kiosk) via CSS breakpoints |
| QR Code Card | `<mat-card>` elevated | Use `appearance="elevated"`. QR rendered via `qrcode` npm package or canvas |
| Location Card | `<mat-card>` outlined | Use `appearance="outlined"`. |
| Timeline | `<mat-list>` + `<mat-list-item>` | 2-line items with `matListItemIcon` for type icon |
| Action Buttons | `<button mat-button>` variants | Depleted: `mat-button` with `color="warn"`. Move: `mat-flat-button` with `color="accent"`. Print: `mat-raised-button` with `color="primary"` |
| Move Dialog | `<mat-dialog>` / `<mat-bottom-sheet>` | Responsive: dialog on kiosk, bottom sheet on mobile |
| Confirmation Dialog | `<mat-dialog>` | With `mat-dialog-actions`: Cancel + Confirm |
| Snackbar | `<mat-snack-bar>` | For success/error feedback on actions |

### Interaction Notes

1. **Collapsible title:** As user scrolls past hero, App Bar title animates from hidden to visible (standard M3 scroll behavior). Use `@angular/material` scroll dispatching.
2. **Progress ring animation:** On load, animate from 0 to actual value over 600ms with `ease-out`.
3. **QR code generation:** If `spool.qrCode` is null, show "Generate" button. On tap, call API to generate QR, then display.
4. **Reprint label:** Calls Bluetooth thermal printer service. Show snackbar: "Label sent to printer ✓" or "Printer not connected ✗".
5. **Move location dialog:** Show location tree (AMS units → slots, shelves). Selected location highlighted. Confirm → API call → snackbar confirmation.
6. **Mark Depleted:** Dialog: "Mark PLA Basic — Matte Black as depleted? This will update the spool's status and remove it from available inventory." Buttons: Cancel (text) / Mark Depleted (error filled).
7. **Delete spool:** Dialog: "Permanently delete PLA Basic — Matte Black? This cannot be undone." Buttons: Cancel (text) / Delete (error filled).
8. **Real-time updates:** Subscribe to `SpoolUpdated` SignalR event. If this spool's weight changes, animate the progress ring and update metrics in-place.

### Accessibility

| Requirement | Implementation |
|-------------|---------------|
| Screen reader (hero) | `aria-label="PLA Basic Matte Black by Bambu Lab, Available, 842 grams remaining of 1000 grams, 67 percent"` |
| Circular progress | `role="progressbar"`, `aria-valuenow="67"`, `aria-valuemin="0"`, `aria-valuemax="100"`, `aria-label="Remaining filament"` |
| Metrics grid | Semantic `<dl>` with `<dt>` (label) + `<dd>` (value), each with `aria-label` |
| QR code | `alt="QR code for spool EXT-2026-PLA-0042"`, `role="img"` |
| Color swatch | `aria-label="Filament color: Matte Black"`, `role="img"` |
| Action buttons | Clear `aria-label`: "Mark as depleted", "Move to new location", "Start print with this spool" |
| Confirmation dialogs | `aria-labelledby` for title, `aria-describedby` for description. Focus trap. Escape to close. |
| Keyboard nav | Tab order: Back → Edit → Overflow → Content sections → Action row. Enter to activate. |
| Focus on open | When navigating from inventory, focus lands on back button, then natural tab flow |

### SignalR Integration

- Subscribe to `SpoolUpdated` hub event, filter by current spool ID.
- On weight change: animate progress ring delta, update metrics, prepend usage timeline entry.
- On status change: update badge, adjust progress ring color, update action row buttons.
- On location change: update location card.

### Performance Notes

- Use `OnPush` change detection strategy for this component.
- QR code should be generated once and cached; don't regenerate on every change detection cycle.
- Usage timeline: load last 5 entries on init, lazy-load full history on "View Full History" tap.