builder
What a graph builder hands the author, in the call form: `proc.define(function(g) ... end)`.
proc.builder
What a graph builder hands the author, in the call form: proc.define(function(g) ... end).
g.<name>(args)adds a node of the node asset the name resolves to, by asset identity: the nodebox and the node's folder name (g.points.disc), a path (g["/zero/source/fx/ring.procNode"]),~(the nearest package, effect or world root:g["~/ring"]), a guid, or a short name (g.disc). A name that matches two nodes, and a name that matches none, are errors that name the candidates. Each call is recorded in the graph by the node's guid. Arguments are a table naming inputs or positional values in the node's input order.- What a call answers: a node with one output answers that output's socket, a node with several answers a
record of sockets by output name (
local f = g.core.normals.face(geo); f.geometry, f.area), a node with none answers nothing. The record does not depend on declaration order. g.op.<name>(args)(andproc.op.<name>) adds a node of an op, for library nodes built on the ops.g:input(name, default, opts)is typed by the default:Float,String,Bool,Vec3,Color,List<T>,Recordwith its fields.optstakesmin,max,options,description,optionalandtypefor a default that does not state its type or no default at all. An empty table default with a statedtypeis that type's empty value (g:input("entities", {}, { type = "List<Entity>" })).- An input with
options, or of type Bool or String, is a plain value while the graph is built:g:inputanswers the value itself,ifover it is allowed, and it passes into calls as a constant. Number and vector inputs are sockets. The graph records the plain values it was built with ingraph.plain, and each such declaration ingraph.inputs[name].plain = true. - Sockets take
+ - * / % ^ // ..and unary minus,math.*andvector.*(each amath.<name>node;vector.createismath.vec2,math.vec3ormath.vec4by its component count),x.name,x.name = vandx[name] = vfor a computed name (which rebindx),x[class][name],x[n], andfor index, item in list do ... end. A source loaded throughbuilder.prepareSourcereads plainmath,vectorandrandover sockets unchanged;defineloads a node or graph entry that way when it names them. g.compare(a, op, b),g.where(cond, a, b),g.pick(choice, alternatives),g:fold(n, init, fn, opts),g:state(name, columns),g:step(dt, substeps, fn),g:check(cond, message),g.has(geometry, class, name)andg.copy(socket)record the constructs the evaluator knows.g:check(cond, message): acondknown while the graph is built refuses the build with the message (a true one records nothing); acondthat reads a socket is recorded for the plan or the cook to answer. The build of a node's own defaults, which is what indexes the node, holds such a refusal instead of raising it (graph.refusals), andforInputsstates it where the node is called or cooked as it stands, so a check over a plain input fires when the call gives it the refused value.- A plain Luau table filled inside a
forbody over sockets keeps one element (rings[#rings + 1] = v,table.insert(rings, v)): the body is one pass for every item.builder.checkrefuses it with the codesocket-loop-append, naming the form to write: a local declared before the loop and assigned inside it, read after the loop, where it is the list of every pass's value. g.copy(value)of a record or a list written in the graph (g.copy({ total = 0 })) is a value of its own that member writes rebind, so aforbody that fills it carries it from pass to pass.- A class view made with a socket key (
names[i]) and read as a value is a node of the scope it was made in, whichever loop body first reads it. - A
forbody is one pass that stands for every item.indexis the item's place (a socket, from 1). A value built outside the body that the body reads or assigns (geometry[class][name] = v,record.name = v,record[name] = v) is carried: each pass starts from what the pass before left, the first from the value as it stood before the loop, and after the loop the value is what the last pass left. The loop records the carries inscope.carries[id] = { init, result }and the refsloop_index,loop_carry(the value at the start of a pass) andloop_result(the value after the loop). A value the body only reads reads as it was. The emitter writes a carrying loop as it was authored: a local that starts asg:copy(value), the body's assignments to it, and the loop reading that local after it (proc.emit). g.clock.placement(16 numbers, column after column),g.clock.inverse,g.clock.rotation({ x, y, z, w }) andg.clock.entityanswer where the graph stands in the scene it is cooked in: each is aconstruct.scenenode that reads the scene the cook is handed (a graph standing on no entity has the identity placement and no entity).g.transform.point(p),g.transform.direction(d)andg.transform.rotation(q)carry a world position, direction or quaternion into the graph's space through the inverse placement; each takes plain values, sockets or Fields.g:fold(n, init, fn, { stop = "changed" })or{ stop = function(before, after) return <Bool> end };fnreturns the state only. The fold runsnpasses and ends early at the first pass whose stop holds.g.elementis the element a Field evaluates over:g.element.id(Int),g.element.P(the position leaf thatfieldc.withPositionsubstitutes, also writteng.element.point.P) andg.element.<class>.<column>for a column of the domain the field stands in. Each read is a socket, sog.element.id * 1.0is a math node.rand.unit(seed, ...scope, id)(a global in a node source, alsobuilder.rand.unit) is the Float field of unit draws keyed by the seed, the scope (graphId, nodeId, channel, orgraphId, compositePath, nodeId, channel) and the elementid, last (g.element.id). It adds anio.luaunode{ module = "@builtin::systems.procgen.proc.fieldc.leaves", fn = "rand", args = { seed, { ...scope }, id }, returns = { "Any" } }and answers itsvalue.geometry.names[class]lists the attribute names a class holds (a list socket the plan answers);geometry[class].count = nassigns the domain count;geometry.material = massigns the material.namesis read by that name on any socket: what is read off it by a class (geometry.names.point) lists the names, and any other read (record.names[2],record.names) is the member a record holds under that name, ascountandkeysare.materialis assigned by that name on any socket.- A member, an item, a column or the names of a value built outside a fold, step or stop body that the body reads first is a node of the scope the value was built in: the body and every later fold read the one value, which the plan writes once. A read keyed by a socket of the body (a fold's index) stays in the body.
g.clock.time,.frame,.deltaand.durationare sockets;.fps,.frames,.loopand.realTimeare the timeline's values.- Luau's
< <= > >= == ~=,and,or,notandifover a socket have no value while the graph is built.builder.check(source)names each one with theg.*form to write, anddefineholds a node or graph entry to it. Plain inputs are not sockets to the check. A plain Luau table indexed by a socket (LANES[values.type]) answers nil while the graph is built, so the check refuses it with the codesocket-table-index, which namesg.pick. - A list of values holds a nil as a value:
{ a, nil, b }is three, and the second is a constant of nothing.
Building a graph for other plain values
A graph whose plain inputs change structure is built again for the values a cook was given.
builder.forInputs(graph, inputs)answersgraphwhile its plain inputs hold what the build used, else the graph built again fromgraph.sourcewith the valuesinputsstates (an input it leaves out takes its default); the result is cached by the source text and the values, so a node written again is built again. It answersnil, reasonwhen the source cannot be built again or a value is outside the input's options.- An optional input with no default (
g:input(name, nil, { optional = true })) is nil while the graph is built for a call that leaves it unwired, and its socket otherwise, soif input == nil then ... endin a node source is decided by what the call wired. The declaration stateswiring = trueand the graph records the wiring it was built for ingraph.wiring[name];forInputsbuilds the graph again for a cook given no value for such an input (values[name] == falsestates none inrebuildandwithInputs). builder.rebuild(graph, values)builds again unconditionally;builder.withInputs(values, fn)runs a function that callsproc.defineand gives that graph the values. A node asset called with a plain value records it as a constant param; the evaluator reads a node's graph throughforInputswith those params.
What a graph records
A call-form graph states surface = "call". Each node it makes carries call = true, seq (the order it was made
in, which the emitter writes it back in) and scope. A node asset is op = { __ref, type = "procNode", name }; an
op is its id string; a construct is op = "construct.<kind>" with construct = <kind>. graph.scopes holds each
for, fold, stop and step body, graph.states each g:state, graph.plain the plain input values.
The inputs of a construct node are refs (a constant is { kind = "const", value }); params are constants.
| construct | inputs | params | answers |
|---|---|---|---|
member | value, name | the member of value | |
member_set | value, name, to | value with the member written | |
item | list, index | the item | |
column | geometry, class, name | the column read (a read of count is the domain count) | |
column_set | geometry, class, name, value | the geometry with the column written | |
column_remove | geometry, class, name | the geometry without the column | |
count_set | geometry, class, count | the geometry with that class's domain count set to count | |
material_set | geometry, material | the geometry with its material set | |
names | geometry, class | the List of attribute names the class holds, answered at plan | |
has | geometry, class, name | a Bool answered at plan: whether the class holds the column | |
check | cond | message | nothing; a cond that is false when cooked is an error stating message |
compare | a, b | op (eq neq lt le gt ge) | a Bool |
where | cond, a, b | a where cond holds, else b | |
pick | choice, alternatives | the alternative the choice names | |
step_sample | step, value | the value of an animated value at the step's time | |
step_between | step, index | the fraction (0 to 1) of the step's movement that source index of the step has covered; the evaluator defines it |
A call that has several outputs names them in refs: { kind = "node_output", node, output = "<name>" }; a node with
one output has output = nil.
Refs
The v1 refs (const, graph_input, node_output, list, record, animated) and:
| ref | stands for |
|---|---|
loop_item { loop }, loop_collect { loop, ref } | the item of a for scope, and the list of ref over every item |
fold_value { scope }, fold_index { scope }, fold_result { scope } | the value and the index (from 1) of a fold pass, and the value after the last pass |
fold_before { scope }, fold_after { scope } | the state before and after a pass, inside a fold's stop function; scope is the stop scope |
step_state { scope }, step_index { scope }, step_result { scope } | the state record, the step record (dt time graphTime index first start, with step_sample and step_between), and the state the step reached |
state { name }, clock { field }, engine | declared state, the clock's field, the engine API namespace |
element { field, class? } | the element a Field evaluates over: field = "id" its index, field = "P" its position leaf (no class), else the column field of the domain class |
Scopes
graph.scopes[id] is { kind, parent, seq, ... }:
for:list,item.fold:count,init,result, andstopwhen it states one:"changed"(the pass ends the fold when the state it produced equals the one it read) or{ scope = <id of a stop scope> }.stop: a scope whoseparentis its fold. Its nodes readfold_beforeandfold_after;resultis the Bool ref the fold stops on. It is evaluated after each pass.step:dt,substeps,result.
The plain table of a graph and the plain = true flag of an input declaration state which inputs are build-time
values.
Part of @builtin::systems.procgen.proc.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2proc.builder: what a graph builder hands the author. ONE CALL FORM. `g.<name>(args)` adds a node of the node asset the name resolves to, by asset identity: the nodebox and the node's folder name (`g.points.disc`), a path, `~` (the nearest root), a guid, or a short name. The call returns the node's outputs in the order the node declares them. `g.op.<name>(args)` (and `proc.op.<name>`) adds a node of an op, for the library nodes that are built on the ops. A SOCKET stands for a value the graph produces. It wraps an InputRef the graph records, so a graph built here serializes with the same refs as one built with `g:node`. Sockets take Luau's arithmetic, `math.*` and `vector.*` (each a `math.<name>` node), member reads and writes, indexing by class and name (`geometry.point.P`, `geometry[class][name] = column`) and generalized iteration (`for _, item in list do ... end`). Luau's comparisons and logic have no value at build time and are refused, naming the `g.*` form.
bind(helpers: any) → void
Bind the graph module's wiring functions. Called by `proc.graph` each time its chunk runs.
| arg | type | description |
|---|---|---|
| helpers | any |
warnOnce(map: { [string]: boolean }, key: string, message: string) → void
| arg | type | description |
|---|---|---|
| map | { [string]: boolean } | |
| key | string | |
| message | string |
fail(message: string, level: number?) → never
| arg | type | description |
|---|---|---|
| message | string | |
| level | number? |
sourceAt(file: string) → string
The text of the source file `file`, or nil when it cannot be read.
| arg | type | description |
|---|---|---|
| file | string |
bindingOf(v: any) → Binding
| arg | type | description |
|---|---|---|
| v | any |
isSocket(v: any) → boolean
Whether a value is a socket.
| arg | type | description |
|---|---|---|
| v | any |
topScope(graph: any) → string
| arg | type | description |
|---|---|---|
| graph | any |
newSocket(graph: any, ref: any?, view: any?) → any
| arg | type | description |
|---|---|---|
| graph | any | |
| ref | any? | |
| view | any? |
socket(graph: any, ref: any) → any
A socket standing for the InputRef `ref` of `graph`.
| arg | type | description |
|---|---|---|
| graph | any | |
| ref | any |
scopeActive(graph: any, id: string) → boolean
| arg | type | description |
|---|---|---|
| graph | any | |
| id | string |
carryPath(b: Binding) → void
The `for` scopes opened since the value's own scope, outermost first; nil when the value is not carried (it was built in the scope in use, or a fold or step body lies between).
| arg | type | description |
|---|---|---|
| b | Binding |
inScopeOf(b: Binding, fn: () → void
Run `fn` with only the scopes open that were open when the socket `b` was made: a socket that stands for a value of a scope (a class view read as a value, made where it is first used) is a node of the scope it belongs to, whichever loop body it is first used in.
| arg | type | description |
|---|---|---|
| b | Binding | |
| fn | ( |
atOwnScope(b: Binding, fn: () → void
Run `fn` as the scope the value `b` belongs to when `b` was built outside a fold, step or stop body that reads it: what is derived from it (a member, a column, the names a class holds) is evaluated once where `b` stands, and every body and every later fold reads that one value. A value a `for` body carries keeps the body's scope, since each pass starts from what the pass before left.
| arg | type | description |
|---|---|---|
| b | Binding | |
| fn | ( |
ensureCarried(b: Binding) → void
| arg | type | description |
|---|---|---|
| b | Binding |
overwrite(dst: any, src: any) → void
| arg | type | description |
|---|---|---|
| dst | any | |
| src | any |
finishCarries(graph: any, id: string) → void
The end of a `for` body: what it assigned is a result of the loop, what it only read is as it was.
| arg | type | description |
|---|---|---|
| graph | any | |
| id | string |
refOf(b: Binding) → any
The InputRef a socket records at the place it is used. A socket made inside a `for` body and read after it arrives as the list of every item's value.
| arg | type | description |
|---|---|---|
| b | Binding |
unwrapDeep(v: any, graph: any?, seen: { [any]: any }) → any
| arg | type | description |
|---|---|---|
| v | any | |
| graph | any? | |
| seen | { [any]: any } |
unwrap(v: any, graph: any?) → any
`v` with every socket inside it replaced by the InputRef it records.
| arg | type | description |
|---|---|---|
| v | any | |
| graph | any? |
graphOfValues(...: any) → any
| arg | type | description |
|---|---|---|
| ... | any |
current( ) → any
freeId(graph: any, base: string) → string
Recording
| arg | type | description |
|---|---|---|
| graph | any | |
| base | string |
nextSeq(graph: any) → number
| arg | type | description |
|---|---|---|
| graph | any |
recordNode(graph: any, label: string, op: any, construct: string?, inputs: any, params: any) → string
A node of the call form: `op` is a node envelope or an op id.
| arg | type | description |
|---|---|---|
| graph | any | |
| label | string | |
| op | any | |
| construct | string? | |
| inputs | any | |
| params | any |
outputSocket(graph: any, id: string, output: string?) → any
| arg | type | description |
|---|---|---|
| graph | any | |
| id | string | |
| output | string? |
wired(value: any, where: string, graph: any) → void
Wire a value: its ref, or `nil, value` for a plain constant.
| arg | type | description |
|---|---|---|
| value | any | |
| where | string | |
| graph | any |
refValue(value: any, where: string, graph: any) → any
A value as the ref a scope records: a socket's ref, a constant, a list or a record of those.
| arg | type | description |
|---|---|---|
| value | any | |
| where | string | |
| graph | any |
construct(graph: any, kind: string, named: { [string]: any }, params: { [string]: any }?) → any
One construct: a node the evaluator itself knows, wired from `named`.
| arg | type | description |
|---|---|---|
| graph | any | |
| kind | string | |
| named | { [string]: any } | |
| params | { [string]: any }? |
classKey(key: any) → boolean
Members, class views and writes
| arg | type | description |
|---|---|---|
| key | any |
rebind(b: Binding, ref: any) → void
| arg | type | description |
|---|---|---|
| b | Binding | |
| ref | any |
checkWritable(b: Binding, what: string) → void
| arg | type | description |
|---|---|---|
| b | Binding | |
| what | string |
memberSocket(b: Binding, key: any) → any
| arg | type | description |
|---|---|---|
| b | Binding | |
| key | any |
realize(b: Binding) → any
A class view read as a value: the member of its parent the key names.
| arg | type | description |
|---|---|---|
| b | Binding |
columnRead(view: Binding, name: any) → any
| arg | type | description |
|---|---|---|
| view | Binding | |
| name | any |
namesView(b: Binding) → any
`geometry.names[class]`: the attribute names a class holds, a list the plan answers.
| arg | type | description |
|---|---|---|
| b | Binding |
__index(_t: any, class: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| class | any |
__newindex( ) → void
stepMethod(b: Binding, key: string) → any
`step.sample(x)` and `step.between(index)`: the methods of the record a step body is handed.
| arg | type | description |
|---|---|---|
| b | Binding | |
| key | string |
columnWrite(view: Binding, name: any, value: any) → void
| arg | type | description |
|---|---|---|
| view | Binding | |
| name | any | |
| value | any |
__index(s: any, key: any) → void
| arg | type | description |
|---|---|---|
| s | any | |
| key | any |
__newindex(s: any, key: any, value: any) → void
| arg | type | description |
|---|---|---|
| s | any | |
| key | any | |
| value | any |
describeSocket(s: any) → string
| arg | type | description |
|---|---|---|
| s | any |
refuseComparison(op: string, form: string) → void
| arg | type | description |
|---|---|---|
| op | string | |
| form | string |
__len(_s: any) → void
| arg | type | description |
|---|---|---|
| _s | any |
__call(_s: any) → void
| arg | type | description |
|---|---|---|
| _s | any |
arithmetic(node: string) → void
| arg | type | description |
|---|---|---|
| node | string |
__unm(a: any) → void
| arg | type | description |
|---|---|---|
| a | any |
__iter(s: any) → void
`for _, item in list do ... end` over a socket: one pass of the body, which stands for every item and is written out per item by the evaluator.
| arg | type | description |
|---|---|---|
| s | any |
entryOf(ref: any) → Entry
| arg | type | description |
|---|---|---|
| ref | any |
bare(path: string) → string
A path as one spelling: the engine answers a world's content under `/zero/source` and `/source`.
| arg | type | description |
|---|---|---|
| path | string |
addTo(map: { [string]: { any } }, key: string, item: any) → void
| arg | type | description |
|---|---|---|
| map | { [string]: { any } } | |
| key | string | |
| item | any |
index( ) → Index
The listing of every node and graph, read again when the asset index moves. A node answers to its full name (rank 1) and to every dotted tail of it, its own name among them (rank 2); a graph is called by its path, its identity or `~`.
recordedCalls(source: string?) → void
The node each name a source calls was recorded as, by that name: the reference table of the asset holding the source names the guid every `g.<name>(...)` reached when it was written, and that record is what the name means wherever the source travels. Read once per source for the listing `index` last took.
| arg | type | description |
|---|---|---|
| source | string? |
rootOf(source: string?) → string
| arg | type | description |
|---|---|---|
| source | string? |
editDistance(a: string, b: string) → number
| arg | type | description |
|---|---|---|
| a | string | |
| b | string |
nearest(entries: { Entry }, name: string) → void
| arg | type | description |
|---|---|---|
| entries | { Entry } | |
| name | string |
readEntry(e: Entry) → string
| arg | type | description |
|---|---|---|
| e | Entry |
isCallForm(e: Entry) → boolean
| arg | type | description |
|---|---|---|
| e | Entry |
describeCandidates(list: { Entry }) → string
| arg | type | description |
|---|---|---|
| list | { Entry } |
resolveEntry(graph: any, name: string) → Entry
The node a name resolves to, or an error naming the candidates.
| arg | type | description |
|---|---|---|
| graph | any | |
| name | string |
collect(match: (Entry) → void
| arg | type | description |
|---|---|---|
| match | (Entry |
collectFrom(list: { Entry }?) → void
| arg | type | description |
|---|---|---|
| list | { Entry }? |
resolveNode(name: string) →
The node a name answers to, the way `g.<name>(...)` resolves it: its full name, its path and its guid.
| arg | type | description |
|---|---|---|
| name | string | A node's name (`points.disc`, or a short name one node alone answers to), a path, an identity or a guid. |
examples
local node = proc.builder.resolveNode("points.disc")loadNodeGraph(e: Entry) → void
| arg | type | description |
|---|---|---|
| e | Entry |
orderedKeys(map: any) → void
| arg | type | description |
|---|---|---|
| map | any |
infoOfEntry(e: Entry) → Info
| arg | type | description |
|---|---|---|
| e | Entry |
infoOfOp(id: string) → Info
| arg | type | description |
|---|---|---|
| id | string |
plainNamed(arg: any, info: Info) → boolean
Calls
| arg | type | description |
|---|---|---|
| arg | any | |
| info | Info |
acceptedNames(info: Info) → string
| arg | type | description |
|---|---|---|
| info | Info |
bind(graph: any, info: Info, display: string, packed: any) → void
| arg | type | description |
|---|---|---|
| graph | any | |
| info | Info | |
| display | string | |
| packed | any |
outputNames(info: Info) → void
| arg | type | description |
|---|---|---|
| info | Info |
callEntry(graph: any, label: string, op: any, info: Info, display: string, packed: any) → void
| arg | type | description |
|---|---|---|
| graph | any | |
| label | string | |
| op | any | |
| info | Info | |
| display | string | |
| packed | any |
callByName(graph: any, name: string, packed: any) → void
| arg | type | description |
|---|---|---|
| graph | any | |
| name | string | |
| packed | any |
callOp(graph: any, id: string, packed: any) → void
| arg | type | description |
|---|---|---|
| graph | any | |
| id | string | |
| packed | any |
outputsOf(op: any) →
The names of the outputs a node of the call form returns, in the order `g.<name>(...)` asset, or the id of an op. A construct has one output.
| arg | type | description |
|---|---|---|
| op | any | The `op` field of a recorded node. |
call(graph: any, name: string, ...: any) → void
Call the node `name` of `graph` with `args` (a table naming inputs, or positional values). Returns the node's outputs in declared order.
| arg | type | description |
|---|---|---|
| graph | any | |
| name | string | |
| ... | any |
callOp(graph: any, id: string, ...: any) → void
Call the op `id` of `graph`.
| arg | type | description |
|---|---|---|
| graph | any | |
| id | string | |
| ... | any |
namespace(graph: any, segments: { string }, isOp: boolean) → any
A namespace: `g.points` stands for the name `points`, `g.points.disc` for `points.disc`; calling it adds the node.
| arg | type | description |
|---|---|---|
| graph | any | |
| segments | { string } | |
| isOp | boolean |
__index(_t: any, seg: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| seg | any |
__call(_t: any, ...: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| ... | any |
__tostring( ) → void
compareOp(a: any, op: any, b: any, graph: any) → any
| arg | type | description |
|---|---|---|
| a | any | |
| op | any | |
| b | any | |
| graph | any |
whereOp(cond: any, a: any, b: any, graph: any) → any
| arg | type | description |
|---|---|---|
| cond | any | |
| a | any | |
| b | any | |
| graph | any |
pickOp(choice: any, alternatives: any, graph: any) → any
`g.pick(choice, alternatives)`: `alternatives` is keyed by option name, or a list where a false choice takes the first entry and a true one the second, and a number takes that position. A choice known while the graph is built picks there; a socket records the pick, and only the chosen alternative cooks.
| arg | type | description |
|---|---|---|
| choice | any | |
| alternatives | any | |
| graph | any |
openScope(graph: any, kind: string, fields: any) → string
| arg | type | description |
|---|---|---|
| graph | any | |
| kind | string | |
| fields | any |
closeScope(graph: any, id: string) → void
| arg | type | description |
|---|---|---|
| graph | any | |
| id | string |
foldOp(graph: any, count: any, init: any, fn: any, opts: any?) → any
`g:fold(n, init, fn)`: `fn(value, i)` is built once and written out n times in a chain, each reading the one before.
| arg | type | description |
|---|---|---|
| graph | any | |
| count | any | |
| init | any | |
| fn | any | |
| opts | any? |
stepOp(graph: any, dt: any, substeps: any, fn: any) → any
`g:step(dt, substeps, fn)`: `fn(state, step)` advances the declared state by one fixed step and returns the next.
| arg | type | description |
|---|---|---|
| graph | any | |
| dt | any | |
| substeps | any | |
| fn | any |
stateOp(graph: any, name: any, columns: any) → any
`g:state(name, columns)`: device columns the runtime keeps across presents.
| arg | type | description |
|---|---|---|
| graph | any | |
| name | any | |
| columns | any |
checkOp(graph: any, cond: any, message: any) → any
`g:check(cond, message)`: a condition known while the graph is built refuses the build; one that reads a socket is recorded for the plan or the cook to answer.
| arg | type | description |
|---|---|---|
| graph | any | |
| cond | any | |
| message | any |
readsSocket(v: any, seen: { [any]: boolean }) → boolean
| arg | type | description |
|---|---|---|
| v | any | |
| seen | { [any]: boolean } |
hasOp(graph: any, geometry: any, class: any, name: any) → any
| arg | type | description |
|---|---|---|
| graph | any | |
| geometry | any | |
| class | any | |
| name | any |
copyOp(graph: any, value: any) → any
| arg | type | description |
|---|---|---|
| graph | any | |
| value | any |
colonOrDot(graph: any, fn: (...any) → void
A method that takes the graph first when written `g:name(...)` and nothing first when written `g.name(...)`.
| arg | type | description |
|---|---|---|
| graph | any | |
| fn | (...any |
methodsOf(graph: any) → void
| arg | type | description |
|---|---|---|
| graph | any |
__index(_t: any, kind: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| kind | any |
sceneValue(graph: any, what: string) → any
The socket answering where the graph stands in the scene it is cooked in: `entity` the entity it stands on, `placement` its matrix (16 numbers, column after column), `inverse` the matrix that takes world values into the graph's space, `rotation` the turn the placement makes as `{ x, y, z, w }`. Read as `g.clock.placement`, `g.clock.inverse`, `g.clock.rotation` and `g.clock.entity`.
| arg | type | description |
|---|---|---|
| graph | any | The graph being built. |
| what | string | entity, placement, inverse or rotation. |
transformView(graph: any) → any
`g.transform`: carries values of the world into the graph's own space, the space whose origin is the entity the graph stands on. `point` applies the inverse of the placement, `direction` only its turn and scale, `rotation` composes the inverse of the placement's turn with a quaternion.
| arg | type | description |
|---|---|---|
| graph | any |
matrix( ) → any
vec3(x: any, y: any, z: any) → any
| arg | type | description |
|---|---|---|
| x | any | |
| y | any | |
| z | any |
__index(_t: any, key: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| key | any |
elementView(graph: any) → any
`g.element`: the element a Field evaluates over. `.id` is its index, `.P` its position leaf, and `.<class>.<column>` a column of the domain it stands in. Each read is a socket of its own.
| arg | type | description |
|---|---|---|
| graph | any |
leaf(field: string, class: string?) → any
| arg | type | description |
|---|---|---|
| field | string | |
| class | string? |
__index(_t: any, key: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| key | any |
__index(_c: any, name: any) → void
| arg | type | description |
|---|---|---|
| _c | any | |
| name | any |
__tostring( ) → void
index(graph: any, key: string) → any
What `graph.<key>` answers when the graph has no such field or method: the builder's constructs, or a namespace for a node or op name.
| arg | type | description |
|---|---|---|
| graph | any | |
| key | string |
anySocket(...: any) → boolean
`math.*` and `vector.*` over sockets
| arg | type | description |
|---|---|---|
| ... | any |
aware(real: any, prefix: string, rename: { [string]: string }?) → any
| arg | type | description |
|---|---|---|
| real | any | |
| prefix | string | |
| rename | { [string]: string }? |
__index(_t: any, key: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| key | any |
held(...: any) → void
| arg | type | description |
|---|---|---|
| ... | any |
unit(seed: any, ...: any) → void
| arg | type | description |
|---|---|---|
| seed | any | |
| ... | any |
__index(_t: any, seg: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| seg | any |
__call(_t: any, id: any) → void
| arg | type | description |
|---|---|---|
| _t | any | |
| id | any |
isVectorTable(v: any) → string
| arg | type | description |
|---|---|---|
| v | any |
isColorTable(v: any) → boolean
| arg | type | description |
|---|---|---|
| v | any |
shapeOf(value: any, where: string) → any
What a default value is, as `{ type, fields?, element? }`.
| arg | type | description |
|---|---|---|
| value | any | |
| where | string |
checkOptions(name: string, options: any, typ: string) → void
| arg | type | description |
|---|---|---|
| name | string | |
| options | any | |
| typ | string |
isOlderForm(second: any, opts: any) → boolean
Whether `second` is the type name of the older `g:input(name, "Float", { default })` form.
| arg | type | description |
|---|---|---|
| second | any | |
| opts | any |
describeInput(name: string, default: any, opts: any?) → any
The declaration `g:input(name, default, opts)` records: the type comes from the default (or `opts.type`), and a list or record default states its fields.
| arg | type | description |
|---|---|---|
| name | string | |
| default | any | |
| opts | any? |
isPlain(decl: any) → boolean
Whether an input declaration states a build-time value: it has `options`, or is a Bool or a String. Such an input is the plain value itself while the graph is built, so `if` over it is allowed.
| arg | type | description |
|---|---|---|
| decl | any | A declaration from `describeInput`. |
wiredInput(graph: any, name: string) → any
The value an optional input with no default stands for in the build of `graph`: nil when the build was made for a call that leaves it unwired (`values[name] == false`), else the socket of the input. The graph records which in `graph.wiring[name]`, so `if input == nil` in a node source is decided by what the call wired.
| arg | type | description |
|---|---|---|
| graph | any | The graph being built. |
| name | string | The input's name. |
plainValue(graph: any, name: string, decl: any) → any
The value a plain input stands for in the build of `graph`: the one the build was given, or the declaration's default. The graph records it in `graph.plain[name]`.
| arg | type | description |
|---|---|---|
| graph | any | The graph being built. |
| name | string | The input's name. |
| decl | any | The input's declaration. |
shapeMismatch(shape: any, value: any, path: string) → string
Whether `value` has the shape `shape` states.
| arg | type | description |
|---|---|---|
| shape | any | |
| value | any | |
| path | string |
refusedValue(decl: any, value: any, name: string) → string
The sentence saying why `value` is not one the input `decl` holds, or nil when it holds it: a value outside the input's `options`, past its `min` or `max`, or not of its type.
| arg | type | description |
|---|---|---|
| decl | any | The input's declaration, `graph.inputs[name]`. |
| value | any | The value to check. |
| name | string | The input's name, for the message. |
noteNodeCall(graph: any) → void
Note that `graph` placed a node with `g:node`: a graph source is warned about once.
| arg | type | description |
|---|---|---|
| graph | any |
resetWarnings( ) → void
Forget which graph sources were warned about (for a test).
tokenize(src: string) → void
| arg | type | description |
|---|---|---|
| src | string |
push(t: string, v: string) → void
| arg | type | description |
|---|---|---|
| t | string | |
| v | string |
unquote(text: string) → string
| arg | type | description |
|---|---|---|
| text | string |
plainInput(toks: { Token }, open: number) → boolean
Whether the `g:input(` call whose parenthesis is `open` declares a build-time value: a Bool or String (by its default or its stated type), or an input with `options`.
| arg | type | description |
|---|---|---|
| toks | { Token } | |
| open | number |
isOpenTok(t: Token) → boolean
| arg | type | description |
|---|---|---|
| t | Token |
isCloseTok(t: Token) → boolean
| arg | type | description |
|---|---|---|
| t | Token |
primaries(toks: { Token }, from: number, to: number) → void
The depth-0 primaries of tokens[from..to]: the leftmost name of each chain.
| arg | type | description |
|---|---|---|
| toks | { Token } | |
| from | number | |
| to | number |
spanLeft(toks: { Token }, at: number) → void
The span of the operand of an operator at `at`, to the left or right: it runs over arithmetic and balanced groups and stops at a boundary.
| arg | type | description |
|---|---|---|
| toks | { Token } | |
| at | number |
spanRight(toks: { Token }, at: number) → void
| arg | type | description |
|---|---|---|
| toks | { Token } | |
| at | number |
exprEnd(toks: { Token }, from: number) → number
The end of the expression that starts at `from`: it continues over operators, member and call chains, and balanced groups.
| arg | type | description |
|---|---|---|
| toks | { Token } | |
| from | number |
blockEnd(toks: { any }, from: number) → number
The index of the `end` that closes the block a `do`, `function` or `if` at `from` opens.
| arg | type | description |
|---|---|---|
| toks | { any } | |
| from | number |
check(source: string) →
Check a graph source for Luau comparisons and logic over sockets, which have no value while a graph is built. Reads the source, follows which locals hold sockets (an input, a call of `g.<name>`, a fold or step parameter, a loop item, anything computed from those), and reports every `< <= > >= == ~=`, `and`, `or`, `not` and `if` condition that reads one, naming the `g.*` form to write. A comparison with `nil` is a build-time test and is allowed.
| arg | type | description |
|---|---|---|
| source | string | The text of a graph's `init.luau`. |
examples
local problems = proc.builder.check(vfs.read(path .. "/init.luau"))
report(line: number, code: string, message: string) → void
| arg | type | description |
|---|---|---|
| line | number | |
| code | string | |
| message | string |
hasSocket(from: number, to: number) → boolean
| arg | type | description |
|---|---|---|
| from | number | |
| to | number |
producesSocket(from: number, to: number) → boolean
Does tokens[from..to] produce a socket?
| arg | type | description |
|---|---|---|
| from | number | |
| to | number |
prepareSource(source: string) → string
The source as the graph loader should compile it: with `math` and `vector` bound to the socket-aware ones, on the source's first line.
| arg | type | description |
|---|---|---|
| source | string | The text of a node or graph `init.luau`. |
chunkPath(fn: any) → string
The path of the node or graph entry a builder function was compiled from, or nil for any other chunk: only a `.procNode` or `.procGraph` entry is read again and checked.
| arg | type | description |
|---|---|---|
| fn | any |
usesMath(src: string) → boolean
| arg | type | description |
|---|---|---|
| src | string |
checkSourceOf(fn: any) → void
Hold the source a builder function came from to the static check, once per source text. An error lists every refused line.
| arg | type | description |
|---|---|---|
| fn | any |
reloadAware(fn: any) → any
The graph the builder function's own source builds when loaded with `math` and `vector` socket-aware, or nil when that is not needed or not possible. `define` calls it before building so a formula written with the plain `math` reads unchanged.
| arg | type | description |
|---|---|---|
| fn | any |
isReloading(fn: any) → boolean
Whether the source of `fn` is being run again by `reloadAware`.
| arg | type | description |
|---|---|---|
| fn | any |
sourceOf(fn: any) → string
The path of the chunk a function came from.
| arg | type | description |
|---|---|---|
| fn | any |
withInputs(values: { [string]: any }, fn: () →
Run `fn`, which builds a graph with `proc.define`, giving the graph the plain input values `values` (inputs with `options`, and Bool and String inputs). An input the table does not name keeps its default.
| arg | type | description |
|---|---|---|
| values | { [string]: any } | A table of input name to value. |
| fn | ( | The function that builds the graph, normally the loaded chunk of a node or graph source. |
rebuild(graph: any, values: { [string]: any }) →
The graph `graph` source builds when its plain inputs hold `values`, read from `graph.source` and run again.
| arg | type | description |
|---|---|---|
| graph | any | A graph built in the call form. |
| values | { [string]: any } | A table of input name to value. |
forInputs(graph: any, inputs: { [string]: any }?) →
The graph to cook for `inputs`: `graph` itself while its plain inputs hold what the build used, else the graph built again with the values `inputs` states (the declaration's default for an input it leaves out).
| arg | type | description |
|---|---|---|
| graph | any | A graph. |
| inputs | { [string]: any }? | A table of input name to value, or nil. |
run(graph: any, fn: (any) → void
Run `fn(g)` with `g` the graph being built, then close any `for` body left open, and record what `fn` returns as the graph's outputs: a table of name to value, in the order the values were made.
| arg | type | description |
|---|---|---|
| graph | any | |
| fn | (any |
reset( ) → void
Forget the cached node index and node graphs (for a test that writes nodes).
isolated(fn: () → void
Run `fn` with a graph-building state of its own: no graph being built, no node or source being loaded and no plain input values waiting for a build. The caller's state is back when `fn` returns or raises, and an error `fn` raises is raised again. What the state caches (node graphs, the node index, checked sources) is shared.
| arg | type | description |
|---|---|---|
| fn | ( | The function to run. |
examples
builder.isolated(function() registry.listAssets() end)
callByName(graph: any, name: string, ...: any) → void
| arg | type | description |
|---|---|---|
| graph | any | |
| name | string | |
| ... | any |
clockSocket(graph: any, field: string) → any
The socket for one field of a graph's clock.
| arg | type | description |
|---|---|---|
| graph | any | |
| field | string |
Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Showing up to 3 levels deep. Open a part to see what it holds further down.
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
agent_score is exposed.+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
Scoped to this part · feeds back into the world's score.