Track Markers¶
A marker is a named visual or physical reference point that drivers actually use on track — "the bridge", "the bump where the road widens", "the Toyota sign letters", "the K-wall bend". Pace-note coaching that names these markers sounds native; coaching that says "brake at 124 metres" does not.
Markers are loaded from the track JSON, exposed via track_loader.MarkerDef, and surfaced into pace-note phrasing by coach_engine.RuleCoach and any LLM coach that consumes CoachContext.next_brake_marker_label.
Why markers (Sonoma intel finding)¶
The Sonoma track intelligence doc found, after surveying every public track guide, that Sonoma's reference vocabulary is environmental, not numeric. Pros call out bridges, tire stacks, sign letters, pavement cracks, K-wall bends, pit-entry lines, and "the bump" — not "the 100 board" or distances in metres. Coaching language must follow.
Concrete impact on our coach output:
| Before markers | After markers |
|---|---|
185, left 6, brake 50, uphill |
185, left 6, brake at the bridge, uphill |
230, right 3, brake 134, late apex |
230, Calamity Corner, brake at the bump where the road widens left, late apex |
128, right 3, brake 86, downhill |
128, the Carousel, brake at just after the slight crest, downhill |
91, right 6, brake 0, late apex |
91, right 6, brake at the 300 board, late apex |
Verified on a full Sonoma replay: 42 % of the 186 pace notes per lap now reference a real Sonoma landmark.
Schema¶
The markers schema is co-located with the corner data in the track JSON. Each marker is also flattened into a top-level markers: [] array so consumers can do a single nearest-marker search without iterating corners.
{
"id": "T11_bump",
"kind": "brake_ref",
"label": "the bump where the road widens left",
"distance": 4080.0,
"corner": "Turn 11",
"source": "blayze",
"note": "best brake reference — wait for the car to compress and settle"
}
| Field | Meaning |
|---|---|
id |
Stable string ID, used for image filenames + cross-references |
kind |
One of brake_ref, apex_ref, turn_in_ref, exit_ref, visual, nickname |
label |
Human-readable phrase the coach speaks ("the bridge") |
distance |
Cumulative track distance in metres (modulo track_length_m) |
corner |
Canonical corner name this marker belongs to |
source |
Attribution: kanga, blayze, lapmeta, bentley, etc. |
note |
Optional caveat or selection hint |
In the per-corner block, each marker also carries at_offset_m_from_entry (positive = before entry, zero = at entry, negative = after entry) so future tooling can re-derive distance if the geometry changes.
Per-corner enrichment also adds:
{
"name": "Turn 11",
"nicknames": ["Calamity Corner", "the hairpin"],
"coaching_tip": "wait for the bump to settle, trail to the apex, all the road on exit",
"markers": [...]
}
Sonoma marker inventory¶
16 markers across 8 corners, authored from docs/sonoma_track_intelligence.md:
| Corner | Marker ID | Kind | Label | Source |
|---|---|---|---|---|
| Turn 1 | T1_kwall_bend |
apex_ref | the K-wall bend | kanga |
| Turn 2 | T2_bridge |
brake_ref | the bridge | kanga |
| Turn 2 | T2_pavement_cracks |
brake_ref | the pavement cracks | kanga |
| Turn 3 | T3_right_curbing |
apex_ref | the right-hand curbing | kanga |
| Turn 3 | T3_light_poles |
visual | the light poles in the stands | kanga |
| Turn 4 | T4_left_wall_step |
brake_ref | where the left wall steps up | kanga |
| Turn 6 | T6_crest |
brake_ref | just after the slight crest | kanga |
| Turn 6 | T6_tires_left |
brake_ref | the tire stacks on the left | kanga |
| Turn 6 | T6_corner_station |
visual | the corner station on the right | kanga |
| Turn 7 | T7_300_board |
brake_ref | the 300 board | blayze |
| Turn 10 | T10_toyota_sign |
visual | the Toyota sign letters | kanga |
| Turn 10 | T10_left_berm |
apex_ref | the left berm | kanga |
| Turn 11 | T11_bump |
brake_ref | the bump where the road widens left | blayze |
| Turn 11 | T11_pit_entry |
brake_ref | the pit-entry lines on the left | kanga |
| Turn 11 | T11_tire_stack_3 |
apex_ref | the third tire stack | blayze |
| Turn 11 | T11_tire_stacks_turnin |
turn_in_ref | the start of the tire stacks on the left | blayze |
Corners without authored markers (T5, T8, T9) intentionally fall back to numeric pace notes — the intel doc didn't surface canonical visual references for those.
Per-corner coaching tips¶
Authored alongside markers, each corner that's covered in the intel doc has a single-sentence coaching cue grounded in either Bentley's actual Sonoma session or per-corner pro guides:
| Corner | Coaching tip |
|---|---|
| Turn 1 | carry throttle through, swing tight to the K-wall bend |
| Turn 2 | you can brake less than you think; carry speed uphill |
| Turn 3 | give-away corner — sacrifice T3 entry to win T3a and T4 |
| Turn 4 | downhill, off-camber — back the brake up by one marker |
| Turn 5 | throwaway corner — preserve T6 entry, breathe the throttle |
| Turn 6 | smooth exit — speed here carries the long straight; no early throttle |
| Turn 7 | eyes up — late turn-in, late apex; second apex matters more |
| Turn 8 | smooth, don't pinch — apexes all slightly late, throttle on exit |
| Turn 9 | setup for T10 — exit T8a at full throttle |
| Turn 10 | lift, don't brake — fastest corner; carry full throttle past apex |
| Turn 11 | wait for the bump to settle, trail to the apex, all the road on exit |
These currently surface in CoachContext.next_corner_tip and are available to LitertCoach (LiteRT-LM via MediaPipe Genai) for prompt injection. The RuleCoach does not voice them directly — they're meant for richer LLM-driven coaching.
Authoring + sync¶
The canonical track JSON lives at data/tracks/sonoma.json. Three duplicates exist (in src/pitwall/features/, flutter/assets/tracks/, flutter/android/app/src/main/assets/tracks/) for different runtime consumers; running python3 tools/enrich_sonoma_track.py syncs all four from the canonical source.
To re-author or extend marker data, edit tools/enrich_sonoma_track.py:ENRICHMENT (one entry per corner) and re-run:
python3 tools/enrich_sonoma_track.py # enrich + sync all 4 copies
python3 tools/enrich_sonoma_track.py --dry-run # show summary only
python3 tools/enrich_sonoma_track.py --no-sync # only edit the canonical copy
A .bak is written next to the canonical file before any mutation.
Runtime use¶
In track_loader.py:
from track_loader import load_track, find_nearest_marker, find_marker_for_next_corner
track = load_track("data/tracks/sonoma.json")
nearest = find_nearest_marker(track, distance_m=350, kind="brake_ref")
# → MarkerDef(id="T2_bridge", label="the bridge", distance=414.0, ...)
best = find_marker_for_next_corner(track, distance_m=350, kind="brake_ref")
# Same as above but biased to markers attached to the upcoming corner first.
build_context() (now in features/coaching/coach_engine.py — a shim that re-exports from features/coaching/engine_base.py) automatically populates CoachContext.next_brake_marker_label and next_apex_marker_label from the upcoming corner's authored markers, so any coach that consumes CoachContext gets marker-aware phrasing for free.
RuleCoach._render() (in features/coaching/rule_coach.py) prefers marker labels when present:
- Beginner:
Turn 2 in 185 meters, brake at the bridge - Intermediate:
185, left 6, brake at the bridge, uphill - Pro:
Turn 2 185m, the bridge, apex 129
Future extensions¶
- Marker GPS coordinates — currently absent. The reference_line trace in the track JSON can be sampled at
marker.distanceto derive(lat, lon)for any marker. Useful for any map UI. - Marker thumbnails — per-marker still images extracted from the synced VBO + dashcam video (
Sonoma Intermediate - 1_47.5.mp4). Seedocs/api.mdfor the proposedtools/extract_marker_thumbnails.pypipeline. - Per-marker confidence + difficulty score — combine corner severity with marker visibility (the bump is harder to use than the bridge); surface as a 1–6 score for the "pick 3 markers" UX.
- Adaptive marker selection — driver-level-specific marker choice (beginner sees "the bridge", pro sees "the second pavement crack").