@bigmistqke/view.gl
v0.1.9
Published
π Utilities for managing WebGL resources.
Readme
ποΈ @bigmistqke/view.gl
π§ 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
Table of Contents
- π¦ 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
π¦ Install
npm install @bigmistqke/view.glpnpm add @bigmistqke/view.glyarn add @bigmistqke/view.glbun add @bigmistqke/view.glποΈ view.gl
The view system provides type-safe WebGL resource management for uniforms, attributes, and buffers
π Basic Usage
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()ποΈ view
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
π ViewSchema
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
interface ViewSchema {
uniforms: UniformSchema
attributes: AttributeSchema
interleavedAttributes: InterleavedAttributeSchema
buffers: BufferSchema
}π Resource Views
Each view type can be imported individually.
π― uniformView
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 uniformsπ UniformSchema
A 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
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>π attributeView
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)π AttributeSchema
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
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>π interleavedAttributeView
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()π InterleavedAttributeSchema
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
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>ποΈ bufferView
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()π BufferSchema
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')
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>π·οΈ view.gl/tag
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
π Basic Usage
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)π glsl
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);
}
`π§© GLSL Fragment
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);
}
`π Symbol Variables
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.
WebGL Version Support
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;
`π·οΈ Resource Tokens
Utilities for defining WebGL resources directly in GLSL templates. These create metadata that the compile consumes to generate the typesafe schema and view.
π― uniform[kind](name, options?)
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)
π attribute[kind](name, options?)
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)
π interleave(name, layout, options?)
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
βοΈ compile(gl, vertex, fragment, overrideSchema?)
Compiles shaders to a WebGLProgram and extracts typesafe schema and view.
π compile.toQuad(gl, fragment, options?)
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
π compile.toString(shader)
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
π compile.toSchema(shader)
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
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())π οΈ Utils
ποΈ createProgram
Creates and links a WebGL program from vertex and fragment shader sources.
const program = createProgram(gl, vertexShaderSource, fragmentShaderSource)πΌοΈ createTexture
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.
π₯οΈ createFramebuffer
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.
π WebGL Type Compatibility
π― Uniform Types
| 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 | β | β
|
π Attribute Types
| 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 | β | β
|
