Aurora Glow
Atmospheric accent-driven backdrop with off-centre bloom and filmic grain
Ship it on every screen.
Aurora glow auto-derives its hue, chroma, and lightness from the active accent token — switch themes in the DS config to see it re-skin.
import { AuroraGlow } from '@/components/aurora-glow';
export const meta = {
layout: 'fullscreen',
} as const;
export default function AuroraGlowPreview() {
return (
<AuroraGlow className="flex min-h-svh flex-col items-center justify-center gap-4 p-12 text-center">
<h2 className="text-balance font-bold font-heading text-4xl tracking-tight md:text-5xl">
Ship it on every screen.
</h2>
<p className="max-w-xl text-balance text-base text-foreground-secondary">
Aurora glow auto-derives its hue, chroma, and lightness from the active
accent token — switch themes in the DS config to see it re-skin.
</p>
</AuroraGlow>
);
} Source Code
import type { VariantProps } from 'cva';
import { Children, cloneElement, isValidElement } from 'react';
import { cn, cva } from '@/lib/utils/classnames';
const auroraStyle = cva({
base: 'relative isolate overflow-hidden',
variants: {
/**
* Where the primary light source sits. `bottom-left` matches the
* Aave Pro / Fey reference; the others let consumers re-anchor the
* spotlight for hero sections, sidebars, etc.
*/
origin: {
'bottom-left':
'[--glow-x:22%] [--glow-y:75%] [--haze-x:35%] [--haze-y:100%]',
'bottom-center':
'[--glow-x:50%] [--glow-y:80%] [--haze-x:50%] [--haze-y:100%]',
'bottom-right':
'[--glow-x:78%] [--glow-y:75%] [--haze-x:65%] [--haze-y:100%]',
'top-left':
'[--glow-x:22%] [--glow-y:25%] [--haze-x:35%] [--haze-y:0%]',
'top-right':
'[--glow-x:78%] [--glow-y:25%] [--haze-x:65%] [--haze-y:0%]',
center: '[--glow-x:50%] [--glow-y:50%] [--haze-x:50%] [--haze-y:50%]',
},
/**
* How dramatic the bloom reads. `subtle` for ambient backdrops,
* `bold` for capstone sections.
*/
intensity: {
subtle: '[--glow-alpha:0.55] [--haze-alpha:0.35]',
default: '[--glow-alpha:0.85] [--haze-alpha:0.55]',
bold: '[--glow-alpha:1] [--haze-alpha:0.7]',
},
/**
* Whether to render the SVG grain overlay. Grain disguises banding
* on dark surfaces and adds the Resend/Raycast filmic texture.
*/
grain: {
none: '[--grain-opacity:0]',
subtle: '[--grain-opacity:0.04] dark:[--grain-opacity:0.06]',
bold: '[--grain-opacity:0.08] dark:[--grain-opacity:0.1]',
},
},
defaultVariants: {
origin: 'bottom-left',
intensity: 'default',
grain: 'subtle',
},
});
interface AuroraGlowProps
extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>,
VariantProps<typeof auroraStyle> {
/**
* Render the wrapper as a different element (e.g. `<section>`) while
* keeping all the aurora styling. Slot composition, not polymorphism.
*/
asChild?: boolean;
children?: React.ReactNode;
}
/**
* Aurora-style atmospheric backdrop. Generates a layered OKLCH gradient
* derived from `--color-accent` so it re-skins automatically when the
* active theme/scheme changes. Adds a subtle vignette on the off-axis
* side and an SVG grain overlay to kill banding.
*
* Inspired by Aave Pro, Fey, Resend, and Raycast launch surfaces.
*/
// Inline SVG noise data URL for grain layer. baseFrequency=0.9 produces a
// fine grain that disappears at low opacity but kills banding.
const NOISE_URL =
"url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>\")";
const GRADIENT_BG = `
radial-gradient(
70% 55% at var(--glow-x) var(--glow-y),
oklch(from var(--color-accent) calc(l + var(--lift)) calc(c + 0.08) h / var(--glow-alpha)),
transparent 65%
),
radial-gradient(
90% 70% at var(--haze-x) var(--haze-y),
oklch(from var(--color-accent) calc(l + var(--lift) - 0.1) calc(c + 0.02) calc(h - 6) / var(--haze-alpha)),
transparent 72%
),
radial-gradient(
120% 90% at 50% 50%,
transparent 45%,
oklch(from var(--color-background) calc(l - 0.04) c h / 0.55) 100%
)
`;
function AuroraLayers() {
return (
<>
{/* Gradient layer — absolute so the consumer can stack any content on
top without worrying about z-index. `--lift` shifts the bloom
lightness in dark mode so it reads as a light source instead of
dissolving into the dark background. `--glow-x/y` and `--haze-x/y`
are set by the `origin` variant. */}
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0 -z-10 [--lift:0] dark:[--lift:0.22]"
style={{ backgroundImage: GRADIENT_BG }}
/>
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0 -z-10 opacity-(--grain-opacity) mix-blend-overlay"
style={{ backgroundImage: NOISE_URL, backgroundSize: '200px 200px' }}
/>
</>
);
}
function AuroraGlow({
asChild,
origin,
intensity,
grain,
className,
children,
...props
}: AuroraGlowProps) {
const styleClass = cn(auroraStyle({ origin, intensity, grain }), className);
if (asChild) {
// Clone the single child element, merging our className and injecting the
// aurora layers alongside the consumer's children. This keeps Slot's
// single-child contract intact while letting consumers render any
// element (e.g. `<section>`) as the root.
const child = Children.only(children);
if (!isValidElement<React.HTMLAttributes<HTMLElement>>(child)) {
return null;
}
return cloneElement(
child,
{
...props,
className: cn(styleClass, child.props.className),
},
<AuroraLayers />,
child.props.children
);
}
return (
<div className={styleClass} {...props}>
<AuroraLayers />
{children}
</div>
);
}
export { AuroraGlow, auroraStyle };
export type { AuroraGlowProps }; Server component. No
'use client'— pure CSS layers with cva variants andcloneElementforasChildcomposition.
AuroraGlow is an atmospheric backdrop in the Aave Pro / Fey / Resend / Raycast
lineage: a single off-centre light source on top of a deep base, with a subtle
vignette and SVG grain to mask banding. All colour is derived from
--color-accent via relative-color OKLCH, so it re-skins automatically when
the active scheme changes.
Anatomy
<AuroraGlow origin="bottom-left" intensity="default" grain="subtle">
{/* your section content sits on top — gradient layer is `-z-10` */}
</AuroraGlow>
The component renders three stacked layers behind whatever content you nest inside it:
- Primary bloom — a saturated radial sitting at
origin, lifted in lightness for dark mode. - Diffuse haze — a softer secondary radial that carries the hue across the section so the bloom doesn’t read as a single dot.
- Vignette + grain — a quiet edge shadow plus a
feTurbulenceoverlay at--grain-opacity.
Props
origin(defaultbottom-left): one ofbottom-left,bottom-center,bottom-right,top-left,top-right,center.intensity(defaultdefault):subtle,default,bold.grain(defaultsubtle):none,subtle,bold.asChild: render as a Slot child (e.g.<section>) instead of<div>.
Theming
The gradient uses oklch(from var(--color-accent) ...) so any scheme that
defines --color-accent works out of the box. Lightness shifts in dark mode
via a --lift CSS variable toggled by the dark: Tailwind variant.
Notes
- The wrapper sets
isolate overflow-hiddenso the gradient layers don’t leak outside. - Content inside the slot does not need
relativeorz-index— the gradient layers sit at-z-10, content stacks on top naturally. - Grain is rendered as an inline SVG data URL — no external asset, no extra network request.
Previous
App Shell
Next
Auto Grid