diff --git a/internal/design/ui/poster.md b/internal/design/ui/poster.md
new file mode 100644
index 00000000..22d70a76
--- /dev/null
+++ b/internal/design/ui/poster.md
@@ -0,0 +1,208 @@
+---
+status: draft
+date: 2025-02-05
+---
+
+# Poster
+
+Display component for video poster image. Shows before playback starts, hides after.
+
+## Problem
+
+Video players show a poster image before playback. The poster:
+
+1. Gives users a preview of the content
+2. Should hide once playback starts
+3. May optionally reappear when playback ends
+
+Existing solutions (Media Chrome, Vidstack) either:
+
+- Manage the image internally via `src` prop
+- Expose complex state (`data-loading`, `data-error`, `data-hidden`, `data-visible`)
+
+We want a simpler approach: expose minimal state, let the user control the image.
+
+## Solution
+
+Minimal components that:
+
+1. Expose `data-visible` for CSS-based show/hide
+2. Do nothing else
+
+**HTML:** Wrapper element that accepts `
` as child.
+**React:** Renders `
` directly — no wrapper needed.
+
+### Usage
+
+#### HTML
+
+```html
+
+
+
+```
+
+#### React
+
+```tsx
+import { Poster } from '@videojs/react';
+
+;
+```
+
+#### CSS
+
+```css
+media-poster:not([data-visible]) {
+ display: none;
+}
+```
+
+### With Responsive Image
+
+#### HTML
+
+```html
+
+
+
+```
+
+#### React
+
+```tsx
+
+```
+
+User controls the image entirely — responsive images, lazy loading, placeholder strategies all work naturally.
+
+### With Placeholder (Blurhash / LQIP)
+
+Use CSS `background-image` on the `
` element to show a placeholder while the main image loads. When the `src` loads, it naturally covers the background.
+
+#### HTML
+
+```html
+
+
+
+```
+
+#### React
+
+```tsx
+
+```
+
+For fade transitions (blur → sharp), handle the `load` event on the image:
+
+```html
+
+
+
+```
+
+## API
+
+### Data Attributes
+
+| Attribute | Description |
+| -------------- | -------------------------------------------- |
+| `data-visible` | Present when poster should show (`!started`) |
+
+### Visibility Logic
+
+```ts
+visible = !playback.started;
+```
+
+The poster is visible until playback has started. Once `started` becomes `true` (user plays or seeks), the poster hides and stays hidden.
+
+**Note:** `started` persists — pausing doesn't reset it. The poster only shows on initial load or after a new source is loaded.
+
+## Styling Notes
+
+The component sets no default styles. Recommended CSS:
+
+```css
+media-poster {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+}
+
+media-poster:not([data-visible]) {
+ display: none;
+}
+
+media-poster img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+}
+```
+
+**`pointer-events: none`** — Clicks should pass through to the video or play button beneath.
+
+## Accessibility
+
+**Wrapper (``):** No ARIA role needed. Custom elements have no implicit role, so there's no semantics to hide or override. Do not add `aria-hidden` to the wrapper — the poster image may be informative.
+
+**Child (`
`):** User provides appropriate `alt` text describing the poster content (e.g., `alt="Keynote speaker at a conference"`). If purely decorative, use `alt=""`.
+
+Whether a poster is informative or decorative is the author's judgment (per [WAI guidelines](https://www.w3.org/WAI/tutorials/images/decorative/)). In most video player contexts, posters are informative — they give users a preview of the video content. This is an advantage over Media Chrome (which forces `aria-hidden="true"` on the internal image) and native `