尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
A StarCraft-inspired sound effects board. Chunky console keys press down and light up as they play. It has hotkeys and quick filters, every key can play your own sound file, and your keys (stored in a Postgres database) and clips (stored in Vercel Blob) can sync across devices.
npm run dev needs the Vercel CLI linked to the project (npx vercel link) and the environment variables below (npx vercel env pull).查看完整 README ↗A StarCraft-inspired sound effects board. Chunky console keys press down and light up as they play. It has hotkeys and quick filters, every key can play your own sound file, and your keys (stored in a Postgres database) and clips (stored in Vercel Blob) can sync across devices.
npm install
npm run dev # vercel dev: the page plus the /api storage routes
npm run dev:static # the page only, no cloud sync, at http://localhost:3000
npm run dev needs the Vercel CLI linked to the project (npx vercel link) and the environment variables below (npx vercel env pull).
At vercel.com/new, import this GitHub repo. Leave Framework Preset on Other with no build command and no output directory. Every push to main redeploys. From the command line, npm run deploy runs vercel --prod.
vercel.json sets security headers, keeps sw.js and the manifest uncached so updates reach users, and caches icons for a week.
Without these steps the board still works; keys and clips just stay in each browser.
DATABASE_URL automatically (POSTGRES_URL also works). The tables are created on first use; db/schema.sql documents them.BLOB_STORE_ID, or BLOB_READ_WRITE_TOKEN on older connections).DECK_PASSWORD with a passcode of your choice, for all environments.If you created the Blob store with Public access instead, also set DECK_BLOB_ACCESS=public. Private is recommended: clips are only served through the app, to someone who has the passcode.
deck_keys table: label, faction, sound (synth preset, spoken line or clips), hotkey, colour, volume, pitch, favourite, its clips in play order (clips, a JSON list) and whether they play in order or at random (play_mode), in board order. The master volume and last-saved time are in deck_settings. Rows saved before multi-clip keys (single file_id / clip_path) are read as a one-clip list.layout.json in Blob storage) is imported automatically the first time the database is read while empty.clips/. Removing or replacing a clip in the editor, switching the key to a built-in sound, or removing the key deletes the clip from the store when no other key uses it.All routes require the passcode in an x-deck-pass header.
| Route | Purpose |
|---|---|
GET /api/layout | Saved board from the database: { layout: { pads, master } | null, savedAt } |
PUT /api/layout | Save the board to the database (JSON body { pads, master }, up to 500 keys) |
POST /api/clips | Upload one clip: raw audio body, Content-Type: audio/*, X-File-Name header → { path } |
GET /api/clips?path=clips/… | Stream one clip |
GET /api/clips | List stored clips from the catalogue, each with inUse (whether any key plays it) |
DELETE /api/clips?path=clips/… | Delete one clip |
The site is a Progressive Web App. In Chrome or Edge, use the install icon in the address bar. On iPhone or iPad, use Share → Add to Home Screen. Once installed it opens in its own window and works offline. Fonts are cached after the first online visit.
When you change index.html or the icons, bump VERSION in sw.js so installed copies fetch the new files.
| File | Purpose |
|---|---|
index.html | The app: markup, styles and script |
api/layout.js | Load and save the board's keys in Postgres |
api/_db.js | Database connection, table setup and key ↔ row mapping (not a route) |
db/schema.sql | Table definitions for reference |
api/clips.js | Upload, stream, list and delete clips in Blob storage |
api/_lib.js | Passcode check and shared helpers (not a route) |
sw.js | Service worker for offline use |
manifest.webmanifest | App name, colours and icons for install |
icons/ | App icon (SVG source plus 192 and 512 px PNGs) |
vercel.json | Headers and URL settings for Vercel |
package.json | @vercel/blob and @neondatabase/serverless dependencies, dev/deploy scripts |
Space stops all sounds, / focuses search, Esc clears filters.nuclear-launch-detected.mp3) is added to that key's clips, so marine-1.mp3 and marine-2.mp3 both land on Marine. Any other file becomes a new key.Paused. The Mission tracker tab is hidden for now; the Soundboard is always shown. The code is still in
index.htmland saved tracker data is kept (and still syncs). To bring it back, setTRACKER_ENABLED = trueinindex.html.
Switch to Mission tracker with the tab under the header (or open the site with #mission). It follows one tabletop game at a time, for StarCraft: The Miniatures Game or any similar skirmish game, through its rounds and phases.
Mission setup edits the whole mission: name, rounds, VP target, phases (with steps, reorderable), resources and their round-start rule, objectives with VP per round, and the phases each item is shown in, plus initiative and sound cues. Save as mission keeps it for reuse; pick it later from Start from a saved mission. The app ships only a generic starter mission, so enter the official mission's phases, objectives and round rules from your rulebook or mission cards.
To start a new game: pick the mission in Mission setup and Apply, then click New game twice. That resets round, scores, resources, objectives and the log, keeping player names, and applies the round-start rules for round 1.
The tracker is saved in the browser (rtsdeck.tracker) and, when Cloud is connected, with the board in the database (deck_settings.tracker), so a phone at the table and a laptop see the same game. Missions saved by earlier versions are converted automatically.
With Cloud connected, everything that describes your board is saved in the database, and the audio files in Blob storage:
| Data | Where |
|---|---|
| Keys: label, faction, sound (synth preset, spoken line or clips), hotkey, colour, volume, pitch, favourite, play mode, board order | deck_keys (one row per key) |
| Which clips each key plays, in order | deck_keys.clips |
| Master volume, last-saved time | deck_settings |
| Mission tracker (paused): missions, saved missions, current game | deck_settings.tracker |
| Every uploaded audio file: name, type, size, upload time | deck_clips (catalogue) |
| The audio files themselves | Blob storage, clips/… |
Kept on each device only, on purpose:
rtsdeck.cloud);rtsdeck.v1, rtsdeck.tracker) and of the audio (IndexedDB rtsdeck), so playback is instant and the app works offline.Saving is reliable: changes are saved to the database within a second. If the network or server fails, saves retry on their own with growing waits (the Cloud button shows Cloud • until they land). Changes made offline are saved when the connection returns, a change made just before closing the tab is sent on the way out, and an app opened while the server is unreachable connects once it's back. Failed clip uploads are retried too. Clips over 4 MB stay on the device that added them.
You can see it happen: every action that reads from or writes to the server shows a small toast in the corner (top of the screen on phones): a spinner while it runs (Saving changes…, Uploading marine.wav…, Loading clip…, Downloading clips · 3 of 8, Syncing with cloud…), then a brief tick when it's done (Saved, Clip removed from cloud), or a red note if it failed (Not saved yet · retrying). The Cloud button's light pulses while the server is busy, Connect shows a spinner while connecting, and a key's light pulses while its clip is fetched from the cloud.
The clip catalogue (deck_clips) is updated on every upload and delete, and resynced with Blob storage (files added or removed outside the app are picked up). GET /api/clips lists every stored file with whether a key still uses it.
This repo ships no game audio. The built-in effects are original synthesized imitations. To use the real game sounds, extract them from your own StarCraft install (for example with CascView) and load them with ⇪ Upload or Load clips. Keep those files out of this repo, since the game audio is Blizzard's copyrighted material. A private Blob store keeps them behind your passcode.
Fan-made project, not affiliated with Blizzard Entertainment.