@inventure71/paddockjs 4.1.0 → 4.3.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.
- package/CHANGELOG.md +76 -0
- package/INSTALL_AND_UPDATE.md +31 -5
- package/README.md +34 -3
- package/docs/advanced_ai_pace.md +131 -0
- package/docs/advanced_physics_rebuild.md +166 -0
- package/docs/architecture.md +111 -30
- package/docs/cleanup_coverage.md +284 -0
- package/docs/component_inventory.md +32 -16
- package/docs/composable-layouts.md +2 -0
- package/docs/concepts.md +12 -1
- package/docs/custom_model_controller.md +1 -1
- package/docs/data_contract.md +33 -10
- package/docs/data_model.md +4 -2
- package/docs/efficiency_cleanup_2026-10-13.md +80 -0
- package/docs/getting-started.md +3 -0
- package/docs/grid_walk.md +80 -0
- package/docs/index.md +5 -2
- package/docs/keyboard_driving_fix.md +118 -0
- package/docs/limit_driving_2026-10-14.md +88 -0
- package/docs/loading.md +141 -0
- package/docs/maintainability_audit_2026-09-08.md +146 -0
- package/docs/racing_ai_improvements.md +145 -0
- package/docs/rules.md +43 -13
- package/docs/sense_contract.md +4 -1
- package/docs/system_specs.md +40 -12
- package/docs/testing-reliability-guide.md +67 -0
- package/docs/v11_improvements.md +108 -0
- package/package.json +23 -15
- package/src/api/MountedSimulatorComponents.js +101 -0
- package/src/api/PaddockSimulatorController.js +56 -81
- package/src/app/BrowserExpertAdapter.js +0 -6
- package/src/app/BrowserExpertExternalRenderer.js +72 -50
- package/src/app/ExternalTrackSnapshot.js +50 -0
- package/src/app/F1SimulatorApp.js +242 -297
- package/src/app/HostLifecycleEmitter.js +93 -0
- package/src/app/banners/raceDataBannerController.js +9 -4
- package/src/app/camera/cameraConstants.js +1 -1
- package/src/app/camera/cameraController.js +10 -13
- package/src/app/camera/cameraGeometry.js +1 -1
- package/src/app/controls/SimulatorViewControls.js +45 -0
- package/src/app/controls/workbenchBindings.js +64 -0
- package/src/app/controls/workbenchDisclosure.js +41 -0
- package/src/app/domBindings.js +21 -13
- package/src/app/gridWalk/GridWalkController.js +180 -0
- package/src/app/gridWalk/gridWalkCamera.js +88 -0
- package/src/app/gridWalk/gridWalkControls.js +24 -0
- package/src/app/gridWalk/gridWalkCrew.js +246 -0
- package/src/app/gridWalk/gridWalkLabels.js +104 -0
- package/src/app/gridWalk/gridWalkLayout.js +46 -0
- package/src/app/gridWalk/gridWalkNavigation.js +99 -0
- package/src/app/gridWalk/gridWalkProjectBanner.js +43 -0
- package/src/app/gridWalk/gridWalkSession.js +50 -0
- package/src/app/layoutSupport.js +2 -0
- package/src/app/raceOverlayClearanceSupport.js +21 -7
- package/src/app/readouts/carOverviewRenderer.js +9 -4
- package/src/app/readouts/readoutFormatters.js +1 -8
- package/src/app/readouts/telemetryRenderer.js +1 -3
- package/src/app/readouts/timingTowerRenderer.js +48 -50
- package/src/app/rendering/appAssets.js +8 -10
- package/src/app/rendering/carRenderer.js +27 -79
- package/src/app/rendering/displayUtils.js +0 -6
- package/src/app/rendering/expertSensorRenderer.js +1 -1
- package/src/app/rendering/replayGhostRenderer.js +4 -1
- package/src/app/rendering/trackRenderer.js +2 -2
- package/src/app/runtime/frameLoop.js +18 -17
- package/src/app/runtime/pixiStartupLifecycle.js +94 -0
- package/src/app/runtime/runtimeTiming.js +4 -1
- package/src/app/runtime/runtimeVisibility.js +7 -2
- package/src/config/cssValues.js +1 -1
- package/src/config/defaultOptions.js +12 -173
- package/src/config/restartOptions.js +1 -0
- package/src/config/runtimeSeed.js +10 -0
- package/src/config/simulatorDefaults.js +106 -0
- package/src/config/telemetryModules.js +20 -0
- package/src/config/theme/cssTokens.js +85 -0
- package/src/config/theme/themeCss.js +72 -0
- package/src/config/theme/themeInputs.js +155 -0
- package/src/config/theme/themeResolver.js +172 -0
- package/src/config/theme/themeSelectors.js +69 -0
- package/src/config/theme/themeTokens.js +257 -0
- package/src/config/theme/themeUtils.js +15 -0
- package/src/config/themeOptions.js +14 -830
- package/src/config/timingGapMode.js +0 -2
- package/src/config/uiOptions.js +53 -0
- package/src/data/championship.js +16 -158
- package/src/data/championshipDefaults.js +87 -0
- package/src/data/driverData.js +10 -20
- package/src/data/entryIdentity.js +67 -0
- package/src/data/entryPresentation.js +23 -0
- package/src/data/entryTypes.d.ts +160 -0
- package/src/data/index.d.ts +12 -195
- package/src/data/ratingScale.js +14 -0
- package/src/data/teamTypes.d.ts +23 -0
- package/src/data/trackTypes.d.ts +101 -0
- package/src/data/vehicleData.js +12 -23
- package/src/environment/actions.js +3 -2
- package/src/environment/controllerLoop.js +57 -44
- package/src/environment/controllerScheduler.js +30 -0
- package/src/environment/driverObservations.js +260 -0
- package/src/environment/driverReset.js +51 -0
- package/src/environment/episode.js +0 -1
- package/src/environment/evaluation.js +6 -90
- package/src/environment/evaluationTracker.js +100 -0
- package/src/environment/events.js +23 -0
- package/src/environment/index.d.ts +35 -91
- package/src/environment/metrics.js +3 -17
- package/src/environment/observationSchema.js +104 -0
- package/src/environment/observationVector.js +16 -115
- package/src/environment/observations.js +16 -316
- package/src/environment/options.js +5 -24
- package/src/environment/renderFrames.js +21 -0
- package/src/environment/resetOptions.js +41 -0
- package/src/environment/results.js +125 -0
- package/src/environment/rewards.js +10 -16
- package/src/environment/runtime.js +17 -300
- package/src/environment/scenarioOptions.js +90 -0
- package/src/environment/scenarioPlacements.js +70 -0
- package/src/environment/scenarioPresets.js +78 -0
- package/src/environment/scenarios.js +5 -236
- package/src/environment/scratch.js +18 -0
- package/src/environment/sensorOptions.js +20 -0
- package/src/environment/sensors/index.js +2 -556
- package/src/environment/sensors/indexedRayBands.js +0 -18
- package/src/environment/sensors/nearbyCars.js +18 -15
- package/src/environment/sensors/opponentRadar.js +3 -2
- package/src/environment/sensors/pitConnectorProximity.js +20 -0
- package/src/environment/sensors/rayBandTrace.js +1 -37
- package/src/environment/sensors/rayBatch.js +81 -0
- package/src/environment/sensors/rayConfig.js +26 -0
- package/src/environment/sensors/rayGeometry.js +0 -8
- package/src/environment/sensors/rayGuards.js +0 -6
- package/src/environment/sensors/rayOutputs.js +75 -0
- package/src/environment/sensors/rayQuery.js +110 -0
- package/src/environment/sensors/rayScratch.js +146 -0
- package/src/environment/sensors/sensorTargets.js +12 -4
- package/src/environment/sensors/surfaceRays.js +6 -61
- package/src/environment/sensors/trackRays.js +7 -80
- package/src/environment/simulationSetup.js +30 -0
- package/src/environment/specs.js +15 -109
- package/src/index.d.ts +43 -202
- package/src/index.js +28 -6
- package/src/placeholder/index.js +1 -8
- package/src/rendering/displayLifecycle.js +6 -0
- package/src/rendering/proceduralTrackAsset.js +1 -1
- package/src/rendering/renderSnapshot.js +3 -0
- package/src/rendering/track/finishLineRenderer.js +1 -1
- package/src/rendering/track/gridRenderer.js +1 -1
- package/src/rendering/track/offsetStrokeSafety.js +2 -2
- package/src/rendering/track/pitLaneRenderer.js +1 -1
- package/src/rendering/track/trackMaterialRenderer.js +4 -4
- package/src/rendering/track/trackRenderConstants.js +0 -1
- package/src/rendering/track/trackRenderGeometry.js +1 -7
- package/src/simulation/collisionGeometry.js +12 -20
- package/src/simulation/driver/advancedPathControls.js +53 -0
- package/src/simulation/driver/advancedRacePace.js +112 -0
- package/src/simulation/driver/advancedRacingControls.js +61 -0
- package/src/simulation/driver/advancedRacingEnvelope.js +255 -0
- package/src/simulation/driver/advancedRacingSteering.js +76 -0
- package/src/simulation/driver/advancedRacingTiming.js +16 -0
- package/src/simulation/driver/arcadeRacePace.js +83 -0
- package/src/simulation/driver/arcadeRacingControls.js +111 -0
- package/src/simulation/driver/arcadeRacingEnvelope.js +63 -0
- package/src/simulation/driver/driverControlConstants.js +0 -2
- package/src/simulation/driver/driverController.js +16 -5
- package/src/simulation/driver/edgeRecovery.js +2 -3
- package/src/simulation/driver/racingControls.js +10 -396
- package/src/simulation/driver/racingDriverProfile.js +48 -0
- package/src/simulation/driver/racingLinePlan.js +54 -20
- package/src/simulation/driver/rejoinControls.js +59 -112
- package/src/simulation/driver/safetyCarControls.js +12 -0
- package/src/simulation/driver/trafficScan.js +136 -27
- package/src/simulation/participants/participantInteractions.js +24 -15
- package/src/simulation/pit/pitCarPlacement.js +29 -0
- package/src/simulation/pit/pitFlow.js +8 -30
- package/src/simulation/pit/pitIntent.js +4 -3
- package/src/simulation/pit/pitOccupancy.js +2 -2
- package/src/simulation/pit/pitQueue.js +2 -18
- package/src/simulation/pit/pitRouteMovement.js +1 -36
- package/src/simulation/pit/pitRouting.js +5 -81
- package/src/simulation/pit/pitService.js +3 -32
- package/src/simulation/pit/pitServiceConstants.js +1 -0
- package/src/simulation/pit/pitServiceProgress.js +34 -0
- package/src/simulation/pit/pitSnapshots.js +8 -4
- package/src/simulation/pit/pitState.js +1 -5
- package/src/simulation/race/classification.js +1 -8
- package/src/simulation/race/raceFinish.js +3 -8
- package/src/simulation/race/raceOrder.js +2 -13
- package/src/simulation/race/raceProgress.js +6 -20
- package/src/simulation/race/raceSetup.js +1 -1
- package/src/simulation/race/raceStep.js +20 -11
- package/src/simulation/race/redFlag.js +2 -4
- package/src/simulation/race/safetyCar.js +5 -9
- package/src/simulation/race/stalledDnf.js +2 -4
- package/src/simulation/raceSimulation.js +6 -38
- package/src/simulation/replay/replayGhosts.js +44 -32
- package/src/simulation/rules/collisionSteward.js +0 -14
- package/src/simulation/rules/penaltyActions.js +37 -0
- package/src/simulation/rules/penaltyLedger.js +8 -1
- package/src/simulation/rules/pitLaneSpeedingSteward.js +1 -1
- package/src/simulation/rules/rulesReview.js +20 -16
- package/src/simulation/rules/trackLimitsSteward.js +2 -2
- package/src/simulation/simMath.js +4 -0
- package/src/simulation/snapshots/raceSnapshots.js +30 -11
- package/src/simulation/timing/drsState.js +8 -0
- package/src/simulation/timing/drsTiming.js +2 -4
- package/src/simulation/timing/lapTelemetry.js +7 -4
- package/src/simulation/timing/sectorPerformance.js +14 -6
- package/src/simulation/timing/timingLines.js +12 -6
- package/src/simulation/track/pitLaneAccess.js +2 -2
- package/src/simulation/track/pitLaneLayout.js +4 -135
- package/src/simulation/track/pitLaneModel.js +70 -0
- package/src/simulation/track/pitLaneState.js +0 -1
- package/src/simulation/track/pitServiceLayout.js +121 -0
- package/src/simulation/track/proceduralTrack.js +77 -0
- package/src/simulation/track/spatialQueries.js +76 -31
- package/src/simulation/track/trackBuilder.js +54 -0
- package/src/simulation/track/trackConstants.js +0 -22
- package/src/simulation/track/trackMath.js +4 -29
- package/src/simulation/track/trackModel.js +12 -240
- package/src/simulation/track/trackModelCache.js +105 -0
- package/src/simulation/track/trackNearestQueries.js +1218 -0
- package/src/simulation/track/trackQueryConstants.js +3 -0
- package/src/simulation/track/trackQueryConstruction.js +368 -0
- package/src/simulation/track/trackQueryIndex.js +12 -1933
- package/src/simulation/track/trackQuerySegments.js +174 -0
- package/src/simulation/track/trackQueryStats.js +12 -0
- package/src/simulation/track/trackRayQueries.js +165 -0
- package/src/simulation/vehicle/advancedContactResponse.js +89 -0
- package/src/simulation/vehicle/advancedTireForces.js +92 -0
- package/src/simulation/vehicle/advancedVehicleModel.js +65 -0
- package/src/simulation/vehicle/advancedVehiclePhysics.js +127 -0
- package/src/simulation/vehicle/contactResolution.js +23 -9
- package/src/simulation/vehicle/mainTrackWheelSurface.js +2 -13
- package/src/simulation/vehicle/pitWheelSurface.js +0 -12
- package/src/simulation/vehicle/runoffResponse.js +2 -4
- package/src/simulation/vehicle/sampledWheelSurface.js +266 -0
- package/src/simulation/vehicle/vehicleGeometry.js +85 -103
- package/src/simulation/vehicle/vehicleKinematics.js +10 -0
- package/src/simulation/vehicle/vehiclePhysics.js +42 -196
- package/src/simulation/vehicle/vehicleSnapshots.js +18 -6
- package/src/simulation/vehicle/vehicleState.js +5 -3
- package/src/simulation/vehicle/wheelSurface.js +13 -432
- package/src/simulation/vehicle/wheelSurfaceCache.js +55 -0
- package/src/simulation/vehicle/wheelSurfaceSummary.js +101 -0
- package/src/styles.css +173 -19
- package/src/ui/bannerTemplates.js +4 -2
- package/src/ui/cameraControlsTemplate.js +4 -2
- package/src/ui/gridWalkTemplate.js +29 -0
- package/src/ui/htmlEscaping.js +8 -0
- package/src/ui/raceCanvasTemplate.js +3 -2
- package/src/ui/shellTemplate.js +3 -0
- package/src/ui/telemetryDrawerTemplate.js +4 -2
- package/src/ui/telemetryTemplates.js +3 -22
- package/src/ui/templateUtils.js +2 -8
- package/src/ui/viewControlsTemplate.js +21 -0
- package/examples/train-basic-policy.mjs +0 -276
- package/examples/trainingData.mjs +0 -133
package/src/index.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import type { PaddockProceduralTrackProfile, PaddockProceduralTrackOptions, PaddockTrackPoint, PaddockDrsZone, PaddockResolvedProceduralTrackOptions, PaddockProceduralTrack } from './data/trackTypes.js';
|
|
2
|
+
import type { TireCompound, CustomField, CustomFieldInput, EntryPresentation, SimulatorDriver, DriverRatings, VehicleRatings, DriverBlueprint, VehicleBlueprint, DriverConstructorArgs, VehicleConstructorArgs, DriverData, VehicleData, ChampionshipEntryBlueprint, NormalizedSimulatorDriver } from './data/entryTypes.js';
|
|
3
|
+
export type { PaddockProceduralTrackProfile, PaddockProceduralTrackOptions, PaddockTrackPoint, PaddockDrsZone, PaddockResolvedProceduralTrackOptions, PaddockProceduralTrack } from './data/trackTypes.js';
|
|
4
|
+
export type { TireCompound, CustomField, CustomFieldInput, EntryPresentation, SimulatorDriver, DriverRatings, VehicleRatings, DriverBlueprint, VehicleBlueprint, DriverConstructorArgs, VehicleConstructorArgs, ChampionshipEntryBlueprint, NormalizedSimulatorDriver } from './data/entryTypes.js';
|
|
5
|
+
export { DriverData, VehicleData } from './data/entryTypes.js';
|
|
6
|
+
|
|
1
7
|
import type {
|
|
2
8
|
PaddockActionSpec,
|
|
3
9
|
PaddockDriverControllerLoop,
|
|
4
10
|
PaddockDriverControllerLoopOptions,
|
|
11
|
+
PaddockEnvironmentResult,
|
|
5
12
|
PaddockEnvironmentOptions,
|
|
6
13
|
PaddockObservationSpec,
|
|
7
14
|
PaddockParticipantInteraction as EnvPaddockParticipantInteraction,
|
|
@@ -12,6 +19,11 @@ import type {
|
|
|
12
19
|
PaddockReplayGhostSnapshot as EnvPaddockReplayGhostSnapshot,
|
|
13
20
|
PaddockReplayGhostTrajectorySample as EnvPaddockReplayGhostTrajectorySample,
|
|
14
21
|
} from './environment/index.js';
|
|
22
|
+
import type {
|
|
23
|
+
PaddockPitCrewStats,
|
|
24
|
+
PaddockThemeSelector,
|
|
25
|
+
TeamData,
|
|
26
|
+
} from './data/teamTypes.js';
|
|
15
27
|
|
|
16
28
|
export type {
|
|
17
29
|
PaddockActionSpec,
|
|
@@ -20,13 +32,18 @@ export type {
|
|
|
20
32
|
PaddockDriverControllerContext,
|
|
21
33
|
PaddockDriverControllerLoop,
|
|
22
34
|
PaddockDriverControllerLoopOptions,
|
|
35
|
+
PaddockEnvironmentResult,
|
|
36
|
+
PaddockEnvironmentSnapshotResult,
|
|
23
37
|
PaddockObservationSpec,
|
|
24
38
|
} from './environment/index.js';
|
|
39
|
+
export type {
|
|
40
|
+
PaddockPitCrewStats,
|
|
41
|
+
PaddockThemeSelector,
|
|
42
|
+
TeamData,
|
|
43
|
+
} from './data/teamTypes.js';
|
|
25
44
|
|
|
26
|
-
export type TireCompound = 'S' | 'M' | 'H';
|
|
27
45
|
export type PaddockPhysicsMode = 'arcade' | 'advanced';
|
|
28
46
|
export type PaddockWarmupPolicy = 'config-change' | 'always' | 'never';
|
|
29
|
-
export type PaddockProceduralTrackProfile = 'race' | 'training-short' | 'training-medium' | 'training-technical';
|
|
30
47
|
|
|
31
48
|
export interface PaddockWarmupOptions {
|
|
32
49
|
enabled?: boolean;
|
|
@@ -34,43 +51,6 @@ export interface PaddockWarmupOptions {
|
|
|
34
51
|
steps?: number;
|
|
35
52
|
}
|
|
36
53
|
|
|
37
|
-
export interface PaddockProceduralTrackOptions {
|
|
38
|
-
profile?: PaddockProceduralTrackProfile;
|
|
39
|
-
minLengthMeters?: number;
|
|
40
|
-
maxLengthMeters?: number;
|
|
41
|
-
startStraightMeters?: number;
|
|
42
|
-
includePitLane?: boolean;
|
|
43
|
-
length?: {
|
|
44
|
-
minMeters?: number;
|
|
45
|
-
maxMeters?: number;
|
|
46
|
-
};
|
|
47
|
-
startStraight?: {
|
|
48
|
-
gridMeters?: number;
|
|
49
|
-
exitMeters?: number;
|
|
50
|
-
blendMeters?: number;
|
|
51
|
-
lockExtraMeters?: number;
|
|
52
|
-
};
|
|
53
|
-
pitLane?: {
|
|
54
|
-
enabled?: boolean;
|
|
55
|
-
};
|
|
56
|
-
shape?: {
|
|
57
|
-
scale?: number;
|
|
58
|
-
cornerDensity?: number;
|
|
59
|
-
variation?: number;
|
|
60
|
-
};
|
|
61
|
-
validation?: {
|
|
62
|
-
minClearanceMultiplier?: number;
|
|
63
|
-
minShapeVariation?: number;
|
|
64
|
-
minNonAdjacentArcMeters?: number;
|
|
65
|
-
maxLocalTurnRadians?: number;
|
|
66
|
-
maxSampleHeadingDeltaRadians?: number;
|
|
67
|
-
};
|
|
68
|
-
attempts?: {
|
|
69
|
-
primary?: number;
|
|
70
|
-
fallback?: number;
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
54
|
export type PaddockStabilityState = 'stable' | 'understeer' | 'oversteer' | 'spin-risk' | 'destroyed';
|
|
75
55
|
export type PaddockPitIntent = 0 | 1 | 2;
|
|
76
56
|
export type PaddockPitIntentRequest = PaddockPitIntent | {
|
|
@@ -90,6 +70,7 @@ export type TimingTowerVerticalFit = 'expand-race-view' | 'scroll';
|
|
|
90
70
|
export type TimingGapMode = 'interval' | 'leader';
|
|
91
71
|
export type LayoutPreset = 'standard' | 'left-tower-overlay';
|
|
92
72
|
export type CameraControlsMode = 'embedded' | 'external' | false;
|
|
73
|
+
export type ViewControlsMode = 'switch' | 'toggle';
|
|
93
74
|
export type PaddockPresetName = 'dashboard' | 'timing-overlay' | 'compact-race' | 'full-dashboard';
|
|
94
75
|
export type TelemetryModuleName = 'core' | 'sectors' | 'lapTimes' | 'sectorTimes';
|
|
95
76
|
export type SectorPerformanceStatus = 'overall-best' | 'personal-best' | 'slower';
|
|
@@ -101,164 +82,7 @@ export type PaddockReplayGhostTrajectorySample = EnvPaddockReplayGhostTrajectory
|
|
|
101
82
|
export type PaddockReplayGhostOptions = EnvPaddockReplayGhostOptions;
|
|
102
83
|
export type PaddockReplayGhostSnapshot = EnvPaddockReplayGhostSnapshot;
|
|
103
84
|
|
|
104
|
-
export interface CustomField {
|
|
105
|
-
label: string;
|
|
106
|
-
value: string;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export type CustomFieldInput = CustomField[] | Record<string, string>;
|
|
110
|
-
|
|
111
|
-
export interface TeamData {
|
|
112
|
-
id?: string;
|
|
113
|
-
name?: string;
|
|
114
|
-
color?: string;
|
|
115
|
-
icon?: string;
|
|
116
|
-
theme?: PaddockThemeSelector;
|
|
117
|
-
pitCrew?: PaddockPitCrewStats;
|
|
118
|
-
pitCrewStats?: PaddockPitCrewStats;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export interface PaddockPitCrewStats {
|
|
122
|
-
speed?: number;
|
|
123
|
-
consistency?: number;
|
|
124
|
-
reliability?: number;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export interface SimulatorDriver {
|
|
128
|
-
id: string;
|
|
129
|
-
name: string;
|
|
130
|
-
color: string;
|
|
131
|
-
link?: string;
|
|
132
|
-
icon?: string;
|
|
133
|
-
code?: string;
|
|
134
|
-
timingName?: string;
|
|
135
|
-
tire?: TireCompound;
|
|
136
|
-
raceData?: string[];
|
|
137
|
-
customFields?: CustomFieldInput;
|
|
138
|
-
team?: TeamData | null;
|
|
139
|
-
driverNumber?: number;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export interface DriverRatings {
|
|
143
|
-
pace: number;
|
|
144
|
-
racecraft: number;
|
|
145
|
-
aggression: number;
|
|
146
|
-
riskTolerance: number;
|
|
147
|
-
patience: number;
|
|
148
|
-
consistency: number;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface VehicleRatings {
|
|
152
|
-
power: number;
|
|
153
|
-
braking: number;
|
|
154
|
-
aero: number;
|
|
155
|
-
dragEfficiency: number;
|
|
156
|
-
mechanicalGrip: number;
|
|
157
|
-
weightControl: number;
|
|
158
|
-
tireCare: number;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export interface DriverBlueprint extends Partial<DriverRatings> {
|
|
162
|
-
customFields?: CustomFieldInput;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export interface VehicleBlueprint extends Partial<VehicleRatings> {
|
|
166
|
-
id?: string | null;
|
|
167
|
-
name?: string | null;
|
|
168
|
-
customFields?: CustomFieldInput;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export interface DriverConstructorArgs {
|
|
172
|
-
ratings: DriverRatings;
|
|
173
|
-
customFields: CustomField[];
|
|
174
|
-
pace: number;
|
|
175
|
-
racecraft: number;
|
|
176
|
-
consistency: number;
|
|
177
|
-
personality: {
|
|
178
|
-
aggression: number;
|
|
179
|
-
riskTolerance: number;
|
|
180
|
-
patience: number;
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export interface VehicleConstructorArgs {
|
|
185
|
-
id: string | null;
|
|
186
|
-
name: string | null;
|
|
187
|
-
ratings: VehicleRatings;
|
|
188
|
-
customFields: CustomField[];
|
|
189
|
-
powerNewtons: number;
|
|
190
|
-
brakeNewtons: number;
|
|
191
|
-
downforceCoefficient: number;
|
|
192
|
-
dragCoefficient: number;
|
|
193
|
-
tireGrip: number;
|
|
194
|
-
mass: number;
|
|
195
|
-
tireCare: number;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export class DriverData {
|
|
199
|
-
constructor(input?: DriverBlueprint);
|
|
200
|
-
readonly pace: number;
|
|
201
|
-
readonly racecraft: number;
|
|
202
|
-
readonly aggression: number;
|
|
203
|
-
readonly riskTolerance: number;
|
|
204
|
-
readonly patience: number;
|
|
205
|
-
readonly consistency: number;
|
|
206
|
-
readonly customFields: CustomField[];
|
|
207
|
-
ratings(): DriverRatings;
|
|
208
|
-
toConstructorArgs(): DriverConstructorArgs;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export class VehicleData {
|
|
212
|
-
constructor(input?: VehicleBlueprint);
|
|
213
|
-
readonly id: string | null;
|
|
214
|
-
readonly name: string | null;
|
|
215
|
-
readonly power: number;
|
|
216
|
-
readonly braking: number;
|
|
217
|
-
readonly aero: number;
|
|
218
|
-
readonly dragEfficiency: number;
|
|
219
|
-
readonly mechanicalGrip: number;
|
|
220
|
-
readonly weightControl: number;
|
|
221
|
-
readonly tireCare: number;
|
|
222
|
-
readonly customFields: CustomField[];
|
|
223
|
-
ratings(): VehicleRatings;
|
|
224
|
-
toConstructorArgs(): VehicleConstructorArgs;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export interface ChampionshipEntryBlueprint {
|
|
228
|
-
driverId: string;
|
|
229
|
-
driverNumber?: number;
|
|
230
|
-
timingName?: string;
|
|
231
|
-
driver?: DriverData | DriverBlueprint;
|
|
232
|
-
vehicle?: VehicleData | VehicleBlueprint;
|
|
233
|
-
team?: TeamData;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export interface NormalizedSimulatorDriver extends SimulatorDriver {
|
|
237
|
-
code: string;
|
|
238
|
-
timingCode: string;
|
|
239
|
-
raceName: string;
|
|
240
|
-
driverNumber: number;
|
|
241
|
-
team: TeamData | null;
|
|
242
|
-
pace: number;
|
|
243
|
-
racecraft: number;
|
|
244
|
-
consistency: number;
|
|
245
|
-
personality: DriverConstructorArgs['personality'];
|
|
246
|
-
vehicle: VehicleConstructorArgs;
|
|
247
|
-
constructorArgs: {
|
|
248
|
-
driver: DriverConstructorArgs;
|
|
249
|
-
vehicle: VehicleConstructorArgs;
|
|
250
|
-
};
|
|
251
|
-
championship: {
|
|
252
|
-
id: string;
|
|
253
|
-
name: string;
|
|
254
|
-
season: number;
|
|
255
|
-
entryIndex: number;
|
|
256
|
-
vehicleId: string | null;
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
|
|
260
85
|
export type PaddockThemeMode = 'dark' | 'light' | 'system';
|
|
261
|
-
export type PaddockThemeSelector = 'default' | 'active' | 'selectedTeam' | 'team' | `team:${string}` | string;
|
|
262
86
|
export type PaddockThemeTokenValue = string | { light?: string; dark?: string };
|
|
263
87
|
export type PaddockThemeTokenName =
|
|
264
88
|
| 'primary'
|
|
@@ -366,6 +190,8 @@ export interface PaddockThemeSyncOptions {
|
|
|
366
190
|
export interface F1SimulatorUiOptions {
|
|
367
191
|
layoutPreset?: LayoutPreset;
|
|
368
192
|
cameraControls?: CameraControlsMode;
|
|
193
|
+
/** Two mode buttons by default; toggle uses one Start race / Stop race action. */
|
|
194
|
+
viewControls?: ViewControlsMode;
|
|
369
195
|
showFps?: boolean;
|
|
370
196
|
showTimingTower?: boolean;
|
|
371
197
|
showTelemetry?: boolean;
|
|
@@ -959,14 +785,14 @@ export interface PaddockEnvironmentResultOptions {
|
|
|
959
785
|
}
|
|
960
786
|
|
|
961
787
|
export interface F1SimulatorExpertApi {
|
|
962
|
-
reset(options?: unknown):
|
|
963
|
-
step(actions: Record<string, F1SimulatorExpertAction>):
|
|
788
|
+
reset(options?: unknown): PaddockEnvironmentResult;
|
|
789
|
+
step(actions: Record<string, F1SimulatorExpertAction>): PaddockEnvironmentResult;
|
|
964
790
|
resetDrivers?(
|
|
965
791
|
placements: Record<string, PaddockScenarioPlacement>,
|
|
966
792
|
resultOptions?: PaddockEnvironmentResultOptions
|
|
967
|
-
):
|
|
968
|
-
getObservation():
|
|
969
|
-
getState():
|
|
793
|
+
): PaddockEnvironmentResult;
|
|
794
|
+
getObservation(): PaddockEnvironmentResult['observation'];
|
|
795
|
+
getState(): PaddockEnvironmentResult['state'];
|
|
970
796
|
getActionSpec(): PaddockActionSpec;
|
|
971
797
|
getObservationSpec(): PaddockObservationSpec;
|
|
972
798
|
attachExternalRenderer(source: PaddockExternalRendererSource): void;
|
|
@@ -975,7 +801,16 @@ export interface F1SimulatorExpertApi {
|
|
|
975
801
|
destroy(): void;
|
|
976
802
|
}
|
|
977
803
|
|
|
804
|
+
export type PaddockView = 'grid-walk' | 'race';
|
|
805
|
+
|
|
806
|
+
export interface GridWalkOptions {
|
|
807
|
+
enabled?: boolean;
|
|
808
|
+
initialView?: PaddockView;
|
|
809
|
+
ambientMotion?: boolean;
|
|
810
|
+
}
|
|
811
|
+
|
|
978
812
|
export interface F1SimulatorOptions extends F1SimulatorCallbacks {
|
|
813
|
+
gridWalk?: GridWalkOptions;
|
|
979
814
|
preset?: PaddockPresetName;
|
|
980
815
|
drivers: SimulatorDriver[];
|
|
981
816
|
entries?: ChampionshipEntryBlueprint[];
|
|
@@ -1031,6 +866,8 @@ export interface F1MountedSimulator {
|
|
|
1031
866
|
getTheme(): ResolvedPaddockTheme;
|
|
1032
867
|
syncThemeFrom(source: Element, options?: PaddockThemeSyncOptions): () => void;
|
|
1033
868
|
selectDriver(driverId: string): void;
|
|
869
|
+
setView(view: PaddockView): boolean;
|
|
870
|
+
getView(): PaddockView;
|
|
1034
871
|
setSafetyCarDeployed(deployed: boolean): void;
|
|
1035
872
|
setRedFlagDeployed(deployed: boolean): void;
|
|
1036
873
|
setPitLaneOpen(open: boolean): void;
|
|
@@ -1053,6 +890,7 @@ export interface PaddockSimulatorController {
|
|
|
1053
890
|
readonly expert: F1SimulatorExpertApi | null;
|
|
1054
891
|
mountRaceControls<T extends Element>(root: T): T;
|
|
1055
892
|
mountCameraControls<T extends Element>(root: T): T;
|
|
893
|
+
mountViewControls<T extends Element>(root: T): T;
|
|
1056
894
|
mountSafetyCarControl<T extends Element>(root: T): T;
|
|
1057
895
|
mountTimingTower<T extends Element>(root: T): T;
|
|
1058
896
|
mountRaceCanvas<T extends Element>(root: T, options?: MountRaceCanvasOptions): T;
|
|
@@ -1075,6 +913,8 @@ export interface PaddockSimulatorController {
|
|
|
1075
913
|
getTheme(): ResolvedPaddockTheme;
|
|
1076
914
|
syncThemeFrom(source: Element, options?: PaddockThemeSyncOptions): () => void;
|
|
1077
915
|
selectDriver(driverId: string): void;
|
|
916
|
+
setView(view: PaddockView): boolean;
|
|
917
|
+
getView(): PaddockView;
|
|
1078
918
|
setSafetyCarDeployed(deployed: boolean): void;
|
|
1079
919
|
setRedFlagDeployed(deployed: boolean): void;
|
|
1080
920
|
setPitLaneOpen(open: boolean): void;
|
|
@@ -1133,11 +973,12 @@ export function simSpeedToMetersPerSecond(simSpeed: number): number;
|
|
|
1133
973
|
|
|
1134
974
|
export function createPaddockSimulator(options: F1SimulatorOptions): PaddockSimulatorController;
|
|
1135
975
|
export function mountF1Simulator(root: Element, options: F1SimulatorOptions): Promise<F1MountedSimulator>;
|
|
1136
|
-
export function createProceduralTrack(seed?: number | string, options?: PaddockProceduralTrackOptions):
|
|
976
|
+
export function createProceduralTrack(seed?: number | string, options?: PaddockProceduralTrackOptions): PaddockProceduralTrack;
|
|
1137
977
|
export function createPaddockDriverControllerLoop(options: PaddockDriverControllerLoopOptions): PaddockDriverControllerLoop;
|
|
1138
978
|
|
|
1139
979
|
export function mountRaceControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1140
980
|
export function mountCameraControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
981
|
+
export function mountViewControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1141
982
|
export function mountSafetyCarControl<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1142
983
|
export function mountTimingTower<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1143
984
|
export function mountRaceCanvas<T extends Element>(
|
package/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export {
|
|
|
8
8
|
createPaddockSimulator,
|
|
9
9
|
mountCarDriverOverview,
|
|
10
10
|
mountCameraControls,
|
|
11
|
+
mountViewControls,
|
|
11
12
|
mountRaceCanvas,
|
|
12
13
|
mountRaceControls,
|
|
13
14
|
mountRaceDataPanel,
|
|
@@ -60,14 +61,30 @@ function assertMountRoot(root) {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
const activeSimulatorRoots = new WeakMap();
|
|
65
|
+
|
|
63
66
|
export async function mountF1Simulator(root, options = {}) {
|
|
64
67
|
assertMountRoot(root);
|
|
68
|
+
if (activeSimulatorRoots.has(root)) {
|
|
69
|
+
throw new Error('mountF1Simulator root already has an active simulator. Destroy it before mounting again.');
|
|
70
|
+
}
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
root
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
const mountToken = {};
|
|
73
|
+
activeSimulatorRoots.set(root, mountToken);
|
|
74
|
+
let app = null;
|
|
75
|
+
let resolvedOptions;
|
|
76
|
+
try {
|
|
77
|
+
resolvedOptions = resolveF1SimulatorOptions(options);
|
|
78
|
+
root.innerHTML = createF1SimulatorShell(resolvedOptions);
|
|
79
|
+
const shell = root.querySelector('[data-f1-simulator-shell]');
|
|
80
|
+
app = new F1SimulatorApp(shell, resolvedOptions);
|
|
81
|
+
await app.init();
|
|
82
|
+
} catch (error) {
|
|
83
|
+
app?.destroy();
|
|
84
|
+
if (activeSimulatorRoots.get(root) === mountToken) activeSimulatorRoots.delete(root);
|
|
85
|
+
root.innerHTML = '';
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
71
88
|
|
|
72
89
|
const syncResolvedTimingGapMode = (timingGapMode) => {
|
|
73
90
|
resolvedOptions = {
|
|
@@ -90,7 +107,10 @@ export async function mountF1Simulator(root, options = {}) {
|
|
|
90
107
|
},
|
|
91
108
|
destroy() {
|
|
92
109
|
app.destroy();
|
|
93
|
-
root
|
|
110
|
+
if (activeSimulatorRoots.get(root) === mountToken) {
|
|
111
|
+
activeSimulatorRoots.delete(root);
|
|
112
|
+
root.innerHTML = '';
|
|
113
|
+
}
|
|
94
114
|
},
|
|
95
115
|
restart(nextOptions = {}) {
|
|
96
116
|
const nextResolvedOptions = resolveF1SimulatorOptions(mergeRestartOptions(syncResolvedRuntimeOptions(), nextOptions));
|
|
@@ -116,6 +136,8 @@ export async function mountF1Simulator(root, options = {}) {
|
|
|
116
136
|
selectDriver(driverId) {
|
|
117
137
|
app.selectCar(driverId, { focus: true });
|
|
118
138
|
},
|
|
139
|
+
setView(view) { return app.setView(view); },
|
|
140
|
+
getView() { return app.getView(); },
|
|
119
141
|
setSafetyCarDeployed(deployed) {
|
|
120
142
|
app.setSafetyCarDeployed(deployed);
|
|
121
143
|
},
|
package/src/placeholder/index.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
return String(value ?? '')
|
|
3
|
-
.replaceAll('&', '&')
|
|
4
|
-
.replaceAll('<', '<')
|
|
5
|
-
.replaceAll('>', '>')
|
|
6
|
-
.replaceAll('"', '"')
|
|
7
|
-
.replaceAll("'", ''');
|
|
8
|
-
}
|
|
1
|
+
import { escapeHtml } from '../ui/htmlEscaping.js';
|
|
9
2
|
|
|
10
3
|
function normalizeVariant(value) {
|
|
11
4
|
return value === 'custom' ? 'custom' : 'lights';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Display objects own their children, while simulator textures remain shared.
|
|
2
|
+
export function destroyDisplayChildren(container) {
|
|
3
|
+
container?.removeChildren?.().forEach((child) => {
|
|
4
|
+
child.destroy?.({ children: true, texture: false, textureSource: false });
|
|
5
|
+
});
|
|
6
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Container } from 'pixi.js';
|
|
2
2
|
import { WORLD } from '../simulation/track/trackModel.js';
|
|
3
|
-
import { destroyDisplayChildren } from './
|
|
3
|
+
import { destroyDisplayChildren } from './displayLifecycle.js';
|
|
4
4
|
import { addAsphalt, addBarriers, addBorders, addBoundaryUnderlay, addGrass, addGravelRunoff, addKerbs } from './track/trackMaterialRenderer.js';
|
|
5
5
|
import { addPitLane, addPitLaneRunoff } from './track/pitLaneRenderer.js';
|
|
6
6
|
import { addStartingGrid } from './track/gridRenderer.js';
|
|
@@ -11,6 +11,9 @@ function interpolateAngle(previous, current, amount) {
|
|
|
11
11
|
|
|
12
12
|
function interpolateMovingEntityInto(target, entity, alpha) {
|
|
13
13
|
Object.assign(target, entity);
|
|
14
|
+
// Retirement stops pose integration, so its previous endpoint may be from
|
|
15
|
+
// the last moving step. A stationary wreck must not replay that movement.
|
|
16
|
+
if (entity.destroyed || entity.outOfRace) return target;
|
|
14
17
|
target.x = lerp(entity.previousX ?? entity.x, entity.x, alpha);
|
|
15
18
|
target.y = lerp(entity.previousY ?? entity.y, entity.y, alpha);
|
|
16
19
|
target.heading = interpolateAngle(entity.previousHeading ?? entity.heading, entity.heading, alpha);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Graphics } from 'pixi.js';
|
|
2
|
-
import { offsetTrackPoint, pointAt } from '../../simulation/trackModel.js';
|
|
2
|
+
import { offsetTrackPoint, pointAt } from '../../simulation/track/trackModel.js';
|
|
3
3
|
import { FINISH_LINE_COLUMNS, FINISH_LINE_DEPTH } from './trackRenderConstants.js';
|
|
4
4
|
|
|
5
5
|
export function addFinishLine(asset, track) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Graphics } from 'pixi.js';
|
|
2
|
-
import { offsetTrackPoint, pointAt } from '../../simulation/trackModel.js';
|
|
2
|
+
import { offsetTrackPoint, pointAt } from '../../simulation/track/trackModel.js';
|
|
3
3
|
import { START_GRID_BOX_LENGTH, START_GRID_BOX_WIDTH, START_GRID_FIRST_DISTANCE, START_GRID_LATERAL_OFFSET, START_GRID_SLOT_COUNT, START_GRID_SLOT_SPACING } from './trackRenderConstants.js';
|
|
4
4
|
|
|
5
5
|
export function addStartingGrid(asset, track) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { nearestTrackState, offsetTrackPoint } from '../../simulation/trackModel.js';
|
|
1
|
+
import { nearestTrackState, offsetTrackPoint } from '../../simulation/track/trackModel.js';
|
|
2
2
|
import { queryNearbyTrackProjections } from '../../simulation/track/trackQueryIndex.js';
|
|
3
3
|
import { metersToSimUnits } from '../../simulation/units.js';
|
|
4
|
-
import { NON_LOCAL_SAMPLE_STEP, OFFSET_GAP_SAMPLE_COUNT, OFFSET_SEGMENT_SAMPLE_COUNT } from './trackRenderConstants.js';
|
|
4
|
+
import { NON_LOCAL_SAMPLE_STEP, OFFSET_GAP_SAMPLE_COUNT, OFFSET_SEGMENT_SAMPLE_COUNT, SEGMENTED_STROKE_STEP } from './trackRenderConstants.js';
|
|
5
5
|
import { arcDistance, interpolatedSegmentPoint, pointDistance } from './trackRenderGeometry.js';
|
|
6
6
|
|
|
7
7
|
export function offsetPointIsLocal(track, source, point, offset) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Graphics } from 'pixi.js';
|
|
2
|
-
import { nearestTrackState } from '../../simulation/trackModel.js';
|
|
2
|
+
import { nearestTrackState } from '../../simulation/track/trackModel.js';
|
|
3
3
|
import { ASPHALT_COLOR, GRAVEL_COLOR, PIT_ASPHALT_COLOR, PIT_BOX_COLOR, PIT_CONNECTOR_WIDTH, PIT_LINE_COLOR, PIT_SPEED_LINE_COLOR } from './trackRenderConstants.js';
|
|
4
4
|
import { colorToNumber, createTeamPitGroupCorners, drawPolyline, offsetVectorPoint } from './trackRenderGeometry.js';
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Graphics, TilingSprite } from 'pixi.js';
|
|
2
|
-
import { offsetTrackPoint } from '../../simulation/trackModel.js';
|
|
2
|
+
import { offsetTrackPoint } from '../../simulation/track/trackModel.js';
|
|
3
3
|
import { ASPHALT_COLOR, BARRIER_WALL_WIDTH, EDGE_REVEAL_OFFSET, EDGE_REVEAL_WIDTH, GRASS_COLOR, GRAVEL_COLOR, KERB_CURVATURE_THRESHOLD, KERB_OFFSET, KERB_STEP, KERB_WIDTH, MATERIAL_TILE_SCALE, OUTER_BOUNDARY_OFFSET, OUTER_BOUNDARY_WIDTH, RUNOFF_GRASS_COLOR, SEGMENTED_STROKE_STEP, WORLD_BACKGROUND_PADDING_MULTIPLIER } from './trackRenderConstants.js';
|
|
4
4
|
import { makeTrackPath, textureOrWhite } from './trackRenderGeometry.js';
|
|
5
5
|
import { getOffsetGapBridges, getOffsetStrokeSegments, offsetSegmentIsSafe } from './offsetStrokeSafety.js';
|
|
@@ -149,7 +149,7 @@ export function addBoundaryUnderlay(asset, track) {
|
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
drawKerbStripes(
|
|
152
|
+
drawKerbStripes(boundary, track, { clipUnsafeSegments: false });
|
|
153
153
|
|
|
154
154
|
[-1, 1].forEach((side) => {
|
|
155
155
|
drawContinuousOffsetStroke(boundary, track, {
|
|
@@ -214,7 +214,7 @@ export function getTrackMaterialBands(track) {
|
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
export function drawKerbStripes(
|
|
217
|
+
export function drawKerbStripes(kerbs, track, { clipUnsafeSegments }) {
|
|
218
218
|
const samples = track.samples.slice(0, -1);
|
|
219
219
|
|
|
220
220
|
for (let index = 0; index < samples.length; index += KERB_STEP) {
|
|
@@ -320,7 +320,7 @@ export function addBorders(asset, track) {
|
|
|
320
320
|
export function addKerbs(asset, track) {
|
|
321
321
|
const kerbs = new Graphics();
|
|
322
322
|
kerbs.label = 'track-kerbs';
|
|
323
|
-
drawKerbStripes(
|
|
323
|
+
drawKerbStripes(kerbs, track, { clipUnsafeSegments: true });
|
|
324
324
|
asset.container.addChild(kerbs);
|
|
325
325
|
|
|
326
326
|
}
|
|
@@ -14,7 +14,6 @@ export const PIT_BOX_COLOR = 0x242831;
|
|
|
14
14
|
export const PIT_LINE_COLOR = 0xf8fafc;
|
|
15
15
|
export const PIT_SPEED_LINE_COLOR = 0xffd166;
|
|
16
16
|
export const PIT_CONNECTOR_WIDTH = metersToSimUnits(12);
|
|
17
|
-
export const PIT_EDGE_WIDTH = metersToSimUnits(0.35);
|
|
18
17
|
export const EDGE_REVEAL_OFFSET = metersToSimUnits(0.35);
|
|
19
18
|
export const EDGE_REVEAL_WIDTH = metersToSimUnits(0.5);
|
|
20
19
|
export const OUTER_BOUNDARY_OFFSET = metersToSimUnits(1.1);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Graphics, Texture } from 'pixi.js';
|
|
2
|
-
import { offsetTrackPoint } from '../../simulation/trackModel.js';
|
|
2
|
+
import { offsetTrackPoint } from '../../simulation/track/trackModel.js';
|
|
3
3
|
import { PIT_LINE_COLOR } from './trackRenderConstants.js';
|
|
4
4
|
|
|
5
5
|
export function colorToNumber(color, fallback = PIT_LINE_COLOR) {
|
|
@@ -29,12 +29,6 @@ export function textureOrWhite(texture) {
|
|
|
29
29
|
return texture ?? Texture.WHITE;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function destroyDisplayChildren(container) {
|
|
33
|
-
container.removeChildren().forEach((child) => {
|
|
34
|
-
child.destroy?.({ children: true, texture: false, textureSource: false });
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
32
|
export function arcDistance(track, first, second) {
|
|
39
33
|
const delta = Math.abs(first - second);
|
|
40
34
|
return Math.min(delta, track.length - delta);
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getVehicleGeometryState,
|
|
3
|
-
vehicleAxes,
|
|
4
|
-
} from './vehicle/vehicleGeometry.js';
|
|
1
|
+
import { getVehicleGeometryState } from './vehicle/vehicleGeometry.js';
|
|
5
2
|
import { normalizeAngle } from './simMath.js';
|
|
6
3
|
|
|
7
4
|
const DEFAULT_SWEEP_STEPS = 16;
|
|
@@ -10,10 +7,6 @@ const DEFAULT_DISTANCE_WINDOW = 150;
|
|
|
10
7
|
const COLLISION_PAIR_FIRST_INDEX = Symbol('collisionPairFirstIndex');
|
|
11
8
|
const COLLISION_PAIR_SECOND_INDEX = Symbol('collisionPairSecondIndex');
|
|
12
9
|
|
|
13
|
-
function dot(a, b) {
|
|
14
|
-
return a.x * b.x + a.y * b.y;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
10
|
function projectShapeInto(target, shape, axis) {
|
|
18
11
|
let min = Infinity;
|
|
19
12
|
let max = -Infinity;
|
|
@@ -91,10 +84,6 @@ function aabbsOverlap(first, second) {
|
|
|
91
84
|
);
|
|
92
85
|
}
|
|
93
86
|
|
|
94
|
-
function createSweptAabb(car) {
|
|
95
|
-
return getVehicleGeometryState(car).sweptBodyAabb;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
87
|
function writeShapeCollisionResult(target, firstShape, secondShape, axisX, axisY, depth) {
|
|
99
88
|
target.axis ??= {};
|
|
100
89
|
target.axis.x = axisX;
|
|
@@ -123,10 +112,12 @@ function withCollisionMetadata(collision, timeOfImpact, swept, scratch) {
|
|
|
123
112
|
function detectVehicleCollisionWithScratch(first, second, sweepSteps, scratch) {
|
|
124
113
|
const firstState = getVehicleGeometryState(first);
|
|
125
114
|
const secondState = getVehicleGeometryState(second);
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
if (aabbsOverlap(firstState.bodyAabb, secondState.bodyAabb)) {
|
|
116
|
+
const current = detectShapeCollision(firstState.current.body, secondState.current.body, scratch);
|
|
117
|
+
if (current) return withCollisionMetadata(current, 1, false, scratch);
|
|
118
|
+
}
|
|
128
119
|
|
|
129
|
-
if (!aabbsOverlap(
|
|
120
|
+
if (!aabbsOverlap(firstState.sweptBodyAabb, secondState.sweptBodyAabb)) return null;
|
|
130
121
|
|
|
131
122
|
const sweepShapes = ensureSweepShapes(scratch, firstState.current.body, secondState.current.body);
|
|
132
123
|
for (let step = 1; step < sweepSteps; step += 1) {
|
|
@@ -340,17 +331,18 @@ function writeInterpolatedBodyShape(target, geometryState, amount) {
|
|
|
340
331
|
const x = pose.previousX + (pose.x - pose.previousX) * amount;
|
|
341
332
|
const y = pose.previousY + (pose.y - pose.previousY) * amount;
|
|
342
333
|
const heading = normalizeAngle(pose.previousHeading + headingDelta * amount);
|
|
343
|
-
const
|
|
334
|
+
const cos = Math.cos(heading);
|
|
335
|
+
const sin = Math.sin(heading);
|
|
344
336
|
const halfLength = target.halfLength;
|
|
345
337
|
const halfWidth = target.halfWidth;
|
|
346
338
|
|
|
347
339
|
target.center.x = x;
|
|
348
340
|
target.center.y = y;
|
|
349
341
|
target.heading = heading;
|
|
350
|
-
target.forward.x =
|
|
351
|
-
target.forward.y =
|
|
352
|
-
target.right.x =
|
|
353
|
-
target.right.y =
|
|
342
|
+
target.forward.x = cos;
|
|
343
|
+
target.forward.y = sin;
|
|
344
|
+
target.right.x = -sin;
|
|
345
|
+
target.right.y = cos;
|
|
354
346
|
|
|
355
347
|
writeOffsetCorner(target.corners[0], target.center, target.forward, target.right, halfLength, halfWidth);
|
|
356
348
|
writeOffsetCorner(target.corners[1], target.center, target.forward, target.right, halfLength, -halfWidth);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { clamp, normalizeAngle } from '../simMath.js';
|
|
2
|
+
import { simUnitsToMeters } from '../units.js';
|
|
3
|
+
import { VEHICLE_LIMITS, tirePerformanceFactor } from '../vehicle/vehiclePhysics.js';
|
|
4
|
+
import { ADVANCED_VEHICLE_MODEL, advancedDriveForce } from '../vehicle/advancedVehicleModel.js';
|
|
5
|
+
import { advancedLateralAccelerationLimit, advancedRearForceCapacity, advancedRollingResistanceForce } from '../vehicle/advancedTireForces.js';
|
|
6
|
+
|
|
7
|
+
export function advancedSteeringToPoint(car, target) {
|
|
8
|
+
const speed = simUnitsToMeters(car.speed);
|
|
9
|
+
const dx = simUnitsToMeters(target.x - car.x);
|
|
10
|
+
const dy = simUnitsToMeters(target.y - car.y);
|
|
11
|
+
const angle = normalizeAngle(Math.atan2(dy, dx) - car.heading);
|
|
12
|
+
// Pure pursuit gives a geometric curvature in 1/m, then a physical wheel
|
|
13
|
+
// angle. Yaw feedback damps the inertial response without moving the car.
|
|
14
|
+
const curvature = 2 * Math.sin(angle) / Math.max(Math.hypot(dx, dy), 1);
|
|
15
|
+
const desiredYaw = speed * curvature;
|
|
16
|
+
const slip = car.slipAngleRadians ?? 0;
|
|
17
|
+
const countersteer = Math.sign(slip) * Math.max(0, Math.abs(slip) - 0.08) * 0.35;
|
|
18
|
+
return {
|
|
19
|
+
curvature,
|
|
20
|
+
steering: Math.atan(simUnitsToMeters(VEHICLE_LIMITS.wheelbase) * curvature) +
|
|
21
|
+
(desiredYaw - (car.yawRate ?? 0)) * 0.04 + countersteer,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function advancedLongitudinalLimits(car) {
|
|
26
|
+
const speed = simUnitsToMeters(car.speed);
|
|
27
|
+
const tireFactor = tirePerformanceFactor(car.tireEnergy ?? 100);
|
|
28
|
+
const capacity = advancedLateralAccelerationLimit(car, speed, tireFactor);
|
|
29
|
+
const lateralUsage = clamp(Math.abs(speed * (car.yawRate ?? 0)) / capacity, 0, 0.95);
|
|
30
|
+
// Static axle capacity is an estimate: keep a margin for load transfer and
|
|
31
|
+
// reserve the lateral share before requesting rear drive or brake force.
|
|
32
|
+
const longitudinalFraction = Math.sqrt(1 - lateralUsage ** 2) * 0.65;
|
|
33
|
+
const force = capacity * car.mass * longitudinalFraction;
|
|
34
|
+
let driveForce = force * (1 - ADVANCED_VEHICLE_MODEL.frontWeightFraction);
|
|
35
|
+
if (speed < 5 && !car.trackState.onTrack) {
|
|
36
|
+
// A crawling car must overcome all four wheels' rolling resistance. Use
|
|
37
|
+
// the rear tires' remaining adhesion, not an artificial minimum throttle.
|
|
38
|
+
const rearCapacity = advancedRearForceCapacity(car, speed, tireFactor) * Math.sqrt(1 - lateralUsage ** 2);
|
|
39
|
+
const rollingCompensation = advancedRollingResistanceForce(car, speed) * (1 - speed / 5);
|
|
40
|
+
driveForce = Math.min(rearCapacity, driveForce + rollingCompensation);
|
|
41
|
+
}
|
|
42
|
+
const throttleLimit = driveForce / advancedDriveForce(car, speed);
|
|
43
|
+
const brakeLimit = force / car.brakeNewtons;
|
|
44
|
+
return { speed, throttleLimit, brakeLimit };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function advancedSpeedControls(car, targetSpeed) {
|
|
48
|
+
const { speed, throttleLimit, brakeLimit } = advancedLongitudinalLimits(car);
|
|
49
|
+
const error = targetSpeed - speed;
|
|
50
|
+
const brake = clamp(-error / 8, 0, Math.min(0.85, brakeLimit));
|
|
51
|
+
const throttle = brake > 0.03 ? 0 : clamp(error / 8, 0, Math.min(1, throttleLimit));
|
|
52
|
+
return { throttle, brake };
|
|
53
|
+
}
|