Wiki 9Minecraft Wiki 9Minecraft

Generating Spheres with Commands and Scripts

Patterns for building solid and hollow block spheres in Bedrock Edition using commands or the Script API.

6Sections
5Code examples
4Known errors

Minecraft Bedrock Edition does not have a built-in `/sphere` command, because native volume commands like `/fill` and `/clone` only operate on axis-aligned bounding boxes. When you need spherical craters, domes, or brush tools in an add-on or map, you have to approximate a sphere by combining radial entity placement with commands or by calculating block coordinates directly in the `@minecraft/server` Script API. This page covers both the pure-command approach using local coordinates and the scripted voxel approach.

Why Bedrock lacks a native sphere command

Every native block-placing command in Bedrock Edition works on a rectangular grid. `/setblock` targets a single integer coordinate, and `/fill` takes two opposite corners of a cuboid. While target selectors have radial arguments like `r` (maximum radius) and `rm` (minimum radius) that define spherical detection zones, those arguments only filter entities—they cannot be passed directly to `/fill` to mask out a block volume.

Because of that limitation, generating a sphere requires translating spherical math into individual block updates. You have three practical ways to do this in a Behaviour Pack: rotating an entity across pitch and yaw angles while placing blocks at a fixed local distance (`^ ^ ^radius`), running a pre-calculated list of `/setblock` and `/fill` offsets inside an `.mcfunction` file, or looping over a 3D bounding box in JavaScript and testing each block's Euclidean distance from the center. The right choice depends on whether you need a fixed-radius effect, an interactive world-building brush, or a massive structure that must not freeze the server tick.

MethodBest ForDrawbacks
Entity Rotation (`^ ^ ^r`)Quick in-game carving or hollow shells without a Behaviour PackSlow to complete; leaves gaps at large radii if step angles are too wide
Static `.mcfunction` OffsetsFixed-size bombs, spells, or arena hazards that trigger instantlyRadius is hardcoded; requires a separate function file for each size
Script API (`@minecraft/server`)Dynamic world-edit brushes, variable radii, and custom block palettesRequires scripting setup in `manifest.json`; large radii need tick-splitting

The Entity Rotation Trick (Pure Commands)

If you are working purely with command blocks or basic functions, you can draw a sphere by summoning a marker entity (such as an `armor_stand`) at the center point and rotating it incrementally. Local coordinates (`^left ^up ^forward`) always resolve relative to the executing entity's facing direction. When an entity at the center of a sphere places a block at `^ ^ ^8`, that block lands exactly 8 blocks away along its line of sight. If you rotate the entity through all possible yaw (horizontal) and pitch (vertical) angles, the placed blocks trace out a hollow sphere.

To build a solid sphere or carve a spherical crater with this method, replace the single `/setblock` at the tip of the ray with several overlapping `/fill` commands stepped along the look vector, or use `/execute` to place blocks at `^ ^ ^1`, `^ ^ ^2`, and so on up to your radius. Keep in mind that `/fill` still draws an axis-aligned box even when given caret coordinates—it simply uses the two calculated caret points as opposite corners. A small box like `/fill ^-1 ^-1 ^8 ^1 ^1 ^8 stone` thickens the brush stroke so you can rotate the entity in larger degree steps (such as 5 or 10 degrees) without leaving pinholes in the shell.

In a Behaviour Pack, you can run a full latitude sweep in a single tick using recursive functions, or spread the horizontal rotation across multiple ticks using a repeating command block or `tick.json`. Below is a two-function setup where a master function rotates a tagged armor stand horizontally each tick and delegates the vertical pitch sweep to a helper function so an entire vertical rib completes instantly.

BP/functions/sphere/step_yaw.mcfunction
# Run every tick as and at the center armor_stand: /execute as @e[type=armor_stand,tag=sphere_gen] at @s run function sphere/step_yaw

# Reset pitch to straight up (-90) while keeping current yaw (~)
teleport @s ~ ~ ~ ~ -90

# Call the recursive pitch sweep to draw one vertical arc from top to bottom
function sphere/sweep_pitch

# Advance horizontal yaw by 6 degrees for the next tick
teleport @s ~ ~ ~ ~6 ~

# Track steps using a scoreboard so the entity cleans itself up after 60 ticks (360 degrees)
scoreboard players add @s sphere_steps 1
execute if score @s sphere_steps matches 60.. run kill @s

Completing the Vertical Arc in a Function

The helper function `sweep_pitch.mcfunction` handles the vertical angle from `-90` (straight up) to `90` (straight down). Because Bedrock command selectors do not have a built-in `rx` or `rxm` filter in the new execute syntax the way older command formats did, the cleanest way to stop the recursion is a scoreboard counter that resets every tick, or by running a fixed chain of commands.

When placing blocks at `^ ^ ^7`, using a 3x3x3 `/fill` brush (`^-1 ^-1 ^7 ^1 ^1 ^7`) patches the gaps between steps around the equator where the rays diverge widest. If you want to carve out terrain instead of building a shell, swap `minecraft:stone` for `minecraft:air` and run multiple `/fill` lines at `^ ^ ^2`, `^ ^ ^4`, and `^ ^ ^6` to hollow out the interior.

