Contents, highlights and quick start first, then features in the order a club uses them, then installation, decoders and development. Adds the start count-down, series hub, practice tooling, audio, OBS and security features, and removes outdated statements. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RC RaceCore
RC timing and race control for clubs: live timing from AMB/MyLaps decoders through AMMC, race day control with EFRA/IFMAR-style start procedures, qualifying and finals, series and cups, practice statistics with mobile driver profiles, announcements with an offline voice, and overlays for screens and OBS. Everything runs locally on one computer (Windows or Linux) with a SQLite database - no cloud service and no internet needed at the track.
Swedish version: README.sv.md · Changes: CHANGELOG.md · Plans: ROADMAP.md · The running version is shown at the bottom of the menu.
Contents
- Highlights
- Screenshots
- Quick start
- Using RaceCore
- Video guides
- Installation
- Decoders and AMMC
- Development and tests
Highlights
- Race Day page with heat queue, preflight checks and one-click start.
- Start procedure as in EFRA/IFMAR: a count-down with announcements (2 min, 1 min, 30 s, 10 s, 9..3), hold for the grid, flying start for qualifying, and grid start with lights and a random start signal for finals.
- Transponder check during the count-down: a green tick for every driver seen, and a wrong transponder fixed in one click.
- Qualifying and finals: generated from the entry list with evenly split heats, A/B/C finals, bump-ups, points tables, tie-breaks and a drag-and-drop grid.
- Series / cup: a points table, best N or drop X, a club-members-only option, standings per class, and each round run from the series page.
- Judging: penalties and lap changes, all logged and undoable.
- Practice statistics per driver, class and track layout: stints, consistency, achievements, goals, and a personal mobile profile with a QR code.
- Clean statistics: suspiciously short practice laps (shortcuts) are flagged automatically and removed in one click.
- Announcements in Swedish or English with a local neural voice (Piper, offline). Races play the passing tone only, as timing systems do.
- Overlays for screens and OBS, with places gained/lost since the start.
- Safe data: SQLite, an automatic backup before every start, full export/import, and an optional admin PIN.
Screenshots
Click an image to open the full-resolution version.
Quick start
Windows 11 (PowerShell):
winget install --id Git.Git --exact --source winget # only if "git --version" fails
Set-Location $HOME
git clone https://git.dio.nu/Public/Live_RC.git Live_RC
Set-Location .\Live_RC
.\windows\install.bat
Linux (Ubuntu/Debian) with Node.js 22 or 24:
git clone https://git.dio.nu/Public/Live_RC.git Live_RC
cd Live_RC
npm ci && npm run verify
npm start
Then open http://localhost:8081, or http://<server-ip>:8081 from another computer on the race network. The in-app Guide (menu) and the video guides walk through the first decoder connection, drivers and the first race. Full steps: Installation.
Using RaceCore
The menu follows how a race day works: Start (Dashboard, Race Day), Create (Race Setup, Sponsor events, Series / cup), Run and follow (Timing, Judging, Overlay, Training stats, Results archive), Directory (Classes, Drivers, Cars) and System and help (Settings, Guide). The interface is in Swedish or English.
Race day
Race Day is the operator's page:
- The heat queue shows the current, next and after-next heat.
- Preflight checks the decoder, participants, transponders (missing or duplicated), the lap window, the grid and audio. Blockers come first, each with a shortcut to the right setting. The min/max lap time can be edited right there.
- An automatic SQLite backup is taken before every start.
Start procedure (EFRA/IFMAR): Start runs a count-down first. Choose Go, 30 s, 1, 1:30, 2, 3 or 5 min; the default is set per event for qualifying and finals.
- During the count-down:
- The track is open.
- The announcer calls "Heat 3 starts in 2 minutes", then every minute, 30 s and 10 s.
- For a grid start it also calls "cars to the grid" at 30 s and counts 9..3.
- Buttons:
- Hold (while cars are put on the grid) and Resume.
- +1 min.
- To 30 s (grid restart).
- To 10 s.
- Go now, which warns about drivers not seen.
- Cancel.
- When the count-down runs out the heat starts by itself.
- Grid start (mass/position): start lights and a random 0-5 s start signal.
- Flying start (default for qualifying): the signal and "Clock is running". Each car's clock starts at its own first crossing, and a late car's clock starts at the latest 150 % of a lap (EFRA 9.3).
- Staggered start: cars are called out one by one.
- Transponder check: every driver in the heat gets a green tick when their transponder crosses during the count-down. A missing driver's transponder can be changed in the panel, or linked to an unknown transponder that just crossed.
- Pause, resume and finish work during the heat. Follow-up time lets the last lap finish after the clock.
Timing shows the live leaderboard (laps, gap to leader and ahead, own delta, best and last lap), recent passings with invalid short laps marked, the grid for position starts, a session replay (1-10x), and the speaker panel.
Judging is where race corrections are made: ±laps, ±seconds and reset, plus removing or restoring any lap. Everything is logged with time and can be undone; the log exports as JSON. In qualifying, heats and finals this is the only place for penalties; Timing shows the corrections and has an Open in Judging button. Practice has no penalties, but laps can be cleaned up right on Timing (see practice).
Lap validation:
- Min lap time rejects shortcuts and false hits.
- Max lap time starts a new statistics stint after a break; the long lap still counts in the race.
Creating races
Race Setup has two ways in:
- Quick Open Practice: just a name. It creates an untimed all-transponder session and goes straight to Timing; no class, drivers or format are needed.
- Create Race Wizard: Basics → Participants → Session plan → Confirm. Choose a class and a preset, pick the drivers, and the practice/qualifying (or team race) sessions are created.
After creation the race is managed in four tabs (Race Setup → Manage):
- Participants & teams: tick who races, and manage teams for endurance.
- Format:
- qualifying rounds, cars per heat, duration and start mode (mass, position, staggered, flying);
- seeding (best N laps total, average, or consecutive);
- qualifying points table (placement, by field size, 10-9-8...) and tie-break;
- finals: legs, counted legs, bump-ups and reserved bump slots;
- count-down length, follow-up time and the min/max lap time;
- presets: short technical track, club race, IFMAR style, endurance, or your own saved club presets;
- Race actions at the bottom of the tab:
- create qualifying from practice (or the entry list); heats are split as evenly as possible, e.g. 9 drivers with max 8 per heat gives 5 + 4;
- reseed upcoming heats; locked manual grids are respected;
- create A/B/C finals and apply bump-ups;
- export the race as a package.
- Live & results:
- grid editor (drag and drop) and lock;
- practice, qualifying and final standings, and a finals matrix;
- print and branded PDF exports;
- split and pit summaries.
- Schedule & print: the day's running order with planned times, and heat sheets.
The Dashboard shows schedule drift (planned vs actual). The Results archive finds finished races without going through Race Setup.
Series / cup
Menu Series / cup runs a championship over any number of rounds, with freely chosen classes. Each class gets its own standings.
- Name and classes.
- Points:
- Who scores: every driver (open series), or club members only. With members only, drivers from other clubs race and appear in the day result but get no series points, and members are re-ranked without them.
- Points table: the ÖRC table (100, 90, 82, 75, 69 … then −4 per place, min 10), 100-80-70, F1, or your own list.
- Counted results: best N (e.g. 9 of 12), or all run rounds except the X worst. A cancelled round then lowers the count automatically.
- Rounds: paste the dates, and one race per date and class is created with the chosen number of qualifying rounds, finals and max cars per heat. Each round is then run from its row:
- pick drivers;
- Copy from previous round;
- New driver for a late entry;
- change the format for that round (it can differ between rounds and classes);
- Create qualifying (heats follow the size of the field) and Create finals;
- Status and Open.
- Standings:
- The day placing comes from the final standings (A before B), then qualifying order.
- No registered lap gives 0. Absence counts as 0 and can be dropped.
- Ties go to most wins, then 2nd places, then the latest common round.
- Print, or export as PDF (wide tables switch to landscape).
Practice and training statistics
Practice sessions:
- Open Practice can run all season; Free Practice is a rolling best-lap session.
- Reset data on Timing clears the session for a new day, but every lap stays in the training statistics.
Track layouts:
- Press New layout (on Training stats, Race Day or the Dashboard) when the track is rebuilt. A running practice moves onto the new layout, and best laps start over.
- Each layout can have its own min/max lap time for practice. Races always use the event's values.
- Statistics are per layout, with an "all layouts" overview.
Suspiciously short laps (practice only):
- A lap far quicker than the driver's own pace (under 85 % of their median, after 5 laps) is flagged ⚠ - typically a shortcut by a new driver or a child.
- It counts as a lap but not as a best lap, record or statistic until someone Approves it.
- Remove is one click, in the panel on Timing and Race Day, or in the driver's lap list.
Training stats (menu):
- The club overview and one page per driver and class show:
- personal best, averages and consistency;
- best 3 consecutive laps and the best 5-minute result;
- stint analysis, 30-minute pace blocks and setup markers with before/after comparison;
- daily history and achievements;
- goals with rewards, daily challenges and a shared club goal.
- Based on: Practice (default), Races or All. Race laps are kept separate and marked 🏁 with race, session and series. Under Races they are listed per race session; a race never forms stints.
- One person can race several classes. Link the class entries to the same practice profile under Drivers; statistics stay per class.
Mobile profile:
- Each driver can get a personal link with a QR code. It shows their own statistics, a practice timer, setup markers and exercises (even laps, step training), and has a choice of practice or race laps.
- The link uses a random token; no transponders or other drivers are shown.
- For use over the internet, set the public address once for everyone under Settings → System & backup → Public address (domain / DynDNS), e.g.
https://club.dyndns.org:8443. Left empty, links use the local network address. - Proxy only these paths to the internet:
/public-training/*,/src/public_training.jsand/src/public_training.css. Ready-made Teltonika files are inscripts/teltonika/.
Audio and announcements
Settings → Audio:
- Race sounds:
- start lights, random start delay and passing tones (optionally a different tone per driver/car);
- announcements in Swedish or English for the start, the clock (1 min, 30 s, 10 s), final lap, finish, winner and podium, pit, penalties and race control (track call, red flag, false start, marshal);
- each event can be switched on or off for effect and voice.
- Calls during a race: "Passing tone only" (default, like timing systems) or "Speaker" with names, personal bests and new leaders. Practice always gets the full calls.
- Local neural voice (Piper): free and works offline. Install from Settings → Audio → Voice engine, or with
npm run tts:install.- Standard voices: Swedish NST (male) and Lisa (female), English Ryan (male) and Lessac (female).
- Under More voices, one at a time (about 63 MB each): Swedish Alma; British Alan, Northern English, Cori and Alba (Scottish); American Joe, John and Norman.
- Pre-generate phrases and driver names before race day.
- If Piper is missing, the browser voice takes over.
- Spoken name per driver: enter a pronunciation or nickname under Drivers and press 🔊 Test pronunciation to hear it in real announcements.
Overlays and OBS
The Overlay menu has leaderboard, speaker, results, TV and team modes, plus an OBS mode with layout (leaderboard, grid, lower third), theme (panel, transparent, chroma), rows and columns:
- Columns: laps, result, best, gap, and places since the start (▲/▼ in heats and finals).
- Copy OBS URL gives a browser-source link; the chosen columns are part of the link.
- Public overlays live at
/public-overlay/<mode>and can require a token: setPUBLIC_OVERLAY_TOKENand add?token=.... Publish only/public-overlay/*through your reverse proxy. - Club branding (name, logo, PDF theme) is applied to the sidebar, overlays, mobile profiles and PDFs; branding can also be set per event.
Sponsor events with shared cars
Sponsor events (track events) let many drivers share a few cars and transponders, e.g. 10 drivers and 4 cars:
- rounds are created automatically and drivers are assigned to cars per session;
- within one session every car needs a unique transponder, but the same transponder can be used again in the next session.
Data, backups and import/export
- Storage:
- Everything is stored in
data/rc_timing.sqlite; the browser keeps a local copy and syncs. - The menu shows the save status (saved, pending, failed, with Retry).
- Judge corrections are sent straight to the server.
- Everything is stored in
- Backups:
- automatic before every session start, plus manual ones;
- the latest 30 are listed under Settings;
- restore with
npm run backup:restore(see Installation).
- Export/import (Settings → Storage):
- full JSON, or the directory only (classes, drivers, cars);
- CSV for drivers and cars (Excel/LibreOffice; comma, semicolon or tab). The CSV import merges: it matches on ID, then transponder, then name + class.
- a single race package from Race Setup;
- club presets.
- Clearing: drivers, cars, classes, races or training statistics can each be cleared separately, every one with its own confirmation. Export first.
Example driver CSV (only name is required):
name;transponder;class;brand;club;country
Anna Andersson;123456;2WD;;JMK;SE
Erik Eriksson;654321;4WD;Associated;;
Security
RaceCore is meant for a trusted race network:
- Admin PIN (Settings → System & backup, off by default) protects every change through the API. The login lasts 30 days and is throttled against guessing.
RC_ADMIN_ALLOWED_CIDRSrestricts admin changes to certain addresses or networks, e.g.192.168.1.0/24.RC_ALLOWED_ORIGINSis for a UI deliberately served from another address.- Don't expose port 8081 to the internet. Reads are not PIN protected. Publish only the public overlay and mobile profile paths through a reverse proxy or VPN.
See docs/security-performance-audit.md.
Video guides
Short narrated recordings (.mkv, H.264/AAC), also linked from the in-app Guide:
- Getting started: Connect a decoder · Add drivers and cars · Create a race · Run a session
- Interface tour: Settings tabs · Event Manager tabs · Race day schedule
Recorded with node scripts/record-video-guides.mjs, against an isolated test server.
Installation
RaceCore runs on 64-bit Windows 11 and Linux with Node.js 22 or 24 LTS and npm 10+. Use npm ci (the repository has a package-lock.json).
Windows 11
- Git: run
git --version. If it's missing, runwinget install --id Git.Git --exact --source wingetand reopen PowerShell, or use Git for Windows. Without Git, download the ZIP from the repository and extract all of it. - Download:
Set-Location $HOME git clone https://git.dio.nu/Public/Live_RC.git Live_RC Set-Location .\Live_RC - Install: run
.\windows\install.bat(or double-click it). It does the following:- installs Node.js LTS if needed, plus the Visual C++ runtime that AMMC needs;
- runs
npm.cmd ci; - verifies Express, SQLite and AMMC;
- creates
data\andlogs\; - starts RaceCore in the background.
- Check:
Then open
npm.cmd run status Invoke-RestMethod -Uri "http://127.0.0.1:8081/api/health"http://localhost:8081, orhttp://<ipconfig address>:8081from another computer.
Use npm.cmd in PowerShell; it avoids the "running scripts is disabled" error. Manual install without the script: npm.cmd ci, npm.cmd run verify, npm.cmd start. Don't use --ignore-scripts, because SQLite needs its install script.
Linux (Ubuntu/Debian)
sudo apt update && sudo apt install -y git curl build-essential
# Node.js 22 if "node --version" is missing or older:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
git clone https://git.dio.nu/Public/Live_RC.git Live_RC
cd Live_RC
npm ci
npm run verify
chmod +x AMMC/linux_x86-64/ammc-*
npm start
npm run status
Open http://localhost:8081, or http://<hostname -I address>:8081. The bundled Linux AMMC needs GLIBC 2.39+ (ldd --version). On older systems, use a matching AMMC build or run AMMC on another host; never replace the system GLIBC.
Runtime commands
Command (Windows: npm.cmd ...) |
What it does |
|---|---|
npm start |
Start in the background |
npm run status |
Is it running? (PID in data/server.pid) |
npm restart |
Restart after an update |
npm stop |
Stop |
npm run start:fg |
Run in the terminal and show errors directly |
npm run tts:install |
Install Piper and the standard voices |
Logs go to logs/server.out.log and logs/server.err.log; data is kept in data/.
The windows\ helper scripts:
install.bat: install, verify and restart.start_backend.batandrestart_backend.bat: start or restart the server.start_ammc.bat: start AMMC.start_all.bat: start AMMC and the server, then open the browser.stop_all.bat: stop the server and AMMC.
Update without losing data
Never delete data/. To update:
npm stop
git pull --ff-only
npm ci
npm run verify
npm restart
On Windows, use the same commands with npm.cmd. The menu shows when an update is available, and the update can also be run from Settings → System & backup. For a ZIP installation, keep data/ and never copy node_modules/ between Windows and Linux.
Restore a server backup
Backups are in data/backups/. Restore is a local command, on purpose:
npm stop
npm run backup:restore -- <backup-file>.sqlite --confirm
npm start
On Windows, find the latest file with Get-ChildItem .\data\backups\*.sqlite | Sort-Object LastWriteTime -Descending | Select-Object -First 1. The restore validates the file and first takes a pre_restore backup of the current database.
Decoders and AMMC
The full guide, with network diagrams, 1-4 decoder examples, firewall setup and troubleshooting, is docs/decoder-setup.md (Swedish: docs/decoder-setup.sv.md).
| Role | Placement | Example decoder IP | AMMC WS port | Effect |
|---|---|---|---|---|
| Main | Start/finish loop | 192.168.1.10 |
9000 |
Counts laps |
| Split | Intermediate loop | 192.168.1.11 |
9001 |
Split time, never a lap |
| Pit entry | Pit lane entry | 192.168.1.12 |
9002 |
Opens a pit stop |
| Pit exit | Pit lane exit | 192.168.1.13 |
9003 |
Closes and times it |
Managed AMMC (Settings):
- Enable Managed AMMC.
- Enter the decoder IP for each channel.
- Click Start AMMC, then Use server WS URL.
AMMC runs on the server computer, not in the browser. The bundled binaries are in AMMC/windows64, AMMC/linux_x86-64 and AMMC/apple_m.
Manual start: run one ammc-amb -w <port> <decoder-ip> per decoder. In Settings, set the WebSocket URL (e.g. ws://<server-ip>:9000) and press Connect decoder. The browser connects to the AMMC host, not the decoder itself. On Linux with UFW, run sudo ufw allow 8081/tcp and sudo ufw allow 9000:9003/tcp.
Diagnostics: Settings → Decoder / socket diagnostics shows each channel's connection, frames and passings, the latest raw message and 50 events. ammc-sim emulates a decoder with chosen transponders, for training and testing without hardware.
AMMC sends PASSING messages like this (AMMC docs):
{ "msg": "PASSING", "passing_number": 1, "transponder": 232323, "rtc_time": "2022-10-11T22:57:36.099+02:00", "strength": 0.0, "resend": false, "loop_id": "55" }
Development and tests
- Unit, logic and API tests:
npm test. The SQLite integration tests start their own server against a temporary database and never touchdata/. - Browser tests:
npm run test:browser. They need Chrome, Chromium or Edge (setCHROME_PATHif it isn't found), and run against an isolated server with a fake decoder. - Screenshots and video guides:
node scripts/capture-screenshots.mjs [name]andnode scripts/record-video-guides.mjs. - Docs: the module overview is docs/javascript-architecture.md, and planned and finished work is in ROADMAP.md.
- Auto reload: the client reloads when
index.htmlor frontend files change. After backend changes, runnpm restart. - Raw data:
/api/passings(latest passings) and/api/state(app state), on the local network only.












