Run Bloxd world code on your own computer, without Bloxd. Catch typos, bad arguments and known engine traps before you paste anything into a world.
Made by Oreo_belt25 with Claude. Free to use and change, just give a shoutout.
| File | What it does |
|---|---|
mkmock.py |
Reads the editor's TypeScript declarations (or, as a fallback, the docs pages) and writes bloxd_api.json : every api function with its parameters, which ones are optional, and its return type, plus every callback |
bloxd_api.json |
The generated description: 247 functions (95 optional parameters marked) and 80 callbacks, from bloxd-types 0.1.2, checked identical to the live editor's types on 25 Sep 2026 |
mock_api.mjs |
Builds a fake api object from that JSON |
quirks.mjs |
Places where the real engine disagrees with the docs, found by testing in-engine |
run.mjs |
Command-line runner: loads your world code, simulates players and ticks, prints a report |
selftest.mjs |
45 checks that the mock still catches what it should. Run node selftest.mjs after any change |
broken_world.js |
A deliberately broken file to see the report in action |
quirk_probe_1.js |
World code that re-checks every rule in quirks.mjs in a real Bloxd world. Paste it into a test world and type!help |
- Node.js 18 or newer
- Python 3 (only to regenerate
bloxd_api.json). On Windows the command is usuallypythonorpyinstead ofpython3. Without Python, the twomkmock.pyself-test checks are skipped and everything else still runs
No packages to install.
node run.mjs my_world.js
node run.mjs my_world.js --players 4 --ticks 400
node run.mjs my_world.js --chat "!help" --chat "p2:!stats" -v
The runner joins the players, runs the tick loop (20 ticks = 1 second), sends any chat messages halfway through, then prints:
- which callbacks your code defines
- total api calls, the average per tick, and the busiest tick with what was called on it (useful for spotting work that should be spread across ticks)
- errors thrown inside callbacks (typos, calls that crash in-engine)
- warnings (arguments the docs or the engine won't accept)
Options: --players N, --ticks N, --chat MSG (repeatable), --null off|warn|throw,
--null-returns (every "possibly null" function returns null, to test your null guards),
--timeout-ms N (how long one callback may run, default 10000),
--fire NAME (fire any callback once halfway through, with placeholder arguments
built from its documented parameters; repeatable),
-v to print everything shown to players (chat, middle and crosshair text,
flying messages, popups, killfeed, and HUD text options like RightInfoText;
HUD text re-set unchanged every tick is printed once), --json for machine-readable output.
The exit code is 2 if any callback threw, so it works in scripts.
The editor's types become data.mkmock.py reads the same TypeScript
declarations the Bloxd code editor uses for autocomplete, so it knows exact
types and which arguments are optional. (It can also read the plain-text docs
pages, which don't mark optional arguments.) Each
function's documented return type is mapped to a placeholder: anumber returns 0, an inventory item returns{name: "Stone", amount: 1, attributes: {}} ,
and so on. Ids are fresh on every call (m_mock_1 ,m_mock_2 ...), so two
spawned mobs never share an id. "Possibly null" (PNull<...> ) functions
return a real value by default, so spawns succeed and the happy path runs;--null-returns flips them all to null to check your guards.
2.
Every call is checked. Too many or too few arguments (a required one left
out), null where the types don't allow it, explicitundefined in the middle of an argument list, and oversized
arguments all get flagged. Calling a function that isn't in the docs throws,
which catches typos likeapi.sendMesage .
3.
Some functions really work. Player lists, player and lobby DB values,
positions,getBlock /setBlock andapi.now() keep real state, so most
world code runs normally instead of falling over on placeholder values.
4.
The clock behaves like Bloxd's.Date.now() is frozen for the whole tick
and jumps 50 ms between ticks, as it does in-engine. A "stop after 5 ms" loop
budget never trips in Bloxd, so when one callback readsDate.now() hundreds of times in a single call, the report flags it with a[clock] warning before it lags a lobby.
Like the engine, any callback that runs for about 10 s is stopped and
reported asInternalError: interrupted , so an infinite loop shows up as
an error instead of freezing your terminal. The mock then stops firing
that callback for the rest of the run.
5.
Callback return values are checked. The Callbacks page lists what each
callback may return. Returning something else, such as"preventchange" instead of"preventChange" , does nothing in-engine, so the mock warns and
suggests the right spelling. Callbacks whose documented return includes a
named object type are skipped rather than risk a false warning.
6.
Engine findings override the docs.quirks.mjs holds behaviour confirmed
by in-engine probes that contradicts or goes beyond the docs. Every rule was
re-checked in-engine on 27 Sep 2026 byquirk_probe_1.js . Examples:
- returning
nullfrom a callbackprevents the action: a block change, a drop, or a hit on a mob or player, just like the documented"prevent..."strings. Return nothing to allow it. The typo"preventchange"is ignored setItemSlotand both chest functions reject amount-1, although the docs suggest itsetMobSetting(..., "heldItemName", null)is the correct way to clear it;""throwssetMobAiStateneeds an explicitnullfor paramsgetCraftingRecipesForPlayerthrows an errortry/catchcan't catch- an
{icon}in a player's name tag is rejected, although the types allow it setItemStat'sCrosshairTextand bowsecondaryDamageare accepted but do nothing- a
ParticleEmitterattached to an entity node, and a meshBoxwith onlyemissiveColor, are accepted but draw nothing "peacefulAdventure"is rejected; gamemode names are all lowercaseisNearInterruptdoes turn true late in a long callback; the mock says true once a callback has used 80% of--timeout-msThe probe also caught four rules Bloxd had fixed, which the mock no longer flags:animateEntity(id, null),giveItemwith an explicitundefined,getHeldItemwithoutattributes, and hand-builttameInfo.
- returning
import { makeMockApi } from "./mock_api.mjs";
const mock = makeMockApi({
players: ["p1", "p2"],
overrides: { getBlock: () => "Stone" }, // replace any function
});
mock.api.setPlayerDbValue("p1", "coins", 5);
mock.api.getPlayerDbValue("p1", "coins"); // -> 5
mock.countCalls("setPlayerDbValue"); // -> 1
mock.warnings; // anything suspicious
From the editor's types (recommended). The npm package bloxd-types
mirrors the declarations built into the Bloxd code editor (checked line by
line against the live editor on 25 Sep 2026: identical apart from a few
//@ts-ignore comments). With Node installed:
npm pack bloxd-types # downloads bloxd-types-<version>.tgz
tar xzf bloxd-types-*.tgz # unpacks to package/
python3 mkmock.py --dts package/types/@bloxd/index.d.ts package/types/@bloxd/globals.d.ts
If the package ever falls behind, you can pull the same files out of the
editor: open World Code, press F12, go to Sources, press Ctrl+Shift+F and
search for interface GameApi. The matching script holds the declarations as
a block of text.
From the docs text (fallback). Copy the API Reference and Callbacks pages
from bloxd.io/docs into text files (select all, paste into a .txt), then:
python3 mkmock.py API_Reference.txt Callbacks.txt
This works, but the docs text doesn't say which arguments are optional, so the "missing required argument" check is switched off.
Either way, if far fewer entries than expected turn up (under 200 functions or 70
callbacks), mkmock.py prints a warning and does not overwrite bloxd_api.json,
since that usually means a cut-off paste or a changed layout. Pass --force to write it anyway.
-
Single-file world code only. Files using
import/exportaren't supported yet. -
Most callbacks only run if you ask. Join, tick, chat and leave fire automatically; anything else needs
--fire NAME, and gets placeholder arguments (playerp1, coordinates 0, block"Stone", shop keys"mock_category"/"mock_item", and a sensible value for other string or number types). -
Placeholders aren't real game state. Functions without built-in behaviour return a placeholder, so code that depends on, say, real mob positions won't behave as it would in a world. Use
overridesto fake what you need. -
Only as good as the docs plus the quirks list. Where the docs are wrong and nobody has probed it yet, the mock is wrong too. Test in-engine before shipping.
-
Use the full types for basic type checks (a number passed where an item name belongs, a string where coordinates belong).
-
Print where the docs and the editor's types disagree, as a doc-bug report.
-
Support multi-file world code.
-
Grow
quirks.mjsas more engine behaviour gets confirmed, and re-runquirk_probe_1.jsafter each Bloxd update.