Skip to Content
ProductsEngine

Engine

@shipshitgames/engine is the shared Three.js game spine.

Use it for gameplay primitives that should not be rewritten in every game:

  • world bounds
  • data-driven arena maps
  • render lifecycle and map lighting
  • camera rigs
  • input seams
  • steering and agents
  • spawn helpers
  • HUD snapshots
  • generic FX, projectile, and pickup lifecycles

Boundary rule

Gameplay is imperative and Three.js-centered. React is for shells, menus, HUD, and overlays.

The engine extraction boundary is tracked in packages/engine/ENGINE-EXTRACTION-BOUNDARY.md. That spec separates reusable engine core from game-owned Scourge Survivors content before runtime systems move into the package.

Ownership and Deadrot consumption

packages/engine in this repo is the canonical source for @shipshitgames/engine. Deadrot games should depend on the package release for CI and release builds:

{ "dependencies": { "@shipshitgames/engine": "^0.1.1", "three": "^0.184.0" } }

When testing unpublished engine changes locally, link the package from this repo instead of editing a Deadrot-owned copy:

cd ../shipshitgames/packages/engine bun link cd ../../../deadrotcom bun link @shipshitgames/engine bun install

The duplicate deadrot.com/packages/engine package is a temporary compatibility copy until the Deadrot repo removes it or replaces it with a shim. Do not add new engine features there, do not rename the package to @deadrot/engine, and do not create a separate engine project board for this scope.

The full ownership contract is tracked in packages/engine/CANONICAL-ENGINE.md.

Asset manifest schema

The engine package intentionally exports the shared game asset manifest schema:

import manifestSchema from "@shipshitgames/engine/assets-manifest.schema.json";

Studio tooling validates each game’s src/assets/assets.json with this schema. The schema belongs with the reusable engine contract; Deadrot-specific asset files and generated source history still belong in ../deadrotcom/packages/assets.

Import examples

import { RectBounds, makeBounds } from "@shipshitgames/engine"; import { ArenaSystem, HudSystem, ProjectilesSystem } from "@shipshitgames/engine"; import { firstPersonPointerLock } from "@shipshitgames/engine";

World bounds

Use bounds for clamp, cull, and spawn decisions instead of scattering global numbers through a game loop.

const bounds = RectBounds.square(40); bounds.clampXZ(position, 1.5);

Arena maps

Use ArenaSystem to interpret serializable map bounds, obstacles, themes, and lights consistently across games.

const arena = new ArenaSystem({ id: "demo-arena", bounds: { kind: "square", half: 40 }, obstacles: [{ kind: "rect", id: "crate-a", x: 3, z: -2, width: 2, depth: 2 }], }); arena.isBlockedXZ(3, -2);

Camera seam

Player systems read body and facing from the rig. The camera is render-only.

const rig = firstPersonPointerLock(camera, body);

HUD and transients

Games supply typed state and content tables. The engine owns fan-out and lifecycle bookkeeping.

const hud = new HudSystem({ health: 100, ammo: 12 }); const projectiles = new ProjectilesSystem({ bullet: { type: "bullet", speed: 20, radius: 0.1, ttl: 1, damage: 4 }, });

Check

cd packages/engine bun run test bun run typecheck