aura-gui 0.3.5

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
// Desenfoque: gaussiana separable sobre texturas de media resolución y copia final a la ventana.
// El compuesto con máscara de rectángulo redondeado vive en `shader.wgsl` (`fs_blur`).

struct Params {
    // 1 / tamaño de la textura de destino, para pasar de píxeles a uv.
    inv_size: vec2<f32>,
    direction: vec2<f32>,
    // Desviación y separación entre muestras, en píxeles de la textura de destino.
    sigma: f32,
    stride: f32,
    taps: f32,
    padding: f32,
}

@group(0) @binding(0) var source: texture_2d<f32>;
@group(0) @binding(1) var source_sampler: sampler;
@group(1) @binding(0) var<uniform> params: Params;

struct FullscreenOut {
    @builtin(position) position: vec4<f32>,
    @location(0) uv: vec2<f32>,
}

// Un triángulo que cubre la pantalla: sin buffer de vértices.
@vertex
fn vs_full(@builtin(vertex_index) index: u32) -> FullscreenOut {
    let uv = vec2<f32>(f32((index << 1u) & 2u), f32(index & 2u));
    var out: FullscreenOut;
    out.position = vec4<f32>(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, 0.0, 1.0);
    out.uv = uv;
    return out;
}

@fragment
fn fs_blur_pass(in: FullscreenOut) -> @location(0) vec4<f32> {
    let taps = i32(params.taps);
    let inverse_variance = 1.0 / max(params.sigma * params.sigma, 0.0001);
    var sum = vec4<f32>(0.0);
    var total = 0.0;
    for (var i = -taps; i <= taps; i++) {
        let t = f32(i);
        let weight = exp(-0.5 * t * t * inverse_variance);
        let offset = params.direction * (t * params.stride) * params.inv_size;
        sum += textureSampleLevel(source, source_sampler, in.uv + offset, 0.0) * weight;
        total += weight;
    }
    return sum / total;
}

@fragment
fn fs_blit(in: FullscreenOut) -> @location(0) vec4<f32> {
    return textureSampleLevel(source, source_sampler, in.uv, 0.0);
}