feat(race-day): start heats with an EFRA/IFMAR count-down and flying start

Race Day Start now runs a count-down (Go, 30 s - 5 min, default per
event) with calls every minute, 30 s and 10 s, grid call and 9..3
count for grid starts, hold/resume/+1 min/to 30 s/to 10 s/Go now, and
starts the heat by itself when it runs out. The transponder check runs
during the count-down, replacing the separate warm-up.

Adds a flying start mode (horn + clock is running, own clock per car)
as the qualifying default, and the latest personal clock start rules
from EFRA 9.3 / IFMAR 4.2.3 for flying and staggered starts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
larssand
2026-09-30 21:27:20 +02:00
parent 1bc75f8ec1
commit 5bfb67ea02
27 changed files with 884 additions and 334 deletions

View File

@@ -1,3 +1,4 @@
import { PROLOGUE_OPTIONS_SEC, formatPrologueOption } from "./prologue_logic.js";
function formatDateTimeLocalValue(ms) {
const date = new Date(ms);
date.setSeconds(0, 0);
@@ -126,6 +127,7 @@ export function renderEventManagerMarkup(context) {
<option value="mass">${t("events.start_mode_mass")}</option>
<option value="position">${t("events.start_mode_position")}</option>
<option value="staggered">${t("events.start_mode_staggered")}</option>
<option value="flying">${t("events.start_mode_flying")}</option>
</select>
<small>${t("events.session_start_mode_hint")}</small>
</label>
@@ -525,8 +527,14 @@ export function renderEventManagerMarkup(context) {
<option value="mass" ${event.raceConfig.qualStartMode === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
<option value="position" ${event.raceConfig.qualStartMode === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
<option value="staggered" ${event.raceConfig.qualStartMode === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
<option value="flying" ${event.raceConfig.qualStartMode === "flying" ? "selected" : ""}>${t("events.start_mode_flying")}</option>
</select>`
) : ""}
${showBasicQualifyingFields ? renderRaceFormatFieldView(
"events.qual_prologue",
"events.prologue_hint",
`<select name="qualPrologueSec">${PROLOGUE_OPTIONS_SEC.map((seconds) => `<option value="${seconds}" ${event.raceConfig.qualPrologueSec === seconds ? "selected" : ""}>${formatPrologueOption(seconds, t)}</option>`).join("")}</select>`
) : ""}
${raceFormatAdvanced
? renderRaceFormatFieldView(
"events.qual_seed_laps",
@@ -610,8 +618,14 @@ export function renderEventManagerMarkup(context) {
<option value="mass" ${event.raceConfig.finalStartMode === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
<option value="position" ${event.raceConfig.finalStartMode === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
<option value="staggered" ${event.raceConfig.finalStartMode === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
<option value="flying" ${event.raceConfig.finalStartMode === "flying" ? "selected" : ""}>${t("events.start_mode_flying")}</option>
</select>`
) : ""}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.final_prologue",
"events.prologue_hint",
`<select name="finalPrologueSec">${PROLOGUE_OPTIONS_SEC.map((seconds) => `<option value="${seconds}" ${event.raceConfig.finalPrologueSec === seconds ? "selected" : ""}>${formatPrologueOption(seconds, t)}</option>`).join("")}</select>`
) : ""}
${showBasicFinalFields ? renderRaceFormatFieldView(
"events.bump_count",
"events.bump_count_hint",
@@ -915,6 +929,7 @@ export function renderEventManagerMarkup(context) {
<option value="mass" ${normalizeStartMode(editingSession.startMode) === "mass" ? "selected" : ""}>${t("events.start_mode_mass")}</option>
<option value="position" ${normalizeStartMode(editingSession.startMode) === "position" ? "selected" : ""}>${t("events.start_mode_position")}</option>
<option value="staggered" ${normalizeStartMode(editingSession.startMode) === "staggered" ? "selected" : ""}>${t("events.start_mode_staggered")}</option>
<option value="flying" ${normalizeStartMode(editingSession.startMode) === "flying" ? "selected" : ""}>${t("events.start_mode_flying")}</option>
</select>
<small>${t("events.session_start_mode_hint")}</small>
</label>