Liquid Glass Easy

The lens and its style

One widget and the descriptor that decides how it looks: shape, appearance, refraction, and the value objects underneath them.

class

LiquidGlassLens#

Extends StatefulWidgetGuide: The lens and its style →

A liquid-glass lens you can place anywhere in the widget tree.

Unlike the children: slot of LiquidGlassView, this lens is layout-driven: it has no position or size parameters — it is exactly where layout puts it and exactly as big as its constraints/child make it (wrap it in a SizedBox to give it explicit dimensions).

Render modes (resolved automatically)

  • Impeller (ImageFilter.isShaderFilterSupported): the lens refracts the live backdrop — whatever your app painted behind it. No LiquidGlassView and no background widget needed at all; drop it over any UI and it works.
  • Skia / Web with an ancestor LiquidGlassView that has a backgroundWidget: the lens refracts the view's captured background, wherever the lens sits inside the view's child.
  • Skia / Web without a view (or without a background): refraction is impossible, so the lens degrades to a frosted look — backdrop blur + tint + border, no refraction — and logs a one-time debug warning.

The mode is an implementation detail: the widget tree you write is identical in all three cases.

Lenses inside scrollables (Impeller)

Android's stretch overscroll effect isolates the scrollable's content into its own compositing layer while the stretch plays. A BackdropFilter-based lens inside that layer can no longer see the real backdrop and renders black at both scroll edges. Disable the overscroll indicator for scrollables that contain lenses:

Dart
ScrollConfiguration(
  behavior: const MaterialScrollBehavior().copyWith(overscroll: false),
  child: ListView(children: [ ...LiquidGlassLens(...)... ]),
)
Dart
SizedBox(
  width: 220,
  height: 120,
  child: LiquidGlassLens(
    style: const LiquidGlassStyle(
      shape: LiquidGlassShape.roundedRectangle(cornerRadius: 36),
    ),
    child: const Center(child: Text('glass')),
  ),
)

Constructors

const LiquidGlassLens({ super.key, this.style = const LiquidGlassStyle(), this.visibility = true, this.useImpellerBackdrop, this.touch, this.deform, this.restSize, this.honorBackdropAlpha = false, this.child })
ParameterTypeDefaultDescription
keyKey?
styleLiquidGlassStyleconst LiquidGlassStyle()The lens's look — its LiquidGlassShape (corners + border), its appearance (tint, blur, saturation) and its refraction (how it bends the content behind it) — bundled as one LiquidGlassStyle. A null style.shape falls back to a default continuous rounded rectangle.
visibilitybooltrueWhether the lens is shown. When false the glass is disabled (no backdrop cost) and the child is removed, so a hidden lens leaves nothing behind. The change is instant — there is no built-in show/hide animation; wrap the lens yourself to animate it.
useImpellerBackdropbool?Override for the Impeller fast-path detection, like LiquidGlassView.useImpellerBackdrop. When null, inherits the ancestor view's setting, falling back to ImageFilter.isShaderFilterSupported.
touchLiquidGlassTouch?How the lens answers a finger — see LiquidGlassTouch. With a LiquidGlassTouch.flex the lens deforms under touch: press it and it compresses, drag it and it elongates along the pull, pinches in the cross axis and leans after your finger, then springs back with a wobble. The lens itself does not move; only its shape and its content deform. null (the default) disables the behaviour entirely — no gesture listener, no ticker, nothing added to the tree. Honored inside a LiquidGlassBlender: the merged metaball silhouette picks a member's deformation up from its resized box. Only LiquidGlassFlexAdvanced.refractionBoost does not survive the merge: a merged member has no refraction band of its own to deepen.
deformLiquidGlassFlexDeform?A deformation supplied from outside, for a host that computes the glass's shape itself instead of letting a finger do it. With touch the lens owns the whole gesture: it listens for pointers and runs its own spring driver. Some hosts cannot work that way — a slider thumb or a nav pill is deformed by where it is being carried, which only the host knows. Passing a deform here skips the listener and the driver entirely and renders exactly what is given. The lens's own box must ALREADY be the deformed size; restSize is what the deformation is measured against, and the shape is evaluated there and stretched by deformed ÷ rest — so a capsule's caps go elliptical instead of being re-rounded at each new size. Both this and restSize must be set for the external path to engage; either one alone is ignored. Takes precedence over touch.
restSizeSize?The undeformed size deform is measured against. See deform.
honorBackdropAlphaboolfalseWhether the shader folds the captured backdrop's alpha into its own coverage — Skia capture path only, ignored on Impeller. false (the default) treats the capture as opaque, which is right for a view whose background is a full page. Set it when the captured background carries authored transparency that must pass through the glass, such as a slider's track, where opaque treatment renders the lens's overhang as a dark body.
childWidget?Content rendered on top of the glass, clipped to the lens shape.

Declared in lib/src/widgets/lens/liquid_glass_lens.dart

class

LiquidGlassLite#

Extends StatelessWidgetGuide: Lite glass →

Glass without the shader: a frosted surface with the lens' own rim light, drawn from plain canvas geometry.

A LiquidGlassLens gets its look from the glass shader: every pixel measures its own distance to the shape's SDF, reads the background under it, bends it, and lights itself. That is what makes the rim feel like an optical consequence of the glass — and it is also why it costs a FragmentProgram, a program warm-up, and (on Impeller) a slot in the lens budget.

This is the light version of that. It gives up refraction, which is the half that needs a shader, and keeps the half that does not: the frost, the rim, and the colour the rim takes off the background.

The rim is the same lighting model, evaluated on the Dart side: the outline is sampled into a ring of points, each point's outward normal is run through the shader's own formulas, and the result is one drawVertices call — a triangle mesh whose vertex colors carry the light around the perimeter and whose alpha carries the falloff across its width. blur is the glass itself; the rim is its edge. No shader asset, no FragmentProgram, nothing to warm up.

It takes the ordinary LiquidGlassShape, so LiquidGlassShape.borderWidth, LiquidGlassShape.lightColor, LiquidGlassShape.lightDirection, LiquidGlassShape.lightIntensity, LiquidGlassShape.lightMode and the OpticalBorder / ClassicBorder parameters mean exactly what they mean on a real lens, at the same numbers. The silhouette comes from the same outline a lens clips to, so all three corner styles — circular, squircle, and the continuous capsule corner — are reproduced exactly.

