Skip to content

Scaffolding charts & components

Data slides shouldn’t start from a blank file. liebstoeckel add scaffolds ready-made charts and building blocks straight into your deck, as source you own rather than a package you import. It’s the shadcn model: the code lands in your project, and from there it’s yours to edit.

Terminal window
liebstoeckel add bar-chart # → charts/BarChart.tsx + its helper, deps installed

A scaffolded item is copied into your deck. There is no @liebstoeckel/charts package to import from and no version to track. add writes real .tsx files into your charts/ directory, and you change the data, palette, layout, or motion however you like. Nothing upstream can override your edits.

What is a dependency is the underlying drawing library: charts are built on visx, so add installs the specific @visx/* packages an item needs into your deck, exactly like shadcn adds Radix. You own the chart; visx is a normal npm dep you can see in package.json.

add always prints its plan before touching disk: every file it will create, overwrite, or skip, plus the dependencies it will install. Then it writes:

$ liebstoeckel add bar-chart
liebstoeckel add use-brand-colors, bar-chart → /path/to/deck
create charts/useBrandColors.ts [use-brand-colors]
create charts/BarChart.tsx [bar-chart]
dependencies: @visx/axis, @visx/grid, @visx/group, @visx/scale, @visx/shape
✓ wrote 2 file(s)
installing: bun add --ignore-scripts @visx/axis @visx/grid @visx/group @visx/scale @visx/shape
✓ dependencies installed

Note the second file you didn’t ask for: bar-chart declares a registry dependency on use-brand-colors, so add resolves the graph and scaffolds the helper too (dependencies first, de-duplicated). Run add again for another chart that shares the helper and it’s reported as skip (exists); your copy is left untouched.

Use the chart in a slide like any component:

slides/03-metrics.tsx
import { BarChart } from "../charts/BarChart";
export default function Metrics() {
return <BarChart data={[{ label: "Q1", value: 128 }, { label: "Q2", value: 174 }]} />;
}

Charts read the active brand’s palette through the scaffolded useBrandColors hook, so they pick up your deck’s theme automatically (no color props required).

The bundled @liebstoeckel registry ships a visx gallery plus a few building blocks:

ItemTypeWhat it is
bar-chart, horizontal-bar-chart, grouped-bar-chart, stacked-bar-chartchartbar families with axes, gridlines, value labels, staggered rise-in
line-chart, area-chart, sparklinecharttrends: full axes, or a compact inline spark
scatter-plot, heatmapchartpoint clouds and grids
donut-chart, radar-chart, radial-bar-chartchartradial: donut, spider, radial bars
treemapchartsized hierarchy
hello-chartcharta minimal starter to copy from
use-brand-colorshookreads the brand chart palette from CSS vars (no flash)
brand-axiselementbrand-styled @visx/axis wrappers
legendelementa small brand-styled legend

A leading category word is optional sugar, and you can scaffold several at once:

Terminal window
liebstoeckel add chart bar-chart line-chart donut-chart

Categories are chart, hook, element, component, layout, motion.

Terminal window
liebstoeckel add [<category>] <name>... [--dir <deck>] [--dry] [--force] [--no-install]
FlagMeaning
--dir <deck>target deck directory (default: current directory)
--dryprint the plan and stop: write nothing, install nothing
--forceoverwrite files that already exist (default: skip them)
--no-installscaffold the files but don’t run bun add for their deps

Dependencies install with bun add --ignore-scripts. Lifecycle scripts are off by design, since registry items may come from third parties. With --no-install, add prints the exact bun add line for you to run yourself.

A bare name (bar-chart) resolves from the bundled @liebstoeckel registry. A scoped ref resolves from a registry you map in the deck’s liebstoeckel.json:

liebstoeckel.json
{
"registries": {
"@acme": "./design-system/registry" // a local path…
}
}
Terminal window
liebstoeckel add @acme/heatmap

Today a registry maps to the built-in "default", a local path, or an authenticated HTTP(S) base URL; npm and git transports are planned. A third-party registry is just a directory (or, later, a package) with an items/<name>.json manifest pointing at the source files to copy, so anyone can publish reusable building blocks, and add materializes them the same way: as owned source in your deck.

Comments

liebstoeckel

Code-first presentations your agent can author. One file out, no server.

© 2026 Leon Kaucher