liquid_glass_widgets 0.8.1
liquid_glass_widgets: ^0.8.1 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.8.1 #
New Features #
GlassInteractionBehavior — precise, orthogonal control of press interactions #
A new first-class enum that independently controls the two dimensions of press
feedback on GlassBottomBar, GlassSearchableBottomBar, and GlassTextField
(as well as its derivative inputs):
| Value | Glow | Scale |
|---|---|---|
none |
✗ | ✗ |
glowOnly |
✓ | ✗ |
scaleOnly |
✗ | ✓ |
full (default) |
✓ | ✓ |
The glow is the iOS 26-style directional light spotlight that follows the touch position across the glass surface. The scale is the spring-physics size pulse on press.
// Glow only — light follows your finger, no bounce:
GlassBottomBar(
interactionBehavior: GlassInteractionBehavior.glowOnly,
...
)
// Scale only — spring bounce, no glow:
GlassSearchableBottomBar(
interactionBehavior: GlassInteractionBehavior.scaleOnly,
pressScale: 1.06,
...
)
// Disable both for a completely static bar:
GlassBottomBar(
interactionBehavior: GlassInteractionBehavior.none,
...
)
Zero overhead when disabled. When interactionBehavior suppresses glow (none
or scaleOnly), the GlassGlow sensor widget is removed from the tree entirely —
saving 3 widget allocations and 3 RenderBox nodes per tab indicator per frame.
Scale is resolved at build time to a scalar 1.0 with no animation controller
overhang.
New parameters on GlassBottomBar, GlassSearchableBottomBar, and GlassTextField #
GlassTextField now shares the same interactionBehavior API as the bar-family
widgets. The scale dimension maps onto the subtle press-bounce animation
(field squishes slightly when pressed down); the glow dimension is the directional
spotlight that tracks touch position across the glass surface.
GlassPasswordField and GlassTextArea delegate to GlassTextField and inherit
the new parameter automatically.
| Parameter | Widget(s) | Type | Default |
|---|---|---|---|
interactionBehavior |
All three | GlassInteractionBehavior |
.full |
pressScale |
Bar widgets / Inputs | double |
1.04 (bars) / 1.03 (inputs) |
interactionGlowColor |
Bar widgets | Color? |
null (theme default) |
glowColor |
GlassTextField |
Color? |
null (~12% white) |
interactionGlowRadius |
Bar widgets | double |
1.5 |
glowRadius |
GlassTextField |
double |
1.5 |
All defaults preserve existing 0.8.0 visual behaviour — no migration required.
Migration from enableGlow / enableFocusAnimation
GlassTextField.enableGlow and GlassTextField.enableFocusAnimation have been
replaced by interactionBehavior. The mapping is direct:
// Before (0.8.0):
GlassTextField(enableGlow: false, enableFocusAnimation: false)
// After (0.8.1):
GlassTextField(interactionBehavior: GlassInteractionBehavior.none)
// Before: glow only
GlassTextField(enableGlow: true, enableFocusAnimation: false)
// After:
GlassTextField(interactionBehavior: GlassInteractionBehavior.glowOnly)
Bug Fixes #
-
FIX:
SearchPillwas silently ignoringinteractionBehavior. TheinteractionGlowColorparameter was never passed to theSearchPillconstructor, so the search pill always rendered with a visible glow regardless of the bar'sinteractionBehaviorsetting. The glow was hardcoded toColor(0x1FFFFFFF)even whenbehavior = none. -
FIX:
SearchPillStatehad no glow short-circuit on the expanded pill path. Added_wrapWithGlowhelper (matching the pattern already inTabIndicatorStateandSearchableTabIndicatorState) to skipGlassGlowallocation when glow is suppressed.
0.8.0 #
New Features #
GlassAdaptiveScope (experimental) — automatic runtime quality adaptation #
A new scope widget that automatically adjusts GlassQuality for its subtree
based on real raster performance observed from SchedulerBinding frame timings.
Handles the three device scenarios that are impossible to test on a developer
device:
- Broken / slow shader drivers (e.g. Pixel 4a, Galaxy A22 class): detected
synchronously at startup via
ImageFilter.isShaderFilterSupportedand capped immediately tominimal. - Warm-up jank ("wrong quality at startup"): resolved by a ~180-frame benchmark that measures real P75 raster durations and sets the initial quality tier before the user notices.
- Thermal throttling ("fine at launch, janky after 10 minutes"): detected and corrected by a continuous runtime hysteresis engine.
Three-phase adaptation:
| Phase | Trigger | Action |
|---|---|---|
| Phase 1 — Static probe | Mount | Forces minimal on unsupported hardware; caps at standard on web |
| Phase 2 — Warm-up | First ~180 frames (~3 s at 60 fps) | Sets initial quality from real P75 raster durations |
| Phase 3 — Runtime hysteresis | Ongoing | Degrades after 3 bad windows; recovers after 10 good windows (8 s cooldown) |
The scope acts as a quality ceiling — widgets with an explicit quality:
parameter are unaffected. The ceiling is enforced by
GlassThemeHelpers.resolveQuality, which reads GlassAdaptiveScopeData from
the nearest ancestor scope.
// Per-screen control:
GlassAdaptiveScope(
child: Scaffold(...),
)
// Advanced — conservative start for fragmented Android market:
GlassAdaptiveScope(
initialQuality: GlassQuality.standard, // earn your way up to premium
allowStepUp: true,
onQualityChanged: (from, to) => analytics.log('glass_quality_changed'),
child: child,
)
Experimental in 0.8.0.
GlassAdaptiveScopeandGlassAdaptiveScopeConfigare annotated@experimental. The three-phase adaptation logic is architecturally sound and fully tested, but the Phase 2 timing thresholds (P75 < 12 ms → premium, 12–20 ms → standard, > 20 ms → minimal) have been validated by reasoning, not yet by broad real-device data across the Android fragmentation landscape.How to enable it:
LiquidGlassWidgets.wrap(myApp, adaptiveQuality: true)(opt-in, defaultfalse).If you observe unexpected behaviour — quality too low on a mid-range device, or stuck at
standardon a flagship — please file an issue with your device model and raster timings from Flutter DevTools. Your data will be used to tune the thresholds for a future release.
GlassAdaptiveScopeConfig (experimental) — portable configuration value object #
Bundles all GlassAdaptiveScope parameters into a single const-constructible,
equality-comparable value object. Used by LiquidGlassWidgets.wrap() and useful
for passing scope configuration through APIs that cannot accept widget parameters
directly.
const config = GlassAdaptiveScopeConfig(
initialQuality: GlassQuality.standard,
allowStepUp: true,
targetFrameMs: 8, // 120 Hz ProMotion
);
API Refactor — initialize() and wrap() separation #
The responsibilities of initialize() and wrap() have been clarified and
made consistent with the broader Flutter ecosystem (cf. easy_localization,
MaterialApp):
| Method | Responsibility |
|---|---|
initialize() |
Async platform / engine setup only (shader prewarming, Impeller pipeline, debug monitor) |
wrap() |
Widget-tree composition and all behavioral configuration |
wrap() — new parameters #
runApp(LiquidGlassWidgets.wrap(
const MyApp(),
respectSystemAccessibility: false, // moved from initialize()
adaptiveQuality: true, // new — inserts GlassAdaptiveScope
adaptiveConfig: GlassAdaptiveScopeConfig(
initialQuality: GlassQuality.standard,
allowStepUp: true,
),
));
Scope nesting order inserted by wrap() #
GlassAdaptiveScope → GlassBackdropScope → child
Breaking Changes #
initialize(respectSystemAccessibility:) removed #
respectSystemAccessibility has moved from initialize() to wrap().
Migration (one-line change):
// Before (0.7.x):
await LiquidGlassWidgets.initialize(respectSystemAccessibility: false);
runApp(LiquidGlassWidgets.wrap(const MyApp()));
// After (0.8.0):
await LiquidGlassWidgets.initialize();
runApp(LiquidGlassWidgets.wrap(const MyApp(), respectSystemAccessibility: false));
The LiquidGlassWidgets.respectSystemAccessibility getter and setter remain
available as an escape hatch for tests and advanced runtime overrides. In
production code, set it through wrap().
Bug Fixes #
Glass invisible on white / light backgrounds (transparency regression) #
-
FIX: Standalone glass widgets (
GlassButton,GlassContainer,GlassTextField,GlassCard, and all widgets that delegate to them) rendered with zero opacity on light backgrounds when no explicitsettings:were provided. Root cause: these widgets fell through toInheritedLiquidGlass.ofOrDefault(), which returnsLiquidGlassSettings()— a default withglassColor: Color(0x00FFFFFF)(alpha = 0). The lightweight shader computesbody tint = glassColor.alpha × 0.15, so0 × 0.15 = 0— the glass body was literally transparent regardless ofthicknessorblur.Fix: Replaced all
InheritedLiquidGlass.ofOrDefault()call sites with the newGlassThemeHelpers.resolveSettings(), which traverses the full 5-level priority chain:- Widget-level
settings:parameter (explicit wins) InheritedLiquidGlass— nearest parentAdaptiveLiquidGlassLayerLiquidGlassWidgets.globalSettings— app-level overrideGlassThemeData— brightness-aware theme variant (light / dark)LiquidGlassSettings()— absolute last resort
Standalone widgets now correctly resolve to the theme's
glassColorand are always visible out of the box. - Widget-level
Light theme defaults rebalanced #
-
TWEAK:
GlassThemeVariant.lightupdated for an icy-frosted aesthetic that reads clearly on white backgrounds:Property Before After blur10.0 6.0 glassColor0x73FFFFFF(45% neutral white)0x4AD2DCF0(~29% cool blue-white)chromaticAberration0.1 0.3 thickness16.0 20.0 lightIntensity1.0 1.2 The cool blue-white tint (
D2DCF0) matches the icy tone of iOS 26 frosted glass. Blur 6 gives visible background diffusion without obscuring content.
API #
GlassBackdropScope now exported from the main barrel #
-
FIX:
GlassBackdropScopewas missing fromliquid_glass_widgets.dart. Consumers had to use the internal pathpackage:liquid_glass_widgets/widgets/shared/glass_backdrop_scope.dart, which is fragile and undocumented. It is now a first-class public export.Migration — update any direct internal imports:
// Before (workaround, fragile): import 'package:liquid_glass_widgets/widgets/shared/glass_backdrop_scope.dart'; // After (correct): import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; -
CHORE: add CI and Codecov badges.
0.7.16 #
Bug Fixes #
- FIX:
GlassSearchableBottomBar— memory leak whencontrollerwas swapped at runtime. The old controller's listener was never removed before attaching to the new controller. Now correctly removed indidUpdateWidget. - FIX:
DraggableIndicatorPhysics— velocity NaN/Infinity guard. A zero-size render box (e.g. during widget tree warm-up) could produceInfinityorNaNforvelocityX, which propagated into the spring physics and caused erratic snapping. Now clamped to 0 when the box has no size.
Refactor (zero breaking changes) #
- REFACTOR: Extracted
GlassSearchBarConfigfromglass_searchable_bottom_bar.dartinto a dedicated filelib/widgets/surfaces/shared/glass_search_bar_config.dart. Resolves a circular import between the public widget and its internal sub-widgets.GlassSearchBarConfigis re-exported from the barrel file — no consumer-facing API change. - REFACTOR: Extracted
_TabIndicator/_TabIndicatorStatefromglass_bottom_bar.dartintoshared/bottom_bar_internal.dartasTabIndicator/TabIndicatorState(package-internal, not exported). Follows the same pattern used forGlassSearchableBottomBar.glass_bottom_bar.dartreduced from 1,406 → ~895 lines. - REFACTOR: Extracted
_TabBarContent,_TabBarContentState, and_TabItemfromglass_tab_bar.dartintoshared/tab_bar_internal.dart.glass_tab_bar.dartreduced from 728 → ~310 lines. Architecture is now consistent across all bar-family widgets.
Test Coverage #
- TEST: Reached 91.85% effective coverage (up from 89.6% in 0.7.15 — excluding GPU/shader renderer paths that are physically untestable in a headless VM). Total: 1,031 tests, all passing, 0 analyzer warnings.
- TEST: New
test/widgets/surfaces/glass_bottom_bar_drag_test.dart— 7 regression tests covering_onDragEndphysics snapping,_onDragCancel(mid-drag and no-drag), slow drags, fast flings, and full-bar sweeps. These paths are the highest-risk regressions in navigation UX.
0.7.15 #
Bug Fixes #
- FIX:
lib/theme/glass_theme_settings.dartwas accidentally omitted from version control in 0.7.14. All consumers ofGlassThemeSettingsreceived a compile error (type 'GlassThemeSettings' is not a subtype). This release commits the missing file. No API change —GlassThemeSettingswas already exported fromliquid_glass_widgets.dart. - FIX:
GlassPerformanceMonitor._emitWarning— division-by-zero crash whenrasterBudgetwas sub-millisecond (< 1 ms). Protected with amax(1, ...)guard.
Refactor (zero breaking changes) #
- REFACTOR: Consolidated 18 quality-resolution chains (
widgetQuality ?? inherited?.quality ?? themeData.qualityFor(context) ?? GlassQuality.standard) into a single canonical helper:GlassThemeHelpers.resolveQuality(context, widgetQuality: ..., fallback: ...). Surface widgets (GlassAppBar,GlassToolbar,GlassBottomBar,GlassSearchableBottomBar,GlassSideBar) passfallback: GlassQuality.premiumto preserve their documented defaults. All other widgets default toGlassQuality.standard. - REFACTOR: Extracted
_buildIconShadowsfromBottomBarTabItemto a@visibleForTestingtop-level functionbuildIconShadows(...)inbottom_bar_internal.dart. No behaviour change — enables isolated unit testing of the shadow-outline geometry.
Test Coverage #
- TEST: Reached 90%+ effective test coverage (90.15% — excluding
src/rendererGPU/shader layer where headless simulation is impossible). Total: 949 tests, all passing. - TEST: New
test/theme/glass_theme_helpers_test.dart— 5 widget tests covering all 4 priority levels ofGlassThemeHelpers.resolveQuality(). - TEST: New
test/widgets/surfaces/build_icon_shadows_test.dart— 6 unit tests coveringbuildIconShadows(): null thickness, active-icon suppression, shadow count, 45° offset math, and color propagation. - TEST: Added
test/theme/,test/renderer/,test/types/,test/constants/,test/utils/, andtest/widgets/test suites (committed for the first time — these were written during the 0.7.13–0.7.14 coverage push but never staged).
0.7.14 #
Bug Fixes #
- FIX:
GlassSearchableBottomBar—extraButtonnow fades out smoothly when search activates instead of being visually clipped/shrunk between the collapsing tab pill and the expanding search pill. Layout space is still reserved during the morph (no pills jump), only the visual opacity transitions. Taps on the extra button are also correctly blocked while hidden. Fades in when search closes. - FIX:
GlassSearchableBottomBar— spring morph animations no longer produce a visible jump when reversing direction. Previously the three spring controllers (tabW,searchLeft,searchW) were each started in separateaddPostFrameCallbackcalls, introducing a 1-frame desync at reversal. All three are now started in a single batched callback, so the morph is perfectly synchronized in both directions. - FIX: Indicator fade animation in
GlassBottomBar/GlassSearchableBottomBar— replacedOpacitywrapper withLiquidGlassSettings.visibilityfading. Wrapping aBackdropFilterinOpacitycomposites into an offscreen buffer, breaking backdrop sampling and causing the indicator to snap in/out instead of fading. Thevisibilitypath is a single GPU pass — no offscreen buffer — improving drag animation performance and working uniformly for allblurvalues. - FIX:
GlassBottomBar,GlassSearchableBottomBar,GlassAppBar,GlassToolbar, andGlassSideBarresolved toGlassQuality.standardinstead of their documentedGlassQuality.premiumdefault. Fixed by settingquality: nullin the built-in light/dark variants so each widget's documented default is respected. - FIX: Setting any property in
GlassThemeVariant.settingssilently zeroed out all unset properties (e.g. setting onlythickness: 50also resetglassColorto fully transparent). Fixed by introducingGlassThemeSettings: a parallel class with all-nullable fields that merges onto each widget's own defaults. Only the fields you explicitly set are applied; everything else inherits from the widget.GlassThemeVariant.settingsnow acceptsGlassThemeSettings?. - FIX:
GlassSearchableBottomBar— multiple layout-math regressions in the morph animation corrected:- Reserved layout width now correctly scales to
min(size, searchBarHeight)during search, eliminating the bloated gap whensearchBarHeight < barHeight. - Extra button rendered width now matches the layout reserve (
extraTargetW), preventing a 14 px overflow into the search pill whensearchBarHeight < barHeight. - Restored
+ widget.spacingintargetSearchLeft; an erroneoustabToNextGapvariable had suppressed the gap between the tab pill and search pill when no extra button was present. collapseOnSearchFocusnow exclusively controls visibility/opacity — it no longer affects layout geometry. Toggling it mid-animation no longer triggers the spring or causes the button to jump inside the collapsed tab circle.
- Reserved layout width now correctly scales to
- FIX:
BottomBarTabItem— removed a fixedvertical: 4padding wrapping the tab column. The padding consumed constraint space beforeFittedBoxcould scale, causing a 2 pxRenderFlexoverflow when the bar morphed tosearchBarHeight.
New #
- NEW:
GlassThemeSettings— a partial settings type for use inGlassThemeVariant. Accepts the same parameters asLiquidGlassSettingsbut all are nullable. Only non-null fields override the target widget's defaults, enabling precise single-property theme overrides without disturbing others. - NEW:
GlassTabPillAnchorenum +GlassSearchableBottomBar.tabPillAnchor— controls how the tab pill is anchored during the morph animation.GlassTabPillAnchor.start(default) preserves existing left-anchor behaviour.GlassTabPillAnchor.centermakes both edges collapse symmetrically from the pill's centre for a more balanced look. The search pill position adjusts automatically in center mode. - NEW:
GlassSearchBarConfig.showsCancelButtonnow defaults totrue. Tapping the dismiss pill unfocuses the keyboard and collapses search, matching the system-level behaviour seen across iOS apps (Weather, App Store, Apple News). PassshowsCancelButton: falseto opt out. - NEW:
GlassSearchBarConfig.collapsedTabWidthis now nullable. When omitted, the collapsed tab pill automatically matchesGlassSearchableBottomBar.searchBarHeight, ensuring it morphs into a geometric circle with no leftover horizontal margin. Pass an explicit value to override. - NEW:
GlassBottomBarExtraButton.collapseOnSearchFocus(defaulttrue) — controls whether the extra button collapses when the search field is focused. Whentrue, the button fades out and its layout space spring-animates to zero, giving the search input the full available width (matching native iOS behaviour). Whenfalse, the button remains fully visible and tappable alongside the search input — useful for contextually relevant actions like a Filter button that applies to search results. - EXAMPLE:
searchable_bar_repro.dartadded to the example app — exercisesGlassSearchableBottomBaredge cases (extra-button fade, spring desync, bar-height scale, dismiss pill) in isolation. Run standalone:flutter run -t example/lib/searchable_bar_repro.dart.
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).