π§ Utilities for managing WebGL resources: uniforms, (interleaved) attributes and buffers.
- schema-based resource management
view-gl - compose schema and shader simultaneously via a tag template literal
view-gl/tag
- π¦ Install
- ποΈ view.gl
- π Basic Usage
- ποΈ view
- π ViewSchema
- π Resource Views
- π― uniformView
- π UniformSchema
- π attributeView
- π AttributeSchema
- π interleavedAttributeView
- ποΈ bufferView
- π BufferSchema
- π― uniformView
- π·οΈ view.gl/tag
- π Basic Usage
- π glsl
- π·οΈ Resource Tokens
- βοΈ compile(gl, vertex, fragment)
- π οΈ Utils
- ποΈ createProgram
- πΌοΈ createTexture
- π₯οΈ createFramebuffer
- π WebGL Type Compatibility
- π― Uniform Types
- π Attribute Types
npm install @bigmistqke/view.glpnpm add @bigmistqke/view.glyarn add @bigmistqke/view.glbun add @bigmistqke/view.glThe view system provides type-safe WebGL resource management for uniforms, attributes, and buffers
const { uniforms, attributes } = view(gl, program, {
uniforms: {
time: { kind: 'float' },
resolution: { kind: 'vec2' },
},
attributes: {
position: { kind: 'vec3' },
uv: { kind: 'vec2' },
},
buffers: {
indices: { target: 'ELEMENT_ARRAY_BUFFER' },
},
})
// Type-safe uniform setting
uniforms.time.set(performance.now())
uniforms.resolution.set(canvas.width, canvas.height)
// Attribute management
attributes.position.set(positionData)
attributes.position.bind()The view() function creates type-safe WebGL resource managers from a schema.
const { uniforms, attributes, buffers } = view(gl, program, schema)Parameters:
gl: WebGL rendering contextprogram: Compiled WebGL programschema: seeViewSchema
Returns:
uniforms: Type-safe uniform settersattributes: Attribute managers with buffer handlingbuffers: Generic buffer managers
The complete schema object that defines all WebGL resources. Contains mappings for:
UniformSchema- uniform variable definitionsAttributeSchema- vertex attribute definitionsInterleavedAttributeSchema- interleaved vertex data definitionsBufferSchema- generic buffer definitions
TypeScript Types
interface ViewSchema {
uniforms: UniformSchema
attributes: AttributeSchema
interleavedAttributes: InterleavedAttributeSchema
buffers: BufferSchema
}Each view type can be imported individually.
Manages shader uniform variables.
const uniforms = uniformView(gl, program, {
time: { kind: 'float' },
lights: { kind: 'vec3', size: 8 }, // Array uniform: vec3[8]
transform: { kind: 'mat4' },
})
uniforms.time.set(performance.now())
uniforms.lights.set(lightData) // Takes Float32Array for array uniformsA mapping of uniform names to their configuration.
kind: GLSL type (see Uniform Types for full list and WebGL compatibility)size: Array size (optional) - converts uniform to array type
TypeScript Types
type UniformKind =
| 'float'
| 'int'
| 'bool'
| 'vec2'
| 'vec3'
| 'vec4'
| 'ivec2'
| 'ivec3'
| 'ivec4'
| 'bvec2'
| 'bvec3'
| 'bvec4'
| 'mat2'
| 'mat3'
| 'mat4'
| 'sampler2D'
| 'samplerCube'
interface UniformDefinition {
kind: UniformKind
size?: number // Creates array uniform with Float32Array setter
}
type UniformSchema = Record<string | symbol, UniformDefinition>Manages vertex attributes with automatic buffer creation and binding.
const attributes = attributeView(gl, program, {
position: { kind: 'vec3' },
instanceOffset: { kind: 'vec2', instanced: true },
})
attributes.position.set(positionData).bind()
attributes.instanceOffset.set(instanceData).bind()
gl.drawArraysInstanced(gl.TRIANGLES, 0, 3, 100)A mapping of attribute names to their configuration.
kind: GLSL type (see Attribute Types for full list and WebGL compatibility)instanced: Boolean (optional) - enables instanced renderingbuffer: Custom WebGLBuffer (optional) - by default it gets created automatically during compilation
TypeScript Types
type AttributeKind =
| 'float'
| 'vec2'
| 'vec3'
| 'vec4'
| 'mat2'
| 'mat3'
| 'mat4'
| 'int'
| 'ivec2'
| 'ivec3'
| 'ivec4'
interface AttributeDefinition {
kind: AttributeKind
instanced?: boolean // Enables vertexAttribDivisor
buffer?: WebGLBuffer // Custom buffer, auto-created if not provided
}
type AttributeSchema = Record<string | symbol, AttributeDefinition>Manages interleaved vertex data with automatic stride/offset calculation.
const interleavedAttributes = interleavedAttributeView(gl, program, {
vertexData: {
layout: [
{ key: 'position', kind: 'vec3' },
{ key: 'normal', kind: 'vec3' },
{ key: 'uv', kind: 'vec2' },
],
},
})
interleavedAttributes.vertexData.set(interleavedVertexData).bind()A mapping of interleaved buffer names to their layout configuration. Each layout defines multiple attributes packed into a single buffer.
layout: Array of attribute definitions withkeyandkind(see Attribute Types)instanced: Boolean - applies to all attributes in layoutbuffer: Custom WebGLBuffer (optional) - by default it gets created automatically during compilation
TypeScript Types
interface InterleavedAttributeDefinition {
layout: Array<{
key: string | symbol
kind: AttributeKind
}>
instanced?: boolean // Applies vertexAttribDivisor to all attributes
buffer?: WebGLBuffer // Custom buffer for interleaved data
}
type InterleavedAttributeSchema = Record<string | symbol, InterleavedAttributeDefinition>Manages generic WebGL buffers.
const buffers = bufferView(gl, {
indices: { target: 'ELEMENT_ARRAY_BUFFER' },
data: { target: 'ARRAY_BUFFER', usage: 'DYNAMIC_DRAW' },
})
buffers.indices.set(indexData).bind()
buffers.data.set(dynamicData).bind()A mapping of buffer names to their configuration. Each buffer has a target type and optional usage pattern.
target: Buffer target ('ARRAY_BUFFER','ELEMENT_ARRAY_BUFFER')usage: Usage pattern ('STATIC_DRAW','DYNAMIC_DRAW','STREAM_DRAW')
TypeScript Types
interface BufferDefinition {
target: 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER'
usage?: 'STATIC_DRAW' | 'DYNAMIC_DRAW' | 'STREAM_DRAW' // Defaults to 'STATIC_DRAW'
}
type BufferSchema = Record<string | symbol, BufferDefinition>Type-safe GLSL template literals with automatic schema extraction and view creation.
- Embedded Resources: Define uniforms, attributes, and interleaved layouts directly in GLSL
- Type Inference: Automatically infers schema types and creates type-safe view
- Unique Variables: Prevent naming collisions using symbols for unique shader variables
- GLSL Composition: Compose reusable GLSL fragments with automatic dependency resolution
const vertexShader = glsl`
${attribute.vec3('position')}
${uniform.mat4('model')}
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = model * vec4(position, 1.0);
}
`
const fragmentShader = glsl`
${uniform.sampler2D('texture')}
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(texture, vUv);
}
`
const { program, schema } = compile(gl, vertexShader, fragmentShader)Template literal processor that handles GLSL code and embedded resources. Supports interpolation of:
- Resource tags:
uniform.*(),attribute.*(),interleave() - GLSL fragments: Reusable shader code snippets
- Symbol Variables: Unique variable names to prevent collisions
- Strings: Interpolated as-is into the shader code
- Arrays: Arrays of any supported interpolation types
const precision = 'precision mediump float;'
const functionName = Symbol('function')
const shader = glsl`
${precision} // String interpolated as-is
${uniform.vec2('resolution')}
${[attribute.vec3('position'), attribute.vec2('uv')]} // Array interpolation
vec3 ${functionName}(vec2 uv) { // Symbol interpolated to unique identifier
return vec3(uv, 0.5);
}
void main() {
gl_Position = vec4(position, 1.0);
}
`Compose reusable GLSL code fragments to build complex shaders:
const lighting = glsl`
vec3 calculateLighting(vec3 normal, vec3 lightDir) {
float diff = max(dot(normal, lightDir), 0.0);
return vec3(diff);
}
`
const vertexShader = glsl`
${attribute.vec3('direction')}
${attribute.vec3('normal')}
${lighting} // Include the lighting fragment
varying vec3 vLighting;
void main() {
vLighting = calculateLighting(normal, direction);
}
`Use JavaScript symbols to prevent naming collisions:
const sum = Symbol('sum')
const sumFragment = glsl`
float ${sum}(float a, float b){
return a + b;
}`
const shader = glsl`
${sumFragment}
void main(){
float result = ${sum}(1.0, 2.0);
}
`Symbols are converted to unique identifiers during the compilation of the shader.
The glsl-function supports both WebGL1 and WebGL2 syntax, automatically using the correct keywords for resource tags:
// WebGL1 (default)
const shader = glsl`
${attribute.vec3('position')} // β attribute vec3 position;
varying vec2 vUv;
`If the shader starts with #version 300 es, resource tags generate WebGL2 syntax:
// WebGL2
const shader = glsl`#version 300 es
${attribute.vec3('position')} // β in vec3 position;
out vec2 vUv;
`Utilities for defining WebGL resources directly in GLSL templates. These create metadata that the compile consumes to generate the typesafe schema and view.
Define uniform variables in GLSL templates (see Uniform Types).
const uniqueTime = Symbol('time')
const shader = glsl`
${uniform.float('time')} // String key
${uniform.float(uniqueTime)} // Symbol key
${uniform.vec3('lights', { size: 8 })} // Array uniform: vec3[8]
void main() {
float wave = sin(time * 2.0 + ${uniqueTime});
vec3 totalLight = vec3(0.0);
for(int i = 0; i < 8; i++) {
totalLight += lights[i] * wave;
}
gl_FragColor = vec4(totalLight, 1.0);
}
`Parameters:
name: Uniform name (string or symbol for unique variables)options: Optional configuration objectsize: Array size (creates array uniform with Float32Array setter)
Define vertex attributes in GLSL templates (see Attribute Types).
const uniquePosition = Symbol('position')
const vertexShader = glsl`
${attribute.vec3('position')} // String key
${attribute.vec3(uniquePosition)} // Symbol key
${attribute.vec2('offset', { instanced: true })}
void main() {
gl_Position = vec4(position + vec3(offset, 0.0), 1.0);
}
`Parameters:
name: Attribute name (string or symbol for unique variables)options: Optional configuration objectinstanced: Boolean - enables instanced rendering withvertexAttribDivisorbuffer: Custom WebGLBuffer (optional)
Define interleaved attribute layouts for efficient vertex data.
const uniqueVertexData = Symbol('vertexData')
const uniquePosition = Symbol('position')
const vertexShader = glsl`
${interleave('vertexData', [
// String key
{ key: 'position', kind: 'vec3' },
{ key: 'uv', kind: 'vec2' },
])}
${interleave(uniqueVertexData, [
// Symbol key
{ key: uniquePosition, kind: 'vec3' }, // Symbol keys in layout
{ key: 'uv', kind: 'vec2' },
])}
void main() {
gl_Position = vec4(position + vec3(uv, 0.0), 1.0);
}
`Parameters:
name: Buffer name (string or symbol for unique variables)layout: Array of attribute definitionskey: Attribute name (string or symbol for unique variables)kind: GLSL type (see Attribute Types)
options: Optional configuration objectinstanced: Boolean - appliesvertexAttribDivisorto all attributes
Compiles shaders to a WebGLProgram and extracts typesafe schema and view.
Convenient helper for fullscreen quad rendering with fragment shaders. Automatically creates a vertex shader with a quad geometry and handles vertex buffer setup.
const { program, schema, view } = compile.toQuad(gl, fragmentShader)
// Ready to render - no vertex setup required
view.uniforms.time.set(performance.now())
gl.drawArrays(gl.TRIANGLES, 0, 6)Perfect for:
- Fragment shader effects (ray-marching, post-processing, etc.)
- Fullscreen compute-style shaders
- Quick prototyping and experimentation
Generated vertex shader:
- Creates
a_quadattribute automatically - Outputs
uvvarying (same as vertex position:[-1,1]range) - Sets up clip-space quad covering the entire screen
Parameters:
gl: WebGL rendering contextfragment: Fragment shader with embedded resourcesoptions: Optional compilation options (same ascompile())
Returns: Same as compile() with pre-configured quad rendering
const { program, schema, view, vertex, fragment } = compile(gl, vertexShader, fragmentShader)
// Use the view directly
view.uniforms.time.set(performance.now())
view.attributes.position.set(vertexData).bind()
// Access the compiled shader strings
console.log(vertex) // Compiled vertex shader GLSL
console.log(fragment) // Compiled fragment shader GLSL
// Or access the extracted schema
console.log(schema.uniforms) // { time: { kind: 'float' }, ... }
console.log(schema.attributes) // { position: { kind: 'vec3' }, ... }Override Schema:
You can provide an optional override schema to enhance or override the automatically extracted schema:
const { program, schema, view } = compile(gl, vertexShader, fragmentShader, {
uniforms: {
// Add additional uniforms not automatically inferred
customTime: { kind: 'float' },
},
buffers: {
// Add buffer definitions
indices: { target: 'ELEMENT_ARRAY_BUFFER' },
},
})
// The override schema is merged with the extracted schema
view.uniforms.customTime.set(123.45)
view.buffers.indices.set(indexData).bind()Returns:
program: Compiled WebGL programschema: Merged schema (extracted + override)view: Ready-to-use view with type-safe resource accessvertex: Compiled vertex shader GLSL stringfragment: Compiled fragment shader GLSL string
Converts a GLSL tagged template to a shader string without compilation of the WebGLProgram. Useful for debugging or when you need the raw shader code.
const vertexShader = glsl`
${attribute.vec3('position')}
${uniform.mat4('mvpMatrix')}
void main() {
gl_Position = mvpMatrix * vec4(position, 1.0);
}
`
const shaderString = compile.toString(vertexShader)
console.log(shaderString)
// Output:
// attribute vec3 position;
// uniform mat4 mvpMatrix;
//
// void main() {
// gl_Position = mvpMatrix * vec4(position, 1.0);
// }Features:
- Converts resource tags to GLSL declarations
- Handles WebGL1/WebGL2 syntax automatically
- Resolves symbol variables to unique identifiers
- Processes nested GLSL fragments and arrays
Extracts the ViewSchema from a GLSL tagged template without compilation of the WebGLProgram. Returns the type-safe schema that could be used by view().
const shader = glsl`
${uniform.float('time')}
${uniform.vec3('lightPos', { size: 4 })}
${attribute.vec3('position')}
${interleave('vertexData', [
attribute.vec2('uv'),
attribute.vec4('color')
])}
`
const schema = compile.toSchema(shader)
console.log(schema)
// Output:
// {
// uniforms: {
// time: { kind: 'float' },
// lightPos: { kind: 'vec3', size: 4 }
// },
// attributes: {
// position: { kind: 'vec3' }
// },
// interleavedAttributes: {
// vertexData: {
// layout: [
// { key: 'uv', kind: 'vec2' },
// { key: 'color', kind: 'vec4' }
// ],
// instanced: false
// }
// }
// }Use Cases:
- Analyze shader resources without GL context
- Generate TypeScript types from shaders
- Validate shader compatibility before compilation
- Build tooling around shader resources
Usage with vanilla view.gl
When manually constructing GLSL strings, use toID() to convert symbols to valid, unique identifiers:
const u_time = Symbol('time')
const a_position = Symbol('position')
const vertex = `
attribute vec3 ${toID(a_position)};
uniform float ${toID(u_time)};
void main() {
gl_Position = vec4(${toID(a_position)}, ${toID(u_time)});
}
`
const fragment = `
precision mediump float;
uniform float ${toID(u_time)};
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, sin(${toID(u_time)}));
}
`
const program = createProgram(gl, vertex, fragment)
const { attributes, uniforms } = view(gl, program, {
uniforms: { [u_time]: { kind: 'float' } },
attributes: { [a_position]: { kind: 'vec3' } },
})
attributes[a_position].set(vertexData)
uniforms[u_time].set(performance.now())Creates and links a WebGL program from vertex and fragment shader sources.
const program = createProgram(gl, vertexShaderSource, fragmentShaderSource)Creates a WebGL texture with specified parameters.
const texture = createTexture(
gl,
{
width: 512,
height: 512,
internalFormat: 'RGBA',
format: 'RGBA',
type: 'UNSIGNED_BYTE',
minFilter: 'LINEAR',
magFilter: 'LINEAR',
wrapS: 'CLAMP_TO_EDGE',
wrapT: 'CLAMP_TO_EDGE',
},
data,
)Automatically validates WebGL2-only formats and provides fallbacks for WebGL1.
Creates a framebuffer with attached texture for render-to-texture operations.
const { framebuffer, texture } = createFramebuffer(gl, {
width: 512,
height: 512,
attachment: 'color',
internalFormat: 'RGBA',
format: 'RGBA',
type: 'UNSIGNED_BYTE',
})Supports color, depth, stencil, and combined depth-stencil attachments with completeness validation.
| Type | WebGL 1 | WebGL 2 |
|---|---|---|
float |
β | β |
int |
β | β |
bool |
β | β |
vec2 |
β | β |
vec3 |
β | β |
vec4 |
β | β |
ivec2 |
β | β |
ivec3 |
β | β |
ivec4 |
β | β |
bvec2 |
β | β |
bvec3 |
β | β |
bvec4 |
β | β |
mat2 |
β | β |
mat3 |
β | β |
mat4 |
β | β |
sampler2D |
β | β |
samplerCube |
β | β |
uint |
β | β |
uvec2 |
β | β |
uvec3 |
β | β |
uvec4 |
β | β |
mat2x3 |
β | β |
mat2x4 |
β | β |
mat3x2 |
β | β |
mat3x4 |
β | β |
mat4x2 |
β | β |
mat4x3 |
β | β |
sampler3D |
β | β |
sampler2DArray |
β | β |
sampler2DShadow |
β | β |
samplerCubeShadow |
β | β |
sampler2DArrayShadow |
β | β |
isampler2D |
β | β |
isampler3D |
β | β |
isamplerCube |
β | β |
isampler2DArray |
β | β |
usampler2D |
β | β |
usampler3D |
β | β |
usamplerCube |
β | β |
usampler2DArray |
β | β |
| Type | WebGL 1 | WebGL 2 |
|---|---|---|
float |
β | β |
vec2 |
β | β |
vec3 |
β | β |
vec4 |
β | β |
mat2 |
β | β |
mat3 |
β | β |
mat4 |
β | β |
int |
β | β |
ivec2 |
β | β |
ivec3 |
β | β |
ivec4 |
β | β |
uint |
β | β |
uvec2 |
β | β |
uvec3 |
β | β |
uvec4 |
β | β |
mat2x3 |
β | β |
mat2x4 |
β | β |
mat3x2 |
β | β |
mat3x4 |
β | β |
mat4x2 |
β | β |
mat4x3 |
β | β |