Tutorial: build a bouncing ball

This tutorial walks through a complete, runnable WCHNT program — a ball bouncing inside a box. You can follow along in the Play page: paste each piece, press Run, and watch it move. This first draft is written by AI. But will shortly be rewritten by a human

By the end you'll have seen the four layers that make up every WCHNT program: Schema, Construction, Methods, and Target.

1. The file is markdown

A WCHNT program is an ordinary markdown file. Prose is for humans; the code goes inside fenced code blocks under a few reserved headings:

## Schema
… classes and relationships …

## Construction
… the initial data …

## Methods
… behaviour …

## Target
… how to run it …

Order matters, and each section appears at most once. Everything else in the file is ignored by the compiler.

2. Schema — what exists, and who owns whom

The Schema is the heart of assemblage programming: one flat map of the object network. Add a ## Schema section with these three classes:

## Schema

```
Game = PlayArea :Ball
PlayArea = Int/x Int/y Int/width Int/height
Ball = Int/x Int/y Int/dx Int/dy Int/rad
```

Read it like this:

The : in front of Ball is a relationship sigil. It makes the ball a context-specific component: the ball belongs to this particular game, and it gets an automatic back-reference called theGame so its methods can reach the rest of the assemblage. We use that below when the ball bounces off the play area.

Int is a primitive supplied by the host platform. Anything that isn't defined in your Schema is assumed to come from the platform.

Field names. By default a component's field name is its type name with a lower-cased first letter: PlayAreaplayArea, Ballball. You can override it with /: write Paddle/paddle1 to call the field paddle1.

3. Construction — the initial heap

Now tell WCHNT what the world looks like at the start. Construction is just a data literal, like a nested list with the class name first:

## Construction

```
[:Game
  [:PlayArea 0 0 800 600]
  [:Ball 200 150 6 5 16]]
```

Newlines are just spacing. You can keep or drop class labels wherever the compiler can infer them from the schema.

4. Methods — behaviour as expressions

Methods are attached to classes with ClassName::methodName. The body is an expression in curly braces. Let's make the ball bounce off the walls:

## Methods

```
Ball::bounceDX = {
  r = theGame.playArea.
  if ((x < r.x) or (x > (r.x + r.width))) { -dx } else { dx }
}

Ball::bounceDY = {
  r = theGame.playArea.
  if ((y < r.y) or (y > (r.y + r.height))) { -dy } else { dy }
}

Game::step = {
  ndx = ball.bounceDX().
  ndy = ball.bounceDY().
  [:Game playArea [:Ball (ball.x + ndx) (ball.y + ndy) ndx ndy ball.rad]]
}
```

Things to unpack:

Game::step returns a new Game — same playArea, new ball. Methods are mostly pure: they return new data rather than mutating.

Typed arguments. A method parameter is just a name (px), but you can annotate it with a type when the compiler needs it for field access: Rect/bounds. More on this in the Guide.

5. Target — where it runs

The last layer names the outer environment. That's what changes when you move from a terminal to a window to a browser. The Play page uses the %canvas host:

## Target

```
%canvas

%init
var assemblage;

function init() {
    assemblage = gameFactory();
}

%step
function step() {
    assemblage = assemblage.step();
    var r = assemblage.playArea;
    var b = assemblage.ball;
    wchntGraphics.clear();
    wchntGraphics.beginFill(0x2a2a2a);
    wchntGraphics.drawRect(r.x, r.y, r.width, r.height);
    wchntGraphics.endFill();
    wchntGraphics.beginFill(0xf2f2f2);
    wchntGraphics.drawCircle(b.x, b.y, b.rad);
    wchntGraphics.endFill();
}
```

The browser harness runs init once and step every frame. gameFactory() builds your assemblage; assemblage.step() advances it; wchntGraphics draws it. Target code is real JavaScript here — but Schema, Construction, and Methods stay exactly the same across hosts.

6. Run it

Open Play, then click New and give the page a name (e.g. bounce) so you get a fresh page to work in — the editor opens a blank page ready to edit. Paste the full program above into that page and press Run. A grey ball should bounce inside the box. Try changing the ball's radius or velocity in Construction, or the wall colour in Target.

Where next

The Guide explains every part of the language in detail — the relationship sigils, collections, update() and reactive dependencies, and the other Target hosts.