Hazel

Blueprint Node API

Every node in the blueprint palette, what it compiles to, and the pins it exposes.

The palette was rebuilt. Blueprints used to be walked by a live interpreter over 191 hand-written node definitions. That interpreter is gone: a graph now compiles to Lua and runs through the script VM, and the nodes were re-added from scratch — each one a single self-contained unit with a test asserting the Lua it emits. This page lists all 15 nodes that currently exist. Anything not here was not ported yet; write it in Lua and attach both, or add the node.

How to read this page

Each node has pins: white exec pins carry control flow, coloured pins carry data.

  • An event node has no exec input — it is a starting point, and maps to a script lifecycle hook.
  • An exec node has an exec input and one or more exec outputs (usually then), and emits a statement.
  • A pure node has no exec pins at all. It emits an expression, evaluated where it is used.

The "Compiles to" column is the actual Lua emitted, with {pin} standing for whatever is wired into that pin (or its default). Every function it calls is in the Scripting API — a blueprint cannot reach anything a script cannot.

Event

Event nodes are graph entry points. Each becomes a Lua lifecycle hook.

Nodenode_typePinsBecomes
On Readyevent/on_readyout: execfunction on_ready()
On Updateevent/on_updateout: exec, delta (Float), elapsed (Float)function on_update()
On Eventevent/on_eventin: name (String); out: exec, value (Any)function on_event(name, args), filtered by name
Emit Eventevent/emitin: exec, name (String), value (Any); out: thenemit({name}, { value = {value} })

On Update hands you the frame's delta and elapsed directly on output pins, so a time-dependent graph needs no extra plumbing.

On Event and Emit Event are a matched pair. Emit writes the payload as { value = … } and On Event reads args.value back out, so the two line up without you having to know the table's shape. Events are broadcast — every script and blueprint that listens for that name hears it, one frame later.

Math (pure)

Nodenode_typePinsCompiles to
Addmath/addin: a, b (Float, default 0); out: result (Float)({a} + {b})
Multiplymath/multiplyin: a, b (Float, default 1); out: result (Float)({a} * {b})
Combine Vec3math/combine_vec3in: x, y, z (Float, default 0); out: result (Vec3)vec3({x}, {y}, {z})

Transform (exec)

All three act on the entity the blueprint is attached to.

Nodenode_typePinsCompiles to
Set Positiontransform/set_positionin: exec, position (Vec3); out: thenset_position(x, y, z)
Set Rotationtransform/set_rotationin: exec, rotation (Vec3, euler degrees); out: thenset_rotation(x, y, z)
Rotatetransform/rotatein: exec, degrees (Vec3, default 0, 90, 0); out: thenrotate(x * delta, y * delta, z * delta)

Rotate takes a rate, not an angle. Its degrees pin is degrees per second, and the compiler multiplies each axis by delta for you — so On Update → Rotate is a complete, frame-rate-independent spin with nothing else wired in. Setting (0, 90, 0) turns the entity a quarter-circle per second on any machine.

A Vec3 input is unwrapped as ({v}).x or {v}[1], so it accepts either a vec3() table or a plain array.

Flow

Nodenode_typePinsCompiles to
Branchflow/branchin: exec, condition (Bool, default true); out: true, falseif {condition} then … else … end

The else arm is emitted only when something is wired to the false pin, so an unused branch costs nothing in the generated source.

Variable

Nodenode_typePinsCompiles to
Get Variablevariable/getin: name (String); out: value (Any)the Lua local named {name}
Set Variablevariable/setin: exec, name (String), value (Any); out: then{name} = {value}

Variable names are sanitized into valid Lua identifiers, so a name with spaces or punctuation still compiles. A variable is an ordinary Lua local in the generated script — it does not persist across scenes, and it is not visible to other entities. To share state, emit an event or write a component field with set.

Debug

Nodenode_typePinsCompiles to
Logdebug/login: exec, message (String, default "Hello!"); out: thenprint_log(tostring({message}))

Output lands in the editor Console. tostring is applied for you, so wiring a number or a Vec3 into message works.

Animation

Nodenode_typePinsCompiles to
Crossfade Animationanimation/crossfadein: exec, name (String), duration (Float, default 0.3), looping (Bool, default true); out: thencrossfade_animation({name}, {duration}, {looping})

What is not in the palette

Everything else. There is no node today for input, physics, audio, spawning, timers, collision, HTTP, networking, UI or math beyond add/multiply/combine — those were part of the old interpreter's palette and have not been re-added.

That is a smaller gap than it looks, because a blueprint and a script are the same thing once compiled:

  • Put the missing logic in a .lua file and attach both a BlueprintGraph and a ScriptComponent to the entity. They run side by side against the same world.
  • Or add the node. One NodeEntry plus a test is the whole job — see Custom Blueprint Nodes.

See also