canvas-renderer 0.1.4

Custom minimal renderer for Saorsa Canvas built on wgpu. Provides GPU rendering with WebGL2/2D fallbacks.
Documentation
// Quad shader for rendering colored rectangles
// Supports both 2D (screen space) and 3D (camera space) rendering

struct VertexInput {
    @location(0) position: vec2<f32>,
    @location(1) uv: vec2<f32>,
}

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) uv: vec2<f32>,
    @location(1) color: vec4<f32>,
}

struct Uniforms {
    // Transform: x, y, width, height
    transform: vec4<f32>,
    // Canvas dimensions: width, height, use_camera (1.0 = yes), reserved
    canvas_size: vec4<f32>,
    // Element color
    color: vec4<f32>,
    // View-projection matrix (used when use_camera = 1.0)
    view_projection: mat4x4<f32>,
}

@group(0) @binding(0)
var<uniform> uniforms: Uniforms;

@vertex
fn vs_main(in: VertexInput) -> VertexOutput {
    var out: VertexOutput;

    // Scale vertex position by element size
    let scaled_pos = in.position * uniforms.transform.zw;

    // Translate to element position
    let world_pos = scaled_pos + uniforms.transform.xy;

    // Check if camera mode is enabled
    if (uniforms.canvas_size.z > 0.5) {
        // 3D mode: Apply view-projection matrix
        // World position is at z=0 for 2D elements rendered in 3D space
        let world_pos_4d = vec4<f32>(world_pos.x, world_pos.y, 0.0, 1.0);
        out.clip_position = uniforms.view_projection * world_pos_4d;
    } else {
        // 2D mode: Convert to normalized device coordinates (-1 to 1)
        // Top-left origin: x goes right (+), y goes down (+)
        let ndc_x = (world_pos.x / uniforms.canvas_size.x) * 2.0 - 1.0;
        let ndc_y = 1.0 - (world_pos.y / uniforms.canvas_size.y) * 2.0;
        out.clip_position = vec4<f32>(ndc_x, ndc_y, 0.0, 1.0);
    }

    out.uv = in.uv;
    out.color = uniforms.color;

    return out;
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    return in.color;
}