@inventure71/paddockjs 2.0.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +176 -1
  2. package/INSTALL_AND_UPDATE.md +24 -4
  3. package/README.md +84 -512
  4. package/docs/architecture.md +38 -24
  5. package/docs/component_inventory.md +72 -0
  6. package/docs/composable-layouts.md +77 -0
  7. package/docs/concepts.md +2 -2
  8. package/docs/custom_model_controller.md +6 -6
  9. package/docs/data-helpers.md +50 -0
  10. package/docs/data_contract.md +104 -27
  11. package/docs/getting-started.md +75 -0
  12. package/docs/headless-environment.md +68 -0
  13. package/docs/index.md +18 -4
  14. package/docs/learnings.md +6 -6
  15. package/docs/rules.md +12 -8
  16. package/docs/sense_contract.md +1 -1
  17. package/docs/system_specs.md +71 -21
  18. package/docs/theming.md +64 -0
  19. package/docs/training.md +26 -19
  20. package/docs/troubleshooting.md +76 -0
  21. package/docs/upgrading-hosts-to-3.md +42 -0
  22. package/examples/python/README.md +6 -0
  23. package/examples/python/base_policy_server.py +19 -0
  24. package/package.json +10 -3
  25. package/src/api/PaddockSimulatorController.js +150 -24
  26. package/src/api/runtimeTheme.js +59 -0
  27. package/src/app/F1SimulatorApp.js +213 -29
  28. package/src/app/banners/raceDataBannerController.js +71 -36
  29. package/src/app/banners/stewardMessageController.js +5 -4
  30. package/src/app/camera/cameraConstants.js +2 -0
  31. package/src/app/camera/cameraController.js +86 -29
  32. package/src/app/camera/cameraGeometry.js +12 -1
  33. package/src/app/domBindings.js +89 -9
  34. package/src/app/layoutScheduler.js +27 -0
  35. package/src/app/layoutSupport.js +165 -0
  36. package/src/app/raceOverlayClearanceSupport.js +158 -0
  37. package/src/app/readouts/carOverviewRenderer.js +16 -8
  38. package/src/app/readouts/controlStateRenderer.js +1 -1
  39. package/src/app/readouts/raceStatusRenderer.js +30 -21
  40. package/src/app/readouts/readoutFormatters.js +2 -0
  41. package/src/app/readouts/telemetryRenderer.js +17 -8
  42. package/src/app/readouts/timingTowerRenderer.js +262 -49
  43. package/src/app/runtime/frameLoop.js +5 -1
  44. package/src/app/runtime/runtimeVisibility.js +66 -5
  45. package/src/config/cssValues.js +16 -0
  46. package/src/config/defaultOptions.js +58 -38
  47. package/src/config/themeOptions.js +830 -0
  48. package/src/config/timingGapMode.js +13 -0
  49. package/src/config/urlOptions.js +25 -0
  50. package/src/data/championship.js +14 -9
  51. package/src/data/index.d.ts +212 -0
  52. package/src/data/index.js +14 -0
  53. package/src/environment/controllerLoop.js +17 -3
  54. package/src/environment/episode.js +11 -1
  55. package/src/environment/index.d.ts +1 -2
  56. package/src/environment/metrics.js +59 -16
  57. package/src/environment/observationVector.js +50 -33
  58. package/src/environment/observations.js +89 -20
  59. package/src/environment/options.js +1 -1
  60. package/src/environment/runtime.js +44 -11
  61. package/src/environment/scenarios.js +1 -1
  62. package/src/environment/sensors/carRays.js +48 -37
  63. package/src/environment/sensors/index.js +501 -97
  64. package/src/environment/sensors/indexedRayBands.js +134 -46
  65. package/src/environment/sensors/rayBandTrace.js +1171 -0
  66. package/src/environment/sensors/rayChannels.js +108 -0
  67. package/src/environment/sensors/rayConfig.js +71 -25
  68. package/src/environment/sensors/rayGeometry.js +23 -17
  69. package/src/environment/sensors/sensorTargets.js +67 -1
  70. package/src/environment/sensors/surfaceRays.js +167 -118
  71. package/src/environment/sensors/trackRays.js +157 -48
  72. package/src/index.d.ts +153 -9
  73. package/src/index.js +52 -3
  74. package/src/simulation/collisionGeometry.js +260 -96
  75. package/src/simulation/driver/driverController.js +1 -1
  76. package/src/simulation/driver/edgeRecovery.js +1 -1
  77. package/src/simulation/driver/racingControls.js +2 -2
  78. package/src/simulation/driver/rejoinControls.js +2 -2
  79. package/src/simulation/pit/pitFlow.js +21 -9
  80. package/src/simulation/pit/pitKinematics.js +2 -2
  81. package/src/simulation/pit/pitQueue.js +5 -3
  82. package/src/simulation/pit/pitRouteMovement.js +9 -4
  83. package/src/simulation/pit/pitRouting.js +79 -46
  84. package/src/simulation/pit/pitState.js +1 -0
  85. package/src/simulation/pit/pitTireService.js +7 -3
  86. package/src/simulation/race/raceFinish.js +25 -8
  87. package/src/simulation/race/raceOrder.js +189 -32
  88. package/src/simulation/race/raceProgress.js +129 -37
  89. package/src/simulation/race/raceSetup.js +4 -6
  90. package/src/simulation/race/raceStep.js +26 -14
  91. package/src/simulation/race/safetyCar.js +1 -1
  92. package/src/simulation/race/stalledDnf.js +1 -1
  93. package/src/simulation/raceSimulation.js +20 -17
  94. package/src/simulation/rules/collisionSteward.js +40 -23
  95. package/src/simulation/rules/rulesReview.js +77 -56
  96. package/src/simulation/snapshots/raceSnapshots.js +37 -0
  97. package/src/simulation/timing/drsTiming.js +143 -30
  98. package/src/simulation/timing/gapEstimation.js +25 -3
  99. package/src/simulation/timing/lapTelemetry.js +138 -40
  100. package/src/simulation/timing/raceTiming.js +5 -1
  101. package/src/simulation/timing/sectorPerformance.js +104 -26
  102. package/src/simulation/timing/timingHistory.js +229 -14
  103. package/src/simulation/timing/timingLines.js +65 -7
  104. package/src/simulation/track/pitLaneLayout.js +30 -3
  105. package/src/simulation/track/pitLaneState.js +218 -19
  106. package/src/simulation/track/spatialQueries.js +66 -33
  107. package/src/simulation/track/trackMath.js +91 -24
  108. package/src/simulation/track/trackModel.js +2 -0
  109. package/src/simulation/track/trackQueryIndex.js +1468 -189
  110. package/src/simulation/track/trackQueryPitIndex.js +138 -14
  111. package/src/simulation/track/trackQueryScratch.js +7 -0
  112. package/src/simulation/track/trackQueryStats.js +25 -0
  113. package/src/simulation/track/trackSnapshotJson.js +139 -0
  114. package/src/simulation/track/trackStatePolicy.js +249 -2
  115. package/src/simulation/vehicle/contactResolution.js +99 -62
  116. package/src/simulation/vehicle/mainTrackWheelSurface.js +73 -34
  117. package/src/simulation/vehicle/pitWheelSurface.js +81 -28
  118. package/src/simulation/vehicle/runoffResponse.js +54 -29
  119. package/src/simulation/vehicle/vehicleGeometry.js +245 -51
  120. package/src/simulation/vehicle/vehicleKinematics.js +2 -2
  121. package/src/simulation/vehicle/vehiclePhysics.js +45 -30
  122. package/src/simulation/vehicle/vehicleSnapshots.js +35 -1
  123. package/src/simulation/vehicle/vehicleState.js +7 -1
  124. package/src/simulation/vehicle/wheelSurface.js +807 -92
  125. package/src/simulation/warmup/runtimeWarmup.js +0 -1
  126. package/src/styles.css +1568 -519
  127. package/src/ui/bannerTemplates.js +38 -28
  128. package/src/ui/cameraControlsTemplate.js +16 -5
  129. package/src/ui/carOverviewTemplate.js +12 -5
  130. package/src/ui/raceCanvasTemplate.js +31 -8
  131. package/src/ui/raceControlsTemplate.js +27 -10
  132. package/src/ui/shellTemplate.js +3 -1
  133. package/src/ui/telemetryDrawerTemplate.js +23 -10
  134. package/src/ui/telemetryTemplates.js +58 -32
  135. package/src/ui/templateUtils.js +48 -0
  136. package/src/ui/timingTowerTemplate.js +29 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,180 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Make Policy Runner HTTP server mode compact by default through protocol version `2`. `/policy/reset` receives static specs and configuration once, while each `/policy/decide-batch` request sends compact vectors, previous actions, metrics, and events instead of repeating rich observation objects, schemas, snapshots, or track metadata.
