logo

Babylon.js Market

ChaseCamera6DOF

camera · space-combat-sim

ChaseCamera6DOF

1
Unlock

Install with the CLI:

bjs download ChaseCamera6DOF

ChaseCamera6DOF

A quaternion-smoothed chase camera for 6-DOF flight — it trails the followed ship behind and above the canopy, in the ship's own local frame, so the view rolls with the cockpit through any pitch, roll, or loop.

What it does

ChaseCamera6DOFSystem follows one subject: the entity carrying ChaseCameraTarget + Transform6DOF (your player ship). Each frame it reads that ship's world pose and eases the camera toward a spot trailDistance behind and trailHeight above it — but "behind" and "above" are measured along the ship's local forward and up axes, so there's no world horizon assumption. That's what keeps the camera glued over the canopy when you barrel-roll or fly inverted, exactly right for a space sim. On frame 1 it snaps straight to the target; after that it blends with a = 1 − exp(-dt / tau) — a true exponential ease that's framerate-independent — orienting via shortest-path quaternion SLERP (gimbal-safe) and decaying position toward the trailing point. It writes the smoothed pose straight into the camera singleton's CameraState6DOF; CameraSync6DOF is what pushes that pose to the actual renderer camera. The component itself is three tunable knobs with a live panel, and it touches no @babylonjs/three — the system constructor takes (eventBus) only.

Use it in a scene

A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.

Build it from scratch with the bjs CLI:

  1. 1Scaffold a project
    npm create @babylonjsmarket/arcade@latest my-game

    World, renderer, and dev server — ready to run.

  2. 2Install dependencies
    cd my-game && npm install
  3. 3Add ChaseCamera6DOF
    bjs download ChaseCamera6DOF

    Copies its source into src/ so the scene resolves.

    First time? Run bjs login once.

  4. 4Paste the scene into src/scenes/arcade-room.ts and run
    npm run dev

    SceneLoader builds the world from the JSON; reload to rebuild.

JSON
{
  "Camera": {
    "tags": ["camera"],
    "components": {
      "CameraState6DOF": { "fov": 1.05, "near": 0.1, "far": 200000 },
      "ChaseCamera6DOF": { "trailDistance": 18, "trailHeight": 6, "tau": 0.18 }
    }
  },
  "Player": {
    "tags": ["player"],
    "components": {
      "Transform6DOF": { "x": 0, "y": 0, "z": 0 },
      "Renderable": { "shape": "spaceplane", "glbSrc": "/wingman/falconship.glb" },
      "ChaseCameraTarget": {}
    }
  }
}

Props

  • trailDistance (number, default 18) — how far behind the ship the camera sits, along the ship's local forward axis (world units).
  • trailHeight (number, default 6) — how far above the ship the camera sits, along the ship's local up axis — so the camera rolls with the cockpit.
  • tau (number, default 0.18) — smoothing time-constant in seconds. Smaller = snappier and stiffer; larger = floatier and more lag. Framerate-independent.

Events

  • Emits nothing.
  • Listens for nothing.

This camera is wired by component lookup, not the event bus: the system queries [ChaseCameraTarget, Transform6DOF] for its subject, resolves the camera singleton by scanning for CameraState6DOF, and writes the pose directly into it. Nothing to subscribe to, nothing to emit.

Dependencies

  • Transform6DOF — on the followed ship; its position + quaternion are the pose the camera trails.
  • ChaseCameraTarget — the marker on the followed ship. Put it on exactly one entity; the system follows the first active one it finds.
  • CameraState6DOF — on the camera singleton, next to this component. The smoother writes its pose here.
  • CameraSync6DOF — reads CameraState6DOF and mints/poses the real renderer camera. Without a sync system, the smoothed pose is computed but never drawn.

Notes

  • ChaseCamera6DOF lives on the camera entity (beside CameraState6DOF), while ChaseCameraTarget lives on the ship. Two entities, one relationship — don't put the tuning knobs on the ship.
  • One camera, one subject: only the first active ChaseCameraTarget is followed. If two entities carry the marker, the second is ignored, not averaged.
  • Frame-1 snaps instantly (no swoop-in from the origin); every frame after eases by tau. If the camera whips or lags wrong, tune tau before touching the trail offsets.
  • The offsets are in the ship's local frame, not world space, so a big trailHeight stays "above the canopy" even when you're upside down — that's the point, not a bug.
  • The panel writes live edits into the component, and the system re-reads trailDistance/trailHeight/tau every frame, so tuning the feel at runtime takes effect immediately without a reload.

More like this

CameraState6DOF
ChaseCameraTarget
Transform6DOF
ArcCamera
Asteroid
CameraFollow
FlightIntent
FreighterCar
FreighterChain
FreighterHead
GameConfig
OilBlob
PinballCamera
PlayerFlightInput
Renderable
ShipFlight
ShooterCamera
SpaceDust
SpaceShooterBullet
SpaceShooterHealth
SpaceShooterScore
Velocity6DOF
WaveDirector
Waypoint
WaypointTrack
WorldOriginAnchor

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search