个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A free music player with full songs, live lyrics, karaoke, story cards and your library on every device.
Spindle is built like an after-hours record store: a living colour field behind everything, a crate of records to dig through, album sleeves you can turn over, and a turntable you can scratch. Every song plays in full, it's free, and there are no ads.
The name is the pin at the centre of a turntable that every record spins on. In the wordmark, the dot of the i is a tiny record that spins while music plays.
Listening
Your library
Sharing
Everywhere
| Layer | What |
|---|---|
| App | React 18, TypeScript, Vite, Framer Motion, Zustand |
| Graphics | WebGL colour field, Canvas story cards, Web Audio visuals and vocal remover |
| Accounts & sync | Supabase (Postgres, Auth, Realtime) with row-level security |
| Server | Vercel functions: importer, share pages, link-preview images |
| Music | YouTube IFrame API, iTunes Search, Audius, LRCLIB lyrics |
src/
api/ iTunes, YouTube lookup, Audius and lyrics clients
components/ player, deck, share sheet, story maker, sign-in gate…
lib/ sync engine, recommendations, autoplay, history & stats, story cards, offline
pages/ Home, Browse, Search, Library, playlists, Stats, Settings, About…
store/ the player and library state (persisted, synced)
server/ importer and share-page logic, shared by dev and Vercel
api/ Vercel functions: /api/import, /api/share (/s/:code), /api/og
supabase/ database schema and branded email templates
public/ brand assets, service worker, privacy and terms pages
src/lib/sync.ts): each library is one JSON document of keyed entries. Devices send only what changed; the database merges entry by entry (newest wins, deletions carry over), and Realtime tells the other devices to pull.src/components/AudioEngine.tsx): finds the YouTube upload for each song, scoring title, artist and length, and falls back to the iTunes preview. Audius tracks play as audio files.src/lib/recommend.ts): the popular songs of the artists a playlist leans on, with name lookups for songs from YouTube or Audius.npm install
npm run dev
Open http://localhost:5173. Without Supabase keys, accounts are switched off and everything is saved on the device, which is handy for working on the UI.
npm test
Vitest covers stats, recommendations, share pages (including escaping), the importer's link checks and the database rules, which run against a real Postgres in memory (PGlite). GitHub Actions runs the type-check, tests and a build on every push.
Create .env.local (never committed):
VITE_SUPABASE_URL=https://<project>.supabase.co
VITE_SUPABASE_ANON_KEY=<publishable key>
VITE_AUTH_PROVIDERS=github # sign-in buttons to show: github, google
VITE_DISCORD_INVITE=<optional> # invite link for the community Discord, shown on Feedback and Settings
VITE_YT_API_KEY=<optional> # YouTube Data API, only used if the free mirrors fail
The Supabase URL and publishable key are public by design; row-level security keeps every library private to its owner.
supabase/schema.sql in the SQL Editor.https://spindle-bice.vercel.app, redirect URLs for production and http://localhost:5173.confirm-signup.html (subject {{ .Token }} is your Spindle code); Reset password uses reset-password.html.https://<project>.supabase.co/auth/v1/callback, then paste its ID and secret under Providers.#/admin shows all feedback and crash reports:
insert into public.admins select id from auth.users where email = '[email protected]' on conflict do nothing;
insert into private.settings values ('discord_webhook', 'https://discord.com/api/webhooks/…')
on conflict (key) do update set value = excluded.value;
The project is deployed on Vercel and every push to main goes live. To deploy your own copy, import the repo into Vercel (free Hobby plan) and add the environment variables above.
desktop/ is a Tauri app: a small native window around the live site, using the browser engine already on the computer (WebView2 on Windows), so the installer is a few MB and it updates whenever the site does. It adds:
spindle:// link), and updates that install from inside the appcd desktop
npm install
npm run dev # run it
npm run build # make an installer in src-tauri/target/release/bundle
It needs Rust. To show Discord status, create an application at discord.com/developers named Spindle and build with its Application ID in SPINDLE_DISCORD_APP_ID. Pushing a tag like desktop-v1.0.0 builds Windows and Mac installers on GitHub and publishes them as a release (set the ID as an Actions variable of the same name).
Updates: releases are signed so installed apps can update themselves. The signing key lives outside the repo; its contents go in the TAURI_SIGNING_PRIVATE_KEY Actions secret, and its public half is in tauri.conf.json. To ship an update, raise version in desktop/src-tauri/tauri.conf.json and Cargo.toml, then push a new desktop-v… tag. The release text becomes the notes in the app's update card. Website changes need no app update: the app loads the live site.
.env.local and Vercel's environment settings.Found something? Please email the address on the privacy page instead of opening a public issue.
| Key | Action |
|---|---|
| Space | Play / pause |
| ← / → | Seek 5 seconds |
| Shift + ← / → | Previous / next song |
| ↑ / ↓ | Volume |
| M | Mute |
| F | Open / close the full player |
| / or Ctrl+K | Search |
Songs stream from YouTube, Apple's iTunes previews and Audius; lyrics come from LRCLIB and lyrics.ovh. Spindle doesn't host or sell any music.
Somesh Sanjay Thakur, Full-Stack & AI Automation Dev. Crafting reactive web apps and autonomous agents with Next.js, React, Tailwind and Python. Shipping at the UX + LLM intersection.
© Somesh Sanjay Thakur. All rights reserved.