---
name: liquid-glass-widgets
description: "Mastery guide and architectural rules for liquid_glass_widgets. Trigger whenever generating, refactoring, or reviewing Flutter UI code using liquid glass, iOS 26/27 aesthetics, GlassScaffold, GlassTabBar, GlassModalSheet, or any Glass* components."
---

# Liquid Glass Widgets — AI Agent Guide

This skill defines the architecture, design principles, API dictionary, and strict implementation rules for building Flutter applications with `liquid_glass_widgets`.

Follow this guide strictly when writing, refactoring, or reviewing UI code to ensure high visual fidelity, 60/120 fps GPU performance, and zero hallucinations.

---

## 1. Golden Architectural Rules (Mandatory)

### Rule 1: Glass is a Platter, Not a Wrapper
Glass in the iOS 26 design system is reserved for the **navigation and control layer** — floating chrome that sits above content.
- **DO use glass for:** Navigation bars (`GlassAppBar`), tab bars (`GlassTabBar`), floating buttons (`GlassButton`, `GlassIconButton`), toolbars, modal sheets (`GlassModalSheet`), dialogs (`GlassDialog`), and standalone floating cards (`GlassCard`).
- **DO NOT use glass for:** Full-screen backgrounds, dense list view items, video players, image galleries, or text article bodies. Backgrounds should be rich wallpapers or gradients; content cards should be clean and readable.

### Rule 2: NEVER Nest Refractive Glass inside Refractive Glass
Placing refractive glass widgets inside another refractive glass container is an optical and performance anti-pattern.
- **CRITICAL ANTI-PATTERN:** Placing `GlassButton`, `GlassIconButton`, `GlassSegmentedControl`, `GlassSlider`, or `GlassSwitch` inside a `GlassCard`, `GlassGroupedSection`, or `GlassContainer`.
- **Why?** Interactive glass controls provide their own refractive surface. Nesting creates severe double-refraction distortion, clips spring jelly animations, and wastes GPU fill-rate.
- **Correct Pattern:**
  - In a `GlassCard` or `GlassGroupedSection`: Use standard text, icons, and non-refractive controls (or `GlassListTile` which is specifically designed without an internal glass layer).
  - Outside the card / on the page platter: Use `GlassSegmentedControl`, `GlassButton`, `GlassSlider`, or standalone `GlassSwitch(useOwnLayer: true)`.

### Rule 3: Single Public Import
- **ALWAYS**: `import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';`
- **NEVER** import `package:liquid_glass_widgets/src/...`.
- **NEVER** instantiate `LiquidGlass(...)` directly — it is an internal Impeller-only renderer. Always use `AdaptiveGlass` or the high-level `Glass*` widgets.

### Rule 4: Ban Obsolete Pre-1.0 APIs
- `GlassBottomBar` and `GlassSearchableBottomBar` were **deleted** in v1.0.0.
- **ALWAYS USE**: `GlassTabBar.bottom(...)` or `GlassTabBar.searchable(...)`.

### Rule 5: Honor Quality Tiers
- **`GlassQuality.standard`**: Default for 95% of controls, cards, and input fields. Uses a highly optimized single-pass fragment shader.
- **`GlassQuality.premium`**: Multi-pass Impeller shader with chromatic dispersion, realistic refraction, and dynamic specular highlights. Reserved for persistent navigation bars (`GlassAppBar`, `GlassTabBar`) and hero surfaces. `GlassScaffold` automatically promotes its bars to premium.
- **`GlassQuality.minimal`**: Lightweight shader-free fallback (`BackdropFilter` only). Use for ultra-dense scrolling lists or low-power modes.

---

## 2. App Lifecycle & Initialization

In `main.dart`, always initialize the shader pipeline before `runApp()`, and wrap the application with `LiquidGlassWidgets.wrap()`.

```dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Pre-warms fragment shaders in parallel to prevent first-frame white flashes or shader jank
  await LiquidGlassWidgets.initialize();

  runApp(
    LiquidGlassWidgets.wrap(
      adaptiveQuality: true, // Dynamically benchmarks device raster budget and scales quality
      respectSystemAccessibility: true, // Automatically degrades on Reduce Motion / Reduce Transparency

      // CRITICAL FOR MATERIAL APPS: Bridges Material ThemeMode without importing flutter/material in the engine
      brightnessResolver: Theme.maybeBrightnessOf,

      // GlassThemeData.simple is the recommended constructor — applies the same settings to
      // both light and dark, overlaid on the library's built-in per-mode defaults.
      // Use GlassThemeData(light: ..., dark: ...) only for fine-grained per-mode control.
      theme: GlassThemeData.simple(
        blur: 12,
        thickness: 25,
        quality: GlassQuality.standard,
      ),
      child: const MyApp(),
    ),
  );
}
```

---

## 3. Screen Architecture: `GlassScaffold`

For any screen featuring liquid glass navigation bars or floating surfaces, **always use `GlassScaffold` instead of Flutter's built-in `Scaffold`**.

`GlassScaffold` solves complex compositing challenges automatically:
1. **Guaranteed Z-Ordering**: App bars and bottom bars paint above scrolling body content, preventing body cards from overlapping navigation buttons.
2. **Edge Fading**: Content fades smoothly as it scrolls under bars (`.scrollEdgeEffectStyle(.soft)` matching iOS 26).
3. **Content-Aware Brightness**: Dynamically flips app bar icons and typography between light and dark depending on the luminosity of the content scrolling underneath.
4. **Auto-Padding**: Automatically accounts for safe areas and bar heights.

```dart
class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  int _selectedTab = 0;

  @override
  Widget build(BuildContext context) {
    return GlassScaffold(
      // 1. Wallpaper background (image, gradient, or solid)
      background: Image.asset('assets/wallpaper.jpg', fit: BoxFit.cover),
      contentAwareBrightness: true,

      // 2. Navigation Bar
      // GlassAppBar uses `actions` (List<Widget>), not `trailing`.
      appBar: GlassAppBar(
        title: const Text('Dashboard'),
        actions: [
          GlassIconButton(
            icon: const Icon(CupertinoIcons.bell_fill),
            onPressed: () => _openNotifications(),
          ),
        ],
      ),

      // 3. Unified Bottom Tab Bar
      bottomBar: GlassTabBar.bottom(
        selectedIndex: _selectedTab,
        onTabSelected: (index) => setState(() => _selectedTab = index),
        tabs: const [
          GlassTab(icon: Icon(CupertinoIcons.house_fill), label: 'Home'),
          GlassTab(icon: Icon(CupertinoIcons.chart_bar_fill), label: 'Stats'),
          GlassTab(icon: Icon(CupertinoIcons.gear_alt_fill), label: 'Settings'),
        ],
      ),

      // 4. Scrollable Body Content
      body: ListView(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
        children: [
          // Content cards stay opaque or use GlassCard for grouping
          GlassGroupedSection(
            header: const Text('ACCOUNT'),
            children: [
              GlassListTile(
                leading: const Icon(CupertinoIcons.person_fill),
                title: const Text('Profile'),
                trailing: GlassListTile.chevron,
                onTap: () {},
              ),
              GlassListTile(
                leading: const Icon(CupertinoIcons.lock_shield_fill),
                title: const Text('Privacy & Security'),
                trailing: GlassListTile.chevron,
                onTap: () {},
              ),
            ],
          ),
        ],
      ),
    );
  }
}
```

---

## 4. Component Dictionary & Substitution Table

When generating Flutter UI, replace standard Flutter widgets with their native liquid glass counterparts:

