Scenes & .esn
An .esn file is the graph: it uses libraries, declares inputs and outputs, and places nodes. A node references a published Kernel by id or carries its own Kernel inline, so one .esn can be complete on its own.
A complete example
Section titled “A complete example”use "kernels/"; // every .ent directly in the directoryuse "../shared/tonemap.ent"; // one library file
input photo: Image; // supplied by the callerparam amount: Float = 1.0; // a graph parameter, overridable by the callerrequire gentle: amount <= 4; // what the parameters must hold to run
node gray: image.grayscale@1 { // reference a published Kernel source <- photo; // wire: this evaluation's value amount = amount; // value: a literal, or a graph param by name}
node trail: kernel { // an anonymous Kernel, placed here requires { field.read; field.write; } input current: Image <- gray.result; // wired where declared input previous: Image <~ trail.result from gray.result; // previous evaluation param decay: Float = 0.9; // the default is this node's value output result: Image; compute { return sample(current) + sample(previous) * decay; }}
node glow: kernel fx.glow@1 { ... } // a named inline Kernel: placed here and publishable by id
node display: graph "../shared/display.esn" { // another graph placed as a node source <- glow.result; // wires its `input`s exposure = 1.2; // sets its `param`s}
output result <- display.result; // a named output; sub-graph outputs read as node.outputoutput kept <- state.result to "saves/state.field"; // also written to a fileA node’s name may be any word, a keyword too (node scan: …); a Kernel’s own names (ports, params, values) cannot be keywords.
The rules in brief
Section titled “The rules in brief”- Wiring is written only at the consumer.
port <- sourcereads this evaluation’s value, a dependency;port <~ source from initialreads what the previous successful evaluation committed, not a dependency, andinitialuntil something is committed. - A source is a graph input by name or
node.port; inputs and nodes share one namespace. - Every declared input port must be wired, and wiring an undeclared port is an error — both reported before anything runs.
- Values use
=: numbers,true/false, negation,vec2/vec3/vec4. A value is written, never computed:gain = 0.5 * 2.0;andgain = n + 1;are refused. domainsets a node’s extent and may be an expression of structure (size(port),window()…).- A Kernel id is unique across everything a graph loads; an anonymous inline Kernel is named
<document>.<node>@1. - A
usepath is relative to the document; a trailing/means the directory’s.entfiles. - A node may bind a backend’s native operation:
node raster: native.rasterize@1 { … }(native.rasterize@1/@3,native.cover@1), published by the runtime, never republished from a document, never fused. - Sub-graphs:
node name: graph "path.esn" { … }flattens on placement, its nodes joining the parent undername.. - Repetition:
times = N;withcarry port <- output;. - Fill nodes:
node zeros: Rows<Float> { domain = 65; value = 0.5; }— a Field rather than a Kernel. async = true;runs off the frame.awake = value(source, row);sleeps a node while that row is 0.require name: a <= b;says what the graph’s params must hold, checked at load and before every evaluation.
Each rule in full is in docs/DOCUMENTS.md, Graph · Rules; every form at a glance in Class reference · Scene syntax.
Outputs and Host devices
Section titled “Outputs and Host devices”A graph may declare several outputs. The window shows the first picture given no device; an output goes to a Host device with to:
| Device | Takes |
|---|---|
to sound |
rows of one or two floats (mono/stereo), a block of samples each frame |
to pointer |
a picture of at most 128 by 128, the system’s pointer |
to pointer_tip |
the pixel of that picture it points with |
to clipboard |
a Rows<Int> of characters, put on the clipboard (the Player needs --allow clipboard.write) |
to "file.ext", to bytes "f.bin", to files "dir/" |
files, with --allow file.write (removal and rename also file.delete) |
A device name the Host lacks is refused before anything runs, with the nearest it has.
Font, directory and field-file nodes
Section titled “Font, directory and field-file nodes”node g: font "x.ttf" { codes <- wanted.result; }reads a font intog.glyphs,g.outlines,g.metrics.node d: files "dir/" { paths <- wanted.result; }lists a folder as an editor does (d.listing), reading only what is opened (d.opened), honoring.gitignore.node near: Rows<Spot> fields "chunks/" { paths <- want.result; }brings.fieldfiles in on demand — how a world larger than memory keeps only what its frames are near.
Loading
Section titled “Loading”The session parses the graph, publishes its inline Kernels, follows its use items, packages included, and rebuilds the Graph model. It publishes the Kernels of the documents the scene’s use items name; of documents those use in turn, the declarations only. A changed document republishes only the Kernels whose text changed; a rejected replacement keeps the running version; a Kernel that leaves its document retires.

