# Video Thumbnail Picker

## Objective

Choose the frame that represents a video, or upload a cover image instead.

A picker that offers candidate frames from a video and accepts a custom uploaded cover image.

## Before You Begin

This feature is being added to an application that already exists and already
works. Do not scaffold a new project, and do not assume a blank slate.

Inspect the codebase first and establish:

- The existing application structure and where code of this kind already lives.
- The framework and version in use.
- The existing design system — colours, spacing, typography, and component conventions.
- Existing UI components you can reuse instead of writing new ones.
- The existing database structure, if this feature needs to persist anything.
- The existing authentication and authorization system, if this feature is user-scoped.
- Dependencies already installed, so you don't add a library that duplicates one.
- The existing test setup and conventions.

Only start writing code once you understand the above. If the application
already implements part of this feature, extend it rather than replacing it.

## Implementation Instructions

1. Generate candidate frames on the server as part of the video's processing pipeline, and show the user a strip of stills to choose from. Do not stream the whole file into the browser to seek it frame by frame.
2. Offer a scrubber for picking an exact moment in addition to the suggested stills, so someone who wants a specific frame is not limited to the ones you guessed.
3. Accept a custom cover image upload as an equal path, and route it through the app's existing File Upload and Image Compression handling rather than adding a second upload endpoint with its own limits.
4. Store one canonical still and derive the sizes each surface needs: grid tile, card, and social share preview. Reuse the app's existing image derivative and cropping behaviour, including Image Focal Point Cropping if it exists, so a face is not cropped out of the square version.
5. Do not block publishing on thumbnail selection. Pick a reasonable default automatically and let the user change it later, or half your videos will sit unpublished behind an unmade decision.

## UI and UX Requirements

Match the application's existing design system exactly. Reuse its components,
spacing, and typography. This feature should look like it was always there.

## Responsive Requirements

Works on mobile, tablet, and desktop. Touch targets are large enough to hit on a
phone, and nothing overflows horizontally at 320px.

## Accessibility Requirements

- Fully keyboard navigable.
- Correct semantic elements and ARIA roles.
- Visible focus states.
- Meets WCAG AA contrast.
- Dynamic changes are announced to screen readers.
- Respects prefers-reduced-motion.

## Edge Cases

- Videos often open on black, a fade-in, or a title card. Score candidate frames and skip near-blank or single-colour ones when suggesting defaults, or every automatic thumbnail will be a black rectangle.
- Replacing the source video invalidates every stored still. Regenerate candidates on replacement and clear the previous selection rather than leaving a cover image from a video that no longer exists.
- Different surfaces need different aspect ratios, and a still cropped independently per surface drifts. Store consistent, named sizes generated from one source frame so the grid, card, and share preview agree.
- A thumbnail can be requested while the video is still encoding. Show a pending state on the picker and generate candidates when processing completes, instead of failing or serving an empty image.
- An uploaded cover image is user-generated content on a public page. Enforce type and size limits on the server, run it through whatever scanning the app already applies to uploads, and treat it as moderatable.
- Reserve the thumbnail's dimensions in every layout that shows it so cards do not resize when images arrive.
- Every thumbnail needs alternative text. Default it to the video title rather than leaving it empty or filling it with a filename.
- Generating stills for a long or high-resolution video is expensive. Cap the work per video and let it fail gracefully to a single default frame rather than tying up the encoder.

## Testing

Exercise the feature end to end in the running application. Cover every edge case
above, then run the existing test suite and confirm nothing regressed.

## Acceptance Criteria

- [ ] Candidate frames are produced server-side and offered as a selectable strip.
- [ ] A user can also seek to an exact frame or upload a custom cover image.
- [ ] Near-blank frames are excluded from automatic suggestions.
- [ ] Replacing the source video regenerates candidates and clears the stale selection.
- [ ] One selected still produces consistent derivatives for grid, card, and share surfaces.
- [ ] A video still encoding shows a pending picker rather than an error.
- [ ] Uploaded covers pass the app's existing size, type, and scanning rules and carry alt text.
- [ ] The feature matches the existing design system.
- [ ] No existing functionality is broken.

## Adaptation Rules

- Match the existing design system. Do not introduce a new colour palette,
  spacing scale, or component library.
- Reuse existing components and utilities wherever they fit.
- Follow the naming, file layout, and code style already present.
- Do not upgrade, replace, or remove existing dependencies to make this
  feature fit. Adapt the feature to the app, not the app to the feature.
- Do not break existing functionality. If a change is genuinely required in
  existing code, make the smallest one that works and say so.
- If something in these instructions conflicts with how the application is
  built, follow the application and explain the deviation.

## Final Verification

Before you report the work as done:

1. Re-read the acceptance criteria above and check each one against what you
   actually built.
2. Run the application and exercise the feature end to end.
3. Run the existing test suite and confirm you have broken nothing.
4. Check the feature on mobile, tablet, and desktop widths.
5. Check keyboard navigation and focus handling.
6. Summarize what changed: files added, files modified, and anything you
   deliberately did differently because of how this application is built.

If any acceptance criterion is unmet, fix it before reporting completion.