BP/functions/sphere/sweep_pitch.mcfunction
# Place a small 3x3x3 cluster 7 blocks ahead of the current facing angle
fill ^-1 ^-1 ^7 ^1 ^1 ^7 minecraft:stone

# Tilt pitch down by 6 degrees
teleport @s ~ ~ ~ ~ ~6

# Increment the vertical step counter
scoreboard players add @s pitch_step 1

# 180 degrees / 6 degrees per step = 30 steps. Recurse until we hit 30.
execute if score @s pitch_step matches ..29 run function sphere/sweep_pitch

# Reset the counter once the stack unwinds
scoreboard players set @s pitch_step 0

Voxel Sphere Generation with the Script API

While the armor stand rotation trick is clever, it wastes work near the poles (where rays overlap heavily) and struggles to make clean, single-block-thick shells without overlapping `/fill` cubes. If your add-on already uses `@minecraft/server`, calculating the sphere in JavaScript is faster, completely accurate on the voxel grid, and lets you pass any radius or block type on the fly.

The standard algorithm iterates through a 3D bounding box from `-radius` to `+radius` on the X, Y, and Z axes relative to a center coordinate. For every offset `(dx, dy, dz)`, you compute the squared distance from the center: `dx * dx + dy * dy + dz * dz`. Comparing squared distances against `radius * radius` avoids calling `Math.sqrt()` thousands of times inside a tight triple loop. Adding `0.5` to the radius threshold (so `rSquared = (radius + 0.5) * (radius + 0.5)`) produces much rounder-looking voxel spheres in Minecraft than a strict integer comparison, which tends to leave flat single-block spikes sticking out of the six cardinal faces.

To triggers this from a command block, an NPC, or an `.mcfunction`, listen to ` system.afterEvents.scriptEventReceive`. This lets you create a custom command syntax like `/scriptevent wiki:sphere 6 minecraft:glass` or `/scriptevent wiki:hsphere 10 minecraft:sea_lantern` that executes at the caller's location.

BP/scripts/sphere_command.js
import { system, BlockPermutation } from "@minecraft/server";

system.afterEvents.scriptEventReceive.subscribe((event) => {
    if (event.id !== "wiki:sphere" && event.id !== "wiki:hsphere") return;

    const source = event.sourceEntity || event.sourceBlock;
    if (!source) return;

    const dimension = source.dimension;
    const center = source.location;

    // Parse message: "<radius> [block_identifier]"
    const args = event.message.trim().split(/\s+/);
    const radius = Math.min(Math.max(parseInt(args[0], 10) || 5, 1), 32);
    const blockName = args[1] || "minecraft:stone";
    const isHollow = event.id === "wiki:hsphere";

    let permutation;
    try {
        permutation = BlockPermutation.resolve(blockName);
    } catch (e) {
        return;
    }

    const maxDistSq = (radius + 0.5) * (radius + 0.5);
    const minDistSq = isHollow ? (radius - 0.5) * (radius - 0.5) : -1;

    const cx = Math.floor(center.x);
    const cy = Math.floor(center.y);
    const cz = Math.floor(center.z);

    for (let dx = -radius; dx <= radius; dx++) {
        for (let dy = -radius; dy <= radius; dy++) {
            for (let dz = -radius; dz <= radius; dz++) {
                const distSq = dx * dx + dy * dy + dz * dz;
                if (distSq <= maxDistSq && distSq >= minDistSq) {
                    const block = dimension.getBlock({
                        x: cx + dx,
                        y: cy + dy,
                        z: cz + dz
                    });
                    if (block) {
                        block.setPermutation(permutation);
                    }
                }
            }
        }
    }
});

Splitting Large Spheres Across Ticks with a Job Queue

Because the volume of a bounding box grows cubically (`(2r + 1)^3`), a radius of 10 checks 9,261 blocks, while a radius of 30 checks 226,981 blocks. Running hundreds of thousands of `dimension.getBlock()` and `block.setPermutation()` calls inside a single event callback will exceed the Script API watchdog time limit and halt your script execution, or cause a severe lag spike for everyone in the world.

For spheres larger than roughly 12 to 15 blocks in radius, replace the synchronous `for` loop with a generator function passed to `system.runJob()`. The Bedrock runtime automatically slices generator jobs across multiple ticks, yielding execution whenever the current tick's scripting budget runs low and resuming cleanly on the next tick. You simply place a `yield;` statement inside the innermost loop.

BP/scripts/sphere_job.js
import { system, BlockPermutation } from "@minecraft/server";

