OrbitMover
Sweeps a mesh around a fixed center on a circle — a moving target with no input wiring.
What it does
The System processes every entity carrying OrbitMover + MeshPrimitive. Each frame it advances angle by speed * dt, places the mesh at (centerX + cos(angle)·radius, centerY, centerZ + sin(angle)·radius), and pushes that through the adapter with setMeshPosition. When faceMotion is on it also yaws the mesh to point along its direction of travel via setMeshRotation. It emits and consumes no events — the motion is self-contained, which makes it the cheapest way to give a camera-follow or look-at mechanic something that actually moves without authoring keyboard control.
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.
Fastest path
Pulls this exact scene into your project and runs it — no copy-paste. Add --all to grab the components and assets it needs too.
Or build it from scratch with the bjs CLI:
- 1Scaffold a project
World, renderer, and dev server — ready to run.
- 2Install dependencies
- 3Add OrbitMover
Copies its source into src/ so the scene resolves.
First time? Run bjs login once.
- 4Paste the scene into src/scenes/arcade-room.ts and run
SceneLoader builds the world from the JSON; reload to rebuild.
Props
radius(number, default5) — orbit radius in world units.speed(number, default0.8) — angular speed in radians/second.centerX/centerZ(number, default0) — center of the circle on the ground plane.centerY(number, default0) — fixed height the mesh holds while it orbits.phase(number, default0) — starting angle in radians; stored as the liveangleand serialized back out asphase.faceMotion(boolean, defaulttrue) — when true, yaw the mesh around Y to face the direction of travel.
Dependencies
MeshPrimitive — supplies the mesh handle the System moves. The query requires both components, so an OrbitMover on an entity with no MeshPrimitive is inert.
Notes
- The System writes the new position into
mesh.position/mesh.rotationas well as calling the adapter, so a save mid-orbit captures where the mesh actually is. - An entity whose
MeshPrimitivehasn't resolved ahandleyet is skipped that frame rather than throwing — the orbit starts once the mesh exists. phaselets multiple movers share one center without overlapping: space them evenly (e.g.0,2.09,4.19for three) to spread them around the ring.




























































