@inventure71/paddockjs 0.3.0 → 2.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 (202) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/INSTALL_AND_UPDATE.md +5 -2
  3. package/README.md +328 -13
  4. package/docs/architecture.md +150 -41
  5. package/docs/concepts.md +22 -3
  6. package/docs/custom_model_controller.md +329 -0
  7. package/docs/data_contract.md +474 -34
  8. package/docs/data_model.md +1 -1
  9. package/docs/index.md +1 -0
  10. package/docs/learnings.md +23 -1
  11. package/docs/rules.md +169 -21
  12. package/docs/system_specs.md +56 -20
  13. package/docs/training.md +369 -25
  14. package/examples/python/README.md +62 -0
  15. package/examples/python/base_policy_server.py +191 -0
  16. package/examples/python/requirements.txt +2 -0
  17. package/examples/train-basic-policy.mjs +5 -6
  18. package/examples/trainingData.mjs +133 -0
  19. package/package.json +15 -4
  20. package/src/api/PaddockSimulatorController.js +36 -2
  21. package/src/app/BrowserExpertAdapter.js +367 -9
  22. package/src/app/F1SimulatorApp.js +615 -940
  23. package/src/app/banners/bannerFormatters.js +55 -0
  24. package/src/app/banners/raceDataBannerController.js +141 -0
  25. package/src/app/banners/stewardMessageController.js +99 -0
  26. package/src/app/camera/cameraConstants.js +21 -0
  27. package/src/app/camera/cameraController.js +265 -0
  28. package/src/app/camera/cameraGeometry.js +176 -0
  29. package/src/app/domBindings.js +14 -1
  30. package/src/app/readouts/carOverviewRenderer.js +109 -0
  31. package/src/app/readouts/controlStateRenderer.js +37 -0
  32. package/src/app/readouts/raceStatusRenderer.js +133 -0
  33. package/src/app/readouts/readoutFormatters.js +58 -0
  34. package/src/app/readouts/telemetryRenderer.js +113 -0
  35. package/src/app/readouts/timingTowerRenderer.js +177 -0
  36. package/src/app/rendering/appAssets.js +38 -0
  37. package/src/app/rendering/carRenderer.js +286 -0
  38. package/src/app/rendering/displayUtils.js +22 -0
  39. package/src/app/rendering/drsTrailRenderer.js +90 -0
  40. package/src/app/rendering/expertSensorRenderer.js +126 -0
  41. package/src/app/rendering/pitLaneStatusRenderer.js +50 -0
  42. package/src/app/rendering/replayGhostRenderer.js +124 -0
  43. package/src/app/rendering/trackRenderer.js +25 -0
  44. package/src/app/runtime/frameLoop.js +66 -0
  45. package/src/app/runtime/runtimeTiming.js +34 -0
  46. package/src/app/runtime/runtimeVisibility.js +45 -0
  47. package/src/config/defaultOptions.js +24 -4
  48. package/src/environment/actions.js +38 -7
  49. package/src/environment/controllerLoop.js +246 -0
  50. package/src/environment/episode.js +86 -2
  51. package/src/environment/evaluation.js +206 -0
  52. package/src/environment/index.d.ts +638 -6
  53. package/src/environment/index.js +14 -0
  54. package/src/environment/metrics.js +159 -0
  55. package/src/environment/observationOptions.js +33 -0
  56. package/src/environment/observations.js +500 -43
  57. package/src/environment/options.js +41 -2
  58. package/src/environment/recorder.js +28 -0
  59. package/src/environment/runtime.js +260 -24
  60. package/src/environment/scenarios.js +249 -0
  61. package/src/environment/sensors/bodySenses.js +23 -0
  62. package/src/environment/sensors/boundarySenses.js +17 -0
  63. package/src/environment/sensors/carRays.js +75 -0
  64. package/src/environment/sensors/contactSenses.js +32 -0
  65. package/src/environment/sensors/index.js +157 -0
  66. package/src/environment/sensors/indexedRayBands.js +103 -0
  67. package/src/environment/sensors/nearbyCars.js +52 -0
  68. package/src/environment/sensors/opponentRadar.js +65 -0
  69. package/src/environment/sensors/rayConfig.js +110 -0
  70. package/src/environment/sensors/rayDefaults.js +6 -0
  71. package/src/environment/sensors/rayGeometry.js +60 -0
  72. package/src/environment/sensors/rayGuards.js +19 -0
  73. package/src/environment/sensors/sensorTargets.js +60 -0
  74. package/src/environment/sensors/surfaceRays.js +296 -0
  75. package/src/environment/sensors/trackRays.js +261 -0
  76. package/src/environment/sensors.js +1 -257
  77. package/src/environment/specs.js +188 -9
  78. package/src/environment/workerProtocol.js +64 -0
  79. package/src/index.d.ts +533 -7
  80. package/src/index.js +26 -0
  81. package/src/rendering/proceduralTrackAsset.js +20 -510
  82. package/src/rendering/renderSnapshot.js +38 -12
  83. package/src/rendering/track/finishLineRenderer.js +34 -0
  84. package/src/rendering/track/gridRenderer.js +47 -0
  85. package/src/rendering/track/offsetStrokeSafety.js +136 -0
  86. package/src/rendering/track/pitLaneRenderer.js +248 -0
  87. package/src/rendering/track/trackMaterialRenderer.js +326 -0
  88. package/src/rendering/track/trackRenderConstants.js +38 -0
  89. package/src/rendering/track/trackRenderGeometry.js +94 -0
  90. package/src/simulation/collisionGeometry.js +214 -0
  91. package/src/simulation/driver/driverControlConstants.js +28 -0
  92. package/src/simulation/driver/driverController.js +47 -0
  93. package/src/simulation/driver/driverInput.js +28 -0
  94. package/src/simulation/driver/driverMath.js +6 -0
  95. package/src/simulation/driver/driverPersonality.js +25 -0
  96. package/src/simulation/driver/edgeRecovery.js +48 -0
  97. package/src/simulation/driver/racingControls.js +399 -0
  98. package/src/simulation/driver/racingLinePlan.js +166 -0
  99. package/src/simulation/driver/recoveryDynamics.js +38 -0
  100. package/src/simulation/driver/rejoinControls.js +213 -0
  101. package/src/simulation/driver/safetyCarControls.js +35 -0
  102. package/src/simulation/driver/trafficScan.js +51 -0
  103. package/src/simulation/driverController.js +4 -253
  104. package/src/simulation/participants/participantInteractions.js +120 -0
  105. package/src/simulation/pit/pitFlow.js +234 -0
  106. package/src/simulation/pit/pitIntent.js +92 -0
  107. package/src/simulation/pit/pitOccupancy.js +47 -0
  108. package/src/simulation/pit/pitPenaltyService.js +71 -0
  109. package/src/simulation/pit/pitQueue.js +55 -0
  110. package/src/simulation/pit/pitRouteMovement.js +160 -0
  111. package/src/simulation/pit/pitRouting.js +319 -0
  112. package/src/simulation/pit/pitService.js +41 -0
  113. package/src/simulation/pit/pitServiceConstants.js +21 -0
  114. package/src/simulation/pit/pitServiceProfile.js +45 -0
  115. package/src/simulation/pit/pitSnapshots.js +61 -0
  116. package/src/simulation/pit/pitState.js +113 -0
  117. package/src/simulation/pit/pitTireService.js +92 -0
  118. package/src/simulation/race/classification.js +104 -0
  119. package/src/simulation/race/gridPenalties.js +37 -0
  120. package/src/simulation/race/raceControlState.js +38 -0
  121. package/src/simulation/race/raceDistance.js +32 -0
  122. package/src/simulation/race/raceFinish.js +65 -0
  123. package/src/simulation/race/raceLifecycle.js +71 -0
  124. package/src/simulation/race/raceOrder.js +113 -0
  125. package/src/simulation/race/raceProgress.js +124 -0
  126. package/src/simulation/race/raceSetup.js +93 -0
  127. package/src/simulation/race/raceStep.js +80 -0
  128. package/src/simulation/race/redFlag.js +15 -0
  129. package/src/simulation/race/retirements.js +44 -0
  130. package/src/simulation/race/safetyCar.js +86 -0
  131. package/src/simulation/race/stalledDnf.js +86 -0
  132. package/src/simulation/raceSimulation.js +386 -1012
  133. package/src/simulation/replay/replayGhosts.js +128 -0
  134. package/src/simulation/rules/collisionSteward.js +69 -0
  135. package/src/simulation/rules/moduleConfig.js +72 -0
  136. package/src/simulation/rules/penaltyConfig.js +99 -0
  137. package/src/simulation/rules/penaltyEvents.js +18 -0
  138. package/src/simulation/rules/penaltyLedger.js +153 -0
  139. package/src/simulation/rules/penaltyStats.js +26 -0
  140. package/src/simulation/rules/pitLaneSpeedingSteward.js +71 -0
  141. package/src/simulation/rules/ruleConfigMerge.js +41 -0
  142. package/src/simulation/rules/ruleDefaults.js +85 -0
  143. package/src/simulation/rules/rulesReview.js +141 -0
  144. package/src/simulation/rules/rulesetPresets.js +47 -0
  145. package/src/simulation/rules/tireRequirementSteward.js +29 -0
  146. package/src/simulation/rules/trackLimitsSteward.js +85 -0
  147. package/src/simulation/rulesConfig.js +34 -0
  148. package/src/simulation/snapshots/raceSnapshots.js +192 -0
  149. package/src/simulation/timing/drsTiming.js +87 -0
  150. package/src/simulation/timing/gapEstimation.js +38 -0
  151. package/src/simulation/timing/lapTelemetry.js +182 -0
  152. package/src/simulation/timing/raceTiming.js +15 -0
  153. package/src/simulation/timing/sectorPerformance.js +60 -0
  154. package/src/simulation/timing/timingConstants.js +5 -0
  155. package/src/simulation/timing/timingHistory.js +46 -0
  156. package/src/simulation/timing/timingLines.js +79 -0
  157. package/src/simulation/track/centerlineSpline.js +59 -0
  158. package/src/simulation/track/drsZones.js +67 -0
  159. package/src/simulation/track/pitLaneAccess.js +103 -0
  160. package/src/simulation/track/pitLaneLayout.js +395 -0
  161. package/src/simulation/track/pitLaneState.js +160 -0
  162. package/src/simulation/track/proceduralCenterline.js +237 -0
  163. package/src/simulation/track/sampleGeometry.js +49 -0
  164. package/src/simulation/track/spatialQueries.js +154 -0
  165. package/src/simulation/track/startStraight.js +141 -0
  166. package/src/simulation/track/trackConstants.js +109 -0
  167. package/src/simulation/track/trackGenerationOptions.js +283 -0
  168. package/src/simulation/track/trackMath.js +241 -0
  169. package/src/simulation/track/trackModel.js +240 -0
  170. package/src/simulation/track/trackQueryIndex.js +945 -0
  171. package/src/simulation/track/trackSectors.js +19 -0
  172. package/src/simulation/track/trackStatePolicy.js +24 -0
  173. package/src/simulation/track/trackValidation.js +98 -0
  174. package/src/simulation/trackModel.js +1 -628
  175. package/src/simulation/units.js +6 -4
  176. package/src/simulation/vehicle/contactResolution.js +116 -0
  177. package/src/simulation/vehicle/mainTrackWheelSurface.js +82 -0
  178. package/src/simulation/vehicle/pitWheelSurface.js +69 -0
  179. package/src/simulation/vehicle/runoffResponse.js +88 -0
  180. package/src/simulation/vehicle/surfacePriority.js +28 -0
  181. package/src/simulation/vehicle/vehicleGeometry.js +247 -0
  182. package/src/simulation/vehicle/vehiclePhysics.js +363 -0
  183. package/src/simulation/vehicle/vehicleSnapshots.js +316 -0
  184. package/src/simulation/vehicle/vehicleState.js +186 -0
  185. package/src/simulation/vehicle/wheelSurface.js +150 -0
  186. package/src/simulation/vehicleGeometry.js +1 -0
  187. package/src/simulation/vehiclePhysics.js +1 -104
  188. package/src/simulation/warmup/runtimeWarmup.js +224 -0
  189. package/src/simulation/wheelSurface.js +1 -0
  190. package/src/styles.css +342 -42
  191. package/src/ui/bannerTemplates.js +69 -0
  192. package/src/ui/cameraControlsTemplate.js +20 -0
  193. package/src/ui/carOverviewTemplate.js +33 -0
  194. package/src/ui/componentTemplates.js +20 -426
  195. package/src/ui/raceCanvasTemplate.js +69 -0
  196. package/src/ui/raceControlStatusBanner.js +39 -0
  197. package/src/ui/raceControlsTemplate.js +36 -0
  198. package/src/ui/shellTemplate.js +6 -5
  199. package/src/ui/telemetryDrawerTemplate.js +55 -0
  200. package/src/ui/telemetryTemplates.js +136 -0
  201. package/src/ui/templateUtils.js +23 -0
  202. package/src/ui/timingTowerTemplate.js +34 -0
package/src/styles.css CHANGED
@@ -10,6 +10,7 @@
10
10
  --text: #f4f7fb;
11
11
  --muted: #8d97a7;
12
12
  --red: var(--paddock-accent-color, #e10600);
13
+ --race-control-red: #e10600;
13
14
  --green: var(--paddock-green-color, #14c784);
14
15
  --yellow: var(--paddock-yellow-color, #ffd166);
15
16
  --blue: #39a7ff;
@@ -68,6 +69,8 @@
68
69
 
69
70
  .sim-backlink,
70
71
  .sim-control {
72
+ min-width: 0;
73
+ overflow: hidden;
71
74
  border: 1px solid var(--line-strong);
72
75
  color: var(--text);
73
76
  background: rgba(255, 255, 255, 0.05);
@@ -77,6 +80,8 @@
77
80
  font-size: 0.76rem;
78
81
  font-weight: 800;
79
82
  padding: 0.75rem 0.9rem;
83
+ text-overflow: ellipsis;
84
+ white-space: nowrap;
80
85
  cursor: pointer;
81
86
  }
82
87
 
@@ -92,7 +97,8 @@
92
97
  border-color: var(--yellow);
93
98
  }
94
99
 
95
- .camera-controls button.is-active {
100
+ .camera-controls button.is-active,
101
+ .camera-controls button[aria-pressed='true'] {
96
102
  color: #08090b;
97
103
  background: var(--text);
98
104
  border-color: var(--text);
@@ -121,6 +127,7 @@
121
127
  }
122
128
 
123
129
  .sim-controls {
130
+ min-width: 0;
124
131
  display: flex;
125
132
  gap: 0.6rem;
126
133
  justify-content: flex-end;
@@ -128,7 +135,7 @@
128
135
 
129
136
  .sim-external-camera-controls {
130
137
  display: flex;
131
- justify-content: flex-end;
138
+ justify-content: flex-start;
132
139
  }
133
140
 
134
141
  .sim-grid {
@@ -136,7 +143,7 @@
136
143
  min-height: 0;
137
144
  position: relative;
138
145
  display: grid;
139
- grid-template-columns: minmax(255px, 0.78fr) minmax(500px, 3fr) minmax(270px, 0.9fr);
146
+ grid-template-columns: minmax(0, 0.78fr) minmax(0, 3fr) minmax(0, 0.9fr);
140
147
  gap: 0.9rem;
141
148
  }
142
149
 
@@ -229,12 +236,12 @@
229
236
  }
230
237
 
231
238
  .sim-shell--left-tower-overlay .race-data-panel {
232
- z-index: 8;
239
+ z-index: 12;
233
240
  grid-template-columns: clamp(4.6rem, 7.5cqw, 7rem) minmax(0, 1fr) auto;
234
241
  }
235
242
 
236
243
  .sim-canvas-panel--with-timing-tower .race-data-panel {
237
- z-index: 8;
244
+ z-index: 12;
238
245
  grid-template-columns: clamp(4.6rem, 7.5cqw, 7rem) minmax(0, 1fr) auto;
239
246
  }
240
247
 
@@ -296,8 +303,13 @@
296
303
 
297
304
  .telemetry-stack {
298
305
  display: grid;
306
+ grid-auto-rows: max-content;
307
+ align-content: start;
299
308
  gap: 0.72rem;
300
309
  min-height: 0;
310
+ max-height: 100%;
311
+ overflow-y: auto;
312
+ scrollbar-width: thin;
301
313
  }
302
314
 
303
315
  .telemetry-stack > .sim-telemetry {
@@ -360,7 +372,7 @@
360
372
 
361
373
  .broadcast-brand,
362
374
  .broadcast-lap,
363
- .broadcast-safety-banner,
375
+ .broadcast-race-control-banner,
364
376
  .broadcast-column-head,
365
377
  .timing-list {
366
378
  position: relative;
@@ -409,21 +421,31 @@
409
421
  letter-spacing: -0.04em;
410
422
  }
411
423
 
412
- .broadcast-safety-banner {
424
+ .broadcast-race-control-banner {
413
425
  display: grid;
414
426
  grid-template-columns: 3.4rem minmax(0, 1fr);
415
427
  align-items: center;
416
428
  margin: 0;
429
+ background: rgba(255, 255, 255, 0.16);
430
+ color: #fff;
431
+ text-transform: uppercase;
432
+ }
433
+
434
+ .broadcast-race-control-banner.is-safety-car {
417
435
  background: #e0ce00;
418
436
  color: #0a0b0d;
419
- text-transform: uppercase;
420
437
  }
421
438
 
422
- .broadcast-safety-banner[hidden] {
439
+ .broadcast-race-control-banner.is-red-flag {
440
+ background: var(--race-control-red);
441
+ color: #fff;
442
+ }
443
+
444
+ .broadcast-race-control-banner[hidden] {
423
445
  display: none;
424
446
  }
425
447
 
426
- .broadcast-safety-banner span {
448
+ .broadcast-race-control-banner span {
427
449
  display: grid;
428
450
  place-items: center;
429
451
  min-height: 2.65rem;
@@ -434,7 +456,7 @@
434
456
  letter-spacing: -0.06em;
435
457
  }
436
458
 
437
- .broadcast-safety-banner strong {
459
+ .broadcast-race-control-banner strong {
438
460
  padding: 0 0.65rem;
439
461
  font-size: 1.1rem;
440
462
  font-weight: 900;
@@ -562,6 +584,11 @@
562
584
  scrollbar-width: thin;
563
585
  }
564
586
 
587
+ .timing-list > li {
588
+ min-width: 0;
589
+ overflow: hidden;
590
+ }
591
+
565
592
  .sim-shell--left-tower-overlay .timing-list {
566
593
  overflow-x: hidden;
567
594
  overflow-y: auto;
@@ -603,6 +630,10 @@
603
630
  min-width: 0;
604
631
  }
605
632
 
633
+ .timing-row > * {
634
+ min-width: 0;
635
+ }
636
+
606
637
  .sim-shell--left-tower-overlay .timing-row {
607
638
  min-width: 0;
608
639
  }
@@ -622,6 +653,28 @@
622
653
  0 0 0 1px rgba(255, 255, 255, 0.68);
623
654
  }
624
655
 
656
+ .timing-row.is-dnf {
657
+ color: rgba(244, 247, 251, 0.56);
658
+ background:
659
+ linear-gradient(90deg, rgba(148, 163, 184, 0.14), transparent 42%),
660
+ rgba(10, 12, 17, 0.58);
661
+ }
662
+
663
+ .timing-row.is-dnf .timing-icon,
664
+ .timing-row.is-dnf .timing-tire {
665
+ filter: grayscale(1);
666
+ opacity: 0.64;
667
+ }
668
+
669
+ .timing-row.is-dnf .timing-position {
670
+ color: rgba(244, 247, 251, 0.68);
671
+ background: rgba(30, 35, 44, 0.78);
672
+ }
673
+
674
+ .timing-row.is-dnf .timing-gap {
675
+ color: rgba(244, 247, 251, 0.68);
676
+ }
677
+
625
678
  .timing-position,
626
679
  .timing-icon,
627
680
  .timing-tire,
@@ -668,7 +721,9 @@
668
721
 
669
722
  .timing-name {
670
723
  min-width: 0;
671
- display: block;
724
+ display: flex;
725
+ align-items: center;
726
+ gap: 0.26rem;
672
727
  overflow: hidden;
673
728
  padding-inline: 0.45rem;
674
729
  font-size: 0.76rem;
@@ -680,11 +735,37 @@
680
735
  text-transform: uppercase;
681
736
  }
682
737
 
738
+ .timing-name > span:first-child {
739
+ min-width: 0;
740
+ overflow: hidden;
741
+ text-overflow: ellipsis;
742
+ }
743
+
744
+ .timing-penalty-badge {
745
+ flex: 0 0 auto;
746
+ display: grid;
747
+ place-items: center;
748
+ width: 1rem;
749
+ height: 1rem;
750
+ color: #fff;
751
+ background: #e10600;
752
+ border: 1px solid rgba(255, 220, 220, 0.78);
753
+ border-radius: 0.18rem;
754
+ font-family: var(--font-mono);
755
+ font-size: 0.66rem;
756
+ font-weight: 900;
757
+ line-height: 1;
758
+ box-shadow: 0 0 14px rgba(225, 6, 0, 0.42);
759
+ }
760
+
683
761
  .timing-gap {
684
762
  color: rgba(244, 247, 251, 0.76);
685
763
  font-size: 0.66rem;
764
+ overflow: hidden;
686
765
  padding-right: 0.25rem;
687
766
  text-align: right;
767
+ text-overflow: ellipsis;
768
+ white-space: nowrap;
688
769
  }
689
770
 
690
771
  .timing-row.is-selected .timing-gap {
@@ -728,6 +809,11 @@
728
809
  .track-canvas {
729
810
  position: absolute;
730
811
  inset: 0;
812
+ z-index: 0;
813
+ background: #2e7d32;
814
+ cursor: default;
815
+ user-select: none;
816
+ touch-action: auto;
731
817
  }
732
818
 
733
819
  .track-canvas canvas {
@@ -736,21 +822,63 @@
736
822
  display: block;
737
823
  }
738
824
 
825
+ .physics-mode-indicator {
826
+ position: absolute;
827
+ z-index: 18;
828
+ top: 0.85rem;
829
+ left: 0.85rem;
830
+ width: 0.8rem;
831
+ height: 0.8rem;
832
+ border: 1px solid rgba(255, 255, 255, 0.72);
833
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.7), 0 0 12px rgba(0, 0, 0, 0.52);
834
+ pointer-events: none;
835
+ }
836
+
837
+ .physics-mode-indicator--arcade {
838
+ background: #168cff;
839
+ }
840
+
841
+ .physics-mode-indicator--simulator {
842
+ background: #e10600;
843
+ }
844
+
739
845
  .race-telemetry-drawer {
740
846
  --telemetry-drawer-width: min(390px, max(300px, 30cqw));
847
+ --race-toolbar-height: 3.4rem;
741
848
  position: relative;
742
- display: block;
849
+ display: flex;
850
+ flex-direction: column;
743
851
  container-type: inline-size;
744
852
  inline-size: 100%;
745
- min-height: var(--paddock-race-view-min-height, 620px);
853
+ max-inline-size: 100%;
854
+ height: var(--paddock-race-view-height, var(--paddock-race-view-min-height, 620px));
855
+ min-height: min(100%, var(--paddock-race-view-min-height, 620px));
746
856
  overflow: hidden;
747
857
  background: #000;
748
858
  }
749
859
 
860
+ .race-telemetry-drawer__toolbar {
861
+ position: relative;
862
+ z-index: 13;
863
+ display: flex;
864
+ align-items: center;
865
+ justify-content: space-between;
866
+ gap: 0.7rem;
867
+ min-height: var(--race-toolbar-height);
868
+ padding: 0.45rem;
869
+ background: #090b0d;
870
+ border-bottom: 1px solid var(--line);
871
+ }
872
+
873
+ .race-telemetry-drawer__toolbar .camera-controls--external {
874
+ flex: 1 1 auto;
875
+ }
876
+
750
877
  .race-telemetry-drawer__race {
751
878
  min-width: 0;
752
879
  display: flex;
753
- min-height: inherit;
880
+ flex: 1 1 auto;
881
+ min-height: 0;
754
882
  margin-right: 0;
755
883
  transition: margin-right 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
756
884
  }
@@ -761,15 +889,12 @@
761
889
 
762
890
  .race-telemetry-drawer__race > .sim-canvas-panel {
763
891
  flex: 1 1 auto;
764
- min-height: inherit;
765
- height: auto;
892
+ min-height: 0;
893
+ height: 100%;
766
894
  }
767
895
 
768
896
  .race-telemetry-drawer__controls {
769
- position: absolute;
770
- z-index: 12;
771
- top: 1rem;
772
- right: 1rem;
897
+ min-width: 0;
773
898
  display: flex;
774
899
  flex-wrap: wrap;
775
900
  justify-content: flex-end;
@@ -780,7 +905,6 @@
780
905
  .race-telemetry-drawer__controls .telemetry-drawer-toggle {
781
906
  min-height: 2.45rem;
782
907
  padding: 0.62rem 0.72rem;
783
- box-shadow: 0 14px 34px rgba(0, 0, 0, 0.3);
784
908
  }
785
909
 
786
910
  .telemetry-drawer-toggle {
@@ -798,47 +922,46 @@
798
922
  .telemetry-drawer {
799
923
  position: absolute;
800
924
  z-index: 11;
801
- top: 0;
925
+ top: var(--race-toolbar-height);
802
926
  right: 0;
803
927
  bottom: 0;
804
928
  width: var(--telemetry-drawer-width);
805
929
  min-width: 0;
806
- height: 100%;
930
+ height: calc(100% - var(--race-toolbar-height));
807
931
  overflow: hidden;
808
932
  color: var(--text);
809
933
  background:
810
934
  linear-gradient(180deg, rgba(255, 255, 255, 0.075), transparent 22%),
811
935
  rgba(8, 9, 11, 0.97);
812
936
  border-left: 1px solid var(--line);
813
- transform: translate3d(100%, 0, 0);
937
+ clip-path: inset(0 0 0 100%);
938
+ transform: translate3d(0, 0, 0);
814
939
  opacity: 0;
815
940
  pointer-events: none;
816
941
  will-change: transform, opacity;
817
942
  transition:
818
- transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1),
943
+ clip-path 320ms cubic-bezier(0.2, 0.8, 0.2, 1),
819
944
  opacity 180ms ease;
820
945
  }
821
946
 
822
947
  .race-telemetry-drawer.is-telemetry-open .telemetry-drawer {
823
- transform: translate3d(0, 0, 0);
948
+ clip-path: inset(0);
824
949
  opacity: 1;
825
950
  pointer-events: auto;
826
951
  }
827
952
 
828
- .telemetry-drawer__header {
829
- min-height: 3.4rem;
830
- border-bottom: 1px solid var(--line);
831
- }
832
-
833
953
  .telemetry-drawer__content {
834
- display: grid;
835
- gap: 0.72rem;
836
- height: calc(100% - 3.4rem);
954
+ height: 100%;
837
955
  padding: 0.72rem;
838
- overflow-y: auto;
956
+ min-height: 0;
957
+ overflow: hidden;
839
958
  scrollbar-width: thin;
840
959
  }
841
960
 
961
+ .telemetry-drawer__content > .telemetry-stack {
962
+ height: 100%;
963
+ }
964
+
842
965
  .camera-controls {
843
966
  position: absolute;
844
967
  top: 1rem;
@@ -855,6 +978,8 @@
855
978
 
856
979
  .camera-controls--external {
857
980
  position: relative;
981
+ top: auto;
982
+ left: auto;
858
983
  max-width: 100%;
859
984
  justify-content: flex-end;
860
985
  background: rgba(8, 9, 11, 0.84);
@@ -877,6 +1002,89 @@
877
1002
  border-color: var(--text);
878
1003
  }
879
1004
 
1005
+ .steward-message {
1006
+ --steward-panel-bg: rgba(8, 9, 11, 0.92);
1007
+ --steward-chip-bg: color-mix(in srgb, var(--steward-color, var(--yellow)) 18%, rgba(8, 9, 11, 0.94));
1008
+ --steward-chip-color: var(--steward-color, var(--yellow));
1009
+ position: absolute;
1010
+ top: 1rem;
1011
+ left: 50%;
1012
+ z-index: 8;
1013
+ display: grid;
1014
+ grid-template-columns: auto minmax(0, 1fr);
1015
+ gap: 0.16rem 0.7rem;
1016
+ min-width: min(28rem, calc(100% - 2rem));
1017
+ max-width: min(34rem, calc(100% - 2rem));
1018
+ padding: 0.62rem 0.75rem;
1019
+ color: var(--text);
1020
+ background: var(--steward-panel-bg);
1021
+ border: 1px solid color-mix(in srgb, var(--steward-color, var(--yellow)) 70%, transparent);
1022
+ box-shadow:
1023
+ inset 0 3px 0 var(--steward-color, var(--yellow)),
1024
+ 0 16px 40px rgba(0, 0, 0, 0.34);
1025
+ transform: translate(-50%, 0);
1026
+ opacity: 1;
1027
+ pointer-events: none;
1028
+ transition:
1029
+ opacity 160ms ease,
1030
+ transform 160ms ease;
1031
+ }
1032
+
1033
+ .steward-message.is-penalty {
1034
+ --steward-panel-bg: linear-gradient(110deg, rgba(68, 6, 8, 0.96), rgba(8, 9, 11, 0.94) 58%);
1035
+ --steward-chip-bg: #e10600;
1036
+ --steward-chip-color: #fff;
1037
+ }
1038
+
1039
+ .steward-message.is-warning {
1040
+ --steward-panel-bg: linear-gradient(110deg, rgba(70, 56, 8, 0.96), rgba(8, 9, 11, 0.94) 58%);
1041
+ --steward-chip-bg: var(--yellow);
1042
+ --steward-chip-color: #111318;
1043
+ }
1044
+
1045
+ .steward-message.is-hidden {
1046
+ opacity: 0;
1047
+ transform: translate(-50%, -0.55rem);
1048
+ }
1049
+
1050
+ .steward-message__kicker {
1051
+ grid-row: span 2;
1052
+ align-self: center;
1053
+ min-width: 4.9rem;
1054
+ padding: 0.48rem 0.62rem;
1055
+ color: var(--steward-chip-color);
1056
+ background: var(--steward-chip-bg);
1057
+ border: 1px solid color-mix(in srgb, var(--steward-chip-color) 34%, transparent);
1058
+ font-family: var(--font-mono);
1059
+ font-size: 1.05rem;
1060
+ font-weight: 900;
1061
+ letter-spacing: 0.02em;
1062
+ line-height: 1;
1063
+ text-align: center;
1064
+ text-transform: uppercase;
1065
+ }
1066
+
1067
+ .steward-message strong {
1068
+ min-width: 0;
1069
+ overflow-wrap: anywhere;
1070
+ overflow: hidden;
1071
+ color: var(--text);
1072
+ font-size: 0.92rem;
1073
+ line-height: 1.08;
1074
+ text-transform: uppercase;
1075
+ white-space: normal;
1076
+ }
1077
+
1078
+ .steward-message span:last-child {
1079
+ min-width: 0;
1080
+ overflow-wrap: anywhere;
1081
+ overflow: hidden;
1082
+ color: var(--muted);
1083
+ font-size: 0.7rem;
1084
+ text-overflow: ellipsis;
1085
+ white-space: normal;
1086
+ }
1087
+
880
1088
  .fps-counter {
881
1089
  position: absolute;
882
1090
  top: 1rem;
@@ -1133,11 +1341,13 @@
1133
1341
  left: var(--race-data-banner-left);
1134
1342
  bottom: 1.2rem;
1135
1343
  transform: translateX(var(--race-data-banner-translate-x));
1136
- z-index: 8;
1344
+ z-index: 12;
1137
1345
  display: grid;
1138
- grid-template-columns: clamp(6.5rem, 12vw, 9.6rem) minmax(280px, 1fr) auto;
1346
+ grid-template-columns: clamp(6.5rem, 12vw, 9.6rem) minmax(0, 1fr) auto;
1139
1347
  align-items: center;
1140
1348
  width: var(--race-data-banner-width);
1349
+ max-width: calc(100% - 1.5rem);
1350
+ min-width: 0;
1141
1351
  min-height: 104px;
1142
1352
  color: var(--text);
1143
1353
  background:
@@ -1187,15 +1397,78 @@
1187
1397
 
1188
1398
  .race-data-copy,
1189
1399
  .race-data-number,
1190
- .race-data-link {
1400
+ .race-data-link,
1401
+ .race-data-dismiss {
1191
1402
  position: relative;
1192
1403
  z-index: 1;
1193
1404
  }
1194
1405
 
1406
+ .race-data-dismiss {
1407
+ --race-data-dismiss-icon-color: rgba(244, 247, 251, 0.9);
1408
+ position: absolute;
1409
+ top: 0.44rem;
1410
+ right: 0.48rem;
1411
+ display: grid;
1412
+ place-items: center;
1413
+ width: 0.95rem;
1414
+ height: 0.95rem;
1415
+ padding: 0;
1416
+ overflow: hidden;
1417
+ color: transparent;
1418
+ background: rgba(8, 10, 16, 0.62);
1419
+ border: 1px solid rgba(244, 247, 251, 0.24);
1420
+ border-radius: 999px;
1421
+ font-family: var(--font-mono);
1422
+ font-size: 0;
1423
+ font-weight: 900;
1424
+ line-height: 0;
1425
+ text-transform: none;
1426
+ white-space: nowrap;
1427
+ z-index: 4;
1428
+ }
1429
+
1430
+ .race-data-dismiss::before,
1431
+ .race-data-dismiss::after {
1432
+ content: "";
1433
+ position: absolute;
1434
+ left: 50%;
1435
+ top: 50%;
1436
+ width: 0.48rem;
1437
+ height: 0.1rem;
1438
+ background: var(--race-data-dismiss-icon-color);
1439
+ border-radius: 999px;
1440
+ }
1441
+
1442
+ .race-data-dismiss::before {
1443
+ transform: translate(-50%, -50%) rotate(45deg);
1444
+ }
1445
+
1446
+ .race-data-dismiss::after {
1447
+ transform: translate(-50%, -50%) rotate(-45deg);
1448
+ }
1449
+
1450
+ .race-data-dismiss:hover {
1451
+ --race-data-dismiss-icon-color: #fff;
1452
+ color: transparent;
1453
+ border-color: color-mix(in srgb, var(--driver-color, var(--red)) 70%, #ffffff);
1454
+ background: color-mix(in srgb, var(--driver-color, var(--red)) 52%, rgba(8, 10, 16, 0.72));
1455
+ }
1456
+
1457
+ .race-data-dismiss:focus-visible {
1458
+ outline: 2px solid var(--driver-color, var(--red));
1459
+ outline-offset: 2px;
1460
+ }
1461
+
1462
+ .race-data-panel--with-telemetry .race-data-dismiss,
1463
+ .race-data-panel.is-radio-mode .race-data-dismiss {
1464
+ z-index: 4;
1465
+ }
1466
+
1195
1467
  .race-data-copy {
1196
1468
  grid-column: 2;
1197
1469
  grid-row: 1;
1198
1470
  min-width: 0;
1471
+ overflow: hidden;
1199
1472
  padding: 0.92rem 1.45rem 0.98rem 0.55rem;
1200
1473
  }
1201
1474
 
@@ -1223,6 +1496,9 @@
1223
1496
 
1224
1497
  .race-data-subtitle {
1225
1498
  display: block;
1499
+ overflow: hidden;
1500
+ text-overflow: ellipsis;
1501
+ white-space: nowrap;
1226
1502
  margin-top: 0.28rem;
1227
1503
  color: rgba(244, 247, 251, 0.72);
1228
1504
  font-family: var(--font-mono);
@@ -1259,7 +1535,7 @@
1259
1535
  }
1260
1536
 
1261
1537
  .race-data-panel--with-telemetry {
1262
- grid-template-columns: clamp(6.5rem, 11vw, 8.7rem) minmax(220px, 1fr) minmax(190px, 0.48fr) auto;
1538
+ grid-template-columns: clamp(6.5rem, 11vw, 8.7rem) minmax(0, 1fr) minmax(150px, 0.48fr) auto;
1263
1539
  min-height: 112px;
1264
1540
  }
1265
1541
 
@@ -1308,7 +1584,7 @@
1308
1584
  }
1309
1585
 
1310
1586
  .race-data-panel.is-radio-mode {
1311
- grid-template-columns: minmax(280px, 1fr);
1587
+ grid-template-columns: minmax(0, 1fr);
1312
1588
  }
1313
1589
 
1314
1590
  .race-data-panel.is-radio-mode .race-data-copy {
@@ -1360,9 +1636,13 @@
1360
1636
  place-items: center;
1361
1637
  align-self: center;
1362
1638
  min-width: clamp(132px, 13vw, 176px);
1639
+ max-width: calc(100% - 0.85rem);
1363
1640
  min-height: 3.1rem;
1364
1641
  margin-right: 0.85rem;
1365
1642
  padding: 0 1.05rem;
1643
+ overflow: hidden;
1644
+ text-overflow: ellipsis;
1645
+ white-space: nowrap;
1366
1646
  color: #f6f8fb;
1367
1647
  background: color-mix(in srgb, var(--driver-color, var(--red)) 88%, #111318);
1368
1648
  border: 1px solid color-mix(in srgb, var(--driver-color, var(--red)) 72%, #ffffff);
@@ -1382,6 +1662,9 @@
1382
1662
 
1383
1663
  .telemetry-grid dt {
1384
1664
  display: block;
1665
+ min-width: 0;
1666
+ overflow: hidden;
1667
+ text-overflow: ellipsis;
1385
1668
  margin-bottom: 0.22rem;
1386
1669
  color: var(--muted);
1387
1670
  font-family: var(--font-mono);
@@ -1392,6 +1675,10 @@
1392
1675
  }
1393
1676
 
1394
1677
  .telemetry-grid dd {
1678
+ min-width: 0;
1679
+ overflow: hidden;
1680
+ text-overflow: ellipsis;
1681
+ white-space: nowrap;
1395
1682
  margin: 0;
1396
1683
  font-family: var(--font-mono);
1397
1684
  font-size: clamp(0.86rem, 1.6vw, 1.15rem);
@@ -1417,9 +1704,10 @@
1417
1704
  }
1418
1705
 
1419
1706
  .telemetry-grid > div {
1707
+ min-width: 0;
1420
1708
  display: flex;
1421
1709
  justify-content: space-between;
1422
- gap: 1rem;
1710
+ gap: 0.55rem;
1423
1711
  padding: 0.82rem 0.7rem;
1424
1712
  background: var(--surface-panel);
1425
1713
  }
@@ -1621,6 +1909,8 @@
1621
1909
  .telemetry-lap-table,
1622
1910
  .telemetry-sector-table {
1623
1911
  width: 100%;
1912
+ min-width: 0;
1913
+ table-layout: fixed;
1624
1914
  border-collapse: collapse;
1625
1915
  overflow: hidden;
1626
1916
  background: rgba(255, 255, 255, 0.045);
@@ -1641,10 +1931,13 @@
1641
1931
  .telemetry-lap-table td,
1642
1932
  .telemetry-sector-table th,
1643
1933
  .telemetry-sector-table td {
1934
+ overflow: hidden;
1644
1935
  padding: 0.55rem 0.5rem;
1645
1936
  font-size: 0.68rem;
1646
1937
  line-height: 1;
1647
1938
  text-align: right;
1939
+ text-overflow: ellipsis;
1940
+ white-space: nowrap;
1648
1941
  }
1649
1942
 
1650
1943
  .telemetry-lap-table th,
@@ -2202,6 +2495,13 @@
2202
2495
  min-height: 48px;
2203
2496
  }
2204
2497
 
2498
+ .race-data-dismiss {
2499
+ top: 0.38rem;
2500
+ right: 0.42rem;
2501
+ width: 0.95rem;
2502
+ height: 0.95rem;
2503
+ }
2504
+
2205
2505
  .sim-telemetry {
2206
2506
  display: block;
2207
2507
  }