Skip to content

Declaring Ports & Parameters

Declarations must come first. The header ends at the first line that is not a declaration, not blank, and not a comment; everything from there down is body. Blank and comment lines between declarations stay in the header.

A declaration line starts with the word in or param followed by a space or tab. That whitespace rule is what keeps ordinary code like int x = 3; or a call to parameterize() from being mistaken for a declaration.

A declaration that has not reached its ; continues onto the lines below it, so a long initializer may be wrapped. The header ends at the first line that starts neither a declaration nor a continuation of one.

in sampler2D source;
in sampler2D detail; // @optional
RuleBehavior
Syntaxin sampler2D <name>; and nothing else is accepted after in
Port orderDeclaration order, top to bottom
Port labelThe declared name, title-cased with a space inserted before an interior capital: source becomes Source, baseColor becomes Base Color
Required by defaultA node with an unconnected required input produces no output
// @optionalMakes the port optional. Unconnected, it reads as opaque mid-gray (0.5, 0.5, 0.5, 1.0)
Maximum4. Declaring a 5th is a compile error
Portability3 or 4 inputs makes the source native-only (the fallback interpreter binds 2 samplers)

Read an input in the body with texture(<name>, uv). Input textures are sampled with repeat addressing and linear filtering at LOD 0, so sampling outside 0.0 to 1.0 reads from the tiled repeat, which is what a seamless neighbor tap needs.

param float amount = 1.0; // @range(0, 2)
param int mode = 0; // @enum(Add, Multiply, Screen)
param bool invert = false;
param seed variation;
param vec3 tint = vec3(1.0, 0.6, 0.2); // @color

Syntax is param <type> <name> with an optional = <default> and an optional trailing annotation comment. Omit the initializer and the parameter starts at 0.

Declared typeProperties controlType seen in the bodyStored parameter name(s)
floatNumber field; a slider appears only when @range gives both boundsfloat<name>
intNumber field and stepped slider, min 0 / max 1 unless @range overrides. With @enum, a dropdown insteadfloat, not int. Write int(name) for integer math<name>
boolOn/off togglebool; if (invert) works<name>
seedNumber field and Random button, no sliderfloat in 0.0 to 100.0, derived from the stored 64-bit seed. A hash offset, not the number in the panel<name> (stores the raw integer)
vec3 or vec4 with @colorColor editor with RGB sliders and a hex fieldvec3, or vec4 with alpha pinned to 1.0Three params: <name>Red, <name>Green, <name>Blue, each 0 to 1
vec2 / vec3 / vec4 without @colorOne plain float controlfloat, see the warning below<name>

Annotations are // comments whose first non-space character is @. Several may share one comment (// @color @range(0, 1)); block comments are never annotations.

AnnotationApplies toEffect
@optionalin sampler2DPort becomes optional; unconnected reads as opaque mid-gray
@range(<min>, <max>)float, intBounds the control and adds a slider. Exactly two numeric values, or it is an error
@enum(<label>, <label>, …)intDropdown with those labels; maximum becomes label-count minus one
@colorvec3, vec4Color editor. Applying it to a smaller type is a compile error

@enum on a float param, or @range on a bool, seed or @color param, is silently ignored.

An initializer may be a plain number, a signed number, true / false, or a constructor of literals such as vec3(1.0, 0.6, 0.2). A single-argument constructor broadcasts: vec3(0.5) is vec3(0.5, 0.5, 0.5).

Initializers are literals only. Expressions (1.0 / 2.0), scientific notation (1e-3), and hex (0x10) are not accepted in the header; the header’s number scanner understands digits, one decimal point, and a trailing f/F suffix. All three are fine inside the body.

Every scalar channel a parameter needs is bound as its own live GPU uniform. The compiled pipeline depends only on the source text, never on parameter values, so dragging a slider re-renders without recompiling the shader. One source is one pipeline.

Inside the body, parameters arrive as ordinary global variables carrying the names you declared. Writing to one is legal but affects nothing beyond the pixel being shaded; treat them as read-only.

Custom Shader parameters can be exposed as project-level globals from the Properties panel like any other node parameter. See Exposed Parameters.

LimitValue
Texture inputs4 maximum; a 5th is a compile error
Inputs before the source becomes native-only3 or more
ParametersNo fixed cap
Parameter defaultsLiterals or literal constructors only; no expressions, no 1e-3, no hex
Vector paramsOnly vec3/vec4 with @color produce a vector in the body