- JavaScript 89.4%
- HTML 9.8%
- TypeScript 0.8%
| public | ||
| src | ||
| .env | ||
| .gitattributes | ||
| .gitignore | ||
| create-project.json | ||
| index.html | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| vite.config.js | ||
Attribution — this is a faithful community port. Upstream: https://github.com/icurtis1/raycast-vehicle Author: Ian Curtis · License: MIT · Ported from commit
f9d2457Changes: build glue only (Genex embed-SDK boot + this notice). All credit for the code and idea goes to the original author.
Raycast RC Car
Play the live demo: https://raycast-rc-car.netlify.app/
Interactive arcade RC car sample built with three.js and
cannon-es. The car uses a
CANNON.RaycastVehicle chassis with GLB visuals, a GLB driving level,
post-processing effects, mobile, desktop, and browser Gamepad API controls,
plus a live tuning panel.
The physics approach is inspired by Bruno Simon's portfolio and swift502/Sketchbook: each wheel is a suspension ray, while the GLB level is converted into static trimesh colliders for ramps, loops, and walls.
Run it
Requires Node.js 20+.
npm install
npm run dev
Then open http://localhost:5173.
Controls
Keyboard
| Key | Action |
|---|---|
| W A S D / arrows | Drive and steer |
| Shift | Boost |
| Space | Jump / handbrake |
| R | Respawn |
| . (period) | Toggle the tuning panel |
| Mouse drag | Orbit the camera (scroll to zoom) |
Touch (phones/tablets)
An on-screen joystick (right) drives and steers, the lightning button (left) boosts, and the small top-left reset button respawns the car. The tuning panel is hidden on touch devices.
Gamepad
| Input | Action |
|---|---|
| Left stick / D-pad | Steer and drive |
| Right trigger | Gas |
| Left trigger | Brake / reverse |
| A (bottom button) | Jump |
| B / right bumper | Boost |
How it works
- The chassis is a single
CANNON.Boxrigid body, with small corner spheres so it can collide with the level'sCANNON.Trimesh(cannon-es trimeshes only generate contacts against spheres and planes, not boxes). - Each wheel is a
CANNON.RaycastVehiclewheel: a ray cast downward that acts as a spring/damper suspension and applies engine, brake, and friction forces at the contact point. There are no wheel collider bodies, which is what makes this technique stable and fast. - The level (
src/assets/rc-level.glb) is used for both rendering and physics: every mesh in it becomes an exactCANNON.Trimeshcollider, so ramps and curved surfaces work without hand-made collision boxes. - Three.js meshes are purely visual and get synced from the physics bodies each
frame (
Vehicle._syncVisuals,World.update). - The chase camera smoothly interpolates toward a point behind the car using frame-rate-independent exponential damping, pulls back and widens the FOV while boosting, and lifts up when the car is airborne.
- A single post-processing pass handles color grading, vignette, chromatic aberration, film noise, and the wind-streak speed effect during boost.
- The sun's shadow camera follows the car and snaps to shadow-map texels to avoid shimmering shadow edges.
Tuning the feel
Press . or use the Vehicle Tuning panel (top-right, lil-gui — closed by
default) to tweak everything live. It is organized into:
- Vehicle — engine, steering, brakes, suspension & tires, chassis, assists, and jump
- Camera — FOV and clipping
- World — environment height, teleporter, lighting & shadows
- Effects — post processing and tire marks, including rear track spacing and forward offset
- Models — visual-only GLB transforms for the body and wheels
- Debug — FPS readout and physics collider wireframes
"Reset to defaults" restores the shipped values.
Defaults live in DEFAULT_PARAMS at the top of src/Vehicle.js. Highlights:
engineForce,boostMultiplier,cruiseSpeedKmh,maxSpeedKmh— acceleration and top speed (with and without boost)maxSteer,steerSpeed— how sharp and how quickly the car steersfrictionSlip— grip (lower = more drifty)suspensionStiffness/suspensionRestLength— ride height and bouncejumpImpulse,airborneGravityScale— jump height and how floaty it feelsinertiaScale,antiWheelie,tiltClampAirborne,uprightAssist,wallSlideAssist— the arcade stability assistsbackWidth,backSpacing,backForwardOffset— rear tire mark placement and shape
Project structure
index.html HUD, mobile controls, and styles
public/og-image.jpg Social share preview image
src/main.js Renderer, camera, post-processing, GUI, input, game loop
src/Vehicle.js Car physics, controls, visuals, tire marks
src/World.js Level loading, trimesh colliders, lights and shadows
src/assets/ Car and level GLBs + reflection texture
Gotchas worth knowing (cannon-es)
CANNON.Trimeshonly collides with spheres and planes. The car's box chassis gets four embedded corner spheres so it can hit trimesh walls.- Rays fail against rotated
CANNON.Planebodies — use boxes or trimeshes for the ground instead. - A body's AABB is computed once at construction;
position.set()after construction leaves it stale, and rays are broadphase-culled against that stale AABB. Callbody.updateAABB()after placing static bodies.
