Skip to content

Welcome to FragmentColor!

FragmentColor is a cross-platform GPU programming library for Rust, JavaScript, Python, Swift, and Kotlin.

It directly targets each platform’s native graphics API: Vulkan, Metal, DirectX, OpenGL, WebGL, or WebGPU.

See Platform Support for details.

The API encourages a simple shader composition workflow. You can use WGSL or GLSL shaders as the source of truth for visual consistency across platforms, while avoiding the boilerplate needed to make modern GPU rendering work.

Check the Documentation and the API Reference for more information.

Follow the project on GitHub to stay tuned on the latest updates.

Terminal window
npm install fragmentcolor
import init, { Renderer, Shader, Pass, Frame } from "fragmentcolor";
async function start() {
// Initializes the WASM module
await init();
// Initializes a renderer and a target compatible with the given canvas
const canvas = document.getElementById("my-canvas");
const renderer = new Renderer();
const target = await renderer.createTarget(canvas);
// You can pass the shader as a source string, file path, or URL:
const circle = new Shader("./path/to/circle.wgsl");
const triangle = new Shader("https://fragmentcolor.org/shaders/triangle.wgsl");
const shader = new Shader(`
28 collapsed lines
struct VertexOutput {
@builtin(position) coords: vec4<f32>,
}
struct MyStruct {
my_field: vec3<f32>,
}
@group(0) @binding(0)
var<uniform> my_struct: MyStruct;
@group(0) @binding(1)
var<uniform> my_vec2: vec2<f32>;
@vertex
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> VertexOutput {
const vertices = array(
vec2( -1., -1.),
vec2( 3., -1.),
vec2( -1., 3.)
);
return VertexOutput(vec4<f32>(vertices[in_vertex_index], 0.0, 1.0));
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(my_struct.my_field, 1.0);
}
`);
// The library binds and updates the uniforms automatically
shader.set("my_struct.my_field", [0.1, 0.8, 0.9]);
shader.set("my_vec2", [1.0, 1.0]);
// One shader is all you need to render
renderer.render(circle, target);
// But you can also combine multiple shaders in a render Pass
const rpass = new Pass("single pass");
rpass.addShader(circle);
rpass.addShader(triangle);
rpass.addShader(shader);
renderer.render(rpass, target);
// Finally, you can combine multiple passes in a Frame
const frame = new Frame();
frame.addPass(rpass);
frame.addPass(new Pass("GUI pass"));
renderer.render(frame, target);
// To animate, simply update the uniforms in a loop
function animate() {
circle.set("position", [0.0, 0.0]);
renderer.render(frame, target);
requestAnimationFrame(animate);
}
animate();
}
start();