Taking colour from the background

The shader's rim samples the refracted background under each pixel and tints the highlight with it, so over a photograph the real rim picks the colours up pixel by pixel. There are three answers to that here, and pickup chooses between them — see LiquidGlassLitePickup:

  • LiquidGlassLitePickup.none takes nothing. White light, which is what the shader produces over a neutral background.
  • LiquidGlassLitePickup.blend adds the rim to what is under it instead of covering it, then multiplies its own colour in, so the hue comes through and the light colour shows — blend modes, no read.
  • LiquidGlassLitePickup.surface is the same rim painted over the tint and the child instead of under them, so the tint colours it.
  • LiquidGlassLitePickup.backdrop (the default) cuts the rim out of a brightened copy of the background, so its colour varies along the rim the way the shader's does. It reads the backdrop, so it costs what a lens costs.

ambientColor is the fourth way, and it is orthogonal: hand it one colour — a sampled backdrop, or whatever surface the border sits on — and it goes through the shader's own highlight math, tinting the whole rim at once instead of each pixel. Free, but one tone for the whole outline.

There is no refraction in any mode — no edge bend. magnification is the flat-slab half only; the rim itself does not shift with the content behind it the way glass does.

It is an inner border

The rim is clipped to the outline, like a lens clips its shader, so it is drawn strictly INSIDE the box — brightest against the edge and falling away inward, never hanging past it. Give the widget the size of the surface the border belongs to, not a box around it.

When to reach for it

For a surface that is not a lens — a card, a list row, a sheet, a focus ring — and for the many-of-them cases where real lenses would be too expensive: long lists, low-end devices, the web.

Out of the box it frosts and picks its rim colour off the background, which reads closest to the real thing and costs two backdrop reads. Both are switchable, and turning both off leaves one drawVertices — put a fill of your own behind it and it is nearly free:

Dart
LiquidGlassLite(
  shape: const LiquidGlassShape(
    cornerRadius: 22,
    borderWidth: 1.5,
    lightDirection: 90,
  ),
  child: const Text('on the glass'),
)
Dart
LiquidGlassLite(
  blur: const LiquidGlassBlur(),
  pickup: LiquidGlassLitePickup.surface,
  shape: shape,
  child: child,
)

Constructors

const LiquidGlassLite({ super.key, this.shape = const LiquidGlassShape(), this.borderAlpha = 1.0, this.blur = const LiquidGlassBlur(sigmaX: 3, sigmaY: 3), this.magnification = 1.0, this.pickup = LiquidGlassLitePickup.backdrop, this.color, this.blendFloor = 0.35, this.ambientColor, this.shapeScale = const Offset(1.0, 1.0), this.child, })
ParameterTypeDefaultDescription
keyKey?
shapeLiquidGlassShapeconst LiquidGlassShape()The geometry and lighting to draw, read exactly as a lens reads it.
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.
blurLiquidGlassBlurconst LiquidGlassBlur(sigmaX: 3, sigmaY: 3)How 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' appearance blur does. It defaults to a light 3 — pass const LiquidGlassBlur() for a bare rim over whatever is already there. It costs a backdrop read, and with LiquidGlassLitePickup.backdrop the rim's own read comes on top of it: two reads for a surface that carries both. That is what a blurred lens costs too, so a screen with many of them wants LiquidGlassBlur() here, or LiquidGlassLitePickup.surface there, or both.
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.
pickupLiquidGlassLitePickupLiquidGlassLitePickup.backdropWhether — and how — the rim takes its colour from what is behind it. See LiquidGlassLitePickup.
colorColor?The glass's own tint, LiquidGlassAppearance.color's counterpart: a flat fill of the shape between the frost and child. Under LiquidGlassLitePickup.backdrop and LiquidGlassLitePickup.blend the rim sits over it and never takes colour from it, as on a lens: laid beneath the rim inside the read's own layer, or painted around the rim, cut by the rim's alpha. Under LiquidGlassLitePickup.surface and LiquidGlassLitePickup.none it is a plain fill under the child, and the rim is painted over it. null, or fully transparent, paints nothing.
blendFloordouble0.35How much plain white rim survives underneath LiquidGlassLitePickup.blend and LiquidGlassLitePickup.surface. The blend there is overlay, and overlay multiplies: over black there is nothing to multiply, so the rim would disappear exactly where it shows most. This is the plain rim screened over the blend afterwards, showing through wherever the blend came out empty. It is a straight trade — every bit of floor buys visibility on black with tint on colour. Measured on a red field and a black one, as how far the rim's red runs ahead of its blue, and how bright it is over black: The default now holds MORE colour than LiquidGlassLitePickup.backdrop does (104 at 70) — and that one reads the backdrop to get there. Ignored by the other pickup modes.
ambientColorColor?The background color the highlight is tinted with. The shader samples this per pixel from the refracted backdrop; here it is one color for the whole rim. Null keeps the shader's untinted behavior — a white highlight scaled by LiquidGlassShape.lightColor.
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. When null the widget expands to its constraints and draws the rim alone.

Declared in lib/src/widgets/components/liquid_glass_lite.dart

enum

LiquidGlassLitePickup#

Guide: Lite glass →

Where a painted rim gets its colour — and what that costs.

The shader's rim reads the refracted background under each pixel and tints itself with it, which is why a real lens' border changes colour along its own length as it crosses a photograph. These are the three ways to answer that without a fragment shader, cheapest first.

Values

