Development
You’ll need Node.js 24 or later for the browser foundation. The Python reference also needs an Apple Silicon Mac and uv. The CONTRIBUTING guide covers the workflow for pull requests.
git clone https://github.com/Eric-Fithian/piano-duet.gitcd piano-duetnpm cinpm ci --prefix sitenpm run dev # app at http://127.0.0.1:5173, docs under /docsThe browser app is under construction: Reading, Drills and Library recording import use the local service and the pinned model catalog. The browser downloads model files when a mode first needs them. For the Python reference, run make setup to install its dependencies, models and browser test engines, then make dev to start it at http://127.0.0.1:8765. Python edits restart that server; browser edits refresh its page without reloading the models.
Account sign-in
Section titled “Account sign-in”Account sync is implemented, and Google is configured for launch. Production and preview builds enable its button; the first real account sign-in still needs verification. Practice history also stays on the device. The sign-in options are:
- Email link: Choose an email provider such as Resend or Postmark and a domain you control. The domain owner must authorize the provider and add its DNS verification records; a
*.vercel.appaddress cannot be verified as the sending domain. Configure custom SMTP in Supabase and verify delivery to a public address. Supabase’s default sender is limited to project-team addresses. Only after verification, setSUPABASE_EMAIL_ENABLED=truefor the app build. It defaults to false. - Google (launch choice): In the chosen Google Cloud project, configure the OAuth consent screen and create a Web application OAuth client. Add
https://piano-duet.vercel.appas an authorized JavaScript origin andhttps://tbiuoywaqiiqjeezrybs.supabase.co/auth/v1/callbackas an authorized redirect URI. Use theopenid,emailandprofilescopes. Add any preview origins individually if needed; Google does not accept wildcard origins. Put the client ID and secret in the Supabase Google provider configuration and enable the provider.SUPABASE_GOOGLE_ENABLED=trueenables the button in production and preview builds; it defaults to false. Google sign-in needs no sign-in email. See Supabase’s Google setup. - Apple later: Use an Apple Developer account to configure the app identifier, web Services ID, signing key and redirect for Sign in with Apple, then configure it in Supabase and the app.
Checks
Section titled “Checks”make check # lint, Python, TypeScript and browser testsmake lint # ruffmake test # pytest, Node and Playwright testsmake benchmark # the real models on synthetic audioThe basic make check suite does not download model weights. CI also downloads and caches the pinned published models for parity and end-to-end microphone checks. Full-model comparisons and their requirements are described in Browser inference measurements.
The benchmark renders a two-handed piano phrase, checks note recognition at three input levels, and measures transcription and time to the first generated note on the actual local models. Synthetic benchmark audio and metrics go to .cache/benchmark/. It is a repeatable smoke test, not an estimate of accuracy on your acoustic piano.
The website
Section titled “The website”The documentation site lives in site/ and is built with Astro Starlight.
make site # http://localhost:4321/docs, with live reloadPages are Markdown files in site/src/content/docs/. Every page has an Edit page link at the bottom.
Layout
Section titled “Layout”| Path | What’s there |
|---|---|
src/piano_duet/ |
The Python server, models and curriculum. See Architecture. |
src/piano_duet/static/ |
The Python reference’s browser interface |
src/core/ |
Portable TypeScript calculations being compared with the reference |
tests/ |
Python, Node and browser tests |
site/app/ |
The browser app foundation, including its SQLite and model workers |
site/src/content/docs/ |
This documentation |
.cache/ |
Downloaded models, samples and notation fonts (ignored by Git) |
.local/ |
Your learner database (ignored by Git) |
Conventions
Section titled “Conventions”- Fail fast: no silent fallbacks. An unexpected state raises, and model errors are shown rather than hidden.
- Comment the why, not the how, and explain every regular expression.
- Every Python file has a
main()right after its imports and constants. - Run commands from the project root; paths such as
.cacheare relative to it.
The model settings flow has an additional full-model browser check: node tests/inference/model-settings.mjs chromium or node tests/inference/model-settings.mjs webkit. It downloads the pinned models into a disposable browser profile and tests fixed, non-user inputs. Chromium requires the Mac’s Apple WebGPU adapter. Playwright WebKit may report its existing large-Blob loading failure for Aria and the score model; the check still requires the other models and samples to pass.