World

World is a level/scene container inside a Game. It groups Actors, sets up a default camera, and optionally enables physics. Toggle worlds on/off with the active prop.

A Game can have multiple Worlds — only the active one is visible and receives rendering.

tsx
import { World } from "@carverjs/core/components";

Quick Start #

tsx
import { Game, World, Actor } from "@carverjs/core/components";

function App() {
  return (
    <Game>
      <World>
        <Actor type="primitive" shape="box" color="red" position={[0, 1, 0]} />
      </World>
    </Game>
  );
}

Props Reference #

PropTypeDefaultDescription
activebooleantrueWhether this world is visible. Set to false to hide it.
physicsWorldPhysicsConfigEnable Rapier physics. Requires @react-three/rapier.
cameraProps2DCameraProps2DOverrides for the default OrthographicCamera (2D mode)
cameraProps3DCameraProps3DOverrides for the default PerspectiveCamera (3D mode)
orbitControlsPropsOrbitControlsPropsOverrides for the default OrbitControls (3D mode)
childrenReactNodeScene content (Actors, Camera, etc.)

Physics #

Pass a physics prop to enable Rapier-based physics for all Actors in the World.

Install #

bash
pnpm add @react-three/rapier

@react-three/rapier is an optional peer dependency — Rapier is lazy-loaded at runtime. If it's not installed and you pass a physics prop, a console warning is logged and children render without physics.

WorldPhysicsConfig #

FieldTypeDefaultDescription
gravity[number, number, number][0, -9.81, 0]Gravity vector
timestepnumber | "vary"1/60Physics timestep. "vary" uses variable timestep.
interpolationbooleantrueSmooth rendering between physics steps
debugbooleanfalseShow wireframe collider outlines

Basic physics #

tsx
<Game>
  <World physics={{ gravity: [0, -9.81, 0] }}>
    <Actor type="primitive" shape="box" color="red" position={[0, 5, 0]}
      physics={{ bodyType: "dynamic" }}
    />
    <Actor type="primitive" shape="plane" color="#eee" size={20}
      rotation={[-Math.PI / 2, 0, 0]}
      physics={{ bodyType: "fixed" }}
    />
  </World>
</Game>

2D physics #

In 2D mode, Z translation and X/Y rotation are auto-locked per Actor.

tsx
<Game mode="2d">
  <World physics={{ gravity: [0, -9.81, 0] }}>
    <Actor type="sprite" src="/player.png" position={[0, 5, 0]}
      physics={{ bodyType: "dynamic" }}
    />
  </World>
</Game>

Debug mode #

tsx
<World physics={{ gravity: [0, -9.81, 0], debug: true }}>
  {/* wireframe colliders visible */}
</World>

Default Camera #

World provides a default camera based on the mode set on the parent Game:

Property3D Mode2D Mode
TypePerspectiveCameraOrthographicCamera
Position[0, 5, 10][0, 0, 100]
FOV / Zoom7550
Near / Far0.1 / 10000.1 / 1000
Orbit ControlsEnabledDisabled

Override defaults #

tsx
<World cameraProps3D={{ position: [0, 10, 20], fov: 60 }}>
  {/* scene */}
</World>

Custom Camera #

Drop a <Camera> inside World to replace the default camera and controls:

tsx
<World>
  <Camera type="perspective" controls="orbit" />
  <Actor type="primitive" shape="box" color="red" />
</World>

When a <Camera> is detected, the default camera and orbit controls are skipped.


Multiple Worlds #

Use the active prop to switch between worlds:

tsx
function App() {
  const [level, setLevel] = useState("forest");

  return (
    <Game>
      <World active={level === "forest"}>
        <ForestScene onComplete={() => setLevel("dungeon")} />
      </World>
      <World active={level === "dungeon"}>
        <DungeonScene />
      </World>
    </Game>
  );
}

Inactive worlds are hidden via visible={false} on the underlying Three.js group. The Canvas and WebGL context are not destroyed during world switches.


Type Definitions #

See Types for WorldPhysicsConfig, CameraProps2D, CameraProps3D, and OrbitControlsProps.