2026-08-28 13:39:12 +02:00
2026-03-14 09:51:35 +01:00
2026-08-24 18:29:39 +02:00
2026-08-28 13:39:12 +02:00
2026-08-28 13:39:12 +02:00
2026-03-14 12:17:35 +01:00
2026-03-14 09:51:35 +01:00
2026-08-28 13:39:12 +02:00
2026-08-28 13:39:12 +02:00

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

Overview

Timing

Timing

Overlay

Overlay

Event

Event

Race Setup

Race Setup

Team Overlay

Team Overlay

Judging

Team Overlay

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 Overlay menu:
    • rows
    • layout: leaderboard, grid, lowerthird
    • theme: panel, transparent, chroma
    • visible columns and blocks
  • Use Copy OBS URL to 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/transponders
    • Race Setup = untimed Open Practice or competition races with personal driver transponders
  • Grouped navigation follows the operating flow: Start, Create, Run and follow, Directory, and System and help.
  • Dashboard -> Getting started links directly to system setup, driver registration, race/practice creation, Timing, and Overlay.
  • 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 and safe merging CSV import for drivers and cars through Excel or LibreOffice
    • single race-package export/import from Race Setup -> Manage -> Race Actions
  • Race Setup includes:
    • Quick Open Practice: enter only a name, create an untimed all-transponder session, and continue directly to Timing
    • no class, registered drivers, preset, qualifying, finals, or duration is required for Quick Open Practice
    • grouped Participants and Teams sections in Manage
    • a four-step Create Race Wizard for new races
    • Manage split into Setup, Format, Generation, and Live / results
    • Basic mode now reacts to the selected preset, including a cleaner endurance view
    • Basic / Advanced mode for Race 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, and Live / 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 actions for generation, reseeding and bump-up
    • reorganized in-app Guide with overview cards and two-column sections
    • explicit race participant selection
    • practice standings
    • qualifying standings with points or best result
    • built-in step-by-step guide
    • inline descriptions for all Race Format fields
    • Follow-up time after scheduled race time before a heat fully closes
    • Min lap time and Max lap time filtering 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 Format presets for short technical tracks, club races, IFMAR-style layouts, and endurance
    • schedule drift on Dashboard between planned and actual runtime
    • session type Free Practice for 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 grid per 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, and top 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
  • Sessions:
    • practice
    • qualification
    • heat
    • final
    • free_practice
    • open_practice
    • team_race
  • Sponsor event tools:
    • automatic round creation (qualification, heat, final)
    • auto-assign driver -> car per session
  • Live timing from AMMC WebSocket (msg: "PASSING")
  • Managed AMMC from the web UI:
    • backend can start/stop local ammc-amb on Windows, Linux, and macOS
    • bundled binaries from AMMC/windows64, AMMC/linux_x86-64, AMMC/apple_m
  • Editing in UI:
    • classes, event names/dates, drivers, and cars can be edited directly
    • drivers and cars support optional brand fields for team, sponsor, manufacturer, or model data
    • Drivers and Cars can 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
    • configurable browser audio for start, finish, and passings (beep or driver name)
    • selectable operating-system speech voice, speech rate/pitch, and per-driver phonetic spoken name
    • session start types: Mass start, Position start, Staggered
    • Timing shows grid/order for the active Position start session
    • leaderboard shows gap to leader, gap ahead, and own delta
    • Recent Passings shows invalid laps such as Short lap and Over max lap
    • manual corrections in Timing -> Details: +1/-1 lap, +1/+5/-1 sec, reset
    • practice/qualifying seeding on best 2 or 3 laps
  • Persistence:
    • frontend state in browser localStorage
    • same state and passings persisted to local SQLite through the Node backend
  • Built-in Guide page 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:
    • SV
    • EN

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 practice plan and active rewards. Goal administration, mobile sharing, detailed history and the club comparison remain available in collapsed sections when needed.

When Open Practice, Free Practice, or Practice is running, the selected driver gets a compact live card with current valid laps, best lap, average, and latest lap. The session remains shared by everyone; only the mobile personal timer and profile link are unique per driver and class. The primary action at the top creates or opens that link.

