Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
2.2 KiB
2.2 KiB
AGENTS.md
Apple Music–style music streaming frontend. Vanilla HTML/CSS/JS, zero dependencies, no build step, no backend/database by design.
Run / verify
- No package.json, no lint/test setup. Verification =
node --check js/*.jsplus a headless smoke test (load all scripts in avmcontext with stubbeddocument/localStorage/Audio, exercise all routes + player ops). - Serve locally:
python -m http.server 5173(or openindex.htmldirectly from file:// — everything works offline; audio streams from SoundHelix).
Architecture (non-obvious)
- Script order in
index.htmlis load-bearing:data.js→artwork.js→store.js→player.js→app.js. Top-levelconsts share global scope across files (classic scripts, NOT ES modules — don't convert to modules, file:// would break). js/data.jsbuilds the 111-song catalog at load time fromARTISTS/ALBUMSwith a seeded RNG (seeded()). Keep it deterministic — durations, plays, artwork patterns andD.topCharts()order all derive from seeds.js/app.jsrouting: hash-based, no router lib. Views register play contexts inctxMap[ctx](ctx string → song id array) BEFORE rendering rows that reference them viadata-ctx/data-index. All clicks go through one delegated[data-action]handler.Player.queuestores enriched song objects (viaD.song), not ids —playContext()normalizes either form.- Persistence:
Store(js/store.js) writes everything (likes, playlists, history, volume, shuffle, repeat) to onelocalStoragekeyaumusic-v1;Store.load()is called at file load. Changing the key or shape silently loses user data.
Gotchas
- Audio is SoundHelix MP3s. They send NO CORS headers: do NOT add
crossoriginto the audio element (playback breaks). Consequence: WebAudio analyser data is tainted/zeroed, sovizLoopin app.js has a synthetic-wave fallback — the zero-sum detection is intentional, not a bug. js/artwork.jsgenerates artwork as inline SVG data URIs; each is ~2–44 KB. Don't swap in external images — the site is meant to be fully offline-capable.- Card artwork click buttons (
.card-play) are nested insidedata-actionrows — the delegated handler relies onclosest()picking the innermost element.