Pipeline Spec¶
This document specifies the Noisemaker Rendering Pipeline and effect definition format. The pipeline supports declarative, multi-pass effects on WebGL 2 and WebGPU backends.
1. Core Philosophy¶
Declarative Effects: Effects are
Effectconfiguration objects that declare parameters, textures, shader programs, and passes.Ordered Execution: Expansion appends passes in DSL plan, effect-step, and definition order. The Pipeline executes that array in the same order.
Multi-Pass By Design: Effect definitions expand into explicit multi-pass schedules with direct support for layering and feedback.
Backend Agnostic: The definition format is abstract. The runtime handles WebGL 2 and WebGPU details.
GPU-Resident Intermediates: Normal pass-to-pass texture flow remains on the GPU. Explicit uploads, frame exports, and readback APIs cross the CPU/GPU boundary when requested.
Compute First: First-class support for compute shaders (native in WebGPU, emulated via GPGPU in WebGL 2).
2. Pipeline Architecture¶
The pipeline consists of three main phases:
Phase 1: Compilation (Source to Compiled Graph)¶
Compilation occurs when the DSL code changes. See Compiler Specification for the detailed specification of this phase.
Parse DSL: Generate the AST.
Analyze: Resolve namespaces and parameters into validated planned chains.
Expand Effects: Append each planned effect’s constituent passes and collect its program and texture specifications.
Scope State Textures: Effects maintain simulation state in
global_*textures, such asglobal_rd_state,global_ca_state, andglobal_accum. Expansion scopes these textures per chain, for exampleglobal_rd_state_chain_0. Instances of the same stateful effect in separate chains therefore have independent state. Expansion further scopes particle textures (global_xyz,global_vel, etc.) per pipeline to their creating node. Effects within a chain share state. Patterns such asloopBegin/loopEndrequire this sharing forglobal_accum.Resource Analysis: Determine the first and last use of each non-global virtual texture and compute a linear-scan allocation map.
Assemble: Package the ordered passes, programs, allocation map, texture specs, render surface, source, source hash, and timestamp.
Phase 2: Pipeline Initialization¶
The Pipeline initializes before execution and revisits texture allocation when dimensions change.
Backend Initialization: Initialize WebGL 2 or WebGPU.
Program Compilation: Resolve each unique program referenced by the pass list. Compile it with the selected backend.
Texture Creation: Resolve graph texture dimensions. Create ordinary textures and double-buffered global surfaces. By default the Pipeline creates textures by virtual ID. When the host passes
texturePooling: true, the Pipeline instead groups the virtual textures that share a physical slot in the compiler’s allocation map and creates one backend texture per group (see Section 7).
Phase 3: Execution (GPU Driver)¶
The Pipeline executes every frame.
Update Globals: Refresh these runtime uniforms from the implementation:
time: seconds since startdeltaTime: frame-to-frame deltaframe: integer tickresolution:vec2pixelsaspect: width ÷ height
Iterate Passes: Walk
graph.passesin compiler-produced order.Dispatch:
WebGL 2:
Activate the compiled
WebGLProgramfor the pass. Resolve the target framebuffer. Global surfaces map to the current write buffer.Derive the viewport from the target texture dimensions or the pass override. Bind the viewport before issuing work.
Bind each declared input texture to successive texture units. Upload merged uniforms from
globalUniforms+ pass uniforms throughgl.uniform*.Configure blending if the pass requests it. Issue
gl.drawArrays(gl.TRIANGLES, 0, 3)for the default full-screen triangle. WhendrawMode == 'points', issuegl.drawArrays(gl.POINTS, ...)instead.
WebGPU:
Create a command encoder at frame start. For each pass, resolve the output texture view with the current double-buffer swaps.
Reflect the program’s supported group-0 bindings. Create entries for its declared textures, selected samplers, and storage resources. Create entries for a packed struct buffer or individual uniform buffers, as applicable.
Render passes load an existing target by default and clear it only when
pass.clearis set. They then bind the pipeline/group and issue the requested draw.For a compute pass, begin the pass. Set the compute pipeline/bind group. Dispatch
passEncoder.dispatchWorkgroups(...)with explicitworkgroupsor dimensions derived from the output texture.
3. Backend Specifics¶
3.1 WebGL 2 Implementation¶
Render Passes: Standard
drawArraysinto Framebuffer Objects (FBOs).GPGPU Fallbacks: Effects that use native WebGPU compute provide separate GLSL fragment programs for WebGL. The backend remaps storage-texture or
outputBufferpasses to framebuffer outputs before drawing the fallback program.
3.2 WebGPU Implementation¶
Render Passes: Native
RenderPipeline.Compute Programs: WGSL sources containing
@computeand no@fragmentcompile to nativeComputePipelineobjects.Supports storage textures and buffers.
Supports arbitrary read/write (scatter/gather).
4. Constraints & Requirements¶
Vanilla JS: No build steps or transpilers required for the runtime logic.
Context Awareness: The pipeline must detect
glvsgpucontext and switch strategies transparently.Hot Reloading: Changing the DSL or an Effect Definition must instantly rebuild the graph without reloading the page.
Error Handling: DSL diagnostics stop compilation, while missing programs, textures, or backend resources fail during Pipeline initialization or pass execution.
5. Compute Shader Support¶
There is no pass type switch in the effect-definition contract. WebGPU
detects a compute program from a WGSL @compute entry point when the source
has no @fragment entry point. Cross-backend effects provide both that WGSL
compute implementation and an explicit GLSL render/GPGPU implementation.
5.1 WebGPU (Native)¶
Each source-detected compute program compiles into a
GPUComputePipeline. Multi-entry-point programs cache a pipeline per selectedentryPoint.Dispatch shape uses
workgroups: [x,y,z]when supplied. Otherwise, the backend tries dimensions in this order:The pass
sizeThe first output texture’s dimensions
The screen dimensions
Dimension-derived dispatches use
[ceil(width/8), ceil(height/8), 1]. The backend raisesERR_COMPUTE_DISPATCH_UNRESOLVEDif none is available.Bindings:
The backend binds reflected
@group(0)resources by name from the pass and frame state. Resources include sampled textures, samplers, uniform buffers, storage buffers, and storage textures.Uniform bindings use the WGSL reflection and per-binding buffer paths described in Section 7.
5.2 WebGL 2 Fallback¶
WebGL has no WGSL entry-point detection, compute dispatch, or
workgroupshandling. The effect’s GLSL program must implement the equivalent operation as a renderable fragment-shader pass.Passes using
storageTexturesor anoutputBufferoutput use the backend’s GPGPU conversion path. This path remaps those outputs to framebuffer color attachments and draws the GLSL fallback program. It does not translate WGSL invocation built-ins into GLSL.Multiple outputs use MRT. Capability and framebuffer failures surface from the backend rather than from a compiler-side MRT validator.
5.3 Cross‑Backend Restrictions¶
WebGPU capabilities come from the WGSL source and active device. There is no
effect.versionfeature gate. WebGL fallback programs remain limited to operations expressible through its render-based path.A source-detected WebGPU compute program may precede or follow render programs. Definition and DSL order determine execution order.
repeatmay be a fixed number or a uniform name. Repeated writes to global surfaces use the Pipeline’s frame-local read/write bindings between iterations.
6. Validation Rules¶
The current implementation validates at these stages:
DSL Parsing: The parser enforces syntax and the mandatory
searchdirective, throwingSyntaxErrorfor parse failures.DSL Semantics: The validator resolves names, chain structure, arguments, enums, and automation. It returns
S001–S008diagnostics. Error-level diagnostics becomeERR_COMPILATION_FAILEDincompileGraph().Expansion: Missing registered effects or a program with no render/write target become
ERR_EXPANSION_FAILED.Effect Harness and Runtime Validation:
validateEffectDefinition()inshaders/src/runtime/effect-validator.jsenforces the full definition grammar consumed by the runtime (metadata, tags, globals, textures, and pass contracts). It returns an array of deterministic error strings (empty when valid) and is run by test harnesses and loaders to catch specification violations before shader compilation or pipeline setup.Backend Validation: The Pipeline detects failures when it compiles or executes programs. These include shader source, binding, program, texture, device-limit, and dispatch failures.
6.1 Shader Compilation Lifecycle¶
Pipeline.init() initializes the backend, walks the ordered pass list, and
compiles each distinct program name once. The expander gives programs
effect-instance-scoped names and includes sorted compile-time define values in
the name, so different define variants receive different backend entries.
During recompilation, CanvasRenderer pauses rendering with isCompiling.
The recompile() method replaces the graph and recreates graph-dependent
textures. CanvasRenderer then invokes compilePrograms() before rendering resumes. A DSL or
expansion failure returns null before the graph swap.
7. Resource Lifetime Analysis¶
analyzeLiveness() scans the ordered pass array. Every non-global texture
mentioned by an input or output receives a {start, end} interval spanning
its first and last mention. The analysis excludes IDs beginning with global_.
allocateResources() then walks the same pass order. It assigns phys_N
slots to previously unseen outputs and releases an input’s slot after its last
use. A released slot can be reused only by an output in a later pass. The compiled graph stores the resulting Map<virtualId, physicalId>.
By default the Pipeline keeps one backend texture per virtual ID. When the
host passes texturePooling: true, the Pipeline consumes the map:
Pipeline.buildTexturePoolingPlan() groups the virtual textures that share
a physical slot, and recreateTextures() creates one backend texture per
group under the group’s primary ID and aliases the other members’ backend map
entries to it, so every pass binds the shared record through either ID. The
sharing survives resize and recompile through
releaseRegroupedTextures()/applyTextureAliases().
A group is pooled only when it is safe to share storage:
every member carries an identical plain 2D spec (no
persistent,mipmaps, or 3Dfilterpolicy);each member’s first touch in the pass list is a producing write, and its own producing pass does not sample it;
no member is written by a partial/non-clearing pass — any explicit
drawModescatter orblendpass, or aviewportwrite withoutclear: true, leaves previous contents observable in the unwritten region, which under pooled storage would expose a group-mate’s content.
Groups that fail these checks stay standalone, so first-read and cross-frame
accumulation semantics match the default pipeline. Pipeline.getResourcePlan()
reports both the analyzer’s physical allocation map and the sharing the
renderer actually materialized (pooling, allocations,
sharedTextures, and per-texture-record virtualTextures).
7.1 Binding Slot Assignment¶
WebGL Texture Units:
The backend assigns slots 0..N sequentially in pass input declaration order.
The backend resolves global surface IDs through the current frame state and binds either 2D or 3D texture targets as required.
The backend checks the available-unit limit while binding. Overflow raises
ERR_TOO_MANY_TEXTURESwith the pass id and device limit.
WebGPU Bind Groups:
The backend parses WGSL resource declarations and entry-point usage, then
builds entries for supported @group(0) bindings. It handles sampled
textures, storage textures, storage buffers, samplers, and uniforms according
to each declaration’s binding index. It currently skips other groups.
7.2 Uniform Transport¶
Uniform transport is backend-specific. WebGL uploads ordinary active uniforms.
If an effect provides uniformLayout metadata for an active uniform block,
WebGL packs that block into the declared 16-byte slots. For WebGPU, a
struct binding receives one packed uniform buffer, while a scalar/vector/matrix
uniform binding receives its own small buffer. The backend recycles those
buffers after submission.
8. Surface Management & Frame Buffering¶
8.0 Surface Types¶
The pipeline provides several types of global surfaces:
2D Surfaces (o0..``o7``): Standard double-buffered surfaces where reading within a frame sees any writes made earlier in that same frame.
3D Volume Surfaces (vol0..``vol7``): Persistent 3D texture volumes for volumetric effects. Default size is 64×64×64.
Geometry Buffers (geo0..``geo7``): Screen-sized 2D textures storing precomputed raymarching results (xyz=surface normal, w=depth). These enable downstream post-processing without re-raymarching.
Global 2D surfaces (o0.. o7) defined implicitly:
surfaceTable = {
o0: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
o1: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
o2: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
o3: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
o4: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
o5: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
o6: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
o7: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true }
}
Global 3D volume surfaces (vol0.. vol7) defined implicitly:
volumeTable = {
vol0: { format: 'rgba16f', width: 64, height: 64, depth: 64, is3D: true },
vol1: { format: 'rgba16f', width: 64, height: 64, depth: 64, is3D: true },
// ... vol2 through vol7
}
Global geometry buffers (geo0.. geo7) defined implicitly:
geoBufferTable = {
geo0: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
geo1: { format: 'rgba16f', width: 'screen', height: 'screen', doubleBuffered: true },
// ... geo2 through geo7
}
CRITICAL: User-Only Surfaces
Surfaces o0..``o7``, vol0..``vol7``, and geo0..``geo7`` are reserved exclusively for user composition.
Effect definitions MUST NOT hardwire these surfaces. Hardwiring them will
corrupt the user’s composition graph.
Effects that need internal feedback or temporary storage must allocate their
own internal surfaces in textures. Examples include _feedbackBuffer
and _temp0.
Terminology:
doubleBuffered: The surface has read and write texture IDs. Frame-local bindings advance after writes. Display surfaces swap at frame end, while recognized state surfaces retain their final bindings.
8.0.1 Global Surface Behavior¶
At frame start, each surface’s current read and write IDs seed frame-local
maps. A chain writing .write(o0) targets the current write ID. The Pipeline
advances the frame-local binding after the pass, so later reads and writes in
the same frame see the newest content. This ordered binding update supports multiple writes. There is no separate
multiwrite validator.
8.1 Resize Behavior¶
Pipeline.resize(width, height) updates the output-sink descriptor, then
calls createSurfaces() and recreateTextures(). The Pipeline resolves dimension specifications against the new screen size
and current pass uniforms. It reuses a backend texture when its resolved
dimensions still match. Otherwise, it destroys and recreates the texture. Resizing also restarts asynchronous effect
initialization.
Two 2D allocation policies (opt-in via the texture spec) change this default behavior:
mipmaps: trueallocates the full mip chain at creation (floor(log2(max(width, height))) + 1levels), with render/compute passes writing into level 0 and sampling through the full-chain view. The chain regenerates from level-0 writes each frame via the backend’sgenerateMipmaps()(WebGL2: level-to-level NEAREST blits; WebGPU: cached fullscreen resample pipelines with per-level bind groups).persistent: truepreserves contents across recreation at a new size: the pipeline copies the old texture into a temporary, recreates, and resamples back throughbackend.copyTexture()(WebGPU usescopyTextureToTexturewhen dimensions match and neither side is mipmapped, a fullscreen resample pass otherwise). Global surface recreation preserves persistent halves and recreates each half exactly once per allocation change.
3D texture specs (textures3d) may author filter: 'nearest' |
'linear'; it is honored by both backends, while unauthored 3D sampling
defaults differ between backends (WebGL2 uses LINEAR, WebGPU keeps the
historical nearest default), so cross-backend parity requires authoring
filter explicitly. Unknown or misplaced texture spec
fields are rejected by validateEffectDefinition() with per-field
diagnostics. The current resize path otherwise does not blit old surface
content into newly sized textures or recompile shader programs.
9. Execution Order¶
There is no dependency DAG or topological sort. expand() appends passes in
DSL plan order, effect-step order, and each definition’s passes array order.
The expander inserts built-in read, write, and final blit passes where it
encounters them. Pipeline.render() walks graph.passes from
index zero to the end.
For global surfaces, the Pipeline maintains frame-local read and write bindings. A write updates those bindings so a later pass in the same frame sees the fresh result. At frame end, the Pipeline swaps or preserves the surface record.
Dynamic Pass Skipping:
The Pipeline evaluates conditions with skipIf and/or runIf on a
pass present in a graph. The effect expander copies conditions from authored
effect pass definitions into expanded passes. For a graph pass with this field, the runtime compares each condition’s named
uniform with equals before dispatch. It skips the pass when the condition
says not to run.
9.1 Repeated Passes¶
The expander copies repeat from the pass definition into the expanded pass.
A number is clamped to an integer of at least one. A string names a global or
pass uniform whose current value supplies that count. The Pipeline executes the same
pass object that many times. After each repeated write to a global surface, it
adopts the new frame-local read/write bindings before the next iteration.
9.2 Pass-Field Propagation and Viewport Resolution¶
The effect expander copies authored pass fields (name, type, clear,
viewport, and samplerTypes) onto each expanded pass:
nameandtyperemain queryable pass labels on the expanded pass (backend shader-kind dispatch remains source-derived).clearreaches the WebGPU render-pass loadOp to clear attachments before execution when true.samplerTypesdirects WebGPU per-binding sampler selection (e.g. nearest vs. linear sampling).viewportspecifies an authored viewport box. The Pipeline evaluatesPipeline.resolvePassViewport()per frame, resolving dimension expressions (numbers, percentages,screen, and{param}/{screenDivide}/{scale, clamp}objects onwidthandheightkeys, alongside numericx,y,w, andhoffsets) against current pass uniforms and screen dimensions into a cachedviewportResolved{x, y, w, h}rectangle that tracks uniform updates without per-frame allocations. The WebGPU and WebGL2 backends preferviewportResolvedin their fallback viewport paths, while the authored specification remains queryable onpass.viewportand fully numeric viewports pass through unchanged.
10. Uniform & Binding Conventions¶
An effect global’s
uniformfield names the shader value populated by the expander. A pass’s resolved uniforms take precedence over same-named runtime globals.When a pass feeds a shader uniform from a differently named global (
uniforms: { layoutMode: "layout" }), the expander records the mapping on the pass asuniformAliases({ shaderUniform: globalName }). The runtime parameter paths write a changed parameter under its own uniform name and write the aliased shader uniforms too, so a live change reaches the shader exactly as a recompile would.Semantic validation resolves enum members to their registered numeric values.
Ordinary uniforms, uniform blocks, samplers, storage buffers, and storage textures follow the backend-specific reflection paths described in Section 7. The runtime does not apply a generic
u_prefix rewrite.
10.1 Pipeline Texture References¶
inputTex is the canonical 2D reference to the previous effect’s output.
During expansion it resolves to the current virtual input texture. A
non-starter effect cannot begin a chain. The DSL validator reports diagnostic
S005 before expansion.
outputTex is the canonical 2D output reference. It resolves to the current node’s virtual output. If the last pass of a writing
chain can target the terminal global surface, it resolves directly to that
surface instead. An ordinary undeclared output
texture receives a screen-sized rgba16f spec in compileGraph().
The corresponding volumetric references are inputTex3d and
outputTex3d. Geometry and particle pipelines similarly use inputGeo /
outputGeo, inputXyz / outputXyz, inputVel / outputVel, and
inputRgba / outputRgba.
11. Runtime Error Codes¶
DSL semantic diagnostics are documented in Polymorphic DSL. The compiler and backends currently emit these structured codes:
Code |
Meaning |
|---|---|
ERR_COMPILATION_FAILED |
Semantic validation returned one or more error diagnostics |
ERR_EXPANSION_FAILED |
Planned chains could not be expanded into passes |
ERR_PROGRAM_SPEC_MISSING |
A pass references no program specification during Pipeline initialization |
ERR_NO_WGSL_SOURCE |
A WebGPU program specification contains no usable WGSL source |
ERR_PROGRAM_NOT_FOUND |
A backend cannot find the pass’s compiled program |
ERR_TEXTURE_NOT_FOUND |
WebGPU cannot resolve an output texture |
ERR_NO_MRT_OUTPUTS |
A WebGPU MRT pass resolves no color attachments |
ERR_COMPUTE_DISPATCH_UNRESOLVED |
WebGPU cannot infer compute workgroup dimensions |
ERR_TOO_MANY_TEXTURES |
A WebGL pass exceeds available texture units |
ERR_UNIFORM_BLOCK_TOO_LARGE |
A WebGL uniform block exceeds the device limit |
ERR_SHADER_COMPILE |
WebGL or WebGPU shader compilation failed |
ERR_SHADER_LINK |
WebGL shader program linking failed |
ERR_SHADER_MISSING |
A pass references a shader source the backend cannot resolve |
Structured Shader Diagnostics: Every backend shader compile, link, and
missing-source failure throws one ShaderDiagnostic (a real Error in
shaders/src/runtime/backends/diagnostics.js) instead of an ad-hoc object
literal. It carries the legacy machine code from the table above, the
backend (webgl2 or webgpu), a stage (compile, link,
missing-source, or bind), the program/pass id when known, the raw
browser/compiler string as detail (byte-identical to the legacy thrown
shape), the offending shader source for compile diagnostics, and a parsed
messages array (one entry per compiler message with severity,
line, column, and message) built from GLSL info logs
(parseGLSLInfoLog()) or WebGPU getCompilationInfo()
(parseWebGPUCompilationMessages()). The legacy enumerable surface
(code, detail, program, source) is preserved, so
err.detail || err.message consumers keep their output. The WebGPU
bind-group retry consumes the parsed bindingIndex through
toDiagnostic()/parseDiagnosticText() instead of re-matching raw
browser error strings. Runtime resource failures (missing framebuffers,
gl.getError() draining, WebGPU uncapturederror) and the silent
unknown WebGL format/dimension fallbacks do not throw the union; they record
non-throwing structured diagnostics instead — ERR_MISSING_RENDER_TARGET
(missing FBO/MRT targets), ERR_GL_ERROR (post-draw drained GL errors) and
ERR_DEVICE_VALIDATION (WebGPU uncapturederror) in
backend.diagnostics, and ERR_UNKNOWN_FORMAT_FALLBACK /
ERR_DIMENSION_FALLBACK for the authoring fallbacks, via the capped
DiagnosticCollector — with console output unchanged.
12. Current Performance Behavior¶
Graph compilation is synchronous. The implementation does not enforce a timing
target by pass count or emit compile-time pool metrics. Normal rendering keeps
intermediate textures on the GPU. Readback occurs only through explicit APIs
such as frame export, cubemap capture, or backend readPixels().
13. Extensibility¶
The current Effect constructor copies the supported configuration fields
described in Effect Definition Spec. It does not expose
an effect.version feature gate. Hosts extend the available language through
effect registration and the namespace registry.
14. Runtime Data Structures¶
14.1 Compiled Graph¶
interface CompiledGraph {
id: string
source: string
passes: ExpandedPass[]
programs: Record<string, ProgramSpec>
allocations: Map<string, string>
textures: Map<string, RuntimeTextureSpec>
renderSurface: string | null
compiledAt: number
}
interface ExpandedPass {
id: string
program: string
inputs: Record<string, string>
outputs: Record<string, string>
uniforms: Record<string, unknown>
entryPoint?: string
drawMode?: string
drawBuffers?: number
count?: number | string
countUniform?: string
repeat?: number | string
blend?: boolean | [string | number, string | number]
workgroups?: [number, number, number]
storageBuffers?: Record<string, unknown>
storageTextures?: Record<string, string>
effectKey?: string
effectFunc?: string
effectNamespace?: string | null
nodeId?: string
stepIndex?: number
}
14.2 Pipeline State¶
The Pipeline holds these runtime resources and state:
The compiled graph and selected backend
Output sinks and double-buffered global surfaces
Global uniforms and dimensions
Frame-local surface bindings
External MIDI/audio state
Async-effect cancellation handles
Managed effect lifecycle set (effects in the current graph that author
onInit/onUpdate/onDestroyhooks)
The isCompiling flag prevents rendering while the backend rebuilds
programs. There is no separate effect lifecycle state machine; lifecycle
hooks are managed through the lifecycle-effect set instead:
initLifecycleEffects() (called at the same sites as
initAsyncEffects()) rebuilds the set from the current graph and runs
onInit() once per effect instance per pipeline lifetime,
render() calls onUpdate() once per frame with returned uniforms
bound under fallback semantics, and dispose() runs onDestroy() for
every managed effect with hook errors joining the existing dispose error
path.
14.3 Frame Execution State¶
interface FrameState {
frameIndex: number
time: number
graph: CompiledGraph
globalUniforms: Record<string, unknown>
surfaces: Record<string, BackendTexture>
writeSurfaces: Record<string, string>
screenWidth: number
screenHeight: number
}
15. Determinism Guarantees¶
The graph
idis a deterministic base-36 hash of the DSL source string.Expansion preserves source plan order, definition pass order, and sorted compile-time define names.
Liveness intervals and
phys_Nassignments are deterministic for the same expanded pass array.
16. Recompilation and Runtime Errors¶
16.1 Hot Reload Protocol¶
CanvasRenderer sets isCompiling before invoking recompile(). If source compilation or expansion fails, the method logs the failure.
It returns null before replacing the existing graph. On success, recompile() assigns pipeline.graph and
recreates graph-dependent surfaces and textures. CanvasRenderer then awaits
compilePrograms() before rendering resumes.
16.2 Error Recovery¶
Pipeline.render() logs a pass execution failure with the pass id and
rethrows it. It does not substitute a fallback texture or continue later
passes. Pipeline initialization likewise propagates program compilation and
resource errors after clearing the isCompiling gate.
17. Glossary¶
AST (Abstract Syntax Tree): The tree representation of the user’s DSL code produced by the Parser.
Planned Chain: The semantic validator’s ordered effect steps, connected by temporary-value indices.
Expanded Pass: One backend-facing pass emitted from an effect definition, with resolved virtual texture bindings and uniforms.
Compiled Graph: The object returned by
compileGraph()containing the source, ordered passes, program specs, allocation map, texture specs, render surface, and metadata. Backend-compiled programs and physical textures live on the Pipeline/backend rather than in this object.