Docs
Coming in the next release
New APIs that are written and documented but not released yet. Each lands in the next release; names and details can still change until then.
Coming in the next release
Send an event to one entity
ctx.events.emitTo(target, name, data?)Like ctx.events.emit, but only the target's behaviors hear it: their onEvent and the listeners they subscribed, at the end of the tick. A target that is no longer alive is heard by nobody. A timer can aim at one entity too, with { to }. Sending a hit to its target, rather than to everyone, cuts a 500-player volley from 946 ms of script to under 50 ms.
TypeScript or JavaScript // Only the entity that was hit hears it. ctx.events.emitTo(target, "hit", { damage: 10 }); // A timer can aim at one entity as well. ctx.time.after(2, "respawn", null, { to: target });Coming in the next release
Hear every entity's events
ctx.events.on(name, handler, { every: true })A character controller's land, jump, moving and idle events now reach only the behaviors on that character, so a crowd landing at once no longer calls every behavior in the scene. To hear every character's (a referee, a crowd director, a test), subscribe with { every: true }, on on or once. This changes behavior: a script that listened for another character's controller events needs the option.
TypeScript or JavaScript // A referee counts every landing, not only its own. ctx.events.on("land", (ev) => { landings[ev.by] = (landings[ev.by] ?? 0) + 1; }, { every: true });Coming in the next release
The nearest match from a query
ctx.world.query({ ..., sort: "distance", limit })sort: "distance" puts the nearest entity first and needs near; limit keeps the first that many, after the sort. Together they find the nearest enemy, with the sorting done in the engine, so the script never reads every match's position. Entities at exactly the same distance keep a fixed order, so two runs, and two players in the same session, get the same answer. Distance is measured from each entity's position, not from its collider. Any other sort, or sort without near, is a TypeError; a limit that is not a whole number of 0 or more is a RangeError.
TypeScript or JavaScript const [nearest] = ctx.world.query({ tag: "enemy", near: ctx.entity, radius: 30, sort: "distance", limit: 1, });Coming in the next release
One preset for networked play
HostConfig::networked()Multiplayer is coming, not in this release; this is the preset its sessions will use. A rollback session will run its scripts under one preset, so every player's machine will stop a runaway script at the same point, and players will compare a fingerprint of the preset when they connect and refuse a mismatch. The preset counts function calls in the work budget, limits calls to 256 deep (write a deep recursion with an explicit stack instead), and refuses async code and shared memory. With a browser player in the session, add with_web_peers(): every player then gets only the script features the browser serves, so all of them behave the same.
Rust // Native players only: let config = HostConfig::networked(); // With a browser player in the session: let config = HostConfig::networked().with_web_peers();Coming in the next release
Global illumination only when it can light something
rayTracing.giAlwaysThe high-definition renderer now skips global illumination on frames where every surface is unlit. The picture is the same, pixel for pixel. The first frame with lit content turns it on for the rest of the run. Set giAlways to keep it on from the first frame.
Settings "rayTracing": { "gi": true, "giAlways": true }