Glass
<Glass> draws liquid glass behind its children: the world under it bends at the rim, blurs across the middle, and takes the theme’s tint, sheen and edge. Use it for a surface the primitives do not draw, such as a quest card or a button of the game’s own. The engine’s glass draws with quickLiquid’s engine, carried in @spawnite/ui under its MIT licence.
Import it from @spawnite/ui, the package whose stylesheet the game’s src/styles.css already imports. The sample’s two components show the two variants and the two shapes: a pane that is the Glass, and a button with an empty Glass behind its label:
import { domAnimation, LazyMotion, m } from "motion/react";import { Glass, GlassVariant, Heading, Text, useLiveReducedMotion,} from "@spawnite/ui";import { glassPress, glassRelease } from "@spawnite/ui/motion";
interface QuestCardProps { title: string; goal: string;}
/** A pane with words on it: Regular, the default. */export function QuestCard({ title, goal }: QuestCardProps) { return ( <Glass className="flex w-72 flex-col gap-1 rounded-pane p-4 text-pane-ink shadow-lg shadow-pane-shadow"> <Heading level={3}>{title}</Heading> <Text>{goal}</Text> </Glass> );}
interface TrackButtonProps { onTrack: () => void;}
/** A control the world shows through: a button with a Clear Glass behind * its label, squashing under a press. */export function TrackButton({ onTrack }: TrackButtonProps) { const isStill = useLiveReducedMotion(); return ( <LazyMotion features={domAnimation}> <m.button type="button" whileTap={isStill ? undefined : glassPress} transition={glassRelease} className="relative isolate flex rounded-control px-4 py-2 text-pane-ink" onClick={onTrack} > <Glass aria-hidden variant={GlassVariant.Clear} className="pointer-events-none absolute inset-0 -z-1 rounded-[inherit]" /> Track </m.button> </LazyMotion> );}Choose a variant
Section titled “Choose a variant”variant picks how much the glass hides, after the two variants of Apple’s Liquid Glass:
GlassVariant.Regular, the default, frosts the world and bends it softly. Use it for a pane with words on it.GlassVariant.Clearblurs less and bends more. Use it for a control the world shows through, such as a round button over the play field.
Size, corner and layout
Section titled “Size, corner and layout”The host’s classes own its size, its corner, its shadow and its layout, as on any element. The glass draws its layers first and wraps the children in one element that takes the host’s layout, so a flex gap-2 on the Glass lays out the children. classNames.content reaches that wrapper, for what only it needs, such as overflow-y-auto on a scrolling pane.
as renders another element or motion component in place of the div, such as "button" or motion’s m.button, and Glass passes on every prop that element takes. An element renders as its motion component, so motion’s props, such as whileHover, reach it too.
Glass behind a control
Section titled “Glass behind a control”A control draws an empty Glass behind its content, as the sample’s TrackButton and every engine control do, rather than being the Glass. The button stays one element when its glass comes or goes, such as on a change of variant, so it keeps the player’s focus, and motion’s press reaches it from the keyboard too.
- The host takes
relative isolate, so the Glass stacks under its content and nothing outside it. - The Glass takes
aria-hiddenandpointer-events-none absolute inset-0 -z-1 rounded-[inherit]: it fills the host, takes its corner, and leaves the pointer and the reader to the host. - The press goes on the host, as
whileTap={glassPress}andtransition={glassRelease}.
Motion
Section titled “Motion”pressable squashes the glass under a press and springs it back on the release. appear grows it in on mount, and shrinks it out when it leaves inside motion’s AnimatePresence. Both hold still for a player who asked for less motion, and a motion prop the game passes wins over them.
The moves are motion targets in @spawnite/ui/motion, for a surface of the game’s own to share:
glassPressandglassRelease: the squash, as awhileTap, and the spring back, as atransition.glassHidden,glassShownandglassGone: the entrance and the exit, asinitial,animateandexit.jiggle: a wobble that calls the eye to a glass, such as one that refused a press, as ananimatetarget.
A move of the game’s own holds still for a player who asked for less motion by reading useLiveReducedMotion() from @spawnite/ui, as the sample’s press does. It follows the setting while the control is on screen, where motion’s own useReducedMotion reads it once, on mount.
Tune the glass from the theme
Section titled “Tune the glass from the theme”Glass reads the theme’s --glass-* and --blur-* tokens, which the theme page lists. A game tunes every Glass at once by setting them on :root. Frost turns the blur up and the refraction and the light down, so its glass is dark and frosted. For an optical option no token reaches, config takes it for one Glass: quality for a phone, saturation, lightAngle, ior, chromaticAberration and the like. The variant picks the material, the theme draws the tint, and the host’s classes own the corner and the shadow, so config has no key for them.
Glass reads the tokens when it mounts, and again when <html>’s attributes or a stylesheet in <head> change. Saturation and the light angle stay live, so a token set on a parent reaches them too. For a setting a player changes, set the tokens under an attribute on <html>, as hack-and-slash’s graphics setting does with data-detail.
What flattens the glass
Section titled “What flattens the glass”The world bends and blurs only in Chromium. Firefox and Safari draw no refraction, and keep the blur, the tint, the rim and the sheen.
Chromium flattens the glass when an ancestor carries an opacity under 1, a filter, a backdrop-filter, a mask, a clip-path or a blend mode. The browser gives no error, so in development Glass warns in the console and names the ancestor. Move the effect onto a sibling or onto the Glass itself. To fade a pane, grow it from its anchor with appear instead.
A player who asked for less transparency gets the pane on the menu’s dark surface, which the world does not show through.