I shipped Crucible v1.0 today. It's a code generation engine — you run a CLI command, it writes production-ready component source files into your project, and then it disappears. Zero runtime footprint. You own every line.
npx crucible add Button
# writes Button/Button.tsx, Button/Button.module.css,
# Button/Button.types.ts, Button/README.md
# into your project. yours forever.
I built it because I kept running into the ceiling of what component libraries let you do — and I wanted to see what the "no library, just code" model looked like taken further than copy-paste snippets.
Here's how it works.
The five-layer pipeline
crucible.config.json
→ Config Layer read + validate with ajv
→ Token Resolver CSS custom props + OKLCH dark mode derivation
→ Component Model normalised IR for templates
→ Template Engine Handlebars, strictly logic-free
→ File Writer hash protection + Prettier formatting
The IR (intermediate representation) layer is the decision I'm happiest with. Without it, templates become conditional nightmares — {{#if angular}}, {{#if dark}}, {{#if compoundComponents}}. With it, all that logic lives in TypeScript where it can be typed and tested. Templates become pure interpolation.
Templates are audited on every build. Comparisons, ternaries, and else-if chains are prohibited at the .hbs level. npm run audit:templates runs as a prebuild hook and fails the build on any violation.
Token resolution
Tokens deep-merge with your chosen preset. Set only what you want to change:
{
"theme": "minimal",
"tokens": {
"color": { "primary": "#FF6B6B" }
}
}
Only primary changes. The rest of the minimal preset — radius, typography, backgrounds — is untouched.
Everything resolves to CSS custom properties. No mode ever hard-codes a hex value:
:root {
--color-primary: #FF6B6B;
--radius-md: 8px;
--spacing-unit: 4px;
}
OKLCH dark mode
Dark tokens are derived in OKLCH, not HSL.
HSL lightness shifts change perceived hue — blue can drift toward cyan, purple toward gray-purple. OKLCH is perceptually uniform: lightness changes without hue drift.
{ "darkMode": { "strategy": "auto" } }
That's the whole config. Crucible derives the full dark palette automatically and emits it as [data-theme="dark"] CSS vars alongside the light :root block.
Manual override is also supported for specific tokens.
Framework output
Three frameworks, three style systems — parallel template folders, no {{#if framework}} anywhere in the templates themselves:
| Framework | Patterns used |
|---|---|
| React 18+ | Hooks, CSS Modules, compound components (static property pattern) |
| Vue 3.4+ | Composition API, <script setup>, named slots |
| Angular 17+ | Standalone components, @if/@for, ng-content
|
Style systems: css (CSS Modules), scss (SCSS Modules), tailwind (Tailwind v4 with CSS variable arbitrary values).
Adding a new framework means adding a template folder — nothing in the engine changes.
Hash-based overwrite protection
Every generated file gets a content hash stored in .crucible/manifest.json. On re-generation:
- Hash matches → overwrite (file is unchanged from generated output)
- Hash differs → warn and skip (you've edited it; Crucible leaves it alone)
-
--force→ overwrite regardless -
--dry-run→ print what would happen, write nothing
The manifest key includes the component subfolder name (Button/Button.tsx) to prevent collisions across components.
CLI
crucible init # scaffold crucible.config.json
crucible add Button # generate one component
crucible add -a # generate all components
crucible add Button --stories # with Storybook stories
crucible eject # copy preset tokens into config for full manual control
crucible tokens # regenerate tokens.css only
crucible doctor # check Node version, config validity, framework install
crucible config # print resolved config
crucible clean # remove generated files
All commands have short aliases: a, i, d, t, e, l, c, cfg.
Components in v1.0
Button · Input · Card · Dialog · Select
Each one: full variant/size/state matrix, TypeScript types, compound components (React) / named slots (Vue) / ng-content (Angular), WCAG 2.1 AA accessibility, auto-generated README.
Test coverage
230 unit tests, 24 test files, 19 E2E phases.
E2E phases cover every framework × style-system combination (React/Vue/Angular × CSS/SCSS/Tailwind = 9 phases), plus write protection scenarios, batch generation, theme presets, custom output directories, and all CLI commands. Each phase runs in an isolated temp directory.
Repo
github.com/Naveen2070/project_crucible — MIT, open from day one.
Good first contributions: Textarea, Badge, Checkbox. The pattern is: add to src/registry/manifests/defaults.ts, create template files in the right framework folders, run the test suite. The engine discovers new components automatically.
Happy to go deep on any of the architecture decisions in the comments.
Top comments (0)