function* generateSphereJob(dimension, center, radius, permutation, isHollow) {
    const maxDistSq = (radius + 0.5) * (radius + 0.5);
    const minDistSq = isHollow ? (radius - 0.5) * (radius - 0.5) : -1;

    const cx = Math.floor(center.x);
    const cy = Math.floor(center.y);
    const cz = Math.floor(center.z);

    for (let dx = -radius; dx <= radius; dx++) {
        for (let dy = -radius; dy <= radius; dy++) {
            for (let dz = -radius; dz <= radius; dz++) {
                const distSq = dx * dx + dy * dy + dz * dz;
                if (distSq <= maxDistSq && distSq >= minDistSq) {
                    try {
                        const block = dimension.getBlock({
                            x: cx + dx,
                            y: cy + dy,
                            z: cz + dz
                        });
                        if (block) {
                            block.setPermutation(permutation);
                        }
                    } catch (err) {
                        // Ignore blocks outside world height limits or in unloaded chunks
                    }
                    yield;
                }
            }
        }
    }
}

system.afterEvents.scriptEventReceive.subscribe((event) => {
    if (event.id !== "wiki:bigsphere") return;

    const source = event.sourceEntity || event.sourceBlock;
    if (!source) return;

    const args = event.message.trim().split(/\s+/);
    const radius = Math.min(Math.max(parseInt(args[0], 10) || 15, 1), 64);
    const blockName = args[1] || "minecraft:stone";
    const isHollow = args[2] === "hollow";

    try {
        const perm = BlockPermutation.resolve(blockName);
        system.runJob(
            generateSphereJob(source.dimension, source.location, radius, perm, isHollow)
        );
    } catch (e) {
        // Invalid block identifier passed in message
    }
});

Wiring the Script into manifest.json

For the `/scriptevent` sphere handler to run, your Behaviour Pack `manifest.json` must declare a `script` module pointing to your entry file and a dependency on `@minecraft/server`. Because `system.afterEvents.scriptEventReceive`, `system.runJob`, `Dimension.getBlock`, and `BlockPermutation.resolve` are all part of the stable 1.x release of `@minecraft/server`, you do not need to enable the Beta APIs toggle in world settings.

BP/manifest.json
{
  "format_version": 2,
  "header": {
    "name": "Sphere Command Utility",
    "description": "Adds /scriptevent sphere builders using stable @minecraft/server",
    "uuid": "a8f4910e-7b23-4c9a-9e12-403958172631",
    "version": [1, 0, 0],
    "min_engine_version": [1, 20, 80]
  },
  "modules": [
    {
      "type": "script",
      "language": "javascript",
      "uuid": "d2c19485-3a11-4f8b-8c44-918273645512",
      "entry": "scripts/sphere_job.js",
      "version": [1, 0, 0]
    }
  ],
  "dependencies": [
    {
      "module_name": "@minecraft/server",
      "version": "1.11.0"
    }
  ]
}

Which versions this applies to

Applies to Bedrock Edition 1.19.50 and newer for the new `/execute` syntax used in `.mcfunction` files. The Script API examples use stable `@minecraft/server` 1.11.0+ APIs (Bedrock 1.20.80+) and do not require any experimental toggles.

When it does not work

What you seeWhyThe fix
Function sphere/sweep_pitch stopped midway with 'Function ... exceeded the maximum command limit of 10000'A single `.mcfunction` invocation (including all nested recursive calls triggered within the same command) cannot execute more than 10,000 commands at once. If you try to loop both yaw and pitch inside the same tick via recursion, you will rapidly exceed 10,000 commands.Run only the vertical pitch sweep recursively inside a single tick (around 150–300 commands total), and advance the horizontal yaw once per tick using a repeating command block or `BP/functions/tick.json`.
Script error: '[Scripting][error]-Script execution timed out' or watchdog warning when building a sphere with radius > 20Calling `dimension.getBlock()` and `block.setPermutation()` tens of thousands of times inside a synchronous `for` loop locks the server thread beyond the per-tick watchdog budget.Convert your coordinate loop into a `function*` generator with a `yield;` after each placed block, and schedule it with `system.runJob()` so Bedrock spreads the work across multiple ticks.
The bottom or top of the sphere gets flattened or throws an unhandled exception in the Content LogWhen the sphere's center is near the top or bottom of the dimension (for example below Y = -64 or above Y = 319 in the Overworld), `dimension.getBlock()` returns `undefined` or throws a location out-of-bounds error, and `/fill` fails with `Cannot place blocks outside of the world`.In scripts, wrap `dimension.getBlock()` in a `try/catch` block or clamp `cy + dy` to `dimension.heightRange.min` and `dimension.heightRange.max - 1`. In command functions, avoid using multi-block `/fill` brushes right against the build limit.
Pure-command sphere has visible rings of empty air around the middle (equator) while the poles are solidAngular steps spread further apart the further you move from the center and the closer the pitch gets to `0` (the horizon). At radius 15, a 10-degree rotation step skips more than 2.5 blocks horizontally.Either decrease your teleport rotation increment (for example from `~10` down to `~3` or `~4`) or thicken the placement tip from `/setblock ^ ^ ^15` to a 3x3x3 `/fill ^-1 ^-1 ^15 ^1 ^1 ^15`.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.