Tutorial
This walks through the examples, one idea at a time. Read it top to bottom; each section assumes the one before it.
The reference compiler is still a skeleton, so the
cairn compilecommands below do not run yet. They match the spec exactly, which makes them the right way to build intuition for the CLI.
1. A cottage
Section titled “1. A cottage”cottage.crn is a complete
Cairn build.
@cairn 2026.06@requires version>=1.20
theme medieval: slot floor -> @oak_planks slot wall -> @cobblestone slot roof -> @spruce_stairs slot glass -> @glass_pane
struct cottage size=9x7 floor mat_slot=floor walls class=outer mat_slot=wall height=4 door side=front at=center window class=small side=front offset=2 y=2 size=2x2 sym=true mat_slot=glass roof kind=gable mat_slot=roof overhang=1Compile it for either edition:
cairn compile examples/cottage.crn --edition java --target 1.21.4cairn compile examples/cottage.crn --edition bedrock --target 1.21.40The Minecraft version is never in the source. It lives in --target, and --edition is
required alongside it. What the source may declare is @requires, a floor on what the target has
to support, and @cairn, the language version the file was written against.
The struct says where; the theme says what. mat_slot=wall is an injection point, not a block
name. The theme binds it. Swap theme medieval for another and the geometry never changes. This is
the CSS idea, applied to blocks.
Positions are semantic. side=front, offset=2, y=2, at=center are positions along a wall.
No absolute coordinates appear anywhere you write.
Order does not matter. The window is written after the roof and is still cut as an opening
in the wall. The compiler sorts commands into fixed phases before evaluating them, so you can write
lines in whatever order reads best.
Blockstate is derived. Nobody writes facing=south for the door, north=tall for the wall, or
the pane’s connected state. The compiler works them out from position and neighbours.
2. Abstract materials and levels
Section titled “2. Abstract materials and levels”themed-tower.crn adds
three ideas to the same shape.
theme keep_dark: slot floor -> @floor.wood.broadleaf # abstract token slot wall -> @wall.stone.cobble slot trim -> @wood.dark slot roof -> @roof.dark_wood
struct keep size=11x9 floor id=base mat_slot=floor walls id=shell mat_slot=wall height=5 roof id=roof kind=gable mat_slot=roof overhang=1
level id=floor1 y=0 ...
level id=floor2 y=5 walls id=upper class=outer mat_slot=wall height=4 window class=arrow_slit side=front repeat=3 step=2 y=2 size=1x2 shape=slit stair id=eave kind=stairs mat_slot=roof side=front half=top facing=out shape=outer_leftTwo kinds of token. @oak_planks is a canonical block token, a specific meaning that can
never be silently downgraded. @floor.wood.broadleaf is an abstract material token, an aesthetic
choice a theme may resolve to oak or birch depending on the target.
level y=5 gives the upper floor its own y=0. The second-floor window stays at y=2 from its
own floor rather than from the ground.
Writing a blockstate promotes it to intent. The stair id=eave line writes half=top facing=out shape=outer_left explicitly, so those values are now yours, not the compiler’s. The rule is “derive
by default; any blockstate that can be intent is overridable”.
Read on: Materials and Themes, Blockstate Model.
3. Redstone as a signal graph
Section titled “3. Redstone as a signal graph”Instead of placing dust and repeaters, you declare what depends on what.
redstone-door.crn:
struct gatehouse size=7x5 floor mat_slot=wall walls class=outer mat_slot=wall height=3 door id=front side=front at=center mat_slot=door
pressure_plate id=plate at=front.outside offset=0 y=0 -> sig.step pressure_plate id=inner at=inside.front offset=1 y=0 -> sig.exit
logic sig.open = sig.step or sig.exit door[id=front] opened_by=sig.open
circuit region=floor void=2
assert truth(sig.step, sig.exit -> sig.open) { 00->0; 01->1; 10->1; 11->1 } assert always(sig.step -> eventually sig.open within 2)Sensors emit, actuators consume. -> sig.step is a sensor’s output; opened_by=sig.open is an
actuator’s input. logic writes the dependency between them.
There is no tick arithmetic. The logic expression carries no time at all. The within 2 in the
assertion is the only place a number means ticks, because delay is not known until the circuit has
been placed and routed.
circuit region=… reserves space for place-and-route. If routing does not fit you get
E_ROUTE_CONGESTION with a suggested fix, never a silent overflow.
Assertions come in three kinds: truth(…) for combinational logic, latency(in → out) <= N for
bounded delay, and always(in -> eventually out within N) for bounded temporal. There is
no full LTL by design, only what a per-tick simulator can decide cheaply.
The edition difference is in the cell library, not the language. The same logic becomes a
ComparatorAND cell on Java and a TorchAND on Bedrock. Circuits that depend on quasi-connectivity
or block-update order are a compile error rather than a silent footgun.
Read on: Redstone.
4. Several buildings
Section titled “4. Several buildings”Once one cottage works, reuse it.
village.crn:
def cottage size=9x7: floor id=floor mat_slot=floor walls id=walls class=outer mat_slot=wall height=4 door id=entry class=entry side=front at=center window id=front side=front y=2 offset=2 size=2x2 mat_slot=glass roof id=roof kind=gable mat_slot=roof overhang=1
site hamlet: place id=home1 use=cottage theme=medieval at=origin place id=home2 use=cottage theme=medieval east_of=home1 gap=4 place id=home3 use=cottage theme=medieval north_of=home1 gap=5
connect home1.entry to home2.entry path=@gravel connect home1.entry to home3.entry path=@graveldef is a reusable component built on the same slot mechanism as theme and site, so
references work the same way across editing, theming, and multi-building.
Placement is relational. east_of=home1 gap=4 is a constraint; turning it into coordinates is
the compiler’s job. That removes the single worst class of LLM arithmetic error.
Structs expose ports. home1.entry is the door member declared in the def, and connect
joins two ports with a walkway.
The 48³ structure-block limit dissolves. A village too large for one structure block is
several defs composed on a site.
Read on: Components, Editing, and Multi-building.
Where to go next
Section titled “Where to go next”| If you want to… | Read |
|---|---|
| Change part of a build without rewriting it | Editing model §9.2, as in edit window[class=vent] set shape=arch |
| Know which Minecraft versions a file works on | Versioning and Editions §10.5, the cairn info report |
| Bring an existing schematic into Cairn | Ecosystem Interop: transliterate, lift, voxel-diff |
| Try the other roof kinds | The roof-shed, roof-hip, and roof-flat examples |
| Look up a term | Glossary |