Language reference

The Irene language

A small Python-flavoured language for making browser games. Designed for kids; honest about how real code works.

Generated from the interpreter source on 2026-05-27 — schema v1.

Overview

Irene is a small Python-flavoured language with significant indentation, a single numeric type, and first-class event handlers (on tick:, on key_down:, on collide:). It runs in a Web Worker in the browser as a tree-walking interpreter — there is no compile step, no async, no I/O. The world is the canvas.

Programs are made of top-level definitions (variables, functions, scenes) and event handlers. Top-level code runs once at start, then the game loop dispatches handlers every frame at roughly 60 Hz.

hero = sprite("panda", 100, 300)
score = 0

on key_down "space":
    hero.y = hero.y - 80
    play("jump")

on tick:
    hero.x = hero.x + 2
    text("Score: " + to_text(score), 10, 10)

Literals

The values you can write directly in source code.

SyntaxKindWhat it is
42 Number Whole numbers and decimals share one type — 3 and 3.0 are equal.
"hello" Text A string of characters in double quotes. Join with +.
true / false Boolean The two yes/no values used by conditions.
nothing Nothing The empty value — used when a variable holds no result.
[1, 2, 3] List An ordered collection. Read items with list[0]; loop with `for x in list`.
{name: "iris", age: 12} Record A bundle of named fields. Read with record.name; assign new fields with record.score = 0.

Operators

No +=, no ternary, no bitwise. Just the basics, plus and / or / not as words rather than symbols.

Arithmetic + - * / %
Numbers, plus + for joining text.
Comparison == != < > <= >=
Returns true or false.
Logical and or not
Combine and flip true/false values; `and`/`or` short-circuit.
Assignment =
First assignment creates a variable; later ones replace its value. No +=.

Keywords

Every reserved word Irene recognises, with what it does. Generated from the lexer's KEYWORDS table.

if
Do something only when a condition is true.
else
What to do when the `if` condition was false.
while
Keep repeating as long as a condition stays true.
for
Do something for each item in a list: `for item in things:`.
in
Used with `for` to step through each item in a list.
repeat
Do something a set number of times: `repeat 10:`.
function
Make your own reusable command.
return
Send a value back out of a function.
on
Start an event handler, like `on tick:` or `on key_down "space":`.
every
Run a block on a slower beat: `every 100:` does it every 100 milliseconds (great for snake-style games).
use
Borrow another file’s functions and values by name: `use enemies` lets you call things from enemies.irene here.
and
True only when both sides are true.
or
True when either side is true.
not
Flips true to false, and false to true.
true
A yes / on value.
false
A no / off value.
nothing
The empty value — nothing at all.
scene
Open a labelled story block: `scene "intro":`. Run it with `go_to "intro"`.
say
Show one line of story text in the panel below the canvas: `say "you find a torch"`. Click Continue to advance.
ask
Show a question with clickable choices. Each `"label":` row underneath is one button — its block runs when the kid picks. Execution pauses until then.
go_to
Jump to a scene by name: `go_to "inside"`. Wipes that scene's sprites and re-runs the target scene fresh. Top-level sprites + variables stay.

Statements

Block-structured constructs the parser accepts at the top level or inside other blocks. Blocks are introduced by : and indentation.

if / else

Branch on a condition. else-if chains as many times as you need.

if score > 100:
    win()
else if score > 50:
    cheer()
else:
    keep_going()

while

Repeat a block as long as the condition stays true.

while lives > 0:
    play_round()

for ... in

Step through every item of a list (or every character of text).

for enemy in enemies:
    enemy.x = enemy.x + 1

repeat

Do a block a fixed number of times. The counted loop, no index variable.

repeat 10:
    spawn_coin()

function

Define a reusable command. Functions are values — you can pass them around.

function distance(a, b):
    dx = a.x - b.x
    dy = a.y - b.y
    return sqrt(dx * dx + dy * dy)

use

Make another file's top-level definitions visible here. One file per concept.

use enemies

on start:
    spawn_wave()

Event handlers

Every Irene program is structured around on <event>: blocks. There is no main() — the runtime calls handlers at the right moment.

on start

Runs once when the game begins.

on start:
    score = 0

on tick

Runs every frame (~60 times a second). Throttle with `on tick every 100:`.

on tick:
    move_enemies()

every N

Sugar for `on tick every Nms:` — runs on a slower beat in milliseconds.

every 100:
    spawn_coin()

on key_down "<key>"

Fires once on a real key press. OS auto-repeat is filtered out — for smooth movement, poll key_held() inside on tick.

on key_down "space":
    player.jump()

on key_up "<key>"

Fires when the key is released.

on key_up "space":
    player.charging = false

on click

Mouse / touch click. mouse.x and mouse.y carry the position; combine with sprite.contains(x, y).

on click:
    if button.contains(mouse.x, mouse.y):
        play("ding")

on mouse_move

Fires while the pointer moves. mouse.x/mouse.y are live.

on mouse_move:
    crosshair.x = mouse.x

on collide a, b

Fires once per overlapping pair per frame. b is a sprite or list of sprites. Inside the body, `other` is the touched sprite.

on collide hero, coins:
    score = score + 1
    other.destroy()

Story mode

Story mode lets a game pause for narration and branching choices. A scene is a named block; go_to jumps into it; say queues a beat; ask presents clickable choices.

scene "cave":
    world.background = "cave"
    say "the torch flickers"
    ask "what do you do?":
        "press on":
            go_to "deeper"
        "turn back":
            go_to "outside"

