# HLS Player Web App Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Build a standalone React + Vite web app that plays any HLS `.m3u8` URL, exposes a configuration dashboard, and generates dynamic iframe embed snippets.

**Architecture:** A client-only React app with two UI modes (Toolbox and Clean). Shared configuration state is encoded/decoded from URL query params; a dedicated `/embed` route renders the distraction-free player. HLS playback uses `hls.js` with a UI wrapper (Plyr or Video.js) and includes error recovery + user-facing status messaging.

**Tech Stack:** React 19, Vite, TypeScript, Tailwind CSS, hls.js, Plyr (or Video.js), Vitest + React Testing Library, React Router.

---

### Task 1: Scaffold the project and baseline tooling

**Files:**
- Create: `hls-player/` (new Vite app root)
- Modify: `hls-player/package.json`

**Step 1: Initialize Vite React + TS app**
Run: `npm create vite@latest hls-player -- --template react-ts`
Expected: new `hls-player` directory created

**Step 2: Install dependencies**
Run: `cd hls-player && npm install`
Expected: `node_modules` created, no errors

**Step 3: Add core dependencies**
Run: `npm install hls.js plyr react-router-dom`
Expected: dependencies added to `package.json`

**Step 4: Add dev/test dependencies**
Run: `npm install -D tailwindcss postcss autoprefixer vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom`
Expected: devDependencies added

**Step 5: Commit**
Run: `git add hls-player/package.json hls-player/package-lock.json`
Run: `git commit -m "chore: scaffold hls player app"`

### Task 2: Configure Tailwind + base styles

**Files:**
- Create: `hls-player/tailwind.config.ts`
- Create: `hls-player/postcss.config.cjs`
- Modify: `hls-player/src/index.css`

**Step 1: Initialize Tailwind config**
Run: `cd hls-player && npx tailwindcss init -p`
Expected: `tailwind.config.ts` and `postcss.config.cjs` created

**Step 2: Configure Tailwind content paths**
Edit: `hls-player/tailwind.config.ts` to include `./src/**/*.{ts,tsx}`
Expected: Tailwind scans React files

**Step 3: Add Tailwind base styles**
Edit: `hls-player/src/index.css` to include `@tailwind base; @tailwind components; @tailwind utilities;`
Expected: Tailwind base styles applied

**Step 4: Commit**
Run: `git add hls-player/tailwind.config.ts hls-player/postcss.config.cjs hls-player/src/index.css`
Run: `git commit -m "chore: configure tailwind"`

### Task 3: Set up routing and app shell

**Files:**
- Modify: `hls-player/src/main.tsx`
- Create: `hls-player/src/App.tsx`
- Create: `hls-player/src/routes/ToolboxPage.tsx`
- Create: `hls-player/src/routes/EmbedPage.tsx`

**Step 1: Add React Router to root**
Edit: `hls-player/src/main.tsx` to wrap with `BrowserRouter`
Expected: App renders with routing enabled

**Step 2: Create app routes**
Create: `hls-player/src/App.tsx` with routes for `/` (Toolbox) and `/embed` (Clean)
Expected: two route components wired

**Step 3: Smoke test in dev server**
Run: `cd hls-player && npm run dev`
Expected: app renders without runtime errors

**Step 4: Commit**
Run: `git add hls-player/src/main.tsx hls-player/src/App.tsx hls-player/src/routes/ToolboxPage.tsx hls-player/src/routes/EmbedPage.tsx`
Run: `git commit -m "feat: add toolbox and embed routes"`

### Task 4: Define configuration schema and URL parsing utilities (@senior-fullstack)

**Files:**
- Create: `hls-player/src/types/playerConfig.ts`
- Create: `hls-player/src/lib/configCodec.ts`
- Test: `hls-player/src/lib/configCodec.test.ts`

**Step 1: Write failing tests for encode/decode**
Create: `hls-player/src/lib/configCodec.test.ts` with cases for default config, URL encoding, and invalid inputs
Run: `cd hls-player && npx vitest run src/lib/configCodec.test.ts`
Expected: FAIL with missing module exports

**Step 2: Implement config types**
Create: `hls-player/src/types/playerConfig.ts` with explicit fields (`url`, `autoplay`, `muted`, `loop`, `poster`, `controls`, `preload`)
Expected: types compile

**Step 3: Implement config codec**
Create: `hls-player/src/lib/configCodec.ts` to parse URLSearchParams and serialize back
Expected: tests pass

**Step 4: Run tests**
Run: `cd hls-player && npx vitest run src/lib/configCodec.test.ts`
Expected: PASS

**Step 5: Commit**
Run: `git add hls-player/src/types/playerConfig.ts hls-player/src/lib/configCodec.ts hls-player/src/lib/configCodec.test.ts`
Run: `git commit -m "feat: add config codec with tests"`

### Task 5: Implement HLS player component with error handling

**Files:**
- Create: `hls-player/src/components/HlsPlayer.tsx`
- Create: `hls-player/src/lib/hlsController.ts`
- Modify: `hls-player/src/routes/EmbedPage.tsx`

**Step 1: Write failing test for player rendering**
Create: `hls-player/src/components/HlsPlayer.test.tsx` to assert video element renders and error state displays on invalid url
Run: `cd hls-player && npx vitest run src/components/HlsPlayer.test.tsx`
Expected: FAIL with missing component

