@inventure71/paddockjs 4.2.0 → 4.3.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.
- package/CHANGELOG.md +40 -0
- package/INSTALL_AND_UPDATE.md +24 -4
- package/README.md +31 -2
- package/docs/advanced_ai_pace.md +131 -0
- package/docs/advanced_physics_rebuild.md +166 -0
- package/docs/architecture.md +109 -30
- package/docs/cleanup_coverage.md +284 -0
- package/docs/component_inventory.md +31 -15
- 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/grid_walk.md +84 -0
- package/docs/index.md +1 -0
- package/docs/keyboard_driving_fix.md +118 -0
- package/docs/limit_driving_2026-10-14.md +88 -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 +38 -11
- package/docs/testing-reliability-guide.md +5 -0
- package/docs/v11_improvements.md +108 -0
- package/package.json +24 -13
- 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 +106 -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 +13 -259
- 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 +21 -140
- 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 +34 -259
- 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 +5 -11
- 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 +14 -3
- package/src/simulation/driver/edgeRecovery.js +0 -1
- package/src/simulation/driver/racingControls.js +10 -406
- package/src/simulation/driver/racingDriverProfile.js +48 -0
- package/src/simulation/driver/racingLinePlan.js +48 -15
- package/src/simulation/driver/rejoinControls.js +58 -111
- package/src/simulation/driver/safetyCarControls.js +12 -0
- package/src/simulation/driver/trafficScan.js +89 -6
- 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 +1 -1
- package/src/simulation/race/redFlag.js +2 -4
- package/src/simulation/race/safetyCar.js +3 -8
- 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/rulesReview.js +1 -7
- 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 +3 -3
- 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 +1 -25
- 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 +4 -241
- 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 +20 -6
- 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 +0 -56
- package/src/simulation/vehicle/vehicleKinematics.js +10 -0
- package/src/simulation/vehicle/vehiclePhysics.js +35 -194
- package/src/simulation/vehicle/vehicleSnapshots.js +13 -4
- package/src/simulation/vehicle/vehicleState.js +2 -1
- 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/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/src/index.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
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,
|
|
@@ -13,6 +19,11 @@ import type {
|
|
|
13
19
|
PaddockReplayGhostSnapshot as EnvPaddockReplayGhostSnapshot,
|
|
14
20
|
PaddockReplayGhostTrajectorySample as EnvPaddockReplayGhostTrajectorySample,
|
|
15
21
|
} from './environment/index.js';
|
|
22
|
+
import type {
|
|
23
|
+
PaddockPitCrewStats,
|
|
24
|
+
PaddockThemeSelector,
|
|
25
|
+
TeamData,
|
|
26
|
+
} from './data/teamTypes.js';
|
|
16
27
|
|
|
17
28
|
export type {
|
|
18
29
|
PaddockActionSpec,
|
|
@@ -25,11 +36,14 @@ export type {
|
|
|
25
36
|
PaddockEnvironmentSnapshotResult,
|
|
26
37
|
PaddockObservationSpec,
|
|
27
38
|
} from './environment/index.js';
|
|
39
|
+
export type {
|
|
40
|
+
PaddockPitCrewStats,
|
|
41
|
+
PaddockThemeSelector,
|
|
42
|
+
TeamData,
|
|
43
|
+
} from './data/teamTypes.js';
|
|
28
44
|
|
|
29
|
-
export type TireCompound = 'S' | 'M' | 'H';
|
|
30
45
|
export type PaddockPhysicsMode = 'arcade' | 'advanced';
|
|
31
46
|
export type PaddockWarmupPolicy = 'config-change' | 'always' | 'never';
|
|
32
|
-
export type PaddockProceduralTrackProfile = 'race' | 'training-short' | 'training-medium' | 'training-technical';
|
|
33
47
|
|
|
34
48
|
export interface PaddockWarmupOptions {
|
|
35
49
|
enabled?: boolean;
|
|
@@ -37,106 +51,6 @@ export interface PaddockWarmupOptions {
|
|
|
37
51
|
steps?: number;
|
|
38
52
|
}
|
|
39
53
|
|
|
40
|
-
export interface PaddockProceduralTrackOptions {
|
|
41
|
-
profile?: PaddockProceduralTrackProfile;
|
|
42
|
-
minLengthMeters?: number;
|
|
43
|
-
maxLengthMeters?: number;
|
|
44
|
-
startStraightMeters?: number;
|
|
45
|
-
includePitLane?: boolean;
|
|
46
|
-
length?: {
|
|
47
|
-
minMeters?: number;
|
|
48
|
-
maxMeters?: number;
|
|
49
|
-
};
|
|
50
|
-
startStraight?: {
|
|
51
|
-
gridMeters?: number;
|
|
52
|
-
exitMeters?: number;
|
|
53
|
-
blendMeters?: number;
|
|
54
|
-
lockExtraMeters?: number;
|
|
55
|
-
};
|
|
56
|
-
pitLane?: {
|
|
57
|
-
enabled?: boolean;
|
|
58
|
-
};
|
|
59
|
-
shape?: {
|
|
60
|
-
scale?: number;
|
|
61
|
-
cornerDensity?: number;
|
|
62
|
-
variation?: number;
|
|
63
|
-
};
|
|
64
|
-
validation?: {
|
|
65
|
-
minClearanceMultiplier?: number;
|
|
66
|
-
minShapeVariation?: number;
|
|
67
|
-
minNonAdjacentArcMeters?: number;
|
|
68
|
-
maxLocalTurnRadians?: number;
|
|
69
|
-
maxSampleHeadingDeltaRadians?: number;
|
|
70
|
-
};
|
|
71
|
-
attempts?: {
|
|
72
|
-
primary?: number;
|
|
73
|
-
fallback?: number;
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface PaddockTrackPoint {
|
|
78
|
-
x: number;
|
|
79
|
-
y: number;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export interface PaddockDrsZone {
|
|
83
|
-
id: string;
|
|
84
|
-
startRatio: number;
|
|
85
|
-
endRatio: number;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface PaddockResolvedProceduralTrackOptions {
|
|
89
|
-
profile: PaddockProceduralTrackProfile;
|
|
90
|
-
length: {
|
|
91
|
-
min: number;
|
|
92
|
-
max: number;
|
|
93
|
-
};
|
|
94
|
-
startStraight: {
|
|
95
|
-
grid: number;
|
|
96
|
-
exit: number;
|
|
97
|
-
blend: number;
|
|
98
|
-
lockExtra: number;
|
|
99
|
-
};
|
|
100
|
-
pitLane: {
|
|
101
|
-
enabled: boolean;
|
|
102
|
-
};
|
|
103
|
-
shape: {
|
|
104
|
-
scale: number;
|
|
105
|
-
cornerDensity: number;
|
|
106
|
-
variation: number;
|
|
107
|
-
};
|
|
108
|
-
validation: {
|
|
109
|
-
minClearanceMultiplier: number;
|
|
110
|
-
minShapeVariation: number;
|
|
111
|
-
minNonAdjacentArcDistance: number;
|
|
112
|
-
maxLocalTurnRadians: number;
|
|
113
|
-
maxSampleHeadingDeltaRadians: number;
|
|
114
|
-
};
|
|
115
|
-
attempts: {
|
|
116
|
-
primary: number;
|
|
117
|
-
fallback: number;
|
|
118
|
-
};
|
|
119
|
-
cacheKey: string;
|
|
120
|
-
[key: string]: unknown;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export interface PaddockProceduralTrack {
|
|
124
|
-
name: string;
|
|
125
|
-
width: number;
|
|
126
|
-
kerbWidth: number;
|
|
127
|
-
gravelWidth: number;
|
|
128
|
-
runoffWidth: number;
|
|
129
|
-
barrierWidth: number;
|
|
130
|
-
sampleCount: number;
|
|
131
|
-
seed?: number;
|
|
132
|
-
curveInterpolation?: string;
|
|
133
|
-
centerlineControls?: readonly PaddockTrackPoint[];
|
|
134
|
-
drsZones?: readonly PaddockDrsZone[] | null;
|
|
135
|
-
pitLane?: { enabled?: boolean } | null;
|
|
136
|
-
generationOptions?: PaddockResolvedProceduralTrackOptions;
|
|
137
|
-
[key: string]: unknown;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
54
|
export type PaddockStabilityState = 'stable' | 'understeer' | 'oversteer' | 'spin-risk' | 'destroyed';
|
|
141
55
|
export type PaddockPitIntent = 0 | 1 | 2;
|
|
142
56
|
export type PaddockPitIntentRequest = PaddockPitIntent | {
|
|
@@ -156,6 +70,7 @@ export type TimingTowerVerticalFit = 'expand-race-view' | 'scroll';
|
|
|
156
70
|
export type TimingGapMode = 'interval' | 'leader';
|
|
157
71
|
export type LayoutPreset = 'standard' | 'left-tower-overlay';
|
|
158
72
|
export type CameraControlsMode = 'embedded' | 'external' | false;
|
|
73
|
+
export type ViewControlsMode = 'switch' | 'toggle';
|
|
159
74
|
export type PaddockPresetName = 'dashboard' | 'timing-overlay' | 'compact-race' | 'full-dashboard';
|
|
160
75
|
export type TelemetryModuleName = 'core' | 'sectors' | 'lapTimes' | 'sectorTimes';
|
|
161
76
|
export type SectorPerformanceStatus = 'overall-best' | 'personal-best' | 'slower';
|
|
@@ -167,164 +82,7 @@ export type PaddockReplayGhostTrajectorySample = EnvPaddockReplayGhostTrajectory
|
|
|
167
82
|
export type PaddockReplayGhostOptions = EnvPaddockReplayGhostOptions;
|
|
168
83
|
export type PaddockReplayGhostSnapshot = EnvPaddockReplayGhostSnapshot;
|
|
169
84
|
|
|
170
|
-
export interface CustomField {
|
|
171
|
-
label: string;
|
|
172
|
-
value: string;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export type CustomFieldInput = CustomField[] | Record<string, string>;
|
|
176
|
-
|
|
177
|
-
export interface TeamData {
|
|
178
|
-
id?: string;
|
|
179
|
-
name?: string;
|
|
180
|
-
color?: string;
|
|
181
|
-
icon?: string;
|
|
182
|
-
theme?: PaddockThemeSelector;
|
|
183
|
-
pitCrew?: PaddockPitCrewStats;
|
|
184
|
-
pitCrewStats?: PaddockPitCrewStats;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export interface PaddockPitCrewStats {
|
|
188
|
-
speed?: number;
|
|
189
|
-
consistency?: number;
|
|
190
|
-
reliability?: number;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export interface SimulatorDriver {
|
|
194
|
-
id: string;
|
|
195
|
-
name: string;
|
|
196
|
-
color: string;
|
|
197
|
-
link?: string;
|
|
198
|
-
icon?: string;
|
|
199
|
-
code?: string;
|
|
200
|
-
timingName?: string;
|
|
201
|
-
tire?: TireCompound;
|
|
202
|
-
raceData?: string[];
|
|
203
|
-
customFields?: CustomFieldInput;
|
|
204
|
-
team?: TeamData | null;
|
|
205
|
-
driverNumber?: number;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export interface DriverRatings {
|
|
209
|
-
pace: number;
|
|
210
|
-
racecraft: number;
|
|
211
|
-
aggression: number;
|
|
212
|
-
riskTolerance: number;
|
|
213
|
-
patience: number;
|
|
214
|
-
consistency: number;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export interface VehicleRatings {
|
|
218
|
-
power: number;
|
|
219
|
-
braking: number;
|
|
220
|
-
aero: number;
|
|
221
|
-
dragEfficiency: number;
|
|
222
|
-
mechanicalGrip: number;
|
|
223
|
-
weightControl: number;
|
|
224
|
-
tireCare: number;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export interface DriverBlueprint extends Partial<DriverRatings> {
|
|
228
|
-
customFields?: CustomFieldInput;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export interface VehicleBlueprint extends Partial<VehicleRatings> {
|
|
232
|
-
id?: string | null;
|
|
233
|
-
name?: string | null;
|
|
234
|
-
customFields?: CustomFieldInput;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export interface DriverConstructorArgs {
|
|
238
|
-
ratings: DriverRatings;
|
|
239
|
-
customFields: CustomField[];
|
|
240
|
-
pace: number;
|
|
241
|
-
racecraft: number;
|
|
242
|
-
consistency: number;
|
|
243
|
-
personality: {
|
|
244
|
-
aggression: number;
|
|
245
|
-
riskTolerance: number;
|
|
246
|
-
patience: number;
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export interface VehicleConstructorArgs {
|
|
251
|
-
id: string | null;
|
|
252
|
-
name: string | null;
|
|
253
|
-
ratings: VehicleRatings;
|
|
254
|
-
customFields: CustomField[];
|
|
255
|
-
powerNewtons: number;
|
|
256
|
-
brakeNewtons: number;
|
|
257
|
-
downforceCoefficient: number;
|
|
258
|
-
dragCoefficient: number;
|
|
259
|
-
tireGrip: number;
|
|
260
|
-
mass: number;
|
|
261
|
-
tireCare: number;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export class DriverData {
|
|
265
|
-
constructor(input?: DriverBlueprint);
|
|
266
|
-
readonly pace: number;
|
|
267
|
-
readonly racecraft: number;
|
|
268
|
-
readonly aggression: number;
|
|
269
|
-
readonly riskTolerance: number;
|
|
270
|
-
readonly patience: number;
|
|
271
|
-
readonly consistency: number;
|
|
272
|
-
readonly customFields: CustomField[];
|
|
273
|
-
ratings(): DriverRatings;
|
|
274
|
-
toConstructorArgs(): DriverConstructorArgs;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export class VehicleData {
|
|
278
|
-
constructor(input?: VehicleBlueprint);
|
|
279
|
-
readonly id: string | null;
|
|
280
|
-
readonly name: string | null;
|
|
281
|
-
readonly power: number;
|
|
282
|
-
readonly braking: number;
|
|
283
|
-
readonly aero: number;
|
|
284
|
-
readonly dragEfficiency: number;
|
|
285
|
-
readonly mechanicalGrip: number;
|
|
286
|
-
readonly weightControl: number;
|
|
287
|
-
readonly tireCare: number;
|
|
288
|
-
readonly customFields: CustomField[];
|
|
289
|
-
ratings(): VehicleRatings;
|
|
290
|
-
toConstructorArgs(): VehicleConstructorArgs;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
export interface ChampionshipEntryBlueprint {
|
|
294
|
-
driverId: string;
|
|
295
|
-
driverNumber?: number;
|
|
296
|
-
timingName?: string;
|
|
297
|
-
driver?: DriverData | DriverBlueprint;
|
|
298
|
-
vehicle?: VehicleData | VehicleBlueprint;
|
|
299
|
-
team?: TeamData;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
export interface NormalizedSimulatorDriver extends SimulatorDriver {
|
|
303
|
-
code: string;
|
|
304
|
-
timingCode: string;
|
|
305
|
-
raceName: string;
|
|
306
|
-
driverNumber: number;
|
|
307
|
-
team: TeamData | null;
|
|
308
|
-
pace: number;
|
|
309
|
-
racecraft: number;
|
|
310
|
-
consistency: number;
|
|
311
|
-
personality: DriverConstructorArgs['personality'];
|
|
312
|
-
vehicle: VehicleConstructorArgs;
|
|
313
|
-
constructorArgs: {
|
|
314
|
-
driver: DriverConstructorArgs;
|
|
315
|
-
vehicle: VehicleConstructorArgs;
|
|
316
|
-
};
|
|
317
|
-
championship: {
|
|
318
|
-
id: string;
|
|
319
|
-
name: string;
|
|
320
|
-
season: number;
|
|
321
|
-
entryIndex: number;
|
|
322
|
-
vehicleId: string | null;
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
|
|
326
85
|
export type PaddockThemeMode = 'dark' | 'light' | 'system';
|
|
327
|
-
export type PaddockThemeSelector = 'default' | 'active' | 'selectedTeam' | 'team' | `team:${string}` | string;
|
|
328
86
|
export type PaddockThemeTokenValue = string | { light?: string; dark?: string };
|
|
329
87
|
export type PaddockThemeTokenName =
|
|
330
88
|
| 'primary'
|
|
@@ -432,6 +190,8 @@ export interface PaddockThemeSyncOptions {
|
|
|
432
190
|
export interface F1SimulatorUiOptions {
|
|
433
191
|
layoutPreset?: LayoutPreset;
|
|
434
192
|
cameraControls?: CameraControlsMode;
|
|
193
|
+
/** Two mode buttons by default; toggle uses one Start race / Stop race action. */
|
|
194
|
+
viewControls?: ViewControlsMode;
|
|
435
195
|
showFps?: boolean;
|
|
436
196
|
showTimingTower?: boolean;
|
|
437
197
|
showTelemetry?: boolean;
|
|
@@ -1041,7 +801,16 @@ export interface F1SimulatorExpertApi {
|
|
|
1041
801
|
destroy(): void;
|
|
1042
802
|
}
|
|
1043
803
|
|
|
804
|
+
export type PaddockView = 'grid-walk' | 'race';
|
|
805
|
+
|
|
806
|
+
export interface GridWalkOptions {
|
|
807
|
+
enabled?: boolean;
|
|
808
|
+
initialView?: PaddockView;
|
|
809
|
+
ambientMotion?: boolean;
|
|
810
|
+
}
|
|
811
|
+
|
|
1044
812
|
export interface F1SimulatorOptions extends F1SimulatorCallbacks {
|
|
813
|
+
gridWalk?: GridWalkOptions;
|
|
1045
814
|
preset?: PaddockPresetName;
|
|
1046
815
|
drivers: SimulatorDriver[];
|
|
1047
816
|
entries?: ChampionshipEntryBlueprint[];
|
|
@@ -1097,6 +866,8 @@ export interface F1MountedSimulator {
|
|
|
1097
866
|
getTheme(): ResolvedPaddockTheme;
|
|
1098
867
|
syncThemeFrom(source: Element, options?: PaddockThemeSyncOptions): () => void;
|
|
1099
868
|
selectDriver(driverId: string): void;
|
|
869
|
+
setView(view: PaddockView): boolean;
|
|
870
|
+
getView(): PaddockView;
|
|
1100
871
|
setSafetyCarDeployed(deployed: boolean): void;
|
|
1101
872
|
setRedFlagDeployed(deployed: boolean): void;
|
|
1102
873
|
setPitLaneOpen(open: boolean): void;
|
|
@@ -1119,6 +890,7 @@ export interface PaddockSimulatorController {
|
|
|
1119
890
|
readonly expert: F1SimulatorExpertApi | null;
|
|
1120
891
|
mountRaceControls<T extends Element>(root: T): T;
|
|
1121
892
|
mountCameraControls<T extends Element>(root: T): T;
|
|
893
|
+
mountViewControls<T extends Element>(root: T): T;
|
|
1122
894
|
mountSafetyCarControl<T extends Element>(root: T): T;
|
|
1123
895
|
mountTimingTower<T extends Element>(root: T): T;
|
|
1124
896
|
mountRaceCanvas<T extends Element>(root: T, options?: MountRaceCanvasOptions): T;
|
|
@@ -1141,6 +913,8 @@ export interface PaddockSimulatorController {
|
|
|
1141
913
|
getTheme(): ResolvedPaddockTheme;
|
|
1142
914
|
syncThemeFrom(source: Element, options?: PaddockThemeSyncOptions): () => void;
|
|
1143
915
|
selectDriver(driverId: string): void;
|
|
916
|
+
setView(view: PaddockView): boolean;
|
|
917
|
+
getView(): PaddockView;
|
|
1144
918
|
setSafetyCarDeployed(deployed: boolean): void;
|
|
1145
919
|
setRedFlagDeployed(deployed: boolean): void;
|
|
1146
920
|
setPitLaneOpen(open: boolean): void;
|
|
@@ -1204,6 +978,7 @@ export function createPaddockDriverControllerLoop(options: PaddockDriverControll
|
|
|
1204
978
|
|
|
1205
979
|
export function mountRaceControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1206
980
|
export function mountCameraControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
981
|
+
export function mountViewControls<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1207
982
|
export function mountSafetyCarControl<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1208
983
|
export function mountTimingTower<T extends Element>(root: T, simulator: PaddockSimulatorController): T;
|
|
1209
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);
|
|
@@ -7,10 +7,6 @@ const DEFAULT_DISTANCE_WINDOW = 150;
|
|
|
7
7
|
const COLLISION_PAIR_FIRST_INDEX = Symbol('collisionPairFirstIndex');
|
|
8
8
|
const COLLISION_PAIR_SECOND_INDEX = Symbol('collisionPairSecondIndex');
|
|
9
9
|
|
|
10
|
-
function dot(a, b) {
|
|
11
|
-
return a.x * b.x + a.y * b.y;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
10
|
function projectShapeInto(target, shape, axis) {
|
|
15
11
|
let min = Infinity;
|
|
16
12
|
let max = -Infinity;
|
|
@@ -88,10 +84,6 @@ function aabbsOverlap(first, second) {
|
|
|
88
84
|
);
|
|
89
85
|
}
|
|
90
86
|
|
|
91
|
-
function createSweptAabb(car) {
|
|
92
|
-
return getVehicleGeometryState(car).sweptBodyAabb;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
87
|
function writeShapeCollisionResult(target, firstShape, secondShape, axisX, axisY, depth) {
|
|
96
88
|
target.axis ??= {};
|
|
97
89
|
target.axis.x = axisX;
|
|
@@ -120,10 +112,12 @@ function withCollisionMetadata(collision, timeOfImpact, swept, scratch) {
|
|
|
120
112
|
function detectVehicleCollisionWithScratch(first, second, sweepSteps, scratch) {
|
|
121
113
|
const firstState = getVehicleGeometryState(first);
|
|
122
114
|
const secondState = getVehicleGeometryState(second);
|
|
123
|
-
|
|
124
|
-
|
|
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
|
+
}
|
|
125
119
|
|
|
126
|
-
if (!aabbsOverlap(
|
|
120
|
+
if (!aabbsOverlap(firstState.sweptBodyAabb, secondState.sweptBodyAabb)) return null;
|
|
127
121
|
|
|
128
122
|
const sweepShapes = ensureSweepShapes(scratch, firstState.current.body, secondState.current.body);
|
|
129
123
|
for (let step = 1; step < sweepSteps; step += 1) {
|
|
@@ -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
|
+
}
|