1
0

California gets roads, traffic, and a car to follow

This commit is contained in:
2026-08-11 18:24:53 -07:00
parent 9c9e78f6f9
commit fe58290728
43 changed files with 5593 additions and 68 deletions
+81
View File
@@ -0,0 +1,81 @@
/** Device adapters for the renderer-independent vehicle action contract. */
import {
normalizeVehicleActions,
type VehicleActionSnapshot,
} from "../transport/vehicleController.ts";
export interface GamepadButtonLike {
pressed: boolean;
value: number;
}
export interface GamepadLike {
axes: readonly number[];
buttons: readonly GamepadButtonLike[];
}
export interface GamepadButtonState {
assist: boolean;
reset: boolean;
}
export interface GamepadVehicleSample {
actions: VehicleActionSnapshot;
buttons: GamepadButtonState;
}
function axis(value: number | undefined, deadzone = 0.12): number {
if (!Number.isFinite(value)) return 0;
const clamped = Math.max(-1, Math.min(1, value ?? 0));
if (Math.abs(clamped) <= deadzone) return 0;
return Math.sign(clamped) * ((Math.abs(clamped) - deadzone) / (1 - deadzone));
}
function button(pad: GamepadLike, index: number): number {
const found = pad.buttons[index];
if (!found) return 0;
return Math.max(0, Math.min(1, Number.isFinite(found.value) ? found.value : found.pressed ? 1 : 0));
}
/**
* Standard-layout mapping: left stick steers, triggers brake/throttle, B is
* handbrake, Y resumes assistance, and X resets. Mode/reset are rising edges.
*/
export function sampleStandardGamepad(
pad: GamepadLike,
previous: GamepadButtonState = { assist: false, reset: false },
): GamepadVehicleSample {
const buttons = {
assist: button(pad, 3) > 0.5,
reset: button(pad, 2) > 0.5,
};
return {
actions: normalizeVehicleActions({
steering: axis(pad.axes[0]),
brake: button(pad, 6),
throttle: button(pad, 7),
handbrake: button(pad, 1) > 0.5,
modeRequest: buttons.assist && !previous.assist ? "assisted" : "none",
reset: buttons.reset && !previous.reset,
}),
buttons,
};
}
/** Keyboard/touch and gamepad may be used together; strongest intent wins. */
export function mergeVehicleActions(
primary: Partial<VehicleActionSnapshot>,
secondary: Partial<VehicleActionSnapshot>,
): VehicleActionSnapshot {
const a = normalizeVehicleActions(primary);
const b = normalizeVehicleActions(secondary);
return normalizeVehicleActions({
throttle: Math.max(a.throttle, b.throttle),
brake: Math.max(a.brake, b.brake),
steering: Math.abs(b.steering) > Math.abs(a.steering) ? b.steering : a.steering,
handbrake: a.handbrake || b.handbrake,
modeRequest: b.modeRequest !== "none" ? b.modeRequest : a.modeRequest,
reset: a.reset || b.reset,
});
}