documentation · generative engine api

The API.

create · build · light · move — and every chart verb, unchanged

Four moves make a scene: createWorld, build shapes with the geometry library, light them with lights and the material options, and register life with grow. Everything Generative Charts exposes works here too, unchanged. Zero dependencies; the browser is the whole runtime.

← Back to Generative Engine

install

One package.

WebGL2 · browser-only — guard SSR imports

npm install @chromatic-coherence/generative-engine

quick start

A lit world in five lines.

create · light · build · grow · start

import { createWorld, v3, heightfield } from "@chromatic-coherence/generative-engine";

const w = createWorld({ canvas, controls: true, shadows: true });

// light it — lights[0] casts the shadows
w.lights.push({ p: v3(-160, 300, 140), intensity: 1.2, falloff: 520 });

// build a shape in a line — your data as terrain
w.mesh(heightfield((x, z) => Math.sin(x * 0.01) * 24, 700, 700), { hue: 210, sat: 45, light: 30 });

// register life — drawn every frame
w.grow((t) => w.drawGlow(v3(Math.cos(t) * 100, 40, Math.sin(t) * 100), 45, 20, 0.9));

w.start();

the surface

Every door, by area.

transcribed from the source of truth

Each entry is a real export of @chromatic-coherence/generative-engine. The heavy features (shadows, glow, contact shading) are opt-in flags — a plain world stays light.

creating a world

One canvas, one World. The engine owns the camera, the light, the frame loop — you build the scene and register life.

createWorld
createWorld(opts: WorldOpts): Worldthe door in — throws cleanly when WebGL2 is missing (catch it and fall back)
shadows
shadows?: boolean | { size?, softness?, bias? }real cast shadows from lights[0] — off by default; 2048px map when on
post
post?: boolean = truethe cinematic finish — glow, soft shading, antialiasing. false renders direct
theme
theme?: "dark" | "light"the ink edition — the same scene on paper; recipes need no changes
background
background?: { hue, sat?, light? } | "transparent"the world owns its ground; fog fades toward it
camera / controls
camera?: { target?, dist?, pitch?, yaw?, fov? } · controls?: booleanstarting view + drag-to-orbit and ctrl-wheel zoom

geometry — shapes in a line

Builders return a Mesh; w.mesh() uploads it with smooth shading. All pure maths, all unit-tested.

heightfield
heightfield(f(x, z), sizeX, sizeZ, nx?, nz?)a surface from any function — your data as terrain
icosphere
icosphere(radius, subdiv?)a sphere with perfectly smooth shading at any detail
tube
tube(path, radius | (u) => radius, segments?, closed?)sweep a tube along any path — taper for free
lathe / extrude
lathe(profile, segments?) · extrude(shape, height)turned profiles and raised footprints
plane / box
plane(sx, sz, nx?, nz?) · box(sx, sy, sz)the ground and the block
transformMesh / mergeMesh
transformMesh(mesh, mat) · mergeMesh(...parts)place, turn, scale and combine before upload
mesh
mesh(geo: Mesh, opts: FaceOpts)upload a whole shape in one call
meshMorph
meshMorph(geoA, geoB, opts)upload a pair (same vertex count) — morph() blends between them live

light & materials

Per-pixel light everywhere; the material lives on each face's options.

lights
world.lights.push({ p, intensity, falloff })up to 8 point lights, steerable per frame; lights[0] casts the shadows
light
world.light = { dir, ambient, diffuse, signed }the directional base light
FaceOpts.gloss
gloss?: 0..1matte cloth to wet shine — drives the highlight
FaceOpts.blood
blood?: 0..1 (+ world.bloodPulse)the living-skin model: flush, pulse, light through tissue
bloom / ssao / fxaa
world.bloom = { on, threshold, strength } · world.ssao · world.fxaathe finish, art-directable — glow, contact shading, smoothing
filmic / grade / vignette
world.filmic · world.grade · world.vignettethe cinematic look: rolled highlights, cool shadows, edge dark

motion — nothing rebuilds

Movement happens on the GPU: the CPU never re-builds a vertex.

grow
grow((t, dt, w) => void)register a per-frame hook — everything alive lives here
setTransform
setTransform(group, mat | { translate?, rotateX/Y/Z?, scale? })move a named group rigidly — bodies orbit, machines roll
morph
morph(group, t: 0..1)blend a meshMorph pair — breathing, becoming; eased like fade
fade
fade(group, target: 0..1)fade a named group in or out (8 groups per world)
ribbon / drawRibbon
ribbon(points, { width, hue, alpha }) · drawRibbon(...)strokes with real pixel width — static, or redrawn every frame
the chart verbs
line · glow · dust · face · drawLine · drawPath · drawGlow · drawLabel · drawFacethe whole Generative Charts surface, unchanged — recipes port as-is

