bevy-react 0.5.0

Drive bevy_ui from a React app over an embedded V8 runtime.
Documentation
// Shadow's two non-blur passes (`builtin/shadow.rs::ShadowParams` resolves to
// silhouette-prep → blur H → blur V → combine; the middle two are literally
// `blur.wgsl` — spread rides in blur's radius slot). Mode-switched on
// `params[0].w` — pass-internal, the same precedent as blur's direction and
// bloom's bright/combine. Packing (Length slots arrive physical px):
//
//   params[0] = (spread_px, 0, 0, mode)   mode 0 = prep, 1 = combine
//   params[1] = (offset_x_px, offset_y_px, 0, 0)
//   params[2] = shadow color, linear straight-alpha RGBA
//
// Premultiplied-alpha decisions (contract in `filter_prelude.wgsl`):
// - PREP samples the source's ALPHA at `uv - offset` (shifting the shadow BY
//   +offset — y down, so positive offsets read right/down like CSS) and
//   emits the tinted silhouette already premultiplied:
//   `(color.rgb * color.a, color.a) * silhouette_alpha`. That feeds the blur,
//   which requires premultiplied color anyway.
// - COMBINE is a premultiplied source-over: `capture_texture` (the original
//   content) OVER `source_texture` (the blurred shadow). In the outset region
//   the capture's alpha is 0 and the shadow supplies its own alpha; a fully
//   transparent shadow color returns the capture exactly (the identity
//   contract, `color: "transparent"`).
//
// (The entry point is `fragment`, not `filter` — `filter` is a WGSL reserved
// word.)

#import bevy_react::filter::{
    FullscreenVertexOutput,
    capture_texture,
    source_sampler,
    source_texture,
    uniforms,
}

@fragment
fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
    if uniforms.params[0].w < 0.5 {
        // PREP: offset + tint the alpha silhouette.
        let offset = uniforms.params[1].xy * uniforms.texel_size;
        let silhouette = textureSample(source_texture, source_sampler, in.uv - offset).a;
        let color = uniforms.params[2];
        return vec4<f32>(color.rgb * color.a, color.a) * silhouette;
    }
    // COMBINE: original content over the blurred shadow.
    let content = textureSample(capture_texture, source_sampler, in.uv);
    let shadow = textureSample(source_texture, source_sampler, in.uv);
    return content + shadow * (1.0 - content.a);
}