Chapter-map callouts
The chapter relief and arrival briefing now show named callouts for the selected stage's start, both saved checkpoints and finish. Each route callout uses the existing catalog name, racing kilometre and model elevation plus the chapter's altitude base. Checkpoint names are explicitly marked SEKTOR: they name the gameplay sector beginning at that checkpoint, not a claim that a named bridge or village model stands at the pin.
Only the Alps receive a named terrain landmark: Schneeberg-Massiv / Kalkfels, pinned to the existing documented DEM hero coordinate. Generic HeroLandmark placeholders from other chapters are not presented as named, built monuments.
Binding and progress
- Start:
PositionAtDistance(course, 40), matchingTrackRuntime.StartDistance. - Checkpoint:
40 + checkpoint.Fraction × stage.RacingLength, matching checkpoint progress and save semantics. - Finish:
40 + stage.RacingLength = stage.Length − 35, matching the actual finish plane, not the end of the road mesh. - Live rider: the exact supplied position of an unfinished active/paused race, identified as LIVE. The caller supplies the actual active stage, even while another stage in the same chapter is selected. A rider retained behind the results screen does not override campaign progress.
- Saved progress: only a matching stage, checkpoint ID and content revision places the marker at the saved checkpoint, identified as GESPEICHERT. Invalid/stale saved coordinates fall back to the next stage start.
- Next trip position: the current unlocked stage start, identified as NÄCHSTER START, rather than an invented moving rider.
- Completed tour: the last real finish position, identified as TOUR GESCHAFFT, rather than the last stage's start.
- No marker is placed in an unrelated chapter. Coincident here/start/checkpoint/finish callouts merge within 15 m to avoid duplicate overlapping labels; the white pin still uses the authoritative here position.
CampaignMapGraphic.FitProjection provides the single aspect-preserving projection for relief, roads, pins and leaders. It reserves a bottom legend strip and supports both top-left and centered map pivots. UI child anchor conversion subtracts the map's top-left coordinate, preventing pin drift if its pivot changes.
Presentation and runtime cost
The selected road remains orange; other roads retain their progress colours. Each 218 × 94 callout has a quiet opaque background, a matching accent and three separate TMP text fields. Header: 18 px high at 14 px type. Name: 46 px high, normal word wrapping, 18–20 px type for up to two lines. Distance/elevation: an independent 20 px field at 14–15 px type. Core text uses no ellipsis, rich-text sizing or shared multiline rectangle. All images and text ignore raycasts. Existing Xbox button selection remains intact; the chapter footer explicitly explains Stick/D-pad selection.
At most six reusable panels and their text/accent children are allocated when the map first needs labels. Layout updates only after chapter/font/size changes, outside the canvas mesh rebuild. The relief's sampled positions/colours are cached for the chapter. LateUpdate exits immediately when clean; it creates no per-frame callout objects. The bounded placement search penalizes label overlaps, hidden pins, route coverage and leaders crossing prior panels. Labels stay within the map and above the legend.
Evidence
The preserved text-layout proof records 1,075 passed checks, zero failures, using compiled production code: all 21 stages, both 1110×476 and 1040×526 map rectangles, 202 actual callout placements, no overlapping rectangles or map-boundary violations. It verifies catalog names, checkpoint/finish distances, arbitrary-pivot projection and the saved/live/stale/foreign-chapter/completed-tour cases. Exact map-source hashes are attached. The check reads the actual production card dimensions through reflection, so the 218 × 94 cards cannot accidentally be tested with the superseded 218 × 66 bounds.
Runtime 90 files and Editor 20 files compile with no warnings/errors after the text correction. This count includes concurrent completed work; it is not a claim that all 110 files changed for the map.
Three earlier CPU schematics were generated and visually inspected for geometry/label composition. They preserve the first 218 × 66 layout, not the corrected card size, Unity's relief rendering or TMP rasterization:
The actual 16:19 chapter screenshot demonstrated the first implementation's text defect: names were ellipsized and the height row disappeared despite the rectangle-only checks passing. This is retained as the native before image, not accepted as successful text rendering.
The follow-up source fix splits those three lines into separate reusable TMP components and enlarges each card. The imported Rampage SDF.asset gives Rajdhani a line height of 114.840004 at point size 90: a 14 px header needs 17.864 px, two 18 px name lines need 45.936 px, and the 15 px height line needs 19.140 px. The three independent rectangles accommodate those actual font metrics without relying on the rich-text autosizer. The geometry checks passed again at the enlarged size. Only CampaignMapGraphic.Labels.cs changed among live sources; the placement/progress/controller formulas are unchanged.
Native correction evidence, 15 September 2026
The 16:59 chapter-map capture was independently viewed after the correction. In its 1110 × 476 chapter map, all five names and their detail rows are fully readable, with no ellipsis, dropped elevation, overlapping cards or hidden legend: Talwiesen 629 m, Dorfbrücke 1.2 km / 634 m, Waldrand 2.5 km / 778 m, Bergwald-Treffpunkt 3.6 km / 755 m, and Schneeberg-Massiv / Kalkfels · Alpen. The white current-start pin and orange selected stage remain clear.
This is the regular Windows build from 16:57:01 Vienna / 14:57:01Z, Unity 6000.3.24f1, Rampage 0.1.0. Invocation and independently checked Assembly-CSharp.dll agree on SHA-256 EA2346AF3984669506C6955A049F5E38620C02CDDDCD19C431BED8AFFB3E543A. The run rendered 1920 × 1080 on Intel UHD / Direct3D11, exited 0, preserved production profiles and reported no driver events.
Native text correction passed for this Alps 1-1 chapter view. This one screenshot does not establish every selected stage, the separate 1040 × 526 briefing map, live/resumed marker variants or physical Xbox navigation. Those broader UI checks remain open; the compiled geometry/progress checks cover both rectangles independently. No Unity or player process was started by this documentation task.
Reproduce the compiled geometry/layout checks:
& 'Tools/Verification/verify-campaign-map-labels.ps1'
Tools/Verification/render_map_label_layout.py regenerates the CPU schematics with Pillow. The temporary drafts under Tools/Art/MapDraft preserve the staged work from the root's native-test freeze; the verified runtime files under Assets are authoritative.
Finished-rider marker correction
The results screen retains the finished motorcycle for its backdrop. Previously, opening a chapter map afterward supplied that old transform as a live rider, and live-marker priority hid the newly unlocked stage start. RampageUI.BuildChapterMap now uses CampaignMapGraphic.LiveRacePosition: an unfinished race in Racing, Pause or its WorldMap/ChapterMap screens may supply its actual position, only in its own chapter. A finished race, results, Home, title or an arrival briefing cannot supply a live position. The existing saved-checkpoint / next-stage / completed-tour resolver then remains authoritative; route geometry, checkpoints and profile data are unchanged.
The updated compiled map proof records 1,091 passed / zero failures, including 16 focused additions. These cover active and paused races, retained finished riders, non-race screens and a foreign chapter. A progression case completes Alps01 through the production profile API, passes the finished-rider result into the actual label resolver, and verifies the white marker at the newly unlocked Alps02 start. It then verifies a matching saved Alps02 checkpoint takes priority. All 202 existing placements still pass. Managed Runtime 92 / Editor 21 compilation completed with zero warnings/errors. These are compiled CPU checks; no Unity or Player was started for this correction, and its native image verification remains pending.