Enu API Reference

Constants

ASAP

Magic speed value. speed = ASAP makes a build draw everything at once instead of block by block.

ASAP = 0.0

Source: enu/types

Enums

Directions

The 6 directions a unit can move, turn or lean. Each one has a single-letter shorthand, so turn r means turn right.

Directions = enum
  up, u, down, d, left, l, right, r, forward, f, back, b

Source: enu/types

Colors

The colors blocks come in. eraser isn't really a color — it removes blocks instead of drawing them.

Colors = enum
  eraser, blue, red, green, black, white, brown

Source: enu/types

Tools

Everything that can go in a player's toolbar: the code editor, one tool for each block color, and the bot placer.

Tools = enum
  CodeMode, BlueBlock, RedBlock, GreenBlock, BlackBlock, WhiteBlock, BrownBlock,
  PlaceBot, None

Source: enu/types

Types

Bot

A robot character. Bots can walk, run, play animations, and be programmed to do whatever you like.

Bot = ref object of Unit

Source: enu/types

Bot.all

Every unit of a kind in the world: Bot.all, Build.all, Player.all, Sign.all or Unit.all. Loop over them with for bot in Bot.all:.

proc all(_: type Bot): Query[seq[Bot]]
go_home

Head back to the start position by turning around and walking there. Also resets scale, glow, and hides any open sign.

proc go_home(self: Bot)
play

Play an animation by name, like play "wave". Play "" to stop.

proc play(self: Bot; animation_name: string)
run

Running speed. The same as speed = 5.

proc run(self: Bot)
walk

Walking speed. The same as speed = 1.

proc walk(self: Bot)

Build

Something made of blocks. Builds have a drawing turtle that commands like forward and turn steer around.

Build = ref object of Unit

Source: enu/types

Build.all
proc all(T: type Build): Query[seq[Build]]
advance

Translate the turtle by steps along its current forward direction without going through begin_move. No drawing, no animation, no speed/ASAP interaction. Used by wall / floor to leave the turtle at the far end of the shape.

proc advance(self: Build; steps: float)
begin_asap
proc begin_asap(self: Build)
bounds_at

The box this build would take up at a different position, rotation or scale. Check before you leap.

proc bounds_at(self: Build; position: Vector3; rotation: float = 0.0;
               scale: float = 0.0): WorldBox
box

Draw a box. box 5, 3, 8 makes one 5 wide, 3 tall and 8 deep, starting where the turtle is and facing the way it faces. Or draw it somewhere else with at = vec3(...), or between two corners with box corner1, corner2. fill = false makes it hollow, like a room.

proc box(self: Build; width, height, depth: int; color = self.color;
         fill = true; pivot: BoxPivot = corner)

proc box(self: Build; width, height, depth: int; at: Vector3;
         color = self.color; rotation = 0.0; fill = true;
         pivot: BoxPivot = corner)

proc box(self: Build; at, to: Vector3; color = self.color; fill = true)
cylinder

Draw a cylinder, size blocks across and height blocks tall, standing on the turtle's spot. Draw it somewhere else with at = vec3(...). can means the same thing.

proc cylinder(self: Build; size: float; height: int; color = self.color;
              fill = true)

proc cylinder(self: Build; size: float; height: int; at: Vector3;
              color = self.color; fill = true)

proc cylinder(self: Build; size: int; height: int; color = self.color;
              fill = true)

proc cylinder(self: Build; size: int; height: int; at: Vector3;
              color = self.color; fill = true)
draw_position

Where the turtle is. Assign a position (or a unit) to teleport the turtle there and keep drawing.

proc draw_position(self: Build): Vector3
draw_position=
proc draw_position=(self: Build; value: Vector3)

proc draw_position=(self: Build; unit: Unit)
draw_voxel

Paints a COMPUTED block at the given position. Re-runs of the script regenerate it, so it isn't persisted to the save file. Used by place (the box/sphere/cylinder primitives draw host-side). For persistent placement (eg. user edits via eval, holes for windows) use place_block from builds_private, which marks the voxel MANUAL.

proc draw_voxel(self: Build; position: Vector3; color: Colors)
drawing

Whether the turtle draws blocks as it moves. drawing = false lets you sneak the turtle somewhere without leaving a trail.

proc drawing(self: Build): bool
drawing=
proc drawing=(self: Build; drawing: bool)
end_asap
proc end_asap(self: Build)
fill_square

Draw a filled square, length blocks on a side.

proc fill_square(self: Build; length = 1)
go_home

Head back to the start position by going forward, left, and down the right amounts. Also resets rotation, scale and glow.

proc go_home(self: Build)
place

Put a single block at exact coordinates, without moving the turtle. place 3, 0, 5, red.

proc place(self: Build; x, y, z: int; color = self.color)
reload_unit

Reloads the Build's voxel data from disk without stopping the script.

proc reload_unit(self: Build)
rendered_voxel_count_get
proc rendered_voxel_count_get(self: Build): int
restore

Jump the turtle back to a spot remembered with save.

proc restore(self: Build; name = "default")
save

Remember the turtle's position, direction, color and drawing state, so restore can jump back later. Give it a name to keep more than one: save "doorway".

proc save(self: Build; name = "default")
sphere

Draw a sphere, size blocks across, centred on the turtle. Draw it somewhere else with at = vec3(...). ball means the same thing and is more fun to say.

proc sphere(self: Build; size: float; color = self.color; fill = true)

