glre
v0.45.0
Published
<strong> <samp>
Maintainers
Readme
🌇 glre
glre is a simple glsl and wgsl Reactive Engine on the web and native via TypeScript, React, Solid and more.
Installation
npm install glreDocumentation
Docs : glre Introduction
API : glre API and feature
Guide : Creating a scene
Ecosystem
⛪️ reev: reactive event state manager
🔮 refr: request animation frame
Staying informed
github discussions welcome✨
@tseijp twitter
tsei.jp articles
What does it look like?
import { createRoot } from 'react-dom/client'
import { useGL } from 'glre/react'
import { vec4, uv } from 'glre/node'
const Canvas = () => {
const gl = useGL({ frag: vec4(uv, 0, 1) })
return <canvas ref={gl.ref} />
}
createRoot(document.getElementById('root')).render(<Canvas />)react-native supported (codesandbox demo)
import { GLView } from 'expo-gl'
import { registerRootComponent } from 'expo'
import { useGL } from 'glre/native'
import { vec4, uv } from 'glre/node'
const Canvas = () => {
const gl = useGL({ frag: vec4(uv, 0, 1) })
return <GLView style={{ flex: 1 }} onContextCreate={gl.ref} />
}
registerRootComponent(Canvas)solid js supported (codesandbox demo)
import { render } from 'solid-js/web'
import { onGL } from 'glre/solid'
import { vec4, uv } from 'glre/node'
const Canvas = () => {
const gl = onGL({ frag: vec4(uv, 0, 1) })
return <canvas ref={gl.ref} />
}
render(() => <Canvas />, document.getElementById('root'))esm supported (codesandbox demo)
<canvas id="canvas"></canvas>
<script type="module">
import { createGL } from 'https://esm.sh/glre'
import { vec4, uv } from 'https://esm.sh/node'
const el = document.getElementById('canvas')
createGL({ el, fs: vec4(uv, 0, 1) }).mount()
</script>Node System
glre's node system reconstructs shader authoring through TypeScript syntax, dissolving the boundary between CPU logic and GPU computation. Rather than traditional string-based shader composition, this system materializes shaders as abstract syntax trees, enabling unprecedented code mobility across WebGL2 and WebGPU architectures.
// Shader logic materializes through method chaining
const fragment = vec4(fract(position.xy.div(iResolution)), 0, 1)
.mul(uniform(brightness))
.mix(texture(backgroundMap, uv()), blend)The system operates through proxy objects that capture mathematical operations as node graphs, later transpiled to target shader languages. This deconstructed approach eliminates the traditional separation between shader compilation and runtime execution.
Type System Deconstruction
Traditional shader types dissolve into factory functions that generate node proxies:
// Types emerge from function calls rather than declarations
const position = vec3(x, y, z) // Becomes position node
const transform = mat4().mul(modelView) // Matrix composition
const sampled = texture(map, uv()) // Sampling operationEach operation generates immutable node structures, building computation graphs that exist independently of their eventual compilation target.
Function Composition Reimagined
The Fn constructor dissolves function boundaries, creating reusable computation patterns:
// Functions exist as first-class node compositions
const noise = Fn(([coord]) => {
return sin(coord.x.mul(12.9898))
.add(sin(coord.y.mul(78.233)))
.mul(43758.5453)
.fract()
})
// Composition becomes transparent
const surface = noise(position.xz.mul(scale)).mix(noise(position.xz.mul(scale.mul(2))), 0.5)Control Flow Dissolution
Traditional control structures become node compositions, eliminating imperative sequence:
// Conditional logic as expression trees
If(height.greaterThan(waterLevel), () => {
return grassTexture.sample(worldUV)
}).Else(() => {
return waterTexture.sample(worldUV.add(wave))
})
// Loops decompose into iteration patterns
Loop(samples, ({ i }) => {
accumulator.assign(accumulator.add(sample(position.add(offsets.element(i)))))
})Reactive Uniform Architecture
Uniforms transcend static parameter passing, becoming reactive data channels:
const time = uniform(0) // Creates reactive binding
const amplitude = uniform(1) // Automatic GPU synchronization
// Values flow reactively without explicit updates
const wave = sin(time.mul(frequency)).mul(amplitude)
// Runtime updates propagate automatically
time.value = performance.now() / 1000Attribute Data Streams
Vertex attributes dissolve into data stream abstractions:
// Attributes become typed data channels
const positions = attribute(vertexData) // Raw data binding
const normals = attribute(normalData) // Parallel stream
const uvs = attribute(textureCoords) // Coordinate mapping
// Streams compose transparently
const worldPosition = positions.transform(modelMatrix)
const viewNormal = normals.transform(normalMatrix)Cross-Platform Transparency
The system dissolves platform-specific shader languages into unified abstractions. WebGL2 GLSL and WebGPU WGSL become implementation details, hidden beneath consistent node operations.
// Same code generates different targets
const shader = {
vertex: worldPosition.transform(projectionMatrix),
fragment: lighting(worldNormal, worldPosition),
}
// Backend selection becomes transparent
// WebGL2: Generates GLSL ES 3.0
// WebGPU: Generates WGSLThis architectural dissolution enables shader code to exist as pure mathematical relationships, freed from the constraints of traditional GPU programming models.