**Step 2: Implement HLS controller**
Create: `hls-player/src/lib/hlsController.ts` to wire `hls.js` to the video element and emit status events
Expected: module compiles

**Step 3: Implement player component**
Create: `hls-player/src/components/HlsPlayer.tsx` using `hls.js` + Plyr wrapper, render status UI
Expected: tests compile

**Step 4: Update Embed route**
Edit: `hls-player/src/routes/EmbedPage.tsx` to render `HlsPlayer` with config from URL
Expected: embed route renders clean view

**Step 5: Run tests**
Run: `cd hls-player && npx vitest run src/components/HlsPlayer.test.tsx`
Expected: PASS

**Step 6: Commit**
Run: `git add hls-player/src/components/HlsPlayer.tsx hls-player/src/lib/hlsController.ts hls-player/src/routes/EmbedPage.tsx hls-player/src/components/HlsPlayer.test.tsx`
Run: `git commit -m "feat: hls player with recovery and status"`

### Task 6: Build Toolbox UI + live preview (@frontend-design)

**Files:**
- Create: `hls-player/src/components/ConfigPanel.tsx`
- Modify: `hls-player/src/routes/ToolboxPage.tsx`
- Create: `hls-player/src/components/EmbedSnippet.tsx`

**Step 1: Write failing test for config form**
Create: `hls-player/src/components/ConfigPanel.test.tsx` to verify input updates state
Run: `cd hls-player && npx vitest run src/components/ConfigPanel.test.tsx`
Expected: FAIL with missing component

**Step 2: Implement config panel**
Create: `hls-player/src/components/ConfigPanel.tsx` with URL input + toggles
Expected: controlled inputs update config

**Step 3: Implement embed snippet component**
Create: `hls-player/src/components/EmbedSnippet.tsx` to display iframe code with copy button
Expected: snippet updates on config change

**Step 4: Connect Toolbox page**
Edit: `hls-player/src/routes/ToolboxPage.tsx` to render panel + live preview
Expected: preview updates as config changes

**Step 5: Run tests**
Run: `cd hls-player && npx vitest run src/components/ConfigPanel.test.tsx`
Expected: PASS

**Step 6: Commit**
Run: `git add hls-player/src/components/ConfigPanel.tsx hls-player/src/components/EmbedSnippet.tsx hls-player/src/routes/ToolboxPage.tsx hls-player/src/components/ConfigPanel.test.tsx`
Run: `git commit -m "feat: toolbox config and embed generator"`

### Task 7: URL sync and shareable state

**Files:**
- Modify: `hls-player/src/routes/ToolboxPage.tsx`
- Modify: `hls-player/src/lib/configCodec.ts`
- Test: `hls-player/src/routes/ToolboxPage.test.tsx`

**Step 1: Write failing test for URL sync**
Create: `hls-player/src/routes/ToolboxPage.test.tsx` to ensure changes update URL query
Run: `cd hls-player && npx vitest run src/routes/ToolboxPage.test.tsx`
Expected: FAIL

**Step 2: Implement URL sync**
Edit: `hls-player/src/routes/ToolboxPage.tsx` to push query params on change
Expected: URL updates without full reload

**Step 3: Run tests**
Run: `cd hls-player && npx vitest run src/routes/ToolboxPage.test.tsx`
Expected: PASS

**Step 4: Commit**
Run: `git add hls-player/src/routes/ToolboxPage.tsx hls-player/src/lib/configCodec.ts hls-player/src/routes/ToolboxPage.test.tsx`
Run: `git commit -m "feat: sync config to URL"`

### Task 8: Error UX + recovery polish

**Files:**
- Modify: `hls-player/src/components/HlsPlayer.tsx`
- Modify: `hls-player/src/lib/hlsController.ts`
- Create: `hls-player/src/components/StatusBanner.tsx`

**Step 1: Add status banner component**
Create: `hls-player/src/components/StatusBanner.tsx` for loading/error messages
Expected: reusable UI for player states

**Step 2: Wire error events to UI**
Edit: `hls-player/src/lib/hlsController.ts` to emit network/media error types + recovery attempts
Expected: status messages updated based on error category

**Step 3: Render status in player**
Edit: `hls-player/src/components/HlsPlayer.tsx` to show `StatusBanner`
Expected: clear UI feedback

**Step 4: Commit**
Run: `git add hls-player/src/components/StatusBanner.tsx hls-player/src/lib/hlsController.ts hls-player/src/components/HlsPlayer.tsx`
Run: `git commit -m "feat: improve error UX"`

### Task 9: QA, build, and deployment checklist

**Files:**
- Modify: `hls-player/README.md`

**Step 1: Document usage and embed instructions**
Edit: `hls-player/README.md` to include config params, embed example, and troubleshooting
Expected: clear user guidance

**Step 2: Run test suite**
Run: `cd hls-player && npm run test`
Expected: PASS

**Step 3: Production build**
Run: `cd hls-player && npm run build`
Expected: build completes with no errors

**Step 4: Commit**
Run: `git add hls-player/README.md`
Run: `git commit -m "docs: add usage and embed guide"`
