Guidelines for coding agents working in the byegl repository—a WebGL-to-WebGPU compatibility library.
pnpm install # Install dependencies
pnpm dev # Start docs dev server
pnpm test:ci # Run all CI checks (style, node tests, types)
pnpm test:node # Run Node.js tests (jsdom)
pnpm test:browser # Run browser tests (webdriverio/chrome)
pnpm test:style # Run Biome linting/formatting
pnpm test:types # TypeScript type checking
pnpm fix # Auto-fix linting/formatting issues├── packages/byegl/ # Main library
│ ├── src/
│ │ ├── index.ts # Entry point & public API (enable, getDevice, etc.)
│ │ ├── byegl-context.ts # Core WebGL context implementation
│ │ ├── buffer.ts # WebGL buffer → WebGPU buffer
│ │ ├── program.ts # Shader program handling
│ │ ├── uniform.ts # Uniform location management
│ │ ├── texture.ts # Texture handling
│ │ ├── attribute.ts # Vertex attribute handling
│ │ ├── framebuffer.ts # Framebuffer implementation
│ │ ├── errors.ts # Custom error classes
│ │ ├── types.ts # Type definitions & $internal symbol
│ │ └── wgsl/ # GLSL → WGSL shader generation
│ │ ├── shaderkit-wgsl-generator.ts # Production generator
│ │ └── mock-wgsl-generator.ts # Test mock
│ └── tests/
│ ├── *.test.ts # Node tests (run with jsdom)
│ ├── *.test.browser.ts # Browser tests (run with Chrome)
│ ├── extendedTest.ts # Test fixtures & helpers
│ └── setup.ts # Node test setup (WebGL mocks)
├── apps/docs/ # Astro documentation site
│ └── src/examples/ # Interactive examples
├── biome.json # Linting/formatting config
└── vitest.config.mjs # Test configuration
# Run specific test file
pnpm test:node -- packages/byegl/tests/uniforms.test.ts
# Run tests matching a pattern
pnpm test:node -- --grep "uniform location"
# Watch mode
pnpm test:node -- --watch
# Browser tests (opens Chrome)
pnpm test:browser -- packages/byegl/tests/remap.test.browser.ts# Build main library
cd packages/byegl && pnpm build
# Build docs site
cd apps/docs && pnpm buildAlways run:
pnpm test:ci && cd packages/byegl && pnpm build- Target: ES2020, ESNext modules, bundler resolution
- Strict mode: Enabled
- Import extensions: Always use
.tsextensions - WebGPU types: Via
@webgpu/types
// Always use .ts extensions
import { ByeGLContext } from './byegl-context.ts';
import { $internal } from './types.ts';
// Type-only imports when appropriate
import type { WebGLBuffer } from './types.ts';
// External imports first, then internal (Biome auto-organizes)
import tgpu from 'typegpu';
import { ByeGLBuffer } from './buffer.ts';- Single quotes
- 2-space indentation
- Semicolons required
- Trailing commas (ES5 style)
- Classes:
PascalCase(e.g.,ByeGLContext,ShaderCompilationError) - Functions/Variables:
camelCase - Internal properties: Use
$internalsymbol fromtypes.ts
// Custom errors in errors.ts
export class NotImplementedYetError extends Error {
constructor(feature: string) {
super(`Feature '${feature}' is not implemented yet...`);
Object.setPrototypeOf(this, NotImplementedYetError.prototype);
}
}
// Validation pattern
if (!(gl instanceof ByeGLContext)) {
throw new Error('Cannot use byegl hooks on a vanilla WebGL context');
}Document public API functions:
/**
* Returns the WebGPU buffer associated with the given WebGL buffer.
* Since byegl might reallocate the buffer if the size of the data changes,
* call this function each time you need access.
*
* @param gl The WebGL (actually byegl) context.
* @param glBuffer
* @returns The WebGPU buffer associated with `glBuffer`.
*/
export function getWebGPUBuffer(...): GPUBuffer { }Tests use Vitest with custom fixtures from extendedTest.ts:
import { describe, expect } from 'vitest';
import { test, toWgsl } from './extendedTest.ts';
describe('float uniform', () => {
test('shader generation', ({ gl }) => {
const { wgsl } = toWgsl(gl, vertShader, fragShader);
expect(wgsl).toMatchInlineSnapshot(`...`);
});
});gl- Mocked WebGL2RenderingContext (ByeGLContext instance)device- Mocked GPUDeviceroot- TgpuRoot instancecommandEncoder- Mocked GPUCommandEncoder
toWgsl(gl, glslVert, glslFrag)- Compiles GLSL to WGSL, returns{ wgsl, program }
Prefer inline snapshots for generated code:
expect(wgsl).toMatchInlineSnapshot(`
"// Generated by byegl
@group(0) @binding(0) var<uniform> uFoo: f32;
"
`);Access internal state via the $internal symbol:
import { $internal } from './types.ts';
// Access internal buffer state
const gpuBuffer = (glBuffer as ByeGLBuffer)[$internal].gpuBuffer;
// Access context internals
const device = gl[$internal].device;- GLSL → WGSL translation via
@iwoplaza/shaderkit - Generator in
src/wgsl/shaderkit-wgsl-generator.ts - Uniforms get automatic
@group(0) @binding(N)assignments
byegl.enable() patches HTMLCanvasElement.prototype.getContext to return ByeGLContext instead of native WebGL contexts.
Use conventional commits:
feat: add support for WebGL2 uniform blocks
fix: correct matrix uniform alignment in WGSL output
test: add browser tests for texture sampling
refactor: extract shader compilation logic
docs: update API documentation
chore: update dependencies
typegpu- WebGPU type system for shader generation@iwoplaza/shaderkit- GLSL → WGSL translation
@webgpu/types- WebGPU TypeScript typestsdown- Build tool with typegpu pluginwebgl-constants- WebGL constant values for tests
- Node.js 22.x+
- pnpm 10.x+