@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/index.d.ts CHANGED
@@ -1,9 +1,87 @@
1
- import type { PaddockActionSpec, PaddockObservationSpec } from './environment/index.js';
2
-
3
- export type { PaddockActionSpec, PaddockObservationSpec } from './environment/index.js';
1
+ import type {
2
+ PaddockActionSpec,
3
+ PaddockDriverControllerLoop,
4
+ PaddockDriverControllerLoopOptions,
5
+ PaddockObservationSpec,
6
+ PaddockParticipantInteraction as EnvPaddockParticipantInteraction,
7
+ PaddockParticipantInteractionsOptions as EnvPaddockParticipantInteractionsOptions,
8
+ PaddockParticipantInteractionOverride as EnvPaddockParticipantInteractionOverride,
9
+ PaddockParticipantInteractionProfile as EnvPaddockParticipantInteractionProfile,
10
+ PaddockReplayGhostOptions as EnvPaddockReplayGhostOptions,
11
+ PaddockReplayGhostSnapshot as EnvPaddockReplayGhostSnapshot,
12
+ PaddockReplayGhostTrajectorySample as EnvPaddockReplayGhostTrajectorySample,
13
+ } from './environment/index.js';
14
+
15
+ export type {
16
+ PaddockActionSpec,
17
+ PaddockControllerRuntime,
18
+ PaddockDriverController,
19
+ PaddockDriverControllerContext,
20
+ PaddockDriverControllerLoop,
21
+ PaddockDriverControllerLoopOptions,
22
+ PaddockObservationSpec,
23
+ } from './environment/index.js';
4
24
 
5
25
  export type TireCompound = 'S' | 'M' | 'H';
6
- export type CameraMode = 'overview' | 'leader' | 'selected' | 'show-all';
26
+ export type PaddockPhysicsMode = 'arcade' | 'simulator';
27
+ export type PaddockWarmupPolicy = 'config-change' | 'always' | 'never';
28
+ export type PaddockProceduralTrackProfile = 'race' | 'training-short' | 'training-medium' | 'training-technical';
29
+
30
+ export interface PaddockWarmupOptions {
31
+ enabled?: boolean;
32
+ policy?: PaddockWarmupPolicy;
33
+ steps?: number;
34
+ }
35
+
36
+ export interface PaddockProceduralTrackOptions {
37
+ profile?: PaddockProceduralTrackProfile;
38
+ minLengthMeters?: number;
39
+ maxLengthMeters?: number;
40
+ startStraightMeters?: number;
41
+ includePitLane?: boolean;
42
+ length?: {
43
+ minMeters?: number;
44
+ maxMeters?: number;
45
+ };
46
+ startStraight?: {
47
+ gridMeters?: number;
48
+ exitMeters?: number;
49
+ blendMeters?: number;
50
+ lockExtraMeters?: number;
51
+ };
52
+ pitLane?: {
53
+ enabled?: boolean;
54
+ };
55
+ shape?: {
56
+ scale?: number;
57
+ cornerDensity?: number;
58
+ variation?: number;
59
+ };
60
+ validation?: {
61
+ minClearanceMultiplier?: number;
62
+ minShapeVariation?: number;
63
+ minNonAdjacentArcMeters?: number;
64
+ maxLocalTurnRadians?: number;
65
+ maxSampleHeadingDeltaRadians?: number;
66
+ };
67
+ attempts?: {
68
+ primary?: number;
69
+ fallback?: number;
70
+ };
71
+ }
72
+
73
+ export type PaddockStabilityState = 'stable' | 'understeer' | 'oversteer' | 'spin-risk' | 'destroyed';
74
+ export type PaddockPitIntent = 0 | 1 | 2;
75
+ export type PaddockPitIntentRequest = PaddockPitIntent | {
76
+ intent?: PaddockPitIntent;
77
+ pitIntent?: PaddockPitIntent;
78
+ targetCompound?: TireCompound | string;
79
+ compound?: TireCompound | string;
80
+ pitCompound?: TireCompound | string;
81
+ pitTargetCompound?: TireCompound | string;
82
+ targetTire?: TireCompound | string;
83
+ };
84
+ export type CameraMode = 'overview' | 'leader' | 'selected' | 'show-all' | 'pit';
7
85
  export type RaceBannerMode = 'project' | 'radio' | 'hidden';
