Skip to content

Illustrations

Ready-made isometric scenes for the moments every product has, drawn from your theme. Install one on its own, draw it by id, or hand it to a block.

Put a scene in an empty state, an onboarding step or a hero, and it's drawn in your theme's colors, light or dark. This one assembles as it comes into view. Point at it and it lifts off.

Each illustration is a small isometric scene: plinths, boxes, cylinders, stacks, turned solids and extruded profiles, shaded from your tokens, with one part in the accent. They cover the moments a product is built around (where its data lives, the machines that serve it, the screens people spend the day in, shipping, safety and the states nobody plans for) and the things people use products for, from shopping and money to travel, food, pets and the weather.

They all frame the same volume, so one scene swaps for another without the layout moving. Draw one by id with <Illustration>, import it as its own component, or pass its id to a block's illustration prop. Each assembles as it comes into view, and comes apart on hover when you ask it to.

The illustrations explorer is the gallery: search every scene by name, category or tag, preview one live in any preset, light or dark, copy its code or its install command, and download it as SVG or PNG.

To make a scene of your own, use the illustration builder (experimental): drag the kit's parts into place, preview it assembling, and export code, SVG or PNG. Draw your own covers the same parts in code.

Installation

From the package

Every scene ships in @youj/illustrations. Draw one by id, or import its component:

npm i @youj/illustrations
import { Illustration, IllustrationCoffee } from '@youj/illustrations'

Then add the package's stylesheet to your global CSS, after Tailwind and the tokens. Its sheet points Tailwind at the scenes; without it the classes they use are never generated:

app/globals.css
@import 'tailwindcss';
@import '@youj/react/styles.css';
@import '@youj/illustrations/styles.css';

One scene, as source

To own and edit a single scene, copy it in with the Youj CLI in an app set up from source (npx @youj/cli init --mode registry). Every scene is its own item, illustration-<id>. It brings the kit the scenes are drawn with (illustration-kit) and the shapes it uses, and nothing else. In an app on the packages, the same command installs @youj/illustrations and adds its stylesheet instead:

npx @youj/cli add illustration-coffee

It lands in components/youj/graphics/illustrations/scenes/<id>.tsx, and you import it from there through your @/ alias:

import { IllustrationCoffee } from '@/components/youj/graphics/illustrations/scenes/coffee'

Each scene's id and install command are on its card in the explorer.

Every scene

A scene's id is what <Illustration scene> takes, and its component is Illustration and the id in PascalCase (server-rack is IllustrationServerRack). The ids, by category:

CategoryScene ids
Databackups database pipeline storage warehouse
Infrastructurecloud edge load-balancer network server-rack
Appanalytics calendar documents mail notifications search
Lifecycledeploy empty not-found security success team
Commercedelivery shopping-bag storefront
Financecalculator coins invoice payment savings stock-chart wallet
Healthfirst-aid fitness heart-rate pills stethoscope tooth yoga
Educationabacus books globe graduation idea library school-backpack
Travelflight map suitcase
Foodbakery cocktail coffee cooking groceries pizza restaurant
Mediacamera design-tools easel film-reel guitar music video
Socialannouncement chat community newsletter phone-call podcast reactions video-call
Homegift home plant
Workbriefcase checklist trophy
Sportsbasketball bicycle stopwatch tennis
Playarcade dice game-controller puzzle
Eventscake party stage ticket
Petscat-tree dog-house fish-bowl pet-bowl
Weatherlightning rain snowflake sun-cloud
Natureflower greenhouse island mountain recycling tree water-drop
Energybattery ev-charger solar-panel wind-turbine
Transportbus car scooter ship train
Placesbank hospital lighthouse museum office-tower school
Outdoorsbeach binoculars compass hot-air-balloon tent
Scienceatom dna lab-flask microscope telescope
Securityfingerprint key padlock shield vault
Devicesdrone laptop phone printer smartwatch vr-headset
Businesscontract handshake meeting org-chart presentation scales target
npm i @youj/illustrations

import { Illustration } from '@youj/illustrations'

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

From the package, everything on this page comes from @youj/illustrations (pnpm add @youj/illustrations).