ValueDescription
noneThe rim carries its own light: one tone, whatever it is over. One drawVertices and nothing else — nothing is read, nothing is layered. The cheap one.
blendThe rim's light is blended into what is under it instead of covering it, so the colour underneath comes through the highlight — and then the rim's own colour is multiplied in over that, so the shape's lightColor and borderColor show the way they do on a lens: a grey light is a grey rim over white, a tint is a tinted rim. The cheap way to look read. Nothing is read back: it is surface's overlay and floor, plus one more pass over the same mesh in multiply. The pass is skipped when the rim's colour is plain white, where it would change nothing.
backdropThe rim is cut out of a brightened, saturated copy of the background, so its colour varies along the rim the way the shader's does: red where it crosses red, blue where it crosses blue, within the one rim. The default. This is the close one, and the expensive one — it reads the backdrop, the same cost a lens pays, plus two layers. Drop to blend or none when a screen has many of them. Two things still part company with the shader: the colour transform is a matrix, so it cannot renormalise a dark background the way the shader's divide-by-luma does (over near black the rim reads grey where the shader reads white), and LiquidGlassLite.ambientColor is not read — the background is the ambient. lightColor scales the rim as it does in the shader, so a grey light is a grey rim over white; borderColor scales it too, rather than replacing it. borderSaturation rides in the colour matrix for free. It reads the background — the frosted, magnified backdrop and nothing else, as the shader samples its rim colour before the tint goes on. The rim sits over LiquidGlassLite.color and under LiquidGlassLite.child, so neither one bleeds into it; the child paints over the rim, as it does over a lens.
surfaceblend's rim, painted over the finished surface instead: the frost, then LiquidGlassLite.color, then LiquidGlassLite.child, and the rim blends into all three. A tinted glass tints its rim, and a label that runs under the edge shows along it. The rim is the topmost thing in the box, over the child. Same passes, same cost, no read.

Declared in lib/src/widgets/components/liquid_glass_lite.dart

The look of a liquid-glass surface, bundled into one reusable descriptor: its shape (corners + border), its appearance (fill tint, blur, saturation, inner transparency) and its refraction (how it bends the content behind it).

This is the single styling vocabulary shared across the library — LiquidGlassLens, the internal lens config, and the components (buttons, bars, the nav pill, …) all describe their glass with the same object. A surface is fully geometry (where + how big) + style (how it looks) + behavior (how it acts).

Non-refracting consumers — e.g. the static (non-glass) selection pill or the frosted fallback — read the subset they can render (shape + appearance) and simply ignore refraction.

Dart
const LiquidGlassStyle(
  shape: LiquidGlassShape.continuousRoundedRectangle(cornerRadius: 24),
  appearance: LiquidGlassAppearance(color: Color(0x22FFFFFF)),
  refraction: LiquidGlassRefraction(distortion: 0.08),
);

Constructors

const LiquidGlassStyle({ this.shape, this.appearance = const LiquidGlassAppearance(), this.refraction = const LiquidGlassRefraction(), this.adaptivity, this.liteGlass, })
ParameterTypeDefaultDescription
shapeLiquidGlassShape?Corners + border of the surface. When null, the consumer picks a sensible default (e.g. the nav pill falls back to a height-tracking capsule), so a style can describe appearance/refraction without pinning the shape.
appearanceLiquidGlassAppearanceconst LiquidGlassAppearance()Fill tint, blur, saturation and inner transparency.
refractionLiquidGlassRefractionconst LiquidGlassRefraction()How the glass bends the content behind it. Ignored by non-refracting consumers.
adaptivityLiquidGlassAdaptivity?iOS-style adaptivity: glass tint + content color flip between two palettes based on the background behind the lens. null (default) disables the feature entirely. Honored by LiquidGlassLens; while active, its glass color overrides appearance's color.
liteGlassLiquidGlassLitePickup?Draw this surface as LiquidGlassLite — frost, tint and a lit rim, no shader and no refraction — whatever engine the app is on, with the rim's colour taken from here: LiquidGlassLitePickup.backdrop reads the background so the colour varies along the rim as the shader's does; blend keeps the tint out of the rim without the read; surface lets the tint and the content colour it; none is white light. null (the default) leaves the choice to the engine switches on LiquidGlassEngine; a lens drawn lite by those, or while the shaders load, takes its rim from LiquidGlassEngine.litePickup instead.

Methods

