# 3D Engine - Minimal 3D Multiplayer Template

**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. Calls `setConfig`, `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 via `translations.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/realtime` kit (presence + world-state channels).
- `network/adapter-3d.js` - the only 3D-aware networking code: bridges `@gipity/realtime` to Three.js / Rapier.
- `packages/realtime/` - the engine-agnostic `@gipity/realtime` kit (transport, channels, host election, sync). Self-describing: see its `README.md`, `contracts/`, and `examples/`. Reusable by any app, not just games.
- `player.js` - optional character controller (call `player.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:

```js
import { world, assets, physics, player, network, ui, THREE, onInit, onUpdate, setConfig, primitives, constraints, workspace, features } from './core.js';
```

### Lifecycle

```js
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`:

```js
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.

```js
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:

```js
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:
- A player controller wired with orbit + aim camera
- A demo scene with voxel structures in two rings
- A `rocket-launcher` feature 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}}

