multi-surface-render
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMulti-Surface Rendering with json-render
基于json-render的多表面渲染
Define once, render everywhere. A single json-render catalog and spec can produce React web UIs, PDF reports, HTML emails, Remotion demo videos, and OG images — each surface gets its own registry that maps catalog types to platform-native components.
一次定义,随处渲染。单个json-render目录与规范可生成React网页UI、PDF报告、HTML邮件、Remotion演示视频以及OG图片——每个渲染表面都有专属注册表,用于将目录类型映射为平台原生组件。
Quick Reference
速查参考
| Category | Rules | Impact | When to Use |
|---|---|---|---|
| Target Selection | 1 | HIGH | Choosing which renderer for your use case |
| React Renderer | 1 | MEDIUM | Web apps, SPAs, dashboards |
| PDF & Email Renderer | 1 | HIGH | Reports, documents, notifications |
| Video & Image Renderer | 1 | MEDIUM | Demo videos, OG images, social cards |
| Registry Mapping | 1 | HIGH | Platform-specific component implementations |
Total: 5 rules across 5 categories
| 分类 | 规则数 | 影响级别 | 使用场景 |
|---|---|---|---|
| 目标选择 | 1 | 高 | 为你的使用场景选择合适的渲染器 |
| React渲染器 | 1 | 中 | 网页应用、单页应用、仪表盘 |
| PDF & 邮件渲染器 | 1 | 高 | 报告、文档、通知 |
| 视频 & 图片渲染器 | 1 | 中 | 演示视频、OG图片、社交卡片 |
| 注册表映射 | 1 | 高 | 平台专属组件实现 |
总计:5个分类下共5条规则
How Multi-Surface Rendering Works
多表面渲染的工作原理
- One catalog — Zod-typed component definitions shared across all surfaces
- One spec — flat-tree JSON/YAML describing the UI structure
- Many registries — each surface maps catalog types to its own component implementations
- Many renderers — each package renders the spec using its registry
The catalog is the contract. The spec is the data. The registry is the platform-specific implementation.
- 一个目录 —— 所有渲染表面共享的Zod类型化组件定义
- 一个规范 —— 描述UI结构的扁平树状JSON/YAML
- 多个注册表 —— 每个渲染表面将目录类型映射为自身的组件实现
- 多个渲染器 —— 每个包使用对应的注册表渲染规范
目录是契约,规范是数据,注册表是平台专属实现。
Quick Start — Same Catalog, Different Renderers
快速入门 —— 同一目录,不同渲染器
Shared Catalog (used by all surfaces)
共享目录(所有表面通用)
typescript
import { defineCatalog } from '@json-render/core'
import { z } from 'zod'
export const catalog = defineCatalog({
Heading: {
props: z.object({
text: z.string(),
level: z.enum(['h1', 'h2', 'h3']),
}),
children: false,
},
Paragraph: {
props: z.object({ text: z.string() }),
children: false,
},
StatCard: {
props: z.object({
label: z.string(),
value: z.string(),
trend: z.enum(['up', 'down', 'flat']).optional(),
}),
children: false,
},
})typescript
import { defineCatalog } from '@json-render/core'
import { z } from 'zod'
export const catalog = defineCatalog({
Heading: {
props: z.object({
text: z.string(),
level: z.enum(['h1', 'h2', 'h3']),
}),
children: false,
},
Paragraph: {
props: z.object({ text: z.string() }),
children: false,
},
StatCard: {
props: z.object({
label: z.string(),
value: z.string(),
trend: z.enum(['up', 'down', 'flat']).optional(),
}),
children: false,
},
})Render to Web (React)
渲染为网页(React)
tsx
import { Renderer } from '@json-render/react'
import { catalog } from './catalog'
import { webRegistry } from './registries/web'
export const Dashboard = ({ spec }) => (
<Renderer spec={spec} catalog={catalog} registry={webRegistry} />
)tsx
import { Renderer } from '@json-render/react'
import { catalog } from './catalog'
import { webRegistry } from './registries/web'
export const Dashboard = ({ spec }) => (
<Renderer spec={spec} catalog={catalog} registry={webRegistry} />
)Render to PDF
渲染为PDF
typescript
import { renderToBuffer, renderToFile } from '@json-render/react-pdf'
import { catalog } from './catalog'
import { pdfRegistry } from './registries/pdf'
// Buffer for HTTP response
const buffer = await renderToBuffer(spec, { catalog, registry: pdfRegistry })
// Direct file output
await renderToFile(spec, './output/report.pdf', { catalog, registry: pdfRegistry })typescript
import { renderToBuffer, renderToFile } from '@json-render/react-pdf'
import { catalog } from './catalog'
import { pdfRegistry } from './registries/pdf'
// 用于HTTP响应的Buffer
const buffer = await renderToBuffer(spec, { catalog, registry: pdfRegistry })
// 直接输出到文件
await renderToFile(spec, './output/report.pdf', { catalog, registry: pdfRegistry })Render to Email
渲染为邮件
typescript
import { renderToHtml } from '@json-render/react-email'
import { catalog } from './catalog'
import { emailRegistry } from './registries/email'
const html = await renderToHtml(spec, { catalog, registry: emailRegistry })
await sendEmail({ to: user.email, subject: 'Weekly Report', html })typescript
import { renderToHtml } from '@json-render/react-email'
import { catalog } from './catalog'
import { emailRegistry } from './registries/email'
const html = await renderToHtml(spec, { catalog, registry: emailRegistry })
await sendEmail({ to: user.email, subject: 'Weekly Report', html })Render to OG Image (Satori)
渲染为OG图片(Satori)
typescript
import { renderToSvg, renderToPng } from '@json-render/image'
import { catalog } from './catalog'
import { imageRegistry } from './registries/image'
const png = await renderToPng(spec, {
catalog,
registry: imageRegistry,
width: 1200,
height: 630,
})typescript
import { renderToSvg, renderToPng } from '@json-render/image'
import { catalog } from './catalog'
import { imageRegistry } from './registries/image'
const png = await renderToPng(spec, {
catalog,
registry: imageRegistry,
width: 1200,
height: 630,
})Render to Video (Remotion)
渲染为视频(Remotion)
tsx
import { JsonRenderComposition } from '@json-render/remotion'
import { catalog } from './catalog'
import { remotionRegistry } from './registries/remotion'
export const DemoVideo = () => (
<JsonRenderComposition
spec={spec}
catalog={catalog}
registry={remotionRegistry}
fps={30}
durationInFrames={150}
/>
)tsx
import { JsonRenderComposition } from '@json-render/remotion'
import { catalog } from './catalog'
import { remotionRegistry } from './registries/remotion'
export const DemoVideo = () => (
<JsonRenderComposition
spec={spec}
catalog={catalog}
registry={remotionRegistry}
fps={30}
durationInFrames={150}
/>
)Decision Matrix — When to Use Each Target
决策矩阵 —— 何时使用各渲染目标
| Target | Package | When to Use | Output |
|---|---|---|---|
| React | | Web apps, SPAs | JSX |
| Vue | | Vue projects | Vue components |
| Svelte | | Svelte projects | Svelte components |
| React Native | | Mobile apps (25+ components) | Native views |
| Reports, documents | PDF buffer/file | |
| Notifications, digests | HTML string | |
| Remotion | | Demo videos, marketing | MP4/WebM |
| Image | | OG images, social cards | SVG/PNG (Satori) |
| YAML | | Token optimization | YAML string |
| MCP | | Claude/Cursor conversations | Sandboxed iframe |
| 3D | | 3D scenes (19 components) | Three.js canvas |
| Codegen | | Source code from specs | TypeScript/JSX |
Load for detailed selection criteria and trade-offs.
rules/target-selection.md| 目标 | 包 | 使用场景 | 输出格式 |
|---|---|---|---|
| React | | 网页应用、单页应用 | JSX |
| Vue | | Vue项目 | Vue组件 |
| Svelte | | Svelte项目 | Svelte组件 |
| React Native | | 移动应用(25+组件) | 原生视图 |
| 报告、文档 | PDF Buffer/文件 | |
| 通知、摘要 | HTML字符串 | |
| Remotion | | 演示视频、营销视频 | MP4/WebM |
| Image | | OG图片、社交卡片 | SVG/PNG(基于Satori) |
| YAML | | 令牌优化 | YAML字符串 |
| MCP | | Claude/Cursor对话 | 沙箱化iframe |
| 3D | | 3D场景(19个组件) | Three.js画布 |
| 代码生成 | | 从规范生成源代码 | TypeScript/JSX |
加载查看详细的选择标准与权衡。
rules/target-selection.mdPDF Renderer — Reports and Documents
PDF渲染器 —— 报告与文档
The package renders specs to PDF using react-pdf under the hood. Three output modes: buffer, file, and stream.
@json-render/react-pdftypescript
import { renderToBuffer, renderToFile, renderToStream } from '@json-render/react-pdf'
// In-memory buffer (for HTTP responses, S3 upload)
const buffer = await renderToBuffer(spec, { catalog, registry: pdfRegistry })
res.setHeader('Content-Type', 'application/pdf')
res.send(buffer)
// Direct file write
await renderToFile(spec, './output/report.pdf', { catalog, registry: pdfRegistry })
// Streaming (for large documents)
const stream = await renderToStream(spec, { catalog, registry: pdfRegistry })
stream.pipe(res)Load for PDF registry patterns and email rendering.
rules/pdf-email-renderer.md@json-render/react-pdftypescript
import { renderToBuffer, renderToFile, renderToStream } from '@json-render/react-pdf'
// 内存中的Buffer(用于HTTP响应、S3上传)
const buffer = await renderToBuffer(spec, { catalog, registry: pdfRegistry })
res.setHeader('Content-Type', 'application/pdf')
res.send(buffer)
// 直接写入文件
await renderToFile(spec, './output/report.pdf', { catalog, registry: pdfRegistry })
// 流式输出(适用于大型文档)
const stream = await renderToStream(spec, { catalog, registry: pdfRegistry })
stream.pipe(res)加载查看PDF注册表模式与邮件渲染内容。
rules/pdf-email-renderer.mdImage Renderer — OG Images and Social Cards
图片渲染器 —— OG图片与社交卡片
The package uses Satori to convert specs to SVG, then optionally to PNG. Designed for server-side generation of social media images.
@json-render/imagetypescript
import { renderToSvg, renderToPng } from '@json-render/image'
// SVG output (smaller, scalable)
const svg = await renderToSvg(spec, {
catalog,
registry: imageRegistry,
width: 1200,
height: 630,
})
// PNG output (universal compatibility)
const png = await renderToPng(spec, {
catalog,
registry: imageRegistry,
width: 1200,
height: 630,
})Load for Satori constraints and Remotion composition patterns.
rules/video-image-renderer.md@json-render/imagetypescript
import { renderToSvg, renderToPng } from '@json-render/image'
// SVG输出(体积更小、可缩放)
const svg = await renderToSvg(spec, {
catalog,
registry: imageRegistry,
width: 1200,
height: 630,
})
// PNG输出(兼容性强)
const png = await renderToPng(spec, {
catalog,
registry: imageRegistry,
width: 1200,
height: 630,
})加载查看Satori的限制与Remotion合成模式。
rules/video-image-renderer.mdRegistry Mapping — Same Catalog, Platform-Specific Components
注册表映射 —— 同一目录,平台专属组件
Each surface needs its own registry. The registry maps catalog types to platform-specific component implementations while the catalog and spec stay identical.
typescript
// Web registry — uses HTML elements
const webRegistry = {
Heading: ({ text, level }) => {
const Tag = level // h1, h2, h3
return <Tag className="font-bold">{text}</Tag>
},
StatCard: ({ label, value, trend }) => (
<div className="rounded border p-4">
<span className="text-sm text-gray-500">{label}</span>
<strong className="text-2xl">{value}</strong>
</div>
),
}
// PDF registry — uses react-pdf primitives
import { Text, View } from '@react-pdf/renderer'
const pdfRegistry = {
Heading: ({ text, level }) => (
<Text style={{ fontSize: level === 'h1' ? 24 : level === 'h2' ? 18 : 14 }}>
{text}
</Text>
),
StatCard: ({ label, value }) => (
<View style={{ border: '1pt solid #ccc', padding: 8 }}>
<Text style={{ fontSize: 10, color: '#666' }}>{label}</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>{value}</Text>
</View>
),
}Load for registry creation patterns and type safety.
rules/registry-mapping.md每个渲染表面需要专属注册表。注册表将目录类型映射为平台专属组件实现,而目录与规范保持一致。
typescript
// 网页注册表 —— 使用HTML元素
const webRegistry = {
Heading: ({ text, level }) => {
const Tag = level // h1, h2, h3
return <Tag className="font-bold">{text}</Tag>
},
StatCard: ({ label, value, trend }) => (
<div className="rounded border p-4">
<span className="text-sm text-gray-500">{label}</span>
<strong className="text-2xl">{value}</strong>
</div>
),
}
// PDF注册表 —— 使用react-pdf原语
import { Text, View } from '@react-pdf/renderer'
const pdfRegistry = {
Heading: ({ text, level }) => (
<Text style={{ fontSize: level === 'h1' ? 24 : level === 'h2' ? 18 : 14 }}>
{text}
</Text>
),
StatCard: ({ label, value }) => (
<View style={{ border: '1pt solid #ccc', padding: 8 }}>
<Text style={{ fontSize: 10, color: '#666' }}>{label}</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>{value}</Text>
</View>
),
}加载查看注册表创建模式与类型安全。
rules/registry-mapping.mdRule Details
规则详情
Target Selection
目标选择
Decision criteria for choosing the right renderer target.
| Rule | File | Key Pattern |
|---|---|---|
| Target Selection | | Use case mapping, output format constraints |
选择合适渲染目标的决策标准。
| 规则 | 文件 | 核心模式 |
|---|---|---|
| 目标选择 | | 用例映射、输出格式约束 |
React Renderer
React渲染器
Web rendering with the component.
<Renderer>| Rule | File | Key Pattern |
|---|---|---|
| React Renderer | | |
使用组件进行网页渲染。
<Renderer>| 规则 | 文件 | 核心模式 |
|---|---|---|
| React渲染器 | | |
PDF & Email Renderer
PDF & 邮件渲染器
Server-side rendering to PDF buffers/files and HTML email strings.
| Rule | File | Key Pattern |
|---|---|---|
| PDF & Email | | renderToBuffer, renderToFile, renderToHtml |
服务端渲染为PDF Buffer/文件与HTML邮件字符串。
| 规则 | 文件 | 核心模式 |
|---|---|---|
| PDF & 邮件 | | renderToBuffer、renderToFile、renderToHtml |
Video & Image Renderer
视频 & 图片渲染器
Remotion compositions and Satori image generation.
| Rule | File | Key Pattern |
|---|---|---|
| Video & Image | | JsonRenderComposition, renderToPng, renderToSvg |
Remotion合成与Satori图片生成。
| 规则 | 文件 | 核心模式 |
|---|---|---|
| 视频 & 图片 | | JsonRenderComposition、renderToPng、renderToSvg |
Registry Mapping
注册表映射
Creating platform-specific registries for a shared catalog.
| Rule | File | Key Pattern |
|---|---|---|
| Registry Mapping | | Per-platform registries, type-safe mapping |
为共享目录创建平台专属注册表。
| 规则 | 文件 | 核心模式 |
|---|---|---|
| 注册表映射 | | 按平台划分的注册表、类型安全映射 |
Key Decisions
关键决策
| Decision | Recommendation |
|---|---|
| PDF library | Use |
| Email rendering | Use |
| OG images | Use |
| Video | Use |
| Registry per platform | Always separate registries; never one registry for all surfaces |
| Catalog sharing | One catalog definition shared via import across all registries |
| 决策 | 推荐方案 |
|---|---|
| PDF库 | 使用 |
| 邮件渲染 | 使用 |
| OG图片 | 使用 |
| 视频 | 使用 |
| 平台注册表 | 始终分离注册表;绝不为所有表面使用单个注册表 |
| 目录共享 | 单个目录定义通过导入在所有注册表中共享 |
Common Mistakes
常见错误
- Building separate component trees for each surface — defeats the purpose; share the catalog and spec
- Using Puppeteer to screenshot React for PDF generation — slow, fragile; use native react-pdf rendering
- One giant registry covering all platforms — impossible since PDF uses /
<View>, web uses<Text>/<div><span> - Forgetting Satori limitations — no CSS grid, limited flexbox; design image registries with these constraints
- Duplicating catalog definitions per surface — one catalog, many registries; the catalog is the contract
- 为每个渲染表面构建独立组件树——违背初衷;应共享目录与规范
- 使用Puppeteer截图React生成PDF——速度慢、易出错;使用原生react-pdf渲染
- 单个巨型注册表覆盖所有平台——不可能实现,因为PDF使用/
<View>,网页使用<Text>/<div><span> - 忽略Satori的限制——不支持CSS Grid,Flexbox功能有限;设计图片注册表时需考虑这些约束
- 为每个渲染表面重复定义目录——一个目录,多个注册表;目录是契约
Related Skills
相关技能
- — Catalog definition patterns with Zod, shadcn components
ork:json-render-catalog - — Video production pipeline using Remotion
ork:demo-producer - — Slide deck generation
ork:presentation-builder - — Rendering specs in Claude/Cursor via MCP
ork:mcp-visual-output
- —— 结合Zod、shadcn组件的目录定义模式
ork:json-render-catalog - —— 使用Remotion的视频制作流水线
ork:demo-producer - —— 幻灯片生成
ork:presentation-builder - —— 通过MCP在Claude/Cursor中渲染规范
ork:mcp-visual-output