Skip to content
View source

Your first Kernel

A Kernel is Entelechy’s law: a small typed function Y = K(X, P, C) — the output Y from input Fields X, params P and context C (coordinates, time, pointer…). This page writes a Kernel that draws concentric rings and checks it with entelechy check.

终端窗口
mkdir -p rings/kernels rings/tests
cd rings

Create kernels/rings.ent:

/// Concentric rings: every pixel works out its own color from where it is.
kernel demo.rings@1 {
requires { field.write; }
/// How many rings fit from the center to the edge.
param count: Float = 6.0;
output result: Image;
compute {
let uv = coord() / domain() * 2.0 - 1.0;
let r = length(uv);
let band = step(0.5, fract(r * count));
return vec4(band, band * 0.6, 1.0 - band, 1.0);
}
}

Line by line:

Form Meaning
kernel demo.rings@1 The Kernel’s identity, name@version. Scenes bind to the id, never to a file.
requires { field.write; } The capabilities it needs. It writes an output and reads none, so field.write alone.
param count: Float = 6.0; A param and its default, which a scene may override. A Float literal is 6.0, never 6.
output result: Image; An output port. Image is Grid<Vec4>, each channel 0 to 1.
compute { … } The map mode: once per element of the output’s domain, returning that element.
coord(), domain() This element’s coordinates and the domain’s extent (see context builtins).
/// A doc comment; it travels with the published Kernel and the kernels operation answers it.
终端窗口
entelechy check kernels/rings.ent
kernels/rings.ent: demo.rings@1
kernel demo.rings@1
requires field.write
param count: Float = 6.0
output result: Image

check prints each Kernel’s manifest; --ir prints the validated IR a backend runs.

Change fract(r * count) to fract(r * cnt) and check again:

kernels/rings.ent:10:40: `cnt` is not defined
error: 1 problem(s) found

A diagnostic is always file:line:column: message. A running session refuses such a version and keeps the old one: the basis of hot swap.

Append a Kernel that tints a picture to the same file:

kernel demo.tint@1 {
requires { field.read; field.write; }
input source: Image;
param warmth: Float = 0.8;
output result: Image;
compute {
let c = sample(source);
return vec4(c.rgb * vec3(1.0, warmth, 0.4), c.a);
}
}

sample(source) reads the input at this element, so it needs field.read. One .ent holds any number of Kernels and the structs, types and fns they share.

A Kernel does not run alone — a scene places it. Next: Your first scene.