Last active
November 27, 2025 01:57
-
-
Save lsparrish/e88f588cda586a8abeb4b1d99863da84 to your computer and use it in GitHub Desktop.
js libs for gemini projects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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