One person can have separate driver entries for classes such as 2WD and 4WD and link them to the same Practice profile under Drivers. The person then has one profile and one mobile link, while every performance statistic is selected and calculated separately per class. Multiple transponders within the same class are combined in that class's statistics.

The personal profile can also store Club and Country. These values are inherited when another class entry is linked to the same practice profile and are included in full JSON and driver CSV exports. They are not disclosed by the public profile link.

  • 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
  • automatic stint boundaries after a passing gap longer than 2 minutes
  • best 3 consecutive laps plus best 5-minute result and its average pace
  • the best 5-minute result counts the final lap when it started before 5:00 (300 s), even when the result finishes after the cutoff
  • daily history for the latest practice days and recent personal-best improvement
  • automatic progression levels at useful lap totals without manual setup
  • a configurable practice timer split into maximum-focus and controlled 80-90% blocks
  • custom lap milestones with quick targets at 500, 1000, and 1500 laps
  • 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 profile and class adds both to the URL so the exact view 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:

  1. Open Training and select the driver.
  2. Open Goals and mobile profile, then click Enable mobile profile.
  3. Copy or open the generated link.
  4. Use Create new link to revoke the previous URL, or Disable profile to turn sharing off.

The URL uses a 192-bit random bearer token rather than a driver ID. The same link provides a class selector with fully separate lap times and practice results for each linked class. The public API does not return transponder IDs, other driver names, race setup or admin state.

The mobile page also includes a local practice timer where the driver chooses minutes for Maximum focus and Controlled. The default is 10 + 10, while a five-minute heat can for example use 5 + 0. 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 and duration choices stay in that phone's browser, separately per driver and class, and do not modify race data. Durations are locked while a session runs and can be changed after finishing or resetting it.

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.

Regression tests use Node's built-in test runner and require no extra test-framework dependency. The suite covers training profiles, race generation and timing, judging corrections, frontend/backend state synchronization, and an isolated SQLite API round-trip using a temporary data directory:

npm test

The integration test starts its own backend on a temporary localhost port and never reads or writes the normal data/rc_timing.sqlite database.

Create Race Wizard

  • Race Setup now starts with a four-step wizard for new races:
    • Basics
    • Participants
    • Session plan
    • Confirm
  • 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 Actions after practice or qualifying is complete.

Manage workflow

  • After the race is created, Manage is split into four clear stages:
    • Setup
    • Format
    • Generation
    • Live / results
  • Setup handles race participants and teams. The top step cards also act as quick navigation between the four blocks.
  • Format handles practice/qualifying, finals, validation, presets, and advanced settings. In Basic mode, endurance hides most qualifying/finals fields until Advanced is opened.
  • Generation is kept separate so actions like qualifying generation, reseeding, finals generation, and bump-up do not clutter the format form.
  • Live / results is where grid, standings, print, PDF, and finals matrix are used once the structure is ready.

Export / Import

  • Settings -> Storage now supports:
    • full JSON export/import for the complete competition database
    • directory JSON export/import for only classes, drivers, and cars
    • CSV export and merging CSV import for drivers and cars; comma, semicolon, and tab delimiters are supported
    • separate clearing of drivers, cars, classes, races/sessions, or training statistics
    • Clear all competition data retains decoder, theme, branding, and server settings
  • Race Setup -> Manage -> Race Actions now 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.
  • CSV imports from the application's own exports preserve IDs. External lists without IDs first match by transponder and then by name + class. Empty fields do not overwrite existing information, and new class names are created automatically.
  • Create a JSON backup before clearing data. Every clear button requires a separate confirmation and cannot be undone.
  • Web clearing removes canonical application data but retains the separate raw SQLite passings table as an audit log. A physical factory reset of the database must be performed locally on the stopped server, never through an unauthenticated LAN route.

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 sec
  • Max lap time = 60 sec

Invalid passings

  • Timing -> Recent Passings shows both valid and invalid passings
  • displayed statuses include:
    • Short lap
    • Over max lap
  • invalid passings are visually highlighted

Manual corrections

  • open Timing
  • click Details on a driver or team
  • available actions:
    • +1 lap
    • -1 lap
    • +1 sec
    • +5 sec
    • -1 sec
    • Reset correction
  • leaderboard and results update immediately

