Windy
| Paradigm(s) | imperative, two-dimensional, stack-based, concurrent |
|---|---|
| Designed by | Sangkeun Kim (sisobus) |
| Appeared in | 2026 |
| Memory system | infinite bi-directional sparse 2D grid + per-IP unbounded stack |
| Computational class | Turing complete |
| Reference implementation | windy-lang |
| File extension(s) | .wnd |
Windy is a two-dimensional esoteric programming language in which a program is laid out as a grid of Unicode characters. One or more instruction pointers (IPs) drift across the grid in one of eight winds — → ↗ ↑ ↖ ← ↙ ↓ ↘ — and execute the cell each one lands on at every tick.
The language has 35 opcodes total. There are no functions, no types, no modules, and no standard library — all program structure is emergent from grid layout, IP geometry, and inter-IP collisions.
The name is the Korean reading of the Pokémon Arcanine (윈디); the wind-direction mechanic is a thematic pun on the name.
Hello, Wind
The reference example is main.wnd in the source distribution, which prints the language's own name and halts:
↘
→→→↘→↘
~ →↗ " →·↘
~~ ↗sisobusY ↓ ~*
↗ ↗ →:#,_↘ D · ↙
↑ ↖ →t← " ↓
~* ↑← ↖←"WIN"←←↙
↖·← ↙·← ~↙
↖←←·←
$ windy run examples/main.wnd WINDY
The IP enters at (0, 0) heading east, NOPs across the empty stretch on row 0, then weaves down through the diagonals to row 2 where " opens string mode. The SE diagonal picks up Y and D before " closes it on row 5; the IP then bounces west via ←, opens string mode again at "WIN" on row 6 to push N/I/W, and climbs back to the print loop :#,_ on row 4. The loop drains the stack — outputting W, I, N, D, Y in order — and exits.
~ cells are pure decoration on this layout: the IP never visits them, so the random direction they would otherwise inject never fires. The sisobus string on row 3 is a watermark column the IP also never enters.
Design highlights
Eight winds, diagonals as primaries
The four diagonals (↗ ↖ ↙ ↘) are first-class glyphs, not synthesized from cardinal pairs. The intent is that programs read as flow diagrams — if you can draw the path the IP should take, you can encode it directly.
The four cardinals also accept ASCII aliases (> ^ < v) for typing convenience, but the printed form uses the Unicode arrows.
Wind speed
Each IP carries a strictly positive integer speed (default 1). The IP advances speed cells per tick, but only the destination cell decodes — intermediate cells are skipped entirely. No string-mode toggles, no unknown-glyph warnings, no opcode dispatch fires for the cells flown over.
≫(GUST) raises speed by 1.≪(CALM) lowers speed by 1; if this would yield 0, the runtime traps with exit code 134.
Speed, like the stack, is BigInt — there is no upper bound. High wind blows past obstacles.
Multi-IP concurrency with collision merge
The t (SPLIT) opcode spawns a new IP at (x − dx, y − dy) going (−dx, −dy) with empty stack, string mode off, and the parent's speed. Multiple IPs run concurrently — every tick, all live IPs execute their current cell in birth order, then move.
When two or more IPs share the same cell at end of tick, the runtime applies a deterministic collision merge:
- Stacks concatenate in birth order (oldest below).
- Direction vectors sum and are then clipped per axis to
{-1, 0, +1}. - If the clipped sum is
(0, 0), all participants die — head-on cancellation. - Otherwise a single survivor IP continues with the merged stack.
- Speed becomes the maximum of participants.
- String mode is reset to
falseon the survivor.
The merge rules are race-free and tick-deterministic. Programs that halt purely via collision merge — with no @ anywhere in the source — are routine.
Arbitrary precision throughout
Stack values, wind speeds, and grid coordinates are all unbounded integers. 2**1000-sized values, six-digit speeds, and grid coordinates at (10^18, -10^18) all work without special syntax or overflow.
Bi-infinite sparse grid
The grid extends infinitely in both directions from the origin (0, 0). Negative g/p coordinates are legal; unwritten cells default to 0x20 (the codepoint of ' ') on read and occupy zero memory until p writes to them.
Tick-determinism
Each tick is a single round-robin pass over live IPs in birth order. New IPs born during a tick wait until the next tick to execute. @ halts only the executing IP; collision merges happen in birth order at end-of-tick.
The same source, same --seed (for the ~ turbulence opcode), and same stdin produce the same stdout, byte for byte, across the native CLI, the WASI binary, and the browser WASM. The reference implementation pins this with two language-neutral JSON conformance harnesses.
Computational class
Windy is Turing complete. The four classical building blocks are all present:
- Unbounded memory — BigInt stack plus the sparse grid via
g/pwith BigInt coordinates is sufficient for an unbounded tape. - Conditional branching —
_(horizontal if) and|(vertical if) pop a value and branch on zero/non-zero. - Looping — winds redirect IP travel back across already-visited cells; the reference distribution's
fib.wndandfactorial.wnduse 2D loops. - Self-modification —
pwrites any value to any grid cell at run time, so a program can rewrite its own code.
Instruction set
35 opcodes split into eight functional groups:
| Group | Glyph | Effect |
|---|---|---|
| Flow | (space) · |
NOP |
| Flow | @ |
HALT — remove the executing IP from the live list. When the list empties, the program ends. |
| Flow | # |
TRAMPOLINE — advance one extra step in the current direction (skip the next cell). |
| Flow | t |
SPLIT — spawn a new IP at (x − dx, y − dy) going (−dx, −dy) with empty stack, string mode off, parent's speed.
|
| Wind | → (>) |
dir ← (+1, 0)
|
| Wind | ↗ |
dir ← (+1, −1)
|
| Wind | ↑ (^) |
dir ← (0, −1)
|
| Wind | ↖ |
dir ← (−1, −1)
|
| Wind | ← (<) |
dir ← (−1, 0)
|
| Wind | ↙ |
dir ← (−1, +1)
|
| Wind | ↓ (v) |
dir ← (0, +1)
|
| Wind | ↘ |
dir ← (+1, +1)
|
| Wind | ~ |
TURBULENCE — uniform random pick of the eight winds; deterministic with --seed.
|
| Speed | ≫ |
GUST — speed += 1.
|
| Speed | ≪ |
CALM — speed −= 1; runtime trap (exit 134) if it would yield 0.
|
| Literal | 0–9 |
push the digit's integer value. |
| Literal | " |
toggle string mode — between two ", every cell pushes its codepoint instead of executing.
|
| Arithmetic | + - * / % |
pop two, push result. Floor division and modulo. Divide by zero pushes 0. |
| Arithmetic | ! |
logical NOT — push 1 if top is 0, else 0. |
| Arithmetic | ` |
GT — pop b, pop a, push 1 if a > b else 0.
|
| Stack | : |
DUP — duplicate top. |
| Stack | $ |
DROP — pop and discard top. |
| Stack | \ |
SWAP — swap top two. |
| Branch | _ |
pop x; dir ← east if x == 0, else west.
|
| Branch | | |
pop x; dir ← south if x == 0, else north.
|
| I/O | . |
PUT_NUM — print top as decimal followed by a single space. |
| I/O | , |
PUT_CHR — print top as a Unicode character. |
| I/O | & |
GET_NUM — read one decimal integer from stdin; on EOF push −1.
|
| I/O | ? |
GET_CHR — read one Unicode character; on EOF push −1.
|
| Grid | g |
pop y, pop x, push G[(x, y)] (default 0x20 if unwritten).
|
| Grid | p |
pop y, pop x, pop v, write G[(x, y)] ← v.
|
Cells outside this table decode as NOP plus a one-shot warning per glyph on stderr.
Stack underflow on arithmetic, stack-manipulation, branch, or I/O ops treats the missing operand(s) as 0 — there is no trap.
Further examples
Add two integers from stdin
&&+.@
Five cells. Two & reads, + sums, . prints, @ halts.
$ echo "3 4" | windy run examples/add.wnd 7
Wind speed in action
"YDNIW"≫$,$,$,$,$,@@
Prints WINDY. The strmode segment loads five codepoints. ≫ raises speed to 2, so the IP lands on every other subsequent cell — exactly the , cells, flying over each $ in between. Without the speed change, the alternating $/, would discard a letter for every one printed. Wind speed is what gets the message to stdout; the trailing @@ is a parity pad — at speed 2 the IP needs the halt cell at an even offset from ≫.
Multi-IP collision halt
→1.2.3t4.5.6←@
Outputs 1 2 4 3 5 2 6 1 5 2 and halts with exit 0. The trailing @ is dead code.
- The IP enters east, prints
1and2, pushes3. tat column 6 spawns a child going west with empty stack.- Parent and child run on the same row simultaneously in opposite directions, each printing as they go.
- After bouncing off
←(parent) and→(child), they meet again at column 6 — the originaltcell — at the same tick. - Direction sum
(−1, 0) + (+1, 0) = (0, 0)→ both die. Live IP list is empty → program halts.
This is the canonical Windy halt pattern: deterministic concurrent IPs cancel each other out without an explicit terminator.
Asymmetric four-IP halt
→1.2.3t4.5t6.7←@
Outputs 1 2 4 3 2 6 5 1 7 4. Two SPLITs spawn four IPs; they pairwise collide at columns 4 and 10 in two distinct ticks. The asymmetric layout (5 cells west of t₁ versus 8 cells east of it) only halts cleanly because the spacing satisfies t₂ − t₁ = ← − t₂ = 4. Random asymmetric layouts cascade indefinitely — the engineered timing is what makes the four IPs collide just before either of them re-executes a t cell.
Spiral that prints "code flows like wind"
"dniw ekil swolf edoc"v
≫
→ , , , , , ↘
↘
≪→→t← ↓
, ,
, ,
, ,
, ,
, ,
↑ ↙
↖ , , , , , ←
Prints code flows like wind and halts. There is no @ anywhere in the source.
The IP rides a clockwise rotation at speed 2, printing one character per non-corner cell along the perimeter. At the eye of the spiral it drops back to speed 1 with ≪, runs t to spawn a counter-going child, and parent + child arrive at the same cell from opposite sides on the next tick. The end-of-tick collision pass cancels them, the live IP list empties, and the program halts. All four "Windy-only" mechanics — eight winds, wind speed, SPLIT, collision merge — appear in one program.
Reference implementation
A single Rust crate, hosted on GitHub at github.com/sisobus/windy and published on crates.io as windy-lang. It compiles to three targets:
- Native —
cargo install windy-langinstalls a CLIwindywith subcommandsrun,debug,version. The debugger steps tick by tick with full IP / stack / grid inspection. wasm32-wasip1— a portablewindy.wasmrunnable under any WASI host (wasmtime,wasmer, etc.).wasm32-unknown-unknown— the browser playground at windy.sisobus.com, with a step debugger and a click-to-insert glyph palette for typing the Unicode arrows.
Two language-neutral conformance harnesses (conformance/cases.json and conformance/v1.json) pin stdout byte-for-byte across all three targets. Future implementations are expected to consume the same JSON.
The interpreter prints a banner to stderr if the source contains the literal substring sisobus; this is part of the spec, and conforming implementations must preserve it.
External resources
- GitHub repository — Rust source, examples, conformance harnesses, CI workflows
- crates.io: windy-lang — published reference implementation
- Browser playground — write, run, and step-debug Windy programs in the browser; modal Vim-style editor with a click-to-insert glyph palette
- Language specification (SPEC.md) — single source of truth for opcode semantics, IP scheduling, and collision-merge rules
- Changelog — version history (Keep-a-Changelog format)
- Examples directory — annotated
.wndprograms from "Hello, World!" to four-IP asymmetric collision puzzles