# 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.
