Interactive Graphics course — Sapienza University of Rome.
The game can be played here:
The accompanying document (technical presentation and user manual) is here:
To run it locally:
npm install
npm run devThen open the address shown by Vite (usually http://localhost:5173). Wait for the loading screen to disappear.
We built a small 3D harbor in the browser. The idea is simple: you work like a crane operator. A cargo ship docks, you pick containers with a portal crane, you stack them on the dock, and you can load them on a truck that leaves the port.
Around this core loop we added a full port scene: roads, buildings, decorative ships, workers, day and night lighting, fog, and physics when a container falls.
The project is not a scored game. There is no timer and no points. It is a playable sandbox. You can stay in the crane and move cargo, or you can walk around as a worker and look at the harbor.
Animations are written in JavaScript. We did not import ready-made animations from the models.
The project runs in a web browser. The graphics API is WebGL.
We did not write raw WebGL shaders for the whole scene. We used Three.js (version 0.185). Three.js sits on top of WebGL and gives us a scene graph, cameras, lights, materials, loaders, and helpers. The renderer is WebGLRenderer with antialiasing. Shadows use PCFSoftShadowMap.
The page is plain HTML and CSS. The code is JavaScript ES modules. There is no React or Vue.
Vite (version 8) is the build tool. In development it serves the files. For GitHub Pages we use npm run build. The entry point is index.html, which loads src/main.js.
Each main object (ship, crane, truck, dock, worker) is a class with a THREE.Group called root. Moving that group moves the whole object. main.js creates the scene, handles keyboard input, and runs the game loop.
This section lists what we used but did not write ourselves.
| Name | Version | What we use it for |
|---|---|---|
| three | ^0.185.1 | 3D scene, renderer, lights, materials, GLB loading |
| @tweenjs/tween.js | ^25.0.0 | Smooth timed motion for the cargo ship, the truck, and decorative ships |
| cannon-es | ^0.20.0 | Physics for falling containers (Cannon.js for ES modules) |
| vite | ^8.2.1 | Dev server and production build |
Three.js add-ons (they come with Three.js, we did not write them):
GLTFLoader— load.glbmodelsOrbitControls— mouse orbit, pan and zoomWater— animated sea surfaceBufferGeometryUtils— merge road marking geometries
We also used Node.js and npm to install packages.
We downloaded or found these models online. We scaled them, placed them, and animated them in code. We did not model them in Blender from scratch, and we did not import their animations.
Gameplay objects
| File | What we use it for | Source |
|---|---|---|
Crane_Modified3.glb |
Portal crane (named parts: boom, spreader, cables, wheels) | Harbor Crane — MisterH |
trucks.glb |
Truck with wheels named FR, FL, RL, RR | Trucks — FS 3D Studio |
simple_truck.glb |
Decorative road traffic (kei truck) | Simple Kei Truck — Spookyghostboo |
Worker.glb |
Walkable worker (skinned mesh, Mixamo-style bones) | Pete — drifter33 |
flashlight.glb |
Flashlight the worker can hold at night | Flashlight — MAR.COS. |
ships/ship_1.glb |
Playable cargo ship (first type) | Cargo Ship 06 without containers — gogiart |
ships/ship_3.glb |
Playable cargo ship (second type) | Multi-purpose Vessel VI — gogiart |
ships/deco/deco_ship_1.glb |
Background ship | Ship AAA Re-upload — gogiart |
ships/deco/deco_ship_2.glb |
Background ship | Multi-purpose Vessel VII — gogiart |
ships/deco/deco_ship_3.glb |
Background ship | Container Ship — RM02 |
ships/deco/deco_ship_4.glb |
Background ship | Rescue Vessel — gogiart |
Containers (picked at random, then scaled to the same size)
| File | What we use it for | Source |
|---|---|---|
20ft_container.glb |
Classic 20-foot container | 20ft Container — dust_iny |
containers/cargo_container_new.glb |
Colored cargo containers | Cargo Container — Satendra Saraswat |
containers/container.glb |
Extra container variant | Container — LiuMeowMeow |
containers/container_3d_model.glb |
Extra container variant | Container 3D Model — Javier Martín Hidalgo |
containers/sea_cargo_container_-_legendarygamedev.glb |
Sea cargo container | Sea Cargo Container — RienceCG |
containers/shipping_container.glb |
Shipping container | Shipping Container — Egor Gulyushkin |
containers/shipping_containers.glb |
Blue, green and red shipping containers | Shipping containers — ForevereQ |
Environment and props
| File | What we use it for | Source |
|---|---|---|
industrial_buildings_set_-_low_poly_models.glb |
Warehouses, tanks, power plant, silos and similar buildings | Industrial Buildings Set - Low Poly Models — Daniel Zhabotinsky |
street_lamp.glb |
Street lamps along the roads | Street Lamp — StratoArt |
forklift_low_poly.glb |
Two parked forklifts | Forklift Low Poly — Ricardo Sanchez |
fuel_truck.glb |
Decorative fuel truck | Fuel Truck — simonthedigger |
docks_bollard.glb |
Mooring posts on the quay | St Katharine Docks Bollard — artfletch |
workers.glb |
Static worker poses around the yard | Constructiin Worker 112 — CloudHubOmniTeam |
damaged_chainlink_fence.glb |
Fence sections | Damaged Chainlink Fence — Arsen Ismailov |
oil_barrel_opt.glb |
Oil barrel piles | Collection of Oil Barrels — MisterH |
plastic_water_container_-_4mb.glb |
Plastic water containers | Plastic Water Container — Mehdi Shahsavan |
| File | What we use it for | Source |
|---|---|---|
textures/waternormals.jpg |
Normal map for the sea | waternormals.jpg — Three.js |
textures/concrete/brushed_concrete_2_diff_2k.jpg |
Dock color (diffuse) | Brushed Concrete 2 — Poly Haven |
textures/concrete/brushed_concrete_2_nor_gl_2k.jpg |
Dock normal map | Brushed Concrete 2 — Poly Haven |
textures/concrete/brushed_concrete_2_rough_2k.jpg |
Dock roughness | Brushed Concrete 2 — Poly Haven |
textures/concrete/quay_wall.png |
Vertical quay wall faces on the dock platform | AI generated |
textures/ground/asphalt_tile.png |
Road surface | AI generated |
textures/ground/dash_centerline_white.png |
White dashed center line on the roads | AI generated |
textures/ground/paint_stripe_white.png |
White road edges and yard slot lines | AI generated |
textures/ground/paint_stripe_orange.png |
Orange hatch markings in the crane zone | AI generated |
textures/ground/decal_manhole.png |
Manhole covers | AI generated |
textures/ground/decal_drain.png |
Storm drains | AI generated |
textures/ground/decal_patch.png |
Repair patches | AI generated |
textures/ground/decal_crack.png |
Pavement cracks | AI generated |
textures/ground/decal_pcrack.png |
Extra crack wear | AI generated |
textures/ground/decal_stop.png |
STOP markings | AI generated |
textures/ground/decal_arrow_white.png |
Direction arrows | AI generated |
textures/ground/decal_letter_d.png |
Depot letter D | AI generated |
textures/ground/decal_letter_y1.png … y5.png |
Yard labels Y1, Y3, Y4, Y5 | AI generated |
textures/ground/decal_dust.png / decal_dust_b.png |
Dust wear | AI generated |
textures/ground/decal_dirt.png / decal_dirt_b.png |
Dirt wear | AI generated |
textures/ground/decal_oil.png |
Oil stains | AI generated |
textures/ground/decal_fish.png |
Fish mark on the quay | AI generated |
textures/ground/decal_salt.png |
Salt wear | AI generated |
textures/ground/decal_net.png |
Net wear | AI generated |
Roads, the dock box, the sky dome and the fog walls are built in code with Three.js geometry. They are not imported models.
This section explains how to use the application.
Open the GitHub Pages link or run the project locally. A dark loading screen appears while models and shaders load. When it says ready, you can play. Until then, keyboard and camera buttons are off.
The default camera is an overview of the working area. You can orbit with the left mouse button, zoom with the wheel, and pan with the right mouse button (when the current view allows it).
- Top left: list of main keys
- Top center: short prompts when an action is available, for example “Press E to load the container”
- Top right: Day / Night switch, and a Sunrise checkbox (only in day mode)
- Bottom left: camera buttons (views 1 to 7)
If a container blocks the truck road, a message appears: Move the container blocking the road so the truck can pass.
This is the main gameplay.
Crane movement
- W / S — raise / lower the boom
- A / D — rotate the upper body
- Up / Down arrows — move the crane along the dock
- R / F — raise / lower the spreader (the hook)
Hold a key to keep moving. If the spreader or the held container hits another container or the truck, that movement stops. Other keys can still work.
Cargo
- E — pick a container if the spreader is above it, or place the held container on the nearest free ship or depot slot
- C — load the held container onto the parked truck
- Q — drop the held container. It falls with physics.
To pick, the spreader must be above the box, not beside it, and there must be space to hang the container. If E does not appear, move the crane a bit.
- SPACE — cargo ship arrives or leaves. You can only toggle when the ship is fully docked or fully gone. If a decorative ship is crossing, the game waits a few seconds so they do not overlap.
- T — truck arrives or leaves.
When you load the truck with C, or you pick the container that was on the truck, the truck leaves by itself after a short delay. When it comes back, there is a 20% chance it brings a new container.
If something is on the road, the truck waits. Move that container with the crane (or drop it somewhere else) and the truck continues.
Use the switch on the top right.
- Day — bright sky, sun shadows
- Night — dark sky, street lamps, crane lights, truck headlights. No sun shadows.
- Sunrise — only in day mode. Warmer light and a low sun.
Press 6 or 7.
- Arrow keys — walk and turn. You stay inside a limited part of the yard.
- L — flashlight, only at night.
Press 1–5 to go back to crane / overview cameras.
| Interaction | How |
|---|---|
| Orbit / zoom / pan | Mouse, depending on camera view |
| Change viewpoint | Keys 1–7 or buttons |
| Day / night / sunrise | UI switches |
| Ship arrive / leave | SPACE |
| Truck arrive / leave | T (also auto after load) |
| Crane boom, rotate, travel, hoist | W S A D arrows R F |
| Pick / place container | E |
| Load truck | C |
| Drop container | Q |
| Walk as worker | arrows in views 6–7 |
| Flashlight | L at night in worker view |
| Truck waits if road is blocked | automatic, with a message |
| Containers fall and can knock stacks | Q and collisions |
| Contextual help | prompts when E or C is possible |
All of this is handled in JavaScript (keydown/keyup and the animation loop).
