@inventure71/paddockjs 1.0.0 → 2.0.1

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 (203) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/INSTALL_AND_UPDATE.md +4 -3
  3. package/README.md +219 -12
  4. package/docs/architecture.md +126 -45
  5. package/docs/concepts.md +9 -5
  6. package/docs/custom_model_controller.md +329 -0
  7. package/docs/data_contract.md +317 -22
  8. package/docs/data_model.md +1 -1
  9. package/docs/index.md +10 -0
  10. package/docs/learnings.md +22 -0
  11. package/docs/rules.md +71 -14
  12. package/docs/sense_contract.md +59 -0
  13. package/docs/system_specs.md +75 -13
  14. package/docs/training.md +280 -32
  15. package/examples/python/README.md +62 -0
  16. package/examples/python/base_policy_server.py +191 -0
  17. package/examples/python/requirements.txt +2 -0
  18. package/package.json +12 -4
  19. package/src/api/PaddockSimulatorController.js +6 -33
  20. package/src/app/BrowserExpertAdapter.js +76 -9
  21. package/src/app/BrowserExpertExternalRenderer.js +303 -0
  22. package/src/app/F1SimulatorApp.js +291 -1630
  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 +4 -0
  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 +20 -0
  48. package/src/config/restartOptions.js +34 -0
  49. package/src/environment/actions.js +13 -5
  50. package/src/environment/controllerLoop.js +261 -0
  51. package/src/environment/episode.js +98 -2
  52. package/src/environment/evaluation.js +54 -32
  53. package/src/environment/index.d.ts +376 -10
  54. package/src/environment/index.js +1 -0
  55. package/src/environment/metrics.js +159 -0
  56. package/src/environment/observationOptions.js +22 -1
  57. package/src/environment/observationVector.js +200 -0
  58. package/src/environment/observations.js +199 -141
  59. package/src/environment/options.js +37 -5
  60. package/src/environment/recorder.js +13 -6
  61. package/src/environment/rewards.js +13 -2
  62. package/src/environment/runtime.js +272 -23
  63. package/src/environment/scenarios.js +57 -9
  64. package/src/environment/sensors/bodySenses.js +23 -0
  65. package/src/environment/sensors/boundarySenses.js +17 -0
  66. package/src/environment/sensors/carRays.js +75 -0
  67. package/src/environment/sensors/contactSenses.js +32 -0
  68. package/src/environment/sensors/index.js +157 -0
  69. package/src/environment/sensors/indexedRayBands.js +103 -0
  70. package/src/environment/sensors/nearbyCars.js +52 -0
  71. package/src/environment/sensors/opponentRadar.js +75 -0
  72. package/src/environment/sensors/rayConfig.js +110 -0
  73. package/src/environment/sensors/rayDefaults.js +6 -0
  74. package/src/environment/sensors/rayGeometry.js +60 -0
  75. package/src/environment/sensors/rayGuards.js +19 -0
  76. package/src/environment/sensors/sensorTargets.js +66 -0
  77. package/src/environment/sensors/surfaceRays.js +360 -0
  78. package/src/environment/sensors/trackRays.js +424 -0
  79. package/src/environment/sensors.js +1 -367
  80. package/src/environment/specs.js +159 -26
  81. package/src/environment/workerProtocol.js +13 -1
  82. package/src/index.d.ts +171 -6
  83. package/src/index.js +6 -32
  84. package/src/rendering/proceduralTrackAsset.js +20 -823
  85. package/src/rendering/renderSnapshot.js +38 -12
  86. package/src/rendering/track/finishLineRenderer.js +34 -0
  87. package/src/rendering/track/gridRenderer.js +47 -0
  88. package/src/rendering/track/offsetStrokeSafety.js +136 -0
  89. package/src/rendering/track/pitLaneRenderer.js +248 -0
  90. package/src/rendering/track/trackMaterialRenderer.js +326 -0
  91. package/src/rendering/track/trackRenderConstants.js +38 -0
  92. package/src/rendering/track/trackRenderGeometry.js +94 -0
  93. package/src/simulation/collisionGeometry.js +1 -1
  94. package/src/simulation/driver/driverControlConstants.js +28 -0
  95. package/src/simulation/driver/driverController.js +47 -0
  96. package/src/simulation/driver/driverInput.js +28 -0
  97. package/src/simulation/driver/driverMath.js +6 -0
  98. package/src/simulation/driver/driverPersonality.js +25 -0
  99. package/src/simulation/driver/edgeRecovery.js +48 -0
  100. package/src/simulation/driver/racingControls.js +399 -0
  101. package/src/simulation/driver/racingLinePlan.js +166 -0
  102. package/src/simulation/driver/recoveryDynamics.js +38 -0
  103. package/src/simulation/driver/rejoinControls.js +213 -0
  104. package/src/simulation/driver/safetyCarControls.js +35 -0
  105. package/src/simulation/driver/trafficScan.js +51 -0
  106. package/src/simulation/driverController.js +4 -619
  107. package/src/simulation/participants/participantInteractions.js +120 -0
  108. package/src/simulation/pit/pitFlow.js +239 -0
  109. package/src/simulation/pit/pitIntent.js +92 -0
  110. package/src/simulation/pit/pitKinematics.js +24 -0
  111. package/src/simulation/pit/pitOccupancy.js +47 -0
  112. package/src/simulation/pit/pitPenaltyService.js +71 -0
  113. package/src/simulation/pit/pitQueue.js +60 -0
  114. package/src/simulation/pit/pitRouteMovement.js +167 -0
  115. package/src/simulation/pit/pitRouting.js +319 -0
  116. package/src/simulation/pit/pitService.js +43 -0
  117. package/src/simulation/pit/pitServiceConstants.js +21 -0
  118. package/src/simulation/pit/pitServiceProfile.js +45 -0
  119. package/src/simulation/pit/pitSnapshots.js +61 -0
  120. package/src/simulation/pit/pitState.js +113 -0
  121. package/src/simulation/pit/pitTireService.js +94 -0
  122. package/src/simulation/race/classification.js +104 -0
  123. package/src/simulation/race/gridPenalties.js +37 -0
  124. package/src/simulation/race/raceControlState.js +38 -0
  125. package/src/simulation/race/raceDistance.js +32 -0
  126. package/src/simulation/race/raceFinish.js +65 -0
  127. package/src/simulation/race/raceLifecycle.js +67 -0
  128. package/src/simulation/race/raceOrder.js +113 -0
  129. package/src/simulation/race/raceProgress.js +129 -0
  130. package/src/simulation/race/raceSetup.js +93 -0
  131. package/src/simulation/race/raceStep.js +80 -0
  132. package/src/simulation/race/redFlag.js +15 -0
  133. package/src/simulation/race/retirements.js +44 -0
  134. package/src/simulation/race/safetyCar.js +92 -0
  135. package/src/simulation/race/stalledDnf.js +77 -0
  136. package/src/simulation/raceSimulation.js +231 -2817
  137. package/src/simulation/replay/replayGhosts.js +128 -0
  138. package/src/simulation/rules/moduleConfig.js +72 -0
  139. package/src/simulation/rules/penaltyConfig.js +99 -0
  140. package/src/simulation/rules/penaltyEvents.js +18 -0
  141. package/src/simulation/rules/penaltyStats.js +26 -0
  142. package/src/simulation/rules/ruleConfigMerge.js +41 -0
  143. package/src/simulation/rules/ruleDefaults.js +85 -0
  144. package/src/simulation/rules/rulesReview.js +144 -0
  145. package/src/simulation/rules/rulesetPresets.js +47 -0
  146. package/src/simulation/rules/trackLimitsSteward.js +1 -1
  147. package/src/simulation/rulesConfig.js +5 -323
  148. package/src/simulation/snapshots/raceSnapshots.js +193 -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/trackQueryGrid.js +94 -0
  171. package/src/simulation/track/trackQueryIndex.js +659 -0
  172. package/src/simulation/track/trackQueryPitIndex.js +140 -0
  173. package/src/simulation/track/trackQueryScratch.js +46 -0
  174. package/src/simulation/track/trackQueryStats.js +28 -0
  175. package/src/simulation/track/trackSectors.js +19 -0
  176. package/src/simulation/track/trackStatePolicy.js +24 -0
  177. package/src/simulation/track/trackValidation.js +98 -0
  178. package/src/simulation/trackModel.js +1 -1706
  179. package/src/simulation/vehicle/contactResolution.js +181 -0
  180. package/src/simulation/vehicle/mainTrackWheelSurface.js +82 -0
  181. package/src/simulation/vehicle/pitWheelSurface.js +69 -0
  182. package/src/simulation/vehicle/runoffResponse.js +87 -0
  183. package/src/simulation/vehicle/surfacePriority.js +28 -0
  184. package/src/simulation/vehicle/vehicleGeometry.js +247 -0
  185. package/src/simulation/vehicle/vehicleKinematics.js +37 -0
  186. package/src/simulation/vehicle/vehiclePhysics.js +364 -0
  187. package/src/simulation/vehicle/vehicleSnapshots.js +327 -0
  188. package/src/simulation/vehicle/vehicleState.js +220 -0
  189. package/src/simulation/vehicle/wheelSurface.js +152 -0
  190. package/src/simulation/vehicleGeometry.js +1 -247
  191. package/src/simulation/vehiclePhysics.js +1 -136
  192. package/src/simulation/warmup/runtimeWarmup.js +224 -0
  193. package/src/simulation/wheelSurface.js +1 -338
  194. package/src/styles.css +42 -0
  195. package/src/ui/cameraControlsTemplate.js +20 -0
  196. package/src/ui/carOverviewTemplate.js +33 -0
  197. package/src/ui/componentTemplates.js +14 -360
  198. package/src/ui/raceCanvasTemplate.js +69 -0
  199. package/src/ui/raceControlsTemplate.js +36 -0
  200. package/src/ui/shellTemplate.js +5 -4
  201. package/src/ui/telemetryDrawerTemplate.js +55 -0
  202. package/src/ui/telemetryTemplates.js +136 -0
  203. package/src/ui/timingTowerTemplate.js +34 -0
