npm package: @smoothie-framework/ui-core
Description: Smoothie UI Core - Portable design tokens, types, and utilities
Author: Smoothie Framework
Latest version: 0.0.2

# @smoothie-framework/ui-core

Portable design tokens, types, and utilities for the Smoothie UI ecosystem.

```
+------------------------------------------------------------------+
|                         CONSUMERS                                 |
|  @smoothie-framework/ui  |  @smoothie-framework/ui-react  |  Zig SDK  |  Berry AI       |
+------------------------------------------------------------------+
                              |
                              v
+------------------------------------------------------------------+
|                      @smoothie-framework/ui-core                            |
|  +-------------+  +-------------+  +-------------+  +-----------+ |
|  | tokens/     |  | theme/      |  | recipes/    |  | protocol/ | |
|  | colors      |  | validation  |  | Button      |  | binary    | |
|  | spacing     |  | extension   |  | Input       |  | JSON      | |
|  | typography  |  | resolution  |  | Stack       |  | Zig       | |
|  +-------------+  +-------------+  +-------------+  +-----------+ |
+------------------------------------------------------------------+
```

---

## What is ui-core?

`@smoothie-framework/ui-core` is the **design system foundation layer** for the Smoothie ecosystem. It defines:

| Layer | Purpose | Consumed By |
|-------|---------|-------------|
| **Tokens** | Raw design values (colors, spacing, typography) | All SDKs, all frameworks |
| **Semantic** | Light/dark mode token mappings | Theme providers |
| **Recipes** | Component variant definitions (styling as data) | Component libraries |
| **Theme** | Composition, validation, reference resolution, CSS compilation | Applications |
| **Protocol** | Binary/JSON/Zig exports for cross-SDK sharing | Zig SDK, Rust SDK, Berry AI |
| **CSS** | CSS variable generation, Tailwind preset | DOM-based renderers |

This package has **zero runtime dependencies** and is **framework-agnostic**.

Documentation model note:

- Strategic and requirements docs for the UI toolkit live in `docs/spec/ui-toolkit/`.
- Canonical implementation-aware UI docs live in `docs/architecture/ui-toolkit/`.
- This README is a package guide, not the primary source for UI toolkit strategy.

Important boundary:
- `@smoothie-framework/ui-core` does **not** include runtime reactivity primitives.
- Use `@smoothie-framework/ui` for `signal/computed/effect/batch` and rendering runtime APIs.

---

## Installation

```bash
bun add @smoothie-framework/ui-core
# or
npm install @smoothie-framework/ui-core
```

---

## Import Paths

The package uses subpath exports for optimal tree-shaking:

```typescript
// Essential exports (most common)
import { colors, spacing, defaultTheme } from '@smoothie-framework/ui-core';
import type { Theme, UINode } from '@smoothie-framework/ui-core';

// Specialized imports
import { buttonRecipe, textRecipe } from '@smoothie-framework/ui-core/recipes';
import { toCssVariables, toTailwindPreset } from '@smoothie-framework/ui-core/css';
import { exportTokensBinary } from '@smoothie-framework/ui-core/protocol';
import { extendTheme, validateTheme, compileThemeCss } from '@smoothie-framework/ui-core/theme';
import { lightSemanticColors, darkSemanticColors } from '@smoothie-framework/ui-core/semantic';
```

| Path | Purpose |
|------|---------|
| `@smoothie-framework/ui-core` | Essential tokens, types, theme utilities |
| `@smoothie-framework/ui-core/tokens` | Primitive design tokens only |
| `@smoothie-framework/ui-core/types` | Type definitions only |
| `@smoothie-framework/ui-core/theme` | Theme composition and validation |
| `@smoothie-framework/ui-core/semantic` | Light/dark mode semantic tokens |
| `@smoothie-framework/ui-core/recipes` | Component variant recipes |
| `@smoothie-framework/ui-core/resolve` | Token resolution primitives |
| `@smoothie-framework/ui-core/css` | CSS variable generation, Tailwind |
| `@smoothie-framework/ui-core/protocol` | Cross-SDK binary/JSON exports |
| `@smoothie-framework/ui-core/schemas/component-contracts` | Canonical component ids, aliases, variants, and styling support |
| `@smoothie-framework/ui-core/utils` | Utility functions |

### Export Strategy

- **Root (`@smoothie-framework/ui-core`)**: ergonomic defaults and high-frequency APIs (tokens, `Theme`, `defaultTheme`, core helpers).
- **Subpaths**: canonical source for specialized features (`/recipes`, `/theme`, `/resolve`, `/css`, `/protocol`).
- **Deep paths (`/protocol/infer`, `/schemas/component-schemas`)**: narrow allowlist for advanced/infra usage; prefer subpath indexes for app code.
- **No compatibility aliases in new API**: import specialized protocol/resolve helpers from their canonical subpaths.

---

## Quick Start

### 1. Use Design Tokens

```typescript
import { colors, spacing, typography, radii, shadows } from '@smoothie-framework/ui-core';

const styles = {
  backgroundColor: colors.blue[500],     // '#3b82f6'
  padding: spacing.md,                   // 16
  borderRadius: radii.md,                // 6
  boxShadow: shadows.md,                 // '0 4px 6px -1px ...'
  fontSize: typography.fontSize.md.size, // 16
};
```

### 2. Create a Theme

```typescript
import { defaultTheme, extendTheme } from '@smoothie-framework/ui-core';

// Use default theme
console.log(defaultTheme.colors.blue[500]); // '#3b82f6'

// Extend with custom values
const { theme } = extendTheme({
  colors: {
    brand: '{colors.blue.600}', // Token reference
  },
});
```

### 3. Apply to DOM

```typescript
import { toCssVariables } from '@smoothie-framework/ui-core/css';

const cssVars = toCssVariables(defaultTheme);
Object.assign(document.documentElement.style, cssVars);

// Now use in CSS:
// background: var(--smoothie-colors-blue-500);
```

### 4. Use Component Recipes

```typescript
import { buttonRecipe, resolveRecipe } from '@smoothie-framework/ui-core/recipes';
import { defaultTheme } from '@smoothie-framework/ui-core/theme';

const styles = resolveRecipe(
  buttonRecipe,
  { variant: 'primary', size: 'md' },
  defaultTheme,
  // mode defaults to 'css-variables'
);
// { background: 'var(--smoothie-button-primary-bg)', ... }
```

---

## Common Consumer Paths

### Using ui-core inside another framework

Use `@smoothie-framework/ui-core` when you want Smoothie tokens, recipes, and theme helpers
without adopting the full `@smoothie-framework/ui` runtime.

Useful imports:

| Import | Purpose |
| --- | --- |
| `@smoothie-framework/ui-core` | tokens and core types |
| `@smoothie-framework/ui-core/recipes` | recipe definitions such as `buttonRecipe` |
| `@smoothie-framework/ui-core/theme` | theme extension and validation |
| `@smoothie-framework/ui-core/css` | CSS variable generation and Tailwind preset |
| `@smoothie-framework/ui-core/resolve` | token resolution helpers |

Typical recipe usage:

```typescript
import { buttonRecipe, resolveRecipe } from '@smoothie-framework/ui-core/recipes';
import { defaultTheme } from '@smoothie-framework/ui-core/theme';

const styles = resolveRecipe(buttonRecipe, { variant: 'primary', size: 'md' }, defaultTheme);
```

### Exporting tokens for cross-SDK consumers

Use the protocol exports when another SDK or runtime needs the same token graph.

```typescript
import { defaultTheme } from '@smoothie-framework/ui-core';
import { exportTokensBinary, exportTokensZig } from '@smoothie-framework/ui-core/protocol';

const tokensBin = exportTokensBinary(defaultTheme);
const tokensZig = exportTokensZig(defaultTheme);
```

### Exporting component schema for Berry and tools

Use component schema exports when tools or AI systems need the canonical UI
contract.

```typescript
import { exportComponentSchema, exportComponentSchemaJSON } from '@smoothie-framework/ui-core/protocol';

const schema = exportComponentSchema();
const json = exportComponentSchemaJSON(true);
```

These exports are the canonical bridge from `ui-core` into Berry, editor tooling,
and future cross-SDK consumers.

Use `@smoothie-framework/ui-core/schemas/component-contracts` when adapters,
styling tooling, or conformance tests need canonical runtime component ids,
schema aliases, recipe variants, or styling-support metadata.

---

## Architecture

### Package Structure

```
src/
  tokens/              # Primitive design tokens
    colors.ts            7 palettes x 11 shades = 77 colors
    paths.ts             Canonical token path unions (KnownTokenPath)
    spacing.ts           xs(4) sm(8) md(16) lg(24) xl(32) 2xl(48) 3xl(64)
    typography.ts        Font families, sizes (xs-4xl), weights
    radii.ts             none(0) xs(2) sm(4) md(6) lg(8) xl(12) 2xl(16) full(9999)
    shadows.ts           xs, sm, md, lg, xl, 2xl, 3xl

  semantic/            # Mode-aware semantic tokens
    colors.ts            accent, background, foreground, muted, border, etc.
    modes.ts             Light/dark mode utilities

  recipes/             # Component variant definitions
    button.ts            variant: primary|secondary|ghost|outline|danger
    input.ts             variant: outline|filled|flushed
    stack.ts             direction, gap, align, justify, wrap
    text.ts              size, weight, align, truncate
    types.ts             Recipe<V>, StyleObject, VariantSchema

  theme/               # Theme system
    default.ts           Default theme with all tokens
    extend.ts            extendTheme(), createThemeVariant()
    validate.ts          validateTheme(), assertValidTheme()
    errors.ts            ThemeError, ThemeErrors classes

  resolve/             # Token resolution primitives
    token-map.ts         buildTokenMap()
    resolve.ts           resolveToken(), resolveStyleObject(), resolveDeep()
    css-vars.ts          resolveStyleObjectToCssVars(), tokenPathToCssVar()
    patterns.ts          canonical regex + token detection helpers

  css/                 # CSS generation
    variables.ts         toCssVariables(), getCssVariable()
    tailwind.ts          toTailwindPreset()

  protocol/            # Cross-SDK exports
    export-tokens.ts     exportTokensBinary() -> Uint8Array
    export-schema.ts     exportComponentSchema() -> JSON
    export-zig.ts        exportTokensZig() -> string

  types/               # Type definitions
    layout.ts            SizeToken, SpacingValue, Alignment, Justification
    ui-node.ts           UINode, UINodeProps, UIEvent
    theme.ts             Theme, ThemeTokens, TokenKey
    index.ts             Public barrel for cross-domain contracts

  utils/               # Utilities
    token-helpers.ts     resolveColor, resolveSpacing, etc.
    theme-utils.ts       createTheme, mergeTheme
    guards.ts            isSizeToken, isUINode, etc.
```

### Consumer Matrix

| Consumer | What They Import | Format |
|----------|------------------|--------|
| `@smoothie-framework/ui` | Direct TypeScript imports | .ts |
| `@smoothie-framework/ui-react` | Direct TypeScript imports | .ts |
| Berry AI | Component schema | .json |
| Zig SDK | Token constants, schema | .zig, .bin |
| Rust SDK | Token constants | .rs, .bin |
| Unity C ABI | Token binary | .bin |
| DOM Adapter | CSS variables | .css |
| Tailwind users | Preset config | .js |

### Dependency Graph

```
@smoothie-framework/ui-core (this package - zero dependencies)
         |
         +---> @smoothie-framework/ui (signals, JSX, components)
         |
         +---> @smoothie-framework/ui-react (React adapter)
         +---> @smoothie-framework/ui-vue (Vue adapter)
         +---> @smoothie-framework/ui-svelte (Svelte adapter)
         |
         +---> Berry AI (component generation)
         +---> Zig SDK (native rendering)
```

### Resolution and Styling Pipeline

The current implementation uses a single token-reference pipeline with two output modes:

1. **Recipe merge**: `base + selected variants + compound variants` (`mergeVariants`)
2. **Resolution mode**:
   - `css-variables` (default runtime path): rewrites `{token.path}` -> `var(--smoothie-...)` without building a token map
   - `values` (build-time/SSR path): resolves references to concrete values via `buildTokenMap`
3. **Token precedence** in map-based mode: `theme.tokens` > `recipe.tokens` > primitive tokens

CSS output options:
- **Inline style path**: consumers call `resolveRecipe(...)` and apply resulting style objects
- **External stylesheet path**: `generateRecipeCss` / `generateStylesheet` emit `.smoothie-*` classes
- **Theme variable path**: `toCssVariables(theme)` emits CSS custom properties for primitives and `theme.tokens` aliases

---

## Token Reference

### Colors

5 primitive palettes, each with 11 shades (50-950):

```typescript
colors.blue[500]      // '#3b82f6' - Blue
colors.green[500]     // '#22c55e' - Green
colors.yellow[500]    // '#f59e0b' - Yellow
colors.red[500]       // '#ef4444' - Red
colors.neutral[500]   // '#737373' - Neutral

// Backward-compatible aliases are still accepted in token references:
// {colors.primary.500} -> {colors.blue.500}
```

### Spacing

4px base unit scale:

| Token | Value | Use Case |
|-------|-------|----------|
| `xs` | 4px | Icon padding |
| `sm` | 8px | Tight spacing |
| `md` | 16px | Default padding |
| `lg` | 24px | Section gaps |
| `xl` | 32px | Large gaps |
| `2xl` | 48px | Hero sections |
| `3xl` | 64px | Page margins |

### Typography

```typescript
typography.fontFamily.sans  // 'Inter, system-ui, ...'
typography.fontFamily.mono  // 'JetBrains Mono, ...'

typography.fontSize.md      // { size: 16, lineHeight: 24 }
typography.fontWeight.bold  // 700
```

---

## Theme System

### Token References

Use `{path.to.token}` syntax for theme composition:

```typescript
import { extendTheme } from '@smoothie-framework/ui-core/theme';

const { theme } = extendTheme({
  colors: {
    accent: '{colors.blue.500}',
    background: '{colors.neutral.50}',
  },
}, { resolveRefs: true });

// theme.colors.accent === '#3b82f6' (resolved)
```

### Theme Token Overrides

```typescript
import { defaultTheme, extendTheme } from '@smoothie-framework/ui-core/theme';

const { theme } = extendTheme({
  tokens: {
    ...defaultTheme.tokens,
    'button.primary.bg': '{colors.blue.600}',
    'button.primary.hover.bg': '{colors.blue.700}',
  },
}, { validate: true });
```

### Theme Validation

```typescript
import { validateTheme } from '@smoothie-framework/ui-core/theme';

const result = validateTheme(myTheme);
if (!result.valid) {
  console.error(result.errors);
  // [{ severity: 'error', path: 'colors.x', message: '...' }]
}
```

---

## Recipes

Component recipes define styling as data:

```typescript
import { buttonRecipe, resolveRecipe, type ButtonVariants } from '@smoothie-framework/ui-core/recipes';
import { defaultTheme } from '@smoothie-framework/ui-core/theme';

// Resolve styles for a specific variant combination (runtime path)
function getButtonStyles(variant: ButtonVariants['variant'], size: ButtonVariants['size']) {
  return resolveRecipe(
    buttonRecipe,
    { variant, size },
    defaultTheme,
  );
}
```

Available recipes: `buttonRecipe`, `inputRecipe`, `stackRecipe`, `rowRecipe`, `textRecipe`, `headingRecipe`

---

## CSS Generation

### CSS Variables

```typescript
import { toCssVariables, getCssVariable } from '@smoothie-framework/ui-core/css';

const vars = toCssVariables(theme);
// { '--smoothie-colors-blue-500': '#3b82f6', ... }

const ref = getCssVariable('colors.blue.500');
// 'var(--smoothie-colors-blue-500)'
```

### Tailwind Preset

```typescript
import { toTailwindPreset } from '@smoothie-framework/ui-core/css';

const preset = toTailwindPreset(theme);
// Use in tailwind.config.js: presets: [preset]
```

---

## Protocol Exports

### Binary Export (for native SDKs)

```typescript
import { exportTokensBinary, getTokenExportMetadata } from '@smoothie-framework/ui-core/protocol';

const metadata = getTokenExportMetadata(theme);
// { version: '1.0', colorCount: 77, spacingCount: 7, sizeBytes: 2847 }

const binary = exportTokensBinary(theme);
await fs.writeFile('tokens.bin', binary);
```

### JSON Schema (for Berry AI)

```typescript
import { exportComponentSchemaJSON } from '@smoothie-framework/ui-core/protocol';

const json = exportComponentSchemaJSON();
await fs.writeFile('schema.json', json);
```

### Zig Source (for Zig SDK)

```typescript
import { exportTokensZig } from '@smoothie-framework/ui-core/protocol';

const zigSource = exportTokensZig(theme);
await fs.writeFile('tokens.zig', zigSource);
```

---

## Design Principles

1. **Zero Runtime Dependencies** - Pure TypeScript, no external packages
2. **Framework Agnostic** - Works with React, Vue, Svelte, or vanilla JS
3. **Platform Agnostic** - Values work on DOM, Canvas, or native
4. **Tree-Shakeable** - Subpath exports for minimal bundle size
5. **Type-Safe** - Full TypeScript coverage with strict mode
6. **Cross-SDK** - Exports to TypeScript, Zig, Rust, JSON

---

## Bundle Size

| Module | Size (gzipped) |
|--------|----------------|
| tokens | ~1.5KB |
| theme | ~2KB |
| recipes | ~1KB |
| css | ~0.5KB |
| protocol | ~1.5KB |
| **Total** | **< 8KB** |

---

## Documentation

- [UI package guide](../ui/README.md) - Runtime usage and styling integration
- [Architecture](../../../../docs/architecture/ui-toolkit/packages/ui-core.md) - Technical design
- [PRD](../../../../docs/PRDs/PRD_FW11_UI_Core.md) - Product requirements

---

## License

MIT