npm package: @10up/block-renderer
Description: Generate valid WordPress block markup from JSON - AI-friendly block generation
Latest version: 0.1.10

# @10up/block-renderer

Main package for Block Renderer - generate valid WordPress block markup from AI-friendly JSON structures.

## Installation

```bash
npm install @10up/block-renderer
# or
pnpm add @10up/block-renderer
```

## Overview

This is the unified package that:

1. **Provides a CLI** - Start MCP servers and generate prompts
2. **Re-exports all sub-packages** - Use any functionality with a single import
3. **Includes debug commands** - Generate documentation of your WordPress setup

## The Problem

When AI generates WordPress block markup directly, it often produces invalid output:
- Incorrect HTML comment syntax
- Malformed JSON in attributes
- Missing closing tags
- Invalid nesting

## The Solution

AI generates a constrained JSON structure, and this package renders it to valid WordPress markup using native `@wordpress/blocks` serialization.

```json
{
  "root": "para-1",
  "elements": {
    "para-1": {
      "key": "para-1",
      "type": "core/paragraph",
      "props": { "content": "Hello world" }
    }
  }
}
```

Becomes:

```html
<!-- wp:paragraph -->
<p>Hello world</p>
<!-- /wp:paragraph -->
```

## CLI Usage

### Start MCP Server

For AI assistant integration (Claude, Cursor, etc.):

```bash
# Basic server
block-renderer mcp-server

# With theme (recommended)
block-renderer mcp-server --theme /path/to/theme

# With preferences
block-renderer mcp-server --theme /path/to/theme --preferences ./prefs.json
```

### Generate AI System Prompt

Generate a system prompt for AI assistants:

```bash
# Generate prompt
block-renderer generate-prompt --theme /path/to/theme

# Compact mode for smaller context
block-renderer generate-prompt --theme /path/to/theme --compact

# With preferences
block-renderer generate-prompt --theme /path/to/theme -p ./prefs.json
```

### Debug Commands

Generate markdown documentation of your WordPress setup:

```bash
# First, create a config file in your theme
# .block-renderer/config.json
# { "themePath": "../" }

# Then run from theme directory:
block-renderer debug:tokens       # Lists color, spacing, typography tokens
block-renderer debug:blocks       # Lists all blocks with attributes
block-renderer debug:patterns     # Lists available patterns
block-renderer debug:css-variables  # Lists CSS custom properties
```

Output files are written to `.block-renderer/` directory.

### CLI Options

```
Options:
  -t, --theme <path>        Path to WordPress theme directory
  -p, --preferences <path>  Path to preferences file
  -c, --compact             Use compact output format
  -h, --help                Show help
  -v, --version             Show version
```

## Programmatic Usage

### Render Blocks

```typescript
import {
  setupBrowserEnvironment,
  registerCoreBlocks,
  renderBlockTree
} from '@10up/block-renderer';

// Setup environment (required once)
setupBrowserEnvironment();
await registerCoreBlocks();

// Render a block tree
const tree = {
  root: 'group-1',
  elements: {
    'group-1': {
      key: 'group-1',
      type: 'core/group',
      props: { layout: { type: 'constrained' } },
      children: ['heading-1', 'para-1']
    },
    'heading-1': {
      key: 'heading-1',
      type: 'core/heading',
      props: { content: 'Welcome', level: 2 },
      parentKey: 'group-1'
    },
    'para-1': {
      key: 'para-1',
      type: 'core/paragraph',
      props: { content: 'Hello world!' },
      parentKey: 'group-1'
    }
  }
};

const markup = renderBlockTree(tree);
```

### Validate Trees

```typescript
import { validateTree, parseTheme, loadPatterns } from '@10up/block-renderer';

const theme = parseTheme('/path/to/theme');
const patterns = loadPatterns('/path/to/theme');

const result = validateTree(tree, {
  tokens: theme.tokens,
  patterns
});

if (!result.valid) {
  console.log('Errors:', result.errors);
}
```

### Parse Theme

```typescript
import { parseTheme } from '@10up/block-renderer';

const theme = parseTheme('/path/to/theme');
console.log(theme.tokens.colors.palette);
console.log(theme.tokens.typography.fontSizes);
console.log(theme.tokens.spacing.spacingSizes);
```

### Load Patterns

```typescript
import { loadPatterns } from '@10up/block-renderer';

const patterns = loadPatterns('/path/to/theme');
for (const [slug, pattern] of patterns) {
  console.log(slug, pattern.title);
}
```

### Generate Prompts

```typescript
import { generateSystemPrompt, parseTheme, loadPatterns } from '@10up/block-renderer';

const theme = parseTheme('/path/to/theme');
const patterns = loadPatterns('/path/to/theme');

const prompt = generateSystemPrompt({
  tokens: theme.tokens,
  patterns,
  compact: true
});
```

### Load Preferences

```typescript
import { loadPreferences, formatPreferencesForPrompt } from '@10up/block-renderer';

const prefs = loadPreferences('/path/to/project');
const promptSection = formatPreferencesForPrompt(prefs);
```

## MCP Server Integration

The recommended approach is **per-project configuration**.

### Setup (Recommended)

1. **Create workspace config** in your project root at `.block-renderer/config.json`:

```json
{
  "themePath": "./wp-content/themes/your-theme",
  "ignite": true,
  "prettyPrint": true
}
```

2. **Create MCP client config** for your IDE:

### Cursor IDE

Create `.cursor/mcp.json` in project root:
```json
{
  "mcpServers": {
    "block-renderer": {
      "command": "npx",
      "args": ["@10up/block-renderer-mcp-server"]
    }
  }
}
```

### Claude Code

Create `.claude/settings.json` in project root:
```json
{
  "mcpServers": {
    "block-renderer": {
      "command": "npx",
      "args": ["@10up/block-renderer-mcp-server"]
    }
  }
}
```

### Claude Desktop

Add to global config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
```json
{
  "mcpServers": {
    "block-renderer": {
      "command": "npx",
      "args": [
        "@10up/block-renderer-mcp-server",
        "--config",
        "/absolute/path/to/your/project"
      ]
    }
  }
}
```

The server automatically watches for file changes and reloads theme tokens, patterns, and blocks.

## Re-exports

This package re-exports from all sub-packages:

| Package | Exports |
|---------|---------|
| `@10up/block-renderer-core` | Types: `BlockTree`, `BlockElement`, `BlockDefinition`, etc. |
| `@10up/block-renderer-block-schemas` | `generateBlockDefinition` |
| `@10up/block-renderer-theme-json` | `parseTheme`, `parseThemeJson` |
| `@10up/block-renderer-patterns` | `loadPatterns`, `scanPatterns` |
| `@10up/block-renderer-serializer` | `setupBrowserEnvironment`, `renderBlockTree`, `registerCoreBlocks`, etc. |
| `@10up/block-renderer-validator` | `validateTree`, `createTreeValidator`, etc. |
| `@10up/block-renderer-preferences` | `loadPreferences`, `formatPreferencesForPrompt` |
| `@10up/block-renderer-prompt-generator` | `generateSystemPrompt`, `generateMinimalPrompt` |

## Block Tree Format

The JSON format uses a flat structure with key references:

```typescript
interface BlockTree {
  root: string;                           // Key of root element
  elements: Record<string, BlockElement>; // Map of key -> element
}

interface BlockElement {
  key: string;                    // Unique identifier
  type: string;                   // Block name, e.g., "core/paragraph"
  props: Record<string, unknown>; // Block attributes
  children?: string[];            // Keys of child elements
  parentKey?: string;             // Key of parent element
}
```

### Why Flat Structure?

1. **Easier for AI to generate** - No deep nesting means fewer bracket-matching errors
2. **Easier to validate** - Each element can be validated independently
3. **Easier to reference** - Elements can reference siblings without knowing the full tree

## Design Tokens

Use WordPress design token syntax for theme-aware values:

```json
{
  "type": "core/group",
  "props": {
    "backgroundColor": "primary",
    "style": {
      "color": { "text": "var:preset|color|contrast" },
      "spacing": { "padding": { "top": "var:preset|spacing|50" } }
    }
  }
}
```

### Token Formats

| Format | Example | Use Case |
|--------|---------|----------|
| Slug only | `"primary"` | Direct attributes like `backgroundColor` |
| CSS var reference | `"var:preset\|color\|primary"` | Inside `style` object |

## Common Block Examples

### Paragraph with Styling

```json
{
  "root": "para",
  "elements": {
    "para": {
      "key": "para",
      "type": "core/paragraph",
      "props": {
        "content": "Styled paragraph text",
        "fontSize": "large",
        "textColor": "primary"
      }
    }
  }
}
```

### Columns Layout

```json
{
  "root": "cols",
  "elements": {
    "cols": {
      "key": "cols",
      "type": "core/columns",
      "children": ["col1", "col2"]
    },
    "col1": {
      "key": "col1",
      "type": "core/column",
      "props": { "width": "66.66%" },
      "children": ["content"],
      "parentKey": "cols"
    },
    "col2": {
      "key": "col2",
      "type": "core/column",
      "props": { "width": "33.33%" },
      "children": ["sidebar"],
      "parentKey": "cols"
    },
    "content": {
      "key": "content",
      "type": "core/paragraph",
      "props": { "content": "Main content" },
      "parentKey": "col1"
    },
    "sidebar": {
      "key": "sidebar",
      "type": "core/paragraph",
      "props": { "content": "Sidebar" },
      "parentKey": "col2"
    }
  }
}
```

### Using a Pattern

```json
{
  "root": "pattern",
  "elements": {
    "pattern": {
      "key": "pattern",
      "type": "core/pattern",
      "props": { "slug": "theme/hero-section" }
    }
  }
}
```

## License

MIT