This page is for choosing. Every option the card parts and the motion system
offer is on it, side by side, each one showing the exact source that produces
it behind “Show code”. Nothing here is a new component: the variants are
modifiers on Card and the transitions are classes in recipes.css.
The reference tables are on Cards for the parts and in
docs/design-system.md for the motion tokens and the site theme.
Four tones, each of them a different answer to “what stands in for the edge”.
outlined is the default and card is its older name; filled and muted
are likewise the same tone. Padding and radius do not move between them, so a
row can mix tones and still line up.
tone="elevated"
A shadow instead of a border.
Show code
<Cardtone="elevated">
<CardContent>A shadow instead of a border.</CardContent>
top is the stacked card. side puts the frame down the leading edge at 40%
of the card and stacks again below 42rem, so a narrow viewport gets the top
placement whatever is asked for. background fills the card with the frame,
draws an overlay over it, and inverts the ink onto the fixed paper tone.
A figure, its label, and an optional change. The number is the child, so it can
carry a unit or markup; the delta is a Badge and its tone is the caller’s,
because the component has no idea whether up is good.
BigNumber is the figure with no card around it: the number at the display
step, the unit beside it a step down, and the label above or below. Sparkline
is the trend at control size, drawn by the same Plot-at-build path as Chart
and shipped as inline SVG — no axes, no gridlines, one series in
--helia-chart-1 unless the composition sets --accent.
The arrow and the ink are two props. direction says which way the number
went; deltaTone says whether that reads well, and only the composition knows,
because a figure that counts open findings goes up and that is not good news.
Both parts set their figures in tabular numerals, so a row of them lines up on
the digit.
Every number below is invented and describes this documentation site. Nothing
here is a measurement of any part.
The accent is a hint, not a field, and so is the ink. A page spends both a few
times: the accent word in the hero, one inked tile in a mosaic, the layer of a
stack the page is about, the leading bar in a comparison, and the link out to
the hub. The parts below are what make those moments cheap to write. What a
page may spend, and how often, is the accent budget in the design system.
tone="ink" puts one card of a set on the ground the contrast hero uses,
pinned dark in both themes, with the inks and the accent re-derived against it.
The title, which is the link, takes the accent. One of them in a set: two
inked tiles is a dark row with a gap in it.
accent on a BigNumber colors the unit and nothing else. The glyph is the
smallest thing on a figure that still reads across a section, so it is what the
budget can afford here; the number stays ink.
Every number below is invented and measures nothing.
<BigNumber accent unit>
Vector over scalar
12×
Vector over DSP
8×
DSP over scalar
3×
Show code
<Card>
<CardContentvariant="stats">
<BigNumberlabel="Vector over scalar"unit="×"accent>
Stack is the chain of layers a product page opens with: what sits above the
thing, the thing, and what it runs on. One layer carries accent, and it is
the page’s own. Below 62rem the chain folds to two columns, because four
columns of wrapped pills on a phone is not a diagram.
Bars is the comparison a heading needs and a chart is too heavy for: labeled
tracks against one scale, an axis under them, and one accented row. Every row
is text as well as a bar, so the reading survives without the tracks. Past a
handful of rows, or with a series that has a shape, reach for Chart.
The figures below are invented and measure nothing.
<Bars rows max ticks>
Vector12.0×
DSP3.3×
Scalar1.0×
0×6×12×
Invented figures, held here to show the scale.
Show code
<Bars
max={12}
ticks={['0×', '6×', '12×']}
caption="Invented figures, held here to show the scale."
Title, one line, and a cue that moves when the card is under the pointer. The
link lives on the title and the recipe stretches it over the card, so the whole
card is the target and the cue is inside the same hit area.
A page that renders its cards from a record writes none of their words in its
source. The parts state their own line for the page’s Markdown twin, so an
agent reading the rendition gets the card the page shows rather than the props
it was written with.
Six cards that need no image. Good artwork is the scarcest thing a card family
depends on, so each of these carries itself on type, a mark or a figure
instead. None of them is a new component: they are the CardHeader marks and
scale, two parts (CardList, CardQuote) and one CardContent variant, so
tone, density and the lift reach all of them unchanged.
Five transitions, each built from the motion tokens and nothing else, so the
per-site dial and the reduced-motion rule reach all of them at once. Point at
the cards below; none of them does anything at rest.
The site theme is nine dials in one file. :root is where a site sets them;
a section that wants its own treatment sets them on a wrapper that carries
data-helia-theme, which is the hook semantic.css re-derives the composed
tokens on. That is the mechanism every example below uses, and it is why they
can sit next to each other on one page. A wrapper without the attribute moves
only the dials themselves, not the radius steps and tinted surfaces built out
of them.
The accent dial reaches a card through its artwork rather than its edge: no
card part carries an accent rule or brim, so a subtree that names an accent
shows it in the media, the badges and the type. The second accent is the one
that pairs with it, and a link card spends it on the cue under the pointer.
Reveal fades and rises what it wraps the first time it reaches the viewport.
Use it on a section, not on every card in one: a page where each element
arrives separately reads as a page that is still loading. stagger is the one
exception, and it is still one wrapper.
The hidden state is a class the script adds, so the content is visible without
JavaScript, and the script returns before arming anything when the motion scale
is 0.
Replay re-arms every reveal on this page, so the entry can be watched without
scrolling away and back. It does nothing for a visitor who asked for reduced
motion, because nothing armed.
Scroll on. The cards below start hidden and arrive as they reach the viewport.
<Reveal>
One section, one reveal.
The cards inside it arrive together.
Which is the point of wrapping the section.
Show code
<Reveal>
<divclassName="gallery-grid not-content">
<Cardtone="elevated">
<CardContent>One section, one reveal.</CardContent>
</Card>
<Cardtone="elevated">
<CardContent>The cards inside it arrive together.</CardContent>
</Card>
<Cardtone="elevated">
<CardContent>Which is the point of wrapping the section.</CardContent>
</Card>
</div>
</Reveal>
A gap, so the staggered grid below is still out of view when the group above
arrives.
The cascade is on the direct children, so the grid is the Reveal rather than
a div inside it: one wrapper with a grid class on it, and the cards are the
children that arrive.
<Reveal stagger>
With stagger, the children arrive in order.
Each one waits a fast step longer than the last.
The wrapper itself does not move.
The cascade stops at the sixth child.
Show code
<Revealstaggerclass="gallery-grid not-content">
<Cardtone="elevated">
<CardContent>With stagger, the children arrive in order.</CardContent>
</Card>
<Cardtone="elevated">
<CardContent>Each one waits a fast step longer than the last.</CardContent>
</Card>
<Cardtone="elevated">
<CardContent>The wrapper itself does not move.</CardContent>
</Card>
<Cardtone="elevated">
<CardContent>The cascade stops at the sixth child.</CardContent>
</Card>
</Reveal>
A second gap, so the group below is still out of view when the first arrives.
<Reveal threshold={0.4}>
A higher threshold waits until more of the section is in view.
Lower it for a section too tall to ever cross the mark.
Show code
<Revealthreshold={0.4}>
<divclassName="gallery-grid not-content">
<Cardtone="filled">
<CardContent>
A higher threshold waits until more of the section is in view.
</CardContent>
</Card>
<Cardtone="filled">
<CardContent>
Lower it for a section too tall to ever cross the mark.
Four parts that arrange a page rather than fill one. None of them knows what it
is carrying: the ground, the cards and the artwork are all handed in, so the
same four cover a product page, a release note and a landing.
Band takes a section to the edges of the reading frame and keeps its content
on the readable measure. tone picks the ground and density the rhythm above
and below it. None of the four grounds draws an edge or an elevation: a section
that carried either would be a very wide card.
<Band tone="muted">
Ground
A section with a ground of its own
The paint runs to the edges of the frame and the words stay on the
measure. Nothing is drawn around it.
Show code
<Bandtone="muted">
<divslot="header">
<Eyebrow>Ground</Eyebrow>
<h4>A section with a ground of its own</h4>
</div>
<p>
The paint runs to the edges of the frame and the words stay on the
CardGrid is the row of peers. A named count steps down at the two
breakpoints; auto fits whatever min allows, which is the answer for a set
whose length the page does not know. stagger makes the grid the reveal
itself, so the cards cascade in rather than the block arriving as one.
<CardGrid columns={3} equalize stagger>
Columns
Two, three, four, or as many as the minimum allows.
Equalise
Every row takes the height of the tallest card on the grid.
Masonry packs cards of unequal height into columns with no dead space under
the short ones. It is CSS columns, so the packing is right in the first paint;
the cost is a reading order that runs down each column before it moves across.
Masonry packs by column with no JavaScript; use CardGrid when rows must
align.
<Masonry columns={3}>
The profile told us where the cycles went on the first afternoon.
DMDana MercerFirmware lead
Uneven by design
A short card next to a long one is what the layout is for. Forcing the
two to one height is what makes a set of notes look padded.
Mosaic gives one card the room to carry artwork and fills the rest of the set
around it. The feature is the first child rather than a prop, so the
arrangement follows reading order. pattern moves it to the end of the set or
across the top.
<Mosaic>
The feature
Two columns by two rows, with somewhere to put the artwork.
The rest of this section is not an example on a stage: the bands are on the
page itself, which is the only way to see a ground actually run to the edges
and a run of sections read as one rhythm. Scroll it as a page rather than as a
set of parts.
Overview
One feature and the set around it
Featured
The one the section is about
Artwork needs room, and a grid of equals says nothing about which card
is the point.
Beside it
Peers, at the size a peer deserves.
Under it
Filled in document order.
And on
The set is as long as the page needs.
Capabilities
Three peers on a ground
The ground changes
The section above it has none, so this one reads as a step rather than
as a box.
The measure does not
Paint to the edges, text on the same width as the prose above it.
Nothing is drawn
No edge, no brim, no shadow. The ground is the whole of the signal.
Notes
What came back from the field
We stopped arguing about section spacing the week the bands landed.
PRPriya RamanPlatform
Content first
Good artwork is the scarcest thing a card family depends on, so the
options that carry a card without an image are the ones a long page
leans on.
Covered
What a note can hold
A quote and who said it
A short list
A line of prose
Three columns, no measuring, no layout shift when the font lands.
SOSam Okafor
The close
The inked ground is pinned dark in both themes, because ink that follows the
theme over a ground that does not is a section that reads half the time.
Code slotted into it holds the dark syntax theme on either page theme, for
the same reason.
Chart draws with Observable Plot at build and ships the result as inline SVG,
so a page with five charts on it still ships no chart JavaScript. The palette is
written as var(--helia-chart-*), which is what lets a figure that will never be
redrawn follow the theme toggle.
The title and the subtitle are the part’s HTML rather than Plot’s type, and the
subtitle says what is plotted against what — which is why no axis is titled.
Gridlines run across the measure; only a scatter, which has a measure on both
axes, gets the second set.
Every number below is invented and describes this documentation site. Nothing
here is a measurement of any part.
kind="line" with two series
Weekly page views
Page views against week of the quarter, by section
Guides
Reference
Synthetic series.
Show code
<Chart
title="Weekly page views"
subtitle="Page views against week of the quarter, by section"
caption="Synthetic series."
kind="line"
data={trafficSeries}
x="week"
y="views"
series="section"
width={900}
height={280}
/>
kind="bar" grouped by series
Build time by stage
Wall-clock seconds against build stage, by cache profile
Cold
Warm
Show code
<Chart
title="Build time by stage"
subtitle="Wall-clock seconds against build stage, by cache profile"
kind="bar"
data={buildSeries}
x="stage"
y="seconds"
series="profile"
width={900}
height={280}
/>
kind="area", one series
Pages published
Pages on the site against week of the quarter
Show code
<Chart
title="Pages published"
subtitle="Pages on the site against week of the quarter"
kind="area"
data={pagesSeries}
x="week"
y="pages"
width={900}
height={260}
/>
kind="scatter", gridlines on both axes
Weight against score
Performance score against transferred kilobytes, by template
Static
Island
Show code
<Chart
title="Weight against score"
subtitle="Performance score against transferred kilobytes, by template"
A chart with more categories than a row of bars can name, and a measure that
spans more than a decade, needs four options the defaults do not give it. The
set below is invented — the routines do not exist and neither do the ratios —
but it is shaped like the one the options were written for: fourteen long
names, three series, and speedups from under one to twelve.
orientation="horizontal" puts the categories on the vertical axis and takes
the left margin from the longest label, so a name is never cut. The data
contract does not move with the drawing: x still names the categories and y
still names the measure.
orientation="horizontal"
Speedup by routine
Times faster than the reference path, by code path
vector path
scalar path
reference
Invented routines and invented ratios.
Show code
<Chart
title="Speedup by routine"
subtitle="Times faster than the reference path, by code path"
caption="Invented routines and invented ratios."
kind="bar"
data={routineSpeedups}
x="routine"
y="speedup"
series="path"
orientation="horizontal"
width={900}
height={620}
/>
scale moves the measure. A log axis ticks at 1, 2 and 5 through each decade
it spans and rounds its own ends to that sequence unless min and max say
otherwise, which is what stops a set with one twelve-times result in it from
drawing every other bar as a stub. A log axis cannot draw a zero or a negative
number: given one, the chart is drawn linear and the build log says why.
scale={{ type: "log", min: 0.5 }}
Speedup by routine, logarithmic
Times faster than the reference path, by code path
vector path
scalar path
reference
Show code
<Chart
title="Speedup by routine, logarithmic"
subtitle="Times faster than the reference path, by code path"
kind="bar"
data={routineSpeedups}
x="routine"
y="speedup"
series="path"
orientation="horizontal"
scale={{ type: 'log', min: 0.5 }}
valueFormat={(value) =>`${value}x`}
width={900}
height={620}
/>
Inside a group the bars run in the order the rows first name the series, not in
the order those names sort in, and the legend lists them in that same order. The
series here are written fastest first — vector path, scalar path,
reference — which is not alphabetical, so the two orders agreeing is the
assertion rather than a coincidence.
Group order is series order
Speedup by routine, compact
Times faster than the reference path, by code path
vector path
scalar path
reference
Show code
<Chart
title="Speedup by routine, compact"
subtitle="Times faster than the reference path, by code path"
kind="bar"
data={routineSpeedups}
x="routine"
y="speedup"
series="path"
orientation="horizontal"
density="compact"
width={900}
height={520}
/>
axis titles an axis the subtitle cannot carry the unit for, valueLabels
writes each bar’s value at its end, and referenceLines draws a rule across
the measure. A constant baseline belongs on the rule rather than in a third
series: it costs a palette color, a legend entry and a third of the bars to
draw a line. Value labels are dropped as a set when the bands are too small to
hold them, so a chart that shows them at one height stops showing them at
another rather than overprinting.
axis, valueLabels and referenceLines
Speedup against the reference path
Two code paths, fourteen routines
vector path
scalar path
Show code
<Chart
title="Speedup against the reference path"
subtitle="Two code paths, fourteen routines"
kind="bar"
data={routinePaths}
x="routine"
y="speedup"
series="path"
orientation="horizontal"
scale={{ type: 'log', min: 0.5 }}
axis={{ valueLabel: 'Times faster than reference', categoryLabel: 'Routine' }}
ChartGroup gives the charts equal columns, so three drawn at the same width
and height line up across the row and read as one figure. Draw them at a width
near the column, not at the page width: the SVG scales into its column and takes
its type with it.
<ChartGroup> of three
Page views
Views against week, by section
Guides
Reference
Build time
Seconds against stage, by cache profile
Cold
Warm
Pages published
Pages against week
Show code
<ChartGroup>
<Chart
title="Page views"
subtitle="Views against week, by section"
kind="line"
data={trafficSeries}
x="week"
y="views"
series="section"
width={300}
height={200}
density="compact"
/>
<Chart
title="Build time"
subtitle="Seconds against stage, by cache profile"
Three parts for an index rather than a grid of cards: the tile that marks an
entry, the row that is one entry, and the panel that sets a short piece of
writing beside the code it describes.
The box comes off the control-height scale and the frame is one of three.
--accent is per instance, so a list can give every entry a color of its own
without the part learning what the list holds.
The anchor is the row itself, so the tile, the title and the line are one hit
area and one accessible name. Hover tints the row where it sits; nothing
lifts. Two to a desktop column and one to a phone is CardGrid columns={2}.
The code slot is what the panel exists for: the block is the answer to the
sentence beside it rather than a fence further down the page. ratio gives the
two columns their share of the width, and below 62rem the text leads and the
code follows.
<SplitPanel ratio="3:2">
Quickstart
Profile a model on the board
The command reads the model, runs it on the attached board and writes the
layer timings beside it.
npm run profile -- model
profile('model')
Show code
<SplitPanelratio="3:2"titleAs="h4">
<spanslot="eyebrow">Quickstart</span>
<spanslot="title">Profile a model on the board</span>
<divslot="body">
The command reads the model, runs it on the attached board and writes
The top of a landing page. The headline is the default slot rather than a prop,
because the word that takes the product accent has to be marked in the markup:
wrap it in <em> and the hero draws it in --helia-product-accent with the
slant taken off. The side column renders only when aside or media has
something in it, and below 62rem it stacks under the lede.
In MDX the headline goes in a <Fragment> on one line, with a blank line
between it and every slotted child. Bare text on its own line is flow content,
so MDX wraps it in a paragraph inside the heading and pulls the line after it
into the same paragraph, which costs the first action its slot.
data-helia-accent is set on the example itself to show one product’s color on
a page that carries none. A product site sets it once, through the Starlight
plugin’s accent option, and writes no CSS.
The copy here is placeholder, not an approved product claim. The code frame in
the side column holds the dark treatment on either page theme, the way one
inside a contrast Band does, down to the frame’s title and buttons.
<Hero variant="contrast" eyebrow badge summary>
Kernel library
Kernel acceleration for the edge.
Preview
A kernel layer with tuned operators, package delivery, and integration paths for the toolchains a firmware build already uses.
With no side column and no ground, the same part is the lede on its own
measure: a section opener rather than a front door. The lede here is the
summary slot rather than the prop, which is what a claim carrying bold or
inline code needs; the slot wins wherever both are set.
<Hero eyebrow> with the summary slot
Design system
Parts, not pages.
Every part on this page is composed from the same tokens, so a site adopts
the theme rather than a stylesheet: the recipes live in recipes.css
and the site writes none of them.
An API reference is generated, not written, and it is generated for four
languages. The extractors differ, the model they produce does not, and these
parts render the model: the same header, the same table, the same columns for
a Python function, a C function and a TypeScript function. Everything below
comes from one hand-written model in src/lib/reference-gallery-model.ts.
A generated module page carries more symbols than a table of contents will
show, so it indexes itself; a site that builds its own sidebar takes the same
tree as nested links.
RefMembers
profile_modelfunctionRun a model on a connected target.
The rest of the Astro parts, one example each. They are documented in depth on
their own pages; they are here so that one page answers what the package can
draw.
<CodeTabs tabs={[...]} />
const average = total / samples.length;
average = total / len(samples)
Show code
<CodeTabs
ariaLabel="Average latency implementation"
tabs={[
{
label: 'TypeScript',
language: 'typescript',
code: 'const average = total / samples.length;',
},
{
label: 'Python',
language: 'python',
code: 'average = total / len(samples)',
},
]}
/>
<AsciiTerminal lines={[...]} />
Expected output
$npm run buildResolving configuration… ENTRY src/index.ts TARGET es2022 ! no accent color set x missing tsconfig path alias✓ Build complete
$ npm run build
Resolving configuration…
ENTRY src/index.ts
TARGET es2022
! no accent color set
x missing tsconfig path alias
✓ Build complete