on start:
    go_to "cave"

Built-in functions

Every callable the interpreter installs into the global scope, generated from BUILTINS in the runtime source. Square-bracketed parameters are optional; name: value are named arguments.

sprite(name, x, y)
Put a picture on the screen, e.g. dog = sprite("dog", 100, 100). Open "Pictures & sounds" to see every picture you can use.
text(message, x, y, [size], [color])
Draw words on the screen at position x, y. Add size (default 20) and a color ("red", "white", …) to style them — without a color it picks one that reads against your background.
tone(pitch, [seconds])
Play a musical note. pitch is a number (440) or a note name ("C"). seconds defaults to 0.2.
play(name)
Play a sound, e.g. play("jump"). Open "Pictures & sounds" to hear and pick from them all.
key_held(key)
True while a key is being held. Use inside on tick for smooth movement: if key_held("right"): hero.x = hero.x + 5.
draw_sprite(name, x, y, [width], [height], [rotation])
Draw a picture once, just for this frame — like text(), but a sprite. Great for snake-style games where you draw lots of moving pieces. Width and height default to the picture's natural size; pass rotation: 45 (named arg) to spin it without resizing.
draw_rect(x, y, width, height, [color])
Draw a filled rectangle for one frame. Quick custom shapes without making a sprite. color defaults to black.
draw_circle(x, y, radius, [color])
Draw a filled circle for one frame. color defaults to black.
draw_line(x1, y1, x2, y2, [color], [thickness])
Draw a line between two points for one frame. color defaults to black; thickness defaults to 2.
save(key, value, [shared: true])
Remember a value between plays. save("high_score", 100) keeps it just for you; add shared: true to share it across everyone playing. Pass nothing for the value to forget it.
load(key, [default], [shared: true])
Read a value you saved earlier. Returns the default (or nothing) if it was never saved. Add shared: true to read everyone's shared value, like a global high score.
to_text(value)
Turn a number into text so you can join it with +. e.g. "Score: " + to_text(score)
length(thing)
How many items are in a list (or letters in a word).
random()
A random number between 0 and 1.
random_int(low, high)
A random whole number from low to high.
pick(list)
Pick a random item from a list. e.g. pick(["red", "blue", "green"]).
abs(n)
The size of a number, ignoring its sign. abs(-5) is 5.
sqrt(n)
The square root of n.
floor(n)
Round a number down to a whole number.
ceil(n)
Round a number up to a whole number.
round(n)
Round a number to the nearest whole number.
min(a, b, ...)
The smallest of the numbers you give it.
max(a, b, ...)
The biggest of the numbers you give it.

Built-in objects

Pre-defined globals you read or assign to. Their fields are listed underneath.

world

The game world. Set world.background; read world.width and world.height. Scroll a wider world with world.camera_x and world.camera_y.

FieldTypeNotes
world.background = "skyblue" The colour or background image filling the screen. Try world.background = "skyblue", or pick one from "Backgrounds".
world.width = 800 Canvas width in pixels. Defaults to 800.
world.height = 600 Canvas height in pixels. Defaults to 600.
world.camera_x = 0 Camera offset along x. Scroll a wider world by moving this with your hero.
world.camera_y = 0 Camera offset along y. Set it to scroll vertically.

mouse

The pointer. Read mouse.x and mouse.y. Inside `on click:` they hold where the click happened — test with sprite.contains(mouse.x, mouse.y).

FieldTypeNotes
mouse.x number Pointer x in world coordinates. Updated before every mouse/click handler.
mouse.y number Pointer y in world coordinates.

Sprite members

Every value returned by sprite() exposes these fields and methods. Methods are called with . like hero.touching(coin).

sprite.x property
number
The sprite's left edge in world coordinates.
sprite.y property
number
The sprite's top edge in world coordinates.
sprite.width property
number
Override the displayed width. Leave unset to use the picture's natural size.
sprite.height property
number
Override the displayed height. Leave unset to use the picture's natural size.
sprite.image property
string
Name of the picture this sprite shows. Change it to swap appearance.
sprite.flip_horizontal property
true | false
Mirror the picture left/right. Handy when your hero turns around.
sprite.rotation property
degrees
Rotate the sprite, in degrees clockwise.
sprite.tile property
true | false
Repeat the picture across width × height instead of stretching it. Use for ground / floors.
sprite.animation property
string
Play one of the sprite's named animations. e.g. panda.animation = "walk" — runs idle / walk / jump / hit / throw / dead at 8 fps. Set to "" to stop.
sprite.frames property
list of names
A list of picture names to cycle through. Usually you set this via .animate(...) or animation = "walk".
sprite.fps property
number
Animation speed in frames per second. Used with frames.
sprite.frame_index property
number
Which frame is showing right now. The runtime advances this for you.
sprite.destroy() method
Take the sprite off the screen and out of collisions for good.
sprite.touching(other) method
True when this sprite overlaps another sprite. e.g. if hero.touching(coin):
sprite.touching_any(others) method
True when this sprite overlaps any sprite in a list.
sprite.first_touching(others) method
The first sprite from a list this one is overlapping — or nothing.
sprite.contains(x, y) method
True when point (x, y) is inside this sprite. Try sprite.contains(mouse.x, mouse.y).
sprite.animate(frames, fps) method
Cycle through frames at fps. frames is a list of picture names or a registered animation name like "soldier_walk".

This reference is auto-generated from the interpreter source. The complete language fits on a single page — that is deliberate. For the design rationale and longer-form examples, see the public DSL design notes.