3D Engine is the blank-slate 3D multiplayer template on Gipity. It boots a Three.js scene, a Rapier physics world, a Colyseus multiplayer client, and exposes the engine API - with no gameplay. Use it when the user wants to build a fresh 3D app without inheriting a demo's logic.
When to use this: When the user describes a new 3D or multiplayer app (e.g. "3D Boggle", "voxel painting", "3D chat room") and you want a clean starting point. If they want a playable reference with rockets, camera orbit, and spawn logic already wired, add the 3d-world starter instead.
Quick Start
add name=3d-engine title="<App Name>"
After adding the template, the player sees a lit ground plane with multiplayer connected. There's no character yet - you decide the control model.
Naming: Use the user's name verbatim if given. If they didn't specify, blend "Gip" or "Gipity" into the name.
Project Structure
After adding the template, all files are in src/ and fully editable. Two-layer split:
Your code (edit these):
game.js- entry point. CallssetConfig,onInit,onUpdate. Start here.config.js- project metadata and feature flags.settings.js- tunable values (world size, colors). Add your own.strings.js- user-facing text. Localized viatranslations.js.scene.js- scene builder. Currently creates one ground plane. Replace with your world.css/game.css- game-specific styles. Empty stub.
Engine (leave as-is unless you know what you're doing):
core.js- boot sequence and render loop. Re-exports every engine module.world.js- Three.js scene, camera, renderer, lighting.physics.js- Rapier physics world, raycasting, triggers.network.js- thin 3D facade over the@gipity/realtimekit (presence + world-state channels).network/adapter-3d.js- the only 3D-aware networking code: bridges@gipity/realtimeto Three.js / Rapier.packages/realtime/- the engine-agnostic@gipity/realtimekit (transport, channels, host election, sync). Self-describing: see itsREADME.md,contracts/, andexamples/. Reusable by any app, not just games.player.js- optional character controller (callplayer.initPlayer(...)when you want one).primitives.js- Part system and workspace.constraints.js- joint/constraint system.assets.js- geometry builders, material presets.shapes.js- voxel shape library (cubes, spheres, arches, towers).utils.js- helpers (randInt, onCircle, placeVoxels).features.js- opt-in feature registry. Empty by default.ui.js- HUD, loading screen, message overlay.css/engine.css- engine styles.
Read the files before making changes - the comments explain what each one does.
Engine API
All engine modules are available via a single import:
import { world, assets, physics, player, network, ui, THREE, onInit, onUpdate, setConfig, primitives, constraints, workspace, features } from './core.js';
Lifecycle
setConfig(config); // set once at import time
onInit(async () => { ... }); // runs after engine boots
onUpdate((dt) => { ... }); // runs every frame
The starter game.js already wires these up - edit its bodies.
Adding a player
The template ships without a character. To add one, import player and call initPlayer in onInit:
import { player } from './core.js';
onInit(async () => {
player.initPlayer({
speed: 12,
jumpForce: 18,
gravity: -40,
color: 0xf26522,
camera: { distance: 20, sensitivity: 0.003 },
});
});
See the 3d-world starter for a full player configuration (camera orbit, aim mode, crosshair).
Building a scene
primitives.createPart(...) is the workhorse. Anchored parts don't move; dynamic parts fall under gravity and collide.
import { primitives } from './core.js';
primitives.createPart({
position: { x: 0, y: 5, z: 0 },
size: { x: 3, y: 3, z: 3 },
color: 0x2196F3,
material: 'wood',
});
For voxel structures, use the shapes library:
import { placeVoxels } from './utils.js';
import { solidCube, voxelSphere, arch } from './shapes.js';
placeVoxels(arch(5, 6), { x: 0, y: 0, z: 10 }, 0x9C27B0);
Multiplayer
Multiplayer runs on the engine-agnostic @gipity/realtime kit (packages/realtime/); network.js is a thin 3D facade over it. The multiplayer feature connects to the Colyseus room named in config.js, broadcasts the local player on the avatars presence channel, and renders remote peers. The room itself is declared in the template's gipity.yaml (a realtime deploy phase), so gipity deploy provisions it automatically. For game events, open a channel: network.channel('events', { sync: 'messages' }) → .send(type, data) / .on(type, cb). For host-authoritative shared world state, enable sync.worldState. See the 3d-world skill's "Multiplayer in Depth" for the full API.
Features
features.js ships empty. To add a feature module:
- Create
js/features/my-feature.jsexportingDEFAULTSandcreate({...settings}, deps). - Register it in
featureLoadersinfeatures.js. - Enable it in
config.js:features: { 'my-feature': true }.
Each feature receives the full engine deps: world, scene, camera, renderer, physics, player, network, ui, assets, primitives, constraints, THREE.
Reference: the 3d-world starter
The 3d-world starter uses this same engine, plus:
- A player controller wired with orbit + aim camera
- A demo scene with voxel structures in two rings
- A
rocket-launcherfeature with projectile + explosion + audio - Block-collision tick sounds
Add one in a throwaway project if you want to see a fully-wired implementation:
add name=3d-world title="Rocket Demo"
Deploy
Same flow as every Gipity app:
project_deploy target=dev
{{DEPLOY_VERIFICATION}}