fresnel_shader 0.1.0
fresnel_shader: ^0.1.0 copied to clipboard
Shader-based Liquid Glass fallback for fresnel. Pure Dart — runs on every platform Flutter targets.
fresnel_shader #
The shader-based Liquid Glass fallback for
fresnel.
Apps should not depend on this package directly. Depend on fresnel, which
uses this automatically on every platform without native glass: Android, web,
Windows, Linux, and iOS below 26.
What it does #
Pure Dart, no native code, so it runs anywhere Flutter does.
ShaderGlassSurface renders fresnel_glass.frag as an ImageFilter.shader
over the backdrop, composed on top of a hardware gaussian:
ui.ImageFilter.compose(
outer: ui.ImageFilter.shader(shader),
inner: ui.ImageFilter.blur(sigmaX: sigma, sigmaY: sigma),
)
Blurring in the filter chain rather than inside the shader matters — Flutter's blur is a tuned separable pass, and a hand-written multi-tap loop is both slower and worse. The shader is left to do only what the built-in filters cannot:
- Edge refraction. A signed-distance field gives a surface normal; samples bend along it, strongest at the rim. This lensing is what separates glass from a frosted pane.
- Specular rim. Directional highlight with an ambient floor so the rim stays legible on dark backgrounds.
- Thickness falloff, so the surface reads as a slab rather than a decal.
- System intensity. The whole effect scales toward "off" with the user's glass-intensity preference, so hand-rendered glass tracks the OS instead of drifting away from it.
FallbackGlassSurface is the last resort — a plain BackdropFilter with a tint
and hairline rim, used on Skia and web where backdrop shaders are unavailable,
and whenever the shader fails to compile.
Precision #
The shader declares precision highp float. mediump's 10-bit mantissa
quantises the displacement into roughly 1.5px of visible banding at typical
thickness values on mobile GPUs.
Notes for anyone writing their own #
Flutter's .frag dialect is GLSL, not SkSL: uniform sampler2D and
texture(sampler, uv) with normalised coordinates. uniform shader and
.eval() are SkSL and fail impellerc with a bare syntax error.
Size a glass surface from inside a Positioned.fill, not from an outer
LayoutBuilder. LayoutBuilder reports the constraints handed down, so any
unbounded parent — a Row, Column, or scrollable — yields infinity and
silently disables the effect.
License #
MIT