Practical Tools
You may need some basic concepts to write PonderJS comfortably, and a few practical tools to speed up scene creation.
What Is a Ponder Scene?
A Ponder scene is not a mini-world/dimension. It is only a scene renderer with specific behaviors.
Block entities and normal entities inside it are not ticked, and multi-state texture animations do not auto-update.
That means basin auto-output, block state visual updates, entity interaction animations, and similar effects must be scripted manually.
The following snippet is from the official Forge Create source:
Create/src/main/java/com/simibubi/create/infrastructure/ponder/scenes/ProcessingScenes.java (Ponder scene for compacting with a Mechanical Press):
BlockPos basin = util.grid.at(1, 2, 2);
BlockPos pressPos = util.grid.at(1, 4, 2); // Mechanical press position
Vec3 basinSide = util.vector.blockSurface(basin, Direction.WEST); // Basin side
ItemStack copper = new ItemStack(Items.COPPER_INGOT); // Copper item
ItemStack copperBlock = new ItemStack(Items.COPPER_BLOCK); // Copper block item
scene.overlay.showText(60)
.pointAt(basinSide)
.placeNearTarget()
.attachKeyFrame()
.text("Pressing items held in a Basin will cause them to be Compacted");
scene.idle(40);
scene.overlay.showControls(new InputWindowElement(util.vector.topOf(basin), Pointing.DOWN).withItem(copper),
30);
scene.idle(30);
Class<MechanicalPressBlockEntity> type = MechanicalPressBlockEntity.class;
scene.world.modifyBlockEntity(pressPos, type, pte -> pte.getPressingBehaviour()
.start(Mode.BASIN)); // Start pressing
scene.idle(30); // Wait for pressing animation (yes, this is the way)
scene.world.modifyBlockEntity(pressPos, type, pte -> pte.getPressingBehaviour()
.makeCompactingParticleEffect(util.vector.centerOf(basin), copper)); // Generate pressing particles
scene.world.modifyBlockEntityNBT(util.select.position(basin), BasinBlockEntity.class, nbt -> {
nbt.put("VisualizedItems",
NBTHelper.writeCompoundList(ImmutableList.of(IntAttached.with(1, copperBlock)), ia -> ia.getValue()
.serializeNBT()));
}); // Add VisualizedItems NBT to basin to produce output animation
scene.idle(4); // Wait for item drop animation
scene.world.createItemOnBelt(util.grid.at(1, 1, 1), Direction.UP, copperBlock);// Spawn the basin output item "falling" onto the belt
scene.idle(30);As shown above, in Ponder you do not place machines, supply power, and get automatic processing like normal gameplay.
All animations/events are manually driven.
So in PonderJS, these animations are also implemented manually:
onEvent("ponder.registry", (event) => {
event.create("minecraft:raw_iron_block") // Raw iron block
.scene(
"potato_raw_block_scene",
"Potatoes and raw iron block...",
"kubejs:potato_raw_block_scene",
(scene, util) => {
const $BasinBlockEntity = java('com.simibubi.create.content.processing.basin.BasinBlockEntity');
const $MechanicalPressBlockEntity = java('com.simibubi.create.content.kinetics.press.MechanicalPressBlockEntity');
const $PressingBehaviour = java('com.simibubi.create.content.kinetics.press.PressingBehaviour');
var depot = util.grid.at(1, 0, 0);
var basin = util.grid.at(1, 1, 1);
var press = util.grid.at(1, 3, 1);
scene.world.setFilterData(basin, $BasinBlockEntity, Item.of("minecraft:air"));
scene.world.modifyBlock(basin, state = state.with("facing", "down"), false);// Basin output direction corresponds to the block state's facing
scene.world.showSection(basin, Direction.UP);
scene.idle(20);
scene.overlay.showoutline(PonderPalette.GREEN, new Object(), basin, 30);
scene.overlay.showFilterslotInput(util.vector.of(1.5, 1.75, 1), Direction.NORTH, 30);
scene.idle(20);
scene.world.setFilterData(basin, $BasinBlockEntity, Item.of("minecraft:raw_iron_block"));
scene.idle(40);
scene.addKeyframe();
let potato = scene.world.createItemEntity([1.5, 2.5, 1.5], [0, 0, 0], "9x potato");
scene.idle(7);
scene.world.modifyEntity(potato, e => { e.kill(); });// Remove dropped item after it falls into the basin
scene.idle(40);
scene.world.setkineticSpeed(press, 64);
scene.world.showSection(press, Direction.DOWN);
scene.world.showSection(depot, Direction.SOUTH);
scene.idle(15);
scene.world.modifyBlock(basin, state = state.with("facing", "north"), false);
scene.addKeyframe();
scene.world.modifyBlockEntity(press, $MechanicalPressBlockEntity, pte => { pte.getPressingBehaviour().start($PressingBehaviour.Mode.BASIN); })
scene.idle(13);
// In 1.18.2, appending NBT failed here, so a dropped-item workaround is used
let raw_iron_block = scene.world.createItemEntity(util.vector.centerof(basin), [0, -0.2, -0.25], "raw_iron_block");
scene.idle(5);
scene.world.modifyEntity(raw_iron_block, e => { e.kill(); });// Remove dropped item after it falls onto the depot
scene.world.createItemOnBeltLike(depot, Direction.UP, "raw_iron_block");// Spawn the basin output item "falling" onto the depot
scene.idle(10);
}
);
});How to Implement a Specific Effect
Ponder is designed by Create to explain its own systems, so effects not shown in official Ponder scenes are usually hard or impossible to reproduce.
But this suggests a good workflow:
If you want a specific effect, first find an official Ponder scene that already does it.
Then locate its implementation in the .
Finally, translate that logic into JS.
Do not forget ProbeJS. When confused, reading Create’s source is often the fastest way forward.
scene utils
For easier positioning/selection in scenes, Ponder provides a util object in addition to scene:

Methods in util.grid select a single position.
util.select selects an area.
util.vector selects a specific vector (for example, the facing of one block side).
The rest is already covered clearly by ProbeJS hints and official usage.