8
+
9
+ ### Performance And Runtime
10
+
11
+ - Rework the race-step phase order so normal active steps perform one authoritative broad race-state commit per simulation step, while pre-physics work reads the previous committed state.
12
+ - Make the normal active-step broad commit consume the already-refreshed post-motion wheel/track state instead of recomputing wheel-surface classification a second time for every car.
13
+ - Derive broad-commit DRS reference cars from one physical-track-order pass instead of re-scanning the full field for every car during the same commit.
14
+ - Keep the common no-DNF full-field DRS reference build on the already-ordered race field and write references straight into the reused indexed buffer, so the benchmark broad-commit path avoids rebuilding a second live-car list before the same ordered-forward reference walk.
15
+ - Keep DRS latch updates on cached active-zone references and in-place detection records instead of repeatedly re-finding the same zone by id and rebuilding the detection object shape on every broad-commit latch update.
16
+ - Cache the next DRS detection-zone index on each car across steady forward motion, so broad-commit DRS latch updates stop rescanning the whole DRS-zone list on the common path while external car-state jumps still invalidate the cache safely.
17
+ - Add a narrower cached-next-zone no-crossing fast path inside broad-commit DRS latch updates, and enforce it with direct unit coverage plus runtime benchmark counters so the dominant steady-forward unlatched case stays off the generic wrap-aware crossing math.
18
+ - Keep the broad-commit DRS latch path on a sim-bound scalar call instead of rebuilding the same options object for every car on every step.
19
+ - Keep the common no-finish race-end check on one direct ordered-field pass, so broad commits stop allocating a temporary finished-car list and then rescanning the same field again just to prove the race is still running.
20
+ - Reuse lap-telemetry sector arrays and sector-performance buffers in place during broad race-state commits, removing per-step short-lived timing allocations without changing the public telemetry shape.
21
+ - Keep lap-telemetry position refresh in place during broad commits, so normal per-car telemetry updates stop allocating a temporary lap/sector position object before rewriting the same fields back onto `lapTelemetry`.
22
+ - Keep the common no-boundary lap-telemetry path on a narrower in-progress sync that updates only live scalars plus the active-sector slots, instead of re-synchronizing the whole three-sector position structure on every committed step.
23
+ - Dirty-gate broad-commit sector-performance classification so unchanged current/last/best sector buffers keep their existing `lapTelemetry.sectorPerformance` arrays instead of rebuilding the whole field classification on every committed step.
24
+ - Reduce browser/runtime churn by keeping full public snapshots for host/debug/export/full-state APIs while using lean render, training, and transport paths for hot loops.
25
+ - Keep Policy Runner diagnostic JSON throttled so automatic playback does not stringify the debug readout every frame.
26
+ - Keep more driver-precision road-edge, kerb, and illegal-surface rays on the direct indexed ray-band path, including validated off-track recovery boundaries, and resolve ambiguous recovery, pit-connector, and pit-lane-origin rays through one bounded sampled pass inside the ray-band tracer instead of separate road/surface fallback scans.
27
+ - Keep diagnostic `debug` precision inside the same ray-band tracer, including refined sampled recovery for pit-connector and other ambiguous diagnostic rays, so debug ray builds no longer escape to the legacy separate road/surface scans unless the track index is unavailable.
28
+ - Keep common main-road illegal-surface direct rays on tracer-owned post-kerb band classification instead of re-running generic nearest-track validation at the outer kerb boundary, so validated direct sensor-ray paths cut their remaining classification queries without reopening the sampled-recovery cases.
29
+ - Rebuild direct sensor-ray origin state from same-pose main-road `progress`/`signedOffset` geometry when that pose already matches the live ray origin, so the runtime sensor-ray benchmark stays on its direct boundary-validation work instead of paying an extra nearest-track origin lookup on every iteration.
30
+ - Let batch-training surface rays use the same ray-band tracer as normal driver rays, with a main-track-only connector mode and scratch-owned tracer result/surface-boundary containers, so kerb/illegal-surface-only batches stay on reusable direct indexed geometry with `nearestQueries: 0` and no per-ray tracer result replacement.
31
+ - Anchor direct sensor-ray boundary validation on the exact ray-hit boundary segment neighborhood instead of a generic nearest-track classification lookup, so the benchmark direct path keeps all `320` rays fully direct with `nearestQueries: 0` while generated-track validation still agrees with sampled characterization.
32
+ - Reuse the already-known main-road origin classification on direct sensor-ray boundary validation, so main-road direct rays validate the outside boundary sample only and the benchmark direct path drops from two indexed boundary-neighborhood queries per ray to one without reopening sampled recovery or generic nearest-track fallbacks.
33
+ - Keep barrier-origin direct illegal-surface boundary validation on the exact ray-hit segment neighborhood instead of falling back to generic nearest-track classification for those three boundary samples, and pin that path with a dedicated runtime benchmark that must stay fully direct with `nearestQueries: 0` and `segmentNeighborhoodQueries: rayCount * 3`.
34
+ - Keep barrier-origin off-track recovery rays on direct indexed band classification whenever the tracer already proves road-edge/kerb misses and the first non-barrier illegal-surface entry, so that recovery route no longer drops into the sampled local-marching path just to confirm the same result.
35
+ - Keep direct sensor-ray boundary tracing on reusable segment-id scans and centerline typed arrays instead of materializing temporary track segment objects, and pin zero ray segment object allocations in the runtime benchmark contract.
36
+ - Keep indexed sensor-ray boundary tracing on tracer-owned reusable offset, distance, segment-id, and boundary-result containers in the per-ray scratch query, and enforce that direct sensor rays reuse those containers in the runtime benchmark contract.
37
+ - Keep indexed sensor-ray grid traversal on one query-scratch sample point instead of allocating a temporary `{ x, y }` point per ray-grid step, and enforce that sample-point reuse in the runtime benchmark contract.
38
+ - Keep sensor-ray channel selection on reusable scalar channel flags in the per-ray shared query instead of allocating `Set` containers or using filter/spread min helpers on the hot tracer path, and enforce zero channel-set allocations plus stable channel-flag containers in the runtime benchmark contract.
39
+ - Resolve pit-lane-origin side rays directly from the pit-road normal/width geometry when the current pit-lane frame proves the boundary hit, so common pit transition rays avoid sampled nearest-track classification entirely while retaining bounded sampled recovery for ambiguous pit rays.
40
+ - Keep pit-route transitions on route-owned scalar segment cursors, reusable stop sample points, and reusable route-projection scratch instead of allocating sampled route points or projection objects during entry, queue-release, and exit movement, and add a required runtime benchmark category that fails on sample allocations or cursor fallback scans.
41
+ - Keep indexed pit-road state projection on reusable polyline projection plus index-owned route distance tables instead of rebuilding candidate sets, filtered segment arrays, or cumulative distance arrays for each entry/fast-lane/working-lane/exit classification, and extend the track-query benchmark with explicit pit-road probes that require grid hits, scratch reuse, precomputed route distances, zero cumulative-distance rebuilds, zero grid misses, and zero pit fallbacks.
42
+ - Keep scratch-backed rich sensor rays on stable road-edge, kerb, illegal-surface, and car-hit channel containers across repeated direct builds, while public no-scratch ray calls still receive fresh channel objects.
43
+ - Keep car-ray exact footprint checks on the caller-owned ray vector and scalar local footprint math, writing scratch-backed hits into reusable per-ray result targets and pinning zero car-ray vector recomputes in the sensor-ray runtime benchmark.
44
+ - Reuse scratch-backed ray-detectable target arrays and target wrappers across vector-only environment ray batches, so car-ray broadphase stops rebuilding target metadata containers while public no-scratch sensor calls keep fresh target arrays.
45
+ - Keep scratch-backed per-car ray target filtering on one stable filtered-target container and scalar write/count loops, so the car-ray path stops rebuilding callback-driven target lists before each ray batch and the runtime benchmark now fails if that filtered container is replaced.
46
+ - Cache normalized ray options inside scratch-backed ray batches and scalarize ray-option normalization loops, so repeated raw ray option objects no longer rebuild normalized ray/channel arrays before every rich/vector/append sensor pass.
47
+ - Reuse headless environment observation lookup scratch for controlled-driver car maps and no-event grouping, so vector-only training steps stop rebuilding those lookup containers on every result while public observation shapes stay unchanged.
48
+ - Reuse headless environment metric lookup scratch for previous/current car maps and contact-event driver grouping, so vector-only training steps stop rebuilding those metric containers on every result while contact counts still dedupe duplicate driver ids per event.
49
+ - Precompute the nearest nonlocal segment distance for each track segment through the kerb band and let hinted nearest-track queries trust local segment neighborhoods only when the current offset is geometrically provable, so centerline/near-center common paths avoid extra exact-grid refinement while close-loop and generated-track cases stay on the more defensive indexed path.
50
+ - Precompute ring-1 segment-neighborhood density per track-query cell and let low-density `track/kerb` hinted nearest-track queries trust their exact local segment neighborhood even when the nonlocal distance proof stays inconclusive, so the benchmark nearest-track path keeps the benchmark track on local geometry instead of dropping into exact-grid refinement while denser generated-track cells stay on the defensive path.
51
+ - Precompute exact ring-1 candidate segment neighborhoods for low-density query cells and let hinted gravel-adjacent nearest-track queries prove exactness by ring-2 lower bounds before falling into the full exact-grid walk, so the benchmark nearest-track path keeps most remaining gravel queries off the broader cell-search loop while denser or more ambiguous cells still fall back to the original exact refinement.
52
+ - Route low-density cell exact nearest-track queries through that grid-owned ring-2 proof before any arc-bucket prepass, so the benchmark gravel path no longer computes the radius-2 arc candidate window just to hand off to the same certified cell-neighborhood winner.
53
+ - Route outside-runoff nearest-track queries through the sparse exact segment-grid walk before arc buckets, so far-out recovery and destroyed-car classifications use the grid-owned exact proof directly instead of seeding the same exact result through a radius-2 arc candidate prepass.
54
+ - Keep benchmark-style runoff nearest-track queries on an exact radius-2 segment-neighborhood proof guarded by ring-3 cell lower bounds, and seed the fallback exact-grid walk from that same local winner when the proof does not close, so the remaining hinted runoff path avoids repeating inner-cell work while generated-track equivalence stays covered.
55
+ - Start exact-grid nearest-track refinement at the first occupied segment-grid ring instead of rescanning known-empty inner rings, so far-off accurate-hint queries skip empty-cell work before they reach real track geometry while preserving the same exact winner.
56
+ - Skip recomputing the already-seeded hinted winner segment when exact-grid nearest-track refinement starts from an initial local projection, so hinted off-track exact checks spend less time re-evaluating the same segment before scanning genuinely competing cells.
57
+ - Precompute the common radius-2 arc-bucket segment neighborhoods at track-query index build time and reuse those candidate lists on hinted arc lookups, so the dominant remaining arc-hint nearest-query path stops rebuilding and re-deduping the same five-bucket candidate window on every query.
58
+ - Precompute immutable centerline projection scalars per segment and reuse them across exact-grid, arc-bucket, candidate, and neighborhood track-query loops, so hot nearest-track projection paths stop rebuilding the same `dx`/`dy`/length-span math on every segment visit.
59
+ - Cache repeated progress-hint segment resolution and hint-point reconstruction across adjacent same-distance nearest-track queries, so the indexed hinted path stops repeating the same binary-search and hint-point reconstruction work for each offset around the same centerline sample.
60
+ - Replace the blanket pit-connector wheel-surface fallback with per-wheel connector geometry plus tighter exact local segment-neighborhood wheel-center projections for the real connector cases, batch those exact wheel-center neighborhood queries across all four wheels, skip pit-lane override work when main-track precedence already settles the wheel, and skip pit-box grid scans outside service/garage bounds, so the benchmark connector pose keeps its one-nearest-query-per-iteration shape, no longer wastes pit-box misses, and connector wheel-center queries stop rebuilding the broader default neighborhood separately for each wheel.
61
+ - Route direct `calculateWheelSurfaceState()` calls through the same scalar wheel-state writers used by the scratch-backed apply path, removing the public-path `map()`/patch-sample fallback arrays and adding a wheel-surface benchmark gate for scratchless scalar writer batches and per-wheel writes.
62
+ - Make exact local segment-neighborhood batch queries scan the shared neighborhood once for all requested wheel centers instead of rerunning the same exact neighborhood walk per wheel, so connector local-refresh path queries reuse segment data without changing exactness.
63
+ - Skip pit-lane override index work for nearest-track queries already proven to be on the main road and outside pit-box bounds, so connector-adjacent common-path track classification stays on the geometry result instead of paying unnecessary pit road/box candidate scans.
64
+ - Keep connector-adjacent pit-entry/pit-exit nearest-track classification on indexed endpoint-window road candidates keyed by track-progress hints, so the track-query benchmark no longer drops those valid cap projections onto the full pit-road polyline fallback after a road-grid miss.
65
+ - Resolve connector-adjacent pit-entry/pit-exit overrides and adjacent non-pit gravel/runoff skips directly from exact local pit-road geometry before the indexed pit-lane query path, so the benchmark track-query route keeps the remaining connector cases off pit-road grid work entirely while preserving the same pit-lane classification.
66
+ - Keep those direct connector pit-road projections on the query-index-owned reusable projection target and route-distance metadata, and extend the runtime track-query benchmark so direct connector state/skip coverage must also prove projection scratch reuse.
67
+ - Precompute pit-route endpoint segment windows and use bounded direct connector projection candidates instead of scanning full pit-entry/pit-exit polylines in connector shortcut paths, while mid-connector points without endpoint progress hints use indexed route candidates without counting as full pit-lane queries.
68
+ - Keep hinted nearest-track projections on a direct hinted-segment neighborhood through the main-road, kerb, and gravel bands, and resolve the remaining wide-runoff cases through one wider same-neighborhood segment-radius search instead of spending the extra local segment-grid refinement on the benchmark path.
69
+ - Precompute the wrapped segment-id neighborhoods for the dominant radius-2 and wide-runoff hinted nearest-track searches, so those hot local hinted paths stop rebuilding the same wrapped modulo walk on every query.
70
+ - Keep hinted and exact local segment-neighborhood track projections on direct wrapped segment loops instead of materializing temporary neighborhood id arrays first, and pin zero hinted-neighborhood id scratch materialization in the runtime benchmark contract.
71
+ - Keep nearest-track exact-grid, arc-bucket, and candidate scans on scalar candidate accumulation instead of allocating transient per-segment projection objects during the hot indexed query path, and pin zero candidate projection object allocations in the runtime benchmark contract.
72
+ - Reuse one internal nearest-track projection scratch object through `nearestTrackState()` while keeping the public nearest-track projection query fresh per call, and pin that reuse in the runtime benchmark contract so the hot indexed track-state path stops rebuilding the same transient projection container.
73
+ - Keep connector local-refresh wheel-surface handling on exact wheel-center projections alone when every exact wheel center still resolves to the main track, so that route avoids materializing redundant finalized connector queried track-state pools before falling straight back to analytic wheel-state handling.
74
+ - Keep the explicit-center connector local-refresh path on a one-pass analytic summary whenever the exact batched wheel-center neighborhood queries all stay on the main track, and add a dedicated runtime benchmark for that explicit-center route so post-runoff wheel-surface work is measured against the same path the sim actually uses during local refresh.
75
+ - Refresh automatic connector-adjacent wheel-surface center state through the existing local runoff-track fast path instead of a broad nearest-track query when a previous committed track state already exists, and pin zero nearest queries for the near-pit connector benchmark path in the runtime benchmark contract.
76
+ - Reuse the already-committed current-pose `car.trackState` directly on same-pose automatic connector-adjacent wheel-surface refreshes, so the near-pit connector benchmark no longer spends a fifth local segment-neighborhood query just to re-derive the already-valid center state.
77
+ - Prove straight connector-adjacent main-track wheel footprints analytically from the center track frame before running exact wheel-center neighborhood projections, so centered pit-straight connector local-refresh paths stay on reusable analytic wheel writes with `segmentNeighborhoodQueries: 0` and `segmentNeighborhoodBatchCalls: 0` while ambiguous pit-side wheels still use the exact connector geometry path.
78
+ - Thread the already-resolved current vehicle geometry straight through wheel-surface recomputes and delay connector sample-closure creation until the path actually needs sampled recovery, so common local-refresh wheel-surface work stops paying duplicate current-geometry reads and unused connector closures.
79
+ - Add a strict common-case wheel-surface fast path for cars whose center state is still on the main track and not near a pit connector, so the dominant local-refresh path returns directly from the analytic main-track branch instead of walking the pit/connector decision tree before landing on the same result.
80
+ - Make exact local segment-neighborhood projections write their final result into reusable target objects instead of allocating a fresh projection object for every connector/runoff exact query, and enforce that reuse on the connector wheel-surface benchmarks.
81
+ - Keep the exact connector wheel-center batch path allocation-light by reusing the queried-state target array and reusable wheel-center point refs instead of allocating a fresh batched state array and copying the results back out on every local-surface refresh.
82
+ - Skip connector wheel-center track queries entirely for connector-adjacent main-track cars whose full wheel footprint stays on the opposite half of the track from the pit-lane side, keeping those cars on the plain analytic wheel path and cutting the local-surface connector query volume back to the ambiguous cases only.
83
+ - Replace per-step timing-history `shift()` trimming and timing-line key rescans with bounded lazy compaction and cached timing-line retention bounds, and add a warmed-history runtime benchmark so long-run timing maintenance stays production-ready.
84
+ - Skip unchanged zero-travel timing-line maintenance once the retained-line prune cutoff is already current, so idle broad-commit timing updates stop rescanning stored crossing keys while still preserving the first prune/bounds catch-up pass.
85
+ - Move runtime timing-history writes onto a fixed structured ring store, so broad race-state commits stop allocating a fresh `{ time, raceDistance }` object for every car on every timing sample while keeping legacy array readers valid for tests and older internal fixtures.
86
+ - Cache the last successful structured timing-history interpolation neighborhood and probe it first on the next adjacent-gap lookup, so broad-commit interval timing stops rescanning the same timing-history window from the tail on every repeated follower-gap estimate.
87
+ - Bound timing-gap timing-line scans to the overlapping stored line window shared by the compared cars, so broad race-state commits stop walking the full retained timing-line span when the latest shared crossing already proves the interval gap.
88
+ - Skip timing-line gap scans entirely when either compared car has not stored a valid timing-line window yet, and enforce that empty-window fast path with a runtime benchmark that must perform zero timing-line crossing reads.
89
+ - Skip the timing-line helper call entirely on the common empty-window gap-estimation path, so adjacent broad-commit gap checks fall straight back to timing-history interpolation without paying extra timing-line wrapper/setup work when no stored timing-line window exists.
90
+ - Cache the last successful timing-history interpolation segment as direct distance/time scalars, so the common adjacent broad-commit gap path can reuse the same structured timing-history segment on nearby repeated targets instead of rebuilding the segment lookup from the offset cache every call.
91
+ - Flatten Policy Runner protocol `2` per-decision JSON around `driverIds`, sending aligned vector arrays, compact previous-action tuples, and compact metric tuples while moving tuple field order into reset metadata, so HTTP policy-server mode spends less bandwidth and stringify time without reintroducing rich observation payloads.
92
+ - Keep `car.trackState` and the wheel-surface cache wrapper stable across internal `applyWheelSurfaceState()` recomputes, so the exact post-physics local-refresh path stops replacing those hot-loop containers when only the track-state fields changed.
93
+ - Replace per-call wheel-surface cache signature string building with direct geometry-pose and center-state field checks, so repeated explicit-center refreshes stay on the cache-hit path without avoidable string churn.
94
+ - Split current-pose vehicle geometry reuse from swept-collision geometry reuse so pre-physics wheel-surface refreshes do not rebuild the same current wheel/body geometry just because `previousX`, `previousY`, and `previousHeading` were updated for collision history.
95
+ - Update the cached current-pose vehicle geometry state in place when the car's live pose changes, so post-physics wheel-surface refreshes stop allocating a fresh current body/wheel/corner tree for every moved car on every step.
96
+ - Keep the cached current-pose geometry writer on shared heading scalars and direct body/wheel rectangle writes, so post-motion local refresh no longer allocates temporary axis and center objects while rebuilding the stable geometry tree.
97
+ - Keep current-pose wheel/body corners lazy inside the wheel-surface geometry cache, so normal post-motion refresh only rebuilds contact-patch centers, axes, and extents while sampled recovery paths still materialize and reuse exact corners on demand.
98
+ - Drop unused string signature bookkeeping from the hot current-only vehicle-geometry cache, so post-motion local refresh stops rebuilding `x:y:heading` signature strings that runtime code never reads.
99
+ - Collapse wheel-surface result summarization into one pass so effective surface, representative offset, and track-limits ownership no longer rescan the same four wheels with separate reductions on every refresh.
100
+ - Keep scratch-backed wheel-surface classification on a reusable summary accumulator whose track-limit result is the stable `car.trackLimitState` object, so connector, pit-analytic, full-sample, and main-track refreshes write wheels, representative state, effective surface, and limit ownership in the classifier pass instead of rescanning the four wheels afterward.
101
+ - Share the projected wheel half-width across the four same-heading main-track wheel patches during the internal analytic apply path and fold analytic wheel writes plus summary into one pass, so the normal local wheel refresh stops recomputing the same projection term four times before summarizing the result again.
102
+ - Replace advanced-physics wheel-surface aggregation and left/right wheel-drag resistance `filter()` / `reduce()` passes with direct scalar loops, removing per-step array churn from the hot advanced integration path while preserving the existing wheel-state contract.
103
+ - Stop broad race-state commits from re-filtering the field for per-car aggression updates, and collapse the common race-order path into one live/DNF partition before sorting.
104
+ - Skip the excluded-participant reset scan on the normal broad-commit path when the ordered list already covers every car, and derive live field depth from the ordered live/DNF boundary instead of another per-commit reduction over the full field.
105
+ - Keep the common running `orderedCars()` path off unnecessary `id -> car` maps and redundant finished/DNF filters, so broad race-state commits only pay those lookup structures in the finished, classified, or frozen-order branches that actually need them.
106
+ - Trim the hot running `orderedCars()` path further by sorting the live field in place and appending DNF cars directly instead of cloning and reassembling extra arrays on the common branch.
107
+ - Reuse the already-built broad-commit ordered field inside finish evaluation instead of recomputing race order again at the end of every normal step, and enforce `0` finish-evaluation ordered-field rescans on the benchmark path.
108
+ - Fold timing-sample recording and timing-line crossing updates into the same per-car broad-commit loop that recomputes race distance and lap telemetry, and enforce one timing-state update per car per commit on the benchmark path.
109
+ - Keep broad-commit DRS references in a reusable per-car indexed scratch array after the physical-track-order pass instead of rebuilding a transient `Map` just to feed the ordered commit loop, and enforce one indexed DRS scratch build per broad commit on the benchmark path.
110
+ - Skip the wrapped-progress physical-order sort inside DRS reference building whenever the active live field still fits inside one lap window, while keeping the old physical-order fallback for lapped-traffic cases where the race order no longer matches the car order on track.
111
+ - Let `calculateWheelSurfaceState()` write the representative state directly into the stable `car.trackState` container on the hot `applyWheelSurfaceState()` path, removing the temporary representative-state object and follow-up copy from local wheel-surface refresh.
112
+ - Keep the advanced simulator physics path on scalar heading axes inside `integrateSimulatorVehiclePhysics()`, removing the per-step temporary `vehicleAxes()` object allocation from the hot velocity projection and acceleration reconstruction path.
113
+ - Make same-lap leader gap seconds accumulate from already-computed interval gaps inside the ordered broad-commit loop, so the normal running path stops re-estimating a separate leader-vs-car timing gap for every follower when finite interval timing is already available.
114
+ - Rework swept collision narrowphase to interpolate body-only rectangles into reusable scratch shapes instead of rebuilding full temporary vehicle geometry for every sweep step.
115
+ - Reuse SAT projection scratch and keep collision narrowphase on direct scalar axis checks instead of rebuilding per-axis projection objects and temporary axis arrays through repeated body-body overlap tests.
116
+ - Keep collision narrowphase contact results, metadata wrappers, and contact-axis containers in reusable scratch storage on hot internal calls, while preserving fresh public no-scratch collision result objects.
117
+ - Keep collision contact velocity response on scalar `velocityX/Y` math instead of rebuilding temporary vector objects for advanced-mode and pit-fixed contact damping, and pin that path in the runtime collision benchmark.
118
+ - Keep collision resolver phase containers in reusable simulation scratch storage, so collidable-car filtering and per-pass reported-contact tracking stay on arrays and typed epoch marks instead of rebuilding arrays or string-key `Set` containers on every collision phase.
119
+ - Keep collision steward context assembly on resolver-owned scratch and scalar velocity math, so fresh-contact reviews stop rebuilding spread metadata/vector helper objects before handing facts to the penalty steward.
120
+ - Emit collision steward penalties directly into the simulation ledger on the internal review path, so fresh-contact review no longer builds an intermediate penalty array before immediately recording the same payloads.
121
+ - Keep collision broadphase candidate de-duplication on scratch-owned typed pair marks, source-indexed distance entries, and reusable missing-distance flag/index arrays instead of object `Map`/`Set` bookkeeping, so hot candidate generation avoids string keys, car-order maps, and fallback sets while preserving the public pair-array result shape.
122
+ - Reuse pit-road and pit-box candidate containers inside indexed pit-lane state resolution, and extend the runtime track-query benchmark so pit-transition queries are explicitly exercised with `pitFallbacks: 0`.
123
+ - Route normal runoff barrier checks through a tiny local segment-neighborhood projection from the previous committed track frame, so main-track cars stop paying both the full nearest-track query and the broader hinted-arc path every step while pit-bound and teleport-like moves still fall back to the broader indexed query path.
124
+ - Reuse the exact local-neighborhood track-state target and returned result wrapper on the common runoff fast path, cutting per-step track-state allocation from post-physics barrier checks without changing runoff query exactness or pit-aware fallback behavior.
125
+ - Tighten the runoff fast path so only roughly meter-scale committed motion uses the smallest exact local-segment neighborhood, while larger non-teleport motion widens back to the broader exact neighborhood automatically and keeps the common benchmark path on the cheaper query radius without weakening exactness.
126
+ - Narrow pit-aware runoff broadphase to connector-only runtime bounds plus a pit-side off-track gate, so true pit-transition edge cases still fall back to the full pit-aware nearest query without collapsing the benchmark path for normal cars running down the pit straight.
127
+ - Replace per-corner runoff barrier reach scans with an analytic body/wheel/visual-footprint reach calculation, keeping barrier contact behavior while removing hot-loop corner projection work.
128
+ - Make hinted local arc projections scan deduped arc-bucket candidates directly instead of first materializing transient candidate arrays, cutting runoff and connector-adjacent query overhead without changing geometric tie-breaking behavior.
129
+ - Make full snapshot JSON serialization use a cached compact track view with rounded static geometry, decimated exported track samples encoded through `track.sampleSchema`, and no engine-only pit bounds / pit-crew metadata or duplicated pit-box/service-area team fields, cutting repeated full-state export cost without changing the live in-memory track object used by the simulator.
130
+
131
+ ### Fixes And Hardening
132
+
133
+ - Reuse render snapshot buffers, collision candidate arrays, wheel-surface containers, and timing-tower row nodes in hot paths.
134
+ - Synchronize the npm lockfile for clean-checkout installs, including optional transitive `@emnapi` entries that a warm local install can mask during `npm ci --dry-run`.
135
+
136
+ ### Migration Notes
137
+
138
+ - Update Policy Runner HTTP servers for protocol version `2`: read model inputs from `body.driverIds[index]` plus aligned `body.vectors[index]`, `body.previousActions[index]`, and `body.metrics[index]`, and cache `actionSpec`, `observationSpec`, configuration, `previousActionFields`, and `metricFields` from `/policy/reset`. There is no legacy rich-observation per-decision transport option in Policy Runner server mode.
139
+ - Browser mounts, composable simulator APIs, headless environment imports, and data helper imports keep the `3.0.0` public API shape unless they depend on Policy Runner HTTP server payloads.
140
+
141
+ ### Verification Notes
142
+
143
+ - The normal package handoff gate is `npm run check`.
144
+ - The final release gate is `npm run check:release`, which adds slow characterization coverage and the full browser smoke matrix.
145
+ - 3.0.0 comparison runs showed real environment stepping faster on the checked worst procedural seeds, including normal-profile seeds `104729`, `4101`, and `47`, and batch-training on the same seeds. A standalone adversarial ray-sensor torture sweep can be slower on kerb/gravel/runoff poses because the current tracer performs more bounded indexed exact validation to preserve driver-precision surface semantics.
146
+ - The final seed sweep covered 69 procedural seeds, 447,120 ray builds, 3,129,840 rays, 149,040 wheel classifications, and 1,380 environment steps with zero invalid ray payloads, wheel classifications, observations, nearest fallbacks, or pit fallbacks.
147
+
148
+ ## 3.0.0
149
+
150
+ ### Major Changes
151
+
152
+ - Add the semantic theme customization system. Themes may be partial, but resolved themes are complete light/dark packages; one-sided light/dark token overrides generate and cache the opposite mode, derivative theme packages cannot invent unknown tokens, component/team theme selectors are supported, and theme plus driver/team colors are validated before becoming CSS variables.
153
+ - Make indexed track queries canonical and internal. Browser mounts, headless environments, Policy Runner, model-sense visualization, and hot simulation paths now use the package-owned index, while unsuitable edge cases stay behind focused internal fallback integrations. The public `trackQueryIndex` option is removed.
154
+ - Add the playable keyboard demo and pit controls. The local preview now exposes a playable route with steering/throttle/brake controls plus pit request, commit, clear, and target compound commands through the normal expert action fields.
155
+ - Finalize the opt-in `driver` camera. Hosts can enable the control with `ui.driverCamera: true` or start directly in it with `initialCameraMode: 'driver'`; the camera follows the selected car from a lower screen anchor, rotates the world around the car heading, respects zoom bounds, and falls back safely when no selected car or snapshot is available.
156
+ - Keep `car.trackState` as a documented public snapshot shape with stable car-center track classification fields, and make package readouts tolerate partial startup or external-renderer snapshots without throwing.
157
+
158
+ ### Fixes And Hardening
159
+
160
+ - Sanitize public URL-like options such as `backLinkHref` so unsafe schemes cannot become clickable package-owned links.
161
+ - Sanitize runtime snapshot colors and escape package asset URLs before writing readout CSS values, so external-renderer or partial-snapshot data cannot inject inline style declarations.
162
+ - Harden track query correctness and performance with deterministic indexed lookup coverage and progress hints as optimization-only inputs.
163
+ - Preserve scheduler cancellation behavior in `createPaddockDriverControllerLoop()` so stopped scheduled playback cancels package-owned and custom scheduler handles cleanly.
164
+
165
+ ### Migration Notes
166
+
167
+ - Remove any host usage of `trackQueryIndex`; indexed queries are always canonical/internal in 3.0.0.
168
+ - Rename the strict physics mode from `physicsMode: 'simulator'` to `physicsMode: 'advanced'`. The old string is no longer accepted and falls back to the default `physicsMode: 'arcade'`.
169
+ - Prefer the semantic `theme` contract over one-off color aliases. Legacy aliases such as `accentColor`, `greenColor`, and `yellowColor` still map to semantic tokens for migration.
170
+ - Use `ui.driverCamera: true` when the generated camera controls should expose the Driver button, or `initialCameraMode: 'driver'` when the simulator should start in driver camera mode.
171
+ - `backLinkHref` now accepts only relative URLs, hash URLs, and absolute `http:` / `https:` URLs; unsafe or malformed values fall back to the package default.
172
+
173
+ ### Verification Notes
174
+
175
+ - The normal package handoff gate is `npm run check`.
176
+ - The final release gate is `npm run check:release`, which adds slow characterization coverage and the full browser smoke matrix.
177
+
3
178
  ## 2.0.1
