-
Notifications
You must be signed in to change notification settings - Fork 0
2.1 Code
Scripts are plain JavaScript files placed anywhere under worlds/my_world/mod/.
All .js files are loaded recursively on startup, sorted alphabetically. One bad
script does not block the others — errors are logged and that script is skipped.
If you are new to JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide
worlds/
my_world/
mod/
my_script.js ← loaded
ui/
hud.js ← also loaded
inventory.js ← also loaded
Load order is alphabetical within each folder, parent folders before subfolders.
If one script needs globals set by another, prefix filenames: 00_lib.js, 01_feature.js.
Four objects are injected into every script automatically. You cannot access arbitrary Java classes — only what is listed here.
| Global | Purpose |
|---|---|
Scene |
Create/move/destroy 3D objects in the world |
Block |
Read and edit voxel blocks |
Engine |
Register per-tick callbacks |
Gui |
Create screen-space text elements |
All Scene methods operate on handles — opaque numbers that refer to a scene node. Never try to store or manipulate the underlying Java object; always go through the handle.
Handle 0 is the world root node. Attach your objects there unless you
have a specific parent in mind.
// createNode(name) → handle
const group = Scene.createNode("myGroup");
// createCube(name, size) → handle
// size is the full edge length, e.g. 1.0 = a standard voxel-sized cube
const cube = Scene.createCube("myCube", 1.0);
// attachChild(parentHandle, childHandle)
Scene.attachChild(0, group); // attach group to world root
Scene.attachChild(group, cube); // attach cube under group
// setPosition(handle, x, y, z)
Scene.setPosition(cube, 10, 5, 0);
// getPosition(handle) → [x, y, z] (world position, not local)
const p = Scene.getPosition(cube);
const wx = p[0], wy = p[1], wz = p[2];
// setColor(handle, r, g, b, a) — values 0..1
Scene.setColor(cube, 1, 0, 0, 1); // red
// destroy(handle) — removes from scene and frees the handle
Scene.destroy(cube);
// getBlockId(x, y, z) → int — read-only voxel query at integer block coords
const id = Scene.getBlockId(10, 4, 0);Read and write voxel blocks. Changes trigger a mesh rebuild for the affected chunk and its neighbors automatically.
// get(x, y, z) → int
const id = Block.get(10, 4, 0);
// place(x, y, z, blockId)
Block.place(10, 5, 0, 2); // place stone
// destroy(x, y, z)
Block.destroy(10, 5, 0); // set to air| ID | Name |
|---|---|
| 0 | Air |
| 2 | Stone |
| 3 | Dirt |
| 4 | Grass |
| 5 | Crystal Ore |
| 6 | Ice Sludge |
| 7 | Silicon |
| 8 | Sulfur |
| 9 | Metal Block |
| 10 | Glass |
for the newest see this java class
Register a function to run on a specific tick group. The engine only ticks named groups — if your tag is not in the game's tick list, your callback only fires when a GUI element with that tag is clicked (see Gui below). Ask a developer to add your tag to the main tick loop if you need it to run every frame.
// Engine.onTick(fn, tag)
// fn receives (tpf, tag):
// tpf — time per frame in seconds (use for frame-rate independent movement)
// tag — the tag this callback was registered under
Engine.onTick(function(tpf, tag) {
const p = Scene.getPosition(cube);
Scene.setPosition(cube, p[0], p[1] + tpf, p[2]); // float upward
}, "myFloatingCube");A tag can have multiple callbacks — all of them fire when that group ticks. Callbacks that throw 5 times in a row are automatically disabled with an error in the log.
Create screen-space text. Coordinates are normalized: 0,0 = bottom-left,
1,1 = top-right. Draw order matches the element list — elements added later
draw on top. toTop/toBottom reorder an existing element.
guiWord is upsert by tag — calling it again with the same tag updates the
existing element instead of creating a duplicate. Call it from your tick callback
every frame to animate text.
// guiWord(word, x, y, z, sizePixels, tag) → handle
// z is reserved for future use — pass 0 for now
const handle = Gui.guiWord("Hello world", 0.5, 0.9, 0, 0.02, "myLabel");
// setColor(handle, r, g, b, a)
Gui.setColor(handle, 0, 1, 0, 1); // green
// toTop(handle) / toBottom(handle) — reorder in draw list
Gui.toTop(handle);
Gui.toBottom(handle);
// removeWord(handle) — removes the element entirely
Gui.removeWord(handle);
// getHandleByTag(tag) → handle — look up a handle you may have lost
const h = Gui.getHandleByTag("myLabel");Every GUI element is clickable. When clicked, the engine fires tick(tpf, tag)
for that element's tag — so a button is just a guiWord whose tag matches a
registered Engine.onTick callback:
const btn = Gui.guiWord("[ Place Stone ]", 0.5, 0.05, 0, 0.025, "placeStoneBtn");
Gui.setColor(btn, 0.4, 0.8, 1.0, 1.0);
Engine.onTick(function(tpf, tag) {
Block.place(10, 5, 0, 2);
Gui.setColor(btn, 0, 1, 0, 1); // flash green on click
}, "placeStoneBtn");Click dispatch and regular per-frame ticking share the same callback — your function runs both when the group ticks normally and when the element is clicked. Design callbacks to be idempotent where possible.
// worlds/my_world/mod/ground_indicator.js
// Colors a cube green when over solid ground, red when over air.
const cube = Scene.createCube("indicator", 0.5);
Scene.attachChild(0, cube);
Scene.setPosition(cube, 10, 20, 0);
const label = Gui.guiWord("...", 0.5, 0.95, 0, 0.02, "groundLabel");
Engine.onTick(function(tpf, tag) {
const p = Scene.getPosition(cube);
const blockBelow = Scene.getBlockId(
Math.floor(p[0]),
Math.floor(p[1]) - 1,
Math.floor(p[2])
);
if (blockBelow !== 0) {
Scene.setColor(cube, 0, 1, 0, 1); // green — solid ground
Gui.guiWord("Ground: solid", 0.5, 0.95, 0, 0.02, "groundLabel");
} else {
Scene.setColor(cube, 1, 0, 0, 1); // red — air below
Gui.guiWord("Ground: air", 0.5, 0.95, 0, 0.02, "groundLabel");
}
}, "groundCheckLabel");- Scripts run on the render thread. Do not spin-wait or do heavy computation
inside
Engine.onTick— keep callbacks short. - Scripts share one GraalVM context. A global variable you declare in one script
is visible in all scripts loaded after it. Use unique names or wrap in an IIFE
(
(function(){ ... })()). - No filesystem, network, or Java class access from scripts.
-
console.logoutput appears in the game's standard output.
- Home
- How to play?
- How to code modifiers using JavaScript?
- jVisualScripting (still in construction 🚧)
- Source Code
- Versions
- Downloads(not working yet) Scroll down to bottom of the release card and click the assets, select .jar/... and download. For more see install page
MtSharpGrain