app/globals.css
@import 'tailwindcss';
@import '@youj/react/styles.css';   /* or '@youj/core/styles.css' without the components */
@import '@youj/illustrations/styles.css';

Its sheet points Tailwind at the built scenes, so it generates the classes they use; it goes after the tokens, in the same file. npx @youj/cli add adds it for you.

From the registry, the illustrations item copies every scene into @/components/youj/graphics/illustrations/, with the kit's shapes they're built from.

Usage

import { Illustration } from '@youj/illustrations'

export function NoInvoices() {
  return <Illustration scene="documents" title="No invoices yet" />
}

Each scene is also its own component, for when you know which one you want and would rather import it directly:

import { IllustrationDatabase } from '@youj/illustrations'

<IllustrationDatabase explode="hover" />

An id that names no scene draws fallback instead, so an id you stored that outlives its scene still draws something:

import { Illustration } from '@youj/illustrations'

function Empty({ sceneId }: { sceneId: string }) {
  return <Illustration scene={sceneId} fallback="empty" />
}

Every scene frames one volume, so swapping never moves the layout. Keyed on the id, the new one assembles in place:

Colour

Scenes are gray by default, with the accent as the one coloured part. Turn colour on with colors="theme" and each scene's subject takes one soft hue, and a second hue sets apart a second kind of thing, such as raw and processed data in a pipeline or two people shaking hands. The structure stays neutral and the accent is still the one lit part.

<Illustration scene="pipeline" colors="theme" />

The theme's pair is derived from the accent, so it follows every preset, light or dark:

  • Hue 1 is the accent's hue at a muted chroma, the scene's main colour.
  • Hue 2 is the hue opposite the accent, for the second kind of thing.
  • Hue 3 is a quarter turn away. It is rare, for a third kind.

Hues are mixed toward the surface, so they always sit quieter than the accent.

colors also takes your own colours, in hue order: tokens, brand colours or oklch(). They're softened the same way, and an empty string or a missing entry keeps the theme's:

<Illustration scene="pipeline" colors={['var(--color-success)', 'var(--color-warning)']} />

When you draw your own, give a shape hue={1} or hue={2} on top of its tone, and set colors on the scene. Without colors the shape shows its tone.

Examples

In a block

Blocks with room for a picture take an illustration prop: a scene's id, your own node, or null for the block's plainer look. Each opens on a scene that fits it.

<AuthShell variant="split" illustration="security">…</AuthShell>
<NoResults illustration="not-found" />
<MarketingCta illustration={<img src="/launch.svg" alt="" />} />
<NoProjects illustration={null} /> {/* the icon on its plates instead */}
BlockDefaultnull
App / Empty statesempty, search, security and cloud, one per stateThe icon on its fanned plates
App / First sourceIts own floor, with the chosen source waiting to landNo picture
App / Onboardingteam, on the welcome stepThe sparkles icon
Auth / Layout and Logindeploy, in the split layout's art panelThe gradient and the quote alone
Marketing / CTAdeploy, beside the call to action from lg upNo picture

On those blocks' pages, the preview's Illustration menu swaps the scene live. An id that names no scene falls back to the block's own.

Reference

Propstitle, description, assemble… (22)

Props

Every scene component, and <Illustration>, takes these.

IllustrationProps props
PropType
titlestring

Names the drawing for assistive tech; without it the scene is decorative (aria-hidden).

–
descriptionstring

A longer description, read after the title.

–
assembleboolean

Parts drop in, far ones first, the first time the scene comes into view.

default true

true
floatboolean

The scene's hero part bobs gently.

default true

true
explodenumber | boolean | 'hover'

Take it apart: a number from 0 to 1, a boolean, or 'hover' (stacks part and the lit part rises while the pointer is over it).

default 0

0
unitnumber

CSS px per grid unit at the drawing's natural size.

default 22

22
growboolean

Scale up past the natural size to fill a wider box.

default false

false
colorsreadonly string[] | 'theme'

