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()
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.
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)
The values you can write directly in source code.
| Syntax | Kind | What 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. |
No +=, no ternary, no bitwise. Just the basics, plus and / or / not as words rather than symbols.
Every reserved word Irene recognises, with what it does. Generated from the lexer's KEYWORDS table.
Block-structured constructs the parser accepts at the top level or inside other blocks. Blocks are introduced by : and indentation.
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()
Repeat a block as long as the condition stays true.
while lives > 0:
play_round()
Step through every item of a list (or every character of text).
for enemy in enemies:
enemy.x = enemy.x + 1
Do a block a fixed number of times. The counted loop, no index variable.
repeat 10:
spawn_coin()
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)
Make another file's top-level definitions visible here. One file per concept.
use enemies
on start:
spawn_wave()
Every Irene program is structured around on <event>: blocks. There is no main() — the runtime calls handlers at the right moment.
Runs once when the game begins.
on start:
score = 0
Runs every frame (~60 times a second). Throttle with `on tick every 100:`.
on tick:
move_enemies()
Sugar for `on tick every Nms:` — runs on a slower beat in milliseconds.
every 100:
spawn_coin()
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()
Fires when the key is released.
on key_up "space":
player.charging = false
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")
Fires while the pointer moves. mouse.x/mouse.y are live.
on mouse_move:
crosshair.x = mouse.x
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 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"
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)
text(message, x, y, [size], [color])
tone(pitch, [seconds])
play(name)
key_held(key)
draw_sprite(name, x, y, [width], [height], [rotation])
draw_rect(x, y, width, height, [color])
draw_circle(x, y, radius, [color])
draw_line(x1, y1, x2, y2, [color], [thickness])
save(key, value, [shared: true])
load(key, [default], [shared: true])
to_text(value)
length(thing)
random()
random_int(low, high)
pick(list)
abs(n)
sqrt(n)
floor(n)
ceil(n)
round(n)
min(a, b, ...)
max(a, b, ...)
Pre-defined globals you read or assign to. Their fields are listed underneath.
The game world. Set world.background; read world.width and world.height. Scroll a wider world with world.camera_x and world.camera_y.
| Field | Type | Notes |
|---|---|---|
| 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. |
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).
| Field | Type | Notes |
|---|---|---|
| mouse.x | number | Pointer x in world coordinates. Updated before every mouse/click handler. |
| mouse.y | number | Pointer y in world coordinates. |
Every value returned by sprite() exposes these fields and methods. Methods are called with . like hero.touching(coin).
sprite.x
property
sprite.y
property
sprite.width
property
sprite.height
property
sprite.image
property
sprite.flip_horizontal
property
sprite.rotation
property
sprite.tile
property
sprite.animation
property
sprite.frames
property
sprite.fps
property
sprite.frame_index
property
sprite.destroy()
method
sprite.touching(other)
method
sprite.touching_any(others)
method
sprite.first_touching(others)
method
sprite.contains(x, y)
method
sprite.animate(frames, fps)
method
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.