TrajectoryPreview
The aim line for a MassDriver: a dashed path showing where the next shot goes, coloured by how it ends.
What it does
Every frame the preview flies a ghost body from its MassDriver's muzzle at the launch velocity, through the pull of every static GravityMass, and draws the path as dashes: green into a CaptureZone, red into a solid mass, violet into an absorbing one such as a black hole, and blue when it is still flying or leaves the field. A crash or a swallow also gets an X where it ends.
The ghost moves by GravityBody's own step function at GravityBody's fixed 1/120 s step, and settles each step in the order play does: move, wormhole, mass contact, then capture zones through CaptureZone's zoneAt. Simpler maths of its own would lie at the edges. With the maths shared, a step that reaches the plant and touches a black hole beside it is a swallow both on the line and in play, and a rock fired with no spread through a still field flies the line exactly.
Static means masses that are not GravityBodies. Rocks in flight are left out, so the line shows what a lone rock would do instead of flickering whenever two pass. A ship on its orbit or a black hole being dragged is read where it is this frame, so the line moves with it.
Wormholes are followed too, and the dashes break at the jump instead of streaking across the field. When the ending changes the System emits trajectory.outcome.changed, so a HUD can say ON TARGET without drawing anything.
Setup
The engine work ships with the component, in adapter/register.ts. A project made with bjs create installs it for you: src/main.ts calls every adapter/register.ts that bjs download puts in the project, before the scene loads. If you boot the game from your own code, call it once, right after building the adapter:
The plugin draws the dashes thick and glowing. Without it the System draws them one pixel wide with the engine's plain line system, and warns once. The plugin is for BabylonAdapter only; with any other adapter the call does nothing.
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:
- 1Scaffold a project
World, renderer, and dev server — ready to run.
- 2Install dependencies
- 3Add TrajectoryPreview
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.
In Space Golf the director sets seconds from each level's previewSeconds, and bounds from its own field.
Props
seconds(number, default5) — seconds of flight to predict. Shorter is harder.dashes(number, default70) — dashes the path is cut into, at least 1.dashFill(number, default0.55) — share of each dash slot that is drawn, kept between 0.05 and 1.bodyRadius(number, default0.3) — radius the ghost collides with.maxSpeed(number, default60) — speed cap.bounds([x, y, z], default[0, 0, 0]) — half-extents of a box round the origin. Leaving it is an escape. Any zero turns the test off.captureColor([r, g, b], default[0.3, 1, 0.55]) — ends in a capture zone.crashColor([r, g, b], default[1, 0.35, 0.3]) — ends on a solid mass.swallowColor([r, g, b], default[0.75, 0.45, 1]) — ends in an absorbing mass.openColor([r, g, b], default[0.55, 0.75, 1]) — still flying whensecondsruns out, or escaped.visible(boolean, defaulttrue) — draw the line. The event fires either way.width(number, default0.22) — line width in world units, read by the plugin when it first draws the line.
Events
Emits:
trajectory.outcome.changed—{ entityId, outcome, targetId }.outcomeiscapture,crash,swallow,escapeoropen;targetIdis the zone or mass the path ends on, or empty. It fires on the first frame, when the ending or its target changes, and when a pooled driver comes back into play.
Listens to nothing.
Dependencies
MassDriver— required on the same entity: muzzle, direction and speed.GravityMass— the masses that bend the line.MeshPrimitive— every position the preview reads.GravityBody— its step function.Wormhole— its pass between mouths.CaptureZone— its zone test.
Notes
- The line is the centre of the launch cone. With MassDriver
spreadabove 0, real rocks scatter a little around it. - Match
bodyRadiusandmaxSpeedto the rock's GravityBody (in Space Golf,0.42and45), or the line and the flight part ways. - Every live zone counts as a goal whatever its
acceptTag, because the ghost has no tags. GravityBody does check the tag, so a zone that takes something else shows a capture the rock flies through. - Parking the driver hides its line until the driver is handed out again; destroying the driver disposes it.
- In a world with no renderer the preview does nothing at all, so a headless test hears no outcome event.











































