API reference
Every public class, method, and event in @codexo/exojs. Generated from source.
classShaderFilter
A Filter that renders its input through a user-supplied shader, in whichever language the active backend speaks. One filter carries both sources - GLSL for WebGL2, WGSL for WebGPU - on the same Shader contract materials use, and picks between them internally. Supply both and the filter runs unchanged under `backend: 'auto'`, where the engine decides which backend it gets. ## Usage ```ts const filter = new ShaderFilter({ glsl: { fragment: `#version 300 es precision mediump float; uniform sampler2D uTexture; uniform float uTime; in vec2 vUv; out vec4 fragColor; void main() { fragColor = texture(uTexture, vUv); } `, }, wgsl: ` struct Uniforms { uTime: f32 }; @group(0) @binding(1) var uTexture: texture_2d<f32>; @group(0) @binding(2) var uSampler: sampler; @group(1) @binding(0) var<uniform> uniforms: Uniforms; @fragment fn fragmentMain(@location(0) vUv: vec2<f32>) -> @location(0) vec4<f32> { return textureSample(uTexture, uSampler, vUv); } `, uniforms: { uTime: 0 }, }); filter.setUniform('uTime', performance.now() / 1000); sprite.filters = [filter]; ``` ## Auto-bound entries Both languages receive the filter's input texture, the output dimensions and the v-axis orientation, and both see a `vUv` varying running 0..1 across the quad. Declare only the ones the source reads. ### GLSL ```glsl uniform sampler2D uTexture; // the filter's input, texture slot 0 uniform vec2 uResolution; // output dimensions in texels uniform float uOrientation; // sign of the v axis against the effect domain in vec2 vUv; ``` ### WGSL ```wgsl @group(0) @binding(0) var<uniform> uResolution: vec2<f32>; @group(0) @binding(1) var uTexture: texture_2d<f32>; @group(0) @binding(2) var uSampler: sampler; @group(0) @binding(3) var<uniform> uOrientation: f32; ``` ## Sampling and the v axis `vUv` addresses the input in TEXEL space: sampling `uTexture` at `vUv` reproduces the input unchanged, whatever the effect domain looks like. The two backends store that domain the other way up, though - a WebGL2 render texture bottom-up, a WebGPU one top-down - so `v` runs downwards through the effect on one and upwards on the other. `uOrientation` is the sign that relates the two: `+1` where `v` grows ALONG the effect domain's y axis (downwards) and `-1` where it grows against it. Multiply the v component of any DIRECTIONAL offset by it and one source behaves identically on both backends: ```glsl // Read the texel `dy` below this one, on either backend. vec4 below = texture(uTexture, vUv + vec2(0.0, dy * uOrientation)); ``` Offsets that are not directional - a radial blur kernel, a symmetric neighbourhood, anything that only recolours its own texel - need nothing. The same sign also maps `vUv` onto a texture sampled ALONGSIDE the input (a displacement or mask map, whose own row 0 is its top on both backends): `0.5 + (vUv.y - 0.5) * uOrientation` is that texture's v. ## User uniforms A source built with createFilterShader can declare its uniforms, in which case the engine generates both languages' declarations from one layout and uniforms becomes a namespace of typed accessors: ```ts const shader = createFilterShader({ glsl: { fragment }, wgsl, uniforms: { uTime: UniformType.Float }, }); const filter = ShaderFilter.from(shader); filter.uniforms.uTime.set(elapsed); ``` Both bodies then read through the instance name `uniforms`, textures are declared in `textures`, and setUniform is gone from the type. Without a declaration the source keeps today's contract: anything in uniforms is bound after the auto-binds, GLSL resolves them by name with texture uniforms claiming slots 1..N, and WGSL packs every non-texture uniform into one buffer at `@group(1) @binding(0)`, each in a 16-byte slot **in declaration order**, binding texture uniforms from `@group(1) @binding(1)` onwards, each followed by its sampler. ## Missing sources A filter that carries only one language throws ShaderFilterBackendError when it attaches to a backend speaking the other one - before it compiles or allocates anything.
import { ShaderFilter } from '@codexo/exojs'A Filter that renders its input through a user-supplied shader, in whichever language the active backend speaks.
One filter carries both sources - GLSL for WebGL2, WGSL for WebGPU - on the same Shader contract materials use, and picks between them internally. Supply both and the filter runs unchanged under `backend: 'auto'`, where the engine decides which backend it gets.
## Usage
```ts const filter = new ShaderFilter({ glsl: { fragment: `#version 300 es precision mediump float; uniform sampler2D uTexture; uniform float uTime; in vec2 vUv; out vec4 fragColor; void main() { fragColor = texture(uTexture, vUv); } `, }, wgsl: ` struct Uniforms { uTime: f32 };
@group(0) @binding(1) var uTexture: texture_2d<f32>; @group(0) @binding(2) var uSampler: sampler; @group(1) @binding(0) var<uniform> uniforms: Uniforms;
@fragment fn fragmentMain(@location(0) vUv: vec2<f32>) -> @location(0) vec4<f32> { return textureSample(uTexture, uSampler, vUv); } `, uniforms: { uTime: 0 }, });
filter.setUniform('uTime', performance.now() / 1000); sprite.filters = [filter]; ```
## Auto-bound entries
Both languages receive the filter's input texture, the output dimensions and the v-axis orientation, and both see a `vUv` varying running 0..1 across the quad. Declare only the ones the source reads.
### GLSL
```glsl uniform sampler2D uTexture; // the filter's input, texture slot 0 uniform vec2 uResolution; // output dimensions in texels uniform float uOrientation; // sign of the v axis against the effect domain in vec2 vUv; ```
### WGSL
```wgsl @group(0) @binding(0) var<uniform> uResolution: vec2<f32>; @group(0) @binding(1) var uTexture: texture_2d<f32>; @group(0) @binding(2) var uSampler: sampler; @group(0) @binding(3) var<uniform> uOrientation: f32; ```
## Sampling and the v axis
`vUv` addresses the input in TEXEL space: sampling `uTexture` at `vUv` reproduces the input unchanged, whatever the effect domain looks like. The two backends store that domain the other way up, though - a WebGL2 render texture bottom-up, a WebGPU one top-down - so `v` runs downwards through the effect on one and upwards on the other.
`uOrientation` is the sign that relates the two: `+1` where `v` grows ALONG the effect domain's y axis (downwards) and `-1` where it grows against it. Multiply the v component of any DIRECTIONAL offset by it and one source behaves identically on both backends:
```glsl // Read the texel `dy` below this one, on either backend. vec4 below = texture(uTexture, vUv + vec2(0.0, dy * uOrientation)); ```
Offsets that are not directional - a radial blur kernel, a symmetric neighbourhood, anything that only recolours its own texel - need nothing. The same sign also maps `vUv` onto a texture sampled ALONGSIDE the input (a displacement or mask map, whose own row 0 is its top on both backends): `0.5 + (vUv.y - 0.5) * uOrientation` is that texture's v.
## User uniforms
A source built with createFilterShader can declare its uniforms, in which case the engine generates both languages' declarations from one layout and uniforms becomes a namespace of typed accessors:
```ts const shader = createFilterShader({ glsl: { fragment }, wgsl, uniforms: { uTime: UniformType.Float }, });
const filter = ShaderFilter.from(shader);
filter.uniforms.uTime.set(elapsed); ```
Both bodies then read through the instance name `uniforms`, textures are declared in `textures`, and setUniform is gone from the type.
Without a declaration the source keeps today's contract: anything in uniforms is bound after the auto-binds, GLSL resolves them by name with texture uniforms claiming slots 1..N, and WGSL packs every non-texture uniform into one buffer at `@group(1) @binding(0)`, each in a 16-byte slot **in declaration order**, binding texture uniforms from `@group(1) @binding(1)` onwards, each followed by its sampler.
## Missing sources
A filter that carries only one language throws ShaderFilterBackendError when it attaches to a backend speaking the other one - before it compiles or allocates anything.
new(options: ShaderFilterOptionsConstruction options for a ShaderFilter.<F, B>): ShaderFilter<F, B>apply(backend: RenderBackend, input: RenderTextureAn off-screen render target that can also be sampled as a texture. Combines RenderTarget (framebuffer attachment) with the sampler parameters of a Texture (sca…, output: RenderTextureAn off-screen render target that can also be sampled as a texture. Combines RenderTarget (framebuffer attachment) with the sampler parameters of a Texture (sca…, resolution: number): voiddestroy(): voidgetOutputBounds(input: ReadonlyRectangleRead-only view of a Rectangle: every accessor and non-mutating query a rectangle offers, with none of its writers. Returned by APIs that hand out a LIVE intern…, output: RectangleMutable axis-aligned rectangle defined by a top-left origin `(x, y)` and dimensions `(width, height)`. Implements Collidable with full SAT collision response f…): voidinvalidate(): voidsetUniform(name: ShaderFilterRawUniformNameA uniform name the raw path accepts; `never` once a schema is declared.<F, B>, value: ShaderFilterUniformValueA scalar number, vector tuple, typed array, or texture - the value types a ShaderFilter accepts for a user uniform and marshals to the active backend.): thissetUniforms(values: Readonly<Record<string, ShaderFilterUniformValueA scalar number, vector tuple, typed array, or texture - the value types a ShaderFilter accepts for a user uniform and marshals to the active backend.>>): thisfrom(source: ShaderImmutable shader source pair shared by Material instances. `Shader` owns only the GLSL/WGSL text and its stable identity; it carries no uniform/texture state (…<F, B>, options?: Omit<ShaderFilterOptionsConstruction options for a ShaderFilter.<F, B>, "autoUpgrade" | "glsl" | "shader" | "wgsl">): ShaderFilter<F, B>resolution: TargetResolution