Script the world
Game scripts are ES modules evaluated by GraalJS. AtlasEngine injects a focused minestom bridge and resolves modules from ae2/stdlib/*. Scripts do not receive Node.js filesystem or network access.
A minimal entrypoint
import { on, onServerStart } from "ae2/stdlib/events";
onServerStart(() => {
minestom.world.setTime(1000);
minestom.world.setWeather("clear");
console.log("game ready");
});
on("playerJoin", ({ uuid, username }) => {
minestom.players.teleport(uuid, { x: 0, y: 42, z: 0 });
minestom.players.showTitle(uuid, "Welcome", username);
});
If a script is loaded after the server has already started, onServerStart runs its callback immediately.
Events
Use on(name, handler) for game-wide orchestration. The runtime exposes player, entity, block, item, projectile, region, quest, UI, tag, and world-time events.
| Event | Typical payload |
|---|---|
playerJoin | { uuid, username } |
playerMove | { player, from, pos } |
itemUse | { player, item, itemModel } |
blockInteract | { player, pos, block, face } |
mobDeath | { mobId, id } |
regionEnter | { player, region, world } |
uiClick | { ui, widget, player, slot, clickType } |
Resource behavior modules use on from ae2/stdlib/behavior. Those handlers are automatically scoped to the behavior's item, block, mob, region, quest, or UI.
Scheduling
AtlasEngine schedules in server ticks. Twenty ticks is one second.
import { everyTicks } from "ae2/stdlib/events";
minestom.schedule(40).then(() => {
minestom.broadcast("Two seconds later");
});
everyTicks(20, () => {
// once per second
});
Reloading a game clears scheduled callbacks so code from a closed script context cannot fire later.
Runtime surfaces
| Surface | Use it for |
|---|---|
players | Teleport, inventory, health, game mode, titles |
world | Blocks, time, weather, positions |
mobs and entities | Spawn, inspect, damage, remove |
navigation | Pathfinding targets and profiles |
projectiles | Shoot and control projectiles |
quests | Player quest state, rewards, visibility |
ui | Open schema-defined inventory interfaces |
board and bossbar | Persistent HUD elements |
droptables | Roll typed drop definitions |
cmd | Register reload-safe game commands |
The web editor gets completion and signatures from the same bridge contract the server registers.
State
Use module variables for state owned by one script context. Use the shared tag store for small scalar values that need to cross between the main script and behavior contexts.
const store = minestom.store();
store.set("round", "active");
const round = store.get("round");
store.delete("round");
Keep domain logic in ordinary modules when possible. Pure state machines and geometry functions can run in Node tests without booting Minecraft.
The game loop runs at 20 TPS. Prefer engine facades and scheduled work over large per-tick scans, blocking operations, or unbounded loops.