4
179
 
5
180
  ### Patch Changes
@@ -11,7 +186,7 @@
11
186
  ### Major Changes
12
187
 
13
188
  - Promote the `v6` simulator work as the next major PaddockJS release. This release keeps the package boundary focused on browser-mounted simulator components, composable simulator surfaces, and browser-free JavaScript environment/control APIs.
14
- - Add the stricter opt-in `physicsMode: 'simulator'` vehicle model with 2D velocity/yaw dynamics, traction limits, speed-sensitive steering, steering scrub, slip telemetry, reduced off-road grip, and simulator-mode AI tuning. The default remains `physicsMode: 'arcade'` for existing hosts.
189
+ - Add the stricter opt-in `physicsMode: 'advanced'` vehicle model with 2D velocity/yaw dynamics, traction limits, speed-sensitive steering, steering scrub, slip telemetry, reduced off-road grip, and advanced-mode AI tuning. The default remains `physicsMode: 'arcade'` for existing hosts.
15
190
  - Add richer procedural track generation with semantic profiles (`race`, `training-short`, `training-medium`, and `training-technical`), validated connected-region centerlines, profile-level generation controls, deterministic `trackGeneration` options, DRS zones, pit-lane access geometry, and cached track query indexes.
16
191
  - Add hard barrier-wall consequences and opt-in stalled off-track DNF handling. Barrier contact now marks cars destroyed/DNF in both physics modes, while `rules.modules.stalledDnf` can retire cars that remain stopped off legal surfaces.