proc sphere(self: Build; size: float; at: Vector3; color = self.color;
            fill = true)

proc sphere(self: Build; size: int; color = self.color; fill = true)

proc sphere(self: Build; size: int; at: Vector3; color = self.color; fill = true)

Context

Context = ref object
  stack*: seq[Frame]

Source: enu/types

advance

advance state machine. Returns true if statemachine is still running. It's ok to run this from within the statemachine, but Halt exceptions must be allowed to propagate.

proc advance(ctx: Context; frame: Frame = nil): bool

Directions

lean

Tip the unit (or the drawing turtle) forward, back, left or right. Like turn, but instead of spinning like a top, you tilt — which lets the turtle draw up and down walls or loop-the-loops.

template lean(direction: Directions; degrees = 90.0)
t

Shorthand for turn.

template t(direction: Directions; degrees = 90.0)
turn

Turn the unit (or the drawing turtle). You can turn:

  • a direction: turn left, or turn left, 45 for 45 degrees
  • a number of degrees: turn 90 (positive turns right, negative turns left)
  • toward something: turn player
  • away from something: turn -player

t is the short version.

template turn(direction: Directions; degrees = 90.0)

Duration

An amount of time. Subtracting two timestamps gives you one.

Duration = object

Source: enu/types

Duration.init
proc init(_: type Duration; seconds: float): Duration
$
proc `$`(d: Duration): string
>=
proc `>=`(a, b: Duration): bool
>
proc `>`(a, b: Duration): bool
<=
proc `<=`(a, b: Duration): bool
<
proc `<`(a, b: Duration): bool
+
proc `+`(a, b: Duration): Duration
-
proc `-`(a, b: Duration): Duration
==
proc `==`(a, b: Duration): bool
milliseconds

The duration as a number of milliseconds.

proc milliseconds(d: Duration): float
seconds

The duration as a number of seconds.

proc seconds(d: Duration): float

Frame

Frame = ref object
  manager*: proc (active: bool): bool
  action*: proc ()

Source: enu/types

Loop

Loop = ref object
  states*: Table[string, NimNode]
  from_states*: seq[(string, NimNode)]

Source: enu/types

Player

A person playing the game. The one at this computer is named player.

Player = ref object of Unit

Source: enu/types

Player.added

Players who joined since the last time you asked. Useful in a loop to greet newcomers.

proc added(_: type Player): Query[seq[Player]]
Player.all
proc all(_: type Player): Query[seq[Player]]
Player.hit

The players currently touching this unit, if any. if Player.hit as toucher: grabs one to work with.

proc hit(_: type Player): Query[seq[Player]]
bounce

Launch the player into the air. More power, more air.

proc bounce(me: Player; power = 1.0)
coding

The unit whose code the player has open, or nil if the editor is closed. Assign a unit to open its code for them.

proc coding(self: Player): Unit
coding=
proc coding=(self: Player; value: Unit)
flying

Whether the player is flying. player.flying = true — no double-jump needed.

proc flying(self: Player): bool
flying=
proc flying=(self: Player; value: bool)
god

God mode: hidden things show up, and locked things can be edited. With great power, etc.

proc god(self: Player): bool
god=
proc god=(self: Player; value: bool)
number

Which player this is: player 1, player 2, and so on.

proc number(self: Player): int
open_sign

The sign the player is reading, or nil if none. Assign a sign to shove it in front of them.

proc open_sign(self: Player): Sign
open_sign=
proc open_sign=(self: Player; value: Sign)
playing

true in play mode, false in edit mode. Assign to switch.

proc playing(self: Player): bool
playing=
proc playing=(self: Player; value: bool)
running

Whether the player is running.

proc running(self: Player): bool
running=
proc running=(self: Player; value: bool)
tool

The tool the player is holding right now, like CodeMode or BlueBlock. Assign to switch tools for them.

proc tool(self: Player): Tools
tool=
proc tool=(self: Player; value: Tools)
tools

The tools in the player's toolbar. Check with in, add with incl, remove with excl, or assign a whole set: player.tools = {CodeMode, BlueBlock}.

proc tools(self: Player): ToolSet
tools=

Replace the whole toolbar at once: player.tools = {CodeMode, BlueBlock, PlaceBot}.

proc tools=(self: Player; value: set[Tools])
tools_clear
proc tools_clear(self: Player)
tools_excl
proc tools_excl(self: Player; tool: Tools)
tools_has
proc tools_has(self: Player; tool: Tools): bool
tools_incl
proc tools_incl(self: Player; tool: Tools)

PositionOffset

A position plus a distance, like home + 5. Move commands accept these as targets.

PositionOffset = object
  position*: Vector3
  offset*: float
  direction*: Vector3

Source: enu/types

+

Add or subtract extra distance from a spot like home. forward home + 2 stops 2 blocks past home.

proc `+`(self: PositionOffset; offset: float): PositionOffset
-
proc `-`(self: PositionOffset; offset: float): PositionOffset
back
template back(offset: PositionOffset)
down
template down(offset: PositionOffset)
forward
template forward(offset: PositionOffset)
left
template left(offset: PositionOffset)
right
template right(offset: PositionOffset)
up
template up(offset: PositionOffset)

Query

The answer to a question like Bot.all or ?player. Acts like true or false in an if, and may carry results you can loop over.

Query[T] = object of RootObj
  result*: T
  truthy*: bool

Source: enu/types

Query.init
proc init[T](_: type Query; results: openArray[T]): Query[seq[T]]
[]
proc `[]`[T: Unit](self: Query[seq[T]]; index: int): T
as