Best laps / average / consecutive

  • Configure per session with Seed Method when Best laps for seeding is greater than 0
  • available modes:
    • Best N laps, total
    • Best N laps, average
    • Best 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

Points tables and tie-break

  • Configure in Race Setup -> Manage -> Race Format
  • qualifying points tables:
    • Placement values (1,2,3...)
    • Descending by field size
    • 10-9-8-7-6-5-4-3-2-1
  • qualifying tie-break options:
    • Compare counted rounds
    • Best single lap
    • Best 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 16s
    • Club race qual + finals
    • IFMAR-style qual/finals
    • Endurance / team race
  • after applying, all fields can still be adjusted manually and saved as usual
  • Save club preset stores your own local presets in app state
  • Delete club preset removes a local preset
  • Settings -> Club presets can export/import the preset library as JSON between installations

Schedule drift on Dashboard

  • Dashboard shows 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 -> Details
  • Invalidate last lap marks the latest counted lap as manually invalid
  • leaderboard, overlay, and lap history update immediately
  • Restore latest manually invalidated lap puts the latest manually invalidated lap back if needed

Judging view

  • separate Judging menu
  • shows active session, leaderboard, lap history, and judging log in one view
  • same corrections as Timing -> Details
  • row filters:
    • All
    • Invalid
    • Corrected
    • Team race
  • judging log can be exported per session as JSON
  • supports Undo latest and per-log-row undo for multiple recent manual actions

Future improvements

  • Optional neural text-to-speech for more natural start, finish, and driver-name announcements.
  • Preferred design: generate speech through the backend, cache short audio files under data/tts/, and play cached audio without network delay during a race.
  • Keep provider credentials on the backend only. Never expose API keys to the browser or public overlay.
  • Retain the current system voice and passing beep as offline fallbacks.
  • Support uploaded or prerecorded WAV/MP3 clips for fixed start and finish announcements.

Windows installation

Use 64-bit Windows 11 and Node.js 22 or 24 LTS. The easiest supported setup is:

  1. Clone or extract the complete repository, preferably to C:\\Live_RC.
  2. Double-click windows\\install.bat.
  3. The installer runs npm.cmd restart and leaves the backend running.
  4. Open http://localhost:8081.

The setup script can install Node.js LTS through winget, runs locked dependency installation with npm.cmd ci, verifies SQLite/Express, and checks the bundled AMMC runtime. Full instructions and troubleshooting: windows/README.md.

Common commands:

npm.cmd start
npm.cmd stop
npm.cmd restart
npm.cmd run status
npm.cmd run start:fg
  • npm.cmd start starts the backend in the background
  • npm.cmd stop stops the process via data/server.pid
  • npm.cmd restart restarts the backend
  • npm.cmd run status shows whether the backend is running
  • npm.cmd run start:fg runs in foreground for troubleshooting

Windows scripts

The windows/ folder includes:

  • windows\\install.bat installs dependencies and runs npm.cmd restart
  • windows\\start_ammc.bat starts AMMC in the background
  • windows\\start_backend.bat starts npm.cmd start in the background
  • windows\\restart_backend.bat runs npm.cmd restart after updates
  • windows\\start_all.bat starts both AMMC + backend and opens the web page
  • windows\\stop_all.bat stops the managed backend and ammc-amb.exe

Backend logs:

  • logs\\server.out.log
  • logs\\server.err.log

SQLite database file:

  • data\\rc_timing.sqlite

Connect to AMMC

There are two supported modes.

For the complete network diagram, ready-to-use 1/2/3/4-decoder examples, firewall setup, and troubleshooting, see docs/decoder-setup.md. Swedish: docs/decoder-setup.sv.md.

A. Managed AMMC from the web UI

Important:

  • AMMC runs on the same host where the backend was started with npm.cmd start
  • if you only browse from another laptop, no process starts there
  • the AMMC executable field in Settings is a path on the backend host, not the client browser machine

Decoder topology

Role Physical placement Example decoder IP AMMC WS port Effect
Main start/finish Start/finish loop 192.168.1.10 9000 Counts laps and controls lap time
Split Intermediate loop 192.168.1.11 9001 Records split from the latest main crossing; never counts a lap
Pit entry Entry to pit lane 192.168.1.12 9002 Opens a pit stop
Pit exit Exit from pit lane 192.168.1.13 9003 Closes and times a pit stop

