7.6 KiB
Below is a clean, concise AGENTS.md “WebGPU Patterns” section designed specifically for your custom framework:
EngineRenderPipelineBlockRenderPassShader
Not the GPT model logic. Not embeddings or inference. Only the architectural usage patterns you want Codex to follow.
You can copy this directly into your existing AGENTS.md under “Example Patterns”, or use it to replace that section entirely.
It teaches Codex:
- How your framework is structured
- How passes are created
- How pipelines are assembled
- How shader setup works
- How buffer binding works
- How execution is called
This ensures that Codex will generate compatible new passes, pipelines, and engine bootstraps.
WEBGPU FRAMEWORK PATTERNS (SHORT, STRICT)
Codex must follow these exact patterns when creating or modifying WebGPU code using the framework located in /framework.
These patterns describe:
- how to extend
RenderPass - how to assemble a
Block - how to create a
RenderPipeline - how to use
Engine - how to load WGSL shaders
- how to bind buffers and call
.execute()
No ML logic included. Only architectural usage patterns.
paths
/framework/RenderPass.js
/framework/WebGpu.js
/framework/Block.js
/framework/EventManager.js
/framework/Camera.js
/framework/Matrix4.js
/framework/vector3.js
1. RenderPass Pattern
A pass is always:
- its own file under
passes/ - a class extending
RenderPass - has
create(),bindBuffers(),execute() - loads its shader using
new Shader(this.device) - sets WGSL variables using
.setVariable()
import { RenderPass } from "framework/RenderPass.js";
import Shader from "framework/WebGpu.js";
export class ExamplePass extends RenderPass {
async create( ) {
this.shader = new Shader( this.device );
await this.shader.setup( "shaders/example.wgsl" );
}
bindBuffers( ) {
var inputData = this.pipeline.memory.inputData;
// set variable can be normal javascript arrays, also typed arrays.
this.shader.setVariable(
"input1",
[1,2,3,4,5]
);
// set variable can be normal javascript arrays, also typed arrays.
this.shader.setVariable(
"input2",
new Float32Array( [ 1,2,3,4 ] )
);
const texture = this.shader.createTextureFromData(
width,
height,
[ 1,2,3... ]
);
this.shader.setVariable( "texture", texture );
// associate buffer from other shader buffer
const prevLayerBlock = this.pipeline.getBlockByName("blockName");
const pass = prevLayerBlock.getPass("passName");
const buffer = pass.shader.getBuffer("outputVector");
this.shader.setBuffer("inputHiddenState", buffer);
}
async execute( ) {
await this.shader.execute( 1 );
}
}
Rules Codex must preserve:
- One blank line between imports.
- Tab-aligned imports before each
from. - No arrow functions.
await this.shader.setup( path ).this.shader.setVariable( name, data )only inbindBuffers()or incremental calls.execute()always callsthis.shader.execute( workgroups ).
2. Block Pattern
A block is a logical grouping of passes. Codex must:
- create blocks using
new Block( "name", pipeline ) - attach passes with
block.addPass( "Name", instance ) - add block to pipeline with
pipeline.addBlock( block )
import { Block } from "./framework/Block.js";
import { ExamplePass } from "../passes/ExamplePass.js";
const block = new Block( "example", this );
const pass = new ExamplePass( );
block.addPass( "Example", pass );
this.addBlock( block );
3. Pipeline Pattern
A pipeline:
- extends
RenderPipeline - constructs blocks in
create() - allocates memory buffers on
this.memory - always calls
await super.create()last - may override
execute()to chain passes logically
import { RenderPipeline } from "./framework/RenderPipeline.js";
import { Block } from "./framework/Block.js";
import { ExamplePass } from "../passes/ExamplePass.js";
export class ExamplePipeline extends RenderPipeline {
async create( ) {
/* Allocate global memory */
this.memory.input = new Float32Array( 1024 );
this.memory.output = new Float32Array( 1024 );
/* Pass block */
const block = new Block( "example", this );
const examplePass = new ExamplePass( );
block.addPass( "Example", examplePass );
this.addBlock( block );
/* Build GPU resources (mandatory) */
await super.create();
}
async execute( ) {
const block = this.blocks[0];
const pass = block.getPass( "Example" );
await pass.execute();
}
}
3. Camera and eventmanager Pattern
import Matrix4 from "framework/Matrix4.js"
import Vector3 from "framework/Vector3.js"
this.camera = new Camera( [0, 0, 1115], [0, -.3, 0], [0, 1, 0] );
this.eventManager.setup( canvas, this.camera );
const viewMatrixData = this.camera.getViewMatrix();
const projectionMatrixData = Matrix4.createProjectionMatrix( this.camera, this.canvas )
const viewProjectionMatrix = Matrix4.multiply( projectionMatrixData, viewMatrixData );
const cameraWorldMatrix = Matrix4.invert( viewMatrixData );
const cameraPosition = Matrix4.getColumn( cameraWorldMatrix, 3 );
this.renderShader.setVariable( "viewProjectionMatrix", viewProjectionMatrix );
this.renderShader.setVariable( "cameraPosition", cameraPosition );
Codex must:
- allocate buffers on
this.memory.* - assemble blocks before
super.create() - not reorder pipeline structure automatically
4. Engine Usage Pattern
The entrypoint must follow this shape whenever Codex creates a new WebGPU project:
import { Engine } from "./framework/Engine.js";
import { ExamplePipeline } from "./pipelines/ExamplePipeline.js";
async function main( ) {
const adapter = await navigator.gpu.requestAdapter( );
const device = await adapter.requestDevice( );
const engine = new Engine( device );
/* Pipeline */
const pipeline = new ExamplePipeline( engine );
pipeline.memory.set( "inputData", new Float32Array( 1024 ) );
await pipeline.create();
await pipeline.bindBuffers();
await pipeline.execute();
}
main( );
Codex must always:
- request adapter → requestDevice
- create
new Engine(device) - instantiate pipeline with
(engine) - set memory with
pipeline.memory.set( key, value ) - call
await pipeline.create() - call
await pipeline.bindBuffers() - call
await pipeline.execute()
5. Shader Usage Pattern
Codex must use the Shader class exactly like this:
this.shader = new Shader( this.device );
await this.shader.setup( "shaders/example.wgsl" );
this.shader.setVariable( "bufferA", floatArray );
await this.shader.execute( workgroups );
Always:
- One shader instance per pass
- WGSL path passed to
.setup() .setVariable()before.execute()- No arrow functions
- Spaces inside parentheses
6. Memory Allocation Pattern
All buffers are allocated as plain typed arrays under:
this.memory.X = new Float32Array( size );
Codex must never use ArrayBuffer directly unless required.
7. Execution Flow Rule
Every pipeline execution must follow:
await pipeline.create()await pipeline.bindBuffers()await pipeline.execute()
Never run execute before create. Never omit bindBuffers if pass needs it.
8. Codex MUST NOT Generate
-
Raw WebGPU API calls (
device.createBuffer) unless inside Shader class -
Inline WGSL; always stored in
.wgslfiles -
Arrow functions
-
Inline callbacks
-
Different architecture than this:
- Engine
- Pipeline
- Block
- RenderPass
- Shader