Grab a result from a query and give it a name, right inside an if: if Player.hit as toucher: toucher.bounce. Only works inside a command loop.

template `as`[T](q: Query[seq[T]]; name: untyped): bool
items
iterator items[T](self: Query[seq[T]]): T
len
proc len[T: Unit](self: Query[seq[T]]): int

Sign

A sign or message floating in the world.

Sign = ref object of Unit

Source: enu/types

Sign.all
proc all(_: type Sign): Query[seq[Sign]]
billboard

Whether the sign spins to always face the player, like it's watching you. (Politely.)

proc billboard(self: Sign): bool
billboard=
proc billboard=(self: Sign; value: bool)
height

How tall the sign is, in blocks.

proc height(self: Sign): float
height=
proc height=(self: Sign; value: float)
message

The text on the sign. It's markdown, so **bold**, lists and headings all work.

proc message(self: Sign): string
message=
proc message=(self: Sign; value: string)
more

Extra text shown when the player opens the sign — good for the long version of the story.

proc more(self: Sign): string
more=
proc more=(self: Sign; value: string)
open

Whether the sign is open full-screen for reading. Set it to pop the sign open (or slam it shut).

proc open(self: Sign): bool
open=
proc open=(self: Sign; value: bool)
size

The text size. Bigger numbers, bigger letters.

proc size(self: Sign): int
size=
proc size=(self: Sign; value: int)
width

How wide the sign is, in blocks.

proc width(self: Sign): float
width=
proc width=(self: Sign; value: float)

Timestamp

A point in time, measured in seconds since Enu started. Get one with now().

Timestamp = object

Source: enu/types

Timestamp.init
proc init(_: type Timestamp; seconds: float): Timestamp
$
proc `$`(t: Timestamp): string
>
proc `>`(a, b: Timestamp): bool
<
proc `<`(a, b: Timestamp): bool
+
proc `+`(a: Timestamp; b: Duration): Timestamp
-

Subtract timestamps to find out how much time passed between them.

proc `-`(a, b: Timestamp): Duration
proc `-`(a: Timestamp; b: Duration): Timestamp

ToolSet

Set-like view over a player's available tools. Operations forward to the host one tool at a time, so no real set crosses the bridge.

ToolSet = distinct Player

Source: enu/players

$
proc `$`(tools: ToolSet): string
clear

Empty the toolbar completely.

proc clear(tools: ToolSet)
contains

true if the tool is in the toolbar: if PlaceBot in player.tools:.

proc contains(tools: ToolSet; tool: Tools): bool
excl

Take a tool out of the toolbar.

proc excl(tools: ToolSet; tool: Tools)
incl

Add a tool to the toolbar.

proc incl(tools: ToolSet; tool: Tools)
items
iterator items(tools: ToolSet): Tools
len
proc len(tools: ToolSet): int

Unit

Anything that exists in the world — a build, a bot, a sign, or the player. Most commands work on any unit.

Unit = ref object of RootObj
  name*: string
  advance_state_machine*: proc (): bool
  sign*: Sign
  query_results*: Table[string, seq[Unit]]

Source: enu/types

Unit.all
proc all(_: type Unit): Query[seq[Unit]]
-

A minus sign in front of a unit means "away from it". turn -player turns your back on the player. Rude, but allowed.

proc `-`(node: Unit): NegativeNode
in
proc `in`(unit: Unit): bool
adopt

Make another unit this unit's child, so it moves when this one moves.

proc adopt(self: Unit; unit: Unit)
anchor

Re-anchor an existing instance. Visibly moves/reorients the instance because it's already rendered; the unit's position and rotation stay constant from the user's perspective.

template anchor(target: Unit; body: untyped)
angle_to

How many degrees this unit would have to turn to face a position (or another unit).

proc angle_to(self: Unit; position: Vector3): float

proc angle_to(self: Unit; enu_target: Unit): float
apply_position

Teleport the unit, unless the position is unset. Used by Enu internally.

proc apply_position(self: Unit; position: Vector3)
b

Shorthand for back.

template b(self: Unit; steps = 1.0)
back

Like forward, but backward.

proc back(self: Unit; steps: float; move_mode: int)

template back(self: Unit; steps = 1.0)
proc back(self: Unit; value: PositionOffset; move_mode: int)

template back(self: Unit; value: PositionOffset)
block_log
proc block_log(self: Unit): string
bounds

The invisible box around the unit and everything it's made of.

proc bounds(self: Unit): WorldBox
build

Switch to build mode: commands like forward and turn steer the drawing turtle, leaving a trail of blocks. This is the normal mode for a Build, so you mostly need it to switch back after move, or to aim commands at a different unit: build enemy.

template build(new_enu_target: Unit)
capture_start_transform
proc capture_start_transform(self: Unit)
clear_block_log
proc clear_block_log(self: Unit)
color

The unit's color. For a Build this is the drawing color — blocks you draw after changing it use the new color.

proc color(self: Unit): Colors
color=
proc color=(self: Unit; color: Colors)
create_new
proc create_new(self: Unit)
current_colliders
proc current_colliders(self: Unit; name: string): seq[Unit]
d

Shorthand for down.

template d(self: Unit; steps = 1.0)
delete

Remove the unit from the level, along with its script and saved data. There's no undo, so be really sure.

proc delete(self: Unit)
distance
proc distance(node: Unit): float
down