@@ -1,6 +1,113 @@
1
1
  export type TireCompound = 'S' | 'M' | 'H';
2
+ export type PaddockPhysicsMode = 'arcade' | 'simulator';
3
+ export type PaddockProceduralTrackProfile = 'race' | 'training-short' | 'training-medium' | 'training-technical';
4
+
5
+ export interface PaddockProceduralTrackOptions {
6
+ profile?: PaddockProceduralTrackProfile;
7
+ minLengthMeters?: number;
8
+ maxLengthMeters?: number;
9
+ startStraightMeters?: number;
10
+ includePitLane?: boolean;
11
+ length?: {
12
+ minMeters?: number;
13
+ maxMeters?: number;
14
+ };
15
+ startStraight?: {
16
+ gridMeters?: number;
17
+ exitMeters?: number;
18
+ blendMeters?: number;
19
+ lockExtraMeters?: number;
20
+ };
21
+ pitLane?: {
22
+ enabled?: boolean;
23
+ };
24
+ shape?: {
25
+ scale?: number;
26
+ cornerDensity?: number;
27
+ variation?: number;
28
+ };
29
+ validation?: {
30
+ minClearanceMultiplier?: number;
31
+ minShapeVariation?: number;
32
+ minNonAdjacentArcMeters?: number;
33
+ maxLocalTurnRadians?: number;
34
+ maxSampleHeadingDeltaRadians?: number;
35
+ };
36
+ attempts?: {
37
+ primary?: number;
38
+ fallback?: number;
39
+ };
40
+ }
41
+
42
+ export type PaddockStabilityState = 'stable' | 'understeer' | 'oversteer' | 'spin-risk' | 'destroyed';
2
43
  export type PaddockPitIntent = 0 | 1 | 2;
