A fully client-side, search-only web UI for the open, community-contributed SimpMusic lyrics database. It lets anyone search plain and time-synced lyrics (plus community translations) keyed by YouTube video ID, read the API reference, and find content-removal / DMCA contact details.
The site is 100% static — no server, no build-time data. Everything is fetched
in the browser from the public API at https://api-lyrics.simpmusic.org/v1.
- Vite + vanilla TypeScript — no UI framework, no runtime dependencies.
- Hand-written CSS with design tokens — a plain, flat dark theme (GitHub/shadcn-zinc style) with a single pink accent.
- System fonts only (no web fonts, no external CDN).
- A tiny hash router with code-split views (
#/search,#/video/{id},#/docs,#/about).
npm install # install dependencies
npm run dev # start the Vite dev server
npm run build # type-check (tsc --noEmit) then build to dist/
npm run preview # serve the production build locallyType-checking and building are the way to verify changes:
npx tsc --noEmit
npm run buildNote: the live API sits behind Cloudflare bot protection, so
curl/noderequests from a terminal are blocked and return an HTML challenge page. Real browsers work fine — verify data flows in the browser, not from the shell.
All deploy-specific values live in one file: src/config.ts.
API_BASE— the API origin + version prefix (https://api-lyrics.simpmusic.org/v1).CONTACT_EMAIL— the address used for content-removal / DMCA links (contact@maxrave.dev).LINKS— public repo / Swagger URLs shown in the Docs and About views.
Change these constants and nothing else needs touching.
The Docs view is rendered entirely from src/data/openapi.json — the single
source of truth. Endpoints, parameters, and schemas are generated from the spec;
if an endpoint is not in the spec, it does not appear.
To refresh the spec, download it from the running service in a browser (the terminal is Cloudflare-blocked):
- Open
https://api-lyrics.simpmusic.org/v3/api-docsin a browser. - Save the JSON response over
src/data/openapi.json.
npm run build emits a static bundle to dist/. The app uses a relative base
(base: './' in vite.config.ts) and hash-based routing, so it deploys to any
static host — including subdirectories — without server-side rewrite rules.
Just serve the contents of dist/.
index.html # shell + boot loader
public/ # favicon.svg, robots.txt
src/
main.ts # bootstrap + CSS imports
config.ts # API_BASE, CONTACT_EMAIL, links (single source)
router.ts # hash router with lazy views
api.ts # typed fetch client + result narrowing
lrc.ts # tolerant LRC parser
types.ts # shared domain + result types
data/openapi.json # vendored OpenAPI spec (drives the Docs view)
ui/ # dom builders, icons, format, states, toast, chrome…
views/ # search, detail, docs, about
styles/ # tokens, global, components, content, search, detail, docs
Contributor display names are shown; contributor email addresses are never rendered anywhere in the UI. Lyrics are community-contributed and provided for educational and personal, non-commercial use only. Rights holders can request removal via the contact address above (see the About page).