Skip to content

Instantly share code, notes, and snippets.

@lsparrish
Last active November 27, 2025 01:57
Show Gist options
  • Select an option

  • Save lsparrish/e88f588cda586a8abeb4b1d99863da84 to your computer and use it in GitHub Desktop.

Select an option

Save lsparrish/e88f588cda586a8abeb4b1d99863da84 to your computer and use it in GitHub Desktop.
js libs for gemini projects
import * as THREE from 'three';
// --- CONFIGURATION ---
export const CAR_SCALE = 0.003;
// Internal constant, accessed via helper if needed
const CAR_BASE_HEIGHT = CAR_SCALE * 0.4;
export const CLIP_OFFSET = 0.0001;
export const AXIAL_WIDTH = 20;
// Physics Tuning
export const DRIVE_ACCEL = 0.1;
export const DRIVE_STEERING_ACCEL = 0.05;
export const DRIVE_DAMPING = 0.95;
export const DRIVE_ROT_DAMPING = 0.85;
export const DRIVE_MAX_SPEED = 6.0;
export function getCarBaseHeight() {
return CAR_BASE_HEIGHT;
}
/**
* Creates the 3D model (THREE.Group) for the car avatar.
* @returns {THREE.Group} The car mesh group.
*/
export function createCarAvatar() {
const scale = CAR_SCALE;
let avatarMesh = new THREE.Group();
const baseHeight = CAR_BASE_HEIGHT;
const chassisGeo = new THREE.BoxGeometry(scale * 1.5, scale * 0.5, scale * 3);
const chassisMat = new THREE.MeshStandardMaterial({ color: 0xcc3333, metalness: 0.8, roughness: 0.3, emissive: 0x882222 });
const chassis = new THREE.Mesh(chassisGeo, chassisMat);
chassis.position.y = baseHeight + scale * 0.25;
avatarMesh.add(chassis);
const cockpitGeo = new THREE.BoxGeometry(scale * 1.2, scale * 0.4, scale * 1.5);
const cockpitMat = new THREE.MeshBasicMaterial({ color: 0x00ffff, transparent: true, opacity: 0.7 });
const cockpit = new THREE.Mesh(cockpitGeo, cockpitMat);
cockpit.position.y = baseHeight + scale * 0.6;
cockpit.position.z = -scale * 0.2;
avatarMesh.add(cockpit);
const wheelGeo = new THREE.CylinderGeometry(scale*0.4, scale*0.4, scale*0.2, 16);
wheelGeo.rotateZ(Math.PI/2);
const wheelMat = new THREE.MeshBasicMaterial({ color: 0x111111 });
const w1 = new THREE.Mesh(wheelGeo, wheelMat); w1.position.set(scale*0.8, baseHeight, scale*1.0);
const w2 = new THREE.Mesh(wheelGeo, wheelMat); w2.position.set(-scale*0.8, baseHeight, scale*1.0);
const w3 = new THREE.Mesh(wheelGeo, wheelMat); w3.position.set(scale*0.8, baseHeight, -scale*1.0);
const w4 = new THREE.Mesh(wheelGeo, wheelMat); w4.position.set(-scale*0.8, baseHeight, -scale*1.0);
avatarMesh.add(w1); avatarMesh.add(w2); avatarMesh.add(w3); avatarMesh.add(w4);
const lightGeo = new THREE.BoxGeometry(scale*0.3, scale*0.1, scale*0.1);
const lightMat = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const l1 = new THREE.Mesh(lightGeo, lightMat); l1.position.set(scale*0.5, baseHeight + scale*0.1, -scale*1.5);
const l2 = new THREE.Mesh(lightGeo, lightMat); l2.position.set(-scale*0.5, baseHeight + scale*0.1, -scale*1.5);
avatarMesh.add(l1); avatarMesh.add(l2);
return avatarMesh;
}
/**
* Sets the camera's local position for the car.
* Position: 2 meters up, 10 meters back (0.002, 0.01 in km units).
* This frames the 3-meter car well with a 25-degree FOV.
*/
export function configureCarCamera(camera) {
camera.position.set(0, 0.002, 0.01);
camera.rotation.set(0, 0, 0);
camera.rotateX(-0.15); // Slight tilt down
}
/**
* Enforces the car's position constraints.
*/
export function enforceDriveConstraints(ship, ROTOR_R) {
// 1. Radial Constraint (Keep the car on the ground)
const xyDist = Math.sqrt(ship.position.x * ship.position.x + ship.position.y * ship.position.y);
const targetR = ROTOR_R - CAR_BASE_HEIGHT - CLIP_OFFSET;
const scaleFactor = targetR / xyDist;
ship.position.x *= scaleFactor;
ship.position.y *= scaleFactor;
// 2. Axial Constraint (Keep the car within the ring's width)
const limit = (AXIAL_WIDTH / 2) - 10;
ship.position.z = Math.max(Math.min(ship.position.z, limit), -limit);
// 3. Up-Vector Constraint
const radial = new THREE.Vector3(ship.position.x, ship.position.y, 0).normalize();
const upVec = radial.clone().negate();
const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(ship.quaternion);
const m = new THREE.Matrix4();
m.lookAt(ship.position, ship.position.clone().add(forward), upVec);
ship.quaternion.setFromRotationMatrix(m);
}
/**
* Updates the physics for the car in DRIVE mode.
*/
export function updateDrivePhysics(ship, keys, velocity, angularVelocity, ROTOR_R) {
if (keys.w) velocity.z -= DRIVE_ACCEL;
if (keys.s) velocity.z += DRIVE_ACCEL;
if (keys.a) angularVelocity.y += DRIVE_STEERING_ACCEL;
if (keys.d) angularVelocity.y -= DRIVE_STEERING_ACCEL;
velocity.multiplyScalar(DRIVE_DAMPING);
angularVelocity.multiplyScalar(DRIVE_ROT_DAMPING);
velocity.clampLength(0, DRIVE_MAX_SPEED);
ship.rotateY(angularVelocity.y);
ship.translateZ(velocity.z);
enforceDriveConstraints(ship, ROTOR_R);
}
import * as THREE from 'three';
// --- CONFIGURATION ---
export const SHIP_SCALE = 8;
// Physics Tuning (Standardized)
export const PILOT_ACCEL = 0.20;
export const PILOT_ROT_ACCEL = 0.002;
export const PILOT_DAMPING = 0.98;
export const PILOT_MAX_SPEED = 20.0;
/**
* Creates the 3D model (THREE.Group) for the space ship avatar.
* @returns {THREE.Group} The ship mesh group.
*/
export function createShipAvatar() {
const scale = SHIP_SCALE;
let avatarMesh = new THREE.Group();
const bodyGeo = new THREE.ConeGeometry(scale * 0.5, scale * 3, 8);
bodyGeo.rotateX(-Math.PI / 2);
const body = new THREE.Mesh(
bodyGeo,
new THREE.MeshPhongMaterial({
color: 0xffaa00,
emissive: 0xff4400,
emissiveIntensity: 0.5
})
);
const wingGeo = new THREE.BoxGeometry(scale * 3, scale * 0.1, scale * 1);
const wingMat = new THREE.MeshPhongMaterial({
color: 0x00ffff,
emissive: 0x00ffff,
emissiveIntensity: 0.8
});
const wing = new THREE.Mesh(wingGeo, wingMat);
avatarMesh.add(body);
avatarMesh.add(wing);
return avatarMesh;
}
/**
* Sets the camera's local position for the ship.
* Using a narrow FOV (Telephoto) requires moving the camera further back.
*/
export function configureShipCamera(camera) {
// Position: Move back significantly (100 units) to compensate for narrow FOV
camera.position.set(0, 25, 100);
camera.rotation.set(0, 0, 0);
}
/**
* Updates the physics for the ship in PILOT mode.
*/
export function updatePilotPhysics(ship, keys, velocity, angularVelocity) {
if (keys.w) velocity.z -= PILOT_ACCEL;
if (keys.s) velocity.z += PILOT_ACCEL;
if (keys.arrowup) angularVelocity.x += PILOT_ROT_ACCEL;
if (keys.arrowdown) angularVelocity.x -= PILOT_ROT_ACCEL;
if (keys.arrowleft) angularVelocity.y += PILOT_ROT_ACCEL;
if (keys.arrowright) angularVelocity.y -= PILOT_ROT_ACCEL;
if (keys.q) angularVelocity.z += PILOT_ROT_ACCEL;
if (keys.e) angularVelocity.z -= PILOT_ROT_ACCEL;
velocity.multiplyScalar(PILOT_DAMPING);
angularVelocity.multiplyScalar(PILOT_DAMPING);
velocity.clampLength(0, PILOT_MAX_SPEED);
ship.rotateX(angularVelocity.x);
ship.rotateY(angularVelocity.y);
ship.rotateZ(angularVelocity.z);
ship.translateX(velocity.x);
ship.translateY(velocity.y);
ship.translateZ(velocity.z);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment