pyblocks reference

Every call, every fact, and every block, each with what it takes, what it gives back, and a line you can paste. Coordinates come first, always x, y, z, and the block name comes last.

Three lines of blocks from one corner: red running east, green going up, blue running south
x runs east (red), y is height (green), z runs south (blue). The gold block at the corner is x 0, y 1, z 0.

How to read this page

Each entry starts with the call written out, then says what each argument is, what the call does, and what it gives back. Under that is a line or two you can paste into your own program.

Two kinds of thing are listed. An action has parentheses and does something: world.set_block(0, 1, 0, "stone"). A fact has none and is a piece of information you read, and sometimes set: player.y tells you how high you are, world.hour = 18 makes it sunset. If you write a fact with parentheses nothing happens, and that is the commonest mistake on this page.

Where an argument is written x, y, z you can always hand over one position instead: world.set_block(player.pos, "gold") and world.set_block(0, 1, 0, "gold") are the same call. Where a block name is asked for, any name from the block table works, and so does a color you made with world.define.

Starting

import time
from pyblocks import world, player, noise, noise_at

Import what you use. world is the world, player is you, and noise and noise_at are smooth random numbers for hills and caves. time is Python's own, for time.sleep(0.1) at the bottom of a loop. A second file of your own beside your program is imported by its name: import mykit.

Every call at a glance

The whole API, in the order it appears below.

Building the world

world.set_block(x, y, z, block)action

x, y, z
whole numbers: east, up, south. One position works too.
block
a block name, or "air" to take a block away.

Puts one block there. Whatever was there before is gone, and putting the same block there again costs nothing you would notice.

world.set_block(0, 1, 0, "gold")
world.set_block(player.pos, "air")

See also world.fill for more than one, and world.get_block to read one back.

world.fill(x1, y1, z1, x2, y2, z2, block)action

x1, y1, z1
one corner.
x2, y2, z2
the opposite corner. Either corner can be first; the two just have to be opposite each other.
block
what to fill the box with. "air" hollows it out.

Fills the whole box between the two corners, both corners included, so from 0 to 5 is six blocks and not five. This is the only call that places more than one block, and it is much faster than a loop that does the same thing: a floor is one fill, and a room is a solid box with a smaller box of air inside it.

world.fill(-8, 0, -8, 8, 0, 8, "grass")
world.fill(-3, 1, -3, 3, 4, 3, "brick")
world.fill(-2, 1, -2, 2, 3, 2, "air")

See also world.clear.

world.clear()action

Every block in the world to air, all at once. How a program starts over. It leaves the player, the labels, and the row of boxes where they are; it is blocks it clears.

world.clear()

See also world.remember, which puts a world back instead of emptying it.

world.generate(seed, preset)action

seed
a whole number. The same seed gives the same land every time, on any machine. 1234 unless you say.
preset
"flat", "hills", "mountains", or "islands". "hills" unless you say.

Makes land: ground, hills, and water, and never a building or a tree. It clears the world first, so call it before you build anything, not after. "flat" is the same ground whatever the seed; change the seed on any of the others and you get a different world of the same kind.

world.generate(7, "mountains")
height = world.get_height(0, 0)

See also world.get_height, which is how you find the ground afterwards, and noise, which is the same smooth random you can shape yourself.

world.size = 256fact, you can set it

How wide the world is, along x and along z, in blocks. 128 unless your program says otherwise. Any multiple of 16 from 32 to 1024. The world stays centered on 0, so a 256 world runs from -128 to 127, and the height is always 64 whatever the width.

Set it before you build: setting it empties the world. A big world is a big program's. 512 is sixteen times as many blocks as 128, and 1024 is sixty-four times, so a fill across the whole of one takes a while and asks a lot of the machine.

world.size = 256
world.generate(1234, "hills")
print(world.min_x, world.max_x)

See also the edges, which answer for whatever size the world is.

world.define(name, (red, green, blue))action

name
what to call your color. After this it is a block name like any other, for as long as the program runs.
red, green, blue
0 to 255 each, the way a color on a web page is written. Three numbers or one color both work.
glows=True
makes it a light, as bright as glowstone.
see_through=True
makes it a pane, like glass: stained glass, colored water, the ghost of a wall.

Gives you a block in any color you like. There is room for 159 of them in one program.

Defining a name you have already defined changes every block of that color at once, wherever they are in the world, without touching a single block. That is how a color is made to move: a row of them defined once and redefined in a loop is an animation that costs nothing.

world.define("sunset", (255, 120, 40))
world.fill(0, 1, 0, 4, 1, 4, "sunset")
world.define("sunset", (255, 60, 20))   # every one of them changes

See also world.color_of.

Reading the world

Reading is free and instant. Your program keeps its own copy of every block, so a loop that asks a million questions never waits for the world.

world.get_block(x, y, z)action, gives an answer

x, y, z
where to look. One position works too.

Gives back the name of the block there as a piece of text, or "air" if the cell is empty. Compare it with a name to decide something.

world.get_block(0, 0, 0)        # "grass", say, or "air" where nothing is

if world.get_block(0, 0, 0) == "water":
    world.say("that is a pond")

See also world.get_height and player.looking_at.

world.get_height(x, z)action, gives an answer

x, z
which column to measure. No y: the answer is a y.

Gives back the y of the highest block in that column, or -1 if the column is empty all the way down. world.get_height(x, z) + 1 is therefore the first free space above the ground, which is where a tree or a flower goes.

top = world.get_height(4, 4)    # 7, on ground seven blocks high
world.set_block(4, top + 1, 4, "poppy")

See also world.generate.

world.in_bounds(x, y, z)action, gives an answer

x, y, z
the place to test. One position works too.

Gives back True if that place is inside the world and False if it is outside. Building outside the world stops your program with a sentence, so a program that works out where to build, rather than being told, should ask first.

spot = player.pos + (0, 0, 10)
if world.in_bounds(spot):
    world.set_block(spot, "lantern")

See also the edges.

world.min_x world.max_x world.min_y world.max_y world.min_z world.max_zfacts, read only

The lowest and highest number the world allows on each axis. They answer for whatever world.size is, so a program written with these works in a world of any size. min_y is 0 and max_y is 63, always.

for x in range(world.min_x, world.max_x + 1):
    world.set_block(x, 1, 0, "stone")

See also world.in_bounds.

world.blocksfact, read only

A list of every block name there is, in the order of the table below, with any color your program defined after them. Loop over it, print it, or pick from it at random.

import random
world.set_block(0, 1, 0, random.choice(world.blocks))

See also world.color_of.

world.color_of(block)action, gives an answer

block
a block name, or a color you defined.

Gives back the color of that block as three numbers from 0 to 255: world.color_of("brick") is (153, 71, 56). For a built-in block it is the color its picture is painted from, so you can compare a pixel of a photograph with every block and find the nearest one. Working out which is nearest is yours to write.

world.color_of("grass")         # (92, 158, 61)

red, green, blue = world.color_of("grass")
print(red, green, blue)                 # 92 158 61

See also world.define and Pillow.

Where the player is

These are facts, so they have no parentheses, and each one is a snapshot of this instant. Read them again inside a loop and they are the player's new answer.

player.x player.y player.zfacts, read only

The block the player is standing in, as three whole numbers. player.y is the cell their feet are in, so the floor they are standing on is player.y - 1, and the cell at head height is player.y + 1.

under = world.get_block(player.x, player.y - 1, player.z)
world.say("standing on " + under)

See also player.pos, which is the three of them together.

player.posfact, read only

The same three numbers as one position, with .x, .y, and .z on it. Anywhere a call wants x, y, z you can hand it one of these instead. You can add to it, and what you get back is another position.

world.set_block(player.pos, "glass")
world.set_block(player.pos + (0, 2, 0), "glowstone")

See also player.set_pos and player.exact_pos.

player.exact_posfact, read only

Where the player is between blocks, with decimals: standing in the middle of the block at 0, 1, 0 reads 0.5, 1.0, 0.5. Use it when a whole number is too coarse, such as measuring how far someone has walked, or how near they are to a mark.

here = player.exact_pos
gap = abs(here.x - 10.5)

See also player.set_exact_pos.

player.facingfact, read only

"north", "east", "south", or "west": the nearest compass point to the way the player is looking. The word you want when a program asks which way someone is pointed and does not care about the exact angle.

if player.facing == "north":
    world.say("the door is behind you")

See also player.yaw for the angle itself.

player.name and player.labelfacts, read only

name is "you" for the player at this keyboard, and a classmate's name on their entry in world.players. It is the same word hit.player, message.player, and key.player carry, so a game can tell who did what.

label is the name that player typed, which is what everybody else sees written over them. For a classmate it is the same as their name; for you it is the name you chose, where name says "you". That is the one name a program cannot work out for itself, so it is the one to write on somebody else's screen.

for hit in world.new_hits():
    if hit.player != "you":
        world.say(f"{hit.player} hit {hit.block}")

for p in world.players:
    if p.name == winner:
        world.say("You win!", to=p.name)
    else:
        world.say(f"{world.players[winner].label} wins", to=p.name)

See also world.players.

player.yaw player.pitchfacts, you can set them

The angles the player is looking along, in degrees. Yaw turns left and right: 0 north, 90 east, 180 south, 270 west, the same way a compass counts. Pitch looks up and down: -90 straight down, 0 level, 90 straight up.

Set either one and the view turns there, the short way round. Setting both one at a time is two turns, so for a camera that moves every tick use player.set_look instead.

player.yaw = 180
player.pitch = -30

See also player.facing and player.set_look.

player.looking_atfact, read only

The block under the crosshair right now, as far as player.reach carries, which is six blocks unless your program says otherwise, or None if the crosshair is on nothing. What you get back has four things on it:

.pos
where that block is.
.block
its name.
.face
which side you are looking at: "top", "bottom", "north", "east", "south", or "west".
.place
the empty cell just outside that face, which is where a block would go if you built on it.

It comes from the same ray a click does, so what your program sees here and what a click would hit always agree. Check for None before you use it.

look = player.looking_at
if look is not None:
    world.set_block(look.place, "lantern")

See also world.new_hits, which is the same information after a click.

Moving the player

player.set_pos(x, y, z)action

x, y, z
the block to stand in. One position works too.

Puts the player in that block at once, however far away it is. The action that goes with the fact pos. Remember that y is the cell the feet are in, so to stand on top of a tower put them one above it.

top = world.get_height(0, 0)
player.set_pos(0, top + 1, 0)

See also player.set_exact_pos and player.home.

player.set_exact_pos(x, y, z)action

x, y, z
where to put them, decimals and all. One position works too.

Puts the player anywhere, between blocks as easily as in one. Sent again and again in a loop, this is how a program flies the camera: the world slides the player from one place to the next over the time between your calls, so the ride is smooth however slowly your loop runs.

While your program is sending these, the keys and gravity wait; a quarter of a second after the last one the player has themselves back. A step of more than four blocks is a cut rather than a slide, which is how you move the camera somewhere else altogether.

for step in range(200):
    player.set_exact_pos(step * 0.1, 20, -30)
    player.set_look(0, -20)
    time.sleep(0.05)

See also player.set_look, which turns the camera as this moves it.

player.set_look(yaw, pitch)action

yaw
0 north, 90 east, 180 south, 270 west.
pitch
-90 down, 0 level, 90 up.

Turns the view, both angles in one line. Setting player.yaw and player.pitch one after the other does the same thing in two, and the first of the two turns with last tick's other angle, which a camera moving every tick can see as a wobble.

player.set_look(90, -20)        # face east, looking down a little

See also player.yaw.

player.home = (0, 1, 8)fact, you can set it

Where the H key and the Home button put the player. The spawn block unless your program says otherwise, and player.home = player.pos turns wherever they are standing into a checkpoint. It stays where you put it after the program ends, until the next Run.

player.home = player.pos

See also player.can_go_home.

player.can_fly = Falsefact, you can set it

Whether F flies. True unless your program says otherwise. Turn it off for a game where climbing is the puzzle; it comes back on at the next Run, not when your program ends, so a game's rule lasts as long as the game is up.

player.can_fly = False

See also player.can_go_home.

player.can_go_home = Falsefact, you can set it

Whether H and the Home button work. True unless your program says otherwise. Off, with player.can_fly off as well, is a maze nobody can step out of.

player.can_go_home = False

See also player.home.

player.speed player.jump player.gravityfacts, you can set them

player.speed
how fast walking is, in blocks a second. 4.3 is normal, and 0 stops them walking, for a game that has ended or a moment when the player may only look. It stops the walking alone: a jump, a ladder and flying are their own facts.
player.jump
how high a jump reaches, in blocks. 1.5 is normal, which clears one block.
player.gravity
how hard the world pulls down, in blocks a second per second. 28 is normal; about 5 is the moon.

The three of them together are what a place feels like to move through. They stay as your program set them until the next Run, so the moon is still the moon after the program ends.

player.gravity = 5
player.jump = 3

See also player.set_exact_pos.

player.reach = 20fact, you can set it

How far the player can click, in blocks. 6 unless your program says, and up to 96.

The crosshair, player.looking_at and every hit come from one ray, so this moves all three together: what your program sees and what a click would hit always agree. Six blocks is an arm's length, which is too short for a game of targets across a field, and setting it is your program's business, since nothing on screen tells the player how far they can reach.

player.reach = 30
world.status("Hit the far targets", at="bottom")

See also player.looking_at and world.new_hits.

What just happened

Clicks, keys, and chat wait in a queue until your program asks for them. Each of these calls empties its queue, so what you are given, you are given once: put the answer in a variable if you need it twice. Ask inside a loop with time.sleep(0.1) at the end of the loop, which is ten looks a second and leaves the machine alone in between.

while True:
    for hit in world.new_hits():
        world.set_block(hit.pos, "air")
    time.sleep(0.1)

world.new_hits()action, gives an answer

A list of every click since the last time you asked, oldest first, and an empty list if there were none. Each hit has six things on it:

.pos
the block that was clicked.
.block
its name, as it was at the moment of the click.
.face
which side was clicked: "top", "bottom", "north", "east", "south", "west", or "none" for a click that hit nothing.
.action
"break" for a left click, "place" for a right click.
.place
the empty cell in front of that face, which is where a block goes if you are building on it.
.player
who clicked: "you", or a classmate's name when somebody has joined your world.

A click on nothing at all is a hit too, with .block of "air" and .face of "none", so a game can tell a miss from no click at all. Clicking does not change the world by itself: nothing moves unless your program moves it.

for hit in world.new_hits():
    if hit.action == "break" and hit.block == "target":
        world.set_block(hit.pos, "air")
        world.effect("sparks", hit.pos)
    elif hit.action == "place":
        world.set_block(hit.place, "stone")

See also world.allow and player.looking_at.

world.allow("break", "place")action

actions
name the clicks you want: "break", "place", both, or neither.

Chooses which clicks become hits. Both, until your program narrows it. world.allow() with nothing inside the parentheses locks the world: clicks still happen and your program no longer hears about them, which is how a museum stops visitors rearranging the exhibits.

world.allow("break")
world.allow()

See also world.new_hits.

world.new_keys()action, gives an answer

A list of every letter and digit pressed since the last time you asked, each press once, as a lowercase character from "a" to "z" or "0" to "9". Keys only count while the player is in the world: typing in the editor or in chat never arrives here, and neither does T, which opens chat. The walking keys arrive here as well as walking the player.

Each key also has .player, who pressed it, which is "you" until somebody has joined your world. It is still an ordinary character otherwise, so key == "r" and "r" in keys both work as they always did.

for key in world.new_keys():
    if key == "r":
        world.restore()

See also world.keys_down, for a key that is held.

world.keys_down()action, gives an answer

A list of the letter and digit keys held down at this instant. Where world.new_keys gives each press once, this gives what is being held, which is what you want for something that goes on happening while a key is down. Asking twice in a row gives the same answer unless the player let go in between.

This one is the keyboard in front of you and nobody else's: it asks the keys in the room. In a world with classmates in it, world.new_keys is the one that says who pressed what.

if "w" in world.keys_down():
    world.effect("smoke", player.pos)

See also world.new_keys.

world.new_messages()action, gives an answer

A list of every line typed into chat since the last time you asked, oldest first. Each one has .text, the line as it was typed, and .player, who typed it, which is "you" until somebody has joined your world. Enter or T opens the chat line. This is how a program takes an order in words rather than in clicks.

for message in world.new_messages():
    if message.text == "night":
        world.hour = 0

See also world.say, which talks back.

world.playersfact, read only

Everybody in the world, you first: a list, always there, of length 1 when you are alone. Each one has .name ("you" for the player at this keyboard, a classmate's name for theirs), the same facts about where they are and where they look that player has, and set_pos. world.players["Ada"] finds one by name. Their view and the world's rules are not yours to set on them: world.players["Ada"].speed = 9 is an error that tells you to set player.speed, which everybody gets.

The places in the list are from the moment you asked for it, so two of them measured against each other are a distance between where they both were, and a classmate who leaves while your loop is running cannot stop it. Ask again for where everybody is now.

if len(world.players) == 1:
    world.say("waiting for a classmate to join")
for p in world.players:
    p.set_pos(0, 1, 8)

See also world.new_players, and hit.player, message.player, and key.player for who did a thing.

world.new_players() and world.gone_players()action, gives an answer

The names of everybody who joined, or left, since the last time you asked, oldest first, read the way world.new_hits is. Everybody already in the world counts as joined when your program starts, so a program that greets players greets them on every run.

for name in world.new_players():
    world.say(f"{name} is here", to=name)
for name in world.gone_players():
    world.say(f"{name} left")

See also world.players.

Showing things

world.say(text, to=None)action

text
anything, including a number. Newlines in it make more than one line.
to=
a player's name, to say it on that screen alone; everybody's without it. A name you have never seen is an error, since it is usually a typo; somebody who has left since you read their name simply does not hear it. world.status takes the same.

A line to the player at the bottom of the world, which fades after a few seconds. The last six stand at once. For something that has to stay on screen, use world.status.

world.say("Found it!")
world.say(f"{count} left")

See also world.status and world.label.

world.status(text, size=, color=, font=, align=, at=)action

text
up to six lines. Write them with newlines in the text, or as a triple-quoted block, which is easier to read. "" takes the status away.
size=
"small", "normal", "big", or "huge".
color=
any block's name, or a color you defined.
font=
"plain", or "mono", whose digits are all one width, so a counter does not jiggle as it counts.
align=
"center", "left", or "right": how the lines line up with each other.
at=
"top", "center", or "bottom": where on the screen it sits.

Text pinned over the world that stays until your program changes it, where a say fades. A score, a timer, a rule, a game over.

Written as a triple-quoted block, the indentation you typed to keep your program tidy is not part of the status, and neither are the blank lines at the two ends. A blank line in the middle stays, as a gap. Nothing sticks from the call before: each call says the whole of how it looks, so a plain one after a big red one is plain again.

world.status(f"""
    Score: {score}
    Lives: {lives}
""", align="left")
world.status("GAME OVER", size="huge", color="red", at="center")

See also world.slots for an inventory, and world.label for writing that stands in the world.

world.slots(items, chosen=None)action

items
a list of up to nine pairs, each a block and a number, like ("wood", 4). None as the block is an empty box. The number can be a short piece of text instead, so "4/8" and "99+" both work; four characters fit. [] takes the row away.
chosen=
which box to light up, counting from 0. It draws a border and nothing else.

A row of boxes along the bottom of the world, for an inventory. Nothing is counted for you, and that is the point: the dictionary your program keeps is the only inventory there is, and this row shows whatever your last call said. Pass every slot every time.

bag = {"wood": 4, "stone": 12}
world.slots([(name, bag[name]) for name in bag], chosen=0)

See also world.status and world.new_hits, which is where the things in a bag come from.

world.label(x, y, z, text, facing=None)action

x, y, z
the cell to write in. One position works too.
text
one line, up to sixty characters. "" takes that label down.
facing=
"north", "east", "south", or "west": which way the sign faces. Without it the sign turns to whoever is reading it.

Writing that stands in the world, like a sign on a museum wall. It is the size of the world, so it grows as you walk up to it, which is what tells you where it is. One label to a cell, and a new one there replaces the old.

In a cell that holds a block the label is written on the block, on the face you named or on top of it, so a label never disappears inside a wall. Labels are paint: they change no block, world.clear leaves them standing, and the next Run takes them all down.

world.label(0, 5, 0, "Robins: 42")
world.label(3, 2, 0, "Entrance", facing="north")

See also world.status, which writes on the screen rather than in the world.

Effects and sound

None of these changes a single block. They are paint and noise over the top of a world your program is in charge of.

world.effect(name, x, y, z, color=None, volume=1.0)action

name
"boom", "sparks", "smoke", "splash", "ding", or "glow".
x, y, z
where it happens. One position works too.
color=
a block's name, whose color the sparks, the smoke, or the glow take. A boom, a splash, and a ding have colors of their own.
volume=
0 to 1. 0.5 is half as loud, and 1 is what you get without asking.

A bang, a flash, a puff, or a chime at that place, with the sound quieter the further away the player is. An explosion that does not move a block is still an explosion: if you want the blocks to go, your program takes them out.

world.effect("boom", 0, 3, 0)
world.effect("sparks", player.pos, color="gold", volume=0.4)

See also world.note and world.drum.

world.note(note, x, y, z, voice=None, volume=1.0, length=None)action

note
a name like "c4" or "f#5", or a piano key number where 60 is middle C and each step up is the next key. 36 to 96.
x, y, z
where it is heard from. One position works too.
voice=
"tone", "pluck", "organ", or "bass".
volume=
0 to 1.
length=
how many seconds it sounds, 0.05 to 3. Without it the voice decides.

One note. Numbers rather than names are what a loop wants, since adding 1 to a number is the next key up and adding 12 is the octave.

world.note("c4", 0, 2, 0)
for step in [0, 2, 4, 5, 7]:
    world.note(60 + step, 0, 2, 0, voice="pluck", volume=0.6)
    time.sleep(0.2)

See also world.drum.

world.drum(name, x, y, z, volume=1.0)action

name
"kick", "snare", "hat", or "clap".
x, y, z
where it is heard from. One position works too.
volume=
0 to 1.

A drum, which has no pitch. A beat is a loop with a sleep in it, and what pattern to play is yours to write.

world.drum("kick", 0, 2, 0)
world.drum("hat", 0, 2, 0, volume=0.3)

See also world.note.

Time and the sky

world.hour = 18fact, you can set it

The time of day: 0 midnight, 6 sunrise, 12 noon, 18 sunset, and 24 is midnight again. Decimals are fine, so 18.5 is half an hour after sunset. Read it to see what time it is now, which with a day running is a number that keeps moving.

world.hour = 18
if world.hour > 20:
    world.set_block(0, 3, 0, "glowstone")

See also world.day_length and world.sun.

world.day_length = 2fact, you can set it

How many real minutes a whole day takes. 0, which is what you get without asking, holds the sun still at whatever hour it is. 2 is a day every two minutes, which is fast enough to watch the shadows move. Decimals are fine.

The clock keeps running after your program ends, so an evening your program asked for stays until the next Run.

world.hour = 6
world.day_length = 2

See also world.hour.

world.sky(latitude, longitude, year, month, day, lines=False, names=False)action

latitude
degrees north, so south is a negative number. All five of these are needed.
longitude
degrees east, so west is negative.
year, month, day
the date. Years run from -4000 to 8000, and -2600 is 2601 BC.
lines=True
joins the stars of each constellation with faint lines.
names=True
writes each constellation's name beside it.

Puts the real sky over the world: the real stars in their real places, the sun rising and setting when and where it really does there, the moon with the phase it really had, and the five planets you can see without a telescope. After this, world.hour is the sun's own time, so 12 is the middle of the day wherever on Earth you are standing.

Call it again to move the sky somewhere else or to some other date, and call it again without lines and names to take those off. A night with no moon is properly dark, so bring lamps.

world.sky(latitude=38.6, longitude=-90.2, year=2026, month=9, day=18,
          lines=True, names=True)

See also world.sun, world.sun_at and world.date.

world.sun world.moonfacts, read only

Where the sun and the moon are at this moment.

.altitude
how many degrees above the horizon. Below 0 it has set.
.azimuth
which way to turn to see it, in degrees clockwise from north, counted the way player.yaw is, so you can look straight at it.
.lit
the moon only: how much of its face is lit, 0.0 at new moon to 1.0 at full.

They always work. Under the usual sky the sun is up at 6 and down at 18 and the moon is always full and opposite it; after world.sky both are the real ones for that place and date. The answer is a snapshot of the instant you asked, so inside a loop, ask inside the loop.

if world.sun.altitude < 0:
    world.say("the sun has set")
player.set_look(world.moon.azimuth, world.moon.altitude)

See also world.sun_at.

world.sun_at(hour) world.moon_at(hour)actions, give an answer

hour
0 to 24, the hour to ask about. The same day the clock is on.

The same answers world.sun and world.moon give, for a different time of the same day, without moving the clock and without disturbing the player. A loop that walks an hour at a time, or a minute at a time, is how a program finds the sunrise for itself.

noon = world.sun_at(12)
print(noon.altitude)            # 68.0, degrees above the horizon

See also world.sky.

world.datefact, read only

The date the real sky is showing, as (year, month, day), or None before world.sky has been called. With a day running it moves on at each midnight, so a program that watches the sky over a week can read which day it has reached. world.sky is what sets it.

world.date                      # (2026, 9, 18), once world.sky has set it

year, month, day = world.date
world.say(f"{year}-{month}-{day}")

See also world.sky.

Putting the world back

world.remember() world.restore()actions

world.remember() takes a copy of every block as it stands. world.restore() puts them all back the way they were, however much has changed since. There is one copy: remembering again replaces it.

This is what a game uses for a reset, and what a digging program uses so the ground can be mended. Labels and the row of boxes are not blocks, so they are left alone.

world.generate(3, "hills")
world.remember()
world.fill(-4, 0, -4, 4, 8, 4, "air")
world.restore()

See also world.clear.

More than one player

Up to five people can be in one world: whoever is hosting, and four classmates who join from their own machines. One program runs, and it is the host's. Everybody else walks, looks, clicks, and types in the world that program builds, exactly as the host does, and their clicks and their chat arrive in that one program with a name on them. Nobody but the program changes a block, which is the same rule as for one player.

Each player wears a color of their own, handed out in the order they arrived, with the name they typed written over their head. F7 twice steps the camera back so you can see yourself among them, and once more draws the world flat from above with everybody on it as a marker in their own color, which is the quickest way to see where five people are.

Opening your world

Programs, Host this worldopens your world to another copy of pyblocks on this machine. Nothing is asked of the network, so this always works: two windows on one desk is a two-player game
Programs, Host on the networkopens it to the machines around you. The first time, the firewall may ask whether to allow it, which an adult has to answer
the panel on the rightwhile you host: the address to type, large, then who is here. Kick sends somebody out, Stop hosting closes the world to everybody
your nameasked for once, the first time you host or join: up to 16 letters and digits, no spaces. It is what the others see written over you

Joining somebody else's

Programs, Join a world...type the address from their screen. More than one is listed there: try another if the first does not answer
while you are in ityou walk, look, click, chat, and press keys, and that is all: Run and Stop are off and the editor is away, because the program belongs to whoever is hosting
Leavethe button where Back to editing was. Your own world and your own editor come back, exactly as you left them
if it says nothe sentence says why: nobody is hosting at that address, your copy of pyblocks is a different version from theirs, somebody already has that name, five players are in already, or their world is too big for your machine

Run counts three down when anybody else is in your world, on every screen including yours, so a round starts together. Pressing Stop during the count calls it off. A rerun does not drop anybody: the world is built again around everybody standing in it, which is how you change a number and play again.

Three things to design around

Everybody sees one world. There is one set of blocks, so nothing can be hidden from one player and shown to another. Hidden information has to come from a message only they get, or from a wall they have to walk around.

Players walk through each other. Nobody is a wall, so catching somebody means measuring: "within two blocks" is a catch, and your program decides what that means.

Two to five, in and out. People join in the middle and leave in the middle. world.new_players and gone_players tell you when, and a game that waits for four before it starts is a game nobody plays, so start with whoever is there.

What to write with

world.playerseverybody, you first. len(world.players) == 1 is how a program notices it is alone
.name and .labelwhat your program calls a player, and the name they typed. See player.name: yours is "you", and your label is what the others read over you
.pos, .exact_pos, .yaw, .facingwhere each of them is and which way they look, all from the moment you asked for the list
.set_pos(x, y, z)moves that player. A loop over the list is "everyone to the start line"
world.new_players, gone_playerswho arrived and who left since you last asked, read the way hits are
hit.player, message.player, key.playerwho clicked, who typed, who pressed a key: on every hit from world.new_hits, every line from world.new_messages, and every key from world.new_keys
to=on world.say and world.status: that screen alone. Without it, everybody's

Everything else about the world is everybody's at once. world.allow decides what every player's clicks do; player.speed, jump, gravity, reach, player.home, and player.can_fly are the rules of the world and apply to all five. Setting one of those on a classmate is an error that says so and tells you to set it on player instead. Reading one off them gives the rule everybody is playing by.

Two mistakes have sentences of their own. Asking for a player who is not there, world.players["Bob"], says who is in the world instead. Setting a classmate's view, world.players["Ada"].yaw = 90, says that their view is their own: your program never turns somebody else's head. A player who leaves in the middle of your loop is not a mistake, though, and will not stop your program.

A game for everybody

First to break the gold block wins. It plays alone, it plays with four, and nothing in it waits for anybody.

import time
from pyblocks import world

world.fill(-8, 0, -8, 8, 0, 8, "grass")
world.set_block(0, 1, 0, "gold")
world.allow("break")
world.status("First to break the gold wins")
winner = ""

while winner == "":
    for name in world.new_players():
        world.say("Break the gold block first!", to=name)
    for hit in world.new_hits():
        if hit.block == "gold":
            winner = hit.player
    time.sleep(0.1)

for p in world.players:
    if p.name == winner:
        world.say("You win!", to=p.name)
    else:
        world.say(f"{world.players[winner].label} wins", to=p.name)

Catching somebody is a distance. Ask for the list once and measure inside it, so every place is from the same instant.

players = world.players
chaser = players["Ada"]
for p in players:
    if p.name != chaser.name:
        across = p.exact_pos.x - chaser.exact_pos.x
        along = p.exact_pos.z - chaser.exact_pos.z
        if across * across + along * along < 4:
            world.say("Caught!", to=p.name)

There is no call that tells you who is nearest, and that is on purpose: the loop above is the program, and writing it is the point.

Smooth random

noise(x, z, seed=0) noise_at(x, y, z, seed=0)actions, give an answer

x, z
where to ask. Decimals are the point of it: divide first.
y
noise_at only: changing with height as well.
seed=
which world of noise to ask. The same seed gives the same answer forever, on any machine.

A number from 0.0 to 1.0 that changes smoothly from place to place, where random.random() jumps about. Ask it along a row and you get a hillside; ask it with plain whole numbers and the hills are one block wide, which looks like noise rather than land, so divide first: noise(x / 10, z / 10) is hills ten blocks across, and dividing by more makes them wider.

noise_at is the same thing in all three directions, for caves, clouds, and pockets of ore. At y = 0 it gives exactly what noise gives.

noise(0.4, 0.7)                 # 0.649
noise(0.4, 0.7, 5)              # 0.554, another world of hills

for x in range(-20, 20):
    for z in range(-20, 20):
        height = int(noise(x / 10, z / 10) * 12)
        world.fill(x, 0, z, x, height, z, "stone")

See also world.generate, which is this with the shaping already done.

Pictures

from PIL import ImagePython library

Pillow comes with pyblocks, for reading a picture that sits beside your program. Open it, make sure it is plain red, green, and blue, shrink it to a size that fits your wall, and ask each pixel what color it is.

Image.open("picture.png")
the file, from the folder your program is saved in.
.convert("RGB")
plain red, green and blue, whatever the file was.
.resize((32, 32))
a new picture that size.
.getpixel((x, y))
the color of one pixel, as (red, green, blue). In a picture, y counts down from the top.
from PIL import Image

picture = Image.open("icon.png").convert("RGB").resize((32, 32))
red, green, blue = picture.getpixel((0, 0))

See also world.color_of, which tells you what color a block is, so a picture can be matched to blocks. Which block is nearest to a pixel is yours to work out.

The 88 blocks

In families, so the one you want is near the ones like it. Nothing here acts on its own: water does not flow, sand does not fall, and TNT explodes only if your program explodes it. Slime, vine, ladder, web, and ice react to you.

NameNotes
airthe empty cell; fill with it to take blocks away
Ground
the grass tilegrass
the dirt tiledirt
the sand tilesand
the gravel tilegravel
the stone tilestone
the snow tilesnow
the ice tileiceslippery: you keep sliding
Building
the wood tilewoodplanks
the birchwood tilebirchwoodpale planks; wood is oak's
the pinewood tilepinewoodreddish planks
the cherrywood tilecherrywooddark red planks
the palmwood tilepalmwoodwarm brown planks
the brick tilebrick
the sandstone tilesandstone
the cobble tilecobble
the slate tileslate
the tile tiletileterracotta roof tiles in overlapping rows
the marble tilemarblenear-white with gray veins
the thatch tilethatch
the clay tileclay
the glass tileglasssee-through
the iron tileiron
the gold tilegold
the lantern tilelanterngives light; a small cube on the floor of its cell
the lamp tilelamplooks lit and gives no light; put glowstone there to light it
the bookshelf tilebookshelftwo shelves of books on every side
Trees
the log tilelogbark on the sides, rings on the ends
the leaves tileleavesoak or birch foliage
the birch tilebirchwhite bark; a trunk
the pine tilepinedark bark; a trunk
the needles tileneedlespine foliage
the blossom tileblossompink foliage
the amber tileamberorange foliage
the cherry tilecherrydark bark with pale bands; the trunk for blossom
the palm tilepalma pale ringed trunk; the trunk for fronds
the fronds tilefrondspalm leaves, bright and coarse
Plants
the poppy tilepoppywalked through
the daisy tiledaisywalked through
the dandelion tiledandelionwalked through
the bluebell tilebluebellwalked through
the mushroom tilemushroomwalked through
the fern tilefernwalked through
the bush tilebushwalked through
the tuft tiletufttall grass; walked through
the cactus tilecactussolid, a little narrower than its cell
Under water
the kelp tilekelptall ribbons for the bottom of a pool or the sea. Water with a plant in it: you swim through it, and a pond with kelp in it has no seams
the coral tilecorala branching fan in two hues. Water with a plant in it, like kelp
the seafan tileseafanthe other coral: a purple fan on a stalk. Water with a plant in it, like kelp
the reeds tilereedsstraight stems with seed heads, for a shoreline; walked through
the lilypad tilelilypadlies flat on whatever is under it, a pond most of all; walked through, and it will not hold you up
Decoration
the moss tilemosssoft uneven green, for ruins and damp ground
the clover tilecloverlies flat on the block under it, grass most of all; walked through
the boulder tilebouldera rounded gray stone, smaller than its cell; solid
the crate tilecrateplanks with a cross of battens
the barrel tilebarrelstaves and two hoops
the bones tilebonespale, with dark lines along it, for caves
Farm
the pumpkin tilepumpkinribbed and orange
the jack tilejacka carved pumpkin with a face on every side; gives light
the melon tilemelongreen with dark stripes
the hay tilehaya bale of straw tied twice
Colors
the white tilewhite
the gray tilegrey
the black tileblack
the red tilered
the orange tileorange
the yellow tileyellow
the green tilegreen
the blue tileblue
the purple tilepurple
the pink tilepink
the brown tilebrown
Special
the glowstone tileglowstonegives light
the water tilewatersee-through. You sink in it slowly. Each press of Space is a stroke up, Shift held is a dive; where the ground is at the water's level, head out and Space held climbs out
the lava tilelavagives light; swum like water, at half the pace
the tnt tiletntexplodes only if your program explodes it
For games to point at
the chest tilechestholds nothing; your program gives it meaning
the target tiletargeta bullseye, to click
the button tilebuttonpresses nothing until your program reads a hit on it
the plate tileplateyour program can tell when you stand on it
the diamond tilediamond
the coal tilecoal
the copper tilecopper
the emerald tileemerald
Reacts to you
the ladder tileladderclimb with W and S, which do not walk you along while you climb; walked through otherwise
the vine tilevineclimb with W and S, which do not walk you along while you climb; walked through otherwise
the slime tileslimea fall onto it bounces
the web tilewebwalked through, slowly

When something is wrong

The console says so in a sentence: a misspelled block name suggests the right one, and an address outside the world says which number is out and what the edges are.

In the app

The pyblocks window: a toolbar across the top, the editor and the console down the left, the world on the right with the position readout at its top and the chat line at its bottom
The toolbar across the top, your program and the console on the left, the world on the right with where you are at its top and the chat line at its bottom.

In the world

click the worldtakes the mouse. Look around with the mouse or the arrow keys; Esc gives it back
W A S D Spacewalk and jump. Ctrl sprints, F flies
flyingSpace up, Shift down. Tap Space twice to fall; landing puts you back on foot
climbingon a vine or a ladder, W goes up and S goes down, and neither walks you along, so a tall one is climbed to the top. At the top you come off: onto whatever it reaches, or into a fall if there is nothing there. A or D lets go at any time, even with W held, and so does Space
swimmingyou sink slowly. Each press of Space is a stroke up, about one a second keeps your head out; Shift held dives. Where the ground is at the water's level, head out and Space held climbs out. A dive in splashes
left click, right clicka break hit and a place hit, for your program to read
Enter or Tchat, for your program to read
F5 F6Run, Stop. Ctrl+S saves, and running saves too. The version you saved over is kept beside your program as name.py.bak, one step back
Ctrl+click on import mykitopens mykit.py from beside your program. File, Open recent is the way back
F2a picture of the world, saved beside your program
Shift+F2a poster of it, big enough to print, with your program's title. # by Ada at the top of your program puts your name on it
F7steps the camera back: behind you, over your shoulder, then the world drawn flat from above, with the numbers along its edges. Press it again to come back. The tutorials have grid paper that prints that drawing empty, to plan a build on
F4point at a block: which line of your program put it there? The editor goes to it. Shift+F4 asks which line dug the space in front of it
Tools, Slow runthe world is drawn a few blocks a second and the editor marks the line behind each one, so you watch the program run rather than the blocks arrive
Tools, Replay barafter a run, a bar under the world you drag back through everything the program did, with the editor on the line that did it
F3the frame time and what the machine is paying for shadows and anti-aliasing
F1the help panel, with a button that opens this page
Play a file, Arcaderun someone else's program with its code out of sight. The Arcade lists a folder of them, and a program in that folder will not open in the editor