filtrate 0.2.0

GPU texture filter library: built-in filters (blur, brightness, color matrix, ...) and runtime, built on filtrate-core.
Documentation
// Line halftone: black ink lines on white paper, line width proportional to
// darkness — the print-screen convention (dark input → thick lines).
//
// Parameters: scale (line pitch in pixels), angle (degrees), center.x,
// center.y (uv space). Lines are antialiased over a one-pixel band.

@compute @workgroup_size(WORKGROUP_X, WORKGROUP_Y)
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
    let dims = vec2<u32>(uniforms.output_dimensions);
    if gid.x >= dims.x || gid.y >= dims.y {
        return;
    }
    let scale = max(param(0u), 2.0);
    let angle = param(1u) * DEGREES_TO_RADIANS;
    let center = vec2<f32>(param(2u), param(3u));
    let uv = output_uv(gid.xy);
    let base = load_input(map_to_input(gid.xy));

    let rel = (uv - center) * uniforms.output_dimensions;
    let rotated = sin(angle) * rel.x + cos(angle) * rel.y;
    // 0 at the stripe center, 1 halfway to the next stripe.
    let stripe = abs(fract(rotated / scale) - 0.5) * 2.0;

    let ink = 1.0 - luminance(base.rgb);
    // One-pixel antialiasing band, expressed in stripe units.
    let aa = 2.0 / scale;
    let coverage = 1.0 - smoothstep(ink - aa, ink + aa, stripe);
    let value = 1.0 - coverage;
    textureStore(
        output_texture,
        vec2<i32>(gid.xy),
        vec4<f32>(vec3<f32>(value * base.a), base.a),
    );
}