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):

Engine (leave as-is unless you know what you're doing):

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:

  1. Create js/features/my-feature.js exporting DEFAULTS and create({...settings}, deps).
  2. Register it in featureLoaders in features.js.
  3. 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:

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}}