3
44
  export type PaddockScenarioPreset = 'cornering' | 'off-track-recovery' | 'overtaking-pack' | 'pit-entry';
45
+ export type PaddockParticipantInteractionProfile =
46
+ | 'normal'
47
+ | 'isolated-training'
48
+ | 'batch-training'
49
+ | 'phantom-race'
50
+ | 'time-trial-overlay';
51
+
52
+ export interface PaddockParticipantInteraction {
53
+ profile: PaddockParticipantInteractionProfile;
54
+ collidable: boolean;
55
+ detectableByRays: boolean;
56
+ detectableAsNearby: boolean;
57
+ blocksPitLane: boolean;
58
+ affectsRaceOrder: boolean;
59
+ }
60
+
61
+ export type PaddockParticipantInteractionOverride =
62
+ Partial<PaddockParticipantInteraction> & { profile?: PaddockParticipantInteractionProfile };
63
+
64
+ export interface PaddockParticipantInteractionsOptions {
65
+ defaultProfile?: PaddockParticipantInteractionProfile;
66
+ drivers?: Record<string, PaddockParticipantInteractionOverride>;
67
+ }
68
+
69
+ export interface PaddockReplayGhostTrajectorySample {
70
+ timeSeconds: number;
71
+ x: number;
72
+ y: number;
73
+ headingRadians: number;
74
+ speedKph?: number;
75
+ progressMeters?: number;
76
+ }
77
+
78
+ export interface PaddockReplayGhostOptions {
79
+ id: string;
80
+ label?: string;
81
+ color?: string;
82
+ opacity?: number;
83
+ visible?: boolean;
84
+ trajectory: PaddockReplayGhostTrajectorySample[];
85
+ sensors?: {
86
+ detectableByRays?: boolean;
87
+ detectableAsNearby?: boolean;
88
+ };
89
+ }
90
+
91
+ export interface PaddockReplayGhostSnapshot {
92
+ id: string;
93
+ label: string;
94
+ color: string;
95
+ opacity: number;
96
+ visible: boolean;
97
+ previousX: number;
98
+ previousY: number;
99
+ x: number;
100
+ y: number;
101
+ previousHeading: number;
102
+ heading: number;
103
+ speedKph: number;
104
+ progressMeters: number;
105
+ timeSeconds: number;
106
+ sensors: {
107
+ detectableByRays: boolean;
108
+ detectableAsNearby: boolean;
109
+ };
110
+ }
4
111
 