The decoder IP and WebSocket address are different things. The decoder IP points from AMMC to physical hardware. The browser connects to AMMC on the backend host, for example ws://192.168.1.100:9001. Each decoder must have a unique network address and each AMMC process must have a unique WebSocket port.

Use only the channels physically installed at the track. One decoder on 9000 remains the default and needs no optional settings. Split timing requires one additional decoder. Pit timing requires two additional decoders because entry and exit are separate events. A complete setup therefore uses four decoders.

Split and pit data is available in several places:

  • Timing shows the active heat summary and complete pit-stop log live.
  • Race Setup -> Manage -> Live / results shows the summary and pit log for every heat, including long 45-minute endurance heats.
  • regular and team result exports include split/pit summaries and the complete entry/exit log in PDF.
  • Training -> More statistics aggregates split and pit performance for the selected personal driver profile and class; different classes are never mixed.
  • the personal mobile profile shows only sanitized counts and aggregate times for the selected class. It never exposes transponders, other drivers, or the raw pit-stop log.

If a team changes driver or car between pit entry and pit exit, the completed stop remains attributed to the driver, car, and transponder detected at pit entry. The exit transponder is retained separately for diagnostics.

  1. Place AMMC binaries in the AMMC/ project folder.
  2. Open Settings.
  3. Enable Managed AMMC.
  4. Set the Main Decoder IP / host, verify port 9000, and optionally enable/configure Split and Pit channels from the table above.
  5. Click Start AMMC.
  6. Click Use server WS URL so the client uses for example ws://<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.10

Complete four-decoder example, using four separate terminals/processes:

ammc-amb.exe -w 9000 192.168.1.10
ammc-amb.exe -w 9001 192.168.1.11
ammc-amb.exe -w 9002 192.168.1.12
ammc-amb.exe -w 9003 192.168.1.13

In the app:

  1. Open Settings
  2. Set WebSocket URL, for example ws://127.0.0.1:9000
  3. Set Backend URL to http://127.0.0.1:8081
  4. Click Test Backend
  5. Go to Timing and click Connect Decoder

If Linux firewall/UFW is enabled:

sudo ufw allow 8081/tcp
sudo ufw allow 9000:9003/tcp

Auto reload during development

  • The server watches index.html, src/app.js, and src/styles.css
  • When files in Live_RC change, the client reloads automatically
  • If backend code changes on Windows, run npm.cmd 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"
}

Race audio and start lights

The repository includes rc-race-sound-pack/. sound_manifest.json is the source of truth for event-to-WAV and Swedish/English announcement mappings. The server exposes it at /race-sounds/sound_manifest.json; WAV files are served from /race-sounds/sounds/effects/.

  1. Open Settings -> Race sounds and announcements.
  2. Select sv or en, then set master, effects, voice, and passing volume.
  3. Enable or disable effect and voice independently for each event and use its Test button. Changes save automatically, and the section also has its own Save button. WAV effects are prerecorded; voice announcements use the operating system Web Speech voices.
  4. Select a 0/10/30/60-second pre-start, start lights, and random delay limits. For timed race sessions the clock starts at the same callback that initiates the start tone. Open/Free Practice starts immediately.
  5. Use the Race Control buttons in Timing for Track call, Track clear, Red flag, False start, and Marshal warning.

Effects are asynchronous and never awaited by decoder processing. Critical speech interrupts lower-priority speech; short passing effects may overlap. Missing WAV files are ignored safely. A driver or car may select pass_01.wav through pass_08.wav; until those optional files exist under rc-race-sound-pack/sounds/effects/, playback falls back to transponder_pass.wav.

Implemented automatic hooks include passings, personal/meeting best, fastest lap, historical class track record, leader and position changes, pit entry/exit, 60/30/10 seconds remaining, final lap/time expired, finish, winner, and podium. Penalty announcements reuse the existing judging correction action.

Description
Live RC timesystem
Readme 255 MiB
Languages
JavaScript 91.8%
CSS 7.5%
PowerShell 0.3%
HTML 0.2%
Batchfile 0.1%