JMK RB RaceController
English README. Swedish version: README.sv.md
JMK RB RaceController is an RC timing and race-control system with support for sponsor events with shared cars/transponders, AMMC WebSocket input, and local persistence through SQLite.
Architecture
- JavaScript module overview:
docs/javascript-architecture.md - Swedish operational guide:
README.sv.md
Screenshots
Overview
Timing
Overlay
Event
Race Setup
Team Overlay
Judging
Public Overlay And OBS
The app now supports a dedicated public overlay route so you do not need to expose the full admin UI externally.
- Public overlay route:
/public-overlay/<mode> - OBS mode:
/public-overlay/obs - OBS overlay can be configured from the
Overlaymenu:- rows
- layout:
leaderboard,grid,lowerthird - theme:
panel,transparent,chroma - visible columns and blocks
- Use
Copy OBS URLto generate a ready-to-paste browser-source link for OBS.
If you want simple protection for public overlays, set this environment variable on the server:
PUBLIC_OVERLAY_TOKEN=your-secret-token
Then the public overlay URL must include:
/public-overlay/obs?token=your-secret-token
Recommended deployment:
- publish only
/public-overlay/*through your reverse proxy - keep the main app/admin UI internal
Features
- Event modes:
Race (driver transponders)Track Event (shared cars)
- UI separation:
Event= sponsor events with shared cars/transpondersRace Setup= competition races with personal driver transponders
- Storage/import tools:
- full race-data export/import for backup or moving to another machine
- directory export/import for only classes, drivers and cars
- CSV export for drivers and cars when you want simple spreadsheet lists
- single race-package export/import from
Race Setup -> Manage -> Race Actions
- Race Setup includes:
- grouped
ParticipantsandTeamssections inManage - a four-step
Create Race Wizardfor new races Managesplit intoSetup,Format,Generation, andLive / results- Basic mode now reacts to the selected preset, including a cleaner endurance view
Basic / Advancedmode forRace Format- a right-side race summary card
- a preset-aware summary card that changes between endurance and normal race focus
- status badges for
Setup,Format,Generation, andLive / results - summary warnings when participants, sessions, teams, or lap-window settings are missing
- clickable summary warnings that jump to the relevant Manage section
- clickable step cards that act as quick navigation inside
Manage - compact step cards with live counters such as drivers, teams, sessions, and active/results state
- separate
Race actionsfor generation, reseeding and bump-up - reorganized in-app
Guidewith overview cards and two-column sections - explicit race participant selection
- practice standings
- qualifying standings with
pointsorbest result - built-in step-by-step guide
- inline descriptions for all
Race Formatfields Follow-up timeafter scheduled race time before a heat fully closesMin lap timeandMax lap timefiltering for shortcuts/false hits and better stint/stat logic- seeding modes for practice/qualifying: best N laps total, average, or consecutive
- selectable qualifying points tables and tie-break rules
Race Formatpresets for short technical tracks, club races, IFMAR-style layouts, and endurance- schedule drift on
Dashboardbetween planned and actual runtime - session type
Free Practicefor rolling lap-time display without seeding - automatic qualifying heat generation from practice standings or class list
- re-seeding of upcoming qualifying heats from current standings
- automatic
A/B/C...finals generation from rankings - persistent manual grid per session with drag-and-drop grid editor
- auto-reseed skips heats with locked manual grid
- explicit
Lock/Unlock gridper session - multi-leg final standings with counted final legs
- optional bump-up between finals
- reserved bump-up slots in higher finals
- visual finals matrix with reserved bump slots
- drag-and-drop grid editor for position starts
- print/export of heat sheets per qualifying/final
- overlay modes for external display screens
- multiple overlay modes: leaderboard, speaker, results, TV, team
- speaker overlay with event markers and separate speaker cues
- live speaker panel in
Timing - speaker cues and club/PDF branding from
Settings - overlay logo upload from
Settings - per-event/per-race branding in
Manage - extra speaker cues for
session start,new best lap, andtop 3 change - selectable PDF themes:
classic,minimal,motorsport - branded print and PDF exports
- server-generated PDF exports with embedded logo
- generated qualifying/finals inherit duration and start mode from race format
- finish sound uses a siren instead of browser TTS
- grouped
- Sessions:
practicequalificationheatfinalfree_practiceopen_practiceteam_race
- Sponsor event tools:
- automatic round creation (
qualification,heat,final) - auto-assign driver -> car per session
- automatic round creation (
- Live timing from AMMC WebSocket (
msg: "PASSING") - Managed AMMC from the web UI:
- backend can start/stop local
ammc-ambon Windows, Linux, and macOS - bundled binaries from
AMMC/windows64,AMMC/linux_x86-64,AMMC/apple_m
- backend can start/stop local
- Editing in UI:
- classes, event names/dates, drivers, and cars can be edited directly
- drivers and cars support optional
brandfields for team, sponsor, manufacturer, or model data DriversandCarscan be searched by name, transponder, or brand directly in the UI- race start lists and heat sheets include driver brand in print, CSV, and PDF exports
- Live race control:
- countdown during timed sessions
- auto-finish at end of session time with
Race is finished - leaderboard sorting by laps first, then nearest to target time when applicable
- browser audio for passings (
beepor driver name) and finish - session start types:
Mass start,Position start,Staggered Timingshows grid/order for the activePosition startsession- leaderboard shows
gap to leader,gap ahead, andown delta Recent Passingsshows invalid laps such asShort lapandOver max lap- manual corrections in
Timing -> Details:+1/-1 lap,+1/+5/-1 sec, reset - practice/qualifying seeding on best
2or3laps
- Persistence:
- frontend state in browser
localStorage - same state and passings persisted to local SQLite through the Node backend
- frontend state in browser
- Built-in
Guidepage in the app covering:- sponsor events (for example 10 drivers / 4 cars)
- standard race setup
- invalid laps, follow-up, and manual corrections
- AMMC + npm setup on Windows and Linux
- UI language selection:
SVEN
Training And Rewards
The Training menu provides a non-race progression view for registered drivers:
The default view is intentionally simple: four key statistics, the next lap target, today's 20-minute plan and active rewards. Goal administration, mobile sharing, detailed history and the club comparison remain available in collapsed sections when needed.
- durable lifetime valid-lap ledger synchronized from stored session results
- practice days, recorded sessions, personal best, overall/recent averages, controlled-lap streak, and recent consistency spread
- daily history for the latest practice days and recent personal-best improvement
- automatic progression levels at useful lap totals without manual setup
- a 20-minute recommendation split into maximum-focus and controlled 80-90% blocks
- custom lap milestones with quick targets at
500,1000, and1500laps - optional reward text and a delivered/redeemed state
- responsive layout for opening the same server from a phone on the local network
Direct mobile/bookmark link: http://<server-ip>:8081/?view=training. Selecting a driver adds its ID to the URL so that driver's page can be bookmarked.
Training statistics currently include only valid laps linked to a registered driver. Anonymous Open Practice transponders are intentionally excluded until they are assigned to a driver.
Judging corrections update ledger laps while the source session still exists. Once a session is deleted, its synchronized training laps remain in the ledger so lifetime progression is not lost. Full data export includes the ledger and reward goals.
Read-only mobile profile
Each registered driver can have an optional personal mobile link:
- Open
Trainingand select the driver. - Open
Goals and mobile profile, then clickEnable mobile profile. - Copy or open the generated link.
- Use
Create new linkto revoke the previous URL, orDisable profileto turn sharing off.
The URL uses a 192-bit random bearer token rather than a driver ID. The public API returns only that driver's display name, class/brand, aggregate practice statistics, daily summaries, goals and reward text. It does not return transponder IDs, other driver names, race setup or admin state.
The mobile page also includes a local 20-minute practice timer: 10 minutes maximum focus followed by 10 minutes controlled 80-90% driving. While a shared Free Practice session keeps running, the card shows that driver's lap count, best lap and average since the personal timer started. Timer state stays in that phone's browser and does not modify race data.
For internet publishing, proxy only these paths:
/public-training/*
/src/public_training.js
/src/public_training.css
Do not expose /api/state or the full admin application. Static serving is restricted to /src and /docs; data/, server scripts and bundled binaries are not public static files.
Create Race Wizard
Race Setupnow starts with a four-step wizard for new races:BasicsParticipantsSession planConfirm
- The wizard is intended to create the first race structure quickly:
- choose class and preset
- scope valid race drivers
- create practice, qualifying, and/or team-race sessions automatically
- Finals are still generated later from
Race Actionsafter practice or qualifying is complete.
Manage workflow
- After the race is created,
Manageis split into four clear stages:SetupFormatGenerationLive / results
Setuphandles race participants and teams. The top step cards also act as quick navigation between the four blocks.Formathandles practice/qualifying, finals, validation, presets, and advanced settings. In Basic mode, endurance hides most qualifying/finals fields until Advanced is opened.Generationis kept separate so actions like qualifying generation, reseeding, finals generation, and bump-up do not clutter the format form.Live / resultsis where grid, standings, print, PDF, and finals matrix are used once the structure is ready.
Export / Import
Settings -> Storagenow supports:- full JSON export/import for the complete competition database
- directory JSON export/import for only classes, drivers, and cars
- CSV export for drivers and cars
Race Setup -> Manage -> Race Actionsnow supports single race packages:- export one race with its sessions, results, and referenced classes/drivers/cars
- import that package into another installation as a new race entry
- JSON export files now include export metadata and a schema version field so future imports can be handled more safely.
Race features
Follow-up time
- Configure it in
Race Setup -> Manage -> Race Format - It can also be set per session when creating or editing a session
- When scheduled time ends, the session enters follow-up first
- When follow-up ends, the session closes automatically
- Generated qualifying/finals inherit follow-up from race format
Min / Max lap time
- Configure it in
Race Setup -> Manage -> Race Format Min lap time:- laps faster than the threshold are ignored as shortcuts or false hits
Max lap time:- laps slower than the threshold are not counted as valid laps
- also used to split stints and improve statistics
Example:
- track around
16 sec/lap Min lap time = 11 secMax lap time = 60 sec
Invalid passings
Timing -> Recent Passingsshows both valid and invalid passings- displayed statuses include:
Short lapOver max lap
- invalid passings are visually highlighted
Manual corrections
- open
Timing - click
Detailson a driver or team - available actions:
+1 lap-1 lap+1 sec+5 sec-1 secReset correction
- leaderboard and results update immediately
Best laps / average / consecutive
- Configure per session with
Seed MethodwhenBest laps for seedingis greater than0 - available modes:
Best N laps, totalBest N laps, averageBest N consecutive laps
- leaderboard and standings use the correct format:
- total:
3/00:48.321 - average:
3 avg 16.107 - consecutive:
3 con 00:49.005
- total:
Points tables and tie-break
- Configure in
Race Setup -> Manage -> Race Format - qualifying points tables:
Placement values (1,2,3...)Descending by field size10-9-8-7-6-5-4-3-2-1
- qualifying tie-break options:
Compare counted roundsBest single lapBest round / heat result
- qualifying standings also show an inline tie-break note in the table
Race format presets
Race Setup -> Manage -> Race Format- choose a preset and click
Apply preset - built-in presets:
Short technical track 16sClub race qual + finalsIFMAR-style qual/finalsEndurance / team race
- after applying, all fields can still be adjusted manually and saved as usual
Save club presetstores your own local presets in app stateDelete club presetremoves a local presetSettings -> Club presetscan export/import the preset library as JSON between installations
Schedule drift on Dashboard
Dashboardshows whether the day is ahead of or behind schedule- planned time includes:
- session duration
- follow-up time
- actual time includes:
- real time from start to stop
- or live runtime if the session is still running
Invalid-lap marker in leaderboard
- if the latest passing for a driver or team is invalid, the row is marked in both leaderboard and overlay
- this makes it easier to see problems without staying in
Recent Passings
Manual invalidate / restore last lap
Timing -> DetailsInvalidate last lapmarks the latest counted lap as manually invalid- leaderboard, overlay, and lap history update immediately
Restore latest manually invalidated lapputs the latest manually invalidated lap back if needed
Judging view
- separate
Judgingmenu - shows active session, leaderboard, lap history, and judging log in one view
- same corrections as
Timing -> Details - row filters:
AllInvalidCorrectedTeam race
- judging log can be exported per session as JSON
- supports
Undo latestand per-log-row undo for multiple recent manual actions
Windows installation
Use 64-bit Windows 11 and Node.js 22 or 24 LTS. The easiest supported setup is:
- Clone or extract the complete repository, preferably to
C:\\Live_RC. - Double-click
windows\\install.bat. - Start with
windows\\start_backend.batornpm start. - Open
http://localhost:8081.
The setup script can install Node.js LTS through winget, runs locked dependency installation with npm ci, verifies SQLite/Express, and checks the bundled AMMC runtime. Full instructions and troubleshooting: windows/README.md.
Common commands:
npm start
npm stop
npm restart
npm run status
npm run start:fg
npm startstarts the backend in the backgroundnpm stopstops the process viadata/server.pidnpm restartrestarts the backendnpm run statusshows whether the backend is runningnpm run start:fgruns in foreground for troubleshooting
Windows scripts
The windows/ folder includes:
windows\\install.batinstalls and verifies Node/npm dependencieswindows\\start_ammc.batstarts AMMC in the backgroundwindows\\start_backend.batstartsnpm startin the backgroundwindows\\start_all.batstarts both AMMC + backend and opens the web pagewindows\\stop_all.batstops the managed backend andammc-amb.exe
Backend logs:
logs\\server.out.loglogs\\server.err.log
SQLite database file:
data\\rc_timing.sqlite
Connect to AMMC
There are two supported modes.
A. Managed AMMC from the web UI
Important:
- AMMC runs on the same host where
npm start/node server.jsruns - if you only browse from another laptop, no process starts there
- the
AMMC executablefield inSettingsis a path on the backend host, not the client browser machine
- Place AMMC binaries in the
AMMC/project folder. - Open
Settings. - Enable
Managed AMMC. - Set
Decoder IP / host, verify port9000, save. - Click
Start AMMC. - Click
Use server WS URLso the client uses for examplews://<server-ip>:9000.
Default binaries:
- Linux host:
AMMC/linux_x86-64/ammc-amb - Windows host:
AMMC/windows64/ammc-amb.exe - macOS host:
AMMC/apple_m/ammc-amb
B. Manual start
Example:
ammc-amb.exe -w 9000 192.168.1.11
In the app:
- Open
Settings - Set
WebSocket URL, for examplews://127.0.0.1:9000 - Set
Backend URLtohttp://127.0.0.1:8081 - Click
Test Backend - Go to
Timingand clickConnect Decoder
If Linux firewall/UFW is enabled:
sudo ufw allow 8081/tcp
Auto reload during development
- The server watches
index.html,src/app.js, andsrc/styles.css - When files in
Live_RCchange, the client reloads automatically - If backend code changes, run
npm restart
Verify SQLite persistence
Latest passings via API:
http://localhost:8081/api/passings
Saved app state via API:
http://localhost:8081/api/state
Important rule for sponsor events
- In the same running session, every active car must have a unique transponder ID
- The same transponder ID can be reused in the next session (
Heat 1 -> Heat 2 -> Heat 3 -> Final 1 ...)
AMMC JSON reference
Official quick start:
Example message:
{
"msg": "PASSING",
"passing_number": 1,
"transponder": 232323,
"rtc_time": "2022-10-11T22:57:36.099+02:00",
"strength": 0.0,
"resend": false,
"tran_code": "ID:232323",
"loop_id": "55"
}






