# QA checklist Use this checklist before promoting a preview deployment to production. ## Installation and build - [ ] Clean checkout installs with `npm install`. - [ ] No manually fabricated lockfile is present. - [ ] `npm run typecheck` passes. - [ ] `npm run lint` passes. - [ ] `npm run test` passes. - [ ] `npm run test:coverage` produces coverage output. - [ ] `npm run build` succeeds. - [ ] `npm run preview` serves the production build. - [ ] Browser console has no errors on initial load. ## Catalogue - [ ] Catalogue renders without layout shift. - [ ] Skeleton state appears on slow reload. - [ ] Search finds machines by title. - [ ] Search finds machines by keyword. - [ ] Category filters work for engines, gearboxes/drives, pumps/fluid systems, mechanisms, and structural/other. - [ ] Difficulty filter works for beginner, intermediate, and advanced. - [ ] Sort by name works. - [ ] Sort by newest works. - [ ] Sort by complexity works. - [ ] Favourite toggle persists after reload. - [ ] Favourite state is keyboard accessible. - [ ] Machine cards have accessible names. - [ ] Empty search state is helpful and recoverable. ## Viewer loading - [ ] Opening a machine lazy-loads the scene. - [ ] Viewer loading fallback keeps layout stable. - [ ] Progress indicator is visible for delayed assets. - [ ] Asset load failure shows a recoverable error panel. - [ ] WebGL initialization failure shows a non-canvas fallback. - [ ] Returning to catalogue does not leave stale loading overlays. ## Viewer interaction - [ ] Orbit rotates smoothly with pointer. - [ ] Zoom works with wheel and pinch. - [ ] Pan works with configured gesture. - [ ] Camera presets work: front, back, left, right, top, isometric. - [ ] Reset camera restores default framing. - [ ] Hover highlight shows part name. - [ ] Click/tap selects part. - [ ] Detail drawer shows part description and specs. - [ ] Part visibility toggles work. - [ ] Part opacity sliders work and clamp values. - [ ] Exploded view slider works from `0` to `1`. - [ ] Wireframe mode is legible. - [ ] Cross-section works on X, Y, and Z axes. - [ ] Annotation labels can be toggled. - [ ] Switching machines resets incompatible part selection. ## Animation - [ ] Play starts animation. - [ ] Pause freezes the mechanism without drifting. - [ ] Resume continues smoothly. - [ ] Restart returns to phase zero. - [ ] RPM slider clamps to machine range. - [ ] Time scale clamps from `0.1x` to `3x`. - [ ] Step-through advances one cycle step at a time. - [ ] Animation loops without visible discontinuity. - [ ] One machine from every category has believable motion. ## Guided tours - [ ] Tour starts from the viewer. - [ ] Tour captions are readable. - [ ] Highlighted parts match caption text. - [ ] Camera movements frame the highlighted system. - [ ] Next/previous controls work. - [ ] Exiting a tour restores manual viewer control. - [ ] Reduced-motion mode avoids large automatic camera flights. ## Sharing - [ ] Copy-link button writes an absolute URL. - [ ] Copy success is visible and announced to assistive tech. - [ ] Clipboard fallback works when Clipboard API is blocked. - [ ] Opening the link in a clean profile restores machine slug. - [ ] Restored state includes camera, exploded amount, display mode, labels, selected part, hidden parts, opacity overrides, RPM, and time scale where encoded. - [ ] Invalid query values are ignored or clamped. - [ ] Unknown part IDs do not break the viewer. ## Accessibility - [ ] All interactive controls are reachable by keyboard. - [ ] Focus-visible styles are clear. - [ ] Icon-only buttons have ARIA labels. - [ ] `Escape` closes drawers/popovers. - [ ] `Tab` order follows visual layout. - [ ] Shortcut keys do not fire while typing in inputs. - [ ] Canvas has an accessible name. - [ ] Part list provides non-canvas access to selectable parts. - [ ] Live regions announce copy status and load failures. - [ ] Text contrast meets WCAG AA. - [ ] Touch targets are at least 44px. - [ ] Application works with `prefers-reduced-motion: reduce`. ## Responsive layout - [ ] Desktop 1440px layout shows left sidebar, canvas, right control panel, status bar. - [ ] Desktop 1280px layout remains uncluttered. - [ ] Tablet 1024px layout keeps primary controls accessible. - [ ] Tablet 768px layout collapses panels appropriately. - [ ] Mobile 430px layout has no horizontal document scroll. - [ ] Mobile 390px layout keeps toolbar accessible. - [ ] Mobile 375px layout keeps part drawer usable. - [ ] Canvas gestures do not accidentally scroll the page. - [ ] Safe-area insets are respected on notched devices. ## Performance - [ ] Catalogue route does not load all machine scene chunks. - [ ] Desktop orbit maintains target frame rate. - [ ] Mobile orbit remains usable. - [ ] Animation does not trigger React re-render every frame. - [ ] Switching machines does not steadily increase memory. - [ ] `npm run analyze` shows expected chunk split. - [ ] GLB/texture assets are not accidentally bundled into primary JS. - [ ] Vercel asset cache headers are present in deployed build. ## Deployment - [ ] Vercel preview uses Node 20 or newer. - [ ] Build command is `npm run build`. - [ ] Output directory is `dist`. - [ ] `VITE_APP_ORIGIN` matches deployment origin. - [ ] SPA routes refresh successfully. - [ ] Security headers are present. - [ ] Decoder/transcoder files, if used by compressed assets, are reachable. - [ ] Default social preview renders with the expected title, description, and image.