Below is a clean, concise **AGENTS.md “WebGPU Patterns” section** designed specifically for *your custom framework*: * `Engine` * `RenderPipeline` * `Block` * `RenderPass` * `Shader` 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()` ```javascript 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 in `bindBuffers()` or incremental calls. * `execute()` always calls `this.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: 1. `await pipeline.create()` 2. `await pipeline.bindBuffers()` 3. `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 `.wgsl` files * Arrow functions * Inline callbacks * Different architecture than this: * Engine * Pipeline * Block * RenderPass * Shader