crowds & nature — thousands, on the GPU

Build one; the GPU draws ten thousand — wind, flight and all.

meshInstanced
meshInstanced(geo, transforms, opts)one mesh, drawn at every transform in a single call — shadow pass included
sway
meshInstanced(…, { sway: { amp, freq? } })every instance sways to its own phase in the vertex stage; w.wind = { dir, speed } is the one wind
flight
meshInstanced(wing, instances, { flight: true })the batch becomes a murmuration — orbits, lobes and wingbeats computed from time alone
water
w.water = { on, level, size, hue, amp, distort, alpha }one water table per world: a reflected second scene pass under a wave-displaced fresnel surface

figures — bones grown from code

No model files: rigs are built like geometry, and posed per frame.

humanoid / quadruped
humanoid(height?) · quadruped(height?)ready rigs — eleven and seven bones; or build your own Rig from bones + a mesh
figure
w.figure(rig, opts) → { pose, bones }upload a rigged figure; place and turn it with its group like any geometry
pose
fig.pose(walkPose(t)) · trotPose · composePoseprocedural cycles, or any per-joint rotations — bent in the vertex stage, shadows and reflections alike

cinema — the finishing pass

dof
w.dof = { on, focus, range, maxBlur }depth of field from the real depth buffer — sharp subjects protected per-tap
motionBlur
w.motionBlur = { on, strength }camera blur by depth reprojection into the previous frame
the grade
w.filmic · w.grade · w.vignette · w.bloom · w.ssaothe HDR post chain, art-directable per scene

objectives — scenes that know where they're going

Give a scene a goal; the engine drives there and a live meter names the movement.

attachObjectives
attachObjectives(world, { floor?, settleAfter? })attach the layer — rides the frame loop, drives the world through its public verbs
define
define(name, { transform?, morph?, fade?, camera?, custom?, pace? })set a named goal — channels ease there over pace seconds
retarget
retarget(name, patch)move a live goal — motion continues from the current state (no snap), the meter re-elevates
onReading / readings
onReading(r => …) · readings()the movement meter: { progress, level, floor, moving, settled, driving[] } — settled is the sustained fall to the floor
remove
remove(name)forget an objective — its channels stay where they were driven

collision control — the world knows where things are

Sphere colliders that ride their group transforms. Flag a mesh, or place invisible ones by hand; then ask the world what a moving thing touches.

collider: true
mesh(geo, { …, collider: true })register the mesh's bounding sphere as a collider — it rides the mesh's group setTransform like the geometry
addCollider / removeCollider
addCollider(p, r, group?) → id · removeCollider(id)invisible sphere colliders placed by hand — walls, triggers, guards
collide / collideAll
collide(p, r?) → { n, depth, p, collider } | nullprobe a sphere against the world: push-out normal + overlap depth — bounce = reflect velocity on n, then push out by depth
rayHit
rayHit(o, dir, maxDist?, r?) → { t, p, collider } | nullthe nearest hit along a ray — pass r to sweep a moving sphere; a beam ends exactly where the world gets in its way
the pure kit
sphereHit(a, b) · raySphere(o, d, s, r?, max?) · boundingSphere(mesh)the DOM-free maths underneath — node-tested, exported for your own systems

camera & lifecycle

cam
cam: { target, dist, pitch, yaw…, fov }public camera state — steer it from a grow hook
fly
createWorld({ controls: "fly" }) · w.flySpeedfree flight: drag to look, wheel to fly along your gaze, W/A/S/D + shift
project / pick / fog
project(p) · pick(sx, sy, planeY?) · fog(z)world to screen, screen to ground, depth fade
start / settle
start() · settle(t)run the loop — or render one settled frame (stills, reduced motion)
poster / capturePoster
poster(t = 0) · capturePoster(opts, build, w, h, t?)the window's first frame as a still: render it in place, or capture it off-screen as a PNG data URL with the context released — the placeholder-image pattern, built in
pause / resume
pause() · resume()freeze an off-screen world (GPU state kept) and wake it instantly
dispose
dispose(releaseContext?: boolean)stop and clean up; true also frees the GL context now (mount a fresh canvas to rebuild)

see it live

Thirty scenes, all copyable.

every scene is a recipe against this surface

Every scene on the Generative Engine collections runs against this API — orbit it, copy the full code, and point it at your own data.