17
192
  - Expand the headless environment contract for real training loops: compact vector/object/full observation output, optional `Float32Array` vectors, schema caching, no-state/minimal/full result output, per-driver episode info, selected-driver resets, reset-only scenario placements, reward normalization, evaluation helpers, rollout metrics, and a shared driver-controller loop.
@@ -1,6 +1,6 @@
1
1
  # PaddockJS Install and Update Guide
2
2
 
3
- This guide explains how host websites consume the published PaddockJS npm package.
3
+ This guide explains how host websites consume the published PaddockJS npm package. For the normal browser integration path, start with [Getting Started](docs/getting-started.md). For split package-owned surfaces, use [Composable Layouts](docs/composable-layouts.md).
4
4
 
5
5
  ## Install
6
6
 
@@ -59,6 +59,8 @@ If the host bundler does not extract package CSS automatically, import the style
59
59
  import '@inventure71/paddockjs/styles.css';
60
60
  ```
61
61
 
62
+ Package CSS is scoped to PaddockJS mount roots/components and does not load remote fonts. Hosts that want custom brand typography should load those fonts in the host app and customize PaddockJS through the public theme/CSS-variable contract.
63
+
62
64
  ## Build Setup
63
65
 
64
66
  Use a browser bundler that understands JavaScript module imports, CSS imports, and image imports. Vite, Rollup, Webpack, and similar bundlers are valid fits.
@@ -112,17 +114,35 @@ npm run check
112
114
  Install a specific version when the host needs a controlled upgrade:
113
115
 
114
116
  ```bash
