One lap. Five checkpoints. Sixteen hazards that want you off the track.
A 3D arcade kart racer built with Three.js, developed for the Interactive Graphics course at Sapienza University of Rome.
Smashy Karts puts you on a closed circuit that is actively trying to wreck you. To win, you must:
Pick your kart in the Showroom → clear all five checkpoints in order → survive the rotating arms, swinging hammers, ramming karts and the crane container → cross the finish line before the clock or your lives run out.
- Procedurally generated track — a closed Catmull-Rom curve sampled into 720 segments, the backbone of the road mesh, kerbs, barrier placement, obstacle positioning and the collision model
- Analytic guardrail — no barrier geometry is tested: the kart's lateral offset from the centreline keeps it inside the corridor and cancels its outward velocity
- Infield lake placed at the circuit's centroid, its radius clamped so it never touches the tarmac
- Trackside scenery — grandstands packed with an animated crowd, pit tents, billboards and up to 130 trees scattered by rejection sampling
Eight distinct types, sixteen instances:
- Rotating arm — a sweeping beam with counterweights, oriented circle-vs-box test
- Pendulum hammer — a swinging stone, harmless at the top of its arc: you have to time the crossing
- Enemy kart — a full
Kartinstance driven sideways across the road by a synthetic input state, so its suspension, wheels and exhaust animate exactly like a player's - Crane container — a trolley sliding along a jib with a container swinging beneath it on cables
- Conveyor belt and industrial fan — non-lethal, they push you toward something that is
- Jump ramp — drive up the slope, but the launch only fires near the exit edge and above a minimum speed
- Water puddles — not fatal, they drag your speed down and throw up a splash
- Inspect the selected kart on the real starting grid before the race
- Auto-orbit camera with an adjustable speed slider, or click-and-drag to orbit manually
- Repositionable spotlight with adjustable intensity, to watch the PBR response change in real time
- Toggle the texture map on/off, switch the mesh to wireframe
- Switch between three Kenney vehicles, preview the headlight glow with
H, and flip day/night
Every animation is written by hand.
- Hierarchical kart rig — wheel spin integrated from speed, front-wheel steering, body roll and pitch smoothed with an exponential lerp, suspension oscillation from two summed sine waves, chassis stretch while airborne
- Animated water — vertices displaced on the CPU by three summed sine waves with per-vertex random parameters, normals recomputed every frame, plus a scrolling normal map for the shimmer
- Crowd and trees — every spectator hops on an
abs(sin)curve with its own phase and speed; every tree sways with a per-tree phase - Four particle pools — exhaust smoke, boost flame, impact sparks and water splash, each a ring-buffer of GPU point sprites integrated with explicit Euler
- PBR
MeshStandardMaterialalmost everywhere, fed by a PMREM environment map generated from the procedural sky, so reflections show exactly the sky you see - Blinn-Phong for the water surfaces, where a classic specular highlight reads better on a rippling transparent sheet
- Procedural sky — an equirectangular canvas with projection compensation at the poles, a sun and moon aligned with the directional light, stars distributed uniformly over the hemisphere
- Fully procedural textures — colour and normal maps for asphalt, metal, grass and wood from value noise through a Sobel filter, plus kerbs, foliage, conveyor stripes, the finish checkerboard and the water specular map
- Real-time shadows — 2048×2048
PCFSoftShadowMapfrom the sun, its orthographic frustum re-centred on the kart every frame - Post-processing —
ACESFilmicToneMappingandUnrealBloomPasson the emissive surfaces (checkpoint strips, lamp lenses, brake lights, boost glow, headlights)
| Key | Action |
|---|---|
| W / S or ↑ / ↓ | Accelerate / brake (reverse when stationary) |
| A / D or ← / → | Steer (response scales with speed) |
| Space | Jump |
| Shift | Boost — one shot per run, only while already rolling on the ground |
| C | Cycle camera: chase → cockpit → top-down → orbit |
| V | Toggle day / night |
| H | Toggle headlights |
| R | Respawn at the last checkpoint (costs a life) |
| P / Esc | Pause |
| Mouse drag | Orbit the camera (in orbit mode, and in the Showroom) |
| Scroll | Zoom (orbit mode) |
final-project-puttparty/
├── index.html # entry point + import map (Three.js r160, bundled locally)
├── css/style.css # menu, HUD, showroom and results overlays
├── js/
│ ├── main.js # bootstrap, menu/showroom/race state machine, post-processing
│ ├── game.js # race loop, kart physics, collisions, checkpoints, lives
│ ├── track.js # centreline, road, kerbs, barriers, lake, scenery, crowd
│ ├── obstacles.js # the eight hazard types: geometry, animation, check()
│ ├── kart.js # glTF rig, hierarchical animation, headlights, glow patches
│ ├── environment.js # procedural sky, PMREM, lighting rig, day/night presets
│ ├── camera.js # CameraRig: chase, cockpit, top-down and orbit modes
│ ├── water.js # animated water surface (CPU vertex displacement)
│ ├── particles.js # four pooled point-sprite systems
│ ├── textures.js # procedural canvas textures + Sobel height-to-normal
│ ├── props.js # Kenney glTF loader and prop factory
│ ├── input.js # keyboard and mouse state
│ └── lib/ # Three.js r160 and its official addons
├── models/
│ ├── kart.glb, kart2.glb, kart3.glb # the three selectable vehicles
│ └── kenney/ # CC0 scenery pieces (barriers, stands, trees, tents…)
└── assets/ # water normal map + menu background
This project has no build step and no external dependencies — Three.js and its addons ship with the repository and are resolved through an import map.
# 1. Clone the repository
git clone https://github.com/SapienzaInteractiveGraphicsCourse/final-project-puttparty.git
cd final-project-puttparty
# 2. Serve it locally (any static server works)
python3 -m http.server 8000Then open http://localhost:8000 in a modern, WebGL-capable browser.
A local server is required because the game uses ES module imports and loads glTF models, which browsers block under the
file://protocol. Once served, no internet connection is needed: every library, model and texture is loaded from the project directory.
https://sapienzainteractivegraphicscourse.github.io/final-project-puttparty/
Developed by Diego Aliaga, Giacomo Barcellona and Dario Finocchiaro for the Interactive Graphics course, Sapienza University of Rome.
- Engine: Three.js (r160)
- Kart and scenery models: Kenney Racing Kit (CC0), license in
models/kenney/License.txt - Water normal map:
assets/waternormals.jpg, the only external image used by the 3D scene - Everything else — textures, animations, sky, particles — is generated procedurally by the team