json-render-catalog について
json-render Component Catalogs は、json-render 用の制約付きコンポーネントカタログを構築するスキルです。Storybookからのインポートと、安全なディレクティブの利用に重点を置いています。
主な機能
- 01Storybookのストーリーからカタログをインポート
- 02Zodでコンポーネントとプロパティを制約
- 03組み込み・カスタムディレクティブの利用
- 04名前付きコンテンツスロットの対応
- 05複数の表示先への仕様のレンダリング
活用シーン
- 01既存のStorybook設定からカタログを生成
- 02AI生成UIを許可されたコンポーネントに限定
- 03書式設定や翻訳値を安全に計算
MCP 対応
READMEでは、@json-render/mcpがMCPツールのJSONを会話内のインタラクティブなiframeに変換すると説明されています。同じ仕様を複数の表示先にレンダリングするMCP連携にも触れています。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yonatangross/ orchestkit --skill json-render-catalogインストール後、Claude Code で/json-render-catalogを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
test-cases.jsonreferences/ork-delta.mdpackage-ecosystem.mdstorybook-fixture.jsonstorybook-import.mdrules/_sections.md_template.mdcatalog-definition.mdprop-constraints.mdtoken-optimization.mdscripts/storybook-to-catalog.mjs詳細
アップストリームのバージョン参照:@json-render/core 0.21.0(2026-09-30)。
json-render コンポーネントカタログ
json-render(Vercel Labs、12.9K stars、Apache-2.0)は、AI セーフなジェネレーティブ UI のためのフレームワークです。AI は、開発者が定義したカタログに制約されたフラットツリー形式の JSON(または YAML)仕様を生成します。カタログは、デザインシステムと AI の出力をつなぐ契約です。カタログにないコンポーネントやプロパティを AI が生成することはできません。
Storybook からカタログへのインポート(#1529、2026-04)
プロジェクトに Storybook の設定がある場合は、カタログを手書きするのではなく、Storybook のストーリーからインポートしてください。付属のインポーター scripts/storybook-to-catalog.mjs は、@storybook/addon-mcp の list-all-documentation マニフェストを読み込み、Zod 型付きの catalog.ts と components.tsx レジストリを生成します。
node "${CLAUDE_SKILL_DIR}/scripts/storybook-to-catalog.mjs" storybook-manifest.json \
--out src/genui/catalog.ts \
--components src/genui/components.tsx \
--project-root .
Storybook が唯一の信頼できる情報源になります。ストーリーを追加すると AI が使用できる範囲が自動的に広がり、削除すると狭まります。インポート時に、コールバック、生のオブジェクトプロパティ、z.any() が除外されるため、AI の安全性が確保されます。マッピングの詳細:references/storybook-import.md。テスト用の関連フィクスチャ:references/storybook-fixture.json。
2026-04 → 2026-08 の新機能(json-render 0.14 → 0.20)
- 名前付きスロット(0.20) —
UIElementにslots?: Record<string, string[]>が追加され、カタログではslots: ["default", "header", "footer"]のように受け入れるスロットを宣言できます。また、React のレジストリコンポーネントはslots?.headerとして名前付きコンテンツを受け取り、childrenはデフォルトスロットのままです。レイアウト領域を別々の兄弟要素として表現するよりも、こちらを優先してください。 - ネストされた繰り返しと項目スコープの表示制御(0.20) —
repeat.statePathでは、項目相対の{"$item": "employees"}形式を使用できるようになりました(新しいRepeatStatePath型とresolveRepeatStatePath/resolveRepeatItemStatePathを追加)。また、同じ要素でrepeatとvisible: {"$item": "status", "eq": "todo"}を組み合わせると、エラーではなく項目のフィルタリングが行われます。validateSpecにinvalid_visible、repeat_without_children、repeat_item_outside_scope、repeat_state_mismatchの問題コードが追加されました。 - カスタムディレクティブ API(0.19) —
@json-render/coreにdefineDirectiveが追加され、レンダリング時に計算値へ解決される新しい JSON 形式(例:$format、$math)を宣言できるようになりました。ディレクティブはネストして組み合わせられ、内側から外側に向かって解決されます。React、Vue、Svelte、Solid の 4 つのレンダラーすべてに、ディレクティブ解決機能が組み込まれています。カタログをz.any()に広げることなく計算値を扱える、安全な拡張方法です。 @json-render/directivesパッケージ(0.19) — すぐに使える 7 つのディレクティブを提供します。$format(Intlによる日付/通貨/数値/パーセント)、$math(加算、減算、乗算、除算、剰余、最小値、最大値、四捨五入、切り捨て、切り上げ、絶対値)、$concat、$count、$truncate、$pluralize、$joinです。さらに、{{param}}補間に対応した$t翻訳キー用のcreateI18nDirectiveと、1 行で登録できるstandardDirectivesも用意されています。一度登録すれば、どの spec でも使用できます。AI が文字列の加工やリテラルの重複を行う必要はありません。- Devtools エコシステム(0.18) — 新たに 5 つのパッケージが追加されました。
@json-render/devtoolsコアと、React、Vue、Svelte、Solid 用のフレームワークアダプターです。インスペクターパネルには 6 つのタブ(Spec、State、Actions、Stream、Catalog、Pick)があり、DOM 要素を選択して対応する spec キーを確認できます。本番環境ではツリーシェイクによりnullになります。AI チャットとカタログを連携した Next.js デモアプリも同梱されています。アダプターがイベントをパネルに反映できるよう、アクションオブザーバーの基盤も公開されています。 - Zod 4 の修正(0.18) —
formatZodTypeがz.record()、z.default()、z.literal()を正しく処理するようになりました(以前はプロンプト出力が空、または不正になっていました)。 - 3 つの編集モード(0.14) — AI による段階的な改善のための
patch(RFC 6902)、merge(RFC 7396)、diff(統合形式)です。@json-render/coreにbuildEditUserPrompt()、diffToPatches()、deepMergeSpec()が追加されました。 @json-render/yaml(0.14) — YAML の公式ワイヤーフォーマットとストリーミングパーサーを提供します。buildUserPrompt({ format: 'yaml' })を使用してください。@json-render/ink(0.15) — 同じ spec を使って、カタログをターミナル UI(Ink ベース、20 以上のコンポーネント)にレンダリングできます。@json-render/next(0.16) — 1 つの spec から、完全な Next.js アプリ(ルート、レイアウト、SSR、メタデータ)を生成します。@json-render/shadcn-svelte(0.16) — React の shadcn カタログに対応する、Svelte 5 + Tailwind 製の 36 コンポーネントのミラーです。- shadcn カタログは 36 コンポーネントに対応(29 と記載されていましたが、0.13 の時点でも数が誤っていました)。
@json-render/shadcnをそのまま使うか、shadcnComponentDefinitionsを独自の定義とともに展開してください。 @json-render/react-three-fiberには 19 個のコンポーネントがあります(2026-07-31 にアップストリームのスキルと照合して確認済みです。ここでは一覧を再掲せず、「アップストリームの対応状況」を参照してください)。@json-render/mcp— 通常の MCP ツール JSON を、Claude/Cursor/ChatGPT の会話内で操作可能な iframe に変換します。ork:mcp-visual-outputスキルを参照してください。- MCP のマルチサーフェス対応:同じ spec を React、PDF(
@json-render/react-pdf)、メール(@json-render/react-email)、ターミナル(Ink)、Next.js アプリ、Remotion 動画にレンダリングできます。
ディレクティブ — @json-render/directives (0.19)
ディレクティブは、計算値を扱うための安全な拡張手段です。AI が $ で始まるオブジェクトを出力すると、レンダラーはコンポーネントに props が渡される前に内側から順に解決します。これによりカタログは厳密なまま(z.any() による型の拡張は不要)、仕様も宣言的に保たれます。@json-render/directives パッケージには、組み込みディレクティブ 7 種と i18n ファクトリーが含まれています。standardDirectives では、それらをひとつの配列としてエクスポートしているため、1 行で登録できます。ディレクティブは自由にネストできます(例:$math を $format でラップ)。また、4 つすべてのレンダラー統合(React、Vue、Svelte、Solid)で解決されます。
登録
import { defineRegistry, JSONUIProvider, Renderer } from '@json-render/react'
import { standardDirectives, createI18nDirective } from '@json-render/directives'
const directives = [
...standardDirectives,
createI18nDirective({
locale: 'en',
fallbackLocale: 'en',
messages: { en: { greeting: 'Hello, {{name}}!' } },
}),
]
const { registry } = defineRegistry(catalog, { components })
// directives register on the provider (RendererProps has no directives prop)
<JSONUIProvider registry={registry} directives={directives}>
<Renderer spec={spec} registry={registry} />
</JSONUIProvider>
組み込みディレクティブ 7 種
| ディレクティブ | 目的 | 最小限の使用例 |
|---|---|---|
$format | date、currency、number、percent の Intl ベースのフォーマットです。locale、currency、notation、および人間が読みやすい日付の差分を表示する style: "relative" に対応しています。 | { "$format": "currency", "value": 1299, "currency": "USD" } → $1,299.00 |
$math | 算術演算です。add、subtract、multiply、divide、mod、min、max、round、floor、ceil、abs に対応しています。ゼロ除算の結果は 0 です。数値以外の入力は 0 に変換されます。 | { "$math": "multiply", "a": { "$state": "/qty" }, "b": 9.99 } |
$concat | 動的な値の配列を文字列に結合します。各要素は、まずディレクティブのパイプラインを通して解決されます。 | { "$concat": ["Hello, ", { "$state": "/user/name" }, "!"] } |
$count | 配列または文字列の長さを返します。それ以外の場合は 0 を返します。 | { "$count": { "$state": "/items" } } |
$truncate | length(既定値は 100)で切り詰めます。任意で suffix(既定値は ...)を指定できます。すでに指定の長さ以下の場合は何もしません。 | { "$truncate": { "$state": "/bio" }, "length": 80 } |
$pluralize | 単数形/複数形/ゼロの場合の表記を選択します。件数を自動的に前置します("3 items"、"1 item"、または zero の文字列)。 | { "$pluralize": { "$state": "/cart/count" }, "zero": "no items", "one": "item", "other": "items" } |
$join | 配列を separator(既定値は ", ")で結合します。 | { "$join": { "$state": "/tags" }, "separator": " · " } |
createI18nDirective({ locale, messages, fallbackLocale? }) は、{{param}} 補間に対応した $t ディレクティブを登録します。使用例:{ "$t": "greeting", "params": { "name": "Ada" } }。
defineDirective によるカスタムディレクティブ
defineDirective は @json-render/core (0.19+) にあります。ディレクティブでは、JSON の形式を定義する Zod スキーマと resolve(raw, ctx) 関数を宣言します。計算する前に、ネストされたディレクティブや状態参照を再帰的に解決するには、resolvePropValue(raw.field, ctx) を使用します。
import { defineDirective, resolvePropValue } from '@json-render/core'
import { z } from 'zod'
export const initialsDirective = defineDirective({
name: '$initials',
description: 'First letter of each word, uppercased.',
schema: z.object({ $initials: z.unknown() }),
resolve(raw, ctx) {
const text = String(resolvePropValue(raw.$initials, ctx) ?? '')
return text.split(/\s+/).map((w) => w[0]?.toUpperCase() ?? '').join('')
},
})
standardDirectives とともにレンダラーへ展開します:directives={[...standardDirectives, initialsDirective]}。スキーマは厳密に保ってください。ディレクティブは、AI がカタログ外の JSON を出力できる唯一の場所です。そのため、コンポーネントの prop と同じように、Zod で形式を検証してください。
Upstream のカバレッジ(再掲しないでください)
json-render には、パッケージごとの独自のスキルが用意されています。このスキルはそれらをラップし、差分のみを残します。差分とは、独自の Storybook インポートパス、独自のカタログ制約、そして references/ork-delta.md に記載された過去の失敗から得た知見です。ベンダーの一覧や API テーブルを再掲しないでください。
| トピック | ファーストパーティのソース |
|---|---|
コア API(defineSchema、defineCatalog、プロンプト、仕様のストリーミング、検証、StateStore) | https://github.com/vercel-labs/json-render skills/core/SKILL.md |
仕様の形式、動的なプロパティ式($state / $bindState / $cond / $template / $computed)、watch、表示制御 | https://github.com/vercel-labs/json-render skills/core/SKILL.md および skills/react/SKILL.md |
組み込みアクション(setState、pushState、removeState、validateForm)とイベントシステム | https://github.com/vercel-labs/json-render skills/react/SKILL.md |
| shadcn のコンポーネント一覧とプロパティスキーマ(36 コンポーネント、React および Svelte) | vercel:shadcn スキル、および https://github.com/vercel-labs/json-render skills/shadcn/SKILL.md と skills/shadcn-svelte/SKILL.md |
| レンダラーごとのコンポーネントと API(Vue、Svelte、Solid、React Native、Ink、Next.js、PDF、email、image、Remotion、react-three-fiber) | https://github.com/vercel-labs/json-render skills/<package>/SKILL.md |
| YAML のワイヤ形式、フェンス、ストリーミングコンパイラー、編集モード | https://github.com/vercel-labs/json-render skills/yaml/SKILL.md |
状態アダプター(zustandStateStore、reduxStateStore、jotaiStateStore、xstateStoreStateStore) | https://github.com/vercel-labs/json-render skills/zustand/SKILL.md、skills/redux/SKILL.md、skills/jotai/SKILL.md、skills/xstate/SKILL.md |
MCP Apps の統合(createMcpApp、iframe クライアント) | ork:mcp-visual-output、および https://github.com/vercel-labs/json-render skills/mcp/SKILL.md |
| 手書きの JSON からコンポーネントへのマッパーの移行 | https://github.com/vercel-labs/json-render skills/core/SKILL.md(カタログと仕様の契約が目標の形です) |
独自の差分、つまり upstream のドキュメントにない内容は、references/ork-delta.md に記載されています。
クイックリファレンス
| カテゴリ | ルール | 影響度 | 使用する場面 |
|---|---|---|---|
| カタログの定義 | 1 | 高 | Zod を使ったコンポーネントカタログの定義 |
| プロパティの制約 | 1 | 高 | 安全性のために AI 生成プロパティを制約する |
| トークンの最適化 | 1 | 中 | YAML モードでトークン使用量を削減する |
合計:3 カテゴリにわたる 3 つのルール
json-render の仕組み
- 開発者がカタログを定義する — プロパティを制約した、Zod 型付きのコンポーネント定義
- AI が仕様を生成する — カタログ内のコンポーネントのみを参照する、フラットツリー形式の JSON/YAML
- ランタイムが仕様をレンダリングする —
<Renderer>コンポーネントが各要素を検証してレンダリングします
カタログが安全性の境界になります。AI が参照できるのはカタログに存在する型のみで、プロパティはランタイムで Zod スキーマに照らして検証されます。これにより、幻覚によるコンポーネントや無効なプロパティが UI に到達するのを防ぎます。
クイックスタート — 3 ステップ
ステップ 1:カタログを定義する
import { defineCatalog } from '@json-render/core'
import { schema } from '@json-render/react/schema'
import { z } from 'zod'
export const catalog = defineCatalog(schema, {
components: {
Card: {
props: z.object({
title: z.string(),
description: z.string().optional(),
}),
children: true,
},
Button: {
props: z.object({
label: z.string(),
variant: z.enum(['default', 'destructive', 'outline', 'ghost']),
}),
children: false,
},
StatGrid: {
props: z.object({
items: z.array(z.object({
label: z.string(),
value: z.string(),
trend: z.enum(['up', 'down', 'flat']).optional(),
})).max(20),
}),
children: false,
},
},
})
LLM の構造化出力との互換性
jsonSchema({ strict: true }) を使用して、LLM の構造化出力 API(OpenAI、Anthropic、Gemini)と互換性のあるカタログスキーマをエクスポートします。
// jsonSchema is a METHOD on the Catalog instance, not a top-level export.
const schema = catalog.jsonSchema({ strict: true })
// Pass to OpenAI response_format, Anthropic tool_use, or Gemini structured output
ステップ 2:コンポーネントを実装する
import type { InferCatalogComponents } from '@json-render/core'
import type { catalog } from './catalog'
export const components: InferCatalogComponents<typeof catalog> = {
Card: ({ title, description, children }) => (
<div className="rounded-lg border p-4">
<h3 className="font-semibold">{title}</h3>
{description && <p className="text-muted-foreground">{description}</p>}
{children}
</div>
),
Button: ({ label, variant }) => (
<button className={cn('btn', `btn-${variant}`)}>{label}</button>
),
StatGrid: ({ items }) => (
<div className="grid grid-cols-3 gap-4">
{items.map((item) => (
<div key={item.label}>
<span>{item.label}</span>
<strong>{item.value}</strong>
</div>
))}
</div>
),
}
ステップ 3:仕様をレンダリングする
import { defineRegistry, Renderer } from '@json-render/react'
import { catalog } from './catalog'
import { components } from './components'
// defineRegistry returns DefineRegistryResult — destructure `registry`
const { registry } = defineRegistry(catalog, { components })
function App({ spec }: { spec: JsonRenderSpec }) {
return <Renderer spec={spec} registry={registry} />
}
仕様の形式
JSON 仕様はフラットツリー形式です。ネストはなく、ID と参照のみで構成されます。フィールドごとのドキュメント(root、elements、props、children、on、watch、state、および $state / $bindState / $cond / $template / $computed 式)は、upstream の https://github.com/vercel-labs/json-render skills/core/SKILL.md にあります。
{
"root": "card-1",
"elements": {
"card-1": {
"type": "Card",
"props": { "title": "Dashboard" },
"children": ["chart-1", "btn-1"]
},
"btn-1": {
"type": "Button",
"props": { "label": "View Details", "variant": "default" }
}
}
}
インタラクティブ機能あり(on / watch / state)
{
"root": "card-1",
"elements": {
"card-1": {
"type": "Card",
"props": { "title": "Dashboard" },
"children": ["chart-1", "btn-1"],
"on": { "press": { "action": "setState", "path": "/view", "value": "detail" } },
"watch": { "/data": { "action": "load_data", "url": "/api/stats" } }
}
},
"state": { "/activeTab": "overview" }
}
イベントハンドラー、watch バインディング、組み込みアクション(setState、pushState、
removeState、validateForm)、および state アダプターは、上流の
https://github.com/vercel-labs/json-render skills/react/SKILL.md と各アダプターの
スキルに記載されています。ここで一覧を繰り返さないでください。その理由については
references/ork-delta.md を参照してください。
YAML モード — トークンを30%削減
スタンドアロン(非ストリーミング)で生成する場合、YAML 仕様は JSON よりトークンを約30%削減できます。
root: card-1
elements:
card-1:
type: Card
props:
title: Dashboard
children: [chart-1, btn-1]
btn-1:
type: Button
props:
label: View Details
variant: default
インラインモード/ストリーミングでは JSON を使用してください(JSONL 上の JSON Patch RFC 6902 には JSON が必要です)。トークンコストが重要なスタンドアロンモードでは YAML を使用してください。選択基準については rules/token-optimization.md を読み込んでください。
プログレッシブストリーミング
json-render はストリーミング中のプログレッシブレンダリングに対応しています。AI が仕様の要素を生成すると、すぐにレンダリングされ、ユーザーは UI がリアルタイムで構築される様子を確認できます。これは、JSONL 上でストリーミングされる JSON Patch(RFC 6902)操作を使用します。
{"op":"add","path":"/elements/card-1","value":{"type":"Card","props":{"title":"Dashboard"},"children":[]}}
{"op":"add","path":"/elements/btn-1","value":{"type":"Button","props":{"label":"Save","variant":"default"}}}
{"op":"add","path":"/elements/card-1/children/-","value":"btn-1"}
要素は、props が完成するとすぐにレンダリングされます。仕様全体を待つ必要はありません。
@json-render/shadcn — 36個の組み込みコンポーネント
@json-render/shadcn パッケージには、Zod スキーマがあらかじめ定義された、本番環境対応の36個のコンポーネントカタログが用意されています。
コンポーネント一覧と props スキーマは、上流の
https://github.com/vercel-labs/json-render skills/shadcn/SKILL.md に記載されています。shadcn/ui
自体の構成については、vercel:shadcn スキルを参照してください。
Svelte:
@json-render/shadcn-svelte(0.16で追加)は、Svelte 5 + Tailwind プロジェクト向けに同じ36個のコンポーネントを提供します。
import { shadcnComponentDefinitions, shadcnComponents } from '@json-render/shadcn'
import { defineRegistry, Renderer } from '@json-render/react'
// Use as-is
const { registry } = defineRegistry(shadcnComponentDefinitions, { components: shadcnComponents })
<Renderer spec={spec} registry={registry} />
// Or merge with custom components
const catalog = { ...shadcnComponentDefinitions, ...customCatalog }
スタイル対応カタログ
shadcn カタログのコンポーネントでは、デフォルトの Tailwind クラスが使用されます。プロジェクトで特定の shadcn v4 スタイル(Luma、Nova など)を使用している場合は、コンポーネントの実装を上書きして一致させてください。
import { shadcnComponentDefinitions, shadcnComponents } from '@json-render/shadcn'
import type { InferCatalogComponents } from '@json-render/core'
// Override shadcn component implementations for Luma style
const lumaComponents: Partial<InferCatalogComponents<typeof shadcnComponentDefinitions>> = {
Card: ({ title, description, children }) => (
<div className="rounded-4xl border shadow-md ring-1 ring-foreground/5 p-6">
<h3 className="font-semibold">{title}</h3>
{description && <p className="text-muted-foreground">{description}</p>}
<div className="mt-6">{children}</div>
</div>
),
Button: ({ label, variant }) => (
<button className={cn('rounded-4xl', buttonVariants({ variant }))}>{label}</button>
),
}
// Merge: catalog schema unchanged, only rendering adapts to style
const components = { ...shadcnComponents, ...lumaComponents }
検出パターン: components.json の "style" フィールドを読み取り、適用する上書きを判断してください。スタイル固有のクラス名:Luma(rounded-4xl、shadow-md、gap-6)、Nova(コンパクトな px-2 py-1)、Lyra(rounded-none)。
編集モード — patch / merge / diff(0.14+)
初回レンダリング後に仕様を更新する場合(AI による調整、ユーザー編集、一部の再生成)、コアには3つの汎用編集モードが用意されています。
| モード | 仕様 | 使用する場面 |
|---|---|---|
patch | RFC 6902 JSON Patch | 差分を正確にストリーミングする場合(プログレッシブストリーミングですでに使用) |
merge | RFC 7396 JSON Merge Patch | よりシンプルな更新や、フィールド全体の置き換え |
diff | シリアライズされた仕様の Unified diff | モデルがプレーンテキストの差分を優先する場合の、AI ネイティブな出力 |
import { deepMergeSpec, diffToPatches, buildEditUserPrompt } from '@json-render/core'
// Ask the model for an edit in whichever format it finds easiest
const prompt = buildEditUserPrompt(currentSpec, instruction, { format: 'yaml', mode: 'merge' })
// Normalize any edit mode to RFC 6902 patches for application
const patches = diffToPatches(aiResponse)
const next = deepMergeSpec(currentSpec, patches)
0.14では buildUserPrompt() に format と serializer オプションも追加されました。スタンドアロン仕様には YAML、ストリーミングには JSON を選択してください。
パッケージエコシステム
ウェブ、モバイル、ターミナル、3D、コード生成、状態管理に対応する、コアと23個のレンダラー/統合パッケージがあります。カテゴリ別に整理された全一覧については、references/package-ecosystem.md を読み込んでください。
0.13以降に追加:
@json-render/yaml(0.14)— YAML ワイヤーフォーマット + ストリーミングパーサー@json-render/ink(0.15)— ターミナル UI レンダラー(Ink ベース、20個以上のコンポーネント)@json-render/next(0.16)— Next.js アプリ全体を生成(ルート、レイアウト、SSR、メタデータ)@json-render/shadcn-svelte(0.16)— React shadcn カタログを再現した、36コンポーネントの Svelte 5 向けパッケージ@json-render/react-three-fiberには19個のコンポーネントが含まれます(2026-07-31確認済み。一覧は上流にあります)@json-render/devtools+ フレームワークアダプター(0.18)— 6タブのインスペクターパネル、DOM ピッカー、本番環境ではnullにツリーシェイク@json-render/directives(0.19)— 7つの Intl/数学/文字列ディレクティブ +createI18nDirective+standardDirectives登録ヘルパー
使用する場合と使用しない場合
json-render を使用する場合:
- AI に UI を生成させる際、生成可能な内容を制限する必要がある
- ハルシネーションによるコンポーネントの生成を防ぐ、実行時に検証される仕様が必要である
- クロスプラットフォームのレンダリング(React、Vue、Svelte、React Native、PDF、メール)が必要である
- 生成 UI の機能(自然言語からのダッシュボード、レポート、フォームの生成)を構築している
json-render を使用しない場合:
- 静的な、開発者が作成する UI を構築している — コンポーネントを直接使用してください
- AI が仕様ではなくコード(JSX/TSX)を生成する — 標準的なコード生成を使用してください
- カタログの制約を受けずに完全な創造の自由が必要である — json-render は意図的に制約を設けています
- 数千の要素を扱うパフォーマンス重視のレンダリングが必要である — フラットツリーの抽象化によってオーバーヘッドが発生します
カスタム GenUI からの移行
既存のカスタム生成 UI(手作業で作成した JSON からコンポーネントへのマッピング)がある場合、
移行先は、上流の https://github.com/vercel-labs/json-render skills/core/SKILL.md に記載された
カタログとフラットツリー仕様の契約です。次の手順が効果的です。
既存の型を一覧にし、それぞれに defineCatalog で Zod スキーマを定義し、ネストされた仕様を
root と elements にフラット化し、ハンドラープロパティを on フィールドに移してから、
既存のコンポーネントをカタログ実装としてラップします。
ルールの詳細
カタログ定義
defineCatalog() と Zod スキーマを使用してカタログを定義する方法です。
| ルール | ファイル | 主要パターン |
|---|---|---|
| カタログ定義 | rules/catalog-definition.md | Zod スキーマ、子要素の型を使用した defineCatalog |
プロパティの制約
AI によるハルシネーションを防ぐためのプロパティの制約です。
| ルール | ファイル | 主要パターン |
|---|---|---|
| プロパティの制約 | rules/prop-constraints.md | z.enum、z.string().max()、z.array().max() |
トークンの最適化
トークン効率を高めるために JSON と YAML のどちらを選ぶかです。
| ルール | ファイル | 主要パターン |
|---|---|---|
| トークンの最適化 | rules/token-optimization.md | スタンドアロンモードでは YAML、インライン/ストリーミングでは JSON |
主な判断基準
| 判断項目 | 推奨事項 |
|---|---|
| カスタムカタログと shadcn カタログ | shadcn から始め、ドメイン固有のコンポーネントにはカスタム型を追加します |
| JSON と YAML の仕様形式 | スタンドアロンモードでは YAML(トークンを 30%削減)、インライン/ストリーミングでは JSON |
| Zod 制約の厳しさ | 厳しいほど適切です。z.string より z.enum を、上限のない z.array より z.array().max() を使用します |
| 状態管理アダプター | アプリで既に使用している状態管理ライブラリ(Zustand、Redux、Jotai、XState)に合わせます |
よくある間違い
- カタログのプロパティで
z.any()またはz.unknown()を使用する — カタログ制約の目的が失われ、AI が何でも生成できるようになります - 常に JSON 仕様を使用する — インライン/ストリーミングが不要な場合、トークンを 30%無駄にします(スタンドアロンモードでは YAML を使用してください)
- コンポーネント定義をネストする — json-render はフラットツリーを使用します。すべての要素は、ID で参照される兄弟要素です
shadcnComponentDefinitionsを展開せずに shadcn コンポーネントを再定義する — 上流の Zod 境界が失われます- 配列に
.max()を設定しない — AI がレイアウトを壊すような、上限のないリストを生成する可能性があります
関連スキル
ork:ai-ui-generation— v0、Bolt、Cursor 向けの AI 支援 UI 生成パターンork:ui-components— shadcn/ui コンポーネントのパターンと CVA バリアントork:component-search— React/Vue コンポーネントの検索と評価ork:design-to-code— デザインを本番用コードに変換