| Flutter Standard Widget | Liquid Glass Replacement | Key Usage Notes |
| :--- | :--- | :--- |
| `Scaffold` | `GlassScaffold` | Handles z-order, edge fading, content-aware brightness. |
| `AppBar` / `CupertinoNavigationBar` | `GlassAppBar` | Transparent iOS 26 style by default. Supports `.pinned` for gel morph. |
| `BottomNavigationBar` / `CupertinoTabBar` | `GlassTabBar.bottom` | Unified glass navigation pill. `GlassBottomBar` is deleted. |
| Bottom nav that collapses to selected tab on scroll | `GlassTabBar.minimizable` | Minimizes to a single pill on scroll; supports an optional trailing action button. |
| `ElevatedButton` / `CupertinoButton` | `GlassButton` | Refractive button with squeeze & stretch physics and touch glow. |
| `IconButton` | `GlassIconButton` | Refractive circular/squircle button with `onPressed`. |
| `PopupMenuButton` / Context Menu | `GlassPullDownButton` | Combined trigger button and `GlassMenu`. |
| `CupertinoSegmentedControl` | `GlassSegmentedControl<T>` | Fluid animated glass indicator with jelly physics. Do NOT wrap in `GlassCard`. |
| `Switch` / `CupertinoSwitch` | `GlassSwitch` | Fluid spring jump animation. Use `useOwnLayer: true` when standalone. |
| `Slider` / `CupertinoSlider` | `GlassSlider` | Glass track with draggable jelly thumb and haptic snaps. |
| `Card` | `GlassCard` | Glass container for grouping content. Content inside stays opaque. |
| Grouped `ListView` | `GlassGroupedSection` | Inset grouped list container with automatic dividers between `GlassListTile`s. |
| `ListTile` | `GlassListTile` | Grouped row item. Shares parent glass layer inside `GlassGroupedSection`. |
| `Divider` | `GlassDivider` | Refractive subtle separator line. |
| `TextField` / `CupertinoTextField` | `GlassTextField` | Input field with glowing refractive focus border. |
| `showModalBottomSheet` | `GlassModalSheet.show` | Multi-detent fluid sheet (peek, half, full) with spring physics. |
| `showDialog` / `CupertinoAlertDialog` | `GlassDialog.show` | Liquid glass modal alert with `GlassDialogAction` buttons. |
| `SnackBar` / Banner | `GlassToast` | Floating glass HUD banner. |

---

## 5. Overlays: Modal Sheets, Dialogs & Transitions

### GlassModalSheet
Presents an iOS 26 fluid modal sheet with detents:

```dart
GlassModalSheet.show(
  context: context,
  initialState: GlassSheetState.half,
  halfSize: 0.5,
  peekSize: 90.0,
  builder: (sheetContext) {
    return ListView(
      padding: const EdgeInsets.all(20),
      children: const [
        Text(
          'Modal Sheet Content',
          style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        ),
      ],
    );
  },
);
```

### GlassDialog
Presents a native alert dialog:

```dart
GlassDialog.show(
  context: context,
  title: 'Discard Draft?',
  message: 'This action cannot be reversed.',
  actions: [
    GlassDialogAction(
      label: 'Cancel',
      onPressed: () => Navigator.of(context).pop(),
    ),
    GlassDialogAction(
      label: 'Discard',
      isDestructive: true,
      onPressed: () {
        Navigator.of(context).pop();
        _discardDraft();
      },
    ),
  ],
);
```

### GlassMenu Submenus
Give a `GlassMenuItem` a `submenu` list to open a native iOS-style card over the parent (the parent recedes and dims; tapping the card's header or the exposed parent collapses one level). Submenus nest. Works in `GlassMenu` and `GlassPullDownButton`:

```dart
GlassPullDownButton(
  icon: const Icon(CupertinoIcons.ellipsis_circle),
  items: [
    GlassMenuItem(
      title: 'Share…',
      icon: const Icon(CupertinoIcons.share),
      // onTap is required but never called on a submenu row:
      // activating it opens the card instead.
      onTap: () {},
      submenu: [
        GlassMenuItem(title: 'Messages', icon: const Icon(CupertinoIcons.chat_bubble_fill), onTap: _sendMessage),
        GlassMenuItem(title: 'Mail', icon: const Icon(CupertinoIcons.mail_solid), onTap: _sendMail),
      ],
    ),
    const GlassMenuDivider(),
    GlassMenuItem(title: 'Delete', icon: const Icon(CupertinoIcons.trash), isDestructive: true, onTap: _delete),
  ],
)
```

- A submenu row shows a chevron automatically unless you pass `trailing`.
- Do **not** build nested menus by opening a second `GlassMenu` from an item's `onTap`; use `submenu`.

### GlassMaterialize
For widgets appearing or disappearing dynamically, use `GlassMaterialize` to match iOS 26's progressive defogging transition:

```dart
GlassMaterialize(
  visible: _showFilterPill,
  // GlassChip.label is a String, not a Widget
  child: GlassChip(
    label: 'Active Filters',
    onDeleted: () => setState(() => _showFilterPill = false),
  ),
)
```

---

## 6. Advanced Navigation: Gel Morph with `GlassNavigationShell`

To achieve the signature iOS 26 navigation bar transition — where the capsule swells, bounces, and cross-fades icons between routes:

1. **Wrap the Navigator** in `GlassNavigationShell` (typically in `CupertinoApp.builder`):

```dart
CupertinoApp(
  builder: (context, child) => GlassNavigationShell(
    swipeCommitTransition: GlassSwipeCommitTransition.crossFade, // optional: plain cross-fade on back-swipe
    verticalBarBehavior: GlassVerticalBarBehavior.automatic,     // optional: iPhone Duo vertical strip
    child: child!,
  ),
  home: const HomeScreen(),
)
```

2. Use `GlassAppBar.pinned` on destination screens. Items are declared as `GlassBarItem` data (not arbitrary widgets), which allows the shell to hoist them above the `Navigator` and morph them across routes:

```dart
GlassAppBar.pinned(
  title: const Text('Detail'),
  actions: [
    // GlassBarItem.icon uses `onTap` (not `onPressed`)
    GlassBarItem.icon(
      icon: const Icon(CupertinoIcons.square_and_arrow_up),
      onTap: () => _share(),
    ),
    // Tinted capsule (iOS 26 prominent action): set tintColor + separate background.
    // The capsule fills with the colour; foreground icon auto-flips to white/black.
    GlassBarItem.icon(
      icon: const Icon(CupertinoIcons.checkmark),
      onTap: _save,
      background: GlassBarItemBackground.separate,
      tintColor: CupertinoColors.activeBlue,
    ),
  ],
)
```

> **Note:** Without `GlassNavigationShell`, `GlassAppBar.pinned` falls back gracefully — items render inside the bar in-route, so all screens work either way.

> **iPhone Duo:** Under the shell, pinned bars, `GlassTabBar.bottom` / `.searchable`, `GlassToolbar` and `GlassLargeTitle` move into the vertical bar strip on their own; pass a large title's controller to its `GlassAppBar.pinned`, which draws the title there. A `GlassAppBar.pinned` inside a `GlassModalSheet` follows the sheet, whose `placement` mirrors `presentationPlacement(_:)`. Use `GlassBarItem.custom(axisBehavior: GlassBarItemAxisBehavior.verticalPreferred)` for custom content that should go with them, and read `GlassVerticalBar.maybeOf(context)` to fit a bar the package does not draw.

---

## 7. Common Agent Pitfalls (Checklist before outputting code)

- [ ] **Did you import the public API only?** (`import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';`). Never import `src/`.
- [ ] **Did you call `await LiquidGlassWidgets.initialize()` in `main()`?** Shaders must be pre-warmed.
- [ ] **Did you wrap your app in `LiquidGlassWidgets.wrap()`?** Required for theme and accessibility scaling.
- [ ] **Are you using `GlassScaffold` instead of `Scaffold`?** Prevents z-index glitches with glass nav bars.
- [ ] **Did you avoid nesting glass in glass?** Never put `GlassButton`, `GlassSlider`, or `GlassSwitch` directly inside `GlassCard` or `GlassGroupedSection`.
- [ ] **Did you use `GlassTabBar.bottom` instead of `GlassBottomBar`?** `GlassBottomBar` is deleted.
- [ ] **`GlassButton` uses `onTap`, not `onPressed`.** (`GlassButton(onTap: () {})`) — the opposite of `ElevatedButton`.
- [ ] **`GlassIconButton` uses `onPressed`, not `onTap`.** (`GlassIconButton(onPressed: () {})`).
- [ ] **`GlassAppBar` uses `actions: [...]` (a List), not `trailing:`.** There is no `trailing` parameter.
- [ ] **`GlassChip.label` is a `String`, not a `Widget`.** Pass `label: 'text'`, not `label: Text('text')`.
- [ ] **`GlassBarItem.icon` uses `onTap` (required), not `onPressed`.**
- [ ] **Nested menus use `GlassMenuItem(submenu: [...])`.** The parent row still needs `onTap: () {}` (required, never called). Don't open a second `GlassMenu` from `onTap`.
- [ ] **`tintColor` on `GlassBarItem` requires `background: GlassBarItemBackground.separate`.** A shared-background item cannot be tinted (asserts in debug mode). The foreground icon colour is flipped automatically — do not also set a manual `Icon(color:)` on the child.
