The TypeScript script API
Scripts live in a project's scripts/ directory and import from pocket.
They run as stateless systems on QuickJS-ng. Mutable state belongs in components;
module scope contains constants, functions, and declarations.
Declare components
import { component, field } from "pocket";
export const Tally = component("Tally", {
version: 1,
doc: "Crates aboard.",
fields: {
taken: field.u32(0, "Crates collected."),
total: field.u32(0, "Crates adrift at the start."),
worth: field.u32(0, "Cargo value aboard."),
},
});
Fields include numbers, booleans, enums, entity references, strings, vectors, and quaternions. Bump a component's version when changing its fields.
Query and update in systems
The sailing sample's Log component stores distance. This system is an abridged example
from that project:
import { system } from "pocket";
export const log = system({
name: "log",
phase: "update",
queries: {
boats: {
with: ["Boat", "Log"],
fields: ["Boat.speed", "Log.distance"],
},
},
run(ctx, { boats }) {
const speed = boats.cols.Boat.speed;
const distance = boats.cols.Log.distance;
boats.each((row) => {
distance[row] += Math.abs(speed[row]) * ctx.dt;
});
},
});
Rows are ordered by entity id. Query columns are typed arrays; changes are written back when
run returns. fields: [] requests no columns, while omitting fields requests all fields.
Assemble the game
import { game } from "pocket";
import { Crew, Tally, Log, Cargo } from "./components";
import { muster, log, takeAboard } from "./rules";
export default game({
components: [Crew, Tally, Log, Cargo],
systems: [muster, log, takeAboard],
});
Use explicit system order. A system can run once with when: "start", or periodically with
when: { every: 10 }.
World, events, and time
| API | Purpose |
|---|---|
ctx.world.get(entity, "Tally") |
Read a frozen component copy |
ctx.world.set(entity, "Tally", { taken: 1 }) |
Stage a checked component write |
ctx.world.insert / remove |
Add or remove a component |
ctx.world.spawn / despawn |
Create or remove an entity |
ctx.emit("crate.taken", data, { subject }) |
Emit a causal event |
ctx.tick, ctx.dt, ctx.time |
Read deterministic simulation time |
ctx.rngFor(entity) |
Use an entity's reproducible random stream |
Writes are applied when a system finishes, and discarded if it throws. Rendering does not
write simulation state. Use the simulation clock and seeded random streams rather than
Date, async code, or mutable top-level variables.
Generated types and checks
./target/release/pocket scripts types --host http://127.0.0.1:7878
./target/release/pocket scripts check --host http://127.0.0.1:7878
./target/release/pocket scripts apply --host http://127.0.0.1:7878
The host writes declarations to the project's .pocket/types/. They describe engine and
project components; do not maintain a second handwritten component declaration file.
See the complete SDK guide for field representations, diagnostics, and common mistakes.