From 1ee6afe0c6073d271e0379e3e4174a9308ce8afe Mon Sep 17 00:00:00 2001 From: paramcodes Date: Sat, 17 Oct 2026 18:35:59 +0530 Subject: [PATCH 01/12] docs: refresh the README and wiki with newly recorded media Recapture screenshots and the demo video/GIF from a production build, and add mobile and collapsed-queue captures. Rewrite the README features and stack to the current app, and update the stack, architecture, design-system, workflow, and roadmap docs to match. Add scripts/capture-readme.mjs so the media can be regenerated. --- README.md | 138 +++++++++++++---------- artifacts/readme/demo.gif | Bin 1750183 -> 2763674 bytes artifacts/readme/demo.mp4 | Bin 434363 -> 275139 bytes artifacts/readme/demo.webm | Bin 211614 -> 1172294 bytes artifacts/readme/home.png | Bin 74079 -> 222107 bytes artifacts/readme/library.png | Bin 61130 -> 91078 bytes artifacts/readme/login.png | Bin 13184 -> 11438 bytes artifacts/readme/mobile-home.png | Bin 0 -> 443633 bytes artifacts/readme/mobile-queue.png | Bin 0 -> 234701 bytes artifacts/readme/playing.png | Bin 74055 -> 223224 bytes artifacts/readme/playlist.png | Bin 45726 -> 106594 bytes artifacts/readme/queue-collapsed.png | Bin 0 -> 251717 bytes artifacts/readme/search.png | Bin 76816 -> 102794 bytes artifacts/readme/signup.png | Bin 13779 -> 11883 bytes docs/architecture.md | 45 ++++---- docs/design-system.md | 17 +-- docs/roadmap.md | 100 +++++++++-------- docs/stack.md | 40 +++---- docs/workflows.md | 40 +++++-- scripts/capture-readme.mjs | 162 +++++++++++++++++++++++++++ 20 files changed, 380 insertions(+), 162 deletions(-) create mode 100644 artifacts/readme/mobile-home.png create mode 100644 artifacts/readme/mobile-queue.png create mode 100644 artifacts/readme/queue-collapsed.png create mode 100644 scripts/capture-readme.mjs diff --git a/README.md b/README.md index a4a7d2c..b718194 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # sunao -A Spotify-like music player. Red theme, dark UI. Built with Next.js 15, Tailwind v4, shadcn/ui, Supabase, Zustand, and TanStack Query. +A Spotify-like music player. Red theme, dark UI. Built with Next.js 16, React 19, Tailwind v4, shadcn/ui on Base UI, Supabase, Zustand, and TanStack Query. **Live demo:** https://sunao-omega.vercel.app - +![sunao demo: play an album, search, open a playlist, collapse the queue, like a track](artifacts/readme/demo.gif) -Fallback (GIF): ![Demo](artifacts/readme/demo.gif) +Full-resolution video: [MP4](artifacts/readme/demo.mp4) · [WebM](artifacts/readme/demo.webm). ## Screenshots @@ -14,59 +14,73 @@ Fallback (GIF): ![Demo](artifacts/readme/demo.gif) |---|---| | ![Home](artifacts/readme/home.png) | ![Search](artifacts/readme/search.png) | -| Library | Playlist detail | +| Library | Playlist | |---|---| | ![Library](artifacts/readme/library.png) | ![Playlist](artifacts/readme/playlist.png) | -| Login | Sign up | Now playing | -|---|---|---| -| ![Login](artifacts/readme/login.png) | ![Sign up](artifacts/readme/signup.png) | ![Playing](artifacts/readme/playing.png) | +| Now playing | Collapsed queue | +|---|---| +| ![Now playing](artifacts/readme/playing.png) | ![Collapsed queue](artifacts/readme/queue-collapsed.png) | + +| Sign in | Sign up | +|---|---| +| ![Sign in](artifacts/readme/login.png) | ![Sign up](artifacts/readme/signup.png) | + +| Mobile home | Mobile queue | +|---|---| +| ![Mobile home](artifacts/readme/mobile-home.png) | ![Mobile queue](artifacts/readme/mobile-queue.png) | + +Captured from a production build; regenerate with [scripts/capture-readme.mjs](scripts/capture-readme.mjs). ## Features Playback -- Play / pause, previous / next track -- Seek scrubber with position + duration -- Playback speed (0.5×, 1×, 1.25×, 1.5×, 2×) -- Like / unlike the current track -- Now-playing card and queue panel; click any queue item to play -- Auto-advance to the next track when a song ends -- Audio: 30-second previews + album artwork fetched from the iTunes Search API (no API key); cached per title+artist, falls back to a bundled sample tone on failure +- Play / pause, previous / next, and auto-advance when a track ends +- Seek scrubber bound to the audio element's real duration, with position and total labels +- Playback speed: 0.5×, 1×, 1.25×, 1.5×, 2× +- Like / unlike the current track (session-only, in memory; not persisted to Supabase) +- Buffering spinner, debounced 200ms so it does not flash on fast loads +- Audio: 30-second previews from the iTunes Search API (no key), cached per title + artist, falling back to a bundled sample tone +- Album artwork from the iTunes CDN, served through `next/image` Browse -- Home: album grid + song list (click a song to play) -- Search: filter songs by title or artist; empty state when nothing matches -- Library: list playlists, create a playlist (writes to Supabase, or a local store without a backend) +- Home: album grid (click an album to play it) plus the full song list +- Search: filter songs by title or artist, with an empty state +- Library: list playlists and create a new one (writes to Supabase, or to a local store without a backend) - Playlist detail: cover, song count, "Play all", remove a song, empty state -Auth (Supabase) -- Email + password sign in / sign up -- Proxy (`src/proxy.ts`) refreshes the session and protects `/library` and `/playlist/*` -- Graceful no-op when Supabase env vars are missing, so the app runs without a backend +Now playing and queue +- Now-playing card and a windowed (virtualized) queue; click any row to jump to it +- Collapsible queue panel at `lg` and up: narrows to a 40px rail instead of unmounting, so the toggle stays reachable and scroll position survives; the collapsed content is `inert` +- Mobile queue in a bottom sheet + +Auth (Supabase, optional) +- Email and password sign in / sign up, plus an `/auth/callback` route for confirmation links +- `src/proxy.ts` refreshes the session and protects `/library` and `/playlist/*` +- With the Supabase env vars unset the app runs without a backend: static seed data, in-memory playlists, and no auth Mobile - Bottom nav (Home / Search / Library / Queue) below `lg`, replacing the hidden sidebar -- Queue opens in a bottom sheet -- Responsive player bar: compact player with a progress line on phones, full controls from `md` up +- Compact player bar with a 2px progress line; the seek bar and speed control appear from `md` up +- Safe-area padding on the bottom nav Polish -- Loading skeletons for the home route (reduces layout shift) -- Empty states for search and playlists -- Accessibility: ARIA labels on player controls, tooltips with keyboard hints, Space-bar play/pause, focus-visible styles -- Performance: `optimizePackageImports` for lucide-react and react-query; lazy-loaded queue panel -- Motion: shared easing tokens, pointer-gated hover, press feedback, reduced-motion aware +- Loading skeletons for the home route; empty states for search and playlists +- Accessibility: ARIA labels and states on player controls, tooltips with keyboard hints, Space toggles play/pause, focus-visible ring, `inert` collapsed panels +- Motion: shared easing tokens, pointer-gated hover, press feedback, staggered album entrance, heart pop, artwork pulse, and reduced-motion support +- Performance: `optimizePackageImports` for lucide-react and react-query ## Tech stack See [docs/stack.md](docs/stack.md) for the full list with rationale. Highlights: -- Next.js 15 (App Router, Turbopack) + React 19 +- Next.js 16 (App Router, Turbopack) and React 19 - TypeScript (strict) -- Tailwind CSS v4 + shadcn/ui (Radix primitives) -- Zustand (player state) + TanStack Query (server state) -- Supabase (Postgres, Auth, RLS) + Zod (boundary validation) -- Vitest + React Testing Library, Playwright (E2E) -- Biome (lint + format), Husky + lint-staged +- Tailwind CSS v4 and shadcn/ui primitives on Base UI +- Zustand (player state) and TanStack Query + Virtual (server state and the queue) +- Supabase (Postgres, Auth, RLS) and Zod (boundary validation) +- Vitest and React Testing Library, Playwright (E2E) +- Biome (lint and format), Husky and lint-staged ## Getting started @@ -74,20 +88,20 @@ Prerequisites: Node 20+, pnpm 12+. ```bash pnpm install -cp .env.example .env.local # optional; app runs without Supabase +cp .env.example .env.local # optional; the app runs without Supabase pnpm dev ``` Open http://localhost:3000. -Environment variables (optional, for Supabase data + auth): +Environment variables (optional, for Supabase data and auth): ``` NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= ``` -Without them the app falls back to static seed data and skips auth. +Without them the app falls back to the bundled seed data and skips auth. ## Scripts @@ -95,7 +109,7 @@ Without them the app falls back to static seed data and skips auth. |---|---| | `pnpm dev` | Dev server (Turbopack) | | `pnpm build` | Production build | -| `pnpm start` | Run production build | +| `pnpm start` | Run the production build | | `pnpm typecheck` | TypeScript strict check | | `pnpm lint` / `pnpm lint:fix` | Biome check / autofix | | `pnpm format` | Biome format | @@ -103,24 +117,42 @@ Without them the app falls back to static seed data and skips auth. | `pnpm test` / `pnpm test:watch` | Vitest | | `pnpm test:e2e` | Playwright | +To refresh the README media, run a server and point the capture script at it: + +```bash +node scripts/capture-readme.mjs # CAPTURE_BASE=http://localhost:3000, CAPTURE_OUT=artifacts/readme +``` + +It writes the screenshots, `demo.webm`, and the `demo.mp4` / `demo.gif` derived from it. Requires `ffmpeg`. + ## Project structure ``` src/ - app/ routes (App Router), layout, globals.css + app/ routes (App Router): (app)/ shell group, login, signup, auth/callback components/ - ui/ shadcn primitives (button, slider, skeleton, empty-state, ...) - layout/ app shell (sidebar, player bar, queue panel) - hooks/ useAudio (HTMLAudioElement <-> store sync) + ui/ shadcn primitives (button, dialog, sheet, slider, tooltip, kbd, skeleton, empty-state) + layout/ app shell (sidebar, player bar, queue panel, mobile nav) + features/ feature components (playlist form) + hooks/ use-audio, use-delayed-flag stores/ Zustand (player) - lib/ utils, query client, Supabase clients, schemas, queries, data + lib/ utils, query client, Supabase clients, schemas, queries, iTunes, data types/ shared types docs/ wiki (stack, architecture, design system, workflows, roadmap) e2e/ Playwright specs supabase/ migrations + seed -scripts/ check-comments.mjs +scripts/ check-comments.mjs, capture-readme.mjs ``` +## Docs + +- [docs/README.md](docs/README.md) — wiki index +- [docs/stack.md](docs/stack.md) — what we use and why +- [docs/architecture.md](docs/architecture.md) — app structure and data flow +- [docs/design-system.md](docs/design-system.md) — tokens, components, motion +- [docs/workflows.md](docs/workflows.md) — dev commands and PR flow +- [docs/roadmap.md](docs/roadmap.md) — the multi-phase plan + ## Contributing 1. Branch from `main`: `feat/phase-N-...` or `fix/...`. @@ -129,20 +161,12 @@ scripts/ check-comments.mjs 4. Open a PR. CI must pass (typecheck, lint, comments, test, build). Squash-merge after green; delete the branch. Notes for contributors -- Comment policy: only allowlisted comments (SPDX/license, eslint-disable, @ts-expect-error, TODO/FIXME with an issue number, public JSDoc). Everything else is rejected by `pnpm check:comments`. Keep code self-documenting; comment only a non-obvious *why*. +- Comment policy: only allowlisted comments (SPDX/license, biome-ignore, @ts-expect-error, TODO/FIXME with an issue number, public JSDoc). Everything else is rejected by `pnpm check:comments`. Keep code self-documenting; comment only a non-obvious *why*. - Pre-commit (Husky + lint-staged) runs Biome on staged files. -- Verification skill + feature map live under `.opencode/skills/verify-sunao/` and `README.md` feature map; update them when adding a phase. - -## Docs - -- [docs/README.md](docs/README.md) — wiki index -- [docs/architecture.md](docs/architecture.md) — app structure and data flow -- [docs/design-system.md](docs/design-system.md) — tokens, components, motion -- [docs/workflows.md](docs/workflows.md) — dev commands and PR flow -- [docs/roadmap.md](docs/roadmap.md) — multi-phase plan +- Verification skill and feature map live under [.opencode/skills/verify-sunao/](.opencode/skills/verify-sunao/); keep them current when you add a feature. ## Status -All phases 0–6 complete. Deployed to https://sunao-omega.vercel.app. -EOF -echo written \ No newline at end of file +Phases 0–6 are complete and deployed to https://sunao-omega.vercel.app. Work after the +original plan (real iTunes artwork and previews, motion polish, queue virtualization, the +collapsible queue panel) shipped on top of it. See [docs/roadmap.md](docs/roadmap.md). diff --git a/artifacts/readme/demo.gif b/artifacts/readme/demo.gif index 5dc80227201be1af71ba76e6cafa438aad84f14b..54c80230d9aeace836110efdf83a4fbffab7b518 100644 GIT binary patch literal 2763674 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 LV_7Ned+|EjA3VC?#sBde z4EgzA*E{e5EdUT9TK{NJv4O;f6b2D)2*Dsjfd~pNAh;k=qQi?BGBVgOfy9Ik99V1! z$pR#Y4kuHFT!~WUOO`NQ#-usZW=othbCx{G0%e8}4mLEQk&!uWHR&wd+=|T*ZbZ3)bvcv}4bzO(#MU&vq@lHf`9rZRft-oA>YC!AT1MaG(H!0}K>2U=X3fgXYhpL*KwK#PtvcuWvxn z9YqTjE5wf{U;p0xdGzVkuV>$We2Wh#LZHx)oy7KoAu?Qepg@6h=$vzozX2a8FoFoG z&eLg3&&mO6-VLX;$|kU|MDv@pX9JLK@g4MWsWLlQXPAcF}UNYS|!8z8U&0H>2N zMjEB7F+dx0#Bs+Nb?lMH8-ElsNFseK5=bMHL~_X?m28s9BcGHqN-CYCF#;q=$RPz9 zQpn+jF24*DOfSh4v&=EmM03qE+cfh{HQkI8PB!V3v(7p5#BZrSwuxHN|vOPdf#5)K3*f000CEXrO=xD0=IG z>|OwBq5p&mnn8maG#F?g@pjN)hZTSoHdtbZHMUq}k5x8VW|wug*|1^N*t*ql0<5EU3b})H(q+-wf9|o=e<|oeB)&(L825e zs;F=?cr**D>6o*B5CYsT4To_F?HXF~-jKmY|0DEa{_iLy@H>lzHJ1U&;2@Fpham5>F{PDvhUtDs>DTjP=%mw!wLB1UrkaPZ^Oj>l(rySk% z(yL7Ubk$LJy>-}Gmwk28A7Fw@Edk|IcR_a_^mpHb?|pdQiwB5zIo_F zm7e+OpRYc8>a%}TQ3V8G;D87ajzB+b6)Ha=6gHS)1FCnG)@}Byj{k%C>xch-`SGV; zfBWoV|YUv;t(u#xl3M91~Zra@MS|3V*e3? zctjv3k%)ZxSPPM`q}V8Gw}_DMzxXm+n#W$b9j%2&D)ma~*)En9iZ zSlS3nTH=!Ml!rWDCQq2bBqlJ8`AcLD^Gn#Xp7xme%OP%RtCpz7EPIz|Uo93gHLP8*sZe>M+D&!|p9{+H{44BX% z0u3lY33^b2CUl?*E$BiW+E9oh^q~@ksK5kf!VwnChB@Tu3_ZHhkLnPlBNb^$JBk2~ zc?^k5RH6}Ex>A?2RHiYdX%%gH#VO|0iaNb1PiZ!^p%v|DNy`8s*bR=v8_uXeSm4?5}~v*R2F+)YM~Ol4a`*P{qTC$0jL zYhCGjR~XqfuXvs7Uj5ov!0I)ye3dKTK-b6zhG zNXdI%^QM=i=v}XRFUCW>%oL{ceQAB=YhRkum!&@C?@s;O)BoZ$z*EfPagwtfDSZ(; zW-aT38suOHl_y-RUO!M(0W$Mon>;8n=INTYgV;WK5dm* zd*#(;8GG1F)v8*hFmHmBxdtRNJr8nQ+NOETW?pmo)LiB>v;P^+Yksqw?Mz#3;nQ2& zKD_O)-+53{AmG$ zy1$|xuz!I{G@~H^X`(Bt+yptdF)~=zur4dDXB}%>=Ni|$t~IZm9?aj|V| zY+@f<*~w=1jSEC%As2bb)0TF%qkU~?*Y0*S$eokD4do|C8Qk9%w`Z|T<#StE%j!n= zx(n64?}bk;3r`w=ewSDjx)dKNn3mC+us7mH$58y-39_Wy8%