This page covers the core language surface. Board and protoboard APIs live under Hardware . CLI and editor behavior live under CLI and Interactive Profile .

Top-Level Forms

name is expr (core)

Layer: core
Behavior: Creates or rebinds a stable top-level slot. Rebinding changes the current value stored in that slot without changing the slot’s identity.
Example:

counter is 0
counter is counter + 1

name is fn [ ... ], to name with a, b [ ... ] (core)

Layer: core
Behavior: Binds a stable top-level slot to a Code value. The docs usually write zero-argument words as name is fn [ ... ] and use to ... with ... when the name and arguments read naturally together.
Example:

boot is fn [ led.on: ]

to blink with pin, wait [
  gpio.high: pin;
  ms: wait;
  gpio.low: pin
]

Calls and Operators

callee: arg1, arg2 (core call syntax)

Layer: core
Behavior: Calls a Code value with ordinary Frothy syntax. Calling any non-Code value is a runtime error.
Example:

blink: LED_BUILTIN, 75
gpio.write: LED_BUILTIN, 1

call expr with ... (core call syntax)

Layer: core
Behavior: Calls the result of a computed expression rather than a literal name. Useful when the callee itself is selected at runtime.
Example:

call pickAction: with

* / % + - < <= > >= == != and or (core operators)

Layer: core
Behavior: Left-to-right binary operators with equal precedence. Parentheses are the only grouping mechanism. Conditions require explicit Bool values.
Example:

(adc.percent: A0) > 50 and enabled

Locals and Mutation

here name is expr, name is expr inside a block (core)

Layer: core
Behavior: Creates a lexical local binding in the current block scope. Locals shadow outer locals and top-level names. Lookup always prefers the nearest reachable local before falling through to outer scopes and then the top level.
Example:

speed is 75

demo is fn [
  here speed is 10;
  speed
]

Worked example:

speed is 75

nested is fn [
  here speed is 10;
  when true [
    here speed is 3;
    speed
  ]
]

The result is 3, not 10 and not 75, because the innermost reachable local wins.

set place to expr (core)

Layer: core
Behavior: Mutates an existing place. A place is either a name or an indexed cells element. Record fields are also valid places. Missing places are an error.
Example:

set counter to counter + 1
set frame[0] to 99
set point->x to 12

Control Flow

if, when, unless (core)

Layer: core
Behavior: Conditional expressions that require Bool conditions. if without else yields nil when the condition is false.
Example:

when adc.percent: A0 > 50 [ led.on: ]

while, repeat, repeat ... as name (core)

Layer: core
Behavior: Loops over a condition or a count. while yields nil, and repeat ... as name exposes the loop index as a local.
Example:

repeat 4 as i [ led.blink: i + 1, 30 ]

Structured Data

cells(n), expr[index] (core)

Layer: core
Behavior: Cells is the narrow fixed-size mutable indexed store. Use cells(n) at top level to create a fixed store you can read and update by index.
Example:

buffer is cells(8)
set buffer[0] to 42

Worked example:

levels is cells(3)
set levels[0] to 20
set levels[1] to 40
set levels[2] to 60

to average3 with values [
  (values[0] + values[1] + values[2]) / 3
]

average3: levels

Use this shape when position is the real structure. values[0], values[1], and values[2] are three lanes in a fixed store, not three named fields on one record.

record Name [ field, ... ], Name: ... (core)

Layer: core
Behavior: Declares a fixed-layout record definition and uses the generated constructor slot to create shaped values.
Example:

record Point [ x, y ]
origin is Point: 0, 0

Worked example:

record Sprite [ x, y, visible ]

player is Sprite: 3, 4, true
set player->x to player->x + 1
set player->visible to false

player->x
player->visible

Use a record when the value represents one coherent thing with named parts. That is why player->x reads better than player[0].

Records may also be stored inside Cells:

pixels is cells(2)
set pixels[0] to Sprite: 1, 2, true
pixels[0]->y

fn [ ... ], fn with ... [ ... ] non-capturing rule (core)

Layer: core
Behavior: A Code value may use its own parameters, locals it binds in its own body, and top-level names. It may not capture locals from an enclosing block or function.
Example:

wait is 75

make-blink is fn [
  fn with pin [
    gpio.high: pin;
    ms: wait;
    gpio.low: pin
  ]
]

Working shape:

step is 1

make-stepper is fn [
  fn with x [ x + step ]
]

stepper is make-stepper:
stepper: 41

This works because step is top-level.

Rejected shape:

make-local-stepper is fn [
  here step is 1;
  fn with x [ x + step ]
]

This fails because the returned Code would need to capture the local step.

Rewrite it one of two ways:

step is 1
make-shared-stepper is fn [ fn with x [ x + step ] ]

adder is fn with x, step [ x + step ]

make-shared-stepper is valid because step is top-level. adder shows the other rewrite: if the value is not top-level, pass it as an argument at call time instead of trying to smuggle it in through closure capture.

Inspection and Persistence Built-Ins

words, show @name, see @name, core @name, info @name (interactive base image)

Layer: core
Behavior: Inspect the live image: visible names, normalized binding view, core debug view, and binding metadata.
Example:

words
info @blink
see @blink

save, restore, dangerous.wipe (interactive base image)

Layer: core
Behavior: Persist, rebuild, or clear the overlay image. dangerous.wipe returns the runtime to the base image.
Example:

save
restore
dangerous.wipe

Worked example:

record Counter [ value ]
counter is Counter: 0

set counter->value to 1
save
set counter->value to 9
restore
counter->value

After restore, counter->value is back to 1. The overlay state is what persists, not the last mutation you happened to make after saving.