Colour for the scene's parts: 'theme' for the theme's pair (derived from the accent), or any CSS colours, its main colour first (an empty entry takes the theme's). Default off: gray, with the accent the only colour.

–
classNamestring–
styleCSSProperties–

<Illustration> adds the scene to draw:

IllustrationComponentProps props
PropType
sceneIllustrationSlot | string

A scene by id, or a node drawn as given. null or false draws nothing.

–
fallbackIllustrationId
'security''target''key''success''database''home''storage''warehouse''analytics''pipeline''backups''server-rack''cloud''network''load-balancer''edge''mail''newsletter''calendar''meeting''documents''search''notifications''deploy''ship''vault''team''not-found''empty''storefront''shopping-bag''delivery''payment''wallet''coins''savings''heart-rate''fitness''first-aid''books''library''graduation''school''idea''suitcase''flight''map''coffee''restaurant''groceries''camera''music''video''chat''video-call''laptop''announcement''tree''plant''gift''checklist''briefcase''trophy''bicycle''basketball''stopwatch''tennis''game-controller''arcade''dice''puzzle''party''ticket''stage''cake''dog-house''fish-bowl''pet-bowl''cat-tree''sun-cloud''rain''snowflake''lightning''mountain''island''beach''flower''recycling''greenhouse''water-drop''solar-panel''wind-turbine''battery''ev-charger''car''bus''train''scooter''office-tower''bank''hospital''museum''lighthouse''tent''compass''binoculars''hot-air-balloon''microscope''lab-flask''atom''telescope''dna''padlock''fingerprint''shield''phone''smartwatch''vr-headset''printer''drone''handshake''presentation''easel''org-chart''contract''scales''stock-chart''calculator''invoice''phone-call''podcast''community''reactions''pizza''bakery''cocktail''cooking''pills''stethoscope''tooth''yoga''globe''school-backpack''abacus''guitar''film-reel''design-tools'

The scene drawn when scene is left out or names no registered scene.

–
titlestring

Names the drawing for assistive tech; without it the scene is decorative (aria-hidden).

–
descriptionstring

A longer description, read after the title.

–
assembleboolean

Parts drop in, far ones first, the first time the scene comes into view.

default true

true
floatboolean

The scene's hero part bobs gently.

default true

true
explodenumber | boolean | 'hover'

Take it apart: a number from 0 to 1, a boolean, or 'hover' (stacks part and the lit part rises while the pointer is over it).

default 0

0
unitnumber

CSS px per grid unit at the drawing's natural size.

default 22

22
growboolean

Scale up past the natural size to fill a wider box.

default false

false
colorsreadonly string[] | 'theme'

Colour for the scene's parts: 'theme' for the theme's pair (derived from the accent), or any CSS colours, its main colour first (an empty entry takes the theme's). Default off: gray, with the accent the only colour.

–
classNamestring–
styleCSSProperties–
MotionAssemble, float, explode · reduced motion

Motion

Scenes move on their stage's shared springs and clock, so the Speed control and the theme's personality reach them.

Motion tokens
MomentTokens
Assembleparts drop in, far ones first, the first time the scene is seen
spring.settlestagger.loose

0.45s, bounce 0.3 · 72ms step

0.45s, bounce 0.372ms step
Floatthe hero part bobs, out of step with its neighbors, paused offscreen
no token

one bob per 10 × deliberate

one bob per 10 × deliberate
Explodeexplode="hover": stacks part and the lit part rises; a reversal carries on from where it is
spring.smooth

0.36s, bounce 0

0.36s, bounce 0

Reduced motion

The finished scene, drawn once: nothing drops, nothing bobs, and a scene that's apart is shown apart.

Reduced motion

Scenes are drawn finished and still. Nothing drops in, nothing bobs, and with explode set they're shown apart.

AccessibilityARIA

Accessibility

  • Scenes are decorative by default (aria-hidden): the words beside them carry the meaning, as in an empty state. Give one a title, and a description if it needs one, when the picture itself says something, and it becomes a named image.
  • The accent marks one part, never the only difference: the lit part is also the one that floats, rises or is named nearby.
  • Hues are decoration, not information: every part keeps its shape and its edges in any colour, and with colour off.
  • Coming apart on hover is a flourish, not a control: it answers a mouse pointer only.