Go down this many blocks (1 if you don't say).

proc down(self: Unit; steps: float; move_mode: int)

template down(self: Unit; steps = 1.0)
proc down(self: Unit; value: PositionOffset; move_mode: int)

template down(self: Unit; value: PositionOffset)
exec_instance
proc exec_instance(self: Unit)
f

Shorthand for forward.

template f(self: Unit; steps = 1.0)
forward

Go forward this many blocks (1 if you don't say). In build mode the turtle draws blocks as it goes; in move mode the whole unit moves. You can also pass a spot like home: forward home goes forward until you're even with it, and forward home + 2 goes 2 blocks past.

proc forward(self: Unit; steps: float; move_mode: int)

template forward(self: Unit; steps = 1.0)
proc forward(self: Unit; value: PositionOffset; move_mode: int)

template forward(self: Unit; value: PositionOffset)
frame_created

The frame number when the unit was created.

proc frame_created(self: Unit): int
global

Whether the unit lives in world space (true) or moves around with its parent (false).

proc global(self: Unit): bool
global=
proc global=(self: Unit; global: bool)
glow

How much the unit glows. 0 is no glow; crank it up to make something impossible to miss.

proc glow(self: Unit): float
glow=
proc glow=(self: Unit; energy: float)
go

Teleport the unit to a position, or to another unit. The same as setting position=.

proc go(self: Unit; position: Unit | Vector3)

Travel to another unit: turn to face it, head forward until you arrive, then drop down to its height.

proc go(unit: Unit)
height
proc height(self: Unit): float
hit
proc hit(self: Unit; node: Unit): bool

true if this unit is touching another unit. if player.hit:.

proc hit(unit: Unit): bool
id

The unit's name, like "bot_1729". Every unit has a different one.

proc id(self: Unit): string
l

Shorthand for left.

template l(self: Unit; steps = 1.0)
lean

Tip the unit (or the drawing turtle) forward, back, left or right. Like turn, but instead of spinning like a top, you tilt — which lets the turtle draw up and down walls or loop-the-loops.

proc lean(self: Unit; direction: Directions; degrees = 90.0; move_mode: int)

proc lean(self: Unit; degrees: float; move_mode: int)

template lean(self: Unit; direction: Directions; degrees = 90.0)
template lean(self: Unit; degrees: float)
left

Go left this many blocks (1 if you don't say). Slides sideways — no turning.

proc left(self: Unit; steps: float; move_mode: int)

template left(self: Unit; steps = 1.0)
proc left(self: Unit; value: PositionOffset; move_mode: int)

template left(self: Unit; value: PositionOffset)
local_position

Where the unit is compared to its parent, instead of the world.

proc local_position(self: Unit): Vector3
lock

Locked units can't be edited in the world with the mouse. Good for finished builds you don't want to nudge by accident.

proc lock(self: Unit): bool
lock=
proc lock=(self: Unit; value: bool)
new_instance
proc new_instance(src, dest: Unit)
over
proc over(node: Unit): bool
overlaps

true if two units' boxes overlap.

proc overlaps(a: Unit; b: Unit): bool
pending_block_updates

How many block changes are still being worked on. 0 means everything you've drawn is actually on screen.

proc pending_block_updates(self: Unit): int
pending_block_updates_get

Unfinished voxel pipeline work (queued, in-flight, or awaiting apply) for the unit and its descendants. 0 = every submitted edit is meshed and visible.

proc pending_block_updates_get(self: Unit): int
position

Where the unit is. Assign to it to teleport: position = player.position (zap!).

proc position(self: Unit): Vector3
position=

Teleport the unit. No walking, no animation — it's just there now. You can also assign another unit to teleport to wherever it is: me.position = player.position, or just me.position = player.

proc position=(self: Unit; position: Vector3)

proc position=(self: Unit; unit: Unit)
r

Shorthand for right.

template r(self: Unit; steps = 1.0)
register_active
proc register_active(self: Unit)
register_template_node
proc register_template_node(self: Unit; name: string)
release

Let a child unit go free. The opposite of adopt.

proc release(self: Unit)
reset

Send the unit back to its start position, rotation and scale. With clear = true, a Build also forgets its drawn blocks.

proc reset(self: Unit; clear = false)
right

Go right this many blocks (1 if you don't say). Slides sideways — no turning.

proc right(self: Unit; steps: float; move_mode: int)

template right(self: Unit; steps = 1.0)
proc right(self: Unit; value: PositionOffset; move_mode: int)

template right(self: Unit; value: PositionOffset)
rotation

Which way the unit is facing, in degrees. Assign to spin it around: rotation = 180 does an about-face.

proc rotation(self: Unit): float
rotation=
proc rotation=(self: Unit; degrees: float)
say

Show a message on a sign above the unit: say "Hello!". Call it again to change the message, or say "" to put the sign away. Markdown works, more adds extra text for when the sign is opened, and width/height/size control the shape if you're picky.

proc say(self: Unit; message: string; more = ""; width = float.high;
         height = float.high; size = int.high; billboard = none(bool)): Sign
scale

How big the unit is. 1 is normal size, 2 is double, 0.5 is half. Careful going tiny — it's easy to lose things.

proc scale(self: Unit): float
scale=
proc scale=(self: Unit; scale: float)
see

true if this unit can see the target: nothing solid in the way, and it's closer than less_than (100 blocks unless you say otherwise). sees works too, so if me.sees player: reads nicely.

template see(target: Unit; less_than = 100.0): bool
proc see(self: Unit; target: Unit; less_than = 100.0): bool
seed

The unit's random seed. See seed=.

proc seed(self: Unit): int
seed=

Random numbers in Enu follow a secret recipe called a seed. Give two units the same seed and they'll roll the same "random" numbers in the same order. By default every unit gets a different seed.

proc seed=(self: Unit; seed: int)
sees

Alias of see.

template sees(target: Unit; less_than = 100.0): bool
proc sees(self: Unit; target: Unit; less_than = 100.0): bool
show

Whether the unit is visible. show = false makes it vanish. It's still there. It's just being sneaky.

proc show(self: Unit): bool
show=
proc show=(self: Unit; value: bool)
speed

How fast the unit moves or builds. 1 is normal, bigger is faster, and 0 means "all at once" for building.

proc speed(self: Unit): float
speed=
proc speed=(self: Unit; speed: float)
start_position

Where the unit starts when the level loads. Assigning moves the start point, and that sticks around after a reload.

proc start_position(self: Unit): Vector3
start_position=

Change where the unit starts. Unlike position=, this is remembered when the level reloads.

proc start_position=(self: Unit; position: Vector3)
t
template t(self: Unit; degrees: float)
template t(enu_target: Unit)
turn

Turn the unit (or the drawing turtle). You can turn:

  • a direction: turn left, or turn left, 45 for 45 degrees
  • a number of degrees: turn 90 (positive turns right, negative turns left)
  • toward something: turn player
  • away from something: turn -player

t is the short version.

proc turn(self: Unit; direction: Directions; degrees = 90.0; move_mode: int)

proc turn(self: Unit; degrees: float; move_mode: int)

template turn(self: Unit; direction: Directions; degrees = 90.0)
template turn(self: Unit; degrees: float)
proc turn(self: Unit; position: Vector3; move_mode: int)

template turn(self: Unit; position: Vector3)
proc turn(self: Unit; enu_target: Unit; move_mode: int)

template turn(self: Unit; enu_target: Unit)
template turn(enu_target: Unit)
template turn(self: Unit; enu_target: NegativeNode)
u

Shorthand for up.

template u(self: Unit; steps = 1.0)
under
proc under(node: Unit): bool
up

Go up this many blocks (1 if you don't say).

proc up(self: Unit; steps: float; move_mode: int)

template up(self: Unit; steps = 1.0)
proc up(self: Unit; value: PositionOffset; move_mode: int)

template up(self: Unit; value: PositionOffset)
velocity

How fast (and which way) the unit is moving right now.

proc velocity(self: Unit): Vector3
velocity=
proc velocity=(self: Unit; velocity: Vector3)
wake
proc wake(self: Unit)

Vector3

A spot (or a direction) in the world. x is left/right, y is up/down, and z is forward/back.

Vector3 = tuple[x, y, z: float]

Source: enu/types

<
proc `<`(a, b: Vector3): bool
*=
proc `*=`(a: var Vector3; b: Vector3)

proc `*=`(a: var Vector3; b: float32)
*
proc `*`(a, b: Vector3): Vector3
proc `*`(a: Vector3; b: float32): Vector3
+=
proc `+=`(a: var Vector3; b: Vector3)
+
proc `+`(a, b: Vector3): Vector3
-=
proc `-=`(a: var Vector3; b: Vector3)
-
proc `-`(a, b: Vector3): Vector3
proc `-`(self: Vector3): Vector3
/=
proc `/=`(a: var Vector3; b: Vector3)

proc `/=`(a: var Vector3; b: float32)
/
proc `/`(a, b: Vector3): Vector3
proc `/`(a: Vector3; b: float32): Vector3
==
proc `==`(a, b: Vector3): bool
abs
proc abs(self: Vector3): Vector3
angleTo
proc angleTo(self, other: Vector3): float32
block_color_at

The color of the block at that spot.

proc block_color_at(position: Vector3): Colors
bounce
proc bounce(self, n: Vector3): Vector3
box
template box(at, to: Vector3; color = active_unit().color; fill = true)
ceil
proc ceil(self: Vector3): Vector3
cross
proc cross(self, other: Vector3): Vector3
cubicInterpolate
proc cubicInterpolate(self, b, preA, postB: Vector3; t: float32): Vector3
distance

How far away something is from this unit, in blocks. player.distance or distance vec3(10, 0, 10).

proc distance(position: Vector3): float
distanceSquaredTo
proc distanceSquaredTo(self, other: Vector3): float32
distanceTo

How far apart two positions are.

proc distanceTo(self, other: Vector3): float32
dot
proc dot(self, other: Vector3): float32
floor
proc floor(self: Vector3): Vector3
fuzzed
proc fuzzed(self, range: Vector3): Vector3
proc fuzzed(self: Vector3; range: float): Vector3

proc fuzzed(self: Vector3; x, y, z: float): Vector3
has_block_at

true if this build has a block at that spot.

proc has_block_at(position: Vector3): bool
height

How high up something is. The same as position.y.

proc height(self: Vector3): float
inverse
proc inverse(self: Vector3): Vector3
isNormalized
proc isNormalized(self: Vector3): bool
length

How long the vector is. If it's the difference between two positions, this is the distance between them.

proc length(self: Vector3): float32
lengthSquared
proc lengthSquared(self: Vector3): float32
lerp

Blend between two vectors. t is how far to go: 0.0 gives you the first vector, 1.0 gives you the second, 0.5 is halfway.

proc lerp(self: Vector3; other: Vector3; t: float32): Vector3
maxAxis
proc maxAxis(self: Vector3): int
minAxis
proc minAxis(self: Vector3): int
moveToward

Take one step of size delta from one position toward another, without overshooting.

proc moveToward(vFrom, to: Vector3; delta: float32): Vector3
normalize

Shrink or stretch the vector so its length is exactly 1, keeping its direction. A vector like this is handy for pointing at things.

proc normalize(self: var Vector3)
normalized

Like normalize, but returns a new vector instead of changing this one.

proc normalized(self: Vector3): Vector3
reflect
proc reflect(self, n: Vector3): Vector3
sign
proc sign(self: Vector3): Vector3
slide
proc slide(self, n: Vector3): Vector3
snap
proc snap(self: var Vector3; other: Vector3)
snapped
proc snapped(self: Vector3; other: Vector3): Vector3
t
template t(position: Vector3)
turn
template turn(position: Vector3)
zero
proc zero(self: var Vector3)

World

The world itself. There's exactly one, named world. Change its settings to change the scenery.

World = ref object of RootObj

Source: enu/types

environment

The world's scenery and lighting, like "default" or "space". world.environment = "space" — instant outer space.

proc environment(self: World): string
environment=
proc environment=(self: World; value: string)
megapixels

How sharp the screen looks. Lower numbers are blurrier but faster — try turning this down if things get choppy.

proc megapixels(self: World): float
megapixels=
proc megapixels=(self: World; value: float)

WorldBox

An invisible box around a unit, described by its lowest corner and its highest corner. Used to check what fits where.

WorldBox = tuple[min, max: Vector3]

Source: enu/types

box_is_free

true if nothing is in the box — handy for checking a spot before building there.

proc box_is_free(box: WorldBox): bool
centre

The point in the middle of the box.

proc centre(b: WorldBox): Vector3
contains

true if the point is inside the box.

proc contains(b: WorldBox; p: Vector3): bool
expanded

A copy of the box, grown by margin in every direction.

proc expanded(b: WorldBox; margin: float): WorldBox
intersects

true if two boxes overlap.

proc intersects(a, b: WorldBox): bool
size

Width, height and depth of the box, as a Vector3.

proc size(b: WorldBox): Vector3
units_overlapping

Every unit whose box overlaps this one.

proc units_overlapping(box: WorldBox): seq[Unit]

base_bridge

Properties and queries that every unit has, like position, speed, color and scale. These commands cross over into the Enu engine itself.

Source: enu/base_bridge

active_unit
proc active_unit(): Unit
added_units
proc added_units(): seq[Unit]
all_bots

Every bot in the world. Bot.all is the fancier way.

proc all_bots(): seq[Bot]
all_builds

Every build in the world. Build.all is the fancier way.

proc all_builds(): seq[Build]
all_players

Everyone playing right now.

proc all_players(): seq[Player]
all_signs

Every sign in the world.

proc all_signs(): seq[Sign]
all_units

Every unit in the world — builds, bots, signs and players.

proc all_units(): seq[Unit]
clear_box

Erase every block inside the box between two corners.

proc clear_box(x1: float; y1: float; z1: float; x2: float; y2: float; z2: float): bool
echo_console
proc echo_console(msg: string)
exit
proc exit(exit_code = 0; msg = "")
find_voxel_overlaps
proc find_voxel_overlaps(limit: int = 50): string
floor_at

The height of the ground at a spot — the y of the highest solid block, plus 1.

proc floor_at(x: float; z: float): int
frame_count
proc frame_count(): int
level_name

The name of the current level.

proc level_name(): string
load_level

Switch to a different level.

proc load_level(level: string; world = "")
now_seconds

Seconds since Enu started. now() is usually nicer.

proc now_seconds(): float
press_action

Pretend a button was pressed, like "jump". release_action lets it go. Yes, this means you can prank the player.

proc press_action(name: string)
release_action
proc release_action(name: string)
reset_level

Restart the current level from scratch.

proc reset_level()
signal_test_complete
proc signal_test_complete(exit_code: int)
units_in_box

Every unit inside the box between two corners.

proc units_in_box(x1: float; y1: float; z1: float; x2: float; y2: float;
                  z2: float): seq[Unit]
world_name

The name of the current world.

proc world_name(): string
write_stack_trace
proc write_stack_trace()

builds

Commands for building with blocks: shapes like box, ball, wall and floor, plus turtle controls like drawing and save/restore.

Source: enu/builds

asap

Draw everything inside the block instantly, instead of block by block. Like speed = ASAP, but it puts the speed back afterward.

template asap(body: untyped)
ball

A sphere, but friendlier. Same as sphere.

template ball(size: int | float; color = active_unit().color; fill = true)
template ball(size: int | float; at: Vector3; color = active_unit().color;
              fill = true)
box
template box(width, height, depth: int; color = active_unit().color;
             fill = true; pivot: BoxPivot = corner)

template box(width, height, depth: int; at: Vector3;
             color = active_unit().color; rotation = 0.0; fill = true;
             pivot: BoxPivot = corner)
can

A cylinder, but friendlier. Same as cylinder.

template can(size: int | float; height: int; color = active_unit().color;
             fill = true)

template can(size: int | float; height: int; at: Vector3;
             color = active_unit().color; fill = true)
cylinder
template cylinder(size: int | float; height: int; color = active_unit().color;
                  fill = true)

template cylinder(size: int | float; height: int; at: Vector3;
                  color = active_unit().color; fill = true)
floor

Draw a flat slab, length deep and width wide (square unless you say). Like wall, the turtle ends up at the far edge, ready for whatever you're building next.

template floor(length: int; width: int = length;
               color: Colors = active_unit().color)
place
template place(x, y, z: int; color = active_unit().color)
save_level_now

Triggers an immediate level save. Used for testing persistence.

proc save_level_now()
sphere
template sphere(size: int | float; color = active_unit().color; fill = true)
template sphere(size: int | float; at: Vector3; color = active_unit().color;
                fill = true)
wall

Draw a wall, length blocks long and height tall (4 unless you say), heading the way the turtle faces. The turtle ends up at the far end, so wall 10; turn right; wall 10 makes a perfect corner. Four of those and you've got yourself a fort.

template wall(length: int; height: int = 4; color: Colors = active_unit().color)

core

The heart of the Enu API: moving, turning, building, random numbers, timers, and the other everyday commands that every script can use.

Source: enu/core

?

"Is this something?" ?player.open_sign is true if the player has a sign open, false if there's nothing there. Works on most things: empty text, empty lists and zero all count as "nothing".

template `?`[T: ref](self: T): Query[T]
template `?`[T: object](self: T): Query[T]
template `?`[T](option: Option[T]): Query[T]
template `?`[T: SomeNumber](self: SomeNumber): Query[T]
template `?`(self: string): Query[string]
template `?`[T: openArray](self: T): Query[T]
template `?`[T: Table](self: T): Query[T]
template `?`[T: set](self: T): Query[T]
template `?`[T: HashSet](self: T): Query[T]
\

Put values inside text: \"score: {score}" becomes "score: 10". Anything in curly braces gets filled in.

template `\`(s: string): string
or

Pick the first value that's "something". name or "mystery guest" gives you name, unless it's empty.

proc `or`[T: not bool](a, b: T): T
anchor

Declare the unit's pivot. Inside the block, turtle commands (forward, right, up, turn, lean, …) accumulate into the unit's anchor pose instead of drawing voxels or moving the unit. The turtle starts at the proto's local (0, 0, 0) facing -Z.

After the block, position places the anchor pivot at the given world coord, rotation pivots around it, and move me; forward moves along the anchor's intrinsic forward.

template anchor(body: untyped)
b

Shorthand for back.

template b(steps = 1.0)
back

Like forward, but backward. b for short.

template back(steps = 1.0)
contains

Roll the dice: 1 in 10 is true 1 time out of 10. Use it for things that should only happen sometimes: if 1 in 100: echo "jackpot!".

proc contains(max, chance: int): bool
cycle

Each time it's called, hand back the next value in the list, looping around forever: red, green, blue, red, green, blue... color = cycle(red, green, blue).

template cycle[T](args: varargs[T]): T
d

Shorthand for down.

template d(steps = 1.0)
down

Go down this many blocks (1 if you don't say). d for short.

template down(steps = 1.0)
dump

Print an expression and its value. dump score prints score = 10. Saves you typing the name twice while debugging.

macro dump(x: typed): untyped
echo

Print something to the console. The best way to spy on what your script is up to: echo "score is ", score.

proc echo(args: varargs[string, `$`])
even

true for even numbers. if frame.even: does something every other time.

proc even(self: int): bool
f

Shorthand for forward.

template f(steps = 1.0)
far

true if something is farther than greater_than blocks (100 unless you say otherwise).

proc far(node: Unit | Vector3; greater_than = 100.0): bool
find_by_id

Search every unit in the world for the one with this id. Returns nil if there's no such unit.

proc find_by_id(id: string): Unit
first

The first unit of a kind: Player.first is the first player, Bot.first the first bot. nil if there aren't any.

proc first[T: Unit](_: type T): T
first_key
proc first_key[K, V](self: Table[K, V]): K
forever

Do something forever. The same as while true, but friendlier. o is the short version (it looks like a loop, see?).

template forever(body)
forward

Go forward this many blocks (1 if you don't say). In build mode the turtle draws blocks as it goes; in move mode the whole unit moves. f is the short version.

template forward(steps = 1.0)
fuzzed

A copy of a number or position, nudged by a random amount up to range. position.fuzzed(0.5) is great for jitters, shivers and nervous-looking bots.

proc fuzzed(self, range: float): float
go_home

Head back to the start position by going forward, left, and down the right amounts. Something solid can block the trip, so if it really matters, compare position to start_position afterward to check you made it.

template go_home()
init

Make an error you can raise. For example, raise ValueError.init("that's not going to work").

proc init[T: Exception](kind: type[T]; message: string;
                        parent: ref Exception = nil): ref Exception
initialize_state

Used by Enu while a level loads. You won't need this in a script.

proc initialize_state()
keep_alive

Enu stops scripts that grind away for ~2 seconds without pausing, in case they're stuck. If your loop really does need that long, call this now and then to say "not stuck, just busy!"

proc keep_alive()
l

Shorthand for left.

template l(steps = 1.0)
lean
template lean(degrees: float)
left

Go left this many blocks (1 if you don't say). Slides sideways — no turning. l for short.

template left(steps = 1.0)
loop_finished

Called by Enu at the end of each trip through a command loop. You won't need this in a script.

proc loop_finished()
move

Switch to move mode: commands like forward and turn now move the unit around instead of drawing blocks. move me moves this unit; move enemy steers a different one. (If the speed was 0, it's bumped to 1 so you can actually see something happen.)

template move[T: Unit](new_enu_target: T)
near

true if something is closer than less_than blocks (5 unless you say otherwise). if player.near: or if player.near(20):.

proc near(node: Unit | Vector3; less_than = 5.0): bool
now

The time right now. Subtract two of these to see how much time passed: let start = now() # ... do something slow ... echo "Took ", now() - start

proc now(): Timestamp
o

Shorthand for forever.

template o(body)
odd

true for odd numbers.

proc odd(self: int): bool
quit

Stop the script.

proc quit(code = 0; msg = "")
r

Shorthand for right.

template r(steps = 1.0)
rand

A random number from a range: rand(1..6) rolls a die. Mostly you don't even need to call this — passing a range where a number goes does it automatically, like forward 2..10.

proc rand[T: int | float](range: Slice[T]): T
random

Pick one of the choices at random. color = random(red, green, blue).

proc random[T](args: varargs[T]): T
register_state_init

Used by Enu while a level loads. You won't need this in a script.

proc register_state_init(callback: proc ())
reset

Send the unit back to its start position, rotation and scale. With clear = true, a Build also forgets its drawn blocks.

template reset(clear = false)
right

Go right this many blocks (1 if you don't say). Slides sideways — no turning. r for short.

template right(steps = 1.0)
sleep

Do nothing for this many seconds. With no argument (or 0), naps for up to half a second, but wakes up early if something bumps into the unit — perfect for a loop that mostly waits around.

proc sleep(seconds = 0.0)
t
template t(degrees: float)
template t(enu_target: NegativeNode)
times

Do something over and over. 4.times: forward 5; turn right draws a square. Inside the block, first and last tell you if this is the first or last time through. Want a counter? Ask for one: 8.times(side): counts side up from 0 to 7.

template times(count: int; body: untyped): untyped
template times(count: int; name: untyped; body: untyped): untyped
turn
template turn(degrees: float)
template turn(enu_target: NegativeNode)
u

Shorthand for up.

template u(steps = 1.0)
units_near

Lists every Unit in the world whose xz-distance to (x, y, z) is <= radius, sorted nearest-first. One line per unit, formatted as: d=DD.D unit_id (X, Y, Z) Useful when chasing overlap reports / "# CLAUDE: ..." marker blocks from MCP: pass the marker's position and skim the candidates.

proc units_near(x, y, z: float; radius = 30.0): string
up

Go up this many blocks (1 if you don't say). u for short.

template up(steps = 1.0)
x

Shorthand for times. 5.x: forward 2.

template x(count: int; body: untyped): untyped

players

Commands for the people playing: their tools, whether they're flying or playing, and what they have open.

Source: enu/players

executing_player

The player who ran this script. runner is the friendly name.

proc executing_player(): Player
runner

The player who ran this script — useful in multiplayer, where player is just the first one.

template runner(): Player

signs

Signs and speech: say something, and control how the sign looks.

Source: enu/signs

say
template say(message: string; more = ""; width = float.high;
             height = float.high; size = int.high; billboard = none(bool)): Sign

state_machine

Command loops and states: loop, and the -> and ==> rules that switch between behaviors.

Source: enu/state_machine

->

A state change rule for loop. wander -> hide means "if we're wandering, start hiding". nil is the state you begin in, any matches every state, others matches every state except the one you're switching to, and (a, b) -> c matches either. Add a do: block to run something once at the moment of the switch.

macro `->`(from_state: untyped; to_state: untyped; body: untyped = nil)
==>

Like ->, but impatient: switches states right away instead of waiting for the current state to finish what it's doing.

macro `==>`(from_state: untyped; to_state: untyped; body: untyped = nil)
loop

A command loop — the heart of a unit's behavior. The body runs over and over (about twice a second), switching between states with -> rules:

loop: nil -> wander if player.near: wander -> hide

macro loop(body: untyped)
macro loop(sig: untyped; body: untyped): untyped
smart_call
macro smart_call(call: untyped)

testing

A little testing framework, for checking that your creations do what you think they do: suite, test and check.

Source: enu/testing

check

Check that something is true. If it isn't, the test fails and tells you what went wrong.

template check(cond: untyped)
require

The same as check.

template require(cond: untyped)
suite

A group of related tests: suite "gravity": ....

template suite(name: string; body: untyped)
test

One test with a name. Put checks inside.

template test(name: string; body: untyped)
test_summary

Print how many tests passed and failed. Call it at the end.

proc test_summary()
tests_failed

true if any test has failed so far.

proc tests_failed(): bool

vectors

Math for positions and directions: Vector3 arithmetic, distances, and the WorldBox helpers.

Source: enu/vectors

*
proc `*`(b: float32; a: Vector3): Vector3
isEqualApprox

true if two numbers are so close that the difference doesn't matter.

proc isEqualApprox(a, b: float32): bool

proc isEqualApprox(a, b: float64): bool
sign

-1.0 for negative numbers, 1.0 for everything else.

proc sign(a: float32): float32

proc sign(a: float64): float64
stepify

Snap value to the nearest multiple of step. stepify(7.3, 5.0) is 5.0. stepify(8.0, 5.0) is 10.0.

proc stepify(value, step: float64): float64

proc stepify(value, step: float32): float32
vec3

Make a Vector3 — a spot (or a direction) in the world. x is left/right, y is up/down, and z is forward/back.

proc vec3(x, y, z: float): Vector3