@netforge/engine/runtime API reference
Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under @netforge with source at github.com/netnetdev/net-forge.
The three.js runtime templates draw with: the WebGPU renderer with a WebGL2 fallback, createRenderStack, the game feel kit, CameraRig, InputController, AssetLoader, instanced and animated crowds, and the arena client.
import { createRenderStack, FeelKit } from "@netforge/engine/runtime";Generated from packages/engine/src/runtime/index.ts by apps/forge-docs/scripts/api.mjs. Signatures are what the TypeScript compiler reports for the current source; long types are cut and say so.
| Kind | Count |
|---|---|
| Functions | 40 |
| Classes | 36 |
| Constants | 13 |
| Types | 109 |
| Other | 1 |
Functions
applyCrowdMotion
Vertex animation for crowds without skeletons: bob, waddle, forward lean and step cadence from each instance's speed, a squash-and-stretch on hit, a hit flash, idle breathing. Applied to an existing node material (positionNode, emissiveNode); geometry stands on y = 0 and faces -z.
function applyCrowdMotion(material: MotionMaterial, attrs: CrowdAttributes, time: Node<"float">, opts?: CrowdMotionOptions): MotionMaterial;Source: packages/engine/src/runtime/render/crowd-motion.ts
bakeVertexAnimation
Bake one or more clips of a skinned mesh into a vertex animation texture
(CPU, at load). Frames are laid out clip after clip; a crowd then plays
any clip on thousands of instances in one draw (VatCrowd).
function bakeVertexAnimation(mesh: SkinnedMesh, clips: AnimationClip | readonly AnimationClip[], opts?: BakeOptions): VertexAnimation;Source: packages/engine/src/runtime/render/vat.ts
billboardWorld
World position of a sprite vertex: center is the feet in world space,
x/y the vertex in metres on the plane (x across, y up from the feet),
flip -1 to mirror. The plane turns to the camera (its up is the camera's
up, so a sprite under a high camera shows its full height).
function billboardWorld(center: Node<"vec3">, x: Node<"float">, y: Node<"float">, flip: Node<"float">): Node<"vec3">;Source: packages/engine/src/runtime/render/sprite.ts
boundsShift
How far to move a view so seen stays inside bounds, per axis: zero
when it already fits, the overshoot when it pokes out of one side, and
centring when it is wider than the bounds.
function boundsShift(seen: GroundBounds, bounds: GroundBounds): { x: number; z: number; };Source: packages/engine/src/runtime/camera.ts
browserHints
Read the hints from the running browser (safe in node: returns {}).
function browserHints(backend?: "webgpu" | "webgl2"): DeviceHints;Source: packages/engine/src/runtime/render/quality.ts
buildSegmentRig
A three-bone procedural character (hip, spine, head) skinned to a cylinder or any upright geometry, with a full animation set built in code: rest, idle, walk, run, hit, attack, die. Templates with procedural art get real skinned animation (and VAT crowds via bakeVertexAnimation) without any asset files.
function buildSegmentRig(material: Material, opts?: SegmentRigOptions): SegmentRig;Source: packages/engine/src/runtime/render/rig.ts
collectManifest
Collect and cross-check what the game module declared. Called by the build and the runtime after importing the module, not by game code.
function collectManifest(): GameManifest;Source: packages/engine/src/api/registry.ts
countUp
Count a number up in an element's text (scores, balances).
function countUp(el: FeelElement, from: number, to: number, ms?: number, format?: (n: number) => string, tweens?: Tweens): void;Source: packages/engine/src/runtime/feel/tween.ts
createPixelStyle
The pixel style with its options.
function createPixelStyle(o?: PixelStyleOptions): StyleKit;Source: packages/engine/src/runtime/styles/pixel/index.ts
createRenderer
three.js WebGPURenderer. It targets WebGPU where navigator.gpu yields an
adapter and falls back to its WebGL2 backend otherwise, so one code path
(node materials, instancing) covers every browser (spec).
function createRenderer(canvas: HTMLCanvasElement, opts?: RendererOptions): Promise<RendererHandle>;Source: packages/engine/src/runtime/renderer.ts
createRenderStack
Everything a template needs for a good-looking frame, in one call:
lighting with a following shadow, fog and sky, bloom and grade, GPU
particles, decals and shockwave rings, quality tiers and dynamic
resolution. Replace renderer.render(scene, camera) with stack.frame(...).
function createRenderStack(handle: RendererHandle, scene: Scene, camera: Camera, opts?: RenderStackOptions): RenderStack;Source: packages/engine/src/runtime/render/stack.ts
createStyledView
The style's view of a scene, or null when the style has no session (lowpoly, unknown, or a kit with world builders only).
function createStyledView(handle: RendererHandle, scene: Scene, camera: Camera, style: string | StyleKit | null | undefined, opts?: StyledViewOptions): StyledView | null;Source: packages/engine/src/runtime/styles/view.ts
damp
Frame-rate independent exponential smoothing factor for a rate in 1/s.
function damp(rate: number, dt: number): number;Source: packages/engine/src/runtime/interpolate.ts
detectTier
Pick a tier from device hints. Phones and tablets start at medium (low on weak or WebGL-only ones); desktops start at high unless the CPU is small. Dynamic resolution then holds the frame rate within the tier.
function detectTier(h: DeviceHints): QualityTier;Source: packages/engine/src/runtime/render/quality.ts
distanceGain
Gain for a source distance m away (inverse falloff, 0 past maxDistance).
function distanceGain(distance: number, refDistance?: number, maxDistance?: number, rolloff?: number): number;Source: packages/engine/src/runtime/feel/audio.ts
fieldBounds
Square bounds around the origin: a field of half size half plus margin of outside ground.
function fieldBounds(half: number, margin?: number): GroundBounds;Source: packages/engine/src/runtime/camera.ts
flashColor
Write a flashed instance colour into out at offset (rgb floats):
base colour mixed toward tint and boosted by the flash.
function flashColor(out: Float32Array | number[], offset: number, flash: number, base?: readonly [number, number, number], tint?: readonly [number, number, number], boost?: number): void;Source: packages/engine/src/runtime/feel/flash.ts
flashMultiplier
Colour multiplier for a flash: 1 at rest, 1 + boost at full flash (instance colours above 1 read as glowing white).
function flashMultiplier(flash: number, boost?: number): number;Source: packages/engine/src/runtime/feel/flash.ts
groundFootprint
The ground a camera sees: the box around where its four corner rays meet
the plane y = groundY. A ray at or above the horizon counts as reaching
reach m out along the ground. The camera's matrices must be current.
function groundFootprint(camera: Camera, groundY?: number, reach?: number): GroundBounds;Source: packages/engine/src/runtime/camera.ts
hashSigned
Seeded integer hash to -1..1 (deterministic, no Math.random).
function hashSigned(i: number, seed: number): number;Source: packages/engine/src/runtime/feel/noise.ts
isSprite
Whether a geometry is a sprite plane (markSprite).
function isSprite(geometry: { userData: Record<string, unknown>; }): boolean;Source: packages/engine/src/runtime/render/sprite.ts
lerp
Linear interpolation.
function lerp(a: number, b: number, t: number): number;Source: packages/engine/src/runtime/interpolate.ts
lerpAngle
Interpolate angles along the shortest arc (radians).
function lerpAngle(a: number, b: number, t: number): number;Source: packages/engine/src/runtime/interpolate.ts
locomotionState
The locomotion state for a speed, with hysteresis around the current state. Pure.
function locomotionState(speed: number, current: LocomotionState, t?: LocomotionThresholds): LocomotionState;Source: packages/engine/src/runtime/render/animation.ts
markSprite
Flag a sprite plane so AnimatedCrowd draws it as billboards (geometry.userData).
function markSprite(geometry: { userData: Record<string, unknown>; }): void;Source: packages/engine/src/runtime/render/sprite.ts
markSpriteMaterial
A sprite material's extra output: the pixel style keeps sprites in their own palette colours and steps only the 3D world into light bands. Safe everywhere: a target without a "sprite" texture just takes the colour.
function markSpriteMaterial(material: { mrtNode: unknown; }): void;Source: packages/engine/src/runtime/render/sprite.ts
pickStyle
The art style a template draws in: a known ?style= on the URL wins over the game's declared style.
function pickStyle(declared: string, requested: string | null | undefined): string;Source: packages/engine/src/runtime/styles/index.ts
pixelBlock
The integer block size (screen pixels per low-res pixel) that puts
texelsPerMetre low-res rows on each metre of a view viewMetres tall.
function pixelBlock(bufferHeight: number, viewMetres: number, texelsPerMetre: number, minRows?: number): number;Source: packages/engine/src/runtime/styles/pixel/index.ts
pop
Punch an element's scale up to scale and spring it back (level-up, coin gain).
function pop(el: FeelElement, scale?: number, ms?: number, tweens?: Tweens): void;Source: packages/engine/src/runtime/feel/tween.ts
qualitySettings
function qualitySettings(tier: QualityTier): QualitySettings;Source: packages/engine/src/runtime/render/quality.ts
resetRegistry
Forget all declarations (the build and tests load several game modules in one process).
function resetRegistry(): void;Source: packages/engine/src/api/registry.ts
resolveLook
A preset by name; unknown names fall back to "studio" (never throws at runtime).
function resolveLook(name: string | undefined): Look;Source: packages/engine/src/runtime/render/presets.ts
seededRandom
A small seeded PRNG (mulberry32), 0..1, for cosmetic variation that should not use Math.random.
function seededRandom(seed: number): () => number;Source: packages/engine/src/runtime/feel/noise.ts
shakeEl
Shake an element sideways by up to px, decaying over ms (denied action, damage taken).
function shakeEl(el: FeelElement, px?: number, ms?: number, tweens?: Tweens): void;Source: packages/engine/src/runtime/feel/tween.ts
snapToTexel
Snap a world point to the shadow map's texel grid in light space, so a
shadow camera that follows the player moves in whole texels and the
shadow edges never shimmer. dir is the light's travel-from direction
(unit), texel the world size of one shadow texel.
function snapToTexel(p: readonly [number, number, number], dir: readonly [number, number, number], texel: number): Vec3Tuple;Source: packages/engine/src/runtime/render/lighting.ts
spriteBillboardNode
positionNode for a single sprite mesh (a player, a boss): the plane faces the camera whatever the mesh's rotation, and mirrors when the mesh's forward (-z) points to screen left.
function spriteBillboardNode(): Node<"vec3">;Source: packages/engine/src/runtime/render/sprite.ts
stepSpring
Advance one spring axis toward target by dt seconds with the exact
solution of the damped oscillator, so it is stable at any stiffness and
frame rate. omega is the natural frequency in rad/s, zeta the damping
ratio. Returns [value, velocity].
function stepSpring(value: number, velocity: number, target: number, omega: number, zeta: number, dt: number): [number, number];Source: packages/engine/src/runtime/feel/spring.ts
styleKit
The kit for a style, or null (low-poly, or a style with no kit yet).
function styleKit(style: string | null | undefined): StyleKit | null;Source: packages/engine/src/runtime/styles/index.ts
toNodeMaterial
Copy a classic MeshStandardMaterial into a node material (so positionNode can be set).
function toNodeMaterial(m: MeshStandardMaterial): MeshStandardNodeMaterial;Source: packages/engine/src/runtime/render/crowd-motion.ts
valueNoise1
Smooth 1D value noise in -1..1, continuous in t, fixed for a seed.
function valueNoise1(t: number, seed: number): number;Source: packages/engine/src/runtime/feel/noise.ts
Classes
AnimatedCharacter
A skinned character (glTF or procedural) with an AnimationMixer:
setSpeed(mps) drives idle/walk/run with crossfades and playback rate
matched to ground speed; oneShot("attack") plays once and blends back
to locomotion; play(name) for anything else. Call update(dt) per frame.
class AnimatedCharacter {
constructor(root: Object3D, clips: readonly AnimationClip[], opts?: AnimatedCharacterOptions);
readonly mixer: AnimationMixer<AnimationMixerEventMap>;
has(name: string): boolean;
get state(): LocomotionState;
get playing(): string | null;
play(name: string, opts?: PlayOptions): boolean;
oneShot(name: string, opts?: Omit<PlayOptions, "loop">): boolean;
setSpeed(mps: number): void;
update(dt: number): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/animation.ts
AnimatedCrowd
An instanced crowd with procedural animation: one draw, per-instance
position, yaw, scale, phase, speed, hit squash and flash. Write instances
between begin() and end(time) each frame; only the written range uploads.
class AnimatedCrowd {
constructor(geometry: BufferGeometry, material: MeshStandardMaterial | MeshStandardNodeMaterial, capacity: number, opts?: CrowdMotionOptions);
readonly mesh: Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>;
readonly time: UniformNode<"float", number>;
readonly attrs: CrowdAttributes;
count: number;
begin(): void;
push(x: number, y: number, z: number, yaw: number, phase: number, speed: number, hit?: number, flash?: number, scale?: number): void;
end(timeSeconds: number): void;
addTo(parent: Object3D): this;
dispose(): void;
}Source: packages/engine/src/runtime/render/crowd-motion.ts
ArenaClient
The week-2 single-player arena: engine-sim on a fixed tick, rendered by three.js with interpolation, one instanced draw for every enemy, a follow camera, keyboard/mouse/touch input. Placeholder primitives only.
class ArenaClient {
constructor(host: HTMLElement, handle: RendererHandle, world: SimWorld, opts: ArenaOptions);
static create(host: HTMLElement, opts?: ArenaOptions): Promise<ArenaClient>;
start(): void;
stats(): ArenaStats | null;
dispose(): void;
}Source: packages/engine/src/runtime/arena.ts
AssetLoader
glTF loading with the runtime's compression stack: meshopt geometry (EXT_meshopt_compression) and KTX2/Basis textures (KHR_texture_basisu). Loads are cached by id, so a prefab used 2,000 times is fetched once.
class AssetLoader {
constructor(renderer: WebGPURenderer, opts: AssetLoaderOptions);
load(id: string): Promise<GLTF>;
dispose(): void;
}Source: packages/engine/src/runtime/assets.ts
Atmosphere
Fog matched to a sky gradient, so the far ground melts into the background instead of meeting a hard color. Linear or exp2 distance fog, plus an optional low height fog (ground mist). Values live in uniforms: changing them never recompiles a shader.
class Atmosphere {
constructor(scene: Scene, opts?: AtmosphereOptions);
readonly fogColor: UniformNode<"color", Color>;
readonly skyTop: UniformNode<"color", Color>;
readonly near: UniformNode<"float", number>;
readonly far: UniformNode<"float", number>;
readonly density: UniformNode<"float", number>;
readonly heightDensity: UniformNode<"float", number>;
readonly heightTop: UniformNode<"float", number>;
setPreset(preset: LookPreset, overrides?: Partial<AtmospherePreset>): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/atmosphere.ts
CameraRig
Third-person orbit-follow camera with the camera parts of the feel kit:
critically damped follow, smoothed and clamped lead, a dead zone, trauma
shake and FOV punches. yaw matches the sim's convention (0 looks down
-z), so the input layer can send the camera's yaw as the character's
facing. Shake is applied as a per-frame offset and roll on top of the
computed pose, so it never accumulates drift.
class CameraRig {
constructor(aspect: number, opts?: CameraRigOptions);
readonly camera: PerspectiveCamera;
yaw: number;
pitch: number;
readonly trauma: Trauma;
readonly offset: Vector3;
roll: number;
readonly clampShift: { x: number; z: number; };
setDistance(metres: number): void;
setBounds(bounds: GroundBounds | null): void;
get target(): Readonly<Vector3>;
look(dYaw: number, dPitch: number): void;
addTrauma(amount: number): void;
shake(amplitude: number, seconds: number): void;
punch(degrees: number): void;
get fovKick(): number;
update(target: Vector3, dt: number, realDt?: number): void;
resize(aspect: number): void;
}Source: packages/engine/src/runtime/camera.ts
CueGate
The DOM-free decision core: may a cue start now? Per-cue gap and voice cap, and a global voice cap.
class CueGate {
constructor(maxVoices?: number);
allow(name: string, nowMs: number, durationMs: number, minGapMs: number, cueVoices: number): boolean;
get voices(): number;
}Source: packages/engine/src/runtime/feel/audio.ts
DamageNumbers
The DOM pool. Construct only in a browser (it creates nodes under host).
class DamageNumbers {
constructor(host: HTMLElement, opts?: DamageNumbersOptions | number);
readonly stack: NumberStack;
get shown(): number;
show(x: number, y: number, amount: number, big?: boolean): void;
add(n: NumberInput, nowMs?: number): void;
update(dt: number): void;
}Source: packages/engine/src/runtime/feel/numbers.ts
DynamicResolution
Pixel-ratio controller: trades pixels for frame time. Push every frame's
interval; update(now) returns the new ratio when it changes, else null.
After a change the window restarts so the next decision sees the new cost.
class DynamicResolution {
constructor(initial: number, opts?: DynamicResolutionOptions);
ratio: number;
readonly o: Required<DynamicResolutionOptions>;
push(frameMs: number): void;
p95(): number;
setRange(min: number, max: number): number | null;
update(now: number): number | null;
}Source: packages/engine/src/runtime/render/quality.ts
FeelAudio
class FeelAudio {
constructor(opts?: FeelAudioOptions);
muted: boolean;
played: number;
readonly gate: CueGate;
unlock(): void;
whenUnlocked(fn: (ctx: AudioContext) => void): void;
get context(): AudioContext | null;
unlockOnGesture(target?: EventTarget): void;
get ready(): boolean;
get master(): number;
define(name: string, recipe: SynthRecipe, opts?: CueOptions): void;
addBuffer(name: string, source: AudioBuffer | string, opts?: CueOptions & { readonly gain?: number; }): Promise<void>;
has(name: string): boolean;
play(name: string, opts?: PlayOptions): boolean;
impact(damage: number, opts?: PlayOptions): boolean;
}Source: packages/engine/src/runtime/feel/audio.ts
FeelClock
class FeelClock {
constructor(opts?: FeelClockOptions);
stops: number;
slows: number;
hitStop(ms: number, realNow?: number): void;
slowMo(scale: number, ms: number, easeMs?: number, realNow?: number): void;
tick(realNow?: number): ClockTick;
get stopped(): boolean;
get lagMs(): number;
}Source: packages/engine/src/runtime/feel/clock.ts
FeelKit
class FeelKit {
constructor(opts?: FeelKitOptions);
readonly preset: FeelPreset;
readonly clock: FeelClock;
readonly flash: HitFlash;
readonly knock: KnockbackOffsets;
readonly trauma: Trauma;
readonly tweens: Tweens;
readonly numbers: DamageNumbers | null;
readonly audio: FeelAudio | null;
readonly rumble: Rumble | null;
readonly footsteps: Footsteps | null;
particles: ParticleSink | null;
hurtPulse: number;
readonly counts: { hits: number; kills: number; bigKills: number; hurts: number; levelUps: number; lands: number; dashes: number; };
camera: TraumaTarget;
project: Projector | undefined;
tick(realNow?: number): ClockTick;
hit(e: HitEvent): void;
kill(e: KillEvent): void;
hurt(amount: number, maxHealth?: number): void;
levelUp(): void;
land(intensity?: number): void;
dash(): void;
footstep(speed: number, grounded?: boolean, surface?: Surface): void;
update(dt: number, realDt?: number): void;
}Source: packages/engine/src/runtime/feel/kit.ts
Footsteps
Footstep cadence from speed: steps per second = speed / stride, with an
alternating left/right pitch. Calls play(pitch, gain) on each step.
class Footsteps {
constructor(play: (pitch: number, gain: number) => void, opts?: FootstepOptions);
surface: "grass" | "stone" | "dirt" | "wood" | "metal";
steps: number;
update(dt: number, speed: number, grounded?: boolean): number;
}Source: packages/engine/src/runtime/feel/audio.ts
FrameStats
Rolling frame-time statistics (ms) over the last size frames.
class FrameStats {
constructor(size?: number);
push(ms: number): void;
get count(): number;
mean(): number;
percentile(q: number): number;
}Source: packages/engine/src/runtime/stats.ts
GpuParticles
Pooled GPU particles: one draw for every additive particle on screen (and one for alpha-blended smoke and dust). The CPU writes only the spawn slots of a burst; the vertex stage computes motion (velocity, drag, gravity, a floor clamp), billboarding, velocity stretch, size and fade.
class GpuParticles {
constructor(parent: Object3D, opts?: GpuParticlesOptions);
readonly time: UniformNode<"float", number>;
bursts: number;
get meshes(): Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>[];
burst(preset: string, x: number, y: number, z: number, opts?: ParticleBurstOptions): void;
emit(preset: string, x: number, y: number, z: number, rate: number, dt: number, opts?: ParticleBurstOptions): void;
update(timeSeconds: number): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/particles.ts
GroundDecals
Ground decals (scorch marks, splats, rings) in one draw: flat quads on the floor, shapes drawn procedurally in the fragment stage (no textures), faded over their life. A ring buffer: the oldest decal is reused.
class GroundDecals {
constructor(parent: Object3D, capacity?: number, random?: () => number, look?: DecalLook);
readonly time: UniformNode<"float", number>;
readonly ring: ParticleRing;
readonly mesh: Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>;
floorY: number;
add(kind: DecalKind, x: number, z: number, opts?: DecalOptions): void;
update(timeSeconds: number): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/decals.ts
GroundRings
Expanding shockwave rings on the floor (nova blasts, landings, dash starts): one additive draw, pooled. Generalized from EMBERWATCH's rings.
class GroundRings {
constructor(parent: Object3D, capacity?: number, look?: RingLook);
readonly time: UniformNode<"float", number>;
readonly ring: ParticleRing;
readonly mesh: Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>;
fired: number;
fire(x: number, z: number, radius: number, opts?: RingOptions): void;
update(timeSeconds: number): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/decals.ts
HeroHighlight
class HeroHighlight {
constructor(root: Object3D, opts?: HeroHighlightOptions);
readonly parts: Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>[];
dispose(): void;
}Source: packages/engine/src/runtime/render/highlight.ts
HitFlash
Hit flash: per-entity timers that read as 0..1 intensity, for instanced crowds that tint an instance toward white (or any colour) on a hit.
class HitFlash {
constructor(seconds?: number);
count: number;
trigger(id: number, strength?: number): void;
value(id: number): number;
update(dt: number): void;
get size(): number;
clear(): void;
}Source: packages/engine/src/runtime/feel/flash.ts
InputController
Keyboard + mouse (pointer lock) and touch (nipplejs virtual stick on the
left half, drag-to-look and action buttons on the right). sample()
produces one sequence-numbered InputCommand per fixed tick.
class InputController {
constructor(element: HTMLElement, look: LookTarget, opts?: InputOptions);
readonly touch: boolean;
sample(tick: number): InputCommand;
dispose(): void;
}Source: packages/engine/src/runtime/input.ts
InstancedCrowd
One InstancedMesh per entity kind: 2,000 enemies are one draw call (spec). Each frame writes interpolated matrices straight into the instance buffer (rotation about y only; no per-instance Object3D).
class InstancedCrowd {
constructor(geometry: BufferGeometry, material: Material, capacity: number, kind: number, scale?: number);
readonly mesh: InstancedMesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>;
update(view: RenderView, alpha: number): number;
dispose(): void;
}Source: packages/engine/src/runtime/crowd.ts
KnockbackOffsets
class KnockbackOffsets {
constructor(opts?: KnockbackOptions);
kicks: number;
kick(id: number, dirX: number, dirZ: number, strength?: number): void;
get(id: number): Readonly<KnockbackSample>;
update(dt: number): void;
get size(): number;
clear(): void;
}Source: packages/engine/src/runtime/feel/knockback.ts
LightingRig
Hemisphere + one directional light whose single shadow map follows a focus point (the player), snapped to texels. Sized for a top-down or third-person view: one tuned map beats cascades at this camera distance.
class LightingRig {
constructor(renderer: WebGPURenderer, scene: Scene, opts?: LightingOptions);
readonly root: Object3D<Object3DEventMap>;
readonly hemi: HemisphereLight;
readonly sun: DirectionalLight;
readonly ambient: AmbientLight;
get texel(): number;
get shadowsOn(): boolean;
setShadowMapSize(size: number): void;
setShadowExtent(extent: number): void;
follow(x: number, y: number, z: number): void;
setPreset(preset: LookPreset, overrides?: Partial<LightingPreset>): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/lighting.ts
NumberStack
class NumberStack {
constructor(capacity?: number, opts?: NumberStackOptions);
readonly slots: NumberSlot[];
shown: number;
merged: number;
add(nowMs: number, n: NumberInput): { index: number; merged: boolean; };
update(dt: number): void;
draw(s: NumberSlot): NumberDraw;
get active(): number;
}Source: packages/engine/src/runtime/feel/numbers.ts
ParticleRing
A ring of capacity particle slots. Allocation never iterates live
particles: the oldest slot is simply overwritten. Records which slot
ranges changed since the last flush so only those bytes are uploaded.
class ParticleRing {
constructor(capacity: number);
head: number;
written: number;
alloc(n: number): number[];
flush(): [number, number][];
}Source: packages/engine/src/runtime/render/particles.ts
PostFX
The post stack: scene pass (HDR) -> bloom -> optional depth outline -> color grade (exposure, contrast, saturation, split tone, vignette, hurt pulse) -> tone mapping and sRGB (once, via renderOutput) -> FXAA.
Tone mapping is the renderer's (renderer.toneMapping), so the same
curve applies whether post is on (here, in renderOutput) or off
(renderer.render to the canvas). Every knob is a uniform.
class PostFX {
constructor(renderer: WebGPURenderer, scene: Scene, camera: Camera, opts?: PostFXOptions);
readonly pipeline: RenderPipeline;
readonly exposure: UniformNode<"float", number>;
readonly contrast: UniformNode<"float", number>;
readonly saturation: UniformNode<"float", number>;
readonly shadowTint: UniformNode<"vec3", Vector3>;
readonly highlightTint: UniformNode<"vec3", Vector3>;
readonly vignette: UniformNode<"float", number>;
readonly hurt: UniformNode<"float", number>;
readonly outlineColor: UniformNode<"color", Color>;
readonly outlineThickness: UniformNode<"float", number>;
readonly outlineThreshold: UniformNode<"float", number>;
readonly outlineStrength: UniformNode<"float", number>;
enabled: boolean;
get bloom(): BloomNode | null;
setPreset(preset: LookPreset, overrides?: Partial<GradePreset>): void;
configure(o: { bloom?: boolean; outline?: boolean; fxaa?: boolean; bloomScale?: number; enabled?: boolean; }): void;
setQuality(tier: QualityTier, outlineWanted?: boolean): void;
get stages(): { enabled: boolean; bloom: boolean; outline: boolean; fxaa: boolean; };
setStyle(style: StylePost | null): void;
setSize(width: number, height: number): void;
render(): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/post.ts
QualityManager
Holds the tier and the dynamic resolution for one renderer. Listeners
(lighting, post, particles) re-read settings on onChange.
class QualityManager {
constructor(target: QualityTarget, tier: QualityTier, opts?: { devicePixelRatio?: number; dynamic?: boolean; budgetMs?: number; });
settings: QualitySettings;
readonly dynamic: DynamicResolution;
enabled: boolean;
get tier(): QualityTier;
get pixelRatio(): number;
onChange(fn: (s: QualitySettings) => void): void;
setTier(tier: QualityTier): void;
frame(now: number): boolean;
}Source: packages/engine/src/runtime/render/quality.ts
RenderClock
class RenderClock {
constructor(opts?: FeelClockOptions);
stops: number;
slows: number;
hitStop(ms: number, realNow?: number): void;
slowMo(scale: number, ms: number, easeMs?: number, realNow?: number): void;
tick(realNow?: number): ClockTick;
get stopped(): boolean;
get lagMs(): number;
}Source: packages/engine/src/runtime/feel/clock.ts
Rumble
class Rumble {
constructor(opts?: RumbleOptions);
enabled: boolean;
pulses: number;
pulse(strong: number, weak?: number, ms?: number): boolean;
}Source: packages/engine/src/runtime/feel/rumble.ts
SoundPlayer
class SoundPlayer {
constructor(audio: FeelAudio, opts?: SoundPlayerOptions);
readonly loaded: { cues: number; failed: number; music: boolean; };
load(bank: SoundBank): void;
unlockOnGesture(target?: EventTarget): void;
get muted(): boolean;
toggle(): boolean;
get musicEnabled(): boolean;
get musicPlaying(): boolean;
get current(): SoundBank | null;
dispose(): void;
}Source: packages/engine/src/runtime/feel/sound.ts
Spring
class Spring {
constructor(value?: number, opts?: SpringOptions);
value: number;
velocity: number;
target: number;
frequency: number;
damping: number;
kick(velocity: number): void;
snap(value: number): void;
step(dt: number): number;
settled(eps?: number): boolean;
}Source: packages/engine/src/runtime/feel/spring.ts
Spring3
Three springs sharing settings (a position or offset).
class Spring3 {
constructor(x?: number, y?: number, z?: number, opts?: SpringOptions);
readonly x: Spring;
readonly y: Spring;
readonly z: Spring;
setTarget(x: number, y: number, z: number): void;
snap(x: number, y: number, z: number): void;
step(dt: number): void;
}Source: packages/engine/src/runtime/feel/spring.ts
SystemScheduler
Runs the declared systems' schedules against a host, one fixed tick at a time. Timers are tick-based (seconds are rounded to whole ticks at declaration), so the schedule is identical on the server and in client prediction. Timers fire in declaration order within a tick.
class SystemScheduler {
constructor(manifest: GameManifest, host: SystemHost);
start(): void;
dispatch(event: string, players: readonly number[]): void;
tick(): void;
}Source: packages/engine/src/api/scheduler.ts
Trauma
Trauma screen shake: hits add trauma 0..1, it decays linearly, and the shake is trauma squared, so small hits barely move the camera and big ones kick hard. Offsets come from smooth seeded noise, so the shake is fluid rather than jittery and never uses Math.random.
class Trauma {
constructor(opts?: TraumaOptions);
value: number;
x: number;
y: number;
roll: number;
adds: number;
get options(): Readonly<Required<TraumaOptions>>;
add(amount: number): void;
addTrauma(amount: number): void;
sustain(seconds: number): void;
get shake(): number;
update(dt: number): void;
reset(): void;
traumaFor(amplitude: number): number;
}Source: packages/engine/src/runtime/feel/trauma.ts
Tweens
class Tweens {
constructor();
to<T extends object>(target: T, props: TweenProps<T>, opts: TweenOptions): number;
cancel(handleOrTarget: number | object): void;
get active(): number;
tick(dt: number): void;
}Source: packages/engine/src/runtime/feel/tween.ts
VatCrowd
Thousands of animated characters in one draw: every instance samples the VAT at its own clip, phase and rate, then is rotated, scaled and placed from per-instance attributes. CPU work per instance is one 12-float write.
class VatCrowd {
constructor(vat: VertexAnimation, material: Material & { positionNode: Node | null; normalNode: Node | null; emissiveNode?: Node | null; flatShading?: boolean; }, capacity: number, opts?: VatCrowdOptions);
readonly mesh: Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>;
readonly time: UniformNode<"float", number>;
count: number;
clipNamed(name: string): VatClip | undefined;
begin(): void;
push(x: number, y: number, z: number, yaw: number, opts?: { clip?: string; phase?: number; rate?: number; scale?: number; flash?: number; }): void;
end(timeSeconds: number): void;
addTo(parent: Object3D): this;
dispose(): void;
}Source: packages/engine/src/runtime/render/vat.ts
Constants
DEFAULT_CUES
The built-in cues every template can use by name.
const DEFAULT_CUES: Readonly<Record<string, SynthRecipe & CueOptions>>;Source: packages/engine/src/runtime/feel/audio.ts
DEFAULT_LOCOMOTION
const DEFAULT_LOCOMOTION: LocomotionThresholds;Source: packages/engine/src/runtime/render/animation.ts
Ease
const Ease: { readonly linear: (t: number) => number; readonly quadIn: (t: number) => number; readonly quadOut: (t: number) => number; readonly quadInOut: (t: number) => number; readonly cubicOut: (t: number) => number; readonly cubicInOut: (t: number) => number; readonly sineInOut: (t: number) => number; readonly expoOut: (t: number) => number; readonly backOut: (t: number) => number; readonly elasticOut: (t: number) => number; readonly bounceOut: (t: number) => number; };Source: packages/engine/src/runtime/feel/tween.ts
FEEL_PRESETS
const FEEL_PRESETS: Readonly<Record<FeelPresetName, FeelPreset>>;Source: packages/engine/src/runtime/feel/kit.ts
LOOK_PRESETS
const LOOK_PRESETS: readonly LookPreset[];Source: packages/engine/src/runtime/render/presets.ts
PARTICLE_PRESETS
const PARTICLE_PRESETS: Readonly<Record<ParticlePresetName, ParticlePreset>>;Source: packages/engine/src/runtime/render/particles.ts
PIXEL_PALETTE
The pixel style's palette (DawnBringer 16). The asset library's manifest/pixel.json carries the same list; its test keeps them equal.
const PIXEL_PALETTE: readonly string[];Source: packages/engine/src/runtime/styles/pixel/index.ts
QUALITY_TIERS
const QUALITY_TIERS: readonly QualityTier[];Source: packages/engine/src/runtime/render/quality.ts
SPRITE_TEXEL
Metres one source pixel covers at spriteScale 1.
const SPRITE_TEXEL: number;Source: packages/engine/src/runtime/render/sprite.ts
spriteScale
The pixel style's resize for every billboard sprite (1 elsewhere).
const spriteScale: UniformNode<"float", number>;Source: packages/engine/src/runtime/render/sprite.ts
STYLE_KITS
One entry per art style. Keep it a plain map.
const STYLE_KITS: Readonly<Record<string, StyleKit>>;Source: packages/engine/src/runtime/styles/index.ts
SURFACES
Surfaces change a footstep's pitch and weight.
const SURFACES: { readonly grass: { readonly pitch: 0.85; readonly gain: 0.8; }; readonly dirt: { readonly pitch: 0.9; readonly gain: 0.9; }; readonly stone: { readonly pitch: 1.25; readonly gain: 1; }; readonly wood: { readonly pitch: 1.05; readonly gain: 1; }; readonly metal: { readonly pitch: 1.6; readonly gain: 1.1; }; };Source: packages/engine/src/runtime/feel/audio.ts
uiTweens
The shared UI tween manager. It drives itself on requestAnimationFrame in a browser; call uiTweens.tick(dt) elsewhere.
const uiTweens: Tweens;Source: packages/engine/src/runtime/feel/tween.ts
Types
AnimatedCharacterOptions
interface AnimatedCharacterOptions {
readonly clips?: Partial<Record<LocomotionState, string>>;
readonly thresholds?: Partial<LocomotionThresholds>;
readonly walkSpeed?: number;
readonly runSpeed?: number;
readonly fade?: number;
}Source: packages/engine/src/runtime/render/animation.ts
AnimationPlayOptions
interface PlayOptions {
readonly fade?: number;
readonly loop?: "repeat" | "once";
readonly timeScale?: number;
}Source: packages/engine/src/runtime/render/animation.ts
ArenaOptions
interface ArenaOptions {
readonly sim?: SimConfig;
readonly forceWebGL?: boolean;
readonly onStats?: (s: ArenaStats) => void;
readonly frameBudgetMs?: number;
readonly autopilot?: boolean;
}Source: packages/engine/src/runtime/arena.ts
ArenaStats
interface ArenaStats {
readonly backend: Backend;
readonly fps: number;
readonly frameMs: { readonly mean: number; readonly p50: number; readonly p95: number; readonly p99: number };
readonly cpuMs: { readonly mean: number; readonly p95: number };
readonly simMsPerTick: number;
readonly drawCalls: number;
readonly triangles: number;
readonly entities: number;
readonly enemies: number;
readonly frames: number;
readonly pixelRatio: number;
readonly tick: number;
readonly health: number;
readonly kills: number;
}Source: packages/engine/src/runtime/arena.ts
AssetLoaderOptions
interface AssetLoaderOptions {
readonly resolve: (id: string) => string;
readonly transcoderPath: string;
}Source: packages/engine/src/runtime/assets.ts
AtmosphereOptions
interface AtmosphereOptions {
readonly preset?: LookPreset;
readonly overrides?: Partial<AtmospherePreset>;
readonly sky?: boolean;
}Source: packages/engine/src/runtime/render/atmosphere.ts
AtmospherePreset
interface AtmospherePreset {
readonly fog: number;
readonly skyTop: number;
readonly mode: "linear" | "exp2";
readonly near: number;
readonly far: number;
readonly density: number;
readonly heightFog: number;
readonly heightFogTop: number;
}Source: packages/engine/src/runtime/render/presets.ts
Backend
type Backend = "webgpu" | "webgl2";Source: packages/engine/src/runtime/renderer.ts
BakeOptions
interface BakeOptions {
readonly fps?: number;
readonly frames?: number;
readonly normals?: boolean;
readonly maxWidth?: number;
}Source: packages/engine/src/runtime/render/vat.ts
CameraRigOptions
interface CameraRigOptions {
readonly distance?: number;
readonly height?: number;
readonly minPitch?: number;
readonly maxPitch?: number;
readonly follow?: number;
readonly lead?: number;
readonly leadMax?: number;
readonly leadSmoothing?: number;
readonly deadZone?: number;
readonly fov?: number;
readonly shake?: TraumaOptions;
readonly punchFrequency?: number;
readonly punchDamping?: number;
readonly bounds?: GroundBounds | null;
readonly groundY?: number;
}Source: packages/engine/src/runtime/camera.ts
ClockTick
interface ClockTick {
readonly now: number;
readonly dt: number;
readonly realDt: number;
readonly timeScale: number;
}Source: packages/engine/src/runtime/feel/clock.ts
CrowdAttributes
The per-instance attributes a crowd-motion material reads.
interface CrowdAttributes {
readonly xform: InstancedBufferAttribute;
readonly anim: InstancedBufferAttribute;
readonly extra: InstancedBufferAttribute;
}Source: packages/engine/src/runtime/render/crowd-motion.ts
CrowdMotionOptions
interface CrowdMotionOptions {
readonly bob?: number;
readonly waddle?: number;
readonly lean?: number;
readonly squash?: number;
readonly cadence?: readonly [number, number];
readonly fullSpeed?: number;
readonly breathe?: number;
readonly flash?: number;
readonly billboard?: boolean;
}Source: packages/engine/src/runtime/render/crowd-motion.ts
CueOptions
interface CueOptions {
readonly minGapMs?: number;
readonly pitchVar?: number;
readonly gainVar?: number;
readonly voices?: number;
}Source: packages/engine/src/runtime/feel/audio.ts
DamageNumbersOptions
interface DamageNumbersOptions extends NumberStackOptions {
readonly capacity?: number;
readonly className?: string;
readonly colors?: Readonly<Record<string, string>>;
readonly format?: (amount: number) => string;
}Source: packages/engine/src/runtime/feel/numbers.ts
DecalKind
type DecalKind = "scorch" | "splat" | "ring";Source: packages/engine/src/runtime/render/decals.ts
DecalLook
type DecalLook = (n: DecalLookInput) => LookOutput;Source: packages/engine/src/runtime/styles/kit.ts
DecalLookInput
What a ground decal's look can read (GroundDecals).
interface DecalLookInput {
readonly uv: Node<"vec2">;
readonly r: Node<"float">;
readonly angle: Node<"float">;
readonly kind: Node<"float">;
readonly t: Node<"float">;
readonly color: Node<"vec3">;
readonly shape: Node<"float">;
readonly opacity: Node<"float">;
}Source: packages/engine/src/runtime/styles/kit.ts
DecalOptions
interface DecalOptions {
size?: number;
color?: number;
life?: number;
opacity?: number;
rotation?: number;
glow?: number;
}Source: packages/engine/src/runtime/render/decals.ts
DeviceHints
What the browser tells us about the device. Every field optional: missing reads as "unknown".
interface DeviceHints {
readonly userAgent?: string;
readonly coarsePointer?: boolean;
readonly hardwareConcurrency?: number;
readonly deviceMemory?: number;
readonly devicePixelRatio?: number;
readonly backend?: "webgpu" | "webgl2";
readonly screenWidth?: number;
}Source: packages/engine/src/runtime/render/quality.ts
DynamicResolutionOptions
interface DynamicResolutionOptions {
readonly budgetMs?: number;
readonly overFactor?: number;
readonly underFactor?: number;
readonly step?: number;
readonly min?: number;
readonly max?: number;
readonly hysteresisMs?: number;
readonly minSamples?: number;
readonly window?: number;
}Source: packages/engine/src/runtime/render/quality.ts
EaseFn
Juicy UI tweens: a tiny tween manager with an easing table, and DOM
helpers (pop, shake, count up) built on it. The helpers use the CSS
scale and translate properties, so they never fight a transform the
page already sets.
type EaseFn = (t: number) => number;Source: packages/engine/src/runtime/feel/tween.ts
EaseName
type EaseName = keyof typeof Ease;Source: packages/engine/src/runtime/feel/tween.ts
FeelAudioOptions
interface FeelAudioOptions {
readonly master?: number;
readonly voices?: number;
readonly refDistance?: number;
readonly maxDistance?: number;
readonly context?: () => AudioContext;
readonly now?: () => number;
readonly seed?: number;
}Source: packages/engine/src/runtime/feel/audio.ts
FeelClockOptions
The render clock: hit-stop and slow motion for the DRAWN world only.
The netcode never pauses; the clock returns a render time now that
runs behind real time while frozen or slowed, then catches up smoothly so
the world never jumps. now never runs ahead of real time.
interface FeelClockOptions {
readonly catchUpMs?: number;
readonly maxLagMs?: number;
readonly maxFrameMs?: number;
}Source: packages/engine/src/runtime/feel/clock.ts
FeelElement
A minimal element: anything with a style and text (real elements, or fakes in tests).
interface FeelElement {
readonly style: { scale: string; translate: string };
textContent: string | null;
}Source: packages/engine/src/runtime/feel/tween.ts
FeelKitOptions
interface FeelKitOptions {
readonly preset?: FeelPresetName | (Partial<FeelPreset> & { readonly base?: FeelPresetName });
readonly camera?: TraumaTarget;
readonly particles?: ParticleSink | null;
readonly project?: Projector;
readonly screenWidth?: () => number;
readonly numbers?: DamageNumbers | HTMLElement | null;
readonly audio?: FeelAudio | null;
readonly rumble?: Rumble | null;
readonly clock?: FeelClock;
}Source: packages/engine/src/runtime/feel/kit.ts
FeelPreset
Tunables for every one-liner. Pick a named preset or override fields.
interface FeelPreset {
readonly hitTrauma: number;
readonly hitTraumaPerFrame: number;
readonly killTrauma: number;
readonly bigKillTrauma: number;
readonly hurtTrauma: number;
readonly bigKillStopMs: number;
readonly hurtStopMs: number;
readonly levelUpStopMs: number;
readonly knockback: number;
readonly bigKnockback: number;
readonly flashSeconds: number;
readonly bigKillPunch: number;
readonly hurtPunch: number;
readonly levelUpPunch: number;
readonly dashPunch: number;
readonly landTrauma: number;
readonly hurtRumble: readonly [number, number, number];
readonly bigKillRumble: readonly [number, number, number];
readonly landRumble: readonly [number, number, number];
readonly killParticles: number;
readonly bigKillParticles: number;
readonly numbersPerFrame: number;
}Source: packages/engine/src/runtime/feel/kit.ts
FeelPresetName
type FeelPresetName = "subtle" | "default" | "heavy";Source: packages/engine/src/runtime/feel/kit.ts
FieldSpec
The play field: a square of half size half m with a wall wallHeight tall, and outside m of dressed ground past it.
interface FieldSpec {
readonly half: number;
readonly wallHeight: number;
readonly outside: number;
readonly theme: WorldTheme;
readonly wall?: boolean;
readonly pillars?: readonly PillarSpec[];
}Source: packages/engine/src/runtime/styles/kit.ts
FootstepOptions
interface FootstepOptions {
readonly stride?: number;
readonly maxRate?: number;
readonly minSpeed?: number;
}Source: packages/engine/src/runtime/feel/audio.ts
GamepadLike
interface GamepadLike {
readonly connected?: boolean;
readonly vibrationActuator?: RumbleActuator | null;
}Source: packages/engine/src/runtime/feel/rumble.ts
GpuBurstOptions
The feel kit's burst options plus the renderer's extras (all optional).
interface ParticleBurstOptions extends FeelBurstOptions {
readonly dirY?: number;
readonly speed?: number;
readonly spread?: number;
readonly size?: number;
}Source: packages/engine/src/runtime/render/particles.ts
GpuParticlesOptions
interface GpuParticlesOptions {
readonly capacity?: number;
readonly random?: () => number;
readonly look?: ParticleShade;
}Source: packages/engine/src/runtime/render/particles.ts
GradePreset
interface GradePreset {
readonly exposure: number;
readonly contrast: number;
readonly saturation: number;
readonly shadowTint: readonly [number, number, number];
readonly highlightTint: readonly [number, number, number];
readonly vignette: number;
readonly bloomStrength: number;
readonly bloomRadius: number;
readonly bloomThreshold: number;
readonly toneMapping: "aces" | "agx" | "neutral";
}Source: packages/engine/src/runtime/render/presets.ts
GroundBounds
A rectangle on the ground plane.
interface GroundBounds {
readonly minX: number;
readonly maxX: number;
readonly minZ: number;
readonly maxZ: number;
}Source: packages/engine/src/runtime/camera.ts
HeroHighlightOptions
interface HeroHighlightOptions {
readonly rim?: ColorRepresentation | null;
readonly rimStrength?: number;
readonly rimPower?: number;
readonly outline?: ColorRepresentation | null;
readonly outlineWidth?: number;
}Source: packages/engine/src/runtime/render/highlight.ts
HitEvent
interface HitEvent {
readonly x: number;
readonly y: number;
readonly z: number;
readonly amount: number;
readonly id?: number;
readonly big?: boolean;
readonly dirX?: number;
readonly dirZ?: number;
readonly kind?: string;
}Source: packages/engine/src/runtime/feel/kit.ts
InputOptions
interface InputOptions {
readonly mouseSensitivity?: number;
readonly touchSensitivity?: number;
readonly touch?: boolean;
}Source: packages/engine/src/runtime/input.ts
KillEvent
interface KillEvent {
readonly x: number;
readonly y: number;
readonly z: number;
readonly big?: boolean;
readonly id?: number;
readonly color?: number;
readonly particles?: string;
readonly dirX?: number;
readonly dirZ?: number;
}Source: packages/engine/src/runtime/feel/kit.ts
KnockbackOptions
Client-side visual knockback and squash per entity. The authoritative
sim moves the entity; this adds a springy offset and a squash-stretch on
top of the interpolated position, so a hit reads instantly even ~100 ms
in the past. Read get(id) each frame and add it when drawing.
interface KnockbackOptions {
readonly frequency?: number;
readonly damping?: number;
readonly maxOffset?: number;
readonly squash?: number;
}Source: packages/engine/src/runtime/feel/knockback.ts
KnockbackSample
interface KnockbackSample {
x: number;
z: number;
sx: number;
sy: number;
sz: number;
}Source: packages/engine/src/runtime/feel/knockback.ts
LightingOptions
interface LightingOptions {
readonly preset?: LookPreset;
readonly overrides?: Partial<LightingPreset>;
readonly shadowMapSize?: number;
readonly shadowExtent?: number;
}Source: packages/engine/src/runtime/render/lighting.ts
LightingPreset
interface LightingPreset {
readonly sky: number;
readonly ground: number;
readonly hemi: number;
readonly sun: number;
readonly sunIntensity: number;
readonly sunDir: readonly [number, number, number];
readonly ambient: number;
readonly ambientColor: number;
readonly shadowStrength: number;
}Source: packages/engine/src/runtime/render/presets.ts
LocomotionState
type LocomotionState = "idle" | "walk" | "run";Source: packages/engine/src/runtime/render/animation.ts
LocomotionThresholds
interface LocomotionThresholds {
readonly walk: number;
readonly run: number;
readonly band: number;
}Source: packages/engine/src/runtime/render/animation.ts
Look
interface Look {
readonly lighting: LightingPreset;
readonly atmosphere: AtmospherePreset;
readonly grade: GradePreset;
}Source: packages/engine/src/runtime/render/presets.ts
LookOutput
A decal or ring look's answer: colour and opacity nodes, and the blend to draw with.
interface LookOutput {
readonly color: Node<"vec3">;
readonly opacity: Node<"float">;
readonly blending?: "add" | "normal";
}Source: packages/engine/src/runtime/styles/kit.ts
LookPreset
Look presets: one name picks the lighting, the atmosphere and the color
grade together, so a template (or a generated game) says preset: "dusk"
and gets a coherent picture. Plain data, node-testable.
type LookPreset = "night" | "dusk" | "day" | "studio";Source: packages/engine/src/runtime/render/presets.ts
LookTarget
interface LookTarget {
look(dYaw: number, dPitch: number): void;
readonly yaw: number;
}Source: packages/engine/src/runtime/input.ts
MusicElement
The slice of HTMLAudioElement the music uses.
interface MusicElement {
src: string;
loop: boolean;
volume: number;
muted: boolean;
preload: string;
readonly paused: boolean;
play(): Promise<void> | void;
pause(): void;
}Source: packages/engine/src/runtime/feel/sound.ts
NavigatorLike
interface NavigatorLike {
getGamepads?(): readonly (GamepadLike | null)[];
vibrate?(pattern: number | number[]): boolean;
}Source: packages/engine/src/runtime/feel/rumble.ts
NumberDraw
interface NumberDraw {
readonly x: number;
readonly y: number;
readonly scale: number;
readonly opacity: number;
}Source: packages/engine/src/runtime/feel/numbers.ts
NumberInput
Floating damage numbers. NumberStack is the DOM-free core (slots,
merging, motion); DamageNumbers draws it with a fixed pool of DOM nodes
moved by transforms only (no layout per frame).
interface NumberInput {
readonly x: number;
readonly y: number;
readonly amount: number;
readonly id?: number;
readonly big?: boolean;
readonly kind?: string;
}Source: packages/engine/src/runtime/feel/numbers.ts
NumberSlot
interface NumberSlot {
active: boolean;
id: number;
amount: number;
t: number;
x: number;
y: number;
drift: number;
big: boolean;
kind: string;
at: number;
gen: number;
}Source: packages/engine/src/runtime/feel/numbers.ts
NumberStackOptions
interface NumberStackOptions {
readonly mergeMs?: number;
readonly lifeSeconds?: number;
readonly rise?: number;
}Source: packages/engine/src/runtime/feel/numbers.ts
ParticleBurstOptions
interface ParticleBurstOptions {
readonly count?: number;
readonly color?: number;
readonly scale?: number;
readonly dirX?: number;
readonly dirZ?: number;
}Source: packages/engine/src/runtime/feel/types.ts
ParticlePreset
interface ParticlePreset {
readonly blend: "add" | "alpha";
readonly count: number;
readonly speed: readonly [number, number];
readonly spread: number;
readonly dir: readonly [number, number, number];
readonly life: readonly [number, number];
readonly size: readonly [number, number];
readonly gravity: number;
readonly drag: number;
readonly color: number;
readonly stretch: number;
readonly jitter: number;
}Source: packages/engine/src/runtime/render/particles.ts
ParticlePresetName
type ParticlePresetName = "sparks" | "burst" | "embers" | "smoke" | "hitSpark" | "dust" | "magic" | "kill" | "bigKill";Source: packages/engine/src/runtime/render/particles.ts
ParticleShade
A particle look: every particle's shape and colour, plus an optional size curve over its life (a pop, a shrink). The default is soft round glows; an art style brings its own (the toon style draws stars, streaks and puffs).
interface ParticleShade {
shade(p: ParticleShadeInput): ParticleShadeOutput;
size?(t: Node<"float">, seed: Node<"float">, blend: "add" | "alpha"): Node<"float">;
}Source: packages/engine/src/runtime/render/particles.ts
ParticleShadeInput
What a particle look (an art style's) reads, per fragment.
interface ParticleShadeInput {
readonly t: Node<"float">;
readonly uv: Node<"vec2">;
readonly color: Node<"vec3">;
readonly seed: Node<"float">;
readonly blend: "add" | "alpha";
}Source: packages/engine/src/runtime/render/particles.ts
ParticleShadeOutput
interface ParticleShadeOutput {
readonly color: Node<"vec3">;
readonly opacity: Node<"float">;
readonly blend?: "add" | "alpha";
}Source: packages/engine/src/runtime/render/particles.ts
ParticleSink
Something that can play a pooled particle effect (the GPU particle system implements it).
interface ParticleSink {
burst(preset: string, x: number, y: number, z: number, opts?: ParticleBurstOptions): void;
}Source: packages/engine/src/runtime/feel/types.ts
PillarSpec
One pillar or post (sim metres).
interface PillarSpec {
readonly x: number;
readonly z: number;
readonly radius: number;
readonly height: number;
}Source: packages/engine/src/runtime/styles/kit.ts
PixelStyleOptions
interface PixelStyleOptions {
readonly texelsPerMetre?: number;
readonly dither?: number;
readonly saturation?: number;
readonly bands?: readonly number[];
readonly minRows?: number;
}Source: packages/engine/src/runtime/styles/pixel/index.ts
PlayOptions
interface PlayOptions {
readonly pitch?: number;
readonly gain?: number;
readonly pan?: number;
readonly screenX?: number;
readonly width?: number;
readonly distance?: number;
}Source: packages/engine/src/runtime/feel/audio.ts
PostFXOptions
interface PostFXOptions {
readonly preset?: LookPreset;
readonly overrides?: Partial<GradePreset>;
readonly bloom?: boolean;
readonly outline?: boolean;
readonly fxaa?: boolean;
readonly enabled?: boolean;
readonly bloomScale?: number;
readonly style?: StylePost;
}Source: packages/engine/src/runtime/render/post.ts
Projector
World position to CSS pixels on the canvas.
type Projector = (x: number, y: number, z: number) => { x: number; y: number; onScreen: boolean };Source: packages/engine/src/runtime/feel/types.ts
QualitySettings
What a tier turns on.
interface QualitySettings {
readonly tier: QualityTier;
readonly shadowMapSize: number;
readonly post: boolean;
readonly bloomScale: number;
readonly outline: boolean;
readonly maxPixelRatio: number;
readonly minPixelRatio: number;
readonly particles: number;
}Source: packages/engine/src/runtime/render/quality.ts
QualityTier
Quality tiers and dynamic resolution ("auto-detected
low, medium or high (shadows, post-processing, resolution scale) with
dynamic resolution to hold the frame rate"). The decision logic is pure
so it is tested in node; QualityManager applies it to a renderer.
type QualityTier = "low" | "medium" | "high";Source: packages/engine/src/runtime/render/quality.ts
RendererHandle
interface RendererHandle {
readonly renderer: WebGPURenderer;
readonly backend: Backend;
}Source: packages/engine/src/runtime/renderer.ts
RendererOptions
interface RendererOptions {
readonly forceWebGL?: boolean;
readonly antialias?: boolean;
readonly maxPixelRatio?: number;
}Source: packages/engine/src/runtime/renderer.ts
RenderStack
interface RenderStack {
readonly lighting: LightingRig;
readonly atmosphere: Atmosphere;
readonly post: PostFX;
readonly particles: GpuParticles;
readonly decals: GroundDecals;
readonly rings: GroundRings;
readonly quality: QualityManager;
readonly style: string | null;
readonly kit: StyleKit | null;
readonly session: StyleSession | null;
readonly time: number;
frame(dt: number, focus: { x: number; y: number; z: number }, realNowMs?: number): boolean;
resize(width: number, height: number): void;
setPreset(preset: LookPreset): void;
setQuality(tier: QualityTier): void;
dispose(): void;
}Source: packages/engine/src/runtime/render/stack.ts
RenderStackOptions
interface RenderStackOptions {
readonly preset?: LookPreset;
readonly style?: string;
readonly quality?: QualityTier | "auto";
readonly bloom?: boolean;
readonly outline?: boolean;
readonly dynamicResolution?: boolean;
readonly shadowExtent?: number;
readonly lighting?: Partial<LightingPreset>;
readonly atmosphere?: Partial<AtmospherePreset>;
readonly grade?: Partial<GradePreset>;
readonly particles?: number;
readonly makeParticles?: (scene: Scene, capacity: number) => GpuParticles;
readonly decals?: number;
readonly resolve?: (id: string) => string | null;
}Source: packages/engine/src/runtime/render/stack.ts
RingLook
type RingLook = (n: RingLookInput) => LookOutput;Source: packages/engine/src/runtime/styles/kit.ts
RingLookInput
What a shockwave ring's look can read (GroundRings).
interface RingLookInput {
readonly uv: Node<"vec2">;
readonly r: Node<"float">;
readonly t: Node<"float">;
readonly alive: Node<"float">;
readonly color: Node<"vec3">;
}Source: packages/engine/src/runtime/styles/kit.ts
RingOptions
interface RingOptions {
color?: number;
duration?: number;
glow?: number;
}Source: packages/engine/src/runtime/render/decals.ts
RumbleActuator
Controller rumble (Gamepad API dual-rumble) with a phone vibration fallback, rate-limited so a swarm of hits is one buzz, not fifty.
interface RumbleActuator {
playEffect?(type: string, params: { duration: number; strongMagnitude: number; weakMagnitude: number; startDelay?: number }): Promise<unknown>;
}Source: packages/engine/src/runtime/feel/rumble.ts
RumbleOptions
interface RumbleOptions {
readonly minGapMs?: number;
readonly vibrateFallback?: boolean;
readonly navigator?: NavigatorLike;
readonly now?: () => number;
}Source: packages/engine/src/runtime/feel/rumble.ts
SegmentRig
interface SegmentRig {
readonly mesh: SkinnedMesh;
readonly bones: readonly [Bone, Bone, Bone];
readonly clips: readonly AnimationClip[];
}Source: packages/engine/src/runtime/render/rig.ts
SegmentRigOptions
interface SegmentRigOptions {
readonly height?: number;
readonly radius?: number;
readonly topRadius?: number;
readonly radialSegments?: number;
readonly heightSegments?: number;
readonly geometry?: BufferGeometry;
}Source: packages/engine/src/runtime/render/rig.ts
SoundBank
Cue name -> sample, and an optional music loop (the asset library's soundBank() builds one).
interface SoundBank {
readonly cues: Readonly<Record<string, SoundBankEntry>>;
readonly music?: SoundBankEntry | null;
}Source: packages/engine/src/runtime/feel/sound.ts
SoundBankEntry
interface SoundBankEntry {
readonly url: string;
readonly gain?: number;
}Source: packages/engine/src/runtime/feel/sound.ts
SoundPlayerOptions
interface SoundPlayerOptions {
readonly musicVolume?: number;
readonly sfxVolume?: number;
readonly music?: boolean;
readonly key?: string | null;
readonly fadeIn?: number;
readonly createMusic?: () => MusicElement | null;
readonly fetchBytes?: (url: string) => Promise<ArrayBuffer>;
readonly pauseWhenHidden?: boolean;
}Source: packages/engine/src/runtime/feel/sound.ts
SpringOptions
Damped springs for game feel: camera follow, FOV punch, knockback
offsets, UI pops. frequency is the natural frequency in Hz and
damping the damping ratio (1 = critically damped, no overshoot; below 1
it wobbles). Integrated with fixed sub-steps, so any frame rate is stable.
interface SpringOptions {
readonly frequency?: number;
readonly damping?: number;
}Source: packages/engine/src/runtime/feel/spring.ts
StyleContext
What a style's session is attached to (one renderer, one scene).
interface StyleContext {
readonly handle: RendererHandle;
readonly renderer: WebGPURenderer;
readonly scene: Scene;
readonly camera: Camera;
readonly tier: QualityTier;
readonly preset: LookPreset;
readonly post?: PostFX;
readonly atmosphere?: Atmosphere;
readonly resolve?: (id: string) => string | null;
}Source: packages/engine/src/runtime/styles/kit.ts
StyledPillar
A pillar as drawn: its body (own material, so the template can fade it), the pieces on top, and where its flame burns (null: none).
interface StyledPillar {
readonly body: Object3D;
readonly fade: readonly Material[];
readonly top: readonly Object3D[];
readonly flame: readonly [number, number, number] | null;
}Source: packages/engine/src/runtime/styles/kit.ts
StyledView
interface StyledView {
readonly session: StyleSession;
readonly post: PostFX;
render(nowMs?: number): void;
setSize(width: number, height: number): void;
dispose(): void;
}Source: packages/engine/src/runtime/styles/view.ts
StyledViewOptions
interface StyledViewOptions {
readonly preset?: LookPreset;
readonly bloom?: boolean;
readonly tier?: QualityTier;
}Source: packages/engine/src/runtime/styles/view.ts
StyleKit
interface StyleKit {
readonly id: string;
stack?(preset: LookPreset): StyleStack;
look?(preset: LookPreset): Look;
readonly needsPost?: boolean;
readonly bloom?: boolean;
readonly outline?: boolean;
attach?(ctx: StyleContext): StyleSession;
field?(spec: FieldSpec): Object3D[];
groundHeight?(spec: FieldSpec, x: number, z: number): number;
pillar?(spec: PillarSpec, theme: WorldTheme, index: number): StyledPillar;
shape?(name: StyleShapeName): StyleShape | null;
}Source: packages/engine/src/runtime/styles/kit.ts
StylePost
Post-graph hooks, in graph order: called whenever the post stack rebuilds its node graph.
interface StylePost {
scenePass?(pass: PassNode): void;
scene?(input: StylePostInput): Node<"vec4">;
color?(rgb: Node<"vec3">, pass: PassNode): Node<"vec3">;
display?(color: Node<"vec4">, input: StylePostInput): Node<"vec4">;
}Source: packages/engine/src/runtime/styles/kit.ts
StylePostInput
What the post stages can read: the scene pass, sampleable at any uv.
interface StylePostInput {
readonly color: Node<"vec4"> & { sample(uv: Node<"vec2">): Node<"vec4"> };
readonly depth: Node<"vec4"> & { sample(uv: Node<"vec2">): Node<"vec4"> };
readonly texel: UniformNode<"vec2", Vector2>;
readonly near: UniformNode<"float", number>;
readonly far: UniformNode<"float", number>;
}Source: packages/engine/src/runtime/styles/kit.ts
StyleSession
One style attached to one renderer and scene (StyleKit.attach).
interface StyleSession {
render?(draw: () => void): void;
readonly post?: StylePost;
readonly particles?: ParticleShade;
readonly decals?: DecalLook;
readonly rings?: RingLook;
frame?(seconds: number): void;
setPreset?(preset: LookPreset): void;
surface?(kind: SurfaceKind, opts?: SurfaceOptions): Texture | null;
setSize?(width: number, height: number): void;
setQuality?(tier: QualityTier): void;
dispose(): void;
}Source: packages/engine/src/runtime/styles/kit.ts
StyleShape
A shape a template draws instanced (bolts, blades, chunks, props).
interface StyleShape {
readonly geometry: BufferGeometry;
readonly material: Material;
}Source: packages/engine/src/runtime/styles/kit.ts
StyleShapeName
Template machinery shapes a style may redraw.
type StyleShapeName = "bolt" | "lance" | "blade" | "pellet" | "shard" | "chunk" | "rock" | "stump" | "barrel" | "crate" | "lantern" | "flame";Source: packages/engine/src/runtime/styles/kit.ts
StyleStack
Overrides for the render stack under one look preset, plus the style's opinion on sun shadows.
interface StyleStack extends Partial<Pick<RenderStackOptions, "lighting" | "atmosphere" | "grade" | "makeParticles">> {
readonly shadows?: boolean;
}Source: packages/engine/src/runtime/styles/kit.ts
Surface
type Surface = keyof typeof SURFACES;Source: packages/engine/src/runtime/feel/audio.ts
SurfaceKind
Surfaces templates build themselves and may ask the style for: ground (a natural field), floor (paving), wall, stone, and glow (a pool of light on the ground, white with alpha, which the template tints).
type SurfaceKind = "ground" | "floor" | "wall" | "stone" | "glow";Source: packages/engine/src/runtime/styles/kit.ts
SurfaceOptions
interface SurfaceOptions {
readonly tile?: number;
readonly mood?: string;
}Source: packages/engine/src/runtime/styles/kit.ts
SynthRecipe
interface SynthRecipe {
readonly wave: OscillatorType | "noise";
readonly f0: number;
readonly f1: number;
readonly ms: number;
readonly gain: number;
}Source: packages/engine/src/runtime/feel/audio.ts
SystemHost
What the scheduler needs from the simulation it drives.
interface SystemHost {
readonly tickRate: number;
tick(): number;
players(): readonly PlayerView[];
spawn(prefab: string, at: readonly [number, number, number], opts?: { readonly elite?: boolean }): void;
random(): number;
emit(event: string, players?: readonly number[]): void;
alive?(prefab?: string): number;
respawnDead?(): void;
end?(outcome: "won" | "lost"): void;
ringPoint?(cx: number, cz: number, radius: number, prefab: string): readonly [number, number] | null;
spawnEdge?(prefab: string, opts: SpawnEdgeOptions): number;
spawnPickup?(prefab: string, at: readonly [number, number, number]): void;
announce?(text: string, tone: "info" | "danger" | "reward"): void;
upcoming?(label: string, seconds: number): void;
bossAlive?(): boolean;
pauseDirector?(seconds: number): void;
surge?(multiplier: number, seconds: number): void;
xpBoost?(multiplier: number, seconds: number): void;
scatter?(prefab: string, count: number): number;
clear?(prefab: string): number;
onScreen?(x: number, z: number): boolean;
}Source: packages/engine/src/api/scheduler.ts
TraumaOptions
interface TraumaOptions {
readonly decay?: number;
readonly exponent?: number;
readonly maxOffset?: number;
readonly maxRoll?: number;
readonly frequency?: number;
readonly seed?: number;
}Source: packages/engine/src/runtime/feel/trauma.ts
TraumaTarget
Anything that takes trauma and an optional FOV punch: a CameraRig, or a bare Trauma.
interface TraumaTarget {
addTrauma(amount: number): void;
punch?(fovKickDegrees: number): void;
}Source: packages/engine/src/runtime/feel/types.ts
TweenOptions
interface TweenOptions {
readonly duration: number;
readonly ease?: EaseName | EaseFn;
readonly delay?: number;
readonly yoyo?: boolean;
readonly repeat?: number;
readonly onUpdate?: () => void;
readonly onDone?: () => void;
}Source: packages/engine/src/runtime/feel/tween.ts
TweenProps
type TweenProps<T> = Partial<Record<NumericKeys<T>, number>>;Source: packages/engine/src/runtime/feel/tween.ts
VatClip
interface VatClip {
readonly name: string;
readonly start: number;
readonly frames: number;
}Source: packages/engine/src/runtime/render/vat.ts
VatCrowdOptions
interface VatCrowdOptions {
readonly bakedNormals?: boolean;
}Source: packages/engine/src/runtime/render/vat.ts
VertexAnimation
A vertex animation texture: every vertex's skinned position (and normal) per frame.
interface VertexAnimation {
readonly positions: DataTexture;
readonly normals: DataTexture | null;
readonly vertexCount: number;
readonly width: number;
readonly rowsPerFrame: number;
readonly totalFrames: number;
readonly fps: number;
readonly clips: readonly VatClip[];
readonly geometry: BufferGeometry;
}Source: packages/engine/src/runtime/render/vat.ts
WorldTheme
Words a template passes so one kit can dress different places: "meadow" (EMBERWATCH's night field), "yard" (VOLTYARD's lot).
type WorldTheme = string;Source: packages/engine/src/runtime/styles/kit.ts
Other
voxel
voxel