liquid_glass_widgets 0.7.13
liquid_glass_widgets: ^0.7.13 copied to clipboard
A Flutter UI kit implementing the iOS 26 Liquid Glass design language. Features shader-based glassmorphism, physics-driven jelly animations, and dynamic lighting.
0.7.13 #
New — GlassQuality.minimal #
-
FEAT:
GlassQuality.minimal— third quality tier: a crisp frosted glass surface with zero custom fragment shader execution on any platform. UsesBackdropFilterblur- Rec. 709 saturation matrix + a light-angle specular rim stroke. No refraction warping or chromatic aberration — a deliberately flat, clean aesthetic that looks excellent on any background and never adds GPU shader cost.
Two distinct use cases:
Device fallback — for hardware where even [standard] is too heavy: very old Android devices with limited shader driver support, or any device where
ImageFilter.isShaderFilterSupportedreturnsfalse.GPU budget management — for shader-dense screens: use [minimal] for background panels, list cards, and decorative containers while keeping [standard] or [premium] on the focal element. A screen with 15 glass list cards running [minimal] fires zero shader invocations during scroll — only
BackdropFiltercompositing.AdaptiveGlass( quality: GlassQuality.minimal, child: child, ) -
FEAT:
GlassThemeVariant.minimal— static preset that applies.minimalquality globally viaGlassThemeData:GlassTheme( data: GlassThemeData( light: GlassThemeVariant.minimal, dark: GlassThemeVariant.minimal, ), child: child, )
New — GlassPerformanceMonitor #
-
FEAT: Debug/profile-only performance monitor that watches raster frame durations while
GlassQuality.premiumsurfaces are active. When frames exceed the GPU budget for 60 consecutive frames, a singleFlutterErroris emitted with actionable guidance (specific widget parameters, device compatibility notes, and alternative quality tiers).Zero production overhead — the monitor never registers a callback in release builds. Enabled by default in debug/profile builds via
LiquidGlassWidgets.initialize():// Default: auto-enabled in debug/profile, zero-cost in release await LiquidGlassWidgets.initialize(); // Opt out: await LiquidGlassWidgets.initialize(enablePerformanceMonitor: false); // Custom thresholds (advanced): GlassPerformanceMonitor.rasterBudget = const Duration(microseconds: 8333); // 120 fps GlassPerformanceMonitor.sustainedFrameThreshold = 120; // 2 seconds at 60 fpsThe monitor correctly attributes slowdowns to premium glass by counting active
GlassQuality.premiumsurfaces. It stays silent when no premium widgets are mounted, avoiding false positives from other parts of the app.
0.7.12 #
Bug Fixes #
-
FIX: Interactive blend-group stretch asymmetry —
LiquidStretchnow expands geometry symmetrically from the widget centre, fixing the left-leans-in / right-resists imbalance during touch-drag on button groups. -
FIX: Erroneous highlight bias — removed a legacy shader hack that skewed surface normals horizontally. Normals are now derived accurately from the SDF gradient, eliminating optical hotspots that made straight groups look crooked.
-
PERF: Zero-jitter animation bounds — geometry texture mapping is now strictly bound to the physical size it was rasterised for, stopping frame-lag wobble when buttons change scale during interactive drags.
-
FIX: Theme quality cascade — audited 15+ widgets (
GlassBottomBar,GlassSwitch,GlassTextField, and others) that were silently overriding the globalGlassThemeVariantquality setting withGlassQuality.premium. All widgets now correctly inherit and respect the global quality profile, protecting frame rate and thermal limits on older devices (e.g. iPhone 12 and below). -
FIX: Zero-thickness blur — setting
thickness: 0no longer makes the glass fully transparent. Backdrop blur now renders correctly on glass surfaces regardless of geometric thickness, restoring backward-compatible behaviour. -
FEAT:
GlassSearchBarConfig.focusNode— optionalFocusNodeforGlassSearchBarConfig. When provided, the caller has full programmatic focus control (requestFocus(),unfocus(),addListener()) independent ofautoFocusOnExpand. The widget adopts the caller-provided node without disposing it (caller owns lifecycle), matching Flutter's ownTextField.focusNodecontract. -
FEAT:
GlassSearchBar.focusNode— sameFocusNodesupport added to the standaloneGlassSearchBarfor consistency.GlassTextFieldalready had this. -
FIX:
ExtraButtonPosition— new enum onGlassBottomBarExtraButton. Set.position = ExtraButtonPosition.afterSearchto pin the extra button to the right of the search pill. Spring geometry calculations reserve space correctly to preventRenderFlexoverflows during expand/collapse. Default isExtraButtonPosition.beforeSearch— fully backwards-compatible. -
FIX: Windows / SkSL shader compilation — eliminated all dynamic array index expressions from
sdf.glsl. The previousgetShapeSDFFromArray(int index)computed offsets at runtime, which SkSL/glslang on Windows rejects with "index expression must be constant". Replaced with literal-indexedsdf0()…sdf15()helpers and a fully-unrolledsceneSDFfor 1–16 shapes.MAX_SHAPESstays 16; no API or visual change. -
TOOLING:
scripts/validate_shaders.sh— macOS script that validates all shaders against Windows/SkSL compiler rules usingglslangValidator. Runbash scripts/validate_shaders.shbefore releasing. Requiresbrew install glslang(one-time).
0.7.11 #
Bug Fixes #
-
FIX: Windows/Android build failure — three shader compilation errors on the SPIR-V/glslang path: loop bounds must be compile-time constants;
dFdx/dFdyon a scalarfloatis rejected by glslang (geometry shader now uses#ifdef IMPELLER_TARGET_METALto keep hardware derivatives on iOS/macOS and fall back to ±0.5 px finite differences on Vulkan/OpenGL ES); global non-constant initialisers at file scope inliquid_glass_final_render.fragmoved intomain(). -
FIX: Blend-group asymmetry — the liquid-glass merge neck between grouped buttons leaned toward the left button. Fixed with a bidirectional smooth-union pass (L→R + R→L, averaged 50/50) that cancels the directional bias exactly.
0.7.10 #
Bug Fixes #
- FIX: Windows build (
flutter build windows) — two shader issues fatal on SkSL/glslang but silently accepted on Metal:no match for min(int, int)(replaced with a ternary) and global non-constant initialisers (moved intomain()). No visual change on any platform.
0.7.9 #
Bug Fixes #
- FIX: Windows build failure —
uShapeData[MAX_SHAPES * 6]was passed as a by-value function parameter, which glslang rejects. Fixed by accessing it as a global uniform. No visual change.
Tweaks #
- TWEAK:
GlassSearchableBottomBariOS 26 Apple News parity — animated inline×clear button replaces microphone when text is present; simplified hit-testing layout replacesOverlaylayers; guaranteed GPU liquid-glass merging between the search and dismiss pills in a single shader pass.
0.7.8 #
Tweaks #
- TWEAK:
GlassThemeVariant.lightnow defaults to a cool-tintedglassColor(Color(0x32D2DCF0)), strongerrefractiveIndex, and boostedambientStrengthto ensure premium specular rendering and visible refraction on flat white backgrounds.
Examples #
- Apple News demo — replaced
Image.networkcalls with pre-sized bundled assets (example/assets/news_images/) to fix Impeller GPU command-buffer overflow on iOS 26 physical devices. - Apple News demo —
collapsedLogoBuildernow mirrors the active tab icon instead of a static badge.
0.7.7 #
Refactor #
- Internal: Removed
GlassIndicatorTapMixinand migratedGlassTabBarandGlassSegmentedControlfully to rawListenerpointer events, matchingGlassBottomBar's robust drag-cancel and press-and-hold handling. No API change.
0.7.6 #
Bug Fixes #
-
FIX:
LiquidGlassBlendGroupasymmetry — left buttons attracted their neighbours more strongly than right buttons in groups of 3+. Fixed with a bidirectional smooth-union pass (L→R + R→L, averaged 50/50). Two-shape groups are mathematically identical to before. -
FIX:
GlassButtonGroup— glass effect could bleed as a dark rectangle on Impeller withGlassQuality.premiumanduseOwnLayer: true. AClipRRect(antiAlias)now hard-clips the bleed at the superellipse boundary without forcing a quality downgrade.
0.7.5 #
Bug Fixes #
-
FIX:
GlassBottomBar/GlassSearchableBottomBar— addedHitTestBehavior.opaqueto the rootGestureDetectorso the full bar height reliably consumes pointer events on simulator and desktop. -
FIX:
GlassSearchableBottomBar— keyboard no longer flickers on physical devices; focus is requested after the expansion animation completes. -
FIX:
GlassSearchableBottomBar— dead zone at expanded search pill edges resolved; the full glass surface now claims taps and routes them to the search field.
New — GlassSearchBarConfig parameters #
Seven new parameters (all backwards-compatible):
| Parameter | Type | Default | Description |
|---|---|---|---|
autoFocusOnExpand |
bool |
false |
Keyboard opens automatically on expand. |
trailingBuilder |
WidgetBuilder? |
null |
Replaces the mic icon with any custom widget. |
textInputAction |
TextInputAction? |
null |
Keyboard action key (search, done, go, …). |
keyboardType |
TextInputType? |
null |
Keyboard layout (url, emailAddress, …). |
autocorrect |
bool |
true |
Disable for codes, usernames, etc. |
enableSuggestions |
bool |
true |
Controls QuickType bar on iOS. |
onTapOutside |
TapRegionCallback? |
null |
Called when user taps outside the field. |
0.7.4 #
New Components #
GlassSearchableBottomBar—GlassBottomBarwith a morphing search pill that shares the sameAdaptiveLiquidGlassLayeras the tab pill, producing iOS 26 liquid-merge blending. WhenisSearchActiveistruethe tab pill collapses and the search pill expands via spring animation. Configured viaGlassSearchBarConfig.
Examples #
- Apple News demo (
example/lib/apple_news/apple_news_demo.dart) — iOS 26 Apple News replica showcasingGlassSearchableBottomBar.
Visual Fixes #
- FIX: Default glow color on press changed from iOS system blue to a brightness-adaptive neutral white (~35% light / ~22% dark), matching iOS 26 glass press behaviour.
0.7.3 #
Performance #
- PERF: Deleted unused
rotate2d()fromrender.glsl— it was compiled into every shader binary but never called. - PERF: Eliminated a redundant
normalize()ininteractive_indicator.fragby reusing an already-computed length. - PERF: Removed a no-op
canvas.save()/canvas.restore()pair inGlassGlowpaint.
Bug Fixes #
- FIX:
GlassGlowtracking — glow gradient is now correctly recreated each frame whenglowOffsetchanges, fixing the spotlight freezing at its initial position. - FIX: Glow on Skia/Web —
LightweightLiquidGlassnow wraps inGlassGlowLayer, giving the Skia path the same light-follows-touch behaviour as Impeller. - FIX: Glow on first touch — spotlight now appears immediately at the tap position instead of sliding in from the widget's top-left corner.
- FIX: Glow tracking inside button groups — converted from widget-local to global coordinates so the spotlight correctly follows touches regardless of nesting depth.
- FIX: Glow radius on wide buttons — switched from
shortestSideto√(width × height)so the spotlight scales proportionally to the button area.
0.7.2 #
Performance & Polish #
- PERF: Lightweight shader (
lightweight_glass.frag) — reduced ALU instruction count ~10–15 ops per fragment; restored thenormalZFresnel ramp tosqrt(1 − dot(n,n)). - PERF: Impeller final render shader — eliminated
length()/normalize()from anisotropic specular; madegetHeight()fully branchless; collapsed fourstep()multiplications into one. - PERF: Dart side — cached light direction trig in
LiquidGlassRenderObject(only recomputed whenlightAnglechanges); changedGlassGroupLink.shapeEntriesfromListtoIterableto eliminate per-frame heap allocation. - FIX: Adjusted
GlassBottomBar,GlassTabBar, andGlassSegmentedControlspring from 500msbouncySpringto 350mssnappySpring, matching iOS 26 segment-indicator physics.
0.7.1 #
Bug Fixes #
- FIX:
GlassBottomBar,GlassTabBar,GlassSegmentedControl— rapid taps no longer prematurely snap the indicator, killing spring physics. Removed pixel-snapping fromonHorizontalDragDownso taps correctly use spatial distance for the iOS 26 jump animation.
0.7.0 #
New Components #
GlassDivider— iOS 26-style hairline separator, horizontal and vertical. Theme-adaptive opacity (dark: 20% white / light: 10% black).GlassListTile— iOS 26 Settings-style row with leading icon, title, subtitle, trailing widget, and automatic grouped dividers. Use inside a zero-paddingGlassCard. Convenience constants:GlassListTile.chevron,GlassListTile.infoButton.GlassStepper— iOS 26UIStepperequivalent. Compact−/+glass pill with auto-repeat on hold,min/maxclamping,wrapscycling, fractionalstep, and haptic feedback.GlassWizard+GlassWizardStep— multi-step flow with numbered indicators, checkmarks, and expandable step content.
Accessibility #
GlassAccessibilityScope— reads platform Reduce Motion and Reduce Transparency preferences and propagates them to all glass widgets in its subtree:- Reduce Motion: spring animations snap instantly.
- Reduce Transparency: replaces the full glass shader pipeline with a plain
BackdropFilter(blur)+ frosted container.
- Semantics updated across all remaining widgets to match iOS
UIAccessibilityconventions.
Performance #
- PERF:
GlassSpecularSharpnessenum — replacespow(lightCatch, exponent)(two transcendentals per fragment) with a pure squaring chain inlightweight_glass.frag. Zero transcendentals. Default:.medium. - PERF:
pow(x, 1.5)→x·√xin Impeller edge lighting —sqrt()is a single hardware SFU instruction. - PERF: Anisotropic specular and Fresnel rim brightening ported from the Impeller path to
lightweight_glass.frag, closing the largest visual gap between rendering paths. - PERF: Content-adaptive glass strength — intensity auto-adjusts based on backdrop luminance on Impeller, or
MediaQuery.platformBrightnesson Skia/Web.
Developer Experience #
GlassRefractionSource— renamed fromLiquidGlassBackgroundto better reflect its role.LiquidGlassBackgroundremains as a deprecatedtypedef(removed in 1.0.0).- Synchronous background capture — rebuilt using
boundary.toImageSync()on native (zero CPU↔GPU readback) and asynctoImage()on web.
0.6.1 #
Visual Quality #
- FIX: True surface normal storage in geometry texture — the geometry pass now stores the SDF-gradient-derived surface normal instead of the refraction displacement vector. The render shader decodes and recomputes displacement via
refract(). Specular highlights on blended glass shapes (e.g. two overlapping pills) now correctly follow true surface curvature rather than the refraction direction. Single-shape surfaces are visually identical to 0.6.0. - FIX: Anisotropic specular highlights (Impeller) — specular lobe stretched 20% along the surface tangent, producing the horizontal oval highlight that matches iOS 26.
- FIX: Fresnel edge luminosity ramp (Impeller) — gentle brightness ramp at grazing angles matching iOS 26's centre-to-edge luminosity gradient.
- FIX: Luminosity-preserving glass tint in lightweight shader — replaced additive tint with the same
applyGlassColor()model as the Impeller path: achromatic glass lifts toward white, chromatic glass shifts hue while preserving luminance.
Performance #
- PERF: Branchless
smoothUnion— eliminated a conditional branch that caused warp divergence when glass shapes transition between merged and separate. - PERF:
if/else ifdispatch in shape SDF — GPU now short-circuits after the first type match; default changed to0.0for a clearly visible failure mode. - PERF: Single texture fetch when chromatic aberration is disabled —
interactive_indicator.fragpreviously sampled the background three times unconditionally; 66% fewer texture reads in the common case. - PERF: Flat-interior early-exit in final render shader — pixels where
normalXY ≈ 0skiprefract()and all texture samples, replaced with a single background sample. Lossless.
0.6.0 #
Breaking Changes #
LiquidGlassLayer.useBackdropGroupremoved. Glass layers now automatically detect aBackdropGroupancestor. RemoveuseBackdropGroup: truefrom anyLiquidGlassLayer(...)calls.
New Features #
LiquidGlassWidgets.wrap()— wraps your app in aGlassBackdropScopein one line:runApp(LiquidGlassWidgets.wrap(const MyApp()));GlassMotionScope— drives glass specular angle from anyStream<double>(e.g. device gyroscope). No new dependencies required.
Performance #
- PERF:
GlassBackdropScopeauto-activation — glass layers automatically share a single GPU backdrop capture when a scope ancestor is present. - PERF: Local-space geometry rasterization — geometry texture cached until pill size or shape changes, eliminating per-frame rebuilds during animation.
- PERF: Shader UV bounds check — discards fragments where geometry UV falls outside
[0, 1], preventing the thin "protruding line" artifact during jelly-physics expansion.
Visual #
- FIX: Refraction UV — uses
uSizeuniform (always valid on first frame) instead oftextureSize()which returns(0,0)on the first frame in Impeller. - FIX:
precision highp floatin final render shader (wasmediump, risking colour banding on mobile). - FIX: iOS 26 glass tint model — preserves backdrop luminance while shifting chroma. Replaces Photoshop Overlay mode.
- FIX: Leading-dot rim artifact —
x / (1 + x)soft-clamping on highlight intensity prevents bright corner artifact during drag. - FIX: Impeller indicator clipping — jelly physics animations no longer clip at the static bounding box (
clipExpansionparameter added). - FIX: Web & WASM — removed
dart:ioimports from shader resolution logic.
Dependencies #
- Removed
motordependency — replaced with self-containedglass_spring.dart. Zero third-party runtime dependencies beyond the Flutter SDK.
0.5.0 #
Breaking Changes #
LiquidGlass removed from the public API.
It was inadvertently exposed and silently renders nothing on Skia/Web. Use AdaptiveGlass instead:
// Before
LiquidGlass(settings: LiquidGlassSettings(...), child: ...)
// After
AdaptiveGlass(settings: LiquidGlassSettings(...), child: ...)
LiquidGlassLayer, LiquidGlassBlendGroup, LiquidGlassSettings, LiquidShape, GlassGlow, and debugPaintLiquidGlassGeometry remain public.
New Features #
GlassBackdropScope— halves GPU blur capture cost when multiple glass surfaces are on screen simultaneously. Wrap yourMaterialApporScaffoldto activate:
GlassBackdropScope(
child: MaterialApp(
home: Scaffold(
appBar: GlassAppBar(...),
bottomNavigationBar: GlassBottomBar(...),
),
),
)
Renderer #
The renderer from liquid_glass_renderer (whynotmake.it, MIT) is now vendored directly, giving full control over the rendering pipeline with no user-facing API changes.
0.4.1 #
Bug Fixes #
- FIX:
GlassBottomBarand other surfaces now correctly respond to dynamicglassSettingschanges onGlassQuality.standard—AdaptiveGlassin grouped mode now inherits settings fromInheritedLiquidGlassinstead of using empty defaults. - FIX: Luminance-aware ambient floor for white glass on
GlassQuality.standard— high-opacity white glass no longer renders as dark grey.
New #
- FEAT:
GlassBottomBar.iconLabelSpacing— configurable vertical gap between tab icon and label (default:4.0). Thanks @baneizalfe (#11).
Breaking Changes #
Library-wide IconData → Widget API migration. All icon parameters now accept any Widget:
// Before
GlassButton(icon: CupertinoIcons.heart, onTap: () {})
// After
GlassButton(icon: Icon(CupertinoIcons.heart), onTap: () {})
// Or any custom widget:
GlassButton(icon: SvgPicture.asset('assets/heart.svg'), onTap: () {})
GlassBottomBarTab.selectedIcon renamed to activeIcon to match Flutter's BottomNavigationBarItem convention.
0.4.0 #
New Components #
GlassMenu/GlassMenuItem/GlassPullDownButton— iOS 26 morphing context menu with spring physics and position-aware expansion.GlassButtonGroup— joined-style container for related actions (e.g. Bold/Italic/Underline toolbar).GlassFormField/GlassPasswordField/GlassTextArea/GlassPicker— full iOS 26 input suite.GlassSideBar— vertical navigation surface with header, footer, and scrollable items.GlassToolbar— standard iOS-style action toolbar.GlassTabBar— horizontal tab navigation bar with animated indicator and scrollable mode for 5+ tabs.GlassProgressIndicator— circular and linear variants (indeterminate and determinate), iOS 26 specs.GlassToast/GlassSnackBar— 5 notification types, 3 positions, auto-dismiss, swipe-to-dismiss.GlassBadge— count and dot status badges, 4 positions.GlassActionSheet— iOS-style bottom-anchored action list.
Performance #
- Universal Platform Support —
AdaptiveGlassandAdaptiveLiquidGlassLayerintroduced. All 26 widgets deliver consistent glass quality on Web, Skia, and Impeller. - Batch-blur optimisation — glass containers share a single
BackdropFilter(was: one per widget). ~5× faster in common multi-widget layouts. - Impeller pipeline warm-up — shaders pre-compile at startup to eliminate first-frame jank.
Theme System #
GlassTheme/GlassThemeData/GlassThemeVariant— global styling and quality inheritance across all widgets. Set once, inherited everywhere.
0.3.0 — 0.1.0 #
Early access and preview releases establishing the core widget library, initial glass rendering pipeline (LiquidGlass, LiquidGlassLayer, LiquidGlassBlendGroup), and foundational components (GlassBottomBar, GlassButton, GlassSwitch, GlassCard, GlassSearchBar, GlassSlider, GlassChip, GlassSegmentedControl, GlassSheet, GlassDialog, GlassIconButton).