A datapack adds custom behavior to a Minecraft world — give items, spawn mobs, react to where players stand — with no mods. Normally you write that in Minecraft's command language, which is picky and verbose. This tool lets you write the same thing in simple Python-like code and turns it into a ready-to-use datapack for you.
You don't need to know Minecraft commands or real Python. If you can copy the examples below and change a few words, you can build a pack.
datapack.zip.datapacks folder. Drop datapack.zip inside — no need to unzip it./reload in the chat.Edit the code, compile again, copy the new zip over the old one, and /reload to see changes. Your work autosaves in this browser, so it's still here when you come back.
Compile and Download builds the zip. Fix Indentation tidies up spacing if you pasted code and it looks crooked. Reset to Example brings back the starter script (this erases your current code).
Editor — where you write code. Functions — a searchable list of everything you can call; click a name to see how to use it. Guide — this help. Output — shows "success" or points to the line with a mistake after you compile. Each panel has a Hide button if you want more room.
Two simple rules:
Code that is not inside a def runs every tick (20 times a second) — use it for things that should keep checking, like "if a player stands on gold, do X".
Code inside def init(): runs once when the pack loads — use it for one-time setup, like starting a score at 0.
def init():
say("Pack loaded!") # once, on /reload
say("tick") # every tick (very spammy!)
Indentation (the spaces at the start of a line) is how the tool knows what belongs inside a def, with, or if — just like Python. Keep it consistent; Fix Indentation can help.
Most actions need to know who to affect, where in the world, or what item/block. These are the words you fill in:
Who: me, players, all, nearest, or near(zombie, distance=8).
Where: here, below, above, rel(0,-1,0), pos(10,64,0).
What: write ids directly. diamond_block compiles as minecraft:diamond_block.
An action is a single thing to do. You call it by name with details in the brackets:
give(me, diamond, 3) title(me, "Wave 1") effect(me, speed, seconds=10) summon(zombie, here, name="Tank", health=80, damage=8)
Don't remember them all — search the Functions panel and click any name for its example.
Use with and if to control who runs the action and when. Put the affected lines underneath, indented. This example tells every player standing on gold a message:
with as_players():
if block_is(below, gold_block):
tell(me, "on gold!")
raycast is built in. It casts from eyes or feet. Inside the block, here is the block position being aimed at; use offset to move along the look ray. through can be one block, a tag, or a list.
with as_players():
with raycast(max=40, offset=-1,
through=[air, cave_air, water]):
setblock(here, glowstone)
raycast_miss runs only if no solid block is hit before max range.
with as_players():
with raycast_miss(max=20):
summon(lightning_bolt, here)
raycast_entity finds the first matching entity near the ray. Inside the block, me is the hit entity and here is the ray position. Set stop_at_blocks=false for through-wall checks.
with as_players():
with raycast_entity(entities(zombie), radius=1):
effect(me, glowing, seconds=2)
raycast_entity_miss runs at max range when no entity is found.
sleep(20) waits 20 ticks. sleep("3s") waits 3 seconds. It schedules the rest of the function for later, so the game keeps running. Use it at top level, in def, or in with; avoid it inside if.
Assign values with normal Python-style syntax:
points = 0 # int - LIVE ready = true # bool - LIVE pi = 3.14 # float - constant name = "Hero" # string- constant spawn = vec3(0,64,0) # vec3 - constant
Live int/bool variables use scoreboards and can change while the pack runs:
points = points + 10 points = points * 2
Constants are fixed when you compile. Use them for config, names, and positions:
setblock(spawn, beacon) greeting = "Hi " + name
Lists stay static unless you mutate them. Static lists compile directly into commands, which is the fastest path:
pass_blocks = [air, cave_air, water]
with as_players():
with raycast(through=pass_blocks):
setblock(here, glowstone)
If you call a mutating method, the list becomes dynamic and is stored in storage. Dynamic setup usually belongs in def init():
def init():
pass_blocks = [air, cave_air, water]
pass_blocks.append(glass)
pass_blocks.insert(1, lava)
pass_blocks.remove_at(0)
pass_blocks.pop_end()
count = len(pass_blocks)
Use persist before the name when a dynamic list should survive reloads. Put the starting value in def init(); it is only applied the first time.
persist pass_blocks
def init():
pass_blocks = [air, cave_air, water]
with as_players():
if block_is(below, gold_block):
pass_blocks.pop_end()
Top-level assignments run every tick and will reset a dynamic list every tick, just like other top-level code.
Use f"..." strings when a message needs a variable value:
tell(me, f"Score: {points}")
actionbar(me, f"{name} has {points}!")
say() cannot show live variables; use tell() or actionbar().
Put color and style tags inside an f"..." string before the text they should affect:
tell(me, f"{gold}{bold}Score: {points}")
actionbar(me, f"{red}Low HP! {reset}{hp}/20")
title(me, f"{aqua}Wave {wave}")
Works in tell, title, actionbar, and item name/lore.
give(me, diamond_sword,
name=f"{aqua}{bold}Frostbite",
lore=[f"{gray}Frozen blade", f"{gold}+5 style"])
Colors: black, dark_blue, dark_green, dark_aqua, dark_red, dark_purple, gold, gray, dark_gray, blue, green, aqua, red, light_purple, yellow, white.
Styles: bold, italic, underlined, strikethrough, obfuscated. Aliases: underline, strike, magic. Use {reset} to go back to the command's default style.
Live variables reset on reload unless you mark them with persist before first use:
persist coins # kept across reloads
def init():
coins = 0 # first load only
tries = 0 # resets on reload
with as_players():
if block_is(below, gold_block):
coins = coins + 1
Only int/bool variables can persist.
give accepts common item fields directly: name, color, lore, enchant, unbreakable, model, attributes, and more. Use components={...} for raw item components.
give(me, diamond_sword,
name="Frostbite", enchant={sharpness:5},
model="my_pack:frostbite", unbreakable=true)
model sets the modern item_model component, which is the normal way to give an item a custom model in 26.1-26.2. For advanced item model predicates, use structured custom_model_data with strings, floats, flags, or colors:
give(me, stick,
custom_model_data={strings:["wand"]})
setblock accepts state={...} for block states, data={...} for block entity data, and command= for command blocks.
setblock(below, chest,
data={Items:[{slot:0, id:"minecraft:diamond", count:5}]})
raw_command("...") emits a Minecraft command unchanged, without the leading slash. It is a fallback, not the recommended way to write packs. If you need it because a command is missing, comment on the Reddit feedback post.
raw_command("weather clear")
Edits autosave in this browser.
Reset to Example restores the starter script.
Fix Indentation cleans pasted code across the whole file.
Function calls can span multiple lines when wrapped in (...), [...], or {...}.
Start typing for autocomplete; use the arrow keys and Enter.
Click a function for its signature and an example.
Edit the code, then click "Compile and Download" to get datapack.zip.