41 KiB
Smart Intake Workflow — Screen Specification
Screen ID: FIL-003
Source of Truth: Material Design 3
Tone: Modern Industrial/Maker
Theme: Dark Mode, High-Contrast
Last Updated: 2026-04-20
1. Objective
Design the primary filament intake experience — the "Smart Intake" workflow — optimized for both the kiosk (USB barcode scanner + touchscreen) and the mobile PWA (device camera + touch). This is the most critical user flow in Extrudex: every new spool enters the system through this workflow.
The workflow follows a strict 3-state linear progression:
SCAN ──→ IDENTIFY ──→ UPDATE ──→ ✓ Complete
Users must be able to:
- Scan: Capture a barcode/QR code via camera (mobile) or USB scanner (kiosk).
- Identify: Confirm or correct the scanned spool's identity (material, brand, color).
- Update: Set initial weight and status, assign a location, and complete intake.
The workflow must feel fast, confident, and forgiving — operators process many spools in a session and can't afford friction or ambiguity at any step.
2. Screen Inventory
Shared Across All States
| Element | MD3 Component | Notes |
|---|---|---|
| Top App Bar | md-top-app-bar (small) |
Title + close/dismiss |
| Step Indicator | Custom linear stepper | 3 dots/steps with active state |
| Bottom Sheet | md-bottom-sheet |
Contextual info/errors on mobile |
Scan State (State 1 of 3)
| Element | MD3 Component | Notes |
|---|---|---|
| Camera Viewport | Custom + video element |
Full-bleed camera with scanning overlay |
| Viewport Frame | Custom overlay | Animated scanning rectangle |
| Scan Result Chip | md-chip (assist) |
Shows last scanned code |
| Manual Entry Link | md-text-button |
Fallback for unreadable codes |
| USB Scanner Badge | md-chip (status) |
Kiosk only — "Scanner Connected ✓" |
Identification State (State 2 of 3)
| Element | MD3 Component | Notes |
|---|---|---|
| Spool Identity Card | md-card (filled) |
Material, brand, color display |
| Confidence Indicator | Custom bar | Match confidence (High/Medium/Low/Unknown) |
| Material Selector | md-dropdown-select |
If multiple matches or no match |
| Brand Selector | md-dropdown-select |
Brand selection |
| Color Picker | Custom swatch grid | Filament color selection |
| Finish + Modifier | md-chip-set (choice) |
Material finish and modifier |
| "Confirm" Button | md-filled-button |
Primary CTA — proceed to Update |
| "Rescan" Button | md-outlined-button |
Go back to Scan state |
Update State (State 3 of 3)
| Element | MD3 Component | Notes |
|---|---|---|
| Weight Input | md-filled-text-field + stepper |
Grams input with +/- buttons |
| Location Selector | md-dropdown-select |
Assign to AMS slot or shelf |
| Status Toggle | md-chip-set (choice) |
Available / In Use |
| QR Preview | md-card |
Generated QR code preview |
| "Complete Intake" Button | md-filled-button |
Primary CTA — finalize |
| "Print Label" Toggle | md-switch |
Auto-print QR label on completion |
| Summary Card | md-card (outlined) |
Final summary before submission |
3. Layout Specification
Shared Layout
Top App Bar (56dp mobile / 64dp kiosk)
- Leading: Close (✕) → returns to Inventory List with unsaved-work confirmation if mid-flow
- Title: "Smart Intake" (all states)
- Trailing: None (deliberate — no distractions during intake)
Step Indicator (40dp, below App Bar)
● ───── ○ ───── ○
Scan Identify Update
- 3-step linear indicator
- Active step:
primaryfilled circle +primaryconnecting line - Completed step:
primaryfilled circle + checkmark icon - Future step:
outlinecircle +outlineVariantconnecting line - Labels:
labelSmallbelow each dot - Animation: Line fills with
primarycolor as each step completes (300ms ease-out)
STATE 1: SCAN
Title: "Scan Spool"
Layout — Mobile (Camera-based)
┌──────────────────────────────────┐
│ ✕ Smart Intake │
│──────────────────────────────────│
│ ● ──── ○ ──── ○ │
│ Scan Identify Update │
│──────────────────────────────────│
│ │
│ ┌──────────────────────────┐ │
│ │ │ │
│ │ ┌────────────────┐ │ │
│ │ │ ╔════════════╗│ │ │
│ │ │ ║ VIEWPORT ║│ │ │
│ │ │ ║ FRAME ║│ │ │
│ │ │ ║ (animated) ║│ │ │
│ │ │ ╚════════════╝│ │ │
│ │ │ │ │ │
│ │ │ ▲ Align barcode │ │ │
│ │ │ within frame │ │ │
│ │ └────────────────┘ │ │
│ │ │ │
│ │ LIVE CAMERA FEED │ │
│ │ │ │
│ └──────────────────────────┘ │
│ │
│ [Last scan: 8901234567890] │
│ │
│ Can't scan? Enter manually │
│ │
└──────────────────────────────────┘
- Camera viewport: Full-bleed video feed with 16:9 or 4:3 aspect ratio
- Scanning frame: Animated rectangle (200dp × 120dp) centered in viewport
- Corner brackets:
primarycolor, 24dp corner length, 3dp stroke - Scan line: Horizontal
primaryline that sweeps top-to-bottom repeatedly (2s cycle) - On successful scan: Frame flashes
successcolor (green) + brief haptic (mobile)
- Corner brackets:
- Instruction text: Below frame,
bodyMedium,onSurfaceVariant - Scan result chip: Appears below camera when a code is detected
- Shows scanned code value in monospace
- Auto-advances to Identification state after 1.5s (with option to cancel)
- Manual entry link: Text button below camera area for fallback
Layout — Kiosk (USB Scanner-based)
┌──────┬──────────────────────────────────────────────┐
│ NAV │ ✕ Smart Intake │
│ RAIL │──────────────────────────────────────────────│
│ │ ● ──── ○ ──── ○ │
│ │ Scan Identify Update │
│ │──────────────────────────────────────────────│
│ │ │
│ │ ┌──────────────────────┐ │
│ │ │ │ │
│ │ │ 📷 SCANNER READY │ │
│ │ │ │ │
│ │ │ USB Scanner: ✓ │ │
│ │ │ │ │
│ │ │ Scan a barcode or │ │
│ │ │ QR code now... │ │
│ │ │ │ │
│ │ │ ═══════════════ │ │
│ │ │ (pulse animation) │ │
│ │ │ │ │
│ │ └──────────────────────┘ │
│ │ │
│ │ Or: [Enter Barcode Manually] │
│ │ │
└──────┴──────────────────────────────────────────────┘
- No camera on kiosk — USB HID barcode scanner is the primary input
- Scanner status card: Shows connected/disconnected state
- Connected:
successicon + "Scanner Connected ✓" - Disconnected:
erroricon + "Scanner Not Found" + "Troubleshoot" button
- Connected:
- Pulse animation: A horizontal line that pulses
primaryto indicate "waiting for scan" - On scan: The scanned code appears in a chip, auto-advances to Identification
- Manual entry: Full keyboard (virtual) for typing barcode numbers
Scan State Elements
| Element | Description |
|---|---|
| Primary CTA | None (scanning is automatic) — the camera/scanner IS the CTA |
| Secondary Actions | Manual entry, close/dismiss |
| Key Components | Camera viewport, scanning frame animation, scanner status (kiosk), scan result chip |
| States | See below |
| State | Visual |
|---|---|
| Initializing camera | Shimmer loading in viewport + "Starting camera…" label |
| Ready (waiting for scan) | Live feed + animated scan line + "Align barcode within frame" |
| Scanning (code detected) | Frame flashes green + scan result chip appears + "Identified!" text |
| No match found | Frame flashes yellow + chip + "Unknown barcode" → still advances to Identify (manual) |
| Camera denied | Error card: "Camera access denied" + "Enter manually" button + permission settings link |
| Scanner disconnected (kiosk) | Error card: "Scanner not detected" + "Reconnect scanner" + "Enter manually" |
| Multiple codes detected | Shows list of detected codes as selectable chips → user picks correct one |
STATE 2: IDENTIFY
Title: "Identify Spool"
Layout (Both platforms)
┌──────────────────────────────────┐
│ ✕ Smart Intake │
│──────────────────────────────────│
│ ✓ ────● ──── ○ │
│ Scan Identify Update │
│──────────────────────────────────│
│ │
│ ┌──────────────────────────┐ │
│ │ Scanned: 8901234567890 │ │
│ │ Match: HIGH CONFIDENCE │ │
│ │ ▓▓▓▓▓▓▓▓▓▓▓▓░░ 92% │ │
│ └──────────────────────────┘ │
│ │
│ Material │
│ ┌──────────────────────────┐ │
│ │ PLA Basic ▾│ │
│ └──────────────────────────┘ │
│ │
│ Brand │
│ ┌──────────────────────────┐ │
│ │ Bambu Lab ▾│ │
│ └──────────────────────────┘ │
│ │
│ Color │
│ ● ● ● ● ● ● ● ● ● [Custom] │
│ Bla Red Blu Grn Yel Org Pur Wh │
│ │
│ Finish Modifier │
│ [Basic][Matte][Silk] [None] │
│ │
│ [Rescan] [Confirm →] │
│ │
└──────────────────────────────────┘
Confidence Indicator
A horizontal bar showing match confidence from the barcode lookup:
| Confidence | Visual | Color | Behavior |
|---|---|---|---|
| High (≥80%) | Full green bar | success |
Pre-fills all fields; user just confirms |
| Medium (40-79%) | Yellow bar | warning |
Pre-fills material/brand; color may need correction |
| Low (<40%) | Orange bar | Custom orange | Pre-fills partial; more fields need manual input |
| Unknown (0%) | Red bar | error |
"Barcode not found" — all fields manual |
Material Selector
mat-selectdropdown with searchable options- Options sourced from normalized taxonomy (MaterialBase list)
- If confidence is High: pre-selected, field is in confirmed state (slight green tint)
- If confidence is Low/Unknown: field is empty, highlighted for input
Brand Selector
mat-selectdropdown with common brands- Searchable with "Other…" option that allows free-text entry
Color Picker
- Swatch grid: 2 rows of circular color swatches (24dp each)
- Common colors: Black, White, Red, Blue, Green, Yellow, Orange, Purple, Grey, Brown, Pink, Transparent
- Tap swatch → selected (ring indicator)
- "Custom" option → opens free-text color name input
- Selected color stored as both name + hex value
Finish + Modifier Chips
- Finish (required):
mat-chip-listboxwith single-select- Options: Basic, Matte, Silk, Sparkle, Metallic, Translucent
- Default: "Basic"
- Modifier (optional):
mat-chip-listboxwith single-select- Options: None, Carbon Fiber, Wood Fill, Glow-in-Dark, Marble, Gradient
- Default: "None"
Identify State Elements
| Element | Description |
|---|---|
| Primary CTA | "Confirm" filled button → advances to Update state |
| Secondary Actions | "Rescan" outlined button → returns to Scan state |
| Key Components | Confidence bar, Material dropdown, Brand dropdown, Color picker grid, Finish chips, Modifier chips |
| Validation | Material and Brand are required. Color is required. Confirm button disabled until all required fields filled. |
STATE 3: UPDATE
Title: "Update Spool"
Layout (Both platforms)
┌──────────────────────────────────┐
│ ✕ Smart Intake │
│──────────────────────────────────│
│ ✓ ────✓ ──── ● │
│ Scan Identify Update │
│──────────────────────────────────│
│ │
│ Initial Weight │
│ ┌──────────────────────────┐ │
│ │ [-] 1000 [+] grams │ │
│ └──────────────────────────┘ │
│ Quick: [250] [500] [750] [1000] │
│ │
│ Assign Location │
│ ┌──────────────────────────┐ │
│ │ Select location... ▾│ │
│ └──────────────────────────┘ │
│ │
│ Status │
│ [● Available] [○ In Use] │
│ │
│ ┌──────────────────────────┐ │
│ │ Summary │ │
│ │ PLA Basic - Matte Black │ │
│ │ Bambu Lab • 1000g │ │
│ │ AMS 2, Slot A3 • Avail │ │
│ │ ID: EXT-2026-PLA-0043 │ │
│ │ │ │
│ │ ┌──────┐ Print Label │ │
│ │ │ QR │ [═══●═══] ON │ │
│ │ │Preview│ │ │
│ │ └──────┘ │ │
│ └──────────────────────────┘ │
│ │
│ [◀ Back] [✓ Complete Intake] │
│ │
└──────────────────────────────────┘
Weight Input
- Stepper control: Number input flanked by – and + buttons
- Step size: 50g (adjustable via long-press to 10g/100g)
- Minimum: 50g, Maximum: 5000g
- Direct numeric keyboard input also available
- Quick-select chips: Common spool sizes (250g, 500g, 750g, 1000g) — tap to set weight instantly
- Active chip:
primaryContainerfill - On kiosk: Larger chips (48dp height) for easy tapping
- Active chip:
- Unit label: "grams" suffix, non-editable,
onSurfaceVariant
Location Selector
mat-selectdropdown organized hierarchically:- AMS Units → Slot A1, A2, A3, A4
- External Holders → Shelf B1, B2, B3
- Unassigned (default)
- Only shows available (unoccupied) locations
- Selected location shows printer/host info as hint text
Status Toggle
mat-chip-listboxsingle-select:- Available (default): Green tonal chip + "Available" label
- In Use: Blue tonal chip + "In Use" label
- Most new spools are "Available" on intake — this is the safe default
Summary Card
- Outlined card showing all intake details for final review:
- Material name, brand, weight, location, status, tracking ID
- QR code preview (small, 80dp) — auto-generated from tracking ID
- "Print Label" toggle switch (default: ON on kiosk, OFF on mobile)
- When ON: Bluetooth thermal printer will produce label after completion
- Kiosk default ON because label printer is always connected
- Mobile default OFF because printer may not be available
Update State Elements
| Element | Description |
|---|---|
| Primary CTA | "Complete Intake" filled button → finalizes spool creation |
| Secondary Actions | "Back" outlined button → returns to Identify state |
| Key Components | Weight stepper, Quick-select chips, Location dropdown, Status toggle, Summary card, Print label switch, QR preview |
| Validation | Weight is required (>0). Location is optional. Confirm button always enabled once weight is set. |
Completion Flow
- User taps "Complete Intake"
- API call creates spool record
- If "Print Label" is ON: send QR to thermal printer
- Success state: Step indicator animates all 3 steps complete + confetti-free success animation + "Spool Added ✓" snackbar
- Two options appear:
- "Add Another Spool" → resets to Scan state (fastest path for batch intake)
- "View Spool" → navigates to Spool Detail View for the newly created spool
- Auto-return to Inventory List after 10s if no action taken (kiosk only — prevents abandoned sessions)
States
| State | Visual |
|---|---|
| Default | All fields at defaults, "Complete Intake" enabled once weight is set |
| Weight invalid | Error text "Enter a weight between 50g and 5000g", button disabled |
| Location unavailable | Dropdown shows "No available locations" + "Add as Unassigned" option |
| Submitting | "Complete Intake" shows mat-spinner inline, disabled. Other elements non-interactive. |
| Success | Green check animation, "Spool Added ✓", two option buttons |
| Error (API) | Error snackbar + "Retry" action button. Form state preserved. |
| Error (Printer) | Success still shows, but printer error snackbar: "Label print failed — reprint from spool detail" |
4. UX Rationale
Scan State
-
Camera-first on mobile. The phone's camera is the fastest barcode scanner available. No typing, no selecting — just point and scan. The animated viewport frame provides clear guidance on where to aim.
-
USB scanner-first on kiosk. The kiosk doesn't need a camera — the USB HID scanner is faster and more reliable than camera-based scanning. The "Scanner Ready" state gives immediate confidence that the hardware is working.
-
Auto-advance after scan. When a barcode is detected, the system should advance automatically. The 1.5s delay lets the user see what was scanned, but doesn't require a manual "next" tap. Speed matters when processing 20 spools in a row.
-
Manual entry always available. Barcodes get damaged. Camera angles are sometimes wrong. The manual fallback prevents workflow dead-ends.
Identification State
-
Confidence indicator reduces anxiety. When a barcode is scanned, the user needs to know: "Did the system recognize this?" The confidence bar answers this instantly. High confidence → "just confirm." Low confidence → "you'll need to fill in details." This sets expectations.
-
Pre-fill everything possible. If the barcode matches a known product (UPC database or previous spools), pre-fill material, brand, and color. The user should confirm, not construct. Every pre-filled field is saved time.
-
Color as swatches, not dropdown. Filament color is visual — selecting from a text dropdown ("Red" vs "Crimson" vs "Scarlet") is ambiguous. Circular swatches are unambiguous and faster to scan.
-
Finish/Modifier as chips. These are small, mutually exclusive option sets. Chips are more glanceable and tappable than dropdowns for 2-6 options.
Update State
-
Weight stepper + quick-select. Operators know spool weights (they're standard sizes). Quick-select chips (250g, 500g, 750g, 1000g) cover 90% of cases in a single tap. The stepper handles the remaining 10% where weight is non-standard.
-
Location as optional. New spools may not be immediately assigned to a printer. Forcing location assignment would create friction — some operators prefer to intake first, assign later.
-
Summary card for confidence. Before committing, the user sees everything in one place. This is the "receipt" pattern — it catches errors before they become data problems. The QR preview is especially important: operators verify the physical label will match.
-
"Add Another" as primary post-completion action. In a batch intake session (which is common), the operator wants to immediately scan the next spool. "Add Another" should be the most prominent post-completion option.
-
Print label default differs by platform. On kiosk, the thermal printer is connected and labels are expected. On mobile, the printer may be remote. The defaults reflect reality.
5. Visual Direction
Typography (MD3 Type Scale)
| Role | Token | Size | Weight | Line Height |
|---|---|---|---|---|
| App Bar Title | titleLarge |
22sp | 400 | 28sp |
| Step Labels | labelSmall |
11sp | 500 | 16sp |
| Section Headers | titleSmall |
14sp | 500 | 20sp |
| Field Labels | bodyMedium |
14sp | 400 | 20sp |
| Field Values | bodyLarge |
16sp | 400 | 24sp |
| Weight Display | headlineMedium |
28sp | 400 | 36sp |
| Confidence Label | labelLarge |
14sp | 500 | 20sp |
| Confidence % | titleMedium |
16sp | 500 | 24sp |
| Scanned Code | labelMedium (monospace) |
12sp | 500 | 16sp |
| Summary Lines | bodyMedium |
14sp | 400 | 20sp |
| Tracking ID | labelMedium (monospace) |
12sp | 500 | 16sp |
| CTA Button | labelLarge |
14sp | 500 | 20sp |
| Instruction Text | bodyMedium |
14sp | 400 | 20sp |
| Quick-Select Chip | labelLarge |
14sp | 500 | 20sp |
Spacing (MD3 8dp grid)
| Element | Spacing |
|---|---|
| App Bar padding | 16dp horizontal, 12dp vertical |
| Step indicator padding | 24dp horizontal, 12dp vertical |
| Camera viewport | Full-bleed (0dp margin), 16dp rounded corners, overflow hidden |
| Section gap | 16dp vertical |
| Field label to input | 8dp |
| Color swatch grid gap | 12dp |
| Quick-select chip gap | 8dp |
| Weight stepper internal | 12dp between elements |
| Summary card padding | 16dp |
| Button row gap | 12dp |
| Bottom padding (before nav bar) | 16dp (mobile) / 0dp (kiosk — no bottom nav) |
Color (MD3 Dark Theme — "Industrial Maker")
Same base palette as FIL-001 and FIL-002. Screen-specific additions:
| Role | Token | Value (Dark) | Usage |
|---|---|---|---|
| Camera Viewport BG | surfaceContainerHighest |
#36343B |
Camera area background (before camera starts) |
| Scan Frame | primary |
#A8CEDA |
Animated scanning rectangle |
| Scan Success Flash | Custom success |
#8BD0A0 |
Flash on successful scan |
| Confidence High | Custom success |
#8BD0A0 |
High confidence bar |
| Confidence High Container | Custom successContainer |
#00522E |
High confidence bar background |
| Confidence Medium | Custom warning |
#FFD580 |
Medium confidence bar |
| Confidence Medium Container | Custom warningContainer |
#5D4200 |
Medium confidence bar background |
| Confidence Low | Custom orange | #FFB784 |
Low confidence bar |
| Confidence Low Container | Custom orange container | #5D3A00 |
Low confidence bar background |
| Confidence Unknown | error |
#F2B8B5 |
Unknown/no match bar |
| Confidence Unknown Container | errorContainer |
#8C1D18 |
Unknown bar background |
| Pre-filled Field Tint | primaryContainer |
#004D63 |
Subtle green-blue tint on pre-filled inputs |
| Quick-Select Active | primaryContainer |
#004D63 |
Active chip fill |
| Scanner Connected | Custom success |
#8BD0A0 |
Kiosk scanner status |
| Scanner Disconnected | error |
#F2B8B5 |
Kiosk scanner status |
Scan Frame Animation
The scanning rectangle uses a sweep line animation:
- Horizontal line travels from top to bottom of the frame over 2 seconds
- Line color:
primary(#A8CEDA) with 40% opacity - Line width: 2dp
- Frame corner brackets: 3dp stroke,
primarycolor - On code detected: Frame corners pulse green (#8BD0A0) once, scan line stops
6. Responsiveness
Kiosk (800×480) — Scan State
┌──────┬──────────────────────────────────────────────┐
│ NAV │ ✕ Smart Intake │
│ RAIL │──────────────────────────────────────────────│
│ │ ● ──── ○ ──── ○ │
│ │ Scan Identify Update │
│ │──────────────────────────────────────────────│
│ │ │
│ │ ┌──────────────────────────────────┐ │
│ │ │ │ │
│ │ │ 📷 SCANNER CONNECTED ✓ │ │
│ │ │ │ │
│ │ │ Scan a barcode or QR code... │ │
│ │ │ │ │
│ │ │ ═══════════════════ │ │
│ │ │ (pulsing line) │ │
│ │ │ │ │
│ │ └──────────────────────────────────┘ │
│ │ │
│ │ Or: [Enter Barcode Manually] │
│ │ │
└──────┴──────────────────────────────────────────────┘
Kiosk (800×480) — Identify State
┌──────┬──────────────────────────────────────────────┐
│ NAV │ ✕ Smart Intake │
│ RAIL │──────────────────────────────────────────────│
│ │ ✓ ────● ──── ○ │
│ │ Scan Identify Update │
│ │──────────────────────────────────────────────│
│ │ Scanned: 8901234567890 HIGH ▓▓▓▓▓▓▓▓ 92% │
│ │──────────────────────────────────────────────│
│ │ Material: [PLA Basic ▾] │
│ │ Brand: [Bambu Lab ▾] │
│ │ Color: ● ● ● ● ● ● ● ● ● [C] │
│ │ Finish: [Basic][Matte][Silk] Mod: [None] │
│ │ │
│ │ [Rescan] [Confirm →] │
└──────┴──────────────────────────────────────────────┘
- Two-column layout for Material/Brand on kiosk (side by side to save vertical space)
- Finish/Modifier on same row to save space
- Color picker horizontal with wrapping
Kiosk (800×480) — Update State
┌──────┬──────────────────────────────────────────────┐
│ NAV │ ✕ Smart Intake │
│ RAIL │──────────────────────────────────────────────│
│ │ ✓ ────✓ ──── ● │
│ │ Scan Identify Update │
│ │──────────────────────────────────────────────│
│ │ Weight: [-] 1000 [+] g │
│ │ Quick: [250] [500] [750] [1000] │
│ │ Location: [AMS 2, Slot A3 ▾] │
│ │ Status: [● Available] [○ In Use] │
│ │──────────────────────────────────────────────│
│ │ ┌──────────────────────────────────┐ │
│ │ │ PLA Basic - Matte Black │ │
│ │ │ Bambu Lab • 1000g • Slot A3 │ │
│ │ │ EXT-2026-PLA-0043 QR ████ │ │
│ │ │ Print Label [═══●═══] ON │ │
│ │ └──────────────────────────────────┘ │
│ │ │
│ │ [◀ Back] [✓ Complete Intake] │
└──────┴──────────────────────────────────────────────┘
- All content fits above fold on kiosk — no scrolling needed
- Summary card compact — inline with QR preview
- Buttons full-width in action row
Mobile PWA (375×812) — Scan State
As shown in Section 3 (full-bleed camera). Key differences:
- Camera takes ~60% of screen height
- Step indicator + instruction text in remaining space
- Scan result chip floats above camera viewport
Mobile PWA (375×812) — Identify State
As shown in Section 3. Key differences:
- Single column layout — all fields stack vertically
- Scrollable — Identification form exceeds screen height on small phones
- Color picker wraps to 2 rows
- Buttons fixed at bottom (sticky)
Mobile PWA (375×812) — Update State
As shown in Section 3. Key differences:
- Scrollable content
- Summary card full-width
- Buttons fixed at bottom (sticky)
Key Adaptations
| Property | Kiosk (800×480) | Mobile (375×812) |
|---|---|---|
| Scan input method | USB HID scanner | Device camera |
| Scanner status card | Yes (connected/disconnected) | No (camera instead) |
| Camera viewport | None | Full-bleed, ~60% height |
| Form layout | Two-column where possible | Single column, scrollable |
| Color picker | Horizontal with wrapping | Horizontal with wrapping (narrower) |
| Quick-select chips | Larger (48dp height) | Standard (36dp height) |
| Print label default | ON | OFF |
| Post-completion auto-return | 10s → Inventory | No auto-return |
| Bottom navigation | No (has rail) | Yes (80dp) |
| Sticky buttons | At bottom of content | At bottom above nav bar |
7. Developer Handoff Notes
Angular Material Components
| UI Element | Angular Material Component | Notes |
|---|---|---|
| Top App Bar | <mat-toolbar> |
Simple, non-collapsible. Close button on left. |
| Step Indicator | Custom component | 3-dot stepper with animated connecting lines. Use @angular/animations for line fill. |
| Camera Viewport | <video> + overlay <div> |
Use @angular/cdk/overlay for scanning frame. Camera via navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }). |
| Scanning Frame | Custom overlay | SVG or absolute-positioned divs for corner brackets. CSS animation for sweep line. |
| Confidence Bar | Custom component | Horizontal bar with dynamic color + width. <div> with [style.width] binding. |
| Material Selector | <mat-select> |
With <mat-option>. Add matSelectSearch for searchable dropdown. |
| Brand Selector | <mat-select> |
Same as Material, plus "Other…" option with conditional <input matInput>. |
| Color Picker | Custom component | Grid of circular <button> elements. Selected state: ring border. |
| Finish Chips | <mat-chip-listbox> |
Single-select. mat-chip-option elements. |
| Modifier Chips | <mat-chip-listbox> |
Single-select. Include "None" as default option. |
| Weight Stepper | Custom component | <button mat-icon-button> (–/+) flanking <input matInput type="number">. |
| Quick-Select Chips | <mat-chip-listbox> |
Single-select. Values: 250, 500, 750, 1000. |
| Location Selector | <mat-select> |
Hierarchical with <mat-optgroup> for AMS/Shelves. |
| Status Toggle | <mat-chip-listbox> |
Two options: Available, In Use. |
| Summary Card | <mat-card> outlined |
Read-only display. Binding from form values. |
| QR Preview | qrcode npm package |
Small preview (80dp). Canvas or SVG rendering. |
| Print Label Switch | <mat-slide-toggle> |
Default ON (kiosk) / OFF (mobile). |
| Complete Intake Button | <button mat-raised-button> |
color="primary". Shows <mat-spinner> inline when submitting. |
| Rescan / Back | <button mat-stroked-button> |
Navigates to previous state. |
| Success State | Custom component | Green checkmark animation + option buttons. |
| Snackbar | <mat-snackbar> |
For success/error messages. Duration: 4s. |
| Confirmation Dialog | <mat-dialog> |
"Discard intake? Unsaved data will be lost." Cancel / Discard. |
Barcode/QR Scanning Implementation
Mobile (Camera):
- Use
@zxing/browserorhtml5-qrcodelibrary for camera-based barcode detection - Configure for: EAN-13, UPC-A, Code-128, QR, Data Matrix
- Continuous scan mode (not snapshot) for faster detection
- On detection: debounce 500ms to prevent duplicate reads
- Vibrate on successful scan (if
Vibration APIavailable)
Kiosk (USB HID Scanner):
- USB HID barcode scanners appear as keyboard input — they type the code + Enter
- Listen for rapid key sequence ending in Enter on the Scan state
- Buffer keystrokes; when Enter detected, treat buffered text as scanned code
- Reset buffer on any pause >100ms between keystrokes
- Debounce: ignore duplicate codes within 2s window
Interaction Notes
- Auto-advance from Scan → Identify: 1.5s delay after successful scan with a cancel affordance (tap scan result chip to cancel auto-advance).
- Confidence-based pre-fill: On entering Identify state, call API with scanned code. If match found, pre-fill form fields. Mark pre-filled fields with subtle
primaryContainerbackground tint. - Weight stepper long-press: Long-press on +/- changes step size (50→10 or 50→100). Visual feedback: tooltip showing current step size.
- Quick-select chip sync: Tapping a quick-select chip updates the stepper value and vice versa. They're two inputs to the same model.
- Form validation (Identify): "Confirm" button is disabled until Material and Color are set. Brand is strongly recommended but not blocking (can be "Unknown").
- Form validation (Update): "Complete Intake" button is disabled until Weight > 0.
- Discard confirmation: Back/close mid-flow triggers dialog: "Discard intake? This spool won't be saved." Cancel / Discard.
- Post-completion "Add Another": Resets all form state, returns to Scan state. Does NOT re-initialize camera (keep it running throughout session for speed).
- Printer error handling: If label printing fails, show snackbar but don't block the success state. The spool is already saved; label can be reprinted from Spool Detail.
- Camera permission denied: Show clear error with "Open Settings" link. Also show "Enter manually" as fallback.
Accessibility
| Requirement | Implementation |
|---|---|
| Step indicator | role="progressbar", aria-valuenow="1/2/3", aria-valuemin="1", aria-valuemax="3", aria-label="Step 1 of 3: Scan" |
| Camera viewport | aria-label="Camera view for barcode scanning", role="application", aria-live="polite" for scan result announcements |
| Scanner status (kiosk) | aria-live="polite" — announces "Scanner connected" or "Scanner disconnected" |
| Scan result | aria-live="assertive" — "Barcode 8901234567890 detected" |
| Confidence bar | role="progressbar", aria-valuenow="92", aria-label="Match confidence: 92 percent, High" |
| Material/Brand selects | Standard mat-select accessibility — aria-label, keyboard navigable |
| Color picker | Each swatch: aria-label="Black", role="radio", aria-checked="true/false". Radio group semantics. |
| Weight stepper | aria-label="Weight in grams", role="spinbutton", aria-valuenow, aria-valuemin="50", aria-valuemax="5000" |
| Quick-select chips | role="radiogroup", each chip role="radio", aria-label="500 grams" |
| Complete Intake button | aria-label="Complete spool intake" — changes to "Submitting…" during submission |
| Close confirmation | aria-labelledby dialog title, aria-describedby dialog content. Focus trap. |
| Motion reduction | Disable scan line animation, use static frame. Disable auto-advance (require manual "Next"). |
| Keyboard flow | Tab: Close → Step indicator → Content → Buttons. Enter to activate. Escape to dismiss/close. |
SignalR Integration
- After "Complete Intake" API call succeeds, the new spool is pushed to all connected clients via
SpoolAddedhub event. - The Inventory List (FIL-001) will receive this event and add the spool with highlight animation.
- If the user navigates to Inventory after intake, the new spool is already in the list — no manual refresh needed.
Performance Notes
- Camera stream: request
640×480resolution for barcode scanning (sufficient, saves battery/CPU) - Keep camera stream alive across "Add Another" cycles — only initialize once per session
- Debounce API calls in Identify state: don't call the barcode lookup API more than once per 2s
- Use
OnPushchange detection for all Smart Intake components - QR preview generation should be non-blocking — render in a
requestAnimationFramecallback
Routing
/intake → Redirect to /intake/scan
/intake/scan → Scan State
/intake/identify → Identification State
/intake/update → Update State
Each state is a separate route. This enables:
- Browser back button works naturally (Update → Identify → Scan)
- Deep-linking to specific states (e.g., for testing)
- URL reflects current step (clear for the user and for analytics)