LeCodesdocs

Scenario aspects — ready-made behaviors

Five aspects that cover the basic "make the scene DO something" scenarios without writing code: travel to a point, run a waypoint circuit, spin, face a target, start a GLB animation. They're designed for the visual scene editor (attach from the Aspects menu, wire targets by picking nodes in the viewport), but they're ordinary aspects — node.aspect(MoveTo, { target }) from hand code works the same.

All motion runs per-frame in play mode. While a scene is being edited, aspects are inert — but the movement aspects draw their paths as editor-only lines (blue for movement, amber for look-at), so you can see and tune a route without running the scene.

The usual recipe pairs them with Empty nodes (plain group nodes — see scene-files.md): place an Empty where something should go, then point the aspect at it. On a camera node, the same aspects become camera moves.

MoveTo

Travel from the node's starting position to a target node.

Field Default Meaning
target null Destination node (ref('name') in scene files)
duration 2 Seconds for the full trip
delay 0 Seconds to wait before starting
mode 'once' 'once' stop there · 'loop' restart from the start point · 'pingpong' back and forth
easing 'smooth' 'smooth' ease-in-out · 'linear' constant speed

The target is tracked live — if it moves, the trip bends toward its new position (and once keeps the node pinned to it after arriving).

TypeScript
crate: {
  mesh: { kind: 'box', size: [1, 1, 1] },
  position: [0, 0.5, 0],
  aspects: [use(MoveTo, { target: ref('dropPoint'), duration: 3, mode: 'pingpong' })],
},
dropPoint: { position: [4, 0.5, -2] },   // an Empty

FollowPath

Travel through the children of a path node, in scene-file order — add an Empty per waypoint.

Field Default Meaning
path null The node whose children are the waypoints
duration 6 Seconds for one full pass
delay 0 Seconds to wait before starting
mode 'loop' 'loop' closed circuit (last → first) · 'once' stop at the last point · 'pingpong' back and forth along the open path
orient true Turn to face the direction of travel
forward '-z' Which local axis leads when orienting

Speed is constant along the whole path (segment lengths are measured live, so dragging a waypoint retimes the run correctly). GLB models usually face +z — flip forward if your model drives backwards.

TypeScript
bus: {
  model: asset('./bus.glb'),
  aspects: [use(FollowPath, { path: ref('route'), duration: 12, forward: 'z' })],
},
route: {
  position: [0, 0, 0],
  children: {
    stop1: { position: [0, 0, 0] },
    stop2: { position: [8, 0, 2] },
    stop3: { position: [5, 0, 8] },
  },
},

Spin

Continuous rotation about a local axis — speed degrees per second, axis 'x' | 'y' | 'z' (default 'y'). Composes in quaternion space, so it's correct on pre-rotated nodes.

LookAt

Keep the node facing a target node each frame.

Field Default Meaning
target null The node to face
forward '-z' Which local axis points at the target
smoothing 0 0 snaps instantly; otherwise seconds of turn lag (bigger = slower)

A turret tracking the player, a signpost, or — on a camera node — a camera that keeps a moving hero framed while FollowPath drives the crane.

PlayAnimation

Start a GLB clip when the scene runs. Attach to a model: node.

Field Default Meaning
clip '' Clip name; empty = the model's first clip
loop true Loop the clip
speed 1 Playback rate

In the editor its inspector card lists the model's clips in a dropdown and can Preview/Stop the clip live while editing. For runtime control (switching clips from your own code, seek, events) use model.anim directly — this aspect only presses play at load.