Liquid Glass Easy

Lite glass

The material without the shader: frost, tint and rim, and nothing to compile.

A lens gets its look from a fragment shader: every pixel measures its distance to the shape, reads the background under it, bends it and lights itself. Lite glass gives up the bending — the half that needs a shader — and keeps everything else: the frost, the tint, and the lens' two lights, evaluated on the Dart side with the shader's own formulas and drawn as triangle meshes from plain canvas geometry. No FragmentProgram, nothing to warm up, no capture on Skia, no slot in the lens budget on Impeller.

Three ways in#

It is one material with three doors. Flip the whole app, flip one lens, or use the widget directly on a surface that was never a lens.

Dart
// 1. Every lens in the app — set once, before the first lens builds.
LiquidGlassEngine.liteGlassOnSkia = true;      // Skia and the web
LiquidGlassEngine.liteGlassOnImpeller = true;  // Impeller

// 2. This lens only, on either engine.
LiquidGlassLens(
  style: const LiquidGlassStyle(liteGlass: true),
  child: child,
)

// 3. The widget itself, for a card, a row, a sheet.
LiquidGlassLite(
  shape: const LiquidGlassShape(cornerRadius: 22),
  specular: const LiquidGlassLight.specular(thickness: 8, angle: 90),
  glow: const LiquidGlassLight.glow(angle: 0, intensity: 0.8),
  blur: 3,
  color: const Color(0x33FFFFFF),
  child: child,
)

With an engine switch on, a LiquidGlassView takes no glass capture at all — the adaptive sampler is not a capture and keeps running — and every lens beneath it draws lite glass, the same thing a lens outside any view already draws. That is the way to put the material on a page that has too many lenses for the shader, or on a device that has no time for it, without touching a single lens.

What a lens keeps#

A lens drawn lite keeps its shape, its color, blur and shadow, and its magnification as a flat zoom in the frost's own filter. refractionIndex, refractionWidth and dispersion are gone — there is no edge bend. The rim is the style's specular and glow at the same numbers: thickness, sharpness, angle, spread, intensity and colour mean what they mean on a real lens, and the glow sits under the specular as it does there. The silhouette is the outline a lens clips to, so all three corner styles are reproduced exactly.

What still works, and what does not#

Lite glass changes how a lens is drawn, not what the tree around it does. Everything that never needed the shader keeps working; the two things that are the shader do not.

WhatUnder lite glass
Every componentWorks the same, with no refraction. The slider, the switch, the button, the FAB, the app bar, the tab bar, the dialog, the sheet, the scaffold, the draggable and the motion pill all keep their behaviour, their motion and their shadow; their glass is frost, tint and rim. The tab bar's pillStyle.mode: both is fine on Skia here, since there is no capture to double.
touch / LiquidGlassFlexWorks. The press swell and the drag deform scale the lite outline and its child exactly as they scale the shader's.
adaptivityWorks. The adaptive sampler is not a glass capture and keeps running under the engine switch, so tint and content still flip with the background — on a lens, in an area, through a link, and on the scaffold's system bars.
LiquidGlassScrollEdgeUnchanged. The band never used the shader.
shadowKept. The contact shadow is drawn around the lite outline as it is around the shader's.
LiquidGlassMorphRuns as `plain`. One lens whose outline springs from the old shape to the new; motion is ignored, there is no second blob and no neck, because two lite surfaces cannot be merged into one.
LiquidGlassBlenderDoes not blend. There is no merged pass: every member paints solo as its own lite surface, with its own outline and its own read. No metaball, no shared material.
LiquidGlassBatchShared on Impeller. Each lite frost is its own filter, and inside a batch it reads the batch's copy like any member. Inert on Skia.
RefractionGone, except `magnification`. refractionIndex, refractionWidth and dispersion do nothing; magnification survives as a flat zoom inside the frost's filter.
glowDrawn, under the specular. It is cut from the same read as the specular, so it costs nothing more.
LiquidGlassShadersNothing to compile. ensureLoaded() is harmless and unnecessary; a LiquidGlassView takes no glass capture.

Where the rim gets its colour#

The shader's rim samples the background under each pixel and tints its highlight with it, so over a photograph the rim is red where it crosses red and blue where it crosses blue. Lite glass does the same thing a cheaper way: the rim is cut out of a brightened copy of the background, so its colour runs along it as the shader's does. The tint sits under it and the child over it, and neither enters the read.

What it costs#

  • The frost is one backdrop read. Blur and magnification go through one filter, so adding magnification to a blur adds no read.
  • The rim is a second read — two in all, what a blurred lens costs. The specular and the glow share it. With blur: 0 and magnification at 1 the frost's read goes and only the rim's is left.
  • Lights that draw nothing read nothing. With the specular at intensity: 0 or thickness: 0 and no glow, there is no rim to read for, so with no blur either the widget is a plain tinted shape — the one to reach for in a long list.

LiquidGlassLite

API reference →
const LiquidGlassLite({ super.key, this.shape = const LiquidGlassShape(), this.specular, this.glow, this.borderAlpha = 1.0, this.blur = 3.0, this.magnification = 1.0, this.color, this.shapeScale = const Offset(1.0, 1.0), this.child, })
ParameterTypeDefaultDescription
keyKey?—
shapeLiquidGlassShapeconst LiquidGlassShape()The outline to draw, read exactly as a lens reads it.
specularLiquidGlassLight?—The rim's highlight; null is LiquidGlassLight.specular(). It is read as a lens reads its specular: thickness, sharpness, angle, spread, intensity and colour.
glowLiquidGlassLight?—The rim's soft side light, drawn under the specular and read as a lens reads its glow: thickness, angle, spread, intensity and colour. null draws none.
borderAlphadouble1.0A global multiplier on the rim's opacity, for fading it in and out. The lens uses the same knob for its own show/hide animation.
blurdouble3.0How much the surface frosts what is behind it, inside its own outline. This is the glass itself rather than its edge: a backdrop blur clipped to the shape, painted under child, the same thing a lens' own blur does. A Gaussian sigma; 3 by default, and 0 is a bare rim over whatever is already there. It costs one backdrop read, the surface's only one, so a screen with many of them wants 0 here.
magnificationdouble1.0How much the surface magnifies what is behind it: the backdrop scaled about the shape's centre, evenly, across the whole surface. This is the flat-slab half of a lens' refraction — the content inside the outline stops lining up with the content outside it. It rides in the blur's own filter, so it is free when blur is on. 1.0 is flat.
colorColor?—The glass's own tint, LiquidGlassStyle.color's counterpart: a flat fill of the shape between the frost and child. The rim is painted over it and blends into it. null, or fully transparent, paints nothing.
shapeScaleOffsetconst Offset(1.0, 1.0)The deformation applied to the outline, matching a lens' shape scale: the shape is built at rest size and stretched, so a squeezed circle becomes an ellipse instead of keeping a fixed corner radius.
childWidget?—The content the rim is drawn over: the rim is painted on top of it. When null the widget expands to its constraints and draws the rim alone.

Comments

Comments are GitHub Discussions — reply from either place.