115
- npm install @inventure71/paddockjs@2.0.1
117
+ npm install @inventure71/paddockjs@4.0.0
116
118
  npm run check
117
119
  ```
118
120
 
119
121
  After updating, smoke-test the page that mounts the simulator. Browser behavior changes should be checked in the consuming host, because host CSS, container size, and route handling are outside the package.
120
122
 
123
+ ### 4.0.0 Migration Notes
124
+
125
+ - Update Policy Runner HTTP servers for protocol version `2`. Cache `actionSpec`, `observationSpec`, configuration, `previousActionFields`, and `metricFields` from `/policy/reset`, then read model inputs from `body.driverIds[index]` plus aligned `body.vectors[index]`, `body.previousActions[index]`, and `body.metrics[index]` in `/policy/decide-batch`. Rich observation objects, schemas, snapshots, and track metadata are no longer sent on every policy-server decision.
126
+ - Browser mounts, composable simulator APIs, headless environment imports, and data helper imports keep the `3.0.0` public API shape unless they depend on Policy Runner HTTP server payloads.
127
+
128
+ ### 3.0.0 Migration Notes
129
+
130
+ - Remove any `trackQueryIndex` host option. Indexed track queries are always canonical package internals in 3.0.0.
131
+ - Rename strict vehicle-physics usage from `physicsMode: 'simulator'` to `physicsMode: 'advanced'`. The old string is no longer accepted and will resolve to the default `physicsMode: 'arcade'`.
132
+ - Prefer the semantic `theme` contract for new customization. Partial themes are valid, resolved themes are complete, and one-sided light/dark token overrides generate and cache the opposite mode. Legacy aliases such as `accentColor`, `greenColor`, and `yellowColor` remain migration aliases.
133
+ - Use `ui.driverCamera: true` to show the generated Driver camera button, or `initialCameraMode: 'driver'` to start in that mode.
134
+ - Use `@inventure71/paddockjs/environment` for browser-free simulation/training imports.
135
+ - Use `@inventure71/paddockjs/data` for CSS-free data/helper imports such as `DriverData`, `normalizeSimulatorDrivers`, `createProceduralTrack`, and speed conversion helpers.
136
+ - `backLinkHref` is sanitized; relative URLs, hash URLs, and absolute `http:` / `https:` URLs are accepted, while unsafe schemes fall back to the package default.
137
+ - Full public snapshots include `car.trackState` for the stable car-center track classification shape.
138
+ - Rebuild the host bundle and browser-smoke the host page, including theme toggles, selected-driver surfaces, and any composable mount roots. See [Troubleshooting](docs/troubleshooting.md) if the host build fails after the upgrade.
139
+
121
140
  ## Package Release Workflow
122
141
 
123
142
  The package repo owns its release process:
124
143
 
125
- - `npm run check` runs fast runtime tests, public type verification, dry-pack verification, packed-consumer install/build verification, the tracked showcase build, and a quick Chromium browser smoke test.
144
+ - `npm run docs:check` validates documentation links and consumer-guidance guardrails.
145
+ - `npm run check` runs docs checks, fast runtime tests, public type verification, dry-pack verification, packed-consumer install/build verification, the tracked showcase build, and a quick Chromium browser smoke test.
126
146
  - `npm run check:release` runs the exhaustive release gate, including slow characterization tests and the full Chromium browser smoke matrix.
127
147
  - `npm run consumer:smoke` packs the package, installs the tarball into a fresh temporary Vite app, and builds that app through public package imports.
128
148
  - `npm run browser:smoke` builds `local-preview`, starts a local preview server, and checks desktop/mobile canvas rendering, overflow constraints, API buttons, and visual policy-runner stepping in Chromium. Use `npm run browser:smoke:quick` for the smaller local browser pass and `npm run browser:smoke:full` for the full matrix.
@@ -139,7 +159,7 @@ For trusted publishing on npm, configure the package settings to trust:
139
159
 
140
160
  No long-lived `NPM_TOKEN` secret is required once trusted publishing is enabled.
141
161
 
142
- The release PR must include synchronized `package.json`, `package-lock.json`, `CHANGELOG.md`, and Changesets output for the version being published.
162
+ The release PR must include synchronized `package.json`, `package-lock.json`, `CHANGELOG.md`, and Changesets output for the version being published. Check `npm ci` behavior from a clean checkout or temporary worktree before handoff; a warm local `node_modules` tree can hide missing optional transitive lockfile entries.
143
163
 
144
164
  ## When Something Breaks
145
165