8
86
  export type RaceBannerEnabledMode = 'project' | 'radio';
9
87
  export type RaceDataBannerSize = 'auto' | 'custom';
@@ -13,6 +91,13 @@ export type CameraControlsMode = 'embedded' | 'external' | false;
13
91
  export type PaddockPresetName = 'dashboard' | 'timing-overlay' | 'compact-race' | 'full-dashboard';
14
92
  export type TelemetryModuleName = 'core' | 'sectors' | 'lapTimes' | 'sectorTimes';
15
93
  export type SectorPerformanceStatus = 'overall-best' | 'personal-best' | 'slower';
94
+ export type PaddockParticipantInteractionProfile = EnvPaddockParticipantInteractionProfile;
95
+ export type PaddockParticipantInteraction = EnvPaddockParticipantInteraction;
96
+ export type PaddockParticipantInteractionOverride = EnvPaddockParticipantInteractionOverride;
97
+ export type PaddockParticipantInteractionsOptions = EnvPaddockParticipantInteractionsOptions;
98
+ export type PaddockReplayGhostTrajectorySample = EnvPaddockReplayGhostTrajectorySample;
99
+ export type PaddockReplayGhostOptions = EnvPaddockReplayGhostOptions;
100
+ export type PaddockReplayGhostSnapshot = EnvPaddockReplayGhostSnapshot;
16
101
 
