g1455 0.4.0
g1455: ^0.4.0 copied to clipboard
Liquid Glass for Flutter: refraction, blur and finishes; bars, tabs, switches, sliders, menus, sheets, dialogs and fusing groups, all sampling one shared capture.
0.4.0 - 2026-10-24 #
Breaking changes #
Constructor calls build unchanged; code that reads these fields back needs a change.
- Colour parameters are nullable, and null means iOS's colour for the
appearance of the glass:
GlassSwitch.activeColorandtrackColor,GlassSlider.activeColorandtrackColor,GlassSegmentedControl.trackColorandthumbColor,GlassTabBar.activeColor,GlassTextField.cursorColor(andGlassTextField.search),GlassSearchBar.cancelColorandGlassBadge.color. A colour you pass is drawn as before; reading one back needs a fallback (??). GlassBar.padding,GlassCard.padding,GlassButton.paddingandGlassScaffold.barMarginareEdgeInsetsGeometry, resolved with the ambientDirectionality, soEdgeInsetsDirectionalmirrors under right to left. Code that reads them asEdgeInsetscallsresolvefirst.kGlassFieldHeightis the field's minimum height, not its fixed height: see the text size changes below.
Added #
GlassHost.appearance: an app whose theme does not follow the phone's declares the appearance it is in. Before, a dark-themed app on a phone in the light appearance got light.regularglass over its dark content. Unlike naming a finish, it keeps adaptive glass and the declared backdrop in play. AGlassScaffoldthat mounts its own host takes the defaults, so declare it on a host of your own.GlassScaffold.resizeToAvoidBottomInset, true by default, asScaffold's: the body ends at the keyboard's top and is told no bottom inset, so a focused field in a scroll view is scrolled into sight, and the floating action stands on the keyboard. The bottom bar stays under it. Before, the body ran under the keyboard;falsekeeps that.ShadowFilteris exported frompackage:g1455/g1455.dart, soGlassHost.shadowFiltercan be given one without asrc/import. Its counters (dropped,picturesForwarded,paragraphsForwarded) say what it left out of the capture and what it could not look into.WalkLogis exported frompackage:g1455/glass_diagnostics.dart: what the capture walk observed on a frame, read asGlassProxyHandle.frame?.log,fellBackincluded (see Fixed).debugGlassWalkFallbackinpackage:g1455/glass_diagnostics.dart, on by default: a benchmark turns the capture's fallback off to price it.
Changed #
- Colours on dark glass are the dark appearance's, as on iOS:
- the default colours of the switch, slider, segmented control, a selected tab, a field's caret and selection, and Cancel;
- the tab bar's resting capsule and an alert's action capsules
(
systemFill); - the destructive red in alerts and menus, and a badge's red
(
systemRed); - a sheet's grabber (
tertiaryLabelof the sheet's appearance; it was 1.18 : 1 against a dark sheet). The slider's default blue in the light appearance is the lightsystemBlue(0xFF007AFF), not the dark one.
- On Impeller the glass blurs as it was calibrated to. Impeller's
ImageFilter.blurdelivers less than the sigma it is asked (2.13 texels for 2.6 on an M2 iPad Pro, nothing under 0.8) and cuts its kernel short, so there the package blurs with a Gaussian of its own,shaders/glass_blur.frag, which delivers the sigma asked to 1-2% on Metal, Vulkan and GLES. The soft scroll edge, which on Impeller left 0.09 of what lies under it where Apple's leaves 0.16, leaves 0.17. It costs up to 0.3 ms of GPU time a frame on an M2 iPad, and on a Galaxy S22 Ultra less than its noise.GlassHost.precacheloads it with the other shaders; until it has loaded, and past 4 texels, the engine's blur is asked for the sigma whose kernel delivers the calibrated one. Skia and the web are unchanged. - Large text sizes:
GlassTabBarandGlassSegmentedControlkeep their labels at no more than the default text size, as UIKit does; at twice the size labels were cut mid-word. A screen reader still gets every label whole.GlassTextFieldandGlassSearchBargrow with their line from 44 pt, keeping 11 pt above and below it, as aUITextFieldunder Dynamic Type.GlassTabBarshows the large content viewer at an accessibility text size (from 1.5 times): a touch on an item puts its icon and title up in a 220 pt panel in the middle of the screen, as iOS 26.5'sUITabBarControllerdoes, following the finger until it lifts. Glass at rest, so a still finger costs no capture (#27).GlassMenuAnchor's rows wrap a long label and grow to hold it, at any text size, as iOS 26.5'sUIMenudoes; they were cut to one line with an ellipsis. With the text, the rows' padding, the icon and its column grow. From 1.5 times the text the icons go and the menu takes the screen's width less 16 a side, up to 400; past 520 tall it scrolls, from the end nearest the anchor. The side it opens to is chosen from the measured height (#26).
- A held segment's label fades from the capsule's ink to the page's as the capsule fades into the drop; on a dark control it was black on the dark track.
- A disabled
GlassSwitchorGlassSliderexposes no tap or scroll action to a screen reader. - The dim behind a sheet fades as the sheet is dragged down to close, and comes back if it is let go short of closing.
Fixed #
- On Android, a fused group drawn as tiles is the picture of the one rectangle: a pixel on a rounded box's diagonal, where the refraction turns from one side to the other, went whichever way the last bit of its coordinate said, and on Vulkan and GLES that bit depends on the rectangle drawn. A lone surface's diagonal is broken the same way.
- Right to left:
GlassTabBarmaps touches, its resting capsule and its held drop from the start edge: a tap selected the mirrored tab (thanks to @sb-dor).- A menu row's inset is at its start edge.
GlassSegmentedControlplaces its capsule correctly when segments are added or removed, and a press held while the direction flips selects the segment it was held over.
- Held presses:
GlassSegmentedControlandGlassTabBarheld while their segments or items are added or removed end the press selecting nothing. The release selected the index held, which could be past the last one.- Disabled while held, both put their capsule back under the selected item, and the tab bar's drop no longer stays lifted.
GlassTabBarno longer clips its held drop at device pixel ratios other than 2, and its accessory no longer clips its capsule's end (thanks to @akoflacko).- A
GlassTabBarrebuilt with nothing changed, by asetStatearound it, is no longer a capture where the bar is lifted, as in aGlassScaffold: it keeps what it built. A newonSelectedalone is taken without a rebuild. - An open
GlassMenuAnchororGlassPopoverAnchorfollows its anchor when the anchor moves by layout alone, such as a list scrolled under it. - A
ShaderMaskorBackdropFilterunder glass, inside a repaint boundary away from the origin (a list row, say), is left as it was by the capture. The capture used to move the mask on screen until the row repainted, and to keep an idle screen capturing on every frame. - Glass over a fade of a
ColorFilteredorImageFilteredsubtree, or over aShaderMaskwhose blend mode paints past its child (srcOver,plus,screenand the like), shows what is on screen. The capture draws its own copy of the screen and, there, drew what the engine does not: the engine folds a fade into the filter and clips the mask to the child. Such a subtree is now drawn by the engine inside the capture, one more render pass on a frame that is capturing anyway, and named inWalkLog.fellBack. A subtree that holds glass is still drawn by the capture, as is aBackdropFilter. - A sheet dragged below its lowest detent is no longer captured on every frame of the drag: the part of it below the screen grew its capture, and the capture is now cut to the screen. A sheet dragged down to close still is, since the dim under it fades with the drag.
- Glass that changes finish over a still screen, such as a
GlassSearchBarturned from light glass to dark, or adaptive glass whose verdict moves, is captured again for the new finish. It used to keep the capture taken for the old one, at the old one's resolution, which showed as a trace of the first finish (6 code values, 15 on Impeller) until something under it moved. The new capture reads nothing back: the screen is what it was. - The hard scroll edge's band is the screen's background at 0.90, as on
iOS: the host's declared
backdrop, or black in the dark appearance (kGlassScrollEdgeHardFillDark, new) and white in the light one. Before, it was white in both, a light band over a dark screen. Measured against iOS 26.5 in the dark appearance. - The capture of glass on glass matches the engine in more cases:
- an opacity at full alpha opens no layer, so a child that clears or blends reaches the page;
- a
ShaderMaskaway from the origin draws its mask from its own corner; - a composited image filter at an offset is applied about that offset;
- a changed colour filter marks its whole clip dirty, so a held capture no longer goes stale;
ShadowFilter.dropMaskFilteredkeeps vertices, atlases and nine-patches, which Skia and Impeller draw sharp anyway.
Documentation #
- The README, the site and the agent skill say what the shadow filter cannot
see into (a cached
Picture, a text'sTextStyle.shadows), and that on Skia a resampling image filter samples slightly differently in the capture than on screen. - "What the app declares" on the site covers
GlassHost.appearance.
0.3.0 - 2026-10-19 #
Changed #
- Under an adaptive host, a tab bar's
bottomAccessorywears the bar's verdict instead of reading its own backdrop, so the two always cross between the light and dark branches together. GlassLedger.readleaves glass that draws nothing out of the load: a control's drop at rest (materialize0) is counted in the newGlassLoad.restingSurfaceCountand in none of the other counts or areas. Twenty resting switches no longer read as twenty captured surfaces.
Added #
GlassSurfaceRecord.drawsandGlassSurfaceRecord.captured: the one test the host's capture and the ledger both use.
Fixed #
- A
GlassSurfaceremoved under a held finger no longer asserts on the rest of the gesture (thanks to @melo936). GlassTabBarandGlassSegmentedControlremoved under a held finger (a route popped, a list recycled the row) ignore the rest of the gesture instead of moving disposed animation controllers.- A tab bar's accessory beside the collapsed circle keeps its lower rim: it was 2 px taller than the bar and clipped.
- A surface that replaces another at the same rect draws immediately; before, it drew nothing until something else on the screen changed. The same fix covers glass that returns to the top rung at the rects it left.
- The capture walk counts a colour filter under an
OpacityLayerthat arrives throughpushLayer, and sends that subtree to the stock capture. FilteringCanvasdrops a mask-filtered paint on every draw that takes a paint (points, images, vertices, atlases), not only on shapes.GlassMenuAnchor,GlassPopoverAnchorand aGlassPageControlwith aPageControllercreate their animation controller ininitState, not for the first time indispose.- A
GlassMenuControllergiven to aGlassMenuAnchororGlassPopoverAnchorin a rebuild drives it; taken away, the anchor's own controller takes over and an open panel stays open. - A
GlassPageControlwhosePageControlleris taken away showscurrentPage. - The capture walk restores its count of open opacities when a painter
throws inside
pushOpacity; every later colour filter in the pass went to the stock capture. GlassBadge,GlassScaffoldandGlassTabBarbuild without an ambientDirectionality.
Documentation #
- The
GlassBackdropReadingexample, the site and the agent skill pick a colour for content on glass withGlassTheme.of(context).legibility().label, notreading.brightness, which switches at a different level from the glass. - The guide, the tab bar page and the README say the tab bar adapts as one control.
0.2.0 - 2026-10-10 #
Changed #
- A pressed
GlassButtonswells (GlassPress);GlassPress.noneturns it off. - A sheet stands on the keyboard instead of under it: 8 px above it at the
medium detent, on it at large. Its content sees no bottom
viewInsets. - The switch, the slider and the segmented control take the drag from
touch-down: inside a horizontal scrollable such as a
PageView, a horizontal drag that starts on them moves the control, not the page. A vertical swipe still scrolls the list around them. - The ripple shader's uniforms moved:
count,reachandlightnow come after its arrays. Only code that writes the uniforms by hand is affected.
Added #
GlassBackdrop: declare what is behind the glass in a subtree (GlassBackdrop.color,.image,.texture,.gradient,.painter), and the glass samples a texture made from the declaration instead of a capture of the screen. A screen whose glass is all declared takes no snapshot.GlassBackdrop.livehands part of the subtree back to the capture. Diagnostics:RenderGlassSurface.paintsWithDeclaredBackdrop,RenderGlassGroup.paintsWithDeclaredBackdrop,RenderGlassSurface.readsDeclaredBackdrop,GlassBackdropDeclaration.renders,GlassSurfaceRecord.declaredandGlassSurfaceRecord.readsCapture.GlassStepper: a minus and a plus in one glass capsule, asUIStepper, with press-and-hold repeat (kGlassStepperRepeatDelay,kGlassStepperRepeatInterval) andwraps.GlassPageControl: page dots on a glass capsule, asUIPageControl. It follows and drives aPageController; a tap moves one page, a drag scrubs.GlassSearchBar: a glass search field with a clear button and a Cancel that slides in while it has the focus.GlassBadge: a count, a label or a dot on the corner of an icon or a tab.- Size constants:
kGlassStepperSize,kGlassPageDot,kGlassPageDotGap,kGlassPageControlHeight,kGlassBadgeHeight,kGlassBadgeDot. - Sheet detents:
showGlassSheet(detents:, initialDetent:, onDetentChanged:)withGlassSheetDetent.mediumandGlassSheetDetent.large. A large sheet drawslargeFinish(by default opaque) and, once fully up, reads no backdrop. GlassTabBar(minimizeBehavior: GlassTabBarMinimizeBehavior.onScrollDown): the bar collapses to a circle on scroll down and expands on scroll up or a tap. The scroll is read by aGlassTabBarMinimizer(GlassScaffoldis one);notificationPredicateandGlassScaffold.minimizeNotificationPredicatelet a nested list drive it.GlassTabBar.bottomAccessory: a glass capsule (kGlassTabAccessoryHeight, 48) above the bar that moves beside the collapsed circle.GlassPress, declared onGlassHost.press,GlassThemeData.pressorGlassButton.press.GlassSlider.divisions.- Keyboard support: the button, switch, slider, segmented control, stepper,
page control and toolbar cells take the focus (
focusNode,autofocus); Space and Enter activate, the arrows step. The focus ring iskGlassFocusRingColor,kGlassFocusRingWidthandkGlassFocusRingGap. - Right-to-left layout for the switch, slider, segmented control, toolbar,
stepper and page control.
SliderGeometry.fillEndtakes atextDirection. GlassConcentric: concentric corner radii as arithmetic.
Fixed #
- A dismissible sheet follows the finger (a 116 px drag moved it about 4.5 px), closes past a third of its height or on a flick, and costs one capture per drag instead of 16.
- Under right to left, the segmented control's capsule sat under the wrong
label, and
GlassButtonGroupbrightened the wrong cell. - A sheet popped while a finger drags it no longer pops the page under it when the finger lifts; a drag down from large after the content or the window changed no longer jumps.
GlassSlidersends exactly oneonChangeStartbefore its changes and oneonChangeEndafter, for every kind of gesture.- A segmented control in a vertical list no longer selects a segment after the list scrolled away under the finger.
GlassButtonGroupno longer throws, or keeps its focus ring on a missing cell, when the focused or held item is removed.
Performance #
- The shaders' uniforms are packed into
vec4s (19 slots to 9 for a surface and a group, 24 to 12 for the ripple): 0.9–1.8 µs less raster time per draw on Impeller/Metal, with byte-identical pixels.
Platforms #
- The minimum is Flutter 3.47.0 (Dart 3.13.0);
sdk: ^3.13.1had excluded 3.47.0 by mistake. CI tests that exact version.
Documentation #
- "Misuse and common errors" in the README and on the site.
- Site pages with live demos of the new components and behaviours; a README pattern for a tab bar that collapses on scroll; the agent skill covers them all.
0.1.4 - 2026-10-05 #
Fixed #
showGlassSheet(barrierDismissible: false)is a sheet only its content closes, as UIKit'sisModalInPresentation: a drag or a flick closed it regardless of the flag. A pull now gives a little and springs back.
Documentation #
- The API reference is grouped into topics, every public name has a doc
comment, and
dart docreports no unresolved reference. GlassProxyis documented in the README and on the site's Capture control page.- Every measured number says where it comes from.
- An agent skill for Claude Code, Codex, Cursor, Antigravity, Gemini CLI and
Copilot in
skills/g1455/:npx skills add PlugFox/g1455. The site publishes it at/.well-known/agent-skills/, withllms.txtand every page as markdown. - pub.dev shows the package icon first among the screenshots.
0.1.3 - 2026-10-04 #
Fixed #
- The README's images show on pub.dev again: 0.1.2 linked them by relative path, which pub.dev drops.
0.1.2 - 2026-10-04 #
Breaking changes #
GlassTabItem.iconis nullable: code that readsitem.iconas anIconDataneeds a null check.
Added #
- Adaptive glass:
GlassHost(adaptive: GlassAdaptive())reads the captured backdrop under eachGlassBar,GlassCardandGlassButton, and picks the light or dark branch of.regularand its label from it, with hysteresis and a tween between branches. Off by default and free when off.GlassTheme.of(context).readinghands the verdict to content on the glass. GlassMorph: swap the child and the glass flows to its new size, as a button becomes its menu (GlassMorphMotion.fluid,.calm).GlassDropMotion: the held drop of the switch, slider, segmented control and tab bar stretches as it sets off and squashes as it stops. Set onGlassHost.dropMotion,GlassThemeData.dropMotionor each control'sdropMotion;GlassDropMotion.noneturns it off.GlassTabItem.iconBuilderandlabelBuilder, given the colour the bar draws the item in.GlassHost.precache()compiles the shaders before the first frame.GlassScaffold: a screen wired the recommended way: a host, a top bar in a softGlassScrollEdge, an optional bottom bar and floating action, and a body that scrolls under the bars.
Fixed #
- A shader that fails to load is reported through
FlutterErrorinstead of escaping as an uncaught error, and the next load tries again. - On the web, a painter that throws while a glass layer records no longer leaks shaders.
Documentation #
- The README opens with a whole-app loop, has a runnable quick start, the
values of every
GlassFinishpreset, common patterns, and what the package does not do and why.
0.1.1 - 2026-10-04 #
Added #
GlassSwitch.semanticLabelandGlassSlider.semanticLabel; a screen reader stepsGlassSliderbysemanticStep.GlassButton.semanticLabel, read in place of the child.barrierLabelonshowGlassSheet,GlassMenuAnchorandGlassPopoverAnchor, so a screen reader can close them.showGlassSheet(constraints:), asshowModalBottomSheet.
Changed #
- The labels of
GlassButton,GlassSegmentedControlandGlassTabBarare not selectable under aSelectionArea.
Fixed #
- Glass draws correctly on CanvasKit (Safari and every browser without WasmGC): shaders were released before the picture was rasterized, and it drew from freed memory.
- Glass standing on glass no longer shifts what is under the lower glass
when a
CompositedTransformTarget(such as aSelectionArea's) is among it. - A
GlassGroupdrawn in tiles no longer loses members on the web. - A platform view or a
Textureis a hole in the capture of an upper level instead of a grey stub.
Documentation #
- The README covers the cost of glass on the web outside Chromium and what to do about it.
0.1.0 - 2026-10-03 #
First release on pub.dev, as g1455.
Breaking changes #
- The package was
glass: the library is nowpackage:g1455/g1455.dartand the shader asset keys arepackages/g1455/shaders/.... GlassFinish.regularis nowGlassFinish.regularDark(damage-table key'regularDark'). The light branch is the newGlassFinish.regularLight, andGlassFinish.regular(appearance:, backdrop:)picks between them as Apple's material does.GlassHost.finishis optional: null picks the.regularbranch from the declaredbackdropand the platform's appearance.
Added #
GlassScrollEdge: the scroll edge effect under a bar, soft or hard, top or bottom.GlassAbove: raises glass over the glass beside it.GlassSegmentedControl,GlassButtonGroup,GlassTextFieldandGlassTextField.search.showGlassDialogwithGlassAlert,showGlassSheet,GlassMenuAnchorandGlassPopoverAnchor. A menu grows out of its anchor and shrinks back.GlassSurface.fade(GlassFade).GlassRipple: an optional viscous wave from the touch point, onGlassHost.ripple,GlassThemeData.rippleorGlassSurface.ripple.
Changed #
- Drops, lone panels, the alert and the menu come and go through
materialize, as Apple's do, instead ofpresence. showGlassDialogandshowGlassSheetcarry the caller'sInheritedThemes to the overlay, asshowDialogdoes.
Fixed #
- The slider's fill ends in a capsule, not a square cut.
- A screen whose only glass is a resting drop no longer redraws every frame.
- Glass on glass no longer re-records a still screen every frame when the
lower glass holds content outside a
RepaintBoundary. - With two finishes on one screen, each blur class blurs only its own slots.
- Closing a menu over an anchor with its own semantics node no longer trips
!semantics.parentDataDirty.
0.1.0-dev.1 #
Not published. The first cut, moved out of the benchmark application that measured it.
- Shaders live under
lib/shaders/. glass_diagnostics.dartholds the benchmark switches and the host's proxy handle (debugGlassFusedSplit,debugGlassFoldCull,debugGlassShaderAntiAlias,fusedDrawTiles,GlassFusedTile,kMaxFusedTiles, the shader asset keys,GlassProxyHandle,GlassProxyScope).GlassPlatformSignalsandGlassSignalswere removed: the package ships no platform code.GlassThermalStatestays.GlassSurface.labelled,GlassGroup.labelledandGlassUnion.labelled: unlabelled glass is exempt from theminLabelContrastdim.GlassButtonno longer fills the width it is offered.- Disabled controls look disabled, as on iOS 26 (
kGlassDisabledOpacity,kGlassDisabledDarkLabel,kGlassDisabledLightLabel), and a control disabled mid-gesture lets go. - The host's debug check for missed repaints no longer fires on glass content or on a boundary that repainted nothing of its own.
