Components
ShaderSurface
Unstable: a moving background drawn by a WebGL shader, the design's Shader Surface in its nine types, for CtaBand, BentoTile, ProfileCard or a page section. Import it from @nizivo/react/unstable/shader-surface.
Examples
Basic
Aurora as ProfileCard's cover (it follows the theme) and as CtaBand's background (aurora-dark, dark on any page, as the band is).
Alex Rivera
Product designer · Lisbon
Ship your next screen with Nizivo
One library, two themes, every state designed.
import type { JSX } from 'react';
import { CtaBand } from '@nizivo/react/unstable/cta-band';
import { ProfileCard } from '@nizivo/react/unstable/profile-card';
import { ShaderSurface } from '@nizivo/react/unstable/shader-surface';
export function ShaderSurfaceExample(): JSX.Element {
return (
<div style={{ display: 'grid', gap: 24, inlineSize: 640, maxInlineSize: '100%' }}>
<ProfileCard
style={{ inlineSize: 320 }}
name="Alex Rivera"
description="Product designer · Lisbon"
cover={<ShaderSurface />}
/>
<CtaBand
title="Ship your next screen with Nizivo"
description="One library, two themes, every state designed."
background={<ShaderSurface variant="aurora-dark" />}
/>
</div>
);
}
Variants
Every variant, as the design's Shader Surface types name them.
import type { JSX } from 'react';
import { ShaderSurface, type ShaderSurfaceVariant } from '@nizivo/react/unstable/shader-surface';
const VARIANTS: readonly [ShaderSurfaceVariant, string][] = [
['aurora', 'Aurora'],
['aurora-dark', 'Aurora Dark'],
['contour', 'Contour'],
['contour-dark', 'Contour Dark'],
['dot-matrix', 'Dot Matrix'],
['glow-orb', 'Glow Orb'],
['glow-orb-dark', 'Glow Orb Dark'],
['rays', 'Rays'],
['mesh', 'Mesh'],
];
export function ShaderSurfaceVariantsExample(): JSX.Element {
return (
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(12rem, 1fr))',
gap: 16,
inlineSize: 640,
maxInlineSize: '100%',
}}
>
{VARIANTS.map(([variant, name]) => (
<figure key={variant} style={{ display: 'grid', gap: 8, margin: 0 }}>
<div style={{ blockSize: 120, borderRadius: 12, overflow: 'hidden' }}>
<ShaderSurface variant={variant} />
</div>
<figcaption>{name}</figcaption>
</figure>
))}
</div>
);
}
Import
import { ShaderSurface } from '@nizivo/react/unstable/shader-surface';
// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/shader-surface.css';Static or interactive
Client. The server renders a poster in the same colours, drawn with CSS; once the page hydrates, a canvas draws the shader over it from its first frame. A browser without WebGL keeps the poster. How to choose.
Variants
variant is the design's Shader Surface type, and each follows the theme:
- Aurora (
aurora, the default): soft curtains of light that sway, lime over a pale ground with mint below. - Contour (
contour): the contour lines of a slowly drifting landscape, pale, with one level in six drawn bold. - Dot Matrix (
dot-matrix): a grid of dots in slow waves, lime where it is brightest. Always dark, as the design draws it. - Glow Orb (
glow-orb): GlowOrb's sphere in a glow that spreads over the box. - Rays (
rays): fine strands of green, lime and warm light, some soft, leaning and waving. - Mesh (
mesh): a soft field of mint, lime, green and the page's ground, drifting.
aurora-dark, contour-dark and glow-orb-dark keep their dark colours on a light page, for a band
that is always dark. The design's Rays use an amber that is not in the palette; here the warm
strands take icon/warning. Each variant's shader loads when the first surface of that variant
mounts, so a page downloads only the ones it shows.
In a component
It fills its box. Pass it to the components the design draws with it:
CtaBand's background (<ShaderSurface variant="aurora-dark" />),
BentoTile's background (Aurora for a wide tile, Glow Orb for a
square one, Contour for a tall one, as the design draws them) and
ProfileCard's cover. Each drops its CSS background behind it, and
CtaBand keeps a soft dark scrim behind its text, so the text stays readable whatever drifts behind.
Light on a phone
No library: one fragment shader on WebGL 1, on the same small runtime as GlowOrb. It draws only while it is on screen and the page is visible, at a pixel ratio of at most 2, and gives its WebGL context back when it unmounts (a page holds about sixteen at once). Under Reduced motion it draws one still frame. In forced colours the canvas is hidden and the system's colours show.
Colours
Each variant reads four of Nizivo's colours, chosen to match the design's. Set
--nz-shader-surface-ground and --nz-shader-surface-tone-1 to -tone-3 to recolour any variant;
the stylesheet says which tone is which in each. It is decoration, hidden from assistive technology; never set text on it without a surface of
its own.
Props
Client component Renders data-slot="shader-surface" with the class nz-shader-surface. Props: ShaderSurfaceProps. Source: src/unstable/shader-surface/shader-surface.client.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
variant | ShaderSurfaceVariant"aurora""aurora-dark""contour""contour-dark""dot-matrix""glow-orb""glow-orb-dark""mesh""rays" | 'aurora' | Figma's Shader Surface type: |
- Also takes every attribute of
<span>exceptchildren. (Omit<ComponentPropsWithRef<"span">, "children">)
Other exports
ShaderSurfacePropstypeimport type { ShaderSurfaceProps } from '@nizivo/react/unstable/shader-surface'The props of
ShaderSurface, listed above.ShaderSurfaceVarianttypeimport type { ShaderSurfaceVariant } from '@nizivo/react/unstable/shader-surface'Figma's Shader Surface types; a
-darkone keeps its dark colours on a light page.type ShaderSurfaceVariant = "aurora" | "aurora-dark" | "contour" | "contour-dark" | "dot-matrix" | "glow-orb" | "glow-orb-dark" | "mesh" | "rays"
Data attributes and slots
Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.
| Slot | Rendered by | Data attributes |
|---|---|---|
shader-surface.nz-shader-surface | ShaderSurfaceroot (no render) |
|
CSS hooks
Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.
| Hook | Default | Read as |
|---|---|---|
--nz-shader-surface-ground |
|
|
--nz-shader-surface-tone-1 |
|
|
--nz-shader-surface-tone-2 |
|
|
--nz-shader-surface-tone-3 |
|
|
Layers: nz.components. Classes: .nz-shader-surface, .nz-shader-surface-canvas, .nz-shader-surface-poster.
Tokens this stylesheet reads (7)
--nz-bg-accent, --nz-bg-accent-subtle, --nz-bg-brand, --nz-bg-brand-muted, --nz-bg-brand-subtle, --nz-bg-canvas, --nz-icon-warning
Accessibility
Nothing in this component takes focus or keyboard input.
Keyboard
None.
Separator
An <hr>: a 1 px border/subtle line. Decorative by default; spacing comes first, a line only when spacing is not enough.
Sidebar
The app's main navigation on screens 640 px and wider, with the store at the top, the destinations, and Settings at the foot. It is 264 px wide from 1280 px and folds to a 72 px icon rail below that, where each destination's Tooltip names it.