5
112
  export interface TeamData {
6
113
  id?: string;
@@ -92,6 +199,7 @@ export type PaddockPenaltyStatus = 'issued' | 'served' | 'applied' | 'cancelled'
92
199
 
93
200
  export interface RaceSnapshot {
94
201
  time: number;
202
+ physicsMode: PaddockPhysicsMode;
95
203
  totalLaps: number;
96
204
  raceControl: {
97
205
  mode: string;
@@ -100,6 +208,7 @@ export interface RaceSnapshot {
100
208
  };
101
209
  track: Record<string, unknown>;
102
210
  cars: Array<Record<string, unknown>>;
211
+ replayGhosts: PaddockReplayGhostSnapshot[];
103
212
  events: RaceEvent[];
104
213
  penalties: PaddockPenaltyEntry[];
105
214
  [key: string]: unknown;
@@ -143,6 +252,14 @@ export interface PaddockRaceRules {
143
252
  compounds?: TireCompound[];
144
253
  mandatoryDistinctDryCompounds?: number | null;
145
254
  };
255
+ tireDegradation?: {
256
+ enabled?: boolean;
257
+ };
258
+ stalledDnf?: {
259
+ enabled?: boolean;
260
+ maxStoppedSeconds?: number;
261
+ speedThresholdKph?: number;
262
+ };
146
263
  penalties?: {
147
264
  enabled?: boolean;
148
265
  stewardStrictness?: number;
@@ -192,22 +309,38 @@ export interface PaddockRaceRules {
192
309
  }
193
310
 
194
311
  export interface PaddockSensorRayResult {
312
+ id?: string;
195
313
  angleDegrees: number;
196
314
  angleRadians: number;
197
315
  lengthMeters: number;
316
+ roadEdge: {
317
+ hit: boolean;
318
+ distanceMeters: number;
319
+ kind: 'exit' | 'entry' | null;
320
+ };
198
321
  track: {
199
322
  hit: boolean;
200
323
  distanceMeters: number;
201
324
  kind: 'exit' | 'entry' | null;
202
325
  };
326
+ kerb: PaddockSurfaceRayHit;
327
+ illegalSurface: PaddockSurfaceRayHit;
203
328
  car: {
204
329
  hit: boolean;
205
330
  distanceMeters: number;
206
331
  driverId: string | null;
332
+ targetId?: string | null;
333
+ targetType?: 'car' | 'replayGhost' | null;
207
334
  relativeSpeedKph: number;
208
335
  };
209
336
  }
210
337
 
338
+ export interface PaddockSurfaceRayHit {
339
+ hit: boolean;
340
+ distanceMeters: number;
341
+ surface: string | null;
342
+ }
343
+
211
344
  export interface PaddockNearbyCarObservation {
212
345
  id: string;
213
346
  relativeForwardMeters: number;
@@ -216,7 +349,13 @@ export interface PaddockNearbyCarObservation {
216
349
  relativeSpeedKph: number;
217
350
  relativeHeadingRadians: number;
218
351
  ahead: boolean;
352
+ behind: boolean;
219
353
  sameLap: boolean;
354
+ closingRateMetersPerSecond: number;
355
+ timeToContactSeconds: number | null;
356
+ leftOverlap: boolean;
357
+ rightOverlap: boolean;
358
+ entityType?: 'car' | 'replayGhost';
220
359
  }
221
360
 
222
361
  export interface PaddockTrackLookaheadObservation {
@@ -225,15 +364,25 @@ export interface PaddockTrackLookaheadObservation {
225
364
  headingDeltaRadians: number;
226
365
  }
227
366
 
367
+ export interface PaddockAppliedControlsObservation {
368
+ steering: number;
369
+ steeringRadians: number;
370
+ throttle: number;
371
+ brake: number;
372
+ }
373
+
228
374
  export interface PaddockDriverObservationObject {
375
+ profile: string;
229
376
  self: {
230
377
  id: string;
231
378
  speedKph: number;
232
379
  speedMetersPerSecond: number;
233
380
  headingRadians: number;
381
+ yawRateRadiansPerSecond: number;
234
382
  steeringAngleRadians: number;
235
383
  throttle: number;
236
384
  brake: number;
385
+ appliedControls: PaddockAppliedControlsObservation | null;
237
386
  lap: number;
238
387
  completedLaps: number;
239
388
  lapProgressMeters: number;
@@ -252,9 +401,27 @@ export interface PaddockDriverObservationObject {
252
401
  pitStopServiceRemainingSeconds: number | null;
253
402
  pitStopPenaltyServiceRemainingSeconds: number | null;
254
403
  pitStopsCompleted: number;
404
+ lateralG: number;
405
+ longitudinalG: number;
406
+ gripUsage: number;
407
+ slipAngleRadians: number;
408
+ tractionLimited: boolean;
409
+ stabilityState: PaddockStabilityState;
410
+ destroyed: boolean;
411
+ destroyReason: string | null;
412
+ };
413
+ trackRelation: {
414
+ lateralOffsetMeters: number;
415
+ headingErrorRadians: number;
416
+ legalWidthMeters: number;
417
+ leftBoundaryMeters: number;
418
+ rightBoundaryMeters: number;
419
+ onLegalSurface: boolean;
420
+ surface: string;
255
421
  };
422
+ contactPatches: PaddockContactPatchObservation[];
256
423
  race: {
257
- position: number;
424
+ position: number | null;
258
425
  totalCars: number;
259
426
  raceMode: string;
260
427
  pitLaneOpen: boolean;
@@ -272,6 +439,17 @@ export interface PaddockDriverObservationObject {
272
439
  events: RaceEvent[];
273
440
  }
274
441
 
442
+ export interface PaddockContactPatchObservation {
443
+ id: 'front-left' | 'front-right' | 'rear-left' | 'rear-right' | string;
444
+ present: boolean;
445
+ signedOffsetMeters: number;
446
+ crossTrackErrorMeters: number;
447
+ surface: string;
448
+ surfaceCode: number;
449
+ onLegalSurface: boolean;
450
+ inPitLane: boolean;
451
+ }
452
+
275
453
  export interface PaddockObservationSchemaEntry {
276
454
  name: string;
277
455
  unit?: string;
@@ -279,21 +457,34 @@ export interface PaddockObservationSchemaEntry {
279
457
  }
280
458
 
281
459
  export interface PaddockDriverObservation {
282
- object: PaddockDriverObservationObject;
283
- vector: number[];
284
- schema: PaddockObservationSchemaEntry[];
460
+ object?: PaddockDriverObservationObject;
461
+ vector?: number[] | Float32Array;
462
+ schema?: PaddockObservationSchemaEntry[];
285
463
  events: RaceEvent[];
286
464
  }
287
465
 
466
+ export type PaddockWarmupPolicy = 'config-change' | 'always' | 'never';
467
+
468
+ export interface PaddockWarmupOptions {
469
+ enabled?: boolean;
470
+ policy?: PaddockWarmupPolicy;
471
+ steps?: number;
472
+ }
473
+
288
474
  export interface PaddockEnvironmentOptions {
289
475
  drivers: SimulatorDriver[];
290
476
  entries?: ChampionshipEntryBlueprint[];
291
477
  controlledDrivers: string[];
292
478
  seed?: number;
293
479
  trackSeed?: number;
480
+ trackGeneration?: PaddockProceduralTrackOptions;
481
+ trackQueryIndex?: boolean;
294
482
  totalLaps?: number;
295
483
  frameSkip?: number;
484
+ physicsMode?: PaddockPhysicsMode;
296
485
  rules?: PaddockRaceRules;
486
+ participantInteractions?: PaddockParticipantInteractionsOptions;
487
+ replayGhosts?: PaddockReplayGhostOptions[];
297
488
  actionPolicy?: 'strict' | 'report';
298
489
  scenario?: {
299
490
  participants?: 'all' | 'controlled-only' | string[];
@@ -307,6 +498,15 @@ export interface PaddockEnvironmentOptions {
307
498
  enabled?: boolean;
308
499
  anglesDegrees?: number[];
309
500
  lengthMeters?: number;
501
+ defaultLengthMeters?: number;
502
+ layout?: 'compact' | 'driver-front-heavy' | 'lidar-lite' | string;
503
+ rays?: Array<number | {
504
+ id?: string;
505
+ angleDegrees: number;
506
+ lengthMeters?: number;
507
+ }>;
508
+ channels?: Array<'roadEdge' | 'kerb' | 'illegalSurface' | 'car'>;
509
+ precision?: 'driver' | 'debug';
310
510
  detectTrack?: boolean;
311
511
  detectCars?: boolean;
312
512
  };
@@ -318,13 +518,27 @@ export interface PaddockEnvironmentOptions {
318
518
  };
319
519
  sensorsByDriver?: Record<string, PaddockEnvironmentOptions['sensors']>;
320
520
  observation?: {
521
+ profile?: 'default' | 'physical-driver' | 'debug-map' | string;
522
+ output?: 'full' | 'vector' | 'object';
523
+ includeSchema?: boolean;
524
+ vectorType?: 'array' | 'float32';
321
525
  lookaheadMeters?: number[];
322
526
  };
527
+ result?: {
528
+ stateOutput?: 'full' | 'minimal' | 'none';
529
+ resetDriversObservationScope?: 'all' | 'reset';
530
+ };
531
+ warmup?: PaddockWarmupOptions | boolean;
323
532
  episode?: {
324
533
  maxSteps?: number;
325
534
  endOnRaceFinish?: boolean;
326
535
  };
327
536
  reward?: (payload: PaddockRewardContext) => number;
537
+ externalRenderer?: PaddockExternalRendererHook | ((frame: PaddockExternalRenderFrame) => void);
538
+ }
539
+
540
+ export interface PaddockExternalRendererHook {
541
+ onFrame(frame: PaddockExternalRenderFrame): void;
328
542
  }
329
543
 
330
544
  export interface PaddockScenarioPlacement {
@@ -351,6 +565,8 @@ export interface PaddockRewardContext {
351
565
  action: PaddockAction | undefined;
352
566
  events: RaceEvent[];
353
567
  state: { snapshot: RaceSnapshot };
568
+ metrics: PaddockEnvironmentDriverMetrics;
569
+ episode: PaddockDriverRuntimeState;
354
570
  }
355
571
 
356
572
  export interface PaddockProgressRewardWeights {
@@ -382,12 +598,18 @@ export interface PaddockActionSpec {
382
598
  }
383
599
 
384
600
  export interface PaddockObservationSpec {
385
- version: 2;
601
+ version: 3 | 6;
386
602
  controlledDrivers: string[];
387
603
  object: Record<string, unknown>;
388
604
  vector: {
389
605
  schema: PaddockObservationSchemaEntry[];
390
606
  };
607
+ perDriver: Record<string, {
608
+ object: Record<string, unknown>;
609
+ vector: {
610
+ schema: PaddockObservationSchemaEntry[];
611
+ };
612
+ }>;
391
613
  }
392
614
 
393
615
  export interface PaddockRolloutTransition {
@@ -446,11 +668,114 @@ export type PaddockPolicyLike =
446
668
  | ((observation: PaddockDriverObservation, context: Record<string, unknown>) => PaddockAction)
447
669
  | { predict(observation: PaddockDriverObservation, context: Record<string, unknown>): PaddockAction };
448
670
 
671
+ export interface PaddockDriverControllerContext {
672
+ runtime: PaddockControllerRuntime;
673
+ mode: string;
674
+ actionRepeat: number;
675
+ controlledDrivers: string[];
676
+ actionSpec: PaddockActionSpec;
677
+ observationSpec: PaddockObservationSpec;
678
+ result: PaddockEnvironmentResult | unknown;
679
+ previousResult: PaddockEnvironmentResult | unknown | null;
680
+ observation: Record<string, PaddockDriverObservation>;
681
+ orderedObservations: Array<{
682
+ driverId: string;
683
+ index: number;
684
+ observation: PaddockDriverObservation | null;
685
+ vector: number[] | Float32Array | null;
686
+ }>;
687
+ metrics: Record<string, PaddockEnvironmentDriverMetrics>;
688
+ events: RaceEvent[];
689
+ info: PaddockEnvironmentResult['info'] | unknown | null;
690
+ previousActions: PaddockActionMap;
691
+ orderedPreviousActions: Array<PaddockAction | null>;
692
+ actions: PaddockActionMap | null;
693
+ policyStep: number;
694
+ runtimeStep: number;
695
+ heldFramesRemaining: number;
696
+ actionIndex: number;
697
+ resetDriverIds: string[];
698
+ }
699
+
700
+ export interface PaddockExternalRenderFrame {
701
+ snapshot: RaceSnapshot;
702
+ observation: Record<string, unknown>;
703
+ meta?: Record<string, unknown> | null;
704
+ }
705
+
706
+ export interface PaddockExternalRendererSource {
707
+ subscribe(onFrame: (frame: PaddockExternalRenderFrame) => void): () => void;
708
+ }
709
+
710
+ export interface PaddockExternalRendererState {
711
+ attached: boolean;
712
+ lastMeta: Record<string, unknown> | null;
713
+ lastFrameAt: number | null;
714
+ lastError: string | null;
715
+ }
716
+
717
+ export interface PaddockDriverController {
718
+ init?(context: PaddockDriverControllerContext): void | Promise<void>;
719
+ reset?(context: PaddockDriverControllerContext): void | Promise<void>;
720
+ decideBatch(context: PaddockDriverControllerContext): PaddockActionMap | Promise<PaddockActionMap>;
721
+ onStep?(context: PaddockDriverControllerContext): void | Promise<void>;
722
+ }
723
+
724
+ export interface PaddockControllerRuntime {
725
+ reset(options?: unknown): PaddockEnvironmentResult | unknown;
726
+ step(actions: PaddockActionMap): PaddockEnvironmentResult | unknown;
727
+ resetDrivers?(
728
+ placements: Record<string, PaddockScenarioPlacement>,
729
+ resultOptions?: PaddockEnvironmentResultOptions
730
+ ): PaddockEnvironmentResult | unknown;
731
+ getObservation(): Record<string, PaddockDriverObservation>;
732
+ getState?(options?: { output?: 'full' | 'minimal' | 'none' }): PaddockEnvironmentResult['state'] | unknown;
733
+ getActionSpec(): PaddockActionSpec;
734
+ getObservationSpec(): PaddockObservationSpec;
735
+ destroy?(): void;
736
+ }
737
+
738
+ export interface PaddockDriverControllerLoopOptions {
739
+ runtime: PaddockControllerRuntime;
740
+ controller: PaddockDriverController;
741
+ actionRepeat?: number;
742
+ mode?: string;
743
+ scheduler?: null | ((callback: () => void | Promise<void>) => unknown);
744
+ }
745
+
746
+ export interface PaddockDriverControllerLoop {
747
+ readonly result: PaddockEnvironmentResult | unknown | null;
748
+ readonly actionSpec: PaddockActionSpec | null;
749
+ readonly observationSpec: PaddockObservationSpec | null;
750
+ readonly stats: {
751
+ policyStep: number;
752
+ runtimeStep: number;
753
+ heldFramesRemaining: number;
754
+ actions: PaddockActionMap | null;
755
+ actionRepeat: number;
756
+ lastDecisionMs: number;
757
+ running: boolean;
758
+ lastError: unknown | null;
759
+ };
760
+ reset(options?: unknown): Promise<PaddockEnvironmentResult | unknown>;
761
+ resetDrivers(
762
+ placements: Record<string, PaddockScenarioPlacement>,
763
+ resultOptions?: PaddockEnvironmentResultOptions
764
+ ): Promise<PaddockEnvironmentResult | unknown>;
765
+ step(): Promise<PaddockEnvironmentResult | unknown>;
766
+ stepFrame(): Promise<PaddockEnvironmentResult | unknown>;
767
+ start(): void;
768
+ stop(): void;
769
+ }
770
+
449
771
  export interface PaddockEnvironmentWorkerMessage {
450
772
  id?: string | number | null;
451
- type: 'reset' | 'step' | 'getActionSpec' | 'getObservationSpec' | 'getObservation' | 'getState' | 'destroy' | string;
773
+ type: 'reset' | 'resetDrivers' | 'step' | 'getActionSpec' | 'getObservationSpec' | 'getObservation' | 'getState' | 'destroy' | string;
452
774
  options?: Partial<PaddockEnvironmentOptions>;
453
775
  actions?: PaddockActionMap;
776
+ placements?: Record<string, PaddockScenarioPlacement>;
777
+ resultOptions?: PaddockEnvironmentResultOptions;
778
+ stateOptions?: { output?: 'full' | 'minimal' | 'none' };
454
779
  }
455
780
 
456
781
  export interface PaddockEnvironmentWorkerResponse {
@@ -468,11 +793,12 @@ export interface PaddockEnvironmentWorkerProtocol {
468
793
  export interface PaddockEnvironmentResult {
469
794
  observation: Record<string, PaddockDriverObservation>;
470
795
  reward: null | Record<string, number>;
796
+ metrics: Record<string, PaddockEnvironmentDriverMetrics>;
471
797
  terminated: boolean;
472
798
  truncated: boolean;
473
799
  done: boolean;
474
800
  events: RaceEvent[];
475
- state: { snapshot: RaceSnapshot };
801
+ state: { snapshot: RaceSnapshot } | null;
476
802
  info: {
477
803
  step: number;
478
804
  elapsedSeconds: number;
@@ -481,20 +807,60 @@ export interface PaddockEnvironmentResult {
481
807
  controlledDrivers: string[];
482
808
  actionErrors: string[];
483
809
  endReason: string | null;
810
+ drivers: Record<string, PaddockDriverRuntimeState>;
484
811
  };
485
812
  }
486
813
 
814
+ export type PaddockEnvironmentSnapshotResult = PaddockEnvironmentResult & {
815
+ state: { snapshot: RaceSnapshot };
816
+ };
817
+
487
818
  export interface PaddockEnvironment {
488
819
  reset(options?: Partial<PaddockEnvironmentOptions>): PaddockEnvironmentResult;
820
+ resetDrivers(
821
+ placements: Record<string, PaddockScenarioPlacement>,
822
+ resultOptions?: PaddockEnvironmentResultOptions
823
+ ): PaddockEnvironmentResult;
489
824
  step(actions: PaddockActionMap): PaddockEnvironmentResult;
490
825
  getObservation(): PaddockEnvironmentResult['observation'];
491
- getState(): PaddockEnvironmentResult['state'];
826
+ getState(options?: { output?: 'full' | 'minimal' | 'none' }): PaddockEnvironmentResult['state'];
492
827
  getActionSpec(): PaddockActionSpec;
493
828
  getObservationSpec(): PaddockObservationSpec;
494
829
  destroy(): void;
495
830
  }
496
831
 
832
+ export interface PaddockEnvironmentResultOptions {
833
+ stateOutput?: 'full' | 'minimal' | 'none';
834
+ observationScope?: 'all' | 'reset';
835
+ resetDriversObservationScope?: 'all' | 'reset';
836
+ }
837
+
838
+ export interface PaddockDriverRuntimeState {
839
+ terminated: boolean;
840
+ truncated: boolean;
841
+ endReason: string | null;
842
+ episodeStep: number;
843
+ episodeId: number;
844
+ }
845
+
846
+ export interface PaddockEnvironmentDriverMetrics {
847
+ progressDeltaMeters: number;
848
+ legalProgressDeltaMeters: number;
849
+ offTrack: boolean;
850
+ kerb: boolean;
851
+ fullyOutsideWhiteLine: boolean;
852
+ severeCut: boolean;
853
+ destroyed: boolean;
854
+ destroyReason: string | null;
855
+ under30kph: boolean;
856
+ spinOrBackwards: boolean;
857
+ completedLap: boolean;
858
+ lapTimeSeconds: number | null;
859
+ contactCount: number;
860
+ }
861
+
497
862
  export function createPaddockEnvironment(options: PaddockEnvironmentOptions): PaddockEnvironment;
863
+ export function createPaddockDriverControllerLoop(options: PaddockDriverControllerLoopOptions): PaddockDriverControllerLoop;
498
864
  export function createProgressReward(options?: PaddockProgressRewardOptions): (context: PaddockRewardContext) => number;
499
865
  export function createRolloutRecorder(): PaddockRolloutRecorder;
500
866
  export function createRolloutTransition(
@@ -504,8 +870,8 @@ export function createRolloutTransition(
504
870
  ): PaddockRolloutTransition;
505
871
  export const ENVIRONMENT_SCENARIO_PRESETS: readonly PaddockScenarioPreset[];
506
872
  export const DEFAULT_EVALUATION_CASES: readonly PaddockEvaluationCase[];
507
- export function createEvaluationTracker(initialResult: PaddockEnvironmentResult): {
508
- update(result: PaddockEnvironmentResult): void;
873
+ export function createEvaluationTracker(initialResult: PaddockEnvironmentSnapshotResult): {
874
+ update(result: PaddockEnvironmentSnapshotResult): void;
509
875
  finish(): Record<string, PaddockEvaluationDriverMetrics>;
510
876
  };
511
877
  export function runEnvironmentEvaluation(options: {
@@ -1,4 +1,5 @@
1
1
  export { createPaddockEnvironment } from './runtime.js';
2
+ export { createPaddockDriverControllerLoop } from './controllerLoop.js';
2
3
  export { createProgressReward } from './rewards.js';
3
4
  export { createRolloutRecorder, createRolloutTransition } from './recorder.js';
4
5
  export {