PackageTrack
Sign in Get early access

liquid_glass_widgets

iOS 26-style liquid glass widgets for Flutter. Built on a custom fragment shader for real blur, liquid interactions, specular highlights, and chromatic aberration.

0.30.2 50K downloads/mo #1464 most downloaded on pub.dev sdegenaar/liquid_glass_widgets

What this package is like to depend on

Last release 3 days ago

21 Aug 2026

Ships on a steady schedule

a new release about every 8 days

Most releases are documented

notes for 86 of 123 stable releases

1 version withdrawn

withdrawn after publishing

8 months old

154 releases · first in 2025

154 releases in the last 12 months

see the full history below

Release timeline

154 releases · Dec 2025 to Aug 2026
2026
Release Pre-release Withdrawn

Releases

latest 60 of 154
  1. 0.30.2 21 Aug 2026
    Release notes

    Bug Fixes

    • GlassPullDownButton / GlassMenu crash in minimal quality (#214): Fixed a crash when quality falls back to GlassQuality.minimal. LiquidGlassBlendGroup is now skipped when no LiquidGlassLayer is present in the tree. Same fix applied to GlassPopover.

    Open source →
  2. 0.30.1 19 Aug 2026
    Release notes

    Bug Fixes

    • Dark mode collapsed tab pill icon (#208): Fixed an issue where the collapsed tab pill icon in GlassTabBar.searchable rendered opaque black in dark mode instead of white when unselectedIconColor was unset.
    • ProgressiveBlur region origin (#210, credit: @jfhair): Fixed ProgressiveBlur rendering black or losing its gradient when not positioned at the top-left of the backdrop layer (modal sheets, inset containers, scroll edges). The shader region origin is now resolved at paint time, keeping the gradient correct through drags and animated transitions.
    • GlassScrollEdgeEffect stale background on route resume (#212): Fixed stale background texture and ghosting shadows when returning from routes where the theme or background changed. Background capture is now deferred until the route resumes, and in-flight capture requests are coalesced.

    Open source →
  3. 0.30.0 19 Aug 2026
    Release notes

    v0.30.0: Eliminate Windows Impeller startup hang and Android GLES ANR…

    Open source →
    Release notes

    Bug Fixes

    • Windows Impeller startup hang (#204): LiquidGlassWidgets.initialize() no longer submits blocking GPU draw calls to the raster thread prior to runApp(). On Flutter 3.47+ Windows Impeller (ANGLE / OpenGLESSDF), runtime GLSL driver compilation previously locked the raster thread during OS surface initialization, preventing the native window from presenting. The app window now displays immediately on Frame 1 on all Windows and desktop configurations.
    • Android GLES ANR (#187 follow-up): Removed the synchronous pre-runApp offscreen warm-up draw. All Android devices launch with zero splash-screen delay, and GLES devices are safely protected from runtime driver compile lockups.

    Architecture & Performance

    • Non-blocking shader preloading with full Vulkan/Metal parity: LiquidGlassWidgets.initialize() now preloads shader bytecode asynchronously into memory via fast I/O on Android (Vulkan and GLES), iOS, and macOS, eliminating first-frame placeholder flashes while ensuring zero GPU raster stalls before runApp().
    • Zero GPU work before runApp(): Removed all toImageSync calls from preWarm(). Internal 1×1 sampler dummy textures are now allocated lazily on first paint in the widget tree.
    • GlassWarmUpMode configuration: Added warmUpMode (GlassWarmUpMode.auto, .always, .never) to LiquidGlassWidgets.initialize(). Default .auto preloads all shaders for Android, iOS, and macOS, while skipping unused premium shaders on statically-capped desktop/web backends. Deprecated warmUpImpellerPipeline.
    • Windows & Linux adaptive defaults: GlassAdaptiveScope static probe defaults Windows and Linux to GlassQuality.standard (lightweight_glass.frag with real iOS 26 squircle geometry, dual specular highlights, meniscus absorption, and blur) for guaranteed 60/120fps performance without driver compile delays.
    • GLES shape compile optimization: shaders/sdf.glsl now caps shape evaluation at 8 shapes on OpenGL ES / ANGLE backends via #ifdef LGR_OPENGLES_CAP_SHAPES (shaders/gles_compat.glsl), reducing the inlined AST size for runtime JIT drivers while leaving Metal (iOS/macOS) and Vulkan (Android) on the full 16-shape unrolled AOT path with zero changes.

    Open source →
  4. 0.29.8 18 Aug 2026
    Release notes

    Maintenance & Upstream Compatibility

    • Pure Flutter SDK dependencies: Removed all third-party and external dependencies across runtime and dev environments (equatable, flutter_shaders, logging, meta, alchemist, and mocktail). Golden tests now use Flutter's native matchesGoldenFile. Package depends purely on flutter: sdk: flutter.
    • Optimized value equality: Replaced Equatable with native operator == and Object.hashAll across shapes and settings, eliminating heap allocations during hot animation loops.
    • Internalized shader loading & uniform binding: Shaders load directly via dart:ui.FragmentProgram with cached isolate pipelines and zero-overhead uniform setters.

    Open source →
  5. 0.29.7 17 Aug 2026
    Release notes

    Performance

    • Progressive blur: 50% fewer texture reads. Gaussian tap count halved with identical ±3σ coverage; GPU memory bandwidth for the blur pass is halved with no perceptible quality change.
    • Gaussian weight loop: exp() eliminated. Per-tap exponential replaced with a two-scalar IIR recurrence — saves 24 GPU instructions per blur pass with mathematically identical output.
    • PlatformView fallback: skipped when unused. The background composite is now gated on a uniform flag; no GPU cost when there is no PlatformView beneath the glass.

    Visual

    • edgeAbsorption parameter added (LiquidGlassSettings, GlassThemeSettings, default 0.0): Physical rim darkening — the glass absorbs more light at the thickest edge. Default 0.0 matches iOS 26's crisp luminous glass. Increase (0.10–0.20) for physical-depth or iOS 27-style recipes.
    • Hemisphere lens profile: Replaced polynomial falloff with a physical circular arc across all shaders — interiors stay crystal clear while absorption steepens at the bevel.
    • Light-modulated absorption: Absorption is scaled by light direction for realistic 3D rim separation without washing out specular highlights.
    • Cross-platform fresnelStrength parity: fresnelStrength now controls grazing-angle rim highlights identically across all rendering engines (Skia, Web, Windows, Android, and Impeller).
    • Edge-concentrated chromatic aberration: Prismatic dispersion is now strictly zero in flat glass interiors, concentrated only at the rim — consistent across all rendering paths.

    Example App & Tooling

    • Meniscus & Blur Lab (MeniscusAndBlurDemoPage): Interactive calibration workbench for live testing of edgeAbsorption, fresnelStrength, thickness, blur, and progressive blur performance.

    Bug Fixes

    • GlassTabBarExtraButton loses backdrop blur in minimal quality (#203): Added isStationary flag to GlassButton (default false). Setting isStationary: true on GlassTabBarExtraButton retains its BackdropFilter blur in GlassQuality.minimal.

    Open source →
  6. 0.29.6 15 Aug 2026
    Release notes

    Bug Fixes

    • Impeller GLES sampling UV double-flip on Flutter 3.46+ (#202): Flutter 3.46 absorbed the OpenGL ES render-to-texture Y-axis inversion inside the engine backend, but six shader sites still compensated for the old convention — actively mirroring every backdrop sample on 3.46+. A new shaders/gles_compat.glsl header gates the flip on IMPELLER_OPENGLES_UNFLIPPED_DEPRECATED, the migration macro introduced by the Flutter engine team for exactly this transition. The fix is correct across all Flutter versions from the existing >=3.41.0 minimum; the pubspec.yaml constraint does not move. A new source-level regression guard in test/shaders/gles_flip_guard_test.dart prevents the pattern from re-appearing.

    Thanks to @TIANLI0 for the contribution (#202).


    Open source →
  7. 0.29.5 12 Aug 2026
    Release notes

    Bug Fixes

    • GlassAppBar title not centred when leading is set (#198): Toolbar layout rewritten using a CustomMultiChildLayout delegate, matching the approach used by Flutter's own CupertinoNavigationBar. The title is now centred on the full bar width regardless of leading/trailing widget sizes, and is constrained to never overlap either button group. centerTitle: false correctly left-aligns the title after the leading widget in both LTR and RTL locales.

    Open source →
  8. 0.29.4 10 Aug 2026
    Release notes

    Bug Fixes

    • GlassModalSheet stale _currentState (#197): A drag ending at its origin state left _currentState holding the predicted mid-drag target. _currentState is now reconciled on every snap unconditionally, preventing the sheet from appearing stuck after a short drag.
    • GlassModalSheet overscroll axis guard (#197): _onScrollNotification now ignores notifications whose metrics.axis is not Axis.vertical, preventing horizontal descendant lists (carousels, date strips) from hijacking the sheet gesture.
    • GlassModalSheet one-shot axis lock (#197): Gesture axis is decided once on the first movement past the threshold and held until the touch lifts, preventing a sideways swipe from later grabbing the sheet mid-gesture.

    Thanks to @jfhair for the contribution (#197).


    Open source →
  9. 0.29.3 09 Aug 2026
    Release notes

    Bug Fixes

    • Premium glass lens detaches during CupertinoSheet drag (#192): The refracted lens drifted away from its pill while an interactive CupertinoSheet drag scaled the background. Fixed by snapshotting the layer's unscaled screen-space coordinates on every paint frame and freezing them the moment a uniform ancestor scale-down is detected, keeping UV mapping locked to the captured texture for the duration of the drag.
    • GlassAppBar title typography (#194): The title widget is now wrapped in DefaultTextStyle using CupertinoTheme's navTitleTextStyle, matching native CupertinoNavigationBar behaviour. A plain Text widget now automatically picks up correct Cupertino typography (weight, size, ellipsis) without manual styling. Also adds Semantics(header: true) for VoiceOver/TalkBack navigation.

    Open source →
  10. 0.29.2 04 Aug 2026
    Release notes

    Universal DPR (Device Pixel Ratio) Normalization

    The Liquid Glass rendering engine now achieves 1:1 mathematical parity across all display densities (e.g., macOS 2.0x, iOS 3.0x, and various Android fractional densities like 2.75x or 3.5x). Previously, running shaders in physical pixels caused inconsistent refraction scaling on high-density screens.

    • Geometry Curvature: effectiveThickness is scaled by DPR, guaranteeing identical refraction depth across devices.
    • Surface Normals: SDF tap spacing is scaled by DPR, ensuring edge highlights and Fresnel rims maintain exact proportional widths.
    • Lighting Clamps: The physical thickness floor is scaled by DPR, preventing lighting anomalies across different hardware.

    Bug Fixes

    • Indicator Pill: Removed chromatic aberration (0.150.0) from the default animated pill to eliminate the rainbow rim artifact, while preserving true lens distortion.
    • Pinch Shader: Fixed a mathematical bug (L6 norm with an 8th-root extraction) in the squircle distance field. Replaced with an exact L4 norm, producing naturally soft, Apple-like corners during drag animations and saving one GPU instruction per fragment.
    • Brightness Cascade (#124): Hardened the brightness resolution cascade by evaluating brightnessResolver before CupertinoTheme.of. This acts as a defensive backstop for older Flutter versions or edge cases where the MaterialBasedCupertinoThemeData bridge fails to propagate ThemeMode correctly.
    • Accessibility / Semantics (#189): Restored VoiceOver/TalkBack tap-to-dismiss behavior. The GlassModalSheet drag indicator now exposes a Semantics.onTap action that correctly triggers sheet dismissal, matching Material's handle behavior.
    • Customization (#190): GlassModalSheet's dragIndicatorColor is now honored. It was previously accepted by the API but dropped internally in favor of hard-coded defaults.
    • Android Quality (Best Foot Forward): GlassAdaptiveScope now seeds at maxQuality (premium) on Android from the very first frame. Previously, Android cold-started at standard and promoted to premium only after the 3-second Phase 2 benchmark. The ANR safety net (shader pre-compilation in LiquidGlassWidgets.initialize()) makes this safe; Phase 2 continues to demote genuinely slow/budget devices.

    Open source →
  11. 0.29.1 03 Aug 2026
    Release notes

    Fixes

    GlassSegmentedControl — duplicate unlabeled semantics node (#188) Each segment emitted two tappable nodes (one unlabeled), breaking VoiceOver/TalkBack. Fixed by adding excludeFromSemantics: true to the internal GestureDetector; semantics are fully handled by GlassFocusRegion.

    GlassTabBar shadow lost in Dark OS + Light app (#124) Shadow disappeared when the device was in Dark Mode but ThemeMode.light was set. Introduced a zero-material IoC bridge: pass brightnessResolver: Theme.maybeBrightnessOf to LiquidGlassWidgets.wrap() so the package correctly honours ThemeMode without importing flutter/material.dart.

    Migration — MaterialApp users must add this one line to fix #124:

    runApp(LiquidGlassWidgets.wrap(
      child: const MyApp(),
      brightnessResolver: Theme.maybeBrightnessOf,
    ));
    

    CupertinoApp users: no change required.

    Dead flutter/material.dart import removed from tab_bar_bottom_internal.dart Leftover from pre-0.26.0, never cleaned up. lib/ is now 100% zero-material for cupertino_ui compatibility.


    Eliminates production ANRs on Android devices running Impeller GLES (devices without Vulkan support, including many MediaTek and budget Qualcomm Snapdragon SoCs).

    Root cause

    On Android GLES, glCompileShader + glLinkProgram executes synchronously on the Flutter raster thread at first use (100–800 ms on mid-range hardware). When this coincides with FlutterJNI.nativeSurfaceChanged during surface setup, Android's watchdog declares an ANR. The previous warm-up implementation instantiated a LiquidGlassLayer widget outside the widget tree — an unmounted widget is never rasterized, so no GPU work occurred. The warm-up was a no-op.

    Fix

    • True GPU warm-up (liquid_glass_setup.dart): _warmUpImpellerPipeline() now draws both premium glass shaders to a 1×1 off-screen surface using Picture.toImage() and awaits rasterization. This forces GLES pipeline compilation on the raster thread while initialize() is still running — before runApp — so compilation completes behind the native splash screen and cannot race with surface setup.

    • Android-only execution: The warm-up is guarded by defaultTargetPlatform == TargetPlatform.android. iOS and macOS use precompiled Metal shaders and skip this step entirely, preserving their zero startup overhead.

    • Reuses cached programs: The warm-up now calls MultiShaderBuilder.cachedProgram() to retrieve the FragmentProgram objects already loaded by precacheShaders() in step 1 of initialize(). No duplicate GPU objects are created.

    • warmUpImpellerPipeline parameter: LiquidGlassWidgets.initialize() accepts a new warmUpImpellerPipeline: bool parameter (default true). On non-Android platforms the parameter is a no-op. Pass false only if you are managing Android shader warm-up yourself.

    • Conservative Android quality seeding (glass_adaptive_scope.dart): Fixed a code-comment mismatch in _GlassAdaptiveScopeState.initState. The file header documented seeding at GlassQuality.standard; the code seeded at maxQuality (premium). On Android, initState now correctly seeds at GlassQuality.standard so Phase 2 benchmarks the device from a stable baseline. iOS and macOS continue to seed at maxQuality for an immediate premium experience.

    No action required

    Existing call sites (await LiquidGlassWidgets.initialize()) are unchanged and benefit from the fix automatically. The adaptiveQuality: true path also benefits from the corrected initState seeding on Android.

    Documentation

    • README Platform Support table now distinguishes Android Vulkan from Android GLES and links to a new Android GLES mitigation section.

    Open source →
  12. 0.29.0 03 Aug 2026
    Release notes

    🎵 iOS 26 tabViewBottomAccessory Support

    Added bottomAccessory / bottomAccessoryHeight / bottomAccessoryEnabled / bottomAccessorySpacing / bottomAccessoryPlacement to both GlassTabBar.bottom and GlassTabBar.searchable — mirroring Apple's tabViewBottomAccessory modifier.

    • Expanded mode — accessory floats directly above the nav bar pill with a configurable spacing gap (default 6.0px, calibrated to match Apple's native spacing).
    • Inline mode (searchable only) — set bottomAccessoryPlacement: GlassTabBarAccessoryPlacement.inline to have the accessory slide horizontally into the gap between the collapsed tab indicator and search capsule, with a simultaneous width squish, matching the iOS 26 .inline placement.
    • Two independent animation timelinesaccessoryT drives the inline↔expanded morph (height, left, right) while searchT tracks the tab-pill→search-capsule height change so the accessory follows the bar downward during the search activation, maintaining a consistent visual overlap gap throughout.
    • Safe defaultsbottomAccessoryPlacement defaults to .expanded. The accessory never collapses inline automatically; developers must explicitly opt into .inline placement, mirroring the iOS 26 model where placement intent is declared at the call site.
    • Pixel-accurate scaffold insetspreferredSize is always in sync with the layout engine so GlassScaffold's edge fade reserves the exact correct amount of space in both expanded and inline states.
    • GlassTabBarAccessoryPlacement enumexpanded and inline values, readable inside the accessory widget itself via GlassTabBarAccessoryPlacementScope.of(context) to adapt the accessory's own layout between the full row and compact strip.
    • Apple Music and Apple Podcasts demos fully showcase the feature — including the expanded/inline transition and the search-active behaviour.

    Upgrading from bodyOverlays

    Previously, the recommended pattern for a floating mini-player was to place it in GlassScaffold.bodyOverlays and manually manage its position using AnimatedPositioned with scroll-offset math. That approach still works and bodyOverlays remains available for other use cases (e.g. floating action overlays, toast banners).

    For a bottom accessory that is architecturally part of the tab bar — which is exactly what iOS 26 tabViewBottomAccessory models — the bottomAccessory API is the correct replacement:

    // Before (bodyOverlays workaround)
    GlassScaffold(
      bodyOverlays: [
        AnimatedPositioned(
          bottom: _isMiniMode ? barH : barH + accessoryH + spacing,
          left: 0, right: 0,
          child: MiniPlayer(),
        ),
      ],
    )
    
    // After (iOS 26-aligned)
    GlassTabBar.searchable(
      bottomAccessory: MiniPlayer(),
      bottomAccessoryHeight: 50.0,
      bottomAccessoryPlacement: _isMiniMode && !_isSearching
          ? GlassTabBarAccessoryPlacement.inline
          : GlassTabBarAccessoryPlacement.expanded,
    )
    

    The new API removes all manual position arithmetic, keeps the GlassScaffold edge fade pixel-accurate, and persists the accessory automatically across tab switches.


    Open source →
  13. 0.28.1 02 Aug 2026
    Release notes

    📚 Internal Refactor — API Documentation

    • 100% Dartdoc coverage — every public member is documented. public_member_api_docs is now permanently enabled in analysis_options.yaml; future undocumented public API additions will fail dart analyze.
    • Internal layout engines moved to lib/src/ — 9 internal implementation files relocated per Dart convention so dart doc and pub.dev omit them from the generated API reference. No public API changes. 2517 tests passing.

    Open source →
  14. 0.28.0 02 Aug 2026
    Release notes

    🌐 Full RTL (Right-to-Left) Support

    Completed the Right-to-Left (RTL) layout audit. All directional padding and alignment primitives now use EdgeInsetsDirectional / AlignmentDirectional so widgets mirror correctly in RTL locales (Arabic, Hebrew, Persian, etc.) without any API changes for existing callers.

    Widgets Updated

    • GlassGroupedSection — header and footer labels now use EdgeInsetsDirectional.only(start: 16, end: 16). Under RTL the text aligns to the correct physical edge.
    • GlassDivider — horizontal divider indent / endIndent now use EdgeInsetsDirectional.only(start: indent, end: endIndent). The leading indent is always on the logical leading side regardless of text direction. Vertical divider top / bottom are unchanged (not directional).
    • GlassAppBar — non-centered title now uses AlignmentDirectional.centerStart + EdgeInsetsDirectional.only(start: 8) so the title anchors to the leading edge in both LTR and RTL.
    • GlassSearchBar — cancel button gap uses EdgeInsetsDirectional.only(start: 10) so the gap appears between the search field and the cancel button in both directions.
    • GlassDialog — horizontal two-button layout gap uses EdgeInsetsDirectional.only(start: 8) so buttons remain correctly spaced in RTL.
    • GlassLargeTitle — two improvements:
      • padding and searchBarPadding defaults changed from EdgeInsets.* to EdgeInsetsDirectional.* — the field types were already EdgeInsetsGeometry, so this is a zero-breaking-change improvement. Callers who pass custom asymmetric directional padding (e.g. EdgeInsetsDirectional.only(start: 32)) now get correct physical mirroring in RTL.
      • Transform.scale alignment changed from Alignment.bottomLeft to AlignmentDirectional.bottomStart — under RTL, the rubber-band overscroll stretch now scales from the correct logical leading edge rather than always pinning to the physical left.
    • GlassProgressIndicator.linear — custom canvas drawing now explicitly respects Directionality. In RTL locales, both the determinate fill and indeterminate moving bar correctly animate from the physical right (logical start) to the left.
    • GlassSlider — drag logic and active track drawing now invert cleanly under RTL. Dragging left increases the value, and the track anchors to the physical right.

    Bug Fixes & Accessibility

    • GlassTabBar.bottom — Resolved an edge-case visual bug in RTL mode where the animated glass pill would jump to the mirror-image tab when selecting an end tab. Fixed by enforcing Alignment(x, y) physical coordinates instead of AlignmentDirectional within the physics engine bounds.
    • GlassSegmentedControl & GlassTabBar — Unselected segments now correctly emit a "not selected" accessibility state (resolves #184). Thanks to @Xodus-CO for the detailed report!

    Open source →
  15. 0.27.0 01 Aug 2026
    Release notes

    ♿ Accessibility & Keyboard Navigation

    Every interactive widget now supports full keyboard traversal, Space/Enter activation, and VoiceOver/TalkBack semantics.

    Focus & Keyboard

    • GlassFocusRegion — new shared widget that is the single source of truth for all focus behaviour. Two modes:
      • Interactive — wraps FocusableActionDetector, registers ActivateIntent (Space/Enter), lifts hover/focus state to parent via ValueNotifier, and paints the iOS 26-style outset focus ring.
      • Observe (.observe()) — for widgets that own their own FocusNode (e.g. GlassTextField). Listens passively and paints the ring; no duplicate traversal or intent handling.
    • iOS 26 focus ring — 3 px outset, 2 px wide, rounded to the widget's shape. Implemented as GlassFocusRingPainter (pure CustomPainter; zero cost for touch users via ValueListenableBuilder).
    • GlassStepper keyboard fix — Space/Enter triggers a single-shot activation; the pointer-only long-press repeat timer is no longer erroneously started by keyboard input.
    • All 12 interactive widget families wired: GlassButton, GlassSwitch, GlassSlider, GlassSegmentedControl, GlassListTile, GlassMenuItem, GlassActionSheet, GlassButtonGroup, GlassTextField, GlassSearchBar, GlassStepper, GlassChip.

    Semantics

    • Semantic roles (isButton, isSlider, isSelected, toggled, value) set on every widget matching Material and Cupertino SDK conventions.
    • Destructive and disabled states propagate correctly to the semantic tree.
    • GlassBadgesemanticLabel and semanticCount overrides — resolves two user-reported limitations:
      • semanticLabel (optional String?) fully replaces the VoiceOver/TalkBack announcement; enables non-notification domains ("5 downloads", "Online", etc.).
      • semanticCount (optional int?) overrides only the spoken number while leaving the visual cap (99+) unchanged; allows "2500 notifications" to be announced when the badge visually shows "99+".
      • Both constructors (GlassBadge and GlassBadge.dot) support semanticLabel; semanticCount is only applicable to count badges.
      • Fully backwards-compatible — existing callers with no overrides get identical defaults.
    • GlassPageControlsemanticLabel param — the capsule now announces 'Page N of M' to VoiceOver/TalkBack by default (1-indexed). A semanticLabel override lets callers substitute domain-specific wording (e.g. 'Slide 3 of 5'). Non-interactive controls (no onPageChanged) omit the tap hint automatically.
    • GlassPasswordField — toggle button semantics — the show/hide password suffix icon is now wrapped in Semantics(label: 'Show password' / 'Hide password', button: true). Previously the GestureDetector was invisible to screen readers; VoiceOver now correctly announces the button and its toggled state.
    • GlassProgressIndicatorsemanticLabel param — the hardcoded 'Progress' label is now an overridable default. Callers can pass semanticLabel: 'Download progress' (or any domain string) to both .circular() and .linear() constructors. Backwards-compatible.
    • GlassPullDownButtonsemanticLabel param — icon-only pull-down buttons previously announced an empty string. A new semanticLabel param (e.g. 'More options') is used as the GlassButton.label in the icon-only code path. Visible-label variants are unaffected.

    Layout & Architecture

    • GlassInteractionStateMixin — internal State mixin (modelled on SingleTickerProviderStateMixin) providing isPressed, isFocused, isHovered ValueNotifiers and their Listenable.merge combinations. Replaces ~76 lines of identical boilerplate across GlassListTile, GlassMenuItem, _ActionSheetButton, and _GlassGroupItemWidget. No public API change.
    • All container-item widgets migrated to ValueNotifier + ListenableBuilder — only the AnimatedContainer highlight layer rebuilds on interaction; the surrounding subtree is stable.
    Open source →
  16. 0.26.1 31 Jul 2026
    Release notes

    🐛 Bug Fixes

    • GlassAdaptiveScope quality oscillation after reset() — when allowStepUp: false, a reset()-triggered warm-up could silently promote quality back up (e.g. standard → premium). Warm-up now respects the flag and can only confirm or lower the current quality, never raise it. Thanks to @jingluoguo for the contribution (#180).
    Open source →
  17. 0.26.0 30 Jul 2026
    Release notes
    • Remove GlassScaffold.floatingActionButton (breaking, pre-v1 cleanup)
    • Zero material.dart imports in lib/ — full Cupertino decoupling
    • Apple replica demos material-free (music, podcasts, messages, news, lockscreen)
    • Replace Material Slider with CupertinoSlider in demo pages
    • Fix navigation double-tap freeze in showcase
    • dart format pass — 293 files stable
    Open source →
    Release notes

    💥 Breaking Changes

    • GlassScaffold.floatingActionButton removed — iOS does not use Floating Action Buttons. floatingActionButton is removed entirely; this package is pre-v1 and that is the window to get the API right.

      Migration:

      // Before
      GlassScaffold(
        floatingActionButton: FloatingActionButton(onPressed: _add, child: Icon(Icons.add)),
        body: ...,
      )
      
      // After — glass-treated, iOS-idiomatic
      GlassScaffold(
        bodyOverlays: [
          Positioned(
            bottom: 24, right: 24,
            child: GlassButton(
              onTap: _add,
              child: const Icon(CupertinoIcons.add, color: CupertinoColors.white),
            ),
          ),
        ],
        body: ...,
      )
      

      bodyOverlays is above the body and below the bars. GlassButton applies the correct liquid glass treatment.

    ♻️ Refactoring — Material Decoupling (material.dart 36 → 0)

    GlassScaffold now uses CupertinoPageScaffold internally. GlassPage no longer injects a Material Theme shim. All Colors.* constants replaced with CupertinoColors or explicit hex literals. No visual changes.

    glass_brightness.dart was completely rewritten to drop its dependency on Theme.maybeBrightnessOf. It now reads CupertinoTheme.of(context).brightness, which natively inherits from the Material ThemeMode when used inside a MaterialApp (thanks to Flutter's automatic MaterialBasedCupertinoThemeData injection).

    With this final swap, liquid_glass_widgets now has zero imports of package:flutter/material.dart in its lib/ directory. It is fully decoupled and ready for the cupertino_ui package split. The example's Apple replica demos (apple_music, apple_podcasts, apple_messages, apple_news, apple_lockscreen) run with zero Material imports as well, proving the library works purely within a Cupertino-only context.

    🐛 Bug Fixes

    • LightweightLiquidGlass incorrect brightness in GlassTheme override contexts — was calling Theme.of(context).brightness instead of the canonical GlassTheme.brightnessOf(context). Could produce wrong brightness when GlassTheme set a different mode than the ambient Material theme. Fixed.
    Open source →
  18. 0.25.1 29 Jul 2026
    Release notes

    chore: bump version to 0.25.1 and clean up changelog

    Open source →
    Release notes

    🐛 Bug Fixes

    • GlassMenu mispositioned inside nested NavigatorsOverlayPortal now targets the root Overlay (via OverlayChildLocation.rootOverlay), matching the screen-global coordinates captured by localToGlobal. Previously the menu drifted by the offset of the nearest nested Overlay from the screen edge (e.g. a side-rail in a StatefulShellRoute layout). Thanks to @sinanhaci for the contribution (#179).
    Open source →
  19. 0.25.0 28 Jul 2026
    Release notes

    chore: release 0.25.0 — GlassModalSheet detents, dismissible flag, po…

    Open source →
    Release notes

    ✨ New Features

    • Optional sheet detentsGlassModalSheet (and .show()) gained a detents set (Set<GlassSheetDetent>, mirroring UIKit's sheet detents) plus a dismissible flag, to compose which stops a sheet offers:

      • {GlassSheetDetent.medium} → a half-only glass sheet that never morphs to the opaque full state (its content still scrolls at the half detent).
      • {GlassSheetDetent.large} → a full-only opaque sheet that opens straight to full.
      • {GlassSheetDetent.medium, GlassSheetDetent.large} → the default two-stop sheet.
      • {GlassSheetDetent.small, ...} → adds the maps-style peek floor underneath, so one mechanism now describes every resting stop.
      • dismissible: false → the sheet rubber-bands at its lowest detent instead of swiping away (the Apple Pay / Sign in with Apple pattern).

      The set must be non-empty (asserted). Style the small detent with the existing peek* params (peekSettings, peekWidth, …), which stay top-level: a Set whose members carried per-instance payload would need equality that ignores that payload, or detents.contains(small) breaks and two differently-configured smalls could sit in one set.

    ⚠️ Deprecations

    • GlassModalSheet.enablePeek → use GlassSheetDetent.small in detents. Peek is now a detent like medium and large. enablePeek is still honoured and takes precedence over the set when set explicitly, so existing code keeps working unchanged; it will be removed in a future release. GlassSheetMode.persistent keeps its peek floor with or without the detent — a persistent sheet is defined by resting rather than dismissing.

    🐛 Bug Fixes

    • GlassModalSheetController reattachment — the controller no longer detaches when its GlassModalSheet is swapped under a stable controller (e.g. a ValueKey change): the replacement's initState runs before the outgoing widget's dispose, so the detach is now guarded to only clear the attachment it still owns. Previously this left the controller inert and the sheet un-openable.
    • Half-only content scrolling — a sheet's inner scroll view now enables at the sheet's topmost detent rather than hardcoding the full state, so a half-only sheet scrolls its content correctly.

    Thanks to @jfhair for the contribution (#178).

    Open source →
  20. 0.24.4 28 Jul 2026
    Release notes

    🐛 Bug Fixes

    • GlassBottomBar collapse trajectory fixed — when GlassBottomBarCollapseConfig with direction: towardsExtraButton was set, the collapsed tab pill stopped short of the extra button, leaving a visible gap between the two circles. The pill now travels to the exact horizontal centre of the extra button on both left and right placements, and the extra button correctly overlays the pill at the end of the animation. Thanks to @jingluoguo for the contribution (#176).

    ✨ Improvements

    • GlassBottomBarCollapseConfig default animationDuration bumped from 220 ms → 280 ms — the collapse animation carries semantic meaning (the tab pill merges into the action button) and the extra 60 ms is enough for the eye to track the trajectory without feeling sluggish. Override it any time via the config:

      collapseConfig: GlassBottomBarCollapseConfig(
        animationDuration: Duration(milliseconds: 220), // snappier
      ),
      
    Open source →
  21. 0.24.3 27 Jul 2026
    Release notes

    🐛 Bug Fixes

    • Transparent scaffold during navigation fixedGlassScaffold was unconditionally setting the inner Scaffold.backgroundColor to Colors.transparent, even when no background widget was provided. This caused the previous route to bleed through the incoming screen during MaterialPageRoute slide transitions, making the new page appear transparent. Fixed by only forcing the scaffold transparent when GlassScaffold actually has a background widget or backgroundColor to render — matching the existing GlassPage behaviour. Screens without an explicit background now inherit the theme's opaque scaffoldBackgroundColor, producing correct, opaque transitions (issue #177).
    Open source →
  22. 0.24.2 27 Jul 2026
    Release notes

    🐛 Bug Fixes

    • Android cold-launch crash fixed — On Android, Flutter's warm-up frame can produce zero-width or unbounded (Infinity) layout constraints before the window fully resolves. RenderLiquidGlassGeometry._buildGeometryPicture would attempt to scale and ceil() those non-finite bounds, throwing UnsupportedError: Infinity or NaN toInt. Fixed by guarding against empty or non-finite bounds and returning a safe empty Picture for the one affected frame. A matching guard was added in LiquidGlassRenderObject.paint to prevent the same non-finite values propagating into toImageSync.
    • Compositing bits race condition fixed (Vulkan/Impeller) — When LightweightLiquidGlass or LiquidGlassRenderObject changed settings that affect alwaysNeedsCompositing, the compositing bit was not synchronised, causing incorrect layer decisions on the first paint under Vulkan. Fixed by calling markNeedsCompositingBitsUpdate() whenever the compositing contract changes.
    Open source →
  23. 0.24.1 26 Jul 2026
    Release notes

    🐛 Bug Fixes

    • GlassButton.custom border invisible in release builds with --obfuscateGlassEffect and LightweightLiquidGlass were using dynamic property access and runtimeType.toString() heuristics to extract the shape's corner radius for the shader. Both techniques are silently broken by the Dart AOT obfuscator: property names are mangled and class names become single-character tokens. The fallback silently resolved to 0.0, producing a perfectly square (borderless) shape in release builds. Fixed by adding a typed effectiveRadius abstract getter to LiquidShape implemented by every concrete shape class — a single virtual dispatch that the compiler can optimise and the obfuscator cannot break.
    Open source →
  24. 0.24.0 26 Jul 2026
    Release notes

    ⚠️ Breaking Changes

    • GlassAppBar.preferredSize constructor parameter removed. Replace with toolbarHeight: double (default 44.0).

      // Before
      GlassAppBar(preferredSize: Size.fromHeight(52))
      
      // After
      GlassAppBar(toolbarHeight: 52)
      

    🐛 Bug Fixes

    • GlassScaffold dark-mode gradient flash fixed. When backgroundColor is set and the device is in dark mode, the edge-fade gradient around GlassTabBar / GlassBottomBar could briefly flash dark. The scaffold now always renders with a transparent Material background (preventing theme bleed), and passes the explicit backgroundColor to the edge-effect fallback gradient.
    • GlassBottomBar default radius inconsistency fixed. Was 32.0; now GlassDefaults.capsuleRadius — consistent with GlassTabBar.bottom.
    • Indicator radius inconsistent across widgets. All interactive widgets (GlassSegmentedControl, GlassTabBar, GlassBottomBar) now share a unified radius calculation that is guaranteed correct during jelly-bloom expansion.

    ✨ New Features

    • 3-tier indicator radius system — all interactive bar/control widgets now follow iOS 26 defaults out of the box:

      • Tier 1 (default): bar and indicator are both a perfect capsule — no configuration needed.
      • Tier 2: set barBorderRadius to a custom value and the indicator automatically tracks at barBorderRadius − padding (concentric nested arcs).
      • Tier 3: set indicatorBorderRadius explicitly to override everything.
    • GlassDefaults.capsuleRadius — named constant (9999.0) for the capsule sentinel:

      GlassBottomBar(barBorderRadius: GlassDefaults.capsuleRadius)
      
    • GlassAppBar.bottom — Accepts any PreferredSizeWidget (typically a TabBar) rendered below the navigation bar title. The scaffold automatically reserves the combined height — no manual sizing needed.

      GlassAppBar(
        title: const Text('Browse'),
        bottom: TabBar(tabs: [...]),
      )
      

    Open source →
  25. 0.23.0 24 Jul 2026
    Release notes

    ⚠️ Breaking Changes

    • AnimatedGlassIndicator.useSuperellipse removed. This parameter has been deleted from the constructor. Any call site passing useSuperellipse: true or useSuperellipse: false will fail to compile.

      Migration: simply remove the parameter. The indicator is always a rounded rectangle (capsule) now, which is mathematically correct. Squircle geometry is unstable for dynamic stretching elements.

      // Before (0.22.1)
      AnimatedGlassIndicator(
        useSuperellipse: false,
        ...
      )
      
      // After (0.23.0) — just remove the parameter
      AnimatedGlassIndicator(
        ...
      )
      

    ✨ New Features

    • LiquidGlassSettings.fresnelStrength — New parameter (range 0.01.0, default 1.0) that scales the natural Fresnel edge luminosity on the Premium rendering path. At 1.0 the glass behaves as physically lit glass with a rim highlight at grazing angles (existing default). At 0.0 the rim is completely suppressed, producing a pure blur-overlay appearance that matches iOS 26 system UI glass (Messages buttons, notification banners, lock screen controls). Intermediate values interpolate smoothly. Fully backwards compatible — omitting the parameter preserves all existing rendering. Also exposed on GlassThemeSettings so it can be set app-wide via GlassTheme.

    • GlassMenuItem.enablePressScale — New bool parameter (default true) that controls the 0.98× scale-down animation on press. Set to false on fill-rate-limited devices to eliminate the per-frame GPU cost of animating a Transform.scale over the glass layer. Fully backwards compatible.

    • GlassExtraButtonPlacement — Added GlassExtraButtonPlacement.left and right for non-searchable bottom bars so GlassTabBarExtraButton can be placed on either side. Defaults to right to preserve existing behavior. Thanks to @jingluoguo (#169).


    🐛 Bug Fixes

    • Fixed hard clip at the top of useOwnLayer: true buttons during press-scale animation on Impeller.
    • GlassSlider — Fixed an issue where discrete slider snapping would round the absolute value and shift the snapped range when using a non-zero minimum. Thanks to @huanglizhuo (#168).

    ♻️ Refactoring — Pure Geometry & iOS 26 Shape Parity

    This release fundamentally solves the long-standing geometry tension between Flutter's path rendering and our GPU shaders. We completely rewrote the squircle math to use pure analytical curves, fixed stretching bugs in tab indicators, and simplified the API.

    1. Pure Analytic Lamé Squircles

    • Shader Rewrite (sdf.glsl): We completely removed the old piecewise 45-degree seam approach and the hacky blend safety valve. sdfSquircle now uses a pure, analytic Lamé curve (|x|^n + |y|^n = 1). Squircles now perfectly match Apple's continuous curve geometry with zero flattening on the edges.
    • Graceful Degradation (The Ghost-Glow Fix): When a squircle is given a radius that physically cannot fit (e.g. r = 18 on a 36px tall button), the shader now dynamically recalculates the exponent n based on the clamped available space. As space runs out, n smoothly degrades to 2.0, collapsing into a perfect circle. This mathematically guarantees that the shader's interaction glow always aligns perfectly flush against Flutter's clipping path, eliminating the dark corner gaps.

    2. Perfect iOS 26 Pills (Capsules)

    Apple never uses squircles for pill shapes (like "Edit" buttons or Tab Indicators). They use pure circular-arc capsules. We audited the library to align with this:

    • GlassChip & Demo Buttons: Replaced LiquidRoundedSuperellipse with LiquidRoundedRectangle for all pill-shaped elements. They now explicitly use sdfRRectAsym, ensuring perfect circular ends.
    • GlassMenu & GlassPopover morph blobs: Replaced LiquidOval with LiquidRoundedRectangle. The rounded rect SDF is mathematically stable at all aspect ratios during dynamic morphs.

    3. AnimatedGlassIndicator API Cleanup

    The glass tab indicator previously suffered from a "stretching bug" where it turned squarish during drag expansion because its finite borderRadius was outgrown by its expanding height.

    • Removed useSuperellipse (see Breaking Changes above): This parameter was mathematically incorrect for dynamic stretching indicators.
    • Optional borderRadius (Default 9999.0): borderRadius is no longer required. It defaults to 9999.0, which offloads the math entirely to the shader's min(r, shortest) clamp. This guarantees a perfect capsule at any drag size.
    • Segmented Controls: GlassSegmentedControl explicitly passes borderRadius: containerRadius - 3, ensuring it retains its correct inset rounded-rectangle geometry rather than defaulting to a capsule.

    📚 Documentation

    • shape_debug_demo.dart — corrected the Standard-mode description banner from the inaccurate "_SquircleClipper + lightweight shader (CPU L4/L2 path)" to the accurate "ShapeBorderClipper + lightweight blur shader (shape-blind)". There is no _SquircleClipper class; the lightweight shader is shape-type-blind by design.

    Open source →
  26. 0.22.1 17 Jul 2026
    Release notes

    🐛 Bug Fixes

    • Tab Bar Semantics — Fixed multiple accessibility issues in GlassTabBar and GlassBottomBar:
      • GlassTab.semanticLabel is now properly propagated, allowing icon-only tabs to be correctly announced instead of defaulting to 'Tab'.
      • Fixed an issue where tab labels were announced twice by wrapping the internal Text widget in ExcludeSemantics.
      • Eliminated duplicate semantic nodes for the active tab by hiding the visual clipping indicator from the accessibility tree, ensuring exactly one node per tab. Thanks to @simiwe (#159).

    ♻️ Refactoring

    • Internal Tab Models — Deprecated GlassBottomBarTab is no longer used by the internal layout engines. They now natively accept GlassTab, removing the need for mapping closures and SizedBox.shrink() sentinels.

    Open source →
  27. 0.22.0 17 Jul 2026
    Release notes

    ci: bump checkout and codecov actions to v7 to resolve Node 20 deprec…

    Open source →
    Release notes

    ✨ New Features

    • ProgressiveBlur — a graduated backdrop blur that is strongest at one edge and dissolves to sharp at the opposite edge (the iOS 26 / Signal header look). Self-contained — no LiquidGlassLayer ancestor required.

      Positioned(
        top: 0, left: 0, right: 0, height: 96,
        child: ProgressiveBlur(maxSigma: 20),
      )
      
      • maxSigma — blur sigma at the strong edge (0 ⇒ passthrough).
      • direction — which edge is strongest (topToBottom / bottomToTop / leftToRight / rightToLeft).
      • falloff — gradient gamma (default 1.2).

      Pre-warmed by LiquidGlassWidgets.initialize() at no extra startup cost; ProgressiveBlur.preload() is available for standalone use. Degrades to a uniform BackdropFilter on Skia / web. See docs/PROGRESSIVE_BLUR.md. Thanks to @Ahmadre (#162).

    ⚡ Performance

    • GlassPopover blur ramp — the backdrop blur now eases in over the opening morph instead of rendering at full strength from frame one. Raster avg halved (10.1 ms → 5.8 ms), worst-case halved, missed-budget frames 15 → 6 on the reference device. See docs/POPOVER_BLUR_RAMP.md.

      Two new backwards-compatible params:

      • blurRampDuration (default Duration(milliseconds: 260)) — set to Duration.zero to restore the previous always-full-blur behaviour.
      • blurRampCurve (default Curves.easeOut).

      Automatically disabled when "reduce motion" is active. Thanks to @Ahmadre (#161).

    🐛 Bug Fixes

    • GlassPopover drifted off its trigger in nested overlays — the morph portal now targets OverlayChildLocation.rootOverlay to match the root-relative coordinates it is placed at. Top-level usage is unaffected. Thanks to @Ahmadre (#163).

    • Intrinsic-height GlassPopover overflowed on live content growth — the popover now re-measures via SizeChangedLayoutNotifier when content grows while open, instead of clamping to the height frozen at open time. Fixed-popoverHeight popovers are unchanged. Thanks to @Ahmadre (#163).


    Open source →
  28. 0.21.6 15 Jul 2026
    Release notes

    🐛 Bug Fixes

    • GlassTabBar.bottom / GlassBottomBar distorted tap hit regions with >2 tabs (#157) — Tapping a tab incorrectly routed through DraggableIndicatorPhysics.getAlignmentFromGlobalPosition, which applies an indicator-center remap (±½ tab-width padding) designed for continuous drag tracking. For discrete taps this shifted the hit boundaries from the correct 25/50/75 % to ~31.25/50/68.75 % on a 4-tab bar, making the right ~25 % of tab 2 select tab 3 instead. A new tabIndexFromGlobalPosition helper bypasses the drag remap and computes the tab index directly from the raw position fraction. The same incorrect remap was present in the recoverIfGestureStuck path (PlatformView gesture recovery) and is fixed there too. The drag path (onHorizontalDragUpdate / onHorizontalDragStart) is unaffected. Thanks to @bayraktarmdkaraca for the precise root-cause analysis!

    Open source →
  29. 0.21.5 14 Jul 2026
    Release notes

    🐛 Bug Fixes

    • GlassTabBar loses shadow when OS is Dark but app is ThemeMode.light — fixed an issue where glass components incorrectly resolved to Brightness.dark when the device OS was in Dark Mode but the MaterialApp was explicitly set to ThemeMode.light. The brightness cascade in resolveGlassBrightness was checking the CupertinoTheme before the Material ThemeMode; inside a MaterialApp the Cupertino theme is implicitly derived from the OS, causing it to return the wrong brightness. The cascade now correctly prioritises ThemeMode in MaterialApp contexts. Thanks to @minhtritc97 for the detailed report!

    Open source →
  30. 0.21.4 13 Jul 2026
    Release notes

    ✨ New Features

    • Vertical GlassSegmentedControl — fixed controls now accept direction: Axis.vertical and an optional segmentExtent. Layout, fractional indicator positioning, jelly expansion, drag velocity, snapping, and gesture recognition all follow the vertical axis. The horizontal default and scrollable constructor remain unchanged. Thanks to @F1orian!

    🐛 Bug Fixes

    • Impeller shadow corruption fixedshadowElevation on LiquidGlass and GlassButton rendered as solid black circles on Windows, Web, and certain Android emulators due to two known Flutter engine bugs (saveLayer texture corruption on Vulkan and Path.combine clipping failures). The package now selectively bypasses the GPU shadow cutout on affected platforms and uses a safe evenOdd winding rule for the fallback, producing perfect shadows without engine issues.

    🧪 Example

    • Added an icon-only vertical segmented control to the Interactive page for tap, drag, indicator, and accessibility testing on a physical device.

    Open source →
  31. 0.21.3 07 Jul 2026
    Release notes

    🐛 Bug Fixes

    • SVG and custom icons restoredSizedBox-wrapped icons (e.g. SvgPicture) were silently stripped from the render tree since 0.20.0. The SizedBox.shrink() sentinel detection now checks width, height, and child fields so a caller-supplied SizedBox wrapping a real icon is always rendered correctly.
    • Searchable bar pill stays active while dragging — the glass indicator on GlassTabBar.searchable collapsed back to its resting state when the finger passed over the currently selected tab mid-drag. The thickness spring now includes the tabIsDragging guard, matching the behaviour already present in GlassTabBar.bottom.
    • JellyClipper Impeller radius guard — the clip radius is now clamped to strictly less than half the indicator's shortest side, preventing a malformed RRect path that caused content to vanish under Impeller's Metal renderer in certain animation frames.

    🧹 Example

    • Indicator Parity demo calibrated — default refraction set to 1.15 (GlassDefaults.refractiveIndex) to match all Apple demos; both GlassTabBar.inline variants now wire live tuner sliders for expansion and pinch strength.

    Open source →
  32. 0.21.2 07 Jul 2026
    Release notes

    🐛 Bug Fixes

    • Extra button stretch disabled over platform viewsGlassTabBarExtraButton now correctly disables its stretch effect when platformViewBackdrop: true, matching the behavior of GlassTabBar.bottom and fixing the jittery spring animation.
    • GlassMenu item scroll wiggle fixed — menu items with wrapped text (e.g. maxLines: 2) could drift sub-pixel vertically during slide-to-select dragging because ClampingScrollPhysics allowed fractional scroll offsets even when no overflow was intended. Non-scrollable menus now use NeverScrollableScrollPhysics, locking the content completely in place during drag.
    • GlassPopover first-frame height fixed — the popover was briefly rendered at full-screen height before its content height was known, producing a visible flash and forcing users to wrap content in a SingleChildScrollView as a workaround. An invisible Offstage measurement pass now runs on Frame 1, letting Flutter's layout engine calculate the exact intrinsic content height before the morph animation starts. The animation launches on Frame 2 with perfect geometry — no mid-flight height correction, no flash, no heuristics.

    ⚡ Performance

    • Removed unnecessary compositing layer in GlassBottomBar — the RepaintBoundary wrapping the icon layer in _buildHighQualityMode is now only mounted when platformViewBackdrop: true, where it is required for the Platform View capture path (bug #99). In the common case (platformViewBackdrop: false) the boundary was creating a GPU offscreen texture every frame with no caching benefit, since the JellyClipper changes on every animation frame.
    • GlassPopover idle trigger optimised — when the popover is fully closed, the trigger widget now skips unnecessary Transform, Opacity, and IgnorePointer compositing layers. This removes redundant GPU work in the common idle state.

    🧹 Code Quality

    • Null-safe trigger child access — replaced a child! force-unwrap in GlassPopoverInternal with a null-safe child ?? const SizedBox.shrink() fallback, preventing a hard crash if child is ever omitted in a future refactor.

    🧪 Example

    • Refraction slider added to Indicator Parity demo tuner — a "Refraction (n)" slider (range 1.0–2.0, default 1.59 matching GlassTabBar.bottom's internal default) for tuning the refractiveIndex on the Premium (Impeller) glass indicator. Standard indicators do not perform background capture so the parameter has no visual effect there.

    Open source →
  33. 0.21.1 05 Jul 2026
    Release notes

    🐛 Bug Fixes — Standard indicator parity

    • Two-pills misalignment fixed — at GlassQuality.standard, the background rim and glass lens now share the same shape geometry (ShapeDecoration) and ride the same jelly Transform, eliminating the visible separation mid-morph. Regression reported against GlassTabBar.inline / segmented controls.
    • Indicator collapse on drag fixed — the glass indicator no longer morphs back to the resting pill when dragging over the selected tab. The thickness gate now includes tabIsDragging so the indicator stays fully active for the entire gesture duration.
    • Standard rim thickness normalised — the indicator rim on GlassQuality.standard is now proportionally mapped from indicatorSettings.thickness (same value as Premium) rather than scaling from the raw glass-depth value, which produced a ~2.8 px border. The result is a fine hairline that gracefully matches the Premium look on Standard-quality devices.

    Open source →
  34. 0.21.0 04 Jul 2026
    Release notes

    ✨ New Features

    • GlassModalSheet drag progress — controller now exposes a progress getter and progressListenable reporting the live 0–1 drag position between half↔full snap points, so hosts can drive coordinated UI in real time. (#148, @jfhair)
    • GlassTabBar.inline spring control — the .inline factory now accepts springDescription, matching the other factory constructors. Previously inline tab bars were locked to the shared default spring. (#149, @jfhair)
    • LiquidGlassSettings.ambientRim — tunable full-perimeter rim on the moving indicator pill. Defaults match Apple Music's segmented control (brighter in light mode, off in dark). (#150, @jfhair)
    • AnimatedGlassIndicator shadowshadowElevation/shadow in indicatorSettings now correctly paints a drop shadow on the glass jelly. Previously these values were silently ignored. (#151, @jfhair)

    🐛 Bug Fixes — PlatformView gesture stability

    • Tab bar freeze fixed: Intermittent freeze where the tab indicator stopped responding after interacting over an iOS PlatformView (e.g. a map or WebView). The iOS gesture arena can silently drop terminal callbacks, leaving the recognizer wedged. Fixed with proactive cleanup on PointerDown, post-frame recovery, and a gesture ID guard to prevent rapid-tap state corruption.
    • Hybrid gesture mode on platformViewBackdrop: true: When the tab bar floats over a PlatformView, the visual indicator now animates to its new position instantly on touch-down (matching native iOS responsiveness), while the actual tab content swap is deferred safely to touch-up. This prevents the iOS UIKit view system from dropping the touch stream mid-gesture due to a mid-frame unmount of the PlatformView. No impact on any screen where platformViewBackdrop is false — those continue to swap instantly on down.
    • Stretch disabled on platformViewBackdrop: true: Flutter's BackdropFilter must re-acquire the native pixel buffer every time its bounding box changes. Stretch animations resize the glass container, causing a one-frame flicker over a PlatformView. Stretch is now skipped on all bar elements when platformViewBackdrop is set; press-scale (interactionScale) is unaffected because it is a GPU-level transform that leaves the backdrop bounds stable. No impact on any other screen or platform.

    Open source →
  35. 0.20.1 02 Jul 2026
    Release notes

    🐛 Bug Fix — GlassButton.custom layout expansion

    Fixes: GlassButton.custom unexpectedly expanding to fill bounded parent constraints (e.g., inside AppBar actions) (#146).

    • GlassButton.custom height now correctly defaults to null (matching documented behavior).
    • The button now properly shrink-wraps to its content when explicit width/height are not provided.
    • Migration: No breaking changes. If you were relying on the undocumented 56px default height, explicitly set height: 56.

    Open source →
  36. 0.20.0 02 Jul 2026
    Release notes

    💥 Breaking — GlassListTile divider refactor

    GlassListTile no longer draws its own divider. The isLast, showDivider, and dividerIndent parameters have been removed.

    Rationale: A list tile should be a clean, position-agnostic item. Divider rendering is a layout concern that belongs to the parent container.

    Migration

    Inside GlassGroupedSection — no changes needed. GlassGroupedSection now automatically injects GlassDividers between tiles with smart leading-indent detection (56px if the preceding tile has a leading widget, 16px otherwise). The last tile never gets a trailing divider.

    Standalone column layouts — compose GlassDivider explicitly:

    // Before:
    Column(children: [
      GlassListTile(title: Text('A')),                    // showDivider: true (default)
      GlassListTile(title: Text('B'), isLast: true),      // suppresses divider
    ])
    
    // After (standard Flutter composition pattern):
    Column(children: [
      GlassListTile(title: Text('A')),
      GlassDivider(indent: 16),
      GlassListTile(title: Text('B')),
    ])
    

    This aligns with Flutter's own ListTile + Divider composition model.


    ✨ New — GlassTabBar.inline

    A compact glass tab bar for pinned content-filter sections — sits fixed between a page header and its scrollable list, not inside the scroll view itself.

    Performance note: GlassQuality.premium re-runs the full shader pipeline whenever the backdrop changes. Placing the bar inside a scroll view invalidates the backdrop on every scroll frame. Pin it outside the scrollable region or drop to GlassQuality.standard if embedding inside a list.

    GlassTabBar.inline(
      tabs: const [
        GlassTab(label: 'For You'),
        GlassTab(label: 'Following'),
        GlassTab(label: 'New'),
      ],
      selectedIndex: _selectedIndex,
      onTabSelected: (i) => setState(() => _selectedIndex = i),
    )
    

    Key differences from GlassTabBar.bottom:

    • Zero padding — sits flush in its parent container.
    • Compact height (40px) with a full stadium shape (barBorderRadius: 100, clamped to height/2).
    • Indicator pill automatically matches the track corner radius (indicatorBorderRadius defaults to barBorderRadius).
    • Indicator expansion h:12, v:10 — same horizontal weight as GlassSegmentedControl and GlassTabBar.bottom, +2px vertical to compensate for the shorter bar height giving the glass pill proportional visual mass.
    • indicatorPinchStrength: 0.4 — aligned with all other pill controls.
    • Magnification disabled (1.0x) — text labels never grow on selection.
    • Text-only tabs render with correct vertical centering (no icon slot consuming space).
    • extraButton not supported (structural navigation feature only).

    All standard physics parameters (indicatorPinchStrength, indicatorExpansion, indicatorSettings, quality) are still fully configurable.

    See the updated Indicator Parity demo (indicator_parity_demo.dart) where GlassTabBar.inline now appears alongside the other five pill widgets — including a text-only variant (40px) and an icon + text variant (52px) — with live tuning sliders.


    Open source →
  37. 0.19.7 02 Jul 2026
    Release notes

    🐛 Bug Fixes

    • GlassTabBar.bottom / GlassBottomBar — fixes RTL support (#143, @naeemeltaief). The pill and tap/drag hit-testing now correctly align with the visually reversed tab order under RTL. The bottom layout normalises the tab data, selected index and callback for RTL, and pins only the two inner tab Rows to LTR — leaving indicatorExpansion, tabPadding and all text to resolve against the ambient direction as expected. Consumers no longer need to force Directionality.ltr and reverse tabs by hand. +2 tests.

    • AnimatedGlassIndicator — restores the resting selection pill inside a GlassContainer (#144, @jfhair). The background pill was permanently hidden whenever an ancestor set avoidsRefraction, which is a steady-state layout flag on GlassContainer — not a transient capture signal. The guard was incorrect and is removed. The pill now renders correctly in all contexts. No API change. +1 test.

    Open source →
  38. 0.19.6 01 Jul 2026
    Release notes

    ✨ New — GlassLargeTitle + GlassLargeTitleController

    First-class iOS 26 large-title + search-bar collapse. Replaces manual ScrollController + setState wiring with a single controller and two widgets.

    Two-phase collapse

    • Phase 1 — large title fades out (Curves.easeIn, rubber-band overscroll stretch).
    • Phase 2 — optional inline search bar collapses under the nav bar immediately after.

    New API

    • GlassLargeTitle — sliver widget. Drop it as the first sliver in any CustomScrollView.
      • searchBar: Widget? — Phase 2 collapse (e.g. GlassSearchBar).
      • trailing, fontSize, fontWeight, letterSpacing, padding, searchBarPadding, color.
    • GlassLargeTitleController — owns the ScrollController, exposes collapseProgress and searchBarCollapseProgress. Self-calibrates to Dynamic Type via reportMeasuredHeight / reportSearchBarHeight.
    • GlassAppBar.largeTitleController — new optional param. Bar title cross-fades in as the large title collapses. Non-breaking.
    final _ctrl = GlassLargeTitleController(); // dispose in State.dispose()
    
    // Phase 1 only
    GlassLargeTitle(text: 'Chats', controller: _ctrl)
    
    // Phase 1 + 2
    GlassLargeTitle(
      text: 'Messages',
      controller: _ctrl,
      searchBar: GlassSearchBar(placeholder: 'Search', onChanged: (_) {}),
    )
    

    Demo

    • Pattern 2 updated to new API. Pattern 7 (Large Title + Search Bar) added.
    • Apple Messages demo migrated from manual AnimatedOpacity to GlassLargeTitle.

    +10 tests. 2,291 total, all passing.

    ⚡ Performance — GlassBottomBar Indicator (Impeller)

    • GlassBottomBar indicator — eliminates the live BackdropFilterLayer on Impeller premium, replacing it with a deterministic toImageSync capture path. Fixes the opaque-white indicator rendering on physical iOS (#99) and improves drag performance by removing a redundant compositor pass.

    🔧 GlassGroupedSection — Header/Footer styling

    • Header and footer text is now styled automatically via DefaultTextStyle (CupertinoColors.secondaryLabel, 13pt) — callers no longer need to style them manually.
    • Margin is now applied via Padding wrapping the full section rather than on the inner GlassCard, fixing card-edge clipping when a header or footer is present.
    • Import changed to cupertino.dart for correct CupertinoColors resolution.

    📝 Dart doc improvements

    • GlassContainer, GlassCard, GlassGroupedSection, GlassSegmentedControl — added ⚠️ Anti-Pattern sections documenting the glass-in-glass restriction: placing interactive glass controls inside a container degrades refraction and clips jelly animations.
    Open source →
  39. 0.19.5 30 Jun 2026
    Release notes
    • LiquidGlassSettings — adds platformViewFallbackColor (#138, @jfhair). Splits backerColor's dual role: backerColor remains the aesthetic backer pad; the new field controls the uBackgroundFallback shader uniform (PlatformView fill). Fully backwards-compatible — defaults to null, falling back to backerColor.

    • GlassModalSheet — removes the interior BoxShadow that bled through the glass as a vignette (#137, @jfhair). Elevation now flows via LiquidGlassSettings.shadowElevation. Pass shadowElevation: 0 to disable entirely.

    Open source →
  40. 0.19.4 29 Jun 2026
    Release notes

    ✨ Enhancements — GlassButtonGroupItem.menu & GlassPullDownButton improvements

    GlassButtonGroupItem.menu — whole-pill liquid glass morph

    Adds a new GlassButtonGroupItem.menu named constructor that turns any item in a GlassButtonGroup.icons pill into a pull-down menu trigger.

    When tapped, the entire pill morphs into the menu — the full GlassButton.custom shell becomes the GlassMenu trigger, so the whole group shape liquefies and expands into the menu card. This matches the iOS 26 GlassEffectContainer morph pattern where the source shape, not just the tapped slot, participates in the transition.

    GlassButtonGroup.icons(
      items: [
        GlassButtonGroupItem(icon: Icon(CupertinoIcons.chart_bar), onTap: () {}),
        GlassButtonGroupItem(icon: Icon(CupertinoIcons.clock),     onTap: () {}),
        GlassButtonGroupItem.menu(
          icon: Icon(CupertinoIcons.ellipsis),
          menuItems: [
            GlassMenuItem(title: 'Add to Watchlist', icon: Icon(CupertinoIcons.star), onTap: () {}),
            GlassMenuItem(title: 'Share',            icon: Icon(CupertinoIcons.share), onTap: () {}),
            GlassMenuDivider(),
            GlassMenuItem(title: 'Remove', icon: Icon(CupertinoIcons.trash), isDestructive: true, onTap: () {}),
          ],
          menuAlignment: GlassMenuAlignment.topRight, // optional
          menuWidth: 200,                              // optional, default 200
        ),
      ],
    )
    

    Notes:

    • Only the first GlassButtonGroupItem.menu in the list is used as the menu trigger; any subsequent menu items are treated as plain tap items.
    • Accepts both GlassMenuItem and GlassMenuDivider, matching GlassMenu.items directly.
    • Non-menu siblings in the group continue to fire their own onTap independently.
    • Works with both Axis.horizontal and Axis.vertical groups.

    Alternatively — group + standalone GlassPullDownButton

    For cases where the menu trigger is a separate, visually distinct action from the group (e.g. a trailing overflow button next to a row of chart controls), compose a GlassButtonGroup alongside a standalone GlassPullDownButton. The pull-down button morphs independently and fully, with no pill residue:

    Row(
      children: [
        GlassButtonGroup.icons(
          items: [
            GlassButtonGroupItem(icon: Icon(CupertinoIcons.chart_bar), onTap: () {}),
            GlassButtonGroupItem(icon: Icon(CupertinoIcons.clock),     onTap: () {}),
          ],
        ),
        SizedBox(width: 8),
        GlassPullDownButton(
          icon: Icon(CupertinoIcons.ellipsis),
          menuAlignment: GlassMenuAlignment.topRight,
          items: [
            GlassMenuItem(title: 'Add to Watchlist', icon: Icon(CupertinoIcons.star), onTap: () {}),
            GlassMenuItem(title: 'Share',            icon: Icon(CupertinoIcons.share), onTap: () {}),
            GlassMenuDivider(),
            GlassMenuItem(title: 'Remove', icon: Icon(CupertinoIcons.trash), isDestructive: true, onTap: () {}),
          ],
        ),
      ],
    )
    
    .menu item (shared pill) group + standalone
    All actions in one pill
    Entire pill morphs
    Menu button morphs independently
    Best for Overflow within a related set Separate trailing action

    GlassPullDownButton improvements

    • items widened to List<Widget> — now accepts GlassMenuDivider alongside GlassMenuItem. Source-compatible: existing List<GlassMenuItem> code compiles and behaves identically. The onSelected callback is applied only to GlassMenuItem instances.
    • menuAlignment exposed — new GlassMenuAlignment? parameter forwarded to the underlying GlassMenu. Defaults to null (auto-detect from screen position) — fully backward-compatible.

    🐛 Bug Fixes — PlatformView Frost Halo & GlassButton Dispose-Race (#134, #135)

    Both fixes contributed by @jfhair.

    LiquidOval rectangular blur halo over a PlatformView (#134)

    Problem: Any glass surface with a LiquidOval shape (the default for GlassButton, GlassIconButton, the collapsed search/dismiss pill, and GlassBottomBarExtraButton) rendered a rectangular blur halo when platformViewBackdrop: true routed it through the _FrostedFallback BackdropFilter path. The halo matched the widget's bounding box rather than its circular outline.

    Root cause: Flutter engine PR #177551 (3.41+) forwards ClipRRect clip data to the iOS PlatformView mutator stack, allowing a descendant BackdropFilter to be bounded correctly over a hybrid-composed view. The same forwarding does NOT apply to ClipPath — and LiquidOval (unlike LiquidRoundedSuperellipse) was routing through ClipPath, leaving the BackdropFilter unclipped.

    Fix: _ShapeClip now accepts a platformViewBackdrop flag. When set, any shape whose border radius can be expressed as a BorderRadius (including LiquidOvalcircular(9999), LiquidRoundedRectangle, and their vertical variants) is routed through ClipRRect instead of ClipPath. The clip is then forwarded to the PlatformView mutator stack and the frost is bounded cleanly to the shape. Off a PlatformView the original ClipPath is used (true ellipse). The flag is threaded through all _ShapeClip call sites in _FrostedFallback — the blur body, the content clip, and the specular rim — as well as the backer dimming pad in AdaptiveGlass._wrapWithBacker.

    Completes the partial fix shipped in 0.19.3 and fully resolves the rectangular-blur regression first reported in #79.

    GlassButton crash when disposed mid-press (#135)

    Problem: Tapping a GlassButton that is removed by the very tap that activates it (e.g. a collapsed bar restore button that expands the bar and disposes itself) could throw:

    AnimationController.reverse() called after AnimationController.dispose()
    (assert _ticker != null)
    

    A queued pointerUp or pointerCancel was still dispatched to the now-disposed RenderPointerListener, and the press handler called _saturationController.reverse() after dispose().

    Fix: All six tap/pointer press handlers in _GlassButtonState now guard on !mounted before touching _saturationController. A disposed State always has mounted == false, so the handler bails safely without touching the controller.

    Surfaces frequently in apps that morph or collapse a bar on the tap of a glass control over a PlatformView (the pattern introduced in #127/#79).

    Open source →
  41. 0.19.3 29 Jun 2026
    Release notes

    🐛 Bug Fixes — Search Pill Colors & PlatformView Compositing

    • Fixed an issue where the SearchPill icon colors (search, mic) would incorrectly render as black when using dark glass (glassColor: Colors.black26) over an iOS PlatformView. The root cause was that the color resolution used the OS system brightness (light) instead of the glass brightness (dark), causing CupertinoDynamicColor.label to always resolve to its light-mode black variant. The widget now resolves colors through GlassTheme.brightnessOf() — the package's single brightness authority — and explicitly passes the resolved color via IconThemeData to guarantee white glyphs on dark glass regardless of system brightness.
    • Mitigated a Flutter engine clipping bug over PlatformViews by ensuring LiquidRoundedSuperellipse and LiquidOval correctly clip their bounds using an outer ClipRRect when rendering over an iOS PlatformView, preventing blur bleed outside the circular button shape.
    • Updated the google_maps_demo to correctly demonstrate how to configure selectedIconColor, unselectedIconColor, and searchIconColor for dark glass bottom bars to ensure all tab elements remain visible over the map layer.
    Open source →
  42. 0.19.2 29 Jun 2026
    Release notes

    🐛 Bug Fixes — PlatformView Gesture & Rendering

    This release resolves a pair of related issues that caused the glass bottom bar to freeze and render incorrectly when floating over an iOS PlatformView (e.g. a Mapbox map). All three fixes were contributed by @jfhair via detailed PRs that included root-cause analysis, regression tests, and working reproductions. Many thanks for the exceptional quality of this contribution.

    Gesture freeze over an iOS PlatformView (#127)

    Problem: GlassTabBar.searchable (and GlassBottomBar) would freeze when the draggable indicator was dragged or tapped while the bar floated over an iOS PlatformView. The freeze was permanent until the widget was rebuilt or disposed.

    Root cause: iOS reconstructs the platform-view clip chain whenever a clip layer is added or removed mid-gesture. The engine responds by cancelling the active touch, which left the bar's GestureDetector recognizer wedged — it never received a terminal callback (onDragEnd / onDragCancel) and stopped responding to input. The most frequent trigger was the indicator's innerBlur frost layer unmounting at drag-start (a clip-add/remove cycle).

    Fix — two-part:

    • Primary fix (PR #127): The indicator's frost ClipRRect + BackdropFilter layer now stays mounted across the full drag lifecycle by tracking a persistent bool _frostMounted flag in AnimatedGlassIndicator. This eliminates the clip-add/remove cycle that was triggering the iOS clip-chain reconstruction.
    • Backstop fix (PR #127): TabBarDragGestureMixin gains a gestureEpoch counter, a _gestureActive liveness flag, and a raw Listener on the GestureDetector subtree. If the raw pointer-up or pointer-cancel arrives while _gestureActive is still true (i.e. the terminal callback was silently dropped by the platform-view gesture arena), recoverIfGestureStuck is called: it selects a fallback tab, bumps gestureEpoch (forcing the GestureDetector to be torn down and recreated via ValueKey), and clears the stuck state. Covers both the tap-without-cancel and drag-start-without-end freeze signatures.

    PlatformView backdrop routing (#128)

    Problem: Setting platformViewBackdrop: true on a bar had no visible effect for the glass indicator or bar body — the premium/standard Impeller shader paths read a captured backdrop that excludes hybrid-composed PlatformViews, so the glass rendered inert (opaque black or clear) over a map.

    Fix: AdaptiveGlass now routes any surface with platformViewBackdrop: true to the frosted fallback (_FrostedFallback) regardless of the requested quality tier. The frosted fallback uses a live BackdropFilter, which correctly blurs hybrid-composed PlatformViews. _FrostedFallback also overrides the isInteractive blur-omission that would otherwise skip the blur for interactive indicator surfaces — over a PlatformView the live blur must always run.

    Premium glass goes black over a PlatformView — backerColor fallback (#129)

    Problem: At GlassQuality.premium over a PlatformView, the Impeller shader sampled a captured backdrop that contained only transparent black where the PlatformView sat. With no real background pixels to refract, the glass lens rendered black.

    Fix: A new uBackgroundFallback (vec4) uniform was added to liquid_glass_final_render.frag. The shader composites the fallback colour over the captured backdrop using a standard over blend weighted by the backdrop's own alpha — where the backdrop is real (alpha ≈ 1) it is left untouched; where it is transparent black (alpha ≈ 0, i.e. over a PlatformView) the fallback fills in. backerColor from LiquidGlassSettings is bound to this uniform at render time, giving the premium lens a solid colour to refract instead of transparent black.

    Extra button platformViewBackdrop threading (follow-up, this release)

    GlassTabBarExtraButton previously ignored the bar's platformViewBackdrop flag — the internal BottomBarExtraBtn widget was not forwarding it to the underlying GlassButton, so the extra button continued to use the inert shader path even when the rest of the bar correctly used the frosted fallback. platformViewBackdrop is now threaded through BottomBarExtraBtn and both call sites (TabBarBottomLayout, TabBarSearchableLayout) to GlassButton.


    Open source →
  43. 0.19.1 25 Jun 2026
    Release notes

    🛡️ Stability Improvements

    Addresses production crash and ANR reports seen with v0.19.0 on Flutter 3.44.2 (tracked in flutter/flutter#187140). These are exposure-window mitigations — the root cause is a Flutter engine issue and requires an engine-level fix.

    Changes

    GlassEffect & LightweightLiquidGlass — lifecycle-aware Ticker suspension Both state classes now implement WidgetsBindingObserver and halt background-capture Tickers during AppLifecycleState.inactive, paused, and hidden. Captures restart one frame after resumed. This reduces GPU texture activity during surface transitions (rotation, split-screen, keyboard resize) which is the window where engine-level crashes and ANRs are most likely to occur.

    GlassEffect & LightweightLiquidGlass_isDisposed guard A _isDisposed flag prevents Ticker callbacks and async .then() continuations from accessing GPU resources after dispose() has completed, guarding against post-frame-callback / dispose races during rapid navigation.

    LiquidGlassWidgets.initialize() — faster startup The Impeller pipeline warm-up is no longer awaited inside initialize(). It now runs after the first frame via addPostFrameCallback, removing a ~16ms delay from the startup critical path. Shader disk-loads are still awaited as before.

    Debug log cleanup Removed stale debugPrint success messages from GlassEffect and LightweightLiquidGlass shader pre-warm paths (✓ Shader precached, ✓ Created unique shader instance). These fired on every debug startup for every app using the package. Failures still surface via the existing [LightweightGlass] Pre-warm failed: error log. The [LiquidGlass] startup bracket (Initializing... / Initialization complete.) and the PerformanceMonitor started log are retained as actionable developer information.

    Open source →
  44. 0.19.0 25 Jun 2026
    Release notes

    💥 Breaking: Pre-v1.0 Public API Cleanup

    A pre-release naming audit to establish consistent, idiomatic conventions before v1.0 locks the API.

    Renames

    Old New Reason
    GlassBottomBarExtraButton GlassTabBarExtraButton Tracks parent rename GlassBottomBarGlassTabBar
    GlassGroupItem GlassButtonGroupItem Mirrors Flutter's DropdownMenuItem pattern
    SheetState GlassSheetState Prevents collision with Material 3 sheet infrastructure
    SheetMode GlassSheetMode Same — too generic as a bare name
    FillTransition GlassFillTransition Too generic as a bare name
    ExtraButtonPosition GlassExtraButtonPosition Ambiguous without prefix

    Migration: A @Deprecated typedef for GlassBottomBarExtraButton is provided. All other old names will produce compile errors — migration is mechanical find-and-replace.

    GlassSegment — new concrete class

    GlassSegment was previously a typedef alias for GlassTab. It is now a proper class with a focused API for GlassSegmentedControl:

    // GlassSegment — for GlassSegmentedControl only
    GlassSegment({ Widget? icon, String? label, String? tooltip, String? semanticLabel, bool enabled = true })
    
    // GlassTab — for GlassTabBar.bottom() and GlassTabBar.searchable()
    GlassTab({ Widget? icon, Widget? activeIcon, String? label, Color? glowColor, double? thickness })
    

    Fields like activeIcon, glowColor, and thickness are navigation-specific and only exist on GlassTab. GlassSegment adds tooltip and enabled (with built-in disabled rendering at 38% opacity).

    Barrel hygiene

    Internal types (SheetSnapshot, SheetGeometry, GesturePhase, GestureArena, FrozenState) are no longer accessible from the package barrel. These were implementation details that leaked through part file exports.

    ⚡ Performance

    • Shader: interactive_indicator.frag — replaced pow() calls with multiply chains; collapsed duplicate rim pass; zero transcendental functions in highlight path.
    • Shader: liquid_glass_final_render.frag⁶√x computed via sqrt cascade (3 SFU vs 2 transcendentals); sceneSDF samples reduced from 5 → 4.
    • Dart: resolveAdaptiveRadius scoped to MediaQuery.viewPaddingOf + MediaQuery.sizeOf — glass widgets no longer rebuild on keyboard or unrelated MediaQueryData changes.
    • Dart: Searchable tab bar and GlassSegmentedControl spring animations now use ListenableBuilder scoped to the indicator subtree. Verified on-device: zero State.build() calls during 120Hz spring animation.

    🐛 Fix

    • LiquidGlassWidgets.initialize() now pre-warms all four shaders — liquid_glass_geometry_blended.frag and liquid_glass_final_render.frag were previously lazy-loaded, causing first-frame jank.
    • GlassSegment.enabled = false now blocks tap/tapDown — disabled segments rendered at 38% opacity but still fired onSegmentSelected in both fixed-width and scrollable modes. Tap and onTapDown handlers now early-return when the target segment is disabled.

    Open source →
  45. 0.18.6 24 Jun 2026
    Release notes

    🐛 Fix: Glass widgets now honour app ThemeMode, not OS dark mode

    Resolves a class of UI inconsistency where glass widgets incorrectly read the device/OS brightness instead of the app's brightness. The most visible symptom was GlassBottomTabBar shadows disappearing when the device was in Dark Mode but the app was pinned to Light Mode via MaterialApp(themeMode: ThemeMode.light).

    Root cause

    Every glass widget that needed to decide between light/dark colours or shadow visibility called either CupertinoTheme.of(context).brightness or MediaQuery.platformBrightnessOf(context) directly. Both of these APIs fall back to the OS/device setting and are blind to MaterialApp.themeMode.

    Fix: Centralised brightness cascade

    A new GlassTheme.brightnessOf(context) authority now governs all brightness decisions in the library. It resolves via a four-level cascade:

    1. GlassThemeData.brightness — new field; an explicit developer override pinned in the GlassTheme widget tree (highest priority).
    2. CupertinoThemeData.brightness — explicit Cupertino pin (non-null only; intentional opt-in).
    3. Theme.maybeBrightnessOf(context) — Material ThemeMode.light/.dark/.system, honouring MaterialApp.themeMode.
    4. MediaQuery.platformBrightnessOf(context) — OS/device setting (safe fallback).

    Changes

    • New: lib/utils/glass_brightness.dartresolveGlassBrightness(context) utility (package-private).
    • New field: GlassThemeData.brightness — explicit brightness override for fine-grained glass-subtree control. Accepted by both the default and GlassThemeData.simple() constructors.
    • New method: GlassTheme.brightnessOf(context) — the single, mandatory brightness authority for the entire library.
    • Fixed: Shadow suppression in GlassBottomTabBar, GlassSearchableBottomBar, AdaptiveLiquidGlassLayer, and AdaptiveGlass (_FrostedFallback).
    • Fixed: Shader backdropLuma proxy in GlassEffect (controls glass strength in the GPU path).
    • Fixed: Light/dark colour selection in 20+ widget files across interactive/, containers/, input/, overlays/, and surfaces/ layers.

    Tests

    Three new test files cover every level of the cascade:

    • test/utils/glass_brightness_test.dart — unit tests for resolveGlassBrightness.
    • test/theme/glass_theme_brightness_test.dartGlassTheme.brightnessOf integration tests including the canonical regression scenario.
    • test/theme/glass_theme_data_brightness_test.dartGlassThemeData.brightness override field, copyWith, equality, and backward-compat tests.

    Open source →
  46. 0.18.5 24 Jun 2026
    Release notes

    🔧 Corrected minimum SDK constraint — Flutter ≥ 3.41.0

    • Fix: Raised the minimum Flutter constraint to 3.41.0. The filterQuality parameter on FragmentShader.setImageSampler() was actually introduced in Flutter 3.41.0 (commit add442b29c), not 3.24.0 as previously stated. This prevents users on 3.38.x from failing at compile time.
    • Reverted: Raised the internal meta constraint back to ^1.18.0 since Flutter 3.41.0 guarantees this version is available.

    Open source →
  47. 0.18.4 23 Jun 2026
    Release notes
    • Fix: Loosened the meta dependency constraint to ^1.12.0 (instead of ^1.18.0) to avoid pub resolution conflicts for users on older Flutter SDKs where flutter_test is bound to meta 1.17.0.

    Open source →
  48. 0.18.3 23 Jun 2026
    Release notes

    ✨ Per-state label text style on bottom bars — selectedLabelStyle / unselectedLabelStyle

    Adds selectedLabelStyle / unselectedLabelStyle (TextStyle?) to GlassTabBar.bottom, GlassTabBar.searchable, and the deprecated GlassBottomBar / GlassSearchableBottomBar.

    This complements the selectedLabelColor / unselectedLabelColor parameters by letting callers set the selected/unselected label's font family, weight, and letter-spacing per state — needed to match Apple's tab bar, where the selected label is heavier than a single shared textStyle can express.

    The per-state style is merged over the base label style, so it overrides only the fields it sets and keeps the resolved per-state label color unless the style provides its own. Both default to null → existing behavior unchanged.

    Also fixes a related precedence bug: an explicit selectedLabelColor / unselectedLabelColor was silently dropped whenever a textStyle was also supplied (the per-state color only fed the fallback style). It now overrides the base color — including a color baked into textStyle — while textStyle-only callers are unaffected.

    innerBlur — Apple-style rest-blur behind the selected tab

    The innerBlur parameter on GlassTabBar.bottom/.searchable (and the deprecated GlassBottomBar/GlassSearchableBottomBar shims) now renders. It was declared and threaded bar→internal, but never forwarded to the indicator, and AnimatedGlassIndicator had no implementation. This wires it through the tab-bar internals and adds the rest-gated BackdropFilter.

    It paints a backdrop blur behind the resting selected pill — the iOS 26 "frost at rest" look — with the sigma scaled by the pill's resting opacity, so the frost is full when settled and fades out as it morphs into the liquid-glass lens during a drag/tap (motion stays crisp).

    • 0.0 (default) disables it — no behavior change for existing callers.
    • Only the background-painting indicator is affected (reads through a translucent indicatorColor).

    platformViewBackdrop on the public glass widgets

    Follows up #94 by exposing the premium-over-PlatformView flag on the remaining public widgets — GlassContainer, GlassButton, GlassIconButton, GlassButtonGroup, GlassMenu, and GlassModalSheet — so apps can render premium glass cleanly over an iOS PlatformView (e.g. a Mapbox MapWidget) for any control, not just the bottom bar.

    Each gets an explicit platformViewBackdrop parameter defaulting to false (zero overhead / no behavior change for callers that don't need it), forwarded to the underlying AdaptiveGlass. For GlassModalSheet the flag threads through GlassModalSheetScaffold and the sheet state down to the _SheetLayout's glass. Adds widget tests covering the simple-widget forwards.

    🧹 Removed — GlassTintBlend (a no-op since 0.17.0)

    GlassTintBlend (added in #107) and the LiquidGlassSettings.tintBlend field have been removed.

    Since the 0.17.0 shader rewrite, tintBlend was never wired into the renderer — it was packed into no uniform, so setting it had no effect: every surface used the automatic chroma-gated blend regardless of the value. We only caught this during real-device tuning, after all the related PRs had already landed.

    The automatic behavior is unchanged. applyGlassColor still picks luminosity-preserving blending for chromatic tints and flat blending for achromatic tints. Recipes that previously passed tintBlend: flat for achromatic (white / grey / near-black) tints render identically, because the chroma gate already resolves those to the flat path.

    Breaking, but inert: code that passed LiquidGlassSettings(tintBlend: …) must drop the argument. No rendered output changes.

    🔧 SDK constraints bump (corrected in 0.18.5)

    Raised minimum Flutter to >=3.24.0 — this was incorrect. The actual minimum is 3.41.0, corrected in 0.18.5.


    Open source →
  49. 0.18.2 23 Jun 2026
    Release notes

    Rendering Quality

    • Fix: Eliminated stair-step aliasing on AnimatedGlassIndicator / GlassEffect pill edges during press animations. Root cause: FragmentShader.setImageSampler() defaults to FilterQuality.none (Nearest-Neighbor). The 4 % press-scale animation was block-replicating geometry texels into 2×2 stair-step patterns visible as jagged fringe on the pill rim. Resolution: Pass filterQuality: FilterQuality.medium to every setImageSampler() call in liquid_glass_render_object.dart, glass_effect.dart, and lightweight_liquid_glass.dart. Zero GPU cost — hardware bilinear filtering happens in a single texel-unit clock cycle.

    • Fix: Eliminated 2×2 blocky normal artifacts on glass pill edges (all platforms, most visible on iOS/macOS Metal). Root cause: Metal's dFdx/dFdy evaluate in 2×2 pixel quads, so all four neighbours share one gradient vector. At the high-contrast white rim of the pill this produces a coarse stair-step normal map that manifests as jaggy rainbow banding regardless of scale. Resolution: Replaced hardware derivatives with per-pixel central finite differences in liquid_glass_geometry_blended.frag (dx = sceneSDF(p + 0.5) − sceneSDF(p − 0.5)). Costs 4 extra SDF evaluations per geometry pixel — negligible on a cached, one-shot geometry pass.

    • Fix: Restored full rim brightness after the anti-aliasing band was widened. Root cause: The previous asymmetric smoothstep(-smoothing, 0.0, sd) placed the mathematical pill boundary (sd = 0) at the dark end of the alpha ramp (alpha = 0). The rim-lighting peak lives exactly at sd = 0, so it was multiplied by zero and rendered invisible. Resolution: Centred the smoothstep around the boundary — smoothstep(smoothing * 0.5, -smoothing * 0.5, sd) — so sd = 0 maps to alpha = 0.5. This is the canonical SDF anti-aliasing formulation and restores maximum rim brightness with no other visual side-effect.

    • Fix: Eliminated backdrop texture wrap-around artifacts during LiquidStretch scaling and jelly overshoot. Root cause: Impeller's default texture sampler wrap mode is Repeat. A fragment slightly outside uGeometrySize (e.g. during a spring overshoot) produced a geometryUV marginally above 1.0; the sampler wrapped it to near-0.0, sampling the opposite edge of the SDF and producing inverted normals and extreme chromatic aliasing. Resolution: Clamp geometryUV to [0, 1] before the texture fetch. Clamped-edge pixels have near-zero SDF alpha and are discarded by the existing geometryData.a < 0.01 early-out — no separate bounds-check branch required.

    • Fix: Eliminated chromatic wrap artifacts during jelly overshoot in interactive_indicator.frag. Root cause: When the indicator pill overshoots its RepaintBoundary bounds, out-of-bounds textureBilinear sample points could trigger the same Repeat-mode wrap in the background texture. Resolution: Explicitly clamp all four bilinear sample points to [0, physSize − 1] before the texture() fetch.

    • Fix: Eliminated jagged/pixelated stair-step artifacts on AnimatedGlassIndicator pill edges when indicatorPinchStrength > 0. Root cause: BackdropFilterLayer implicit samplers are bound to FragmentShader as Nearest-Neighbor with no Dart API to override it (Flutter Issue #139887). Continuous sub-pixel UV shifts from the lens pinch and chromatic aberration were snapping to integer texels, producing blocky rainbow fringes on high-contrast backgrounds. Resolution: Added a textureBilinear helper to liquid_glass_final_render.frag that performs a standard 4-texel bilinear interpolation in GLSL, restoring perfectly smooth sub-pixel background sampling. The geometry texture (uGeometryTexture) is intentionally excluded — its pixel-aligned SDF data must not be softened.

    • Fix: Eliminated pixelation on the interactive indicator pill (GlassSegmentedControl, GlassEffect). Two compounding causes: (1) the background texture was previously captured at pixelRatio: 1.0, so each texel covered a 3×3 block of physical pixels on a 3× Retina display; (2) Impeller's setImageSampler() binding defaults to Nearest-Neighbor, snapping continuous UV offsets from edge refraction to these large texels. Resolution: Background capture now uses the device's full DPR. A textureBilinear GLSL helper replaces all raw texture() calls in interactive_indicator.frag. ~250 KB additional GPU texture memory; sub-0.1 ms additional GPU time per frame — negligible on any modern device.

    • Fix: Resolved intermittent Metal API Validation abort on iOS (GlassQuality.premium) — missing buffer bindings for uWhiten, uWhitenGated, and uPinchStrength (#121). All shader uniforms (slots 0–20) are now written atomically on every paint frame, preventing a stale or zero-initialised FragmentShader snapshot from reaching the Metal draw call. Affected: GlassTabBar.bottom(quality: GlassQuality.premium) with an animating indicator. No API changes.

    Notes

    • Note (Flutter engine limitation): The textureBilinear workaround in liquid_glass_final_render.frag (4-tap bilinear in GLSL) remains necessary for backdrop sampling because Impeller binds the implicit BackdropFilterLayer sampler as Nearest-Neighbor with no Dart API to override FilterQuality. A Flutter engine feature request to expose sampler filter quality for backdrop layers has been filed at Flutter Issue #188365. Once resolved, the GLSL workaround can be replaced with a single texture() call.

    Chore

    • Chore: Removed unreachable early-out branch in liquid_glass_final_render.frag — the if (any(lessThan(geometryUV, ...))) check after clamp(geometryUV, 0.0, 1.0) could never fire. Replaced with a single consolidated comment explaining how the clamp and the downstream alpha check together handle both the Impeller Repeat-mode and clipExpansion cases.
    • Chore: Removed dead code from render.glsl (computeY, getHeight, calculateLighting, calculateRefraction, renderLiquidGlass, debugNormals) — functions superseded by the inline logic in liquid_glass_final_render.frag. Reduces compiled shader binary size.
    Open source →
  50. 0.18.1 22 Jun 2026
    Release notes
    • Hotfix: Resolved missing coverage in layout engines and segmented controls.
    • Hotfix: Fixed package analysis warnings due to unused local variables and unnecessary imports in test files.
    Open source →
  51. 0.18.0 22 Jun 2026
    Release notes

    🏗️ Unified Navigation API — iOS 26 Alignment

    This release consolidates the widget API to map 1:1 with Apple's iOS 26 control vocabulary. Two v1-era widgets are deprecated (see Migration below), and GlassTabBar becomes the single source of truth for all tab-navigation work.


    ⚠️ Breaking Change: Android Bottom Bar Padding

    GlassScaffold now automatically manages the Android system navigation bar padding for bottomBar. If you previously added manual Padding or SafeArea around your bottom bar to prevent it from slipping behind the Android navigation buttons, please remove it to avoid double-padding.


    New: GlassTabBar.bottom() — iOS 26 UITabBar equivalent

    Named constructor for bottom navigation bars. Full liquid glass layer, jelly physics pill indicator, MaskingQuality dual-layer icon rendering, and optional dividerSettings.

    GlassTabBar.bottom(
      tabs: [
        GlassTab(icon: Icon(Icons.home), label: 'Home'),
        GlassTab(icon: Icon(Icons.search), label: 'Search'),
        GlassTab(icon: Icon(Icons.person), label: 'Profile'),
      ],
      selectedIndex: _selectedIndex,
      onTabSelected: (i) => setState(() => _selectedIndex = i),
    )
    

    New: GlassTabBar.searchable() — UITabBar + morphing search

    Named constructor combining bottom navigation with a morphing glass search pill. Identical API to GlassTabBar.bottom() with additional searchBarConfig and controller parameters.

    GlassTabBar.searchable(
      tabs: [...],
      selectedIndex: _selectedIndex,
      onTabSelected: (i) => setState(() => _selectedIndex = i),
      searchBarConfig: GlassSearchBarConfig(hintText: 'Search...'),
      controller: _tabBarController,
    )
    

    New: GlassSegmentedControl — icon support + scrollable mode

    Icon + label support (fixed mode)

    segments now accepts List<GlassTab> instead of List<String>. Each segment can render:

    • Label onlyGlassTab(label: 'Weekly')
    • Icon onlyGlassTab(icon: Icon(Icons.photo))
    • Icon + labelGlassTab(icon: Icon(Icons.photo), label: 'Photos') (icon above label)

    This matches iOS 26 UISegmentedControl which has supported UIImage segments since early iOS.

    Scrollable mode — 100% parity with original GlassTabBar(isScrollable: true)


    🚨 Removed: GlassTabBar() inline constructor

    The default GlassTabBar() constructor has been removed. GlassTabBar is now exclusively used for structural bottom navigation (GlassTabBar.bottom() and GlassTabBar.searchable()).

    Migration: For all inline tab bars, pill menus, or scrollable tag lists, use GlassSegmentedControl() or GlassSegmentedControl.scrollable(). They provide 100% feature parity with the old inline GlassTabBar.

    - GlassTabBar(
    -   tabs: const [
    -     GlassTab(label: 'A'),
    -     GlassTab(label: 'B'),
    -   ],
    -   selectedIndex: _selectedIndex,
    -   onTabSelected: (i) => setState(() => _selectedIndex = i),
    - )
    + GlassSegmentedControl(
    +   segments: const [
    +     GlassSegment(label: 'A'),
    +     GlassSegment(label: 'B'),
    +   ],
    +   selectedIndex: _selectedIndex,
    +   onSegmentSelected: (i) => setState(() => _selectedIndex = i),
    + )
    

    New GlassSegmentedControl.scrollable() named constructor for category filter tabs (6+ items). Internally uses ScrollableSegmentContent — a dedicated widget that owns scrollable pill physics, gesture handling, and 3-layer rendering. Structurally identical to the old inline GlassTabBar(isScrollable: true), now correctly located in the interactive widget family.

    // Fixed (UISegmentedControl — equal width, 2–6 items)
    GlassSegmentedControl(
      segments: const [
        GlassSegment(label: 'All'),
        GlassSegment(icon: Icon(Icons.photo), label: 'Photos'),
        GlassSegment(label: 'Videos'),
      ],
      selectedIndex: _selectedIndex,
      onSegmentSelected: (i) => setState(() => _selectedIndex = i),
    )
    
    // Scrollable (category filter tabs — natural width, 7+ items)
    GlassSegmentedControl.scrollable(
      segments: List.generate(12, (i) => GlassSegment(label: 'Category ${i + 1}')),
      selectedIndex: _selectedIndex,
      onSegmentSelected: (i) => setState(() => _selectedIndex = i),
    )
    

    Architecture: Dependency inversion

    All tab-bar layout logic now lives in dedicated layout files:

    File Owns
    interactive/shared/scrollable_segment_content.dart ScrollableSegmentContent — scrollable pill + gesture engine (used by GlassSegmentedControl.scrollable)
    interactive/shared/segmented_control_internal.dart SegmentedControlContent — fixed-width pill + gesture engine (used by GlassSegmentedControl)
    surfaces/shared/tab_bar_bottom_layout.dart TabBarBottomLayout — full glass bottom shell
    surfaces/shared/tab_bar_searchable_layout.dart TabBarSearchableLayout — search morph shell

    GlassTabBar dispatches to these shells. GlassBottomBar and GlassSearchableBottomBar are now zero-logic shims that delegate to the same shells.


    Deprecated — removal in v1.0

    GlassBottomBarGlassTabBar.bottom()

    // BEFORE
    GlassBottomBar(
      tabs: [GlassBottomBarTab(icon: Icon(Icons.home), label: 'Home')],
      selectedIndex: _selectedIndex,
      onTabSelected: (i) => setState(() => _selectedIndex = i),
    )
    
    // AFTER
    GlassTabBar.bottom(
      tabs: [GlassTab(icon: Icon(Icons.home), label: 'Home')],
      selectedIndex: _selectedIndex,
      onTabSelected: (i) => setState(() => _selectedIndex = i),
    )
    

    GlassSearchableBottomBarGlassTabBar.searchable()

    // BEFORE
    GlassSearchableBottomBar(tabs: [...], ...)
    
    // AFTER
    GlassTabBar.searchable(tabs: [...], ...)
    

    GlassTabBar() default constructor → GlassSegmentedControl

    // BEFORE
    GlassTabBar(
      tabs: [GlassTab(label: 'A'), GlassTab(label: 'B')],
      selectedIndex: _selectedIndex,
      onTabSelected: (i) => setState(() => _selectedIndex = i),
    )
    
    // AFTER
    GlassSegmentedControl(
      segments: [GlassTab(label: 'A'), GlassTab(label: 'B')],
      selectedIndex: _selectedIndex,
      onSegmentSelected: (i) => setState(() => _selectedIndex = i),
    )
    

    GlassSegmentedControl.segments: List<String>List<GlassTab>

    // BEFORE
    GlassSegmentedControl(segments: ['Daily', 'Weekly', 'Monthly'], ...)
    
    // AFTER
    GlassSegmentedControl(
      segments: [
        GlassTab(label: 'Daily'),
        GlassTab(label: 'Weekly'),
        GlassTab(label: 'Monthly'),
      ],
      ...
    )
    

    iOS 26 control vocabulary — full mapping

    Widget iOS 26 equivalent Glass tier
    GlassSegmentedControl(...) UISegmentedControl Light tint + glass pill
    GlassSegmentedControl.scrollable(...) Scrollable filter tabs Light tint + glass pill
    GlassTabBar.bottom(...) UITabBar Full liquid glass
    GlassTabBar.searchable(...) UITabBar + search Full liquid glass

    New: Configurable label colors and indicator border radius for bottom bars

    GlassTabBar.bottom(), GlassTabBar.searchable(), GlassBottomBar, and GlassSearchableBottomBar expose three additional styling parameters:

    • selectedLabelColor — tab label colour when selected, independent of selectedIconColor
    • unselectedLabelColor — tab label colour when unselected, independent of unselectedIconColor
    • indicatorBorderRadius — pill indicator corner radius, independent of barBorderRadius (e.g. 100 for a fully round pill on a subtly curved bar)

    All three are optional; omitting them preserves existing behaviour exactly.

    GlassTabBar.bottom(
      tabs: [...],
      selectedIndex: _selectedIndex,
      onTabSelected: (i) => setState(() => _selectedIndex = i),
      selectedLabelColor: Colors.blue,
      unselectedLabelColor: Colors.grey,
      indicatorBorderRadius: 100,
    )
    

    Open source →
  52. 0.17.1 20 Jun 2026
    Release notes

    🐛 Fix — platformViewBackdrop toggle no longer snaps the selected-tab indicator (#112 by @jfhair)

    Toggling platformViewBackdrop at runtime (e.g. switching between a map tab and a Flutter-content tab) caused the selected-indicator pill to snap to the new tab instead of sliding. The spring animation controllers inside the indicator subtree were being re-seeded at their already-settled value because the toggle added or removed the LiquidGlassBlendGroup wrapper in AdaptiveLiquidGlassLayer, changing the child's depth in the element tree and forcing Flutter to discard and re-inflate the whole subtree via initState.

    Fix: AdaptiveLiquidGlassLayer is now a StatefulWidget that holds a stable GlobalKey. The child is always wrapped in a KeyedSubtree with that key, so the element identity is preserved across the wrapper toggle — the indicator's AnimationControllers survive and the morph continues correctly.

    No API changes. No breaking changes.


    Open source →
  53. 0.17.0 19 Jun 2026
    Release notes

    🔬 iOS 26 Concave Lens Pinch — All Four Pill Widgets

    The indicatorPinchStrength concave lens warp is now unified across all four interactive pill widgets. During a drag the pill edges curve inward (iOS 26 "through a lens" effect). Fully tunable — 0.0 disables it, 1.0 is maximum distortion.

    New parameters

    • GlassTabBar.indicatorPinchStrength (default 0.4)
    • GlassTabBar.indicatorExpansion (default EdgeInsets.symmetric(horizontal: 12, vertical: 8))
    • GlassSegmentedControl.indicatorPinchStrength (default 0.4)
    • GlassSegmentedControl.indicatorExpansion (default EdgeInsets.symmetric(horizontal: 12, vertical: 8))
    • AnimatedGlassIndicator exported from the public API — enables baseIndicatorSettings.copyWith(...) from app code.

    Changed defaults (AnimatedGlassIndicator.baseIndicatorSettings)

    • glassColor: alpha: 0.15alpha: 0.0 — glass pill no longer applies a white tint overlay by default.
    • chromaticAberration: GlassDefaults.chromaticAberration0.15 — the iridescent rim fringe is now explicitly set for iOS 26 parity.

    Bug fixes

    • GlassSegmentedControl refraction — labels are now refracted through the glass pill at GlassQuality.premium (was rendered in wrong z-order).
    • GlassTabBar indicator radius — resting pill now inherits the tab bar's borderRadius (was hardcoded 16 px).
    • AnimatedGlassIndicator settings merge — partial indicatorSettings overrides no longer silently reset chromaticAberration.
    • Pinch lens jitter at rest — icon and label content no longer shimmers through the lens when the pill settles. Root cause: the jelly spring's micro-oscillations (±10 % of thickness) were directly amplified into the UV warp. Fixed by applying a quadratic ease-out to the pinch multiplier (1 − (1 − fade)²), compressing the near-settled oscillation range ≈10×.

    Try it — Indicator Parity demo

    The example app includes a live Indicator Parity demo (Demos → Indicator Parity) with all four pill widgets side-by-side and real-time sliders for pinchStrength, indicatorExpansion, and chromaticAberration. Use it to tune parameters before writing any code.

    🌑 Apple Dimming Layer — LiquidGlassSettings.backerColor (#111 by @jfhair)

    New optional backerColor on LiquidGlassSettings — a shape-matched color pad composited behind the glass, giving a control's content contrast over rich or colorful backdrops (video, maps, photography) where the glass tint alone can't. This is Apple's "dimming layer" guidance from the Human Interface Guidelines (Materials section) and the pattern behind SwiftUI's clear Glass variant.

    LiquidGlassSettings(
      glassColor: Color(0x20FFFFFF),
      backerColor: Color(0x59000000), // ~35% black — Apple's starting point
    )
    
    • backerColor (Color?, default null) — the color's alpha is the dimming opacity. null means no backer, so all existing recipes are untouched.
    • Rendered at the widget level (like shadow) and clipped to the glass shape via ClipRRect, so it composites correctly even over a PlatformView — maps, video — where a shader-side tint cannot reach.
    • Applies in both light and dark mode, and for flat-edge shapes (a bar over a map is a primary use case).
    • Skipped on the grouped path (like shadow) — inserting a Stack between grouped glass and its shared layer would break metaball morphing.
    • lerp fades backerColor smoothly from transparent when one side is null, rather than snapping at the midpoint.

    Migration

    All four widgets share the same tuning API:

    indicatorPinchStrength: 0.4,
    indicatorExpansion: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
    indicatorSettings: AnimatedGlassIndicator.baseIndicatorSettings
        .copyWith(chromaticAberration: 0.15),
    

    Open source →
  54. 0.16.3 18 Jun 2026
    Release notes

    GlassTintBlend — selectable tint blending path (#107 by @jfhair)

    New GlassTintBlend enum on LiquidGlassSettings to explicitly control how glassColor blends with the refracted backdrop, instead of relying entirely on the chroma heuristic.

    • GlassTintBlend.auto — the default. Existing chroma gate, byte-for-byte unchanged behavior.
    • GlassTintBlend.luminosity — always preserve backdrop luminosity. For near-neutral tints that need to keep the glassy look rather than flattening to a film.
    • GlassTintBlend.flat — always impose the tint's brightness. For dimming layers, backing scrims, or deliberate frost-film surfaces.

    Fully threaded through LiquidGlassSettings (copyWith, lerp, props), both the Premium and Standard shader paths, and preserved through AdaptiveGlass elevation rebuilds. Frosted fallback renders flat by construction and ignores the setting.

    GlassScrollEdgeEffect.bottomFadeInset (#109 by @jfhair)

    New optional bottomFadeInset parameter (default 0.0) that lifts the bottom fade off the widget's true bottom edge by the specified logical pixels. Fixes cases where the scroll viewport extends below the visible area — such as a bottom sheet whose content box overflows past the screen bottom — causing the bottom fade to anchor off-screen and never appear.

    No breaking changes. All new parameters are optional with safe defaults.


    Open source →
  55. 0.16.2 17 Jun 2026
    Release notes

    🐛 Bug Fix — GlassMenu / GlassPopover rebuild on keyboard open/close

    GlassMenu and GlassPopover were rebuilding on every keyboard open/close event, even when closed. Caused by MediaQuery.of(context) in didChangeDependencies subscribing to viewInsets. Fixed by switching to scoped accessors (disableAnimationsOf, maybeSizeOf, textScalerOf). Regression tests added.

    ✨ Content-luminance scroll-edge scrim (#106 by @jfhair)

    The continuous companion to the contentAwareBrightness discrete lever. Scroll-edge fades now track content luminance and dissolve toward a dark color as dark content scrolls under the bars — matching the native App Store early-darkening behaviour.

    • GlassContentAwareScope.register() gains onLuminanceChanged (brightness callback is now optional). Per-rect mean luminance is delivered from the existing single capture; deliveries are gated on >0.005 movement.
    • GlassScrollEdgeEffect.contentAwareFade — each edge band registers with the scope and lerps toward darkFadeColor as content darkens (luminanceDarkBelow / luminanceLightAbove thresholds, 280 ms ease-out). Inert without a scope.
    • GlassScaffold.contentAwareEdgeFade — one flag to enable both bars, composing with contentAwareBrightness.
    • Latent wrap-order fix (0.16.0): GlassScaffold was wrapping the body in GlassContentAwareContent after the edge fade, so the fade overlays were inside the sampled region. With the adaptive scrim this is a feedback loop. Wrap order corrected + regression test added.

    🐛 GlassModalSheet handle-drag fixes (#106)

    • Handle drag no longer fights the inner scroll. _handleDragActive notifier is set on pointer-down (before the inner Scrollable can claim slop), disabling inner scroll for the gesture lifetime. Fixes a freeze when dragging the handle over a PlatformView.
    • dragIndicatorColor now actually reaches the drag indicator — it was silently wired into _SheetLayout but never forwarded to _GlassDragIndicator.

    🐛 GlassEffect — defer capture when boundary is mid-paint (#106)

    toImageSync called during a dirty repaint boundary spammed [GlassEffect] toImageSync failed in debug and dropped the frame's capture. Guarded with debugNeedsPaint check (release-safe, same pattern as GlassScrollEdgeEffect).

    No breaking changes. New parameters are all optional with safe defaults — existing code compiles and behaves identically without changes.


    Open source →
  56. 0.16.1 15 Jun 2026
    Release notes

    🍎 iOS 26 Indicator Defaults — Parity Calibration

    Three indicator defaults have been updated across GlassBottomBar and GlassSearchableBottomBar to better match the iOS 26 bottom-bar pill out of the box. No API changes — all parameters remain fully configurable.

    Changed defaults

    indicatorPinchStrength1.00.4

    The previous default of 1.0 applied the maximum concave lens / pinch effect during drag. iOS 26's actual pinch is more restrained — 0.4 produces the characteristic "through a lens" look without over-distorting the edges.

    To restore the previous behaviour:

    GlassBottomBar(
      indicatorPinchStrength: 1.0,
      ...
    )
    

    indicatorExpansionEdgeInsets.all(8)EdgeInsets.symmetric(horizontal: 12, vertical: 8)

    The indicator pill in iOS 26 bottom bars is slightly wider than it is tall — a subtle "landing pad" shape that reads as a rounded rectangle rather than a near-circle. The new default matches this proportion.

    To restore the previous behaviour:

    GlassBottomBar(
      indicatorExpansion: const EdgeInsets.all(8.0),
      ...
    )
    

    AnimatedGlassIndicator chromatic aberration — 0.00.15

    The indicator's internal _baseGlassSettings now sets chromaticAberration: 0.15. Real iOS 26 glass has a faint iridescent rainbow fringe at the rim. At 0.15 the effect is a whisper — visible up close, subliminal during normal use.

    To disable the aberration pass a full indicatorSettings override:

    GlassBottomBar(
      indicatorSettings: LiquidGlassSettings(
        chromaticAberration: 0.0,
        // include other fields you need
      ),
      ...
    )
    

    Affected widgets

    • GlassBottomBarindicatorPinchStrength and indicatorExpansion
    • GlassSearchableBottomBarindicatorPinchStrength and indicatorExpansion
    • All widgets using AnimatedGlassIndicatorchromaticAberration baseline

    GlassTabBar and GlassSegmentedControl retain their existing expansion defaults (EdgeInsets.all(8.0)) as their geometry is different from a bottom navigation bar.


    Open source →
  57. 0.16.0 12 Jun 2026
    Release notes

    🎨 Content-Aware Light/Dark Adaptation

    Glass bars now automatically adapt their icon and label colors to match the content scrolling behind them — light glyphs over dark content, dark glyphs over light content — with a smooth cross-fade transition. This matches the iOS 26 behaviour where navigation chrome remains legible regardless of what is visible underneath.

    Core engine contributed by @jfhair in PR #103.

    New widgets

    • GlassContentAwareScope — wraps a screen and owns the sampling engine. Captures the content boundary at scroll rate (~5 fps), divides each registered control's rectangle into voting cells, and delivers per-control brightness verdicts via WCAG contrast ratios and dual-threshold hysteresis.
    • GlassContentAwareContent — marks the sampled content region. Installs a RepaintBoundary that the scope captures. Controls must be outside this region (e.g. in Scaffold.bottomNavigationBar with extendBody: true).
    • GlassContentAwareBrightness — per-control consumer that cross-fades between the light and dark GlassThemeVariant via GlassThemeVariant.lerp. Supports an external brightnessOverride (for PlatformView escape hatches), configurable grid dimensions, and per-control flip duration/curve overrides.

    New parameters on existing widgets

    • GlassBottomBaradaptiveBrightness, brightnessOverride, onBrightnessChanged. Set adaptiveBrightness: true to opt in.
    • GlassSearchableBottomBar — same three parameters. Both bars automatically wrap in GlassContentAwareBrightness when enabled.
    • GlassScaffoldcontentAwareBrightness. When true, the scaffold automatically wraps the body in GlassContentAwareContent and the entire layout in GlassContentAwareScope. One flag, no manual widget wiring.

    New API surface

    • GlassThemeVariant.lerp(a, b, t) — interpolates settings, glow colors, quality, and border radius between two theme variants. Used internally by the cross-fade but available to consumers building custom transitions.
    • GlassThemeSettings.lerp(a, b, t) — interpolates all 9 glass setting fields (thickness, blur, glassColor, lightAngle, lightIntensity, etc.).
    • resolveBarLabelColor(context, brightness) — shared utility for bars to resolve label color from CupertinoTheme given an overridden brightness.

    Usage

    The recommended path — one flag on GlassScaffold, one on the bar:

    GlassScaffold(
      contentAwareBrightness: true,
      bottomBar: GlassBottomBar(
        adaptiveBrightness: true,
        onBrightnessChanged: (b) => /* flip your own icon colors */,
        tabs: [...],
        selectedIndex: _index,
        onTabSelected: (i) => setState(() => _index = i),
      ),
      body: CustomScrollView(...),
    )
    

    For custom layouts without GlassScaffold, use the standalone widgets directly:

    GlassContentAwareScope(
      child: Scaffold(
        extendBody: true,
        body: GlassContentAwareContent(
          child: ListView(...),
        ),
        bottomNavigationBar: GlassBottomBar(
          adaptiveBrightness: true,
          ...
        ),
      ),
    )
    

    Bug fix

    • GlassThemeVariant.== / hashCode missing borderRadius — fixed a pre-existing bug where two variants differing only in borderRadius compared equal. This caused stale radius during content-aware cross-fades where intermediate lerped variants would not trigger rebuilds.

    Polish

    • _sample() error reporting — the bare catch (_) in the sampling pipeline now reports to FlutterError inside an assert closure. Errors are still suppressed in release builds but surface in debug mode so programming mistakes are visible.
    • Removed redundant setState_GlassContentAwareBrightnessState._setBrightness no longer calls setState since AnimatedBuilder already listens to the animation controller and rebuilds on every tick.

    Example app

    • Content-Aware Brightness demo (new) — dedicated showcase with alternating light and dark content bands that force visible bar flips during scrolling. Available in the Examples tab.

    Open source →
  58. 0.15.7 12 Jun 2026
    Release notes

    🌙 Adaptive Brightness Fix

    Fixed a bug in LightweightLiquidGlass where the shader's internal brightness estimation (backdropLuma) was incorrectly reading from the OS-level MediaQuery.platformBrightnessOf(context) rather than the inherited Flutter Theme.of(context).brightness.

    This ensures that glass surfaces now correctly switch to Light Mode parameters (such as the legibility veil) when the app itself overrides the theme to Light Mode, even if the user's physical device remains in Dark Mode.


    Open source →
  59. 0.15.6 11 Jun 2026
    Release notes

    🌫️ Scroll Edge Fade — Perceptual Gradient Curve

    Replaced the 2-stop linear alpha gradient in GlassScrollEdgeEffect with a multi-stop eased curve that matches the perceptual dissolve of iOS 26.

    • 5-stop gradient profiles for both soft and hard styles — eliminates the "denser in the centre" banding and the visible seam at the fade boundary.
    • hard style reworked: steeper hold → sharper drop curve instead of just compressing the soft profile. Height multiplier relaxed from 0.33× to 0.5×.
    • Example app: Nav Patterns demo now fully brightness-aware (adaptive text colours, GlassStatusBarStyle.auto, adaptive solid-bar colour).

    No API changes. No breaking changes.


    Open source →
  60. 0.15.5 11 Jun 2026
    Release notes

    ✨ Whiten Strength — Light-Mode Legibility Veil

    Opt-in whitening ("legibility veil") lifts glass toward white for legibility over busy light backgrounds — modelling iOS 26's light-mode glass.

    • LiquidGlassSettings.whitenStrength (0.0–1.0, default 0.0): lifts the finished glass toward white as the last step of the render. A single control-wide value with no spatial seams or halo artifacts.

    • LiquidGlassSettings.whitenGated (default true): when gated, the lift scales by per-pixel luminance so bright content lifts to white while dark content (text, icons) stays crisp. Ungated applies the lift uniformly — useful for dark-mode frost effects.

    • Consistent across all three quality tiers from one knob: Premium (fragment shader), Standard (tint lerp), and Minimal (frosted fallback) all render the same whitenStrength value consistently.

    • GlassSearchableBottomBar whiten-at-bottom: when a scrollController is provided, the bar animates its whitening toward full white as the page nears the scroll bottom — the iOS light-mode behaviour where content crowding under a bar gets the strongest legibility lift.

    • Example app: Buttons & Shadows demo now includes a real-time whiten slider with side-by-side comparison cards and scroll-to-bottom boost preview.

    Contributed by @jfhair in PR #100.

    🎬 Scale-with-Morph — Cohesive Overlay Content Reveal

    Menu items and popover content now scale in alongside the liquid morph animation instead of popping in at the tail. The glass container and its content feel like a single continuous motion.

    • Items enter the tree at 30% morph progress (down from 94%) and scale from 0.5× to 1.0× via an easeOut curve alongside opacity. Text and icons visually grow with the expanding glass container.
    • Applied to both GlassMenu and GlassPopover for consistent overlay behaviour across the widget family. Content scales in on open and scales back out on close — the morph animation is symmetrical in both directions.
    • No new API surface. No breaking changes. Purely visual polish.

    GlassMenu scale-with-morph contributed by @F1orian in PR #97.


    Open source →

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive