@smile-design/design-engine
v0.1.0
Published
Design intelligence engine for smile-design — DESIGN.md ↔ Tailwind v4 token round-trip, design-system presets, aesthetic checks (contrast / typography / spacing / alignment), and the Harness hook bus consumed by smile-design Web UI / MCP Server / preview-
Maintainers
Readme
@smile-design/design-engine
Design intelligence engine for smile-design — DESIGN.md ↔ Tailwind v4 token round-trip, ready-to-apply design-system presets, aesthetic checks (contrast / typography / spacing / alignment), and the Harness hook bus consumed by @smile-design/mcp-server, @smile-design/preview-server, and the smile-design Web UI.
This package is the design-knowledge layer of smile-design. End users typically reach it transitively through @smile-design/mcp-server (Claude Code subprocess) or the desktop app, but the engines are exported as a standalone library for anyone who wants to programmatically read DESIGN.md, write Tailwind v4 @theme blocks, or run aesthetic checks.
Install
pnpm add @smile-design/design-engineSubpath exports
| Specifier | Use |
| ------------------------------------------------------- | ----------------------------------------------------------------------- |
| @smile-design/design-engine | Type-only barrel (avoid bundle leak — use a subpath instead) |
| @smile-design/design-engine/design-md | DESIGN.md AST parser, writer, and compileDesignMd token compiler |
| @smile-design/design-engine/tailwind | Tailwind v4 @theme reader / writer (round-trip with DESIGN.md) |
| @smile-design/design-engine/presets | Built-in corporate / default-minimalist design systems registry |
| @smile-design/design-engine/guides | Aesthetic guide renderers (Markdown → system prompt fragments) |
| @smile-design/design-engine/aesthetics | Static aesthetic checks (contrast / typography on globals.css only) |
| @smile-design/design-engine/aesthetics/dynamic-sample | Playwright-backed sampling for spacing / alignment checks |
| @smile-design/design-engine/harness/hooks | HookBus event types and helpers (no Playwright in dependency closure) |
The package barrel (@smile-design/design-engine) deliberately exports only types so consumers cannot accidentally pull playwright or DOM globals through transitive re-exports — always import via a subpath.
Use
Read & write DESIGN.md
import {
parseDesignMd,
writeDesignMd,
compileDesignMd,
} from '@smile-design/design-engine/design-md';
const ast = parseDesignMd(fs.readFileSync('DESIGN.md', 'utf-8'));
const tokens = compileDesignMd(ast); // → DesignTokenSet
const md = writeDesignMd(ast); // round-tripRound-trip with Tailwind v4 @theme
import { readTailwindTheme, writeTailwindTheme } from '@smile-design/design-engine/tailwind';
const tokens = readTailwindTheme(fs.readFileSync('app/globals.css', 'utf-8'));
const css = writeTailwindTheme(tokens, { layout: 'theme-inline' });Apply a built-in design-system preset
import { listPresets, loadPresetSource } from '@smile-design/design-engine/presets';
const names = await listPresets(); // → ['corporate', 'default-minimalist']
const designMd = await loadPresetSource('corporate'); // raw DESIGN.md textThe presets ship inside the package (templates/design-systems/<name>/), so no monorepo layout assumption is required at runtime.
Run aesthetic checks (static)
import { runStaticChecks } from '@smile-design/design-engine/aesthetics';
const report = runStaticChecks({
globalsCss: fs.readFileSync('app/globals.css', 'utf-8'),
});
// report: { issues: AestheticIssue[], summary: { errors, warnings, info } }For dynamic checks (spacing rhythm, alignment) that require sampling rendered DOM, use aesthetics/dynamic-sample — it spawns a headless Playwright browser and is server-only.
Subscribe to Harness events
import { getHookBus, registerBuiltInHooks } from '@smile-design/design-engine/harness/hooks';
registerBuiltInHooks();
const bus = getHookBus();
bus.on('on-preview-error', (ev) => {
console.warn('preview error →', ev.reason, ev.detail);
});harness/hooks is the narrowest subpath that does not drag playwright into a consumer's bundle — Web UI client code that just needs to emit / listen to events should always import from this path.
Built-in presets
| Name | Aesthetic | Source |
| -------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------- |
| default-minimalist | Restrained Helvetica + neutral palette (smile-design default for new projects) | templates/design-systems/default-minimalist/ |
| corporate | Bolder type, accent blue, larger spacing scale | templates/design-systems/corporate/ |
Each preset is { DESIGN.md, tokens.compiled.json, globals.css.template } — loadPresetSource(name) returns the DESIGN.md, loadPreset(name) returns the precompiled DesignTokenSet for fast token consumption without parsing.
Requirements
- Node.js ≥ 22 (LTS)
- TypeScript ≥ 5.4 (consumers)
- For the
aesthetics/dynamic-samplesubpath: a Chromium download vianpx playwright install chromium
License
MIT
