CallerBuddy is a Progressive Web App for square dance callers to manage a collection of music (MP3) and lyrics (Markdown in the library; HTML/text on import), build playlists for a dance, and play songs with independent pitch and tempo control while reading lyrics on-screen. It is loosely inspired by SqView but redesigned from scratch as a modern, cross-platform PWA.
Run CallerBuddy Now in the browser: https://vancem.github.io/CallerBuddy/
To learn about using CallerBuddy, open the app above and read the CallerBuddy help. The rest of this file README is about how to BUILD or MODIFY CallerBuddy itself.
Before you can build CallerBuddy, you will need some developer software installed on your machine. None of this costs money, but you do have to trust it.
- Git (Git for Windows includes Git Credential Manager for GitHub sign-in)
- Node.js 20 or later (includes npm)
- Chrome or Edge (the File System Access API is Chromium-only; also used for manual app testing)
- A GitHub account, authenticated on this machine (see below) — required to
push changes; the GitHub CLI (
gh) is the easiest way to set this up
Git refuses to commit until your name and email are set. Run these once per machine (use the email on your GitHub account):
git config --global user.name "Your Name"
git config --global user.email "you@example.com"Confirm:
git config --global --get user.name
git config --global --get user.emailSetting your identity is not enough to push. You must also authenticate so Git — and Cursor, which shells out to your local Git — can talk to GitHub on your behalf.
Option A — GitHub CLI (recommended):
winget install GitHub.cli --accept-package-agreements --accept-source-agreementsgh is added to the PATH by the installer, but already-running terminals
(and Cursor itself) keep their old PATH. If gh is “not recognized”, fully
quit and restart Cursor — opening a new terminal tab in the same window is
not enough. Then:
gh auth loginAnswer the prompts:
- What account do you want to log into? →
GitHub.com - Preferred protocol for Git operations? →
HTTPS - Authenticate Git with your GitHub credentials? →
Yes - How would you like to authenticate? →
Login with a web browser
gh then shows a one-time code and opens
https://github.com/login/device. Sign in, enter the code, and authorize the
GitHub CLI. If the browser does not open automatically, paste that URL into
Chrome or Edge yourself.
Option B — Personal Access Token (PAT):
- On GitHub: Settings → Developer settings → Personal access tokens (fine-grained or classic). Create a token with repo access.
- On first
git push/git pullover HTTPS, when Windows asks for a password, paste the token (not your GitHub password). Git Credential Manager will store it for later.
Verify authentication succeeded:
gh auth statusAfter either option, Cursor can run Git commands using the same credentials.
If node / npm are not already on your PATH, install the LTS build with
winget (expect a UAC / administrator prompt):
winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreementsIf winget is unavailable, download the Windows LTS installer from https://nodejs.org instead.
Then close and reopen your terminal (and Cursor / VS Code, if the
integrated terminal still cannot find npm) so the updated PATH is picked up.
Confirm:
node -v
npm -vPowerShell may block npm.ps1 with an error like “running scripts is disabled
on this system.” Allow local scripts for your user account:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSignedOpen a new terminal afterward, then retry npm commands.
git clone https://github.com/vancem/CallerBuddy.git
cd CallerBuddy
npm installnpm install pulls in the Playwright package, but you still need the browser
binaries once per machine. Run this in a normal developer terminal (same place
you run npm commands):
npx playwright install chromiumWithout this step, npm run ci and npm run e2e fail because Chromium is
missing.
If you want a real folder of test songs to point the app at during manual testing:
node scripts/generate-test-data.cjsThis creates a test-data/ folder with 3 short WAV files (2 singing calls
with Markdown lyrics, 1 patter with no lyrics).
Start the Vite dev server with hot-module replacement:
npm run devThen Ctrl-click the URL shown in the terminal (default http://localhost:5173).
The predev hook automatically injects the version from package.json into
src/version.ts and public/manifest.json.
npm run buildThis runs tsc (type-checking production code via tsconfig.build.json, which
excludes test files) then vite build. Output goes to dist/.
To preview the production build locally:
npm run previewTo simulate the GitHub Pages deployment path (serves under /CallerBuddy/):
# Windows
set BASE_PATH=CallerBuddy
npm run build
npm run preview
# macOS/Linux
BASE_PATH=CallerBuddy npm run build
npm run previewEach build embeds a version string (e.g. 0.1.0-pre.9 abc12345 or
0.1.0-pre.9 abc12345-dirty) in the app. The second part is the Git
commit hash (8 chars). A -dirty suffix means there were uncommitted changes
when the build ran.
To see exactly which source produced a build, use the hash with Git:
git show abc12345 # full commit details and diff
git log -1 abc12345 # one-line summaryOn GitHub: https://github.com/vancem/CallerBuddy/commit/<hash>.
Before pushing to main, run the same build + test pipeline that CI runs:
npm run ciThis executes npm run build (TypeScript type-check + Vite bundle), npm test
(unit tests), npm run lint, and npm run e2e (Playwright). If it passes
locally, the GitHub Actions build will pass too.
Tests live alongside the source files they cover (*.test.ts next to the
corresponding *.ts). Run npm test for the current count.
npm test # single run
npm run test:watch # re-run on file changesThey cover:
- Pure functions: time formatting, song filename parse/build, settings normalize, lyrics import, play-history math, song-table text filter
- Stateful logic:
AppStateplaylist operations, tab management, events - Mocked integrations:
scanDirectory,loadSongsJson,saveSongsJson,detectBPM, ZIP onboarding heuristics
Chromium-only tests in e2e/basic-flow.spec.ts. Run npm run e2e for the
current count (~a few seconds).
npm run e2e # headless run
npm run e2e:ui # interactive Playwright UIThe E2E tests mock the File System Access API entirely in-browser (no real files needed). They exercise: welcome screen, folder selection, song browsing, playlist building, and brief playback of both singing calls and patter.
CallerBuddy deploys to GitHub Pages via a GitHub Actions workflow that runs
on every push to main.
- Bump the version in
package.json(e.g.0.1.0-pre.8to0.1.0-pre.9). - Commit and push to
main. - The Deploy preview workflow builds and deploys automatically.
First-time setup: enable Settings > Pages > Source: GitHub Actions in the repo. See RELEASE.md for the full process and troubleshooting.
For private device debugging without a full deploy, RELEASE.md also documents a local dist/ server (npm run preview:pages) and an optional Cloudflare Tunnel approach to open that build on your phone over HTTPS.
Goal: searching for CallerBuddy (and CallerBuddy vancem) should find the app at https://vancem.github.io/CallerBuddy/ and the GitHub repo.
Manage indexing in:
- Google Search Console — property
https://vancem.github.io/CallerBuddy/ - Bing Webmaster Tools — same site URL
This file proves to Google that we own the GitHub Pages site. Search Console
issued it; Vite copies everything in public/ into dist/, so after deploy it
is served at:
https://vancem.github.io/CallerBuddy/google9f9f34b405a49230.html
Keep this file in public/ and do not rename or delete it unless you
re-verify ownership another way. Putting it only at the repo root does not work
— Google checks the Pages URL above, not a github.com/.../blob/... path. The
github.com/vancem/CallerBuddy repo page cannot use this HTML-file method (we
do not control github.com).
This file proves ownership to Bing (same pattern as Google’s HTML file). Bing Webmaster Tools issued it; after deploy it is served at:
https://vancem.github.io/CallerBuddy/BingSiteAuth.xml
Keep this file in public/ and do not rename or delete it unless you
re-verify in Bing Webmaster Tools. Like the
Google file, it must be published under the Pages URL, not only as a blob on
github.com.
Crawlers lean on the repo About fields (right sidebar). Keep them filled:
- Description — short product summary
- Website —
https://vancem.github.io/CallerBuddy/ - Topics — e.g.
square-dance,caller,music-player
gh repo view vancem/CallerBuddy --json description,homepageUrl,repositoryTopics
gh repo edit vancem/CallerBuddy --description "..." --homepage "https://vancem.github.io/CallerBuddy/" --add-topic square-dance- Do not remove
public/google9f9f34b405a49230.htmlorpublic/BingSiteAuth.xmlfrom the tree or from production deploys (verification can break if either disappears). - After a major URL or homepage change, request a recrawl in
Search Console (URL
inspection → Request indexing) and in
Bing Webmaster Tools (URL submission /
Site Explorer) for
https://vancem.github.io/CallerBuddy/. - Periodically (every few months, or when someone reports a search engine
can’t find us): check
site:vancem.github.io/CallerBuddyand"CallerBuddy" vancemin an incognito window on both Google and Bing; skim Search Console and Bing Webmaster Pages / indexing reports for coverage drops. - Keep the GitHub About description, homepage, and topics accurate when the product pitch changes.
- Prefer inbound links from pages search engines already know (GitHub profile README, Samples repo, caller forums, blog posts). Stars alone do little; links help.
- When improving crawlability of the app shell, keep a meaningful
<title>, meta description, and some static text inindex.html— the SPA body alone is nearly empty to non-JS crawlers.
| File | What it covers |
|---|---|
| CallerBuddySpec.md | Product specification: requirements, user workflows, UI layout, file conventions. Read this first. |
| BACKLOG.md | Active task list, design rules, design philosophy, and all major design decisions with rationale (framework choices, audio engine, state management, etc.). |
| FUTURE.md | Features deferred from V1 (named playlists, richer play-history filters, song structure analysis). |
| RELEASE.md | Versioning scheme and GitHub Pages deployment process. |
| src/caller-buddy.ts | Application singleton. Start here for the code: it owns all services, coordinates initialization, and handles the song-play lifecycle. |
| src/services/app-state.ts | Centralized state with EventTarget-based change notification. Manages tabs, playlist, settings, and playback state. |
| src/components/app-shell.ts | Root UI component. Renders the tab bar and dispatches to the view components. |
CallerBuddy/
src/
caller-buddy.ts # App singleton (entry point for logic)
main.ts # Bootstrap: creates singleton, mounts <app-shell>
help-content.md # In-app user help (Markdown)
help-toc.ts # Help table of contents (must match heading ids)
components/ # Lit web components
app-shell.ts # Root shell with tab management
welcome-view.ts # First-run folder picker
playlist-editor.ts # Song browser + playlist builder
playlist-play.ts # Now Playing view with break timer
song-play.ts # Single-song playback with controls
song-onboard.ts # ZIP/folder import review
lyrics-editor.ts # Shared lyrics Markdown editor
help-view.ts # In-app help tab
tab-bar.ts # Chrome-style tab strip
controllers/ # Panel resize, playlist drag-and-drop
services/ # Core services (no UI)
app-state.ts # Centralized state + events
audio-engine.ts # Web Audio + SoundTouchJS playback
bpm-detector.ts # Background BPM analysis
file-system-service.ts # File System Access API wrapper
song-library.ts # Scan folders, load/merge/save CallerBuddySongs.json
song-onboarding.ts # ZIP/folder import heuristics
lyrics-import.ts # HTML/text → lyrics Markdown
logger.ts # Logging with levels
models/ # Data models
song.ts # Song interface + parsing utilities
settings.ts # App settings (timers, panel sizes)
utils/
format.ts # Time formatting helpers
e2e/
basic-flow.spec.ts # Playwright E2E tests
scripts/
generate-test-data.cjs # Creates test WAV/lyrics files
inject-version.cjs # Stamps version into source + manifest
public/ # Static assets copied to dist (icons, manifest, SW, Google verify HTML)
| Technology | Purpose |
|---|---|
| Lit 3 | Web component framework for UI |
| Vite 7 | Dev server and production bundler |
| TypeScript 5.9 | Language (strict mode) |
| SoundTouchJS | Independent pitch shifting and tempo stretching |
| web-audio-beat-detector | Automatic BPM detection |
| Vitest | Unit testing |
| Playwright | E2E browser testing (Chromium) |
This project uses Cursor with AI assistance. When non-trivial changes are made,
a summary is logged to AI_Logs/Summary.YY-MM-DD.NN.description.md. These logs
capture what was changed, which files were touched, and why. See the
BACKLOG.md rules section for the full convention.