17
102
  export interface CustomField {
18
103
  label: string;
@@ -26,6 +111,14 @@ export interface TeamData {
26
111
  name?: string;
27
112
  color?: string;
28
113
  icon?: string;
114
+ pitCrew?: PaddockPitCrewStats;
115
+ pitCrewStats?: PaddockPitCrewStats;
116
+ }
117
+
118
+ export interface PaddockPitCrewStats {
119
+ speed?: number;
120
+ consistency?: number;
121
+ reliability?: number;
29
122
  }
30
123
 
31
124
  export interface SimulatorDriver {
@@ -184,9 +277,16 @@ export interface F1SimulatorUiOptions {
184
277
  };
185
278
  raceDataBannerSize?: RaceDataBannerSize;
186
279
  raceDataTelemetryDetail?: boolean;
280
+ penaltyBanners?: boolean;
281
+ timingPenaltyBadges?: boolean;
282
+ simulationSpeedControl?: boolean;
187
283
  timingTowerVerticalFit?: TimingTowerVerticalFit;
188
284
  }
189
285
 
286
+ export interface F1SimulatorDebugOptions {
287
+ physicsModeIndicator?: boolean;
288
+ }
289
+
190
290
  export interface TrackTextureAssets {
191
291
  asphalt?: string;
192
292
  }
@@ -206,9 +306,113 @@ export interface TrackSnapshot {
206
306
  width?: number;
207
307
  length?: number;
208
308
  sectors?: TrackSectorSnapshot[];
309
+ pitLane?: PitLaneSnapshot;
209
310
  [key: string]: unknown;
210
311
  }
211
312
 
313
+ export interface TrackPointSnapshot {
314
+ x: number;
315
+ y: number;
316
+ heading?: number;
317
+ distance?: number;
318
+ }
319
+
320
+ export interface PitLaneSnapshot {
321
+ enabled: boolean;
322
+ side: -1 | 1;
323
+ width: number;
324
+ offset?: number;
325
+ boxCount: number;
326
+ teamCount: number;
327
+ boxesPerTeam: number;
328
+ entry: {
329
+ trackDistance: number;
330
+ distanceFromStart: number;
331
+ trackPoint: TrackPointSnapshot;
332
+ edgePoint: TrackPointSnapshot;
333
+ trackConnectPoint: TrackPointSnapshot;
334
+ lanePoint: TrackPointSnapshot;
335
+ roadCenterline: TrackPointSnapshot[];
336
+ connector: TrackPointSnapshot[];
337
+ };
338
+ exit: {
339
+ trackDistance: number;
340
+ distanceFromStart: number;
341
+ trackPoint: TrackPointSnapshot;
342
+ edgePoint: TrackPointSnapshot;
343
+ trackConnectPoint: TrackPointSnapshot;
344
+ lanePoint: TrackPointSnapshot;
345
+ roadCenterline: TrackPointSnapshot[];
346
+ connector: TrackPointSnapshot[];
347
+ };
348
+ mainLane: {
349
+ start: TrackPointSnapshot;
350
+ end: TrackPointSnapshot;
351
+ points: TrackPointSnapshot[];
352
+ length: number;
353
+ heading: number;
354
+ };
355
+ fastLane?: {
356
+ offset: number;
357
+ width: number;
358
+ };
359
+ workingLane?: {
360
+ start: TrackPointSnapshot;
361
+ end: TrackPointSnapshot;
362
+ points: TrackPointSnapshot[];
363
+ offset: number;
364
+ width: number;
365
+ };
366
+ serviceNormal: { x: number; y: number };
367
+ teams?: PitTeamSnapshot[];
368
+ boxes: PitBoxSnapshot[];
369
+ serviceAreas?: PitServiceAreaSnapshot[];
370
+ }
371
+
372
+ export interface PitTeamSnapshot {
373
+ id: string;
374
+ name: string;
375
+ color: string;
376
+ index: number;
377
+ boxIds: string[];
378
+ serviceAreaId?: string | null;
379
+ }
380
+
381
+ export interface PitBoxSnapshot {
382
+ id: string;
383
+ index: number;
384
+ teamIndex: number;
385
+ teamBoxIndex: number;
386
+ teamId?: string;
387
+ teamName?: string;
388
+ teamColor?: string;
389
+ distanceAlongLane: number;
390
+ laneTarget: TrackPointSnapshot;
391
+ center: TrackPointSnapshot;
392
+ length: number;
393
+ depth: number;
394
+ corners: TrackPointSnapshot[];
395
+ }
396
+
397
+ export interface PitServiceAreaSnapshot {
398
+ id: string;
399
+ index: number;
400
+ teamIndex: number;
401
+ teamId?: string;
402
+ teamName?: string;
403
+ teamColor?: string;
404
+ distanceAlongLane: number;
405
+ queueDistanceAlongLane: number;
406
+ laneTarget: TrackPointSnapshot;
407
+ center: TrackPointSnapshot;
408
+ queuePoint: TrackPointSnapshot;
409
+ length: number;
410
+ depth: number;
411
+ corners: TrackPointSnapshot[];
412
+ queueCorners: TrackPointSnapshot[];
413
+ garageBoxIds: string[];
414
+ }
415
+
212
416
  export interface TrackSectorSnapshot {
213
417
  index: number;
214
418
  id: string;
@@ -227,6 +431,8 @@ export interface LapTelemetrySnapshot {
227
431
  currentSectorElapsed: number | null;
228
432
  currentSectorProgress: number | null;
229
433
  currentSectors: Array<number | null>;
434
+ sectorProgress: Array<number | null>;
435
+ liveSectors: Array<number | null>;
230
436
  sectorPerformance: {
231
437
  current: Array<SectorPerformanceStatus | null>;
232
438
  last: Array<SectorPerformanceStatus | null>;
@@ -239,28 +445,250 @@ export interface LapTelemetrySnapshot {
239
445
  completedLaps: number;
240
446
  }
241
447
 
448
+ export interface PitStopSnapshot {
449
+ status: 'pending' | 'entering' | 'queued' | 'servicing' | 'exiting' | 'completed';
450
+ intent: PaddockPitIntent;
451
+ phase: 'entry' | 'queue' | 'queue-release' | 'penalty' | 'service' | 'exit' | null;
452
+ boxIndex: number;
453
+ boxId: string;
454
+ garageBoxIndex?: number | null;
455
+ garageBoxId?: string | null;
456
+ teamId?: string | null;
457
+ teamColor?: string | null;
458
+ stopsCompleted: number;
459
+ queueingForService?: boolean;
460
+ plannedRaceDistance: number | null;
461
+ entryRaceDistance: number | null;
462
+ serviceRemainingSeconds: number | null;
463
+ penaltyServiceRemainingSeconds: number | null;
464
+ penaltyServiceTotalSeconds: number | null;
465
+ servingPenaltyIds: string[];
466
+ targetTire?: TireCompound | string | null;
467
+ serviceProfile?: {
468
+ baseSeconds: number;
469
+ seconds: number;
470
+ perfect: boolean;
471
+ variabilityEnabled: boolean;
472
+ teamId?: string | null;
473
+ pitCrew: Required<PaddockPitCrewStats>;
474
+ speedDeltaSeconds: number;
475
+ consistencyDeltaSeconds: number;
476
+ issueDelaySeconds: number;
477
+ issue?: string | null;
478
+ } | null;
479
+ }
480
+
242
481
  export interface RaceEvent {
243
482
  type: string;
244
483
  at?: number;
484
+ firstShapeId?: string;
485
+ secondShapeId?: string;
486
+ contactType?: 'body-body' | 'body-wheel' | 'wheel-body' | 'wheel-wheel' | string;
487
+ depth?: number;
488
+ timeOfImpact?: number;
489
+ [key: string]: unknown;
490
+ }
491
+
492
+ export type PaddockRulesetName = 'paddock' | 'custom' | 'grandPrix2025' | 'fia2025';
493
+
494
+ export interface PaddockPitStopRules {
495
+ enabled?: boolean;
496
+ pitLaneSpeedLimitKph?: number;
497
+ defaultStopSeconds?: number;
498
+ variability?: {
499
+ enabled?: boolean;
500
+ perfect?: boolean;
501
+ speedImpactSeconds?: number;
502
+ consistencyJitterSeconds?: number;
503
+ issueChance?: number;
504
+ issueMaxDelaySeconds?: number;
505
+ };
506
+ maxConcurrentPitLaneCars?: number;
507
+ minimumPitLaneGapMeters?: number;
508
+ doubleStacking?: boolean;
509
+ tirePitRequestThresholdPercent?: number;
510
+ tirePitCommitThresholdPercent?: number;
511
+ }
512
+
513
+ export interface PaddockTireStrategyRules {
514
+ enabled?: boolean;
515
+ compounds?: TireCompound[];
516
+ mandatoryDistinctDryCompounds?: number | null;
517
+ }
518
+
519
+ export interface PaddockTireDegradationRules {
520
+ enabled?: boolean;
521
+ }
522
+
523
+ export interface PaddockStalledDnfRules {
524
+ enabled?: boolean;
525
+ maxStoppedSeconds?: number;
526
+ speedThresholdKph?: number;
527
+ }
528
+
529
+ export interface PaddockPenaltySubsectionRules {
530
+ strictness?: number;
531
+ timePenaltySeconds?: number;
532
+ consequences?: PaddockPenaltyConsequence[];
533
+ }
534
+
535
+ export type PaddockPenaltyConsequence =
536
+ | { type: 'warning' }
537
+ | { type: 'time'; seconds: number }
538
+ | { type: 'driveThrough'; conversionSeconds?: number }
539
+ | { type: 'stopGo'; seconds?: number; conversionSeconds?: number }
540
+ | { type: 'positionDrop'; positions: number }
541
+ | { type: 'gridDrop'; positions: number }
542
+ | { type: 'disqualification' };
543
+
544
+ export type PaddockPenaltyStatus = 'issued' | 'served' | 'applied' | 'cancelled';
545
+
546
+ export interface PaddockTrackLimitPenaltyRules extends PaddockPenaltySubsectionRules {
547
+ warningsBeforePenalty?: number;
548
+ relaxedMarginMeters?: number;
549
+ }
550
+
551
+ export interface PaddockCollisionPenaltyRules extends PaddockPenaltySubsectionRules {
552
+ minimumSeverity?: number;
553
+ relaxedSeverityMargin?: number;
554
+ minimumImpactSpeedKph?: number;
555
+ relaxedImpactSpeedKph?: number;
556
+ }
557
+
558
+ export interface PaddockPitLaneSpeedingPenaltyRules extends PaddockPenaltySubsectionRules {
559
+ speedLimitKph?: number;
560
+ marginKph?: number;
561
+ relaxedMarginKph?: number;
562
+ }
563
+
564
+ export interface PaddockPenaltyRules {
565
+ enabled?: boolean;
566
+ stewardStrictness?: number;
567
+ trackLimits?: PaddockTrackLimitPenaltyRules;
568
+ collision?: PaddockCollisionPenaltyRules;
569
+ tireRequirement?: PaddockPenaltySubsectionRules;
570
+ pitLaneSpeeding?: PaddockPitLaneSpeedingPenaltyRules;
571
+ }
572
+
573
+ export interface PaddockRaceModules {
574
+ pitStops?: PaddockPitStopRules;
575
+ tireStrategy?: PaddockTireStrategyRules;
576
+ tireDegradation?: PaddockTireDegradationRules;
577
+ stalledDnf?: PaddockStalledDnfRules;
578
+ penalties?: PaddockPenaltyRules;
579
+ weather?: { enabled?: boolean };
580
+ reliability?: { enabled?: boolean };
581
+ fuelLoad?: { enabled?: boolean };
582
+ }
583
+
584
+ export interface PaddockRaceRules {
585
+ ruleset?: PaddockRulesetName;
586
+ profile?: PaddockRulesetName;
587
+ modules?: PaddockRaceModules;
588
+ drsDetectionSeconds?: number;
589
+ safetyCarSpeed?: number;
590
+ safetyCarLeadDistance?: number;
591
+ safetyCarGap?: number;
592
+ collisionRestitution?: number;
593
+ standingStart?: boolean;
594
+ startLightCount?: number;
595
+ startLightInterval?: number;
596
+ startLightsOutHold?: number;
597
+ }
598
+
599
+ export interface PaddockPenaltyEntry {
600
+ id: string;
601
+ type: string;
602
+ at: number;
603
+ lap: number;
604
+ driverId: string;
605
+ strictness: number;
606
+ status: PaddockPenaltyStatus;
607
+ penaltySeconds: number;
608
+ pendingPenaltySeconds?: number;
609
+ consequences: PaddockPenaltyConsequence[];
610
+ serviceType?: 'driveThrough' | 'stopGo' | null;
611
+ serviceRequired?: boolean;
612
+ serviceServedAt?: number | null;
613
+ appliedAt?: number;
614
+ cancelledAt?: number;
615
+ unserved?: boolean;
616
+ positionDrop?: number;
617
+ gridDrop?: number;
618
+ disqualified?: boolean;
619
+ reason?: string;
620
+ otherCarId?: string;
621
+ aheadDriverId?: string;
622
+ atFaultDriverId?: string;
623
+ sharedFault?: boolean;
624
+ impactSpeedKph?: number;
625
+ impactSpeedThresholdKph?: number;
245
626
  [key: string]: unknown;
246
627
  }
247
628
 
629
+ export interface WheelSurfaceSnapshot {
630
+ id: string;
631
+ x: number;
632
+ y: number;
633
+ signedOffset: number;
634
+ crossTrackError: number;
635
+ surface: string;
636
+ onTrack: boolean;
637
+ inPitLane: boolean;
638
+ fullyOutsideWhiteLine: boolean;
639
+ }
640
+
248
641
  export interface CarSnapshot {
249
642
  id: string;
250
- rank: number;
643
+ rank: number | null;
251
644
  code: string;
252
645
  timingCode: string;
253
646
  name: string;
254
647
  color: string;
255
648
  tire: TireCompound;
649
+ interaction?: PaddockParticipantInteraction;
256
650
  lap: number;
257
651
  speedKph: number;
652
+ finishRank?: number | null;
653
+ status?: 'racing' | 'waved-flag' | 'destroyed' | string;
654
+ raceStatus?: 'racing' | 'waved-flag' | 'destroyed' | string;
655
+ wavedFlag?: boolean;
258
656
  finished?: boolean;
657
+ destroyed?: boolean;
658
+ destroyReason?: string | null;
659
+ destroyedAt?: number | null;
660
+ dnf?: boolean;
661
+ dnfReason?: string | null;
662
+ dnfAt?: number | null;
663
+ dnfOrder?: number | null;
664
+ outOfRace?: boolean;
259
665
  finishTime?: number | null;
666
+ penaltySeconds?: number;
667
+ adjustedFinishTime?: number | null;
260
668
  classifiedRank?: number | null;
261
669
  intervalAheadSeconds?: number | null;
262
670
  leaderGapSeconds?: number | null;
671
+ gapAheadLaps?: number;
672
+ intervalAheadLaps?: number;
673
+ leaderGapLaps?: number;
263
674
  lapTelemetry?: LapTelemetrySnapshot;
675
+ surface?: string;
676
+ lateralG?: number;
677
+ longitudinalG?: number;
678
+ gripUsage?: number;
679
+ slipAngleRadians?: number;
680
+ tractionLimited?: boolean;
681
+ stabilityState?: PaddockStabilityState;
682
+ signedOffset?: number;
683
+ crossTrackError?: number;
684
+ inPitLane?: boolean;
685
+ wheels?: WheelSurfaceSnapshot[];
686
+ pitLanePart?: 'entry' | 'fast-lane' | 'working-lane' | 'exit' | 'service-box' | 'garage-box' | null;
687
+ pitBoxId?: string | null;
688
+ pitLaneCrossTrackError?: number | null;
689
+ usedTireCompounds?: Array<TireCompound | string>;
690
+ pitIntent?: PaddockPitIntent;
691
+ pitStop?: PitStopSnapshot | null;
264
692
  [key: string]: unknown;
265
693
  }
266
694
 
@@ -271,11 +699,22 @@ export interface RaceClassificationEntry {
271
699
  lap: number;
272
700
  finished: boolean;
273
701
  finishTime?: number | null;
702
+ dnf?: boolean;
703
+ dnfReason?: string | null;
704
+ dnfAt?: number | null;
705
+ dnfOrder?: number | null;
706
+ penaltySeconds?: number;
707
+ adjustedFinishTime?: number | null;
708
+ gapLaps?: number;
709
+ intervalLaps?: number;
710
+ positionDrop?: number;
711
+ disqualified?: boolean;
274
712
  [key: string]: unknown;
275
713
  }
276
714
 
277
715
  export interface RaceSnapshot {
278
716
  time: number;
717
+ physicsMode: PaddockPhysicsMode;
279
718
  world: {
280
719
  width: number;
281
720
  height: number;
@@ -285,6 +724,15 @@ export interface RaceSnapshot {
285
724
  totalLaps: number;
286
725
  raceControl: {
287
726
  mode: string;
727
+ redFlag: boolean;
728
+ pitLaneOpen: boolean;
729
+ pitLaneStatus?: {
730
+ enabled: boolean;
731
+ open: boolean;
732
+ reason: string;
733
+ color: string;
734
+ light: string;
735
+ };
288
736
  finished: boolean;
289
737
  finishedAt: number | null;
290
738
  winner: CarSnapshot | null;
@@ -294,13 +742,22 @@ export interface RaceSnapshot {
294
742
  [key: string]: unknown;
295
743
  };
296
744
  };
745
+ pitLaneStatus?: {
746
+ enabled: boolean;
747
+ open: boolean;
748
+ reason: string;
749
+ color: string;
750
+ light: string;
751
+ };
297
752
  safetyCar: {
298
753
  deployed: boolean;
299
754
  [key: string]: unknown;
300
755
  };
301
- rules: Record<string, unknown>;
756
+ rules: PaddockRaceRules;
302
757
  events: RaceEvent[];
758
+ penalties: PaddockPenaltyEntry[];
303
759
  cars: CarSnapshot[];
760
+ replayGhosts: PaddockReplayGhostSnapshot[];
304
761
  }
305
762
 
306
763
  export interface LifecycleErrorContext {
@@ -313,7 +770,7 @@ export interface F1SimulatorCallbacks {
313
770
  onLoadingChange?: (state: { loading: boolean; phase: string }) => void;
314
771
  onReady?: (payload: { snapshot: RaceSnapshot }) => void;
315
772
  onError?: (error: unknown, context: LifecycleErrorContext) => void;
316
- onDriverSelect?: (driver: CarSnapshot, snapshot: RaceSnapshot) => void;
773
+ onDriverSelect?: (driver: NormalizedSimulatorDriver, snapshot: RaceSnapshot) => void;
317
774
  onRaceEvent?: (event: RaceEvent, snapshot: RaceSnapshot) => void;
318
775
  onLapChange?: (payload: {
319
776
  previousLeaderLap: number | null;
@@ -334,6 +791,8 @@ export interface F1SimulatorExpertOptions {
334
791
  frameSkip?: number;
335
792
  visualizeSensors?: boolean | {
336
793
  rays?: boolean;
794
+ drivers?: 'selected' | 'all' | string[];
795
+ selectedDriverId?: string;
337
796
  };
338
797
  }
339
798
 
@@ -341,15 +800,56 @@ export interface F1SimulatorExpertAction {
341
800
  steering: number;
342
801
  throttle: number;
343
802
  brake: number;
803
+ pitIntent?: PaddockPitIntent;
804
+ pitCompound?: TireCompound | string;
805
+ pitTargetCompound?: TireCompound | string;
806
+ }
807
+
808
+ export interface PaddockExternalRenderFrame {
809
+ snapshot: RaceSnapshot;
810
+ observation: Record<string, unknown>;
811
+ meta?: Record<string, unknown> | null;
812
+ }
813
+
814
+ export interface PaddockExternalRendererSource {
815
+ subscribe(onFrame: (frame: PaddockExternalRenderFrame) => void): () => void;
816
+ }
817
+
818
+ export interface PaddockExternalRendererState {
819
+ attached: boolean;
820
+ lastMeta: Record<string, unknown> | null;
821
+ lastFrameAt: number | null;
822
+ lastError: string | null;
823
+ }
824
+
825
+ export interface PaddockScenarioPlacement {
826
+ distanceMeters?: number;
827
+ startDistanceMeters?: number;
828
+ offsetMeters?: number;
829
+ speedKph?: number;
830
+ headingErrorRadians?: number;
831
+ }
832
+
833
+ export interface PaddockEnvironmentResultOptions {
834
+ stateOutput?: 'full' | 'minimal' | 'none';
835
+ observationScope?: 'all' | 'reset';
836
+ resetDriversObservationScope?: 'all' | 'reset';
344
837
  }
345
838
 
346
839
  export interface F1SimulatorExpertApi {
347
840
  reset(options?: unknown): unknown;
348
841
  step(actions: Record<string, F1SimulatorExpertAction>): unknown;
842
+ resetDrivers?(
843
+ placements: Record<string, PaddockScenarioPlacement>,
844
+ resultOptions?: PaddockEnvironmentResultOptions
845
+ ): unknown;
349
846
  getObservation(): unknown;
350
847
  getState(): unknown;
351
848
  getActionSpec(): PaddockActionSpec;
352
849
  getObservationSpec(): PaddockObservationSpec;
850
+ attachExternalRenderer(source: PaddockExternalRendererSource): void;
851
+ detachExternalRenderer(): void;
852
+ getExternalRendererState(): PaddockExternalRendererState;
353
853
  destroy(): void;
354
854
  }
355
855
 
@@ -359,7 +859,14 @@ export interface F1SimulatorOptions extends F1SimulatorCallbacks {
359
859
  entries?: ChampionshipEntryBlueprint[];
360
860
  seed?: number;
361
861
  trackSeed?: number;
862
+ trackGeneration?: PaddockProceduralTrackOptions;
863
+ trackQueryIndex?: boolean;
864
+ warmup?: PaddockWarmupOptions | boolean;
362
865
  totalLaps?: number;
866
+ physicsMode?: PaddockPhysicsMode;
867
+ rules?: PaddockRaceRules;
868
+ participantInteractions?: PaddockParticipantInteractionsOptions;
869
+ replayGhosts?: PaddockReplayGhostOptions[];
363
870
  initialCameraMode?: CameraMode;
364
871
  theme?: F1SimulatorTheme;
365
872
  title?: string;
@@ -368,6 +875,7 @@ export interface F1SimulatorOptions extends F1SimulatorCallbacks {
368
875
  backLinkLabel?: string;
369
876
  showBackLink?: boolean;
370
877
  ui?: F1SimulatorUiOptions;
878
+ debug?: F1SimulatorDebugOptions;
371
879
  assets?: F1SimulatorAssets;
372
880
  expert?: F1SimulatorExpertOptions;
373
881
  }
@@ -397,9 +905,17 @@ export interface F1MountedSimulator {
397
905
  restart(nextOptions?: F1SimulatorRestartOptions): void;
398
906
  selectDriver(driverId: string): void;
399
907
  setSafetyCarDeployed(deployed: boolean): void;
908
+ setRedFlagDeployed(deployed: boolean): void;
909
+ setPitLaneOpen(open: boolean): void;
400
910
  callSafetyCar(): void;
401
911
  clearSafetyCar(): void;
402
912
  toggleSafetyCar(): void;
913
+ setPitIntent(driverId: string, intent: PaddockPitIntentRequest, targetCompound?: TireCompound | string): boolean;
914
+ getPitIntent(driverId: string): PaddockPitIntent;
915
+ getPitTargetCompound(driverId: string): TireCompound | string | null;
916
+ getSimulationSpeed(): number;
917
+ servePenalty(penaltyId: string): PaddockPenaltyEntry | null;
918
+ cancelPenalty(penaltyId: string): PaddockPenaltyEntry | null;
403
919
  getSnapshot(): RaceSnapshot | null;
404
920
  }
405
921
 
@@ -426,9 +942,17 @@ export interface PaddockSimulatorController {
426
942
  restart(nextOptions?: F1SimulatorRestartOptions): void;
427
943
  selectDriver(driverId: string): void;
428
944
  setSafetyCarDeployed(deployed: boolean): void;
945
+ setRedFlagDeployed(deployed: boolean): void;
946
+ setPitLaneOpen(open: boolean): void;
429
947
  callSafetyCar(): void;
430
948
  clearSafetyCar(): void;
431
949
  toggleSafetyCar(): void;
950
+ setPitIntent(driverId: string, intent: PaddockPitIntentRequest, targetCompound?: TireCompound | string): boolean;
951
+ getPitIntent(driverId: string): PaddockPitIntent;
952
+ getPitTargetCompound(driverId: string): TireCompound | string | null;
953
+ getSimulationSpeed(): number;
954
+ servePenalty(penaltyId: string): PaddockPenaltyEntry | null;
955
+ cancelPenalty(penaltyId: string): PaddockPenaltyEntry | null;
432
956
  getSnapshot(): RaceSnapshot | null;
433
957
  }
434
958
 
@@ -463,6 +987,8 @@ export function simSpeedToMetersPerSecond(simSpeed: number): number;
463
987
 
464
988
  export function createPaddockSimulator(options: F1SimulatorOptions): PaddockSimulatorController;
465
989
  export function mountF1Simulator(root: Element, options: F1SimulatorOptions): Promise<F1MountedSimulator>;
990
+ export function createProceduralTrack(seed?: number | string, options?: PaddockProceduralTrackOptions): unknown;
991
+ export function createPaddockDriverControllerLoop(options: PaddockDriverControllerLoopOptions): PaddockDriverControllerLoop;
466
992
 
467
993
  export function mountRaceControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
468
994
  export function mountCameraControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;