commit fa63f4d95600643b7b37081f268a47db681e242d Author: Aaron <44r0n7+Claude@pm.me> Date: Sat May 23 10:35:02 2026 -0400 Initial implementation: single-file MTV-style music video TV channel PWA Includes all spec features plus pop-out player with bidirectional video transfer: - YouTube IFrame API + Data API v3 channel management - Idle/broadcast mode, channel flip animation, NCO onboarding - Pop-out player (⧉/P) transfers video to popup; P closes and returns it Co-Authored-By: claude-flow diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..482e34b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*.swp +*.swo diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..561986f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,67 @@ +# VidFlow — Codex Agent Instructions + +## Role + +Codex implements. Claude reads context, writes task prompts, and reviews diffs. When Claude delegates a task here, implement it fully and trust your own reading of the file — Claude will catch anything that needs correction in the diff review. + +## How Claude Delegates + +Claude writes a task description and runs: + +```bash +cd /home/aaron/Programming/vidflow && /home/aaron/.npm-global/bin/codex exec < /tmp/vf-task.md +# or inline: +cd /home/aaron/Programming/vidflow && /home/aaron/.npm-global/bin/codex exec "edit vidflow.html: ..." +``` + +After you finish, Claude reviews with `git -C /home/aaron/Programming/vidflow diff` and either accepts or makes targeted corrections. + +## Project Rules (enforce these without being told) + +- **Single file**: everything lives in `vidflow.html` — no new files, no build step, no frameworks +- **Script section order** must be preserved (see below) +- **Never hardcode API keys** — stored in `localStorage` only +- **All app state in `const A`** — never create separate state variables +- **Keyboard shortcuts**: call player API directly, never `.click()` on DOM elements +- **`DEBUG = false`** — never commit as true + +## Script Section Order + +When adding functions, insert them in the correct section: + +1. State (`const A`, `const FD`, `DEBUG`, `dbg`) +2. Utility (`qs`, `qsa`, `esc`, `cleanArtist`, `extractPID`) +3. YouTube IFrame API (`onYouTubeIframeAPIReady`, `onPReady`, `onPState`, `onPErr`) +4. Channel flip (`flip()`) +5. Channel loading (`loadCh()`) +6. Now playing (`updateNP`, `setTicker`, `tickerLoop`, `showTitleCard`) +7. Progress bar (`startPB`) +8. Data API (`apiFetch`, `validateKey`, `searchPL`, `getPLInfo`) +9. Channel management (`addCh`, `removeCh`, `updateCS`) +10. UI rendering (`renderTab`, `renderChTab`, `renderSearchTab`, `renderAddTab`) +11. NCO onboarding (`initNCO`, `renderNCOTab`, `ncoAdd`) +12. Visibility helpers + toast +13. Persistence (`save`, `loadState`) +14. Setup (`initSetup`) +15. App launch (`launchApp`) +16. Controls wiring (`wireControls`) +17. Pop-out transfer (`popOut`, storage listeners) +18. Idle system (poll + event listeners) +19. PWA manifest injection +20. Init: `loadState(); wireControls(); initSetup();` + +## Known Gotchas (check these when editing related code) + +- `stopVideo()` before `loadPlaylist()` on channel switch — prevents shared-video stuck state +- Shuffle: must call `setShuffle(true)` AND `playVideoAt(startIdx)` — `loadPlaylist` index alone isn't enough +- Sidebar click-close: guard with `document.contains(e.target)` before checking `sb.contains()` +- Keyboard handlers: skip if `e.target.tagName` is INPUT or TEXTAREA +- `window.opener` distinguishes popup from main window for pop-out transfer logic + +## Local Dev + +```bash +python3 -m http.server 8080 +# Open http://localhost:8080/vidflow.html +# Must be HTTP — YouTube API rejects file:// +``` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..13602f5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,12 @@ +# VidFlow + +> Context for Claude/Codex is maintained in Obsidian Mind: +> ~/my-vault/work/projects/vidflow.md +> Run `/om-project-switch` from the vault to load full context. + +## Operational Rules + +- Single-file project — everything lives in `vidflow.html` +- No build step, no framework, no external dependencies +- Local dev: `python3 -m http.server 8080` (must be HTTP, not file://) +- Never hardcode API keys diff --git a/vidflow.html b/vidflow.html new file mode 100644 index 0000000..5ff9d4a --- /dev/null +++ b/vidflow.html @@ -0,0 +1,1010 @@ + + + + + +VIDFLOW + + + + + + + + + + +
+
+ +
Music Video Television
+
YouTube Data API v3 Key
+ +
+ Get a free key at Google Cloud Console → + Enable YouTube Data API v3 → Credentials → Create API Key.
+ No Google login needed to watch videos. +
+ +
+
No key? Demo mode (search disabled, add by URL works)
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+ +
Your Music Video Channel
+
+
🔍 SEARCH
+
🔗 PASTE URL
+
+
+
+
+ +
+
+
+
TAP TO WATCH
+
+
+ + + +
+
VIDFLOW
+
+
+ +
+
+ + + +
+
+ +
+
+
+ +
+
NOW PLAYING
+
+
+ Select a channel above to begin +
+
+
+ + + + + +
+
+ +
+
+
SPACE · ←→ · ↑↓ vol · +/- ch · S shuffle · C channels · P pop-out · ESC
+ +
+
+
CHANNELS
+ +
+
+
MY LIST
+
SEARCH
+
ADD URL
+
+
+
+
CH1
+
+ + + +