SignatureDescription
LiquidGlassStyle copyWith({ LiquidGlassShape? shape, LiquidGlassAppearance?…Returns a copy with the given fields replaced.
LiquidGlassStyle merge(LiquidGlassStyle? other)Overlays other on top of this style: other's appearance and refraction replace this one's, and its shape, adaptivity and liteGlass win when set (falling back to this style's when null). Returns this style unchanged when other is null. Useful for a base/theme style with per-surface overrides.

Declared in lib/src/widgets/liquid_glass_style.dart

The geometry, border and lighting of a liquid-glass lens.

One concrete class: the corner curve is chosen by cornerStyle (or one of the LiquidGlassShape.rounded / LiquidGlassShape.squircle / LiquidGlassShape.continuous convenience constructors). Border styling is shared across both classic and optical border modes; mode-specific parameters are encapsulated in borderType.

Constructors

const LiquidGlassShape({ this.cornerStyle = LiquidGlassCornerStyle.continuousRoundedRectangle, this.cornerRadius = 50.0, this.clipQuality = LiquidGlassClipQuality.roundedRectangle, this.borderWidth = 1.0, this.borderColor, this.lightIntensity = 1.0, this.lightColor = const Color(0xB2FFFFFF), this.lightDirection = 0.0, this.lightMode = LiquidGlassLightMode.edge, this.borderType = const OpticalBorder(), })
ParameterTypeDefaultDescription
cornerStyleLiquidGlassCornerStyleLiquidGlassCornerStyle.continuousRoundedRectangleThe corner curve. See LiquidGlassCornerStyle.
cornerRadiusdouble50.0The corner radius in logical pixels.
clipQualityLiquidGlassClipQualityLiquidGlassClipQuality.roundedRectangleWhether the lens is clipped with the cheap circular rounded rectangle (ClipRRect) or an exact ClipPath matching this shape's shader corner. See LiquidGlassClipQuality. Defaults to LiquidGlassClipQuality.roundedRectangle.
borderWidthdouble1.0The thickness of the lens border in logical pixels. Increasing this value makes the border appear thicker around the lens perimeter.
borderColorColor?The base color of the lens border. If not null, this will replace the light and shadow color. It's a solid color.
lightIntensitydouble1.0The brightness multiplier for lens lighting and reflections. Controls how strongly highlights and shadows appear on the border. - Typical range: 0.0 (no lighting) → 1.0 (normal brightness) → >1.0 (strong glow).
lightColorColorconst Color(0xB2FFFFFF)The primary highlight color applied to illuminated areas of the lens border. Used in both classic mode (sweep gradient highlight) and optical mode (specular boost highlights). Usually a lighter tint such as white or pale yellow.
lightDirectiondouble0.0The directional angle (in degrees) from which the simulated light hits the lens. - means light comes from the right. - 90° means light comes from the top. - 180° from the left, and 270° from the bottom. Used to compute where highlights and shadows fall on the border.
lightModeLiquidGlassLightModeLiquidGlassLightMode.edgeDefines how lighting is calculated along the liquid glass border. • LiquidGlassLightMode.edge — Uses the shape's edge gradient as the surface normal, producing lighting that follows the contour of the glass border and the light to expand along straight edges. This results in more physically accurate edge highlights. • LiquidGlassLightMode.radial — Uses a radial direction from the center of the glass to each fragment, causing the light to expand naturally along curved edges creating a uniform, lens-like lighting sweep around the border.
borderTypeLiquidGlassBorderTypeconst OpticalBorder()Defines the rendering style and mode-specific parameters for the border. - ClassicBorder — Sweep gradient with light/shadow colors and softness. - OpticalBorder — Apple-style SDF rim light with ambient tinting and saturation. Defaults to OpticalBorder.
const LiquidGlassShape.roundedRectangle({ double cornerRadius = 50.0, LiquidGlassClipQuality clipQuality = LiquidGlassClipQuality.roundedRectangle, double borderWidth = 1.0, Color? borderColor, double lightIntensity = 1.0, Color lightColor = const Color(0xB2FFFFFF), double lightDirection = 0.0, LiquidGlassLightMode lightMode = LiquidGlassLightMode.edge, LiquidGlassBorderType borderType = const OpticalBorder(), })

A plain circular rounded rectangle (LiquidGlassCornerStyle.roundedRectangle). The cheapest style.

ParameterTypeDefaultDescription
cornerRadiusdouble50.0The corner radius in logical pixels.
clipQualityLiquidGlassClipQualityLiquidGlassClipQuality.roundedRectangleWhether the lens is clipped with the cheap circular rounded rectangle (ClipRRect) or an exact ClipPath matching this shape's shader corner. See LiquidGlassClipQuality. Defaults to LiquidGlassClipQuality.roundedRectangle.
borderWidthdouble1.0The thickness of the lens border in logical pixels. Increasing this value makes the border appear thicker around the lens perimeter.
borderColorColor?The base color of the lens border. If not null, this will replace the light and shadow color. It's a solid color.
lightIntensitydouble1.0The brightness multiplier for lens lighting and reflections. Controls how strongly highlights and shadows appear on the border. - Typical range: 0.0 (no lighting) → 1.0 (normal brightness) → >1.0 (strong glow).
lightColorColorconst Color(0xB2FFFFFF)The primary highlight color applied to illuminated areas of the lens border. Used in both classic mode (sweep gradient highlight) and optical mode (specular boost highlights). Usually a lighter tint such as white or pale yellow.
lightDirectiondouble0.0The directional angle (in degrees) from which the simulated light hits the lens. - means light comes from the right. - 90° means light comes from the top. - 180° from the left, and 270° from the bottom. Used to compute where highlights and shadows fall on the border.
lightModeLiquidGlassLightModeLiquidGlassLightMode.edgeDefines how lighting is calculated along the liquid glass border. • LiquidGlassLightMode.edge — Uses the shape's edge gradient as the surface normal, producing lighting that follows the contour of the glass border and the light to expand along straight edges. This results in more physically accurate edge highlights. • LiquidGlassLightMode.radial — Uses a radial direction from the center of the glass to each fragment, causing the light to expand naturally along curved edges creating a uniform, lens-like lighting sweep around the border.
borderTypeLiquidGlassBorderTypeconst OpticalBorder()Defines the rendering style and mode-specific parameters for the border. - ClassicBorder — Sweep gradient with light/shadow colors and softness. - OpticalBorder — Apple-style SDF rim light with ambient tinting and saturation. Defaults to OpticalBorder.
const LiquidGlassShape.squircle({ double cornerRadius = 50.0, LiquidGlassClipQuality clipQuality = LiquidGlassClipQuality.roundedRectangle, double borderWidth = 1.0, Color? borderColor, double lightIntensity = 1.0, Color lightColor = const Color(0xB2FFFFFF), double lightDirection = 0.0, LiquidGlassLightMode lightMode = LiquidGlassLightMode.edge, LiquidGlassBorderType borderType = const OpticalBorder(), })

An L^n squircle rounded rectangle (LiquidGlassCornerStyle.squircle) — iOS-style continuous-curvature corners.

ParameterTypeDefaultDescription
cornerRadiusdouble50.0The corner radius in logical pixels.
clipQualityLiquidGlassClipQualityLiquidGlassClipQuality.roundedRectangleWhether the lens is clipped with the cheap circular rounded rectangle (ClipRRect) or an exact ClipPath matching this shape's shader corner. See LiquidGlassClipQuality. Defaults to LiquidGlassClipQuality.roundedRectangle.
borderWidthdouble1.0The thickness of the lens border in logical pixels. Increasing this value makes the border appear thicker around the lens perimeter.
borderColorColor?The base color of the lens border. If not null, this will replace the light and shadow color. It's a solid color.
lightIntensitydouble1.0The brightness multiplier for lens lighting and reflections. Controls how strongly highlights and shadows appear on the border. - Typical range: 0.0 (no lighting) → 1.0 (normal brightness) → >1.0 (strong glow).
lightColorColorconst Color(0xB2FFFFFF)The primary highlight color applied to illuminated areas of the lens border. Used in both classic mode (sweep gradient highlight) and optical mode (specular boost highlights). Usually a lighter tint such as white or pale yellow.
lightDirectiondouble0.0The directional angle (in degrees) from which the simulated light hits the lens. - means light comes from the right. - 90° means light comes from the top. - 180° from the left, and 270° from the bottom. Used to compute where highlights and shadows fall on the border.
lightModeLiquidGlassLightModeLiquidGlassLightMode.edgeDefines how lighting is calculated along the liquid glass border. • LiquidGlassLightMode.edge — Uses the shape's edge gradient as the surface normal, producing lighting that follows the contour of the glass border and the light to expand along straight edges. This results in more physically accurate edge highlights. • LiquidGlassLightMode.radial — Uses a radial direction from the center of the glass to each fragment, causing the light to expand naturally along curved edges creating a uniform, lens-like lighting sweep around the border.
borderTypeLiquidGlassBorderTypeconst OpticalBorder()Defines the rendering style and mode-specific parameters for the border. - ClassicBorder — Sweep gradient with light/shadow colors and softness. - OpticalBorder — Apple-style SDF rim light with ambient tinting and saturation. Defaults to OpticalBorder.
const LiquidGlassShape.continuousRoundedRectangle({ double cornerRadius = 50.0, LiquidGlassClipQuality clipQuality = LiquidGlassClipQuality.roundedRectangle, double borderWidth = 1.0, Color? borderColor, double lightIntensity = 1.0, Color lightColor = const Color(0xB2FFFFFF), double lightDirection = 0.0, LiquidGlassLightMode lightMode = LiquidGlassLightMode.edge, LiquidGlassBorderType borderType = const OpticalBorder(), })

An Apple capsule-style continuous rounded rectangle (LiquidGlassCornerStyle.continuousRoundedRectangle).

ParameterTypeDefaultDescription
cornerRadiusdouble50.0The corner radius in logical pixels.
clipQualityLiquidGlassClipQualityLiquidGlassClipQuality.roundedRectangleWhether the lens is clipped with the cheap circular rounded rectangle (ClipRRect) or an exact ClipPath matching this shape's shader corner. See LiquidGlassClipQuality. Defaults to LiquidGlassClipQuality.roundedRectangle.
borderWidthdouble1.0The thickness of the lens border in logical pixels. Increasing this value makes the border appear thicker around the lens perimeter.
borderColorColor?The base color of the lens border. If not null, this will replace the light and shadow color. It's a solid color.
lightIntensitydouble1.0The brightness multiplier for lens lighting and reflections. Controls how strongly highlights and shadows appear on the border. - Typical range: 0.0 (no lighting) → 1.0 (normal brightness) → >1.0 (strong glow).
lightColorColorconst Color(0xB2FFFFFF)The primary highlight color applied to illuminated areas of the lens border. Used in both classic mode (sweep gradient highlight) and optical mode (specular boost highlights). Usually a lighter tint such as white or pale yellow.
lightDirectiondouble0.0The directional angle (in degrees) from which the simulated light hits the lens. - means light comes from the right. - 90° means light comes from the top. - 180° from the left, and 270° from the bottom. Used to compute where highlights and shadows fall on the border.
lightModeLiquidGlassLightModeLiquidGlassLightMode.edgeDefines how lighting is calculated along the liquid glass border. • LiquidGlassLightMode.edge — Uses the shape's edge gradient as the surface normal, producing lighting that follows the contour of the glass border and the light to expand along straight edges. This results in more physically accurate edge highlights. • LiquidGlassLightMode.radial — Uses a radial direction from the center of the glass to each fragment, causing the light to expand naturally along curved edges creating a uniform, lens-like lighting sweep around the border.
borderTypeLiquidGlassBorderTypeconst OpticalBorder()Defines the rendering style and mode-specific parameters for the border. - ClassicBorder — Sweep gradient with light/shadow colors and softness. - OpticalBorder — Apple-style SDF rim light with ambient tinting and saturation. Defaults to OpticalBorder.

Properties

NameTypeDescription
oneSideLightIntensitydoubleThe one-sided specular highlight intensity. Classic-only: returns the value from ClassicBorder.oneSideLightIntensity in classic mode, and 0.0 for optical mode (which derives its rim from the glass shape and does not use this specular term).
doubleSideLightIntensitydoubleThe double-sided specular highlight intensity. Classic-only: returns the value from ClassicBorder.doubleSideLightIntensity in classic mode, and 0.0 for optical mode (which derives its rim from the glass shape and does not use this specular term).
borderSoftnessdoubleThe border softness (classic only, returns 1.0 for optical).
shadowColorColorThe shadow color (classic only, returns transparent black for optical).
ambientIntensitydoubleThe ambient intensity used by the shader for the optical rim. Returns the user-configurable value from OpticalBorder.ambientIntensity when in optical mode, and 0.0 for classic mode (which doesn't use the ambient term).
borderSaturationdoubleThe border saturation (optical only, returns 1.0 for classic).
borderSoliditydoubleThe optical-mode rim solidity. 0.0 for classic mode (unused there).
lightSpreaddoubleThe optical-mode rim highlight spread. 0.5 (neutral) for classic mode, which doesn't use the directional-rim term.
isOpticalBorderboolWhether the border mode is optical.
borderModeLiquidGlassBorderModeThe border mode as the enum value (for shader uniform).

Declared in lib/src/widgets/utils/liquid_glass_shape.dart

class

LiquidGlassAppearance#

Guide: The lens and its style →

Material group: the lens's appearance — tint, blur, saturation and inner transparency (everything visual that isn't optical refraction).

One of the groups a LiquidGlassStyle is made of.

Constructors

const LiquidGlassAppearance({ this.saturation = 1.0, this.blur = const LiquidGlassBlur(), this.color = Colors.transparent, this.enableInnerRadiusTransparent = false, this.shadow, })
ParameterTypeDefaultDescription
saturationdouble1.0Color saturation of the output (1.0 = unchanged, 0.0 = grayscale).
blurLiquidGlassBlurconst LiquidGlassBlur()Blur applied to the content beneath the glass.
colorColorColors.transparentBase color tint of the lens (often semi-transparent).
enableInnerRadiusTransparentboolfalseWhether the inner, non-distorted region is transparent.
shadowLiquidGlassShadow?Contact shadow around the lens — the soft dark band that hugs its rim and pools underneath, so the glass reads as sitting in the page rather than floating on it. null (the default) draws none. Honored by LiquidGlassLens: the lens wraps itself in the LiquidGlassShadow this describes (its child is ignored), with the ring's corner defaulting to the lens shape's own radius. The wrap lives inside the flex deformation's box, so on a lens given a touch the ring swells, leans and springs back with the body instead of staying frozen on the rest silhouette. Its visible flag composes with the lens's own visibility. Not supported inside a LiquidGlassBlender: a merged metaball silhouette has no single ring to cast.

Methods

SignatureDescription
LiquidGlassAppearance copyWith({ double? saturation, LiquidGlassBlur? blur,…

Declared in lib/src/widgets/liquid_glass_config.dart

class

LiquidGlassRefraction#

Guide: The lens and its style →

Refraction group: how the glass bends light — the optical distortion of the content behind the lens.

One of the groups a LiquidGlassStyle is made of.

Constructors

const LiquidGlassRefraction({ this.distortion = 0.1, this.distortionWidth = 30, this.magnification = 1, this.chromaticAberration = 0.003, this.refractionMode = LiquidGlassRefractionMode.shapeRefraction, this.refractionType, this.diagonalFlip = 0, })
ParameterTypeDefaultDescription
distortiondouble0.1Legacy/default standard distortion strength (0.01.0). Used only when refractionType is null.
distortionWidthdouble30Legacy/default standard distortion-band width, in logical pixels. Used only when refractionType is null.
magnificationdouble1Magnification of the content seen through the lens (1.0 = none).
chromaticAberrationdouble0.003Strength of the chromatic aberration (color-channel separation).
refractionModeLiquidGlassRefractionModeLiquidGlassRefractionMode.shapeRefractionGeometry used to direct the refraction (shape vs. radial).
refractionTypeLiquidGlassRefractionType?Optional calculation-specific controls. When null, distortion and distortionWidth select the standard calculation for backward compatibility. When non-null, those legacy fields are ignored and this object's values are used instead.
diagonalFlipdouble0Diagonal mirroring/flip of the refraction direction.

Properties

NameTypeDescription
effectiveDistortiondoubleStrength fed to the shader's u_distortion uniform. For StandardRefraction this is the legacy distortion. For OpticalRefraction it carries OpticalRefraction.depth — the optical displacement strength rides the same wire, so the shader's physical path scales its travel distance by it.
effectiveRefractionIndexdoubleRefractive index for the optical calculation (1.0 = no bending).
effectiveDistortionWidthdoubleWidth resolved from refractionType, or the legacy distortionWidth.

Methods

SignatureDescription
LiquidGlassRefraction copyWith({ double? distortion, double? distortionWidt…

Declared in lib/src/widgets/liquid_glass_config.dart

The backdrop blur behind the glass, as a pair of sigmas. Separate axes so a bar can blur hard across its short side and barely at all along its length.

Constructors

const LiquidGlassBlur({ this.sigmaX = 0, this.sigmaY = 0, })
ParameterTypeDefaultDescription
sigmaXdouble0The horizontal blur intensity (sigma value). Controls how much the background is blurred horizontally beneath the lens. - Higher values produce a stronger blur along the X-axis.
sigmaYdouble0The vertical blur intensity (sigma value). Controls how much the background is blurred vertically beneath the lens. - Higher values produce a stronger blur along the Y-axis.

Declared in lib/src/widgets/utils/liquid_glass_blur.dart

class

LiquidGlassShadow#

Extends StatelessWidgetGuide: Shadow →

The contact shadow of a glass pill: a soft dark band that hugs the rim and pools underneath, so the glass reads as sitting in the surface rather than floating flat on it.

Wrap the lens, don't go inside it

This is a parent of the glass, not its content:

That placement is the whole point. A lens clips its own child to its outline, so a shadow passed as content can only ever darken the inside — the half that pools below the pill would be cut away, which is the half that actually reads as contact. As a parent it is unclipped, and free to spill past the edge.

It paints behind what it wraps (CustomPaint.painter, before the child), so the glass sits over its own shadow. That is also what keeps a rest state honest: a solid pill drawn over the glass covers the shadow with it, instead of wearing a dark band it should never have.

It never touches what it wraps, so it composes with any lens.

The shape

The shadow is cast by a ring, not by the pill itself: an outer capsule pushed out by 1 px horizontally and blur/2 vertically, minus an inner capsule pulled in by blur/2 vertically. Only a band straddling the rim casts anything, so the middle of the glass stays clear.

That ring is then displaced downward by offset (blur + 2 by default) and blurred. The upper arc lands just inside the top rim; the lower arc lands entirely below the pill. One ring gives both the inner rim contact and the drop beneath.

It composites with BlendMode.multiply, so it darkens whatever is under it — the glass on the inside, the page on the outside — instead of laying flat grey over both.

Under a deformed lens

A squashed or stretched lens keeps its authored corner radius and stretches the whole outline (the shader's u_shapeScale), so its caps go elliptical rather than re-rounding. Pass the same scale the lens is drawn with and the ring follows that ellipse; leave it at (1, 1) and the ring is a plain capsule.

Dart
LiquidGlassShadow(
  child: LiquidGlassLens(...),
)

Constructors

const LiquidGlassShadow({ super.key, this.blur = 3.5, this.opacity = 0.2, this.color = Colors.black, this.offset, this.cornerRadius, this.scale = const Offset(1, 1), this.inset = 0, this.visible = true, this.child, })
ParameterTypeDefaultDescription
keyKey?
blurdouble3.5Blur radius of the shadow, and the vertical thickness of the ring that casts it.
opacitydouble0.2Shadow opacity.
colorColorColors.blackShadow color before opacity.
offsetOffset?Downward displacement of the ring. null uses blur + 2, which is what puts the upper arc inside the rim and the lower arc below the pill.
cornerRadiusdouble?The pill's rest corner radius. null makes it a capsule (half the shorter side of the undeformed box).
scaleOffsetconst Offset(1, 1)The lens's outline stretch — deformed size ÷ rest size. Pass the lens's own value so the ring tracks an elliptical cap; (1, 1) for an undeformed lens.
insetdouble0How far inside the glass the shadow's own pill sits, in logical pixels on every side. 0 (the default) casts from a pill the same size as the lens, so the blurred halo reaches a little past its rim. Raise it to tuck the shadow in — the glass then overhangs its own shadow, which reads as a thinner, tighter contact on a small control where a full-size halo looks like a glow.
visiblebooltrueWhether the shadow is drawn at all. false paints nothing and leaves child untouched, so it can be toggled without changing the widget tree's shape.
childWidget?The glass this shadow belongs to. Sized by the parent; the shadow takes whatever box the child gets.

Declared in lib/src/widgets/components/liquid_glass_shadow.dart

enum

LiquidGlassCornerStyle#

The corner curve of a LiquidGlassShape.

Selects which corner SDF the shader draws and which exact clip path the renderers use. The single axis of variation between the old RoundedRectangleShape / SquircleShape / ContinuousRoundedRectangleShape classes, now an explicit value.

Values

ValueDescription
roundedRectanglePlain circular rounded rectangle — corners are circular arcs of cornerRadius. The cheapest style.
squircleL^n squircle — the corners use the superellipse (L^n-norm) continuous-curvature profile, full iOS-style smoothing. The shader draws the matching squircle* SDF.
continuousRoundedRectangleApple capsule-style continuous rounded rectangle — each corner is an exact circle "belly" plus a tuned G2 shoulder onto each flat edge. The shader draws the matching continuousRoundedRect* SDF; at full radius it degrades to a clean capsule. The default corner style.

Declared in lib/src/widgets/utils/liquid_glass_shape.dart

enum

LiquidGlassClipQuality#

How a lens is clipped to its outline. Every LiquidGlassShape carries its own LiquidGlassShape.clipQuality.

Values

ValueDescription
roundedRectangleCheapest: a plain circular rounded-rectangle clip (ClipRRect). The historic default. Its silhouette is a circular corner even when the shader draws a squircle/continuous corner, so for those shapes the clipped child/blur edge may not perfectly hug the refraction.
exactAn exact ClipPath that matches this shape's shader corner: the squircle L^n curve for LiquidGlassCornerStyle.squircle, the Apple capsule-style curve for LiquidGlassCornerStyle.continuous, and a circular rounded rect for LiquidGlassCornerStyle.circular. Slightly pricier (adds a save layer) but the clipped silhouette lines up exactly with the refraction.

Declared in lib/src/widgets/utils/liquid_glass_shape.dart

enum

LiquidGlassLightMode#

Defines how lighting is calculated along the liquid glass border.

This enum controls how the light interacts with the edges of the liquid glass effect, influencing the highlights and shading along the border.

Values

ValueDescription
edgeUses the shape’s edge gradient as the surface normal. Produces lighting that follows the contour of the glass border, allowing the light to expand along straight edges. This results in more physically accurate edge highlights.
radialUses a radial direction from the center of the glass to each fragment. Causes the light to expand naturally along curved edges, creating a uniform, lens-like lighting sweep around the border.

Declared in lib/src/widgets/utils/liquid_glass_light_mode.dart

class

LiquidGlassBorderType#

Defines the rendering style for the liquid glass border.

OpticalBorder is the default and the one to use: Apple-style SDF rim lighting, derived from the glass shape, tinted by what is behind it. ClassicBorder is the older sweep-gradient rim and is deprecated.

Example:

Dart
// Optical border with saturation boost
LiquidGlassShape.roundedRectangle(
  borderType: OpticalBorder(
    borderSaturation: 1.5,
  ),
)

Constructors

const LiquidGlassBorderType()

Properties

NameTypeDescription
isOpticalboolWhether this is an optical border.
isClassicboolWhether this is a classic border.

Declared in lib/src/widgets/utils/liquid_glass_border_mode.dart

class

ClassicBorder#

Extends LiquidGlassBorderTypeGuide: The lens and its style →

Classic sweep gradient border.

Light and shadow colors sweep around the shape based on the angle between the surface normal and light direction. This produces a clean, stylized border with direct control over light/shadow colors.

Parameters specific to classic mode:

  • borderSoftness — Controls the feathered edge transition.
  • shadowColor — The shadow color on the opposite side.
  • oneSideLightIntensity — One-sided specular highlight strength.
  • doubleSideLightIntensity — Double-sided specular highlight strength.

Deprecated

The rim is drawn rather than derived: a sweep painted from a light angle, with its own colours and its own specular terms, sitting on glass whose every other facet comes out of the shape. OpticalBorder — the default — takes the rim from the shape's own field, picks its colour up from the background, and is what the material means by an edge.

It is not a parameter-for-parameter swap, and it is not meant to be: shadowColor, oneSideLightIntensity and doubleSideLightIntensity have no optical counterpart because the optical rim has no separate light to aim. Reach for OpticalBorder.borderSaturation, OpticalBorder.ambientIntensity, OpticalBorder.borderSolidity and OpticalBorder.lightSpread instead, and borderWidth, lightIntensity, lightColor and lightDirection carry over unchanged — they live on the shape, not on the border type.

Constructors

const ClassicBorder({ this.borderSoftness = 1.0, this.shadowColor = const Color(0x1A000000), this.oneSideLightIntensity = 0.0, this.doubleSideLightIntensity = 0.0, })
ParameterTypeDefaultDescription
borderSoftnessdouble1.0The smoothness or falloff softness of the border edge. A higher value results in a softer, feathered border transition, while a lower value keeps it crisp and sharp.
shadowColorColorconst Color(0x1A000000)The shadow color used on the opposite side of the lens border to enhance depth and contrast. Typically a darker or cooler tone to complement the shared lightColor.
oneSideLightIntensitydouble0.0Controls the intensity of the one-sided specular highlight applied to the glass border. This affects only the specular reflection component and is applied from a single light direction, creating a focused glass-like shine on one side of the border. - 0.0 → Disables the specular highlight entirely. - 1.0 → Default subtle specular reflection. - >1.0 → Produces a stronger, sharper highlight for a more glossy or crystal-like appearance. Recommended range: 0.0 to 2.0. This parameter is classic-only — the optical border derives its rim from the glass shape and does not use these specular terms.
doubleSideLightIntensitydouble0.0Controls the intensity of the double-sided specular highlight. Adds focused specular reflections on both sides of the light axis, simulating light hitting a glass surface from both directions. - 0.0 → Disabled (default). - 1.0 → Subtle double specular. - >1.0 → Stronger highlights on both sides. Recommended range: 0.0 to 2.0. This parameter is classic-only — the optical border derives its rim from the glass shape and does not use these specular terms.

Declared in lib/src/widgets/utils/liquid_glass_border_mode.dart

class

OpticalBorder#

Extends LiquidGlassBorderTypeGuide: The lens and its style →

Apple-style optical border.

The border emerges as an optical consequence of the glass shape, using SDF-based rim lighting with rational falloff, background-tinted highlights, dual-sided specular reflections, and a lens height profile.

The border automatically picks up background color through ambient tinting (always active in optical mode).

Parameters specific to optical mode:

  • borderSaturation — Saturation boost applied to the border color.
  • ambientIntensity — Ambient lighting contribution to the rim.
  • borderSolidity — How much lightIntensity can drive the rim toward a fully opaque/solid look.
  • lightSpread — How far the bright rim highlight wraps around the perimeter (higher = broader).

Constructors

const OpticalBorder({ this.borderSaturation = 1.0, this.ambientIntensity = 1.0, this.borderSolidity = 0.0, this.lightSpread = 0.5, })
ParameterTypeDefaultDescription
borderSaturationdouble1.0Controls the saturation boost applied to the final border color. Values above 1.0 increase color vividness, while values below 1.0 desaturate toward grayscale. - 0.0 — Fully desaturated (grayscale border). - 1.0 — No change (default). - 1.5 — Moderately more vivid. - 2.0 — Strongly saturated. Recommended range: 0.0 to 3.0.
ambientIntensitydouble1.0Controls the ambient lighting contribution to the optical rim. The ambient term is added on top of the directional light strength, brightening the rim uniformly so it remains visible even on the shadow side of the shape. - 0.0 — No ambient contribution (rim only lit from the directional light). - 1.0 — Default ambient gain. - >1.0 — Stronger ambient glow that washes around the entire rim. Recommended range: 0.0 to 5.0.
borderSoliditydouble0.0Controls how much lightIntensity can push the optical rim toward a fully solid (opaque) appearance. By default the optical rim caps its internal light contribution to 1.0 so increasing lightIntensity only modulates visibility within a fixed extent — the rim never goes fully solid. With higher solidity the cap is gradually lifted, allowing high lightIntensity to drive the rim alpha to fully opaque (the older renderer-style behavior). - 0.0 — Translucent rim only (default; current behavior). - 0.5 — Halfway: rim brightens past the cap but stays partially translucent. - 1.0 — Light-driven solid rim (legacy behavior — high lightIntensity makes the rim opaque). Recommended range: 0.0 to 1.0.
lightSpreaddouble0.5Controls how far the bright rim highlight spreads around the perimeter. The optical rim has two overlapping contributions: an angle-independent ambient ring (see ambientIntensity) and a directional highlight that is brightest where the surface faces the light. lightSpread widens or tightens the angular reach of that directional highlight — i.e. how much of the perimeter it wraps across before fading into the ambient ring. - 0.0 — Tight, concentrated highlight on the light-facing sides only. - 0.5 — Default (matches the legacy fixed falloff). - 1.0 — Broad highlight that wraps almost all the way around the rim. Recommended range: 0.0 to 1.0.

Declared in lib/src/widgets/utils/liquid_glass_border_mode.dart

enum

LiquidGlassBorderMode#

For backward compatibility — the enum is still used internally by the shader dispatch logic.

Values

ValueDescription
classic
optical

Declared in lib/src/widgets/utils/liquid_glass_shape.dart

class

LiquidGlassRefractionType#

Base type for a liquid-glass refraction calculation and its controls.

This is independent of LiquidGlassRefractionMode, which selects the geometry that directs the refraction (shape or radial).

Constructors

const LiquidGlassRefractionType()

Properties

NameTypeDescription
widthdoubleWidth of the affected edge band, in logical pixels.
isOpticalboolWhether this selects the physical optical calculation.

Methods

SignatureDescription
LiquidGlassRefractionType withEffectFactor(double factor)Scales the visible effect while preserving calculation semantics.
LiquidGlassRefractionType withWidthFactor(double factor)Scales width only, leaving the strength dials alone. For a surface that grows into its final size, the band has to grow with it — a width authored for the full-size glass is a huge proportion of a small one, so it would swallow the whole surface at the start of the animation.

Declared in lib/src/widgets/utils/liquid_glass_refraction_type.dart

class

StandardRefraction#

Extends LiquidGlassRefractionType

The package's original nonlinear distortion calculation.

Constructors

const StandardRefraction({ this.distortion = 0.1, this.distortionWidth = 30, })
ParameterTypeDefaultDescription
distortiondouble0.1Strength of the anchor-based distortion (0.0-1.0).
distortionWidthdouble30Width of the distortion band around the perimeter, in logical pixels.

Declared in lib/src/widgets/utils/liquid_glass_refraction_type.dart

class

OpticalRefraction#

Extends LiquidGlassRefractionType

A physical refraction approximation based on Snell's law.

Constructors

const OpticalRefraction({ this.refraction = 1.5, this.refractionWidth = 30, this.depth = 0.1, })
ParameterTypeDefaultDescription
refractiondouble1.5Refractive index used by Snell's law — the bending angle. 1.0 produces no bending; common glass is approximately 1.5. The calculation saturates, so the useful range is roughly 1.02.0; much higher values barely change the result (the ray is already fully bent). Use depth to control how much the content moves.
refractionWidthdouble30Width of the affected edge band, in logical pixels — how far in from the rim the bevel ramps from flat to vertical.
depthdouble0.1Optical depth — the strength dial (0.01.0): how far the refracted ray travels, i.e. how much the content behind the glass is displaced. Decoupled from refractionWidth (the band size) and from refraction (the angle): turn this up to bend more, like the old distortion knob, without widening the band.

Declared in lib/src/widgets/utils/liquid_glass_refraction_type.dart

enum

LiquidGlassRefractionMode#

Determines which geometry directs light through the liquid glass surface.

This is independent of LiquidGlassRefractionType, which selects the standard or optical calculation used to bend the sampled background.

Values

ValueDescription
shapeRefractionRefracts light based on the underlying shape geometry. The distortion follows the contours of the glass, creating a more physically accurate refraction effect based on the shape.
radialRefractionRefracts light radially from a central point. Creates a circular distortion pattern, useful for effects like magnifying or warping around a center point.

Declared in lib/src/widgets/utils/liquid_glass_refraction_mode.dart

Comments

Comments are GitHub Discussions — reply from either place.