Every component. Every state. Your real CSS.

Zandbox is a component lab for Bun + HTMX projects. Every component, in every state, on its own stage — styled by the CSS your app actually ships, so what you see here is what your users get. No build step, no rendering library, no second design system to keep in sync.

Get started bun run ~/zandbox/engine/cli.ts init

Dev-only. Binds 127.0.0.1, ships nowhere near production.

Klectr the Alien playing in a sandbox, building a sandcastle out of UI components

This lab built Zimer's interface: 60 stories, 13 groups, 20 tokens from its DESIGN.md — every screen checked here before it shipped.

How it works

Your components never know Zandbox exists. A story is a thin file that renders one component in a given state; a single config file gathers the stories and maps your assets. The engine — one small Bun server — does the rest.

01

Write a story

One .stories.ts file per component: the component, its states, fictional data. Kept apart from the component, Storybook-style.

02

Register it once

zandbox.config.ts gathers your story arrays, maps your stylesheet, and points at your DESIGN.md if you keep one.

03

Browse the lab

bun run zandbox — the terminal names any story that fails to render; then pick a story in the sidebar and see it alone on the stage. Filter as you type; every story has a shareable URL.

Built for how Bun + HTMX projects actually work

Four things a lab owes you when your components are server functions, not framework components.

Catch a broken state before your users do

At startup the lab renders every story once and names the ones that throw — in your terminal, before you open the browser. The state you would have found by clicking is the state it reports.

What you see is what ships

The lab serves your stylesheet as-is, and your components return the same HTML here that they return in the app. There is no preview layer to drift from production.

Your spec, rendered

Point designMd at your DESIGN.md and every color token becomes a swatch story. When the spec and the screen disagree, you can see it — and so can anyone reviewing the change.

Any component, seconds away

Filter the sidebar as you type, open a story's bare canvas, share its URL with a reviewer. Stories are files in git next to the components — not rows in a database, not a second codebase.

The terminal tells you the truth at startup

A real Zandbox boot, on loop. This is the whole startup output — nothing is summarized away.

Zandbox · engine 0.1.0
→ http://127.0.0.1:8935
Stories: 60 in 13 groups
Assets: /static/style.css → site/static/style.css
Tokens: 20 colors from DESIGN.md
Render check: all 60 stories render

Why not Storybook?

A fair question — it is the default. The answer is shape.

Storybook's shape

Framework components rendered through a bundler build: JSX or a framework renderer, a config of addons, a second build to keep green. Superb — if your project already has that machinery.

Zandbox's shape

One Bun server and one config file. Your components already return HTML strings; your CSS already exists. There is nothing to compile and nothing new to adopt.

Honestly: if you ship React or Vue with a bundler in the project, Storybook is the right tool and this page is not for you. If your components are functions that return HTML, there is nothing for Storybook to render — and Zandbox starts exactly there.

Questions, answered

Does it work with React or Vue components?

No. Zandbox renders components that return HTML strings — server templates and Web Components. Framework components belong in Storybook.

Can any of this reach production?

No. The engine lives in a hidden .zandbox/ folder, binds 127.0.0.1 only, and renders fictional data. It is a development tool by construction, not by configuration.

How do I update the engine?

Delete .zandbox/ and re-run init. Your config, your stories, and your components are never touched — they were never the engine's.

What does it cost?

Nothing. MIT licensed, source on GitHub, built on Bun.

Get started

Clone Zandbox once, run init inside your project, start the lab. About five minutes, most of it the clone.

# 1 — clone Zandbox (once, park it anywhere) git clone https://github.com/Klectr/zandbox ~/zandbox # 2 — initialize your project cd ~/your-project bun run ~/zandbox/engine/cli.ts init # 3 — start the lab bun run zandbox → http://127.0.0.1:8935