Adds Alma (sv), Alan, Northern English, Cori, Alba (British/Scottish)
and Joe, John, Norman (American) as optional voices downloaded one at
a time from Settings, with gender (measured pitch) and accent shown in
the voice lists. The standard install is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The installer now fetches one male and one female Piper voice per language (Swedish
NST/Lisa, English Ryan/Lessac), with genders confirmed by measuring each voice's pitch
rather than guessed from the name. Settings -> Audio gets a voice selector per language
with its own Test button that always plays the Piper voice. Male is preselected for both.
The integration test now runs its server with an empty home directory, so voices
installed on the developer's own machine can't leak into it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Announcements can use Piper, a free local neural TTS, instead of the browser's system
voice. No account, no paid service, and it keeps working with no internet at the track.
- npm run tts:install (or Settings -> Audio -> Install) downloads the standalone Piper
release for Linux/Windows/macOS plus Swedish and English voices into piper/ once
- server/tts.js generates each line once, one at a time, and caches it as WAV under
data/tts/; a new line takes ~0.3 s with the standalone build
- src/piper_speech.js plays it and falls back to the browser voice if Piper is missing,
errors, or takes over 2.5 s, so no announcement is lost and timing is never held up
- "Pre-generate phrases and driver names" renders every fixed phrase and name in both
languages before race day
Browser voice stays the default. Generation routes fall under the admin PIN.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Off by default. Once a PIN is set in Settings -> System & backup, every non-GET /api/*
request (plus GET /api/ammc/config) needs a signed 30-day HttpOnly cookie, which also
closes the unauthenticated /api/update/run restart trigger. A 401 opens a PIN dialog
and the pending save is retried after login. Reads stay open because the public overlay
hydrates through GET /api/state. Optional RC_ADMIN_ALLOWED_CIDRS restricts the same
routes by client address.
The PIN hash and signing secret live in data/, outside the app_state blob, so they
never leak through GET /api/state, exports or backups.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
guide.jpg was captured before this session's Schedule feature and video guides existed,
so it was missing both. Event Manager's tabbed layout (also from this session) had never
been pictured in the README at all. Added scripts/capture-screenshots.mjs as a reusable
tool for this instead of another throwaway script, since screenshot refreshes are clearly
a recurring need - reuses the same isolated-server/headless-Chrome pattern as the video
recorder and test suite, with one shared seeded demo dataset so future captures stay
visually consistent.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Commit all 7 recorded clips to docs/videos/ (alongside the existing docs/screenshots/)
instead of leaving them in the gitignored video-guides/ folder from the earlier
feasibility spike - they're meant to be shipped, discoverable assets now, not scratch
output. scripts/record-video-guides.mjs writes there by default going forward.
Added a "Video Guides" section to README.md/README.sv.md (Getting started + Interface
tour groups) and a matching in-app "Video guides" panel on the Guide page, right after
the overview cards - the most discoverable spot for a brand-new user. Links point at
/docs/videos/<name>.mkv, served by the server's existing /docs static route.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
formatRaceClock rendered a doubled-up, garbled time (e.g.
"02:48.20:207") everywhere a race clock is shown - Timing, Overlay,
Results archive, Judging, Training stint logs - because it
concatenated both a centiseconds and a milliseconds computation into
the same string. Only the milliseconds part was ever meant to be
there. Found while building realistic demo data for new screenshots,
since every prior test/demo session was empty and never exercised
this code path with a real result.
Also regenerates all screenshots in docs/screenshots against a
realistic seeded race (drivers, cars, qualifying heats, finals,
practice history, a real judging correction) instead of empty demo
data, adds two new ones (Managed AMMC config, the in-app Guide page)
aimed at helping a new user understand initial setup, removes 6
screenshots orphaned by an earlier README revision, and updates both
README.md and README.sv.md's screenshot tables accordingly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>