Kaynağa Gözat

rename modes (#197)

* rename modes

* improvements

* fixes

* fix homepage
Chris Tate 4 ay önce
ebeveyn
işleme
dc9e9d17f3

+ 1 - 0
.gitignore

@@ -4,6 +4,7 @@
 node_modules
 .pnp
 .pnp.js
+.pnpm-store/
 
 # Local env files
 .env*

+ 12 - 12
apps/web/app/(main)/docs/ai-sdk/page.mdx

@@ -3,7 +3,7 @@ export const metadata = pageMetadata("docs/ai-sdk")
 
 # AI SDK Integration
 
-Use json-render with the [Vercel AI SDK](https://sdk.vercel.ai) for seamless streaming. json-render supports two modes: **Generate** (standalone UI) and **Chat** (UI embedded in conversation). See [Generation Modes](/docs/generation-modes) for a detailed comparison.
+Use json-render with the [Vercel AI SDK](https://sdk.vercel.ai) for seamless streaming. json-render supports two modes: **Standalone** (standalone UI) and **Inline** (UI embedded in conversation). See [Generation Modes](/docs/generation-modes) for a detailed comparison.
 
 ## Installation
 
@@ -11,9 +11,9 @@ Use json-render with the [Vercel AI SDK](https://sdk.vercel.ai) for seamless str
 npm install ai @ai-sdk/react
 ```
 
-## Generate Mode
+## Standalone Mode
 
-In generate mode, the AI outputs only JSONL patches. The entire response is a UI spec with no prose. This is the default mode and is ideal for playgrounds, builders, and dashboard generators.
+In standalone mode, the AI outputs only JSONL patches. The entire response is a UI spec with no prose. This is the default mode and is ideal for playgrounds, builders, and dashboard generators.
 
 ### API Route
 
@@ -73,9 +73,9 @@ function GenerativeUI() {
 }
 ```
 
-## Chat Mode
+## Inline Mode
 
-In chat mode, the AI responds conversationally and includes JSONL patches inline. Text-only replies are allowed when no UI is needed. This is ideal for chatbots, copilots, and educational assistants.
+In inline mode, the AI responds conversationally and includes JSONL patches inline. Text-only replies are allowed when no UI is needed. This is ideal for chatbots, copilots, and educational assistants.
 
 ### API Route
 
@@ -96,7 +96,7 @@ export async function POST(req: Request) {
 
   const result = streamText({
     model: yourModel,
-    system: catalog.prompt({ mode: "chat" }),
+    system: catalog.prompt({ mode: "inline" }),
     messages,
   });
 
@@ -182,13 +182,13 @@ const systemPrompt = catalog.prompt({
 });
 ```
 
-### Chat Mode Prompt
+### Inline Mode Prompt
 
 ```typescript
-const chatPrompt = catalog.prompt({ mode: "chat" });
+const inlinePrompt = catalog.prompt({ mode: "inline" });
 ```
 
-In chat mode, the prompt instructs the AI to respond conversationally first, then include JSONL patches on their own lines when UI is needed. Text-only replies are allowed.
+In inline mode, the prompt instructs the AI to respond conversationally first, then include JSONL patches on their own lines when UI is needed. Text-only replies are allowed.
 
 ## Which Mode?
 
@@ -197,8 +197,8 @@ In chat mode, the prompt instructs the AI to respond conversationally first, the
     <thead>
       <tr>
         <th></th>
-        <th>Generate</th>
-        <th>Chat</th>
+        <th>Standalone</th>
+        <th>Inline</th>
       </tr>
     </thead>
     <tbody>
@@ -215,7 +215,7 @@ In chat mode, the prompt instructs the AI to respond conversationally first, the
       <tr>
         <td>System prompt</td>
         <td><code>catalog.prompt()</code></td>
-        <td><code>{"catalog.prompt({ mode: \"chat\" })"}</code></td>
+        <td><code>{"catalog.prompt({ mode: \"inline\" })"}</code></td>
       </tr>
       <tr>
         <td>Stream utility</td>

+ 4 - 4
apps/web/app/(main)/docs/api/core/page.mdx

@@ -75,7 +75,7 @@ interface Catalog {
 interface PromptOptions {
   system?: string;           // Custom system message intro
   customRules?: string[];    // Additional rules to append
-  mode?: "generate" | "chat"; // Output mode (default: "generate")
+  mode?: "standalone" | "inline" | "generate" | "chat"; // Output mode (default: "standalone")
 }
 
 interface SpecValidationResult<T> {
@@ -370,7 +370,7 @@ Most users should use `pipeJsonRender()` instead, which wraps this transform for
 
 ### createMixedStreamParser
 
-Parse a mixed stream of text and JSONL patches (used for Chat + GenUI mode):
+Parse a mixed stream of text and JSONL patches (used for Inline mode):
 
 ```typescript
 import { createMixedStreamParser } from '@json-render/core';
@@ -389,7 +389,7 @@ parser.flush();
 
 ### pipeJsonRender
 
-Pipe an AI SDK `UIMessageStream` through the json-render transform. Lines that parse as JSONL patches are emitted as `data-spec` parts; everything else passes through as text. Used in Chat mode API routes.
+Pipe an AI SDK `UIMessageStream` through the json-render transform. Lines that parse as JSONL patches are emitted as `data-spec` parts; everything else passes through as text. Used in Inline mode API routes.
 
 ```typescript
 import { pipeJsonRender } from '@json-render/core';
@@ -403,7 +403,7 @@ const stream = createUIMessageStream({
 return createUIMessageStreamResponse({ stream });
 ```
 
-See [Generation Modes](/docs/generation-modes) for full Chat mode setup.
+See [Generation Modes](/docs/generation-modes) for full Inline mode setup.
 
 ### SpecStream Types
 

+ 2 - 0
apps/web/app/(main)/docs/changelog/page.mdx

@@ -341,6 +341,8 @@ February 2026
 
 ### New: Chat Mode (Inline GenUI)
 
+> **Note:** These modes were renamed in v0.12.1 — "Generate" is now "Standalone" and "Chat" is now "Inline". The old names are accepted as deprecated aliases.
+
 json-render now supports two generation modes: **Generate** (JSONL-only, the default) and **Chat** (text + JSONL inline). Chat mode lets the AI respond conversationally with embedded UI specs, ideal for chatbots and copilot experiences.
 
 ```typescript

+ 11 - 11
apps/web/app/(main)/docs/generation-modes/page.mdx

@@ -3,15 +3,15 @@ export const metadata = pageMetadata("docs/generation-modes")
 
 # Generation Modes
 
-json-render supports two modes for AI-generated UI: **Generate mode** for standalone UI and **Chat mode** for inline UI within a conversation.
+json-render supports two modes for AI-generated UI: **Standalone mode** for standalone UI and **Inline mode** for inline UI within a conversation.
 
 The mode controls how the AI formats its output and how your app processes the stream. The underlying JSONL patch format is the same in both modes.
 
 <GenerationModesDiagram />
 
-## Generate Mode (Standalone)
+## Standalone Mode
 
-In generate mode, the AI outputs **only JSONL patches** — no prose, no markdown. The entire response is a UI spec.
+In standalone mode, the AI outputs **only JSONL patches** — no prose, no markdown. The entire response is a UI spec.
 
 This is the default mode and is ideal for:
 
@@ -25,7 +25,7 @@ This is the default mode and is ideal for:
 ```typescript
 import { streamText } from "ai";
 
-// Generate mode is the default (no mode option needed)
+// Standalone mode is the default (no mode option needed)
 const systemPrompt = catalog.prompt({
   customRules: [
     "Use Card as root for forms and small UIs.",
@@ -74,9 +74,9 @@ The AI outputs only JSONL — one patch per line, no surrounding text:
 {"op":"add","path":"/elements/submit","value":{"type":"Button","props":{"label":"Sign In"}}}
 ```
 
-## Chat Mode (Inline)
+## Inline Mode
 
-In chat mode, the AI responds **conversationally first**, then outputs JSONL patches on their own lines. Text-only replies are allowed when no UI is needed (e.g. greetings, clarifying questions).
+In inline mode, the AI responds **conversationally first**, then outputs JSONL patches on their own lines. Text-only replies are allowed when no UI is needed (e.g. greetings, clarifying questions).
 
 This is ideal for:
 
@@ -92,8 +92,8 @@ import { streamText } from "ai";
 import { pipeJsonRender } from "@json-render/core";
 import { createUIMessageStream, createUIMessageStreamResponse } from "ai";
 
-// Enable chat mode
-const systemPrompt = catalog.prompt({ mode: "chat" });
+// Enable inline mode
+const systemPrompt = catalog.prompt({ mode: "inline" });
 
 const result = streamText({
   model: yourModel,
@@ -180,8 +180,8 @@ If the user asks a simple question ("what does BTC stand for?"), the AI replies
     <thead>
       <tr>
         <th />
-        <th>Generate</th>
-        <th>Chat</th>
+        <th>Standalone</th>
+        <th>Inline</th>
       </tr>
     </thead>
     <tbody>
@@ -198,7 +198,7 @@ If the user asks a simple question ("what does BTC stand for?"), the AI replies
       <tr>
         <td>System prompt</td>
         <td><code>{"catalog.prompt()"}</code></td>
-        <td><code>{'catalog.prompt({ mode: "chat" })'}</code></td>
+        <td><code>{'catalog.prompt({ mode: "inline" })'}</code></td>
       </tr>
       <tr>
         <td>Stream utility</td>

+ 26 - 1
apps/web/app/(main)/docs/migration/page.mdx

@@ -309,10 +309,35 @@ const catalog = defineCatalog(schema, {
 
 const prompt = catalog.prompt();
 
-// Chat mode prompt
+// Inline mode prompt (formerly "chat")
+const inlinePrompt = catalog.prompt({ mode: "inline" });
+```
+
+## Generation Modes
+
+The generation mode values passed to `catalog.prompt()` have been renamed for clarity:
+
+- `"generate"` is now `"standalone"`
+- `"chat"` is now `"inline"`
+
+The old names are accepted as deprecated aliases, so existing code will continue to work. Update when convenient.
+
+**Before:**
+
+```typescript
+const prompt = catalog.prompt({ mode: "generate" });
 const chatPrompt = catalog.prompt({ mode: "chat" });
 ```
 
+**After:**
+
+```typescript
+const prompt = catalog.prompt({ mode: "standalone" });
+const inlinePrompt = catalog.prompt({ mode: "inline" });
+```
+
+The default mode (when no `mode` option is provided) is `"standalone"`, which behaves identically to the previous `"generate"` default.
+
 ## Validation
 
 `ValidationCheck` now uses `type` instead of `fn`, `ValidationProvider` uses `customFunctions` instead of `functions`, and `useFieldValidation` takes a config object instead of a checks array.

+ 1 - 1
apps/web/app/(main)/docs/page.mdx

@@ -91,7 +91,7 @@ The result is a native UI built from your own components — not an iframe, not
 - **[Streaming](/docs/streaming)** — Render progressively as the AI responds. Each JSONL patch adds to the spec and the UI updates in real time.
 - **[Data Binding](/docs/data-binding)** — Bind props to runtime data with `$state` paths, repeat elements over arrays, and wire two-way input bindings.
 - **[Visibility](/docs/visibility)** — Show or hide elements based on state conditions. The AI can generate conditional UIs without writing logic.
-- **[Generation Modes](/docs/generation-modes)** — Generate standalone UI (playground/builder) or inline UI within a chat conversation.
+- **[Generation Modes](/docs/generation-modes)** — Standalone mode for full-page generated UI or inline mode for UI embedded in a conversation.
 
 ## Next
 

+ 6 - 6
apps/web/components/generation-modes-diagram.tsx

@@ -19,11 +19,11 @@ function FormUI() {
   );
 }
 
-function ChatModeDiagram() {
+function InlineModeDiagram() {
   return (
     <div className="flex flex-col h-full">
       <div className="text-xs font-medium text-muted-foreground mb-3 text-center">
-        Chat Mode
+        Inline Mode
       </div>
       <div className="flex-1 border border-border rounded-lg bg-background overflow-hidden flex flex-col">
         {/* Chat area */}
@@ -69,11 +69,11 @@ function ChatModeDiagram() {
   );
 }
 
-function GenerateModeDiagram() {
+function StandaloneModeDiagram() {
   return (
     <div className="flex flex-col h-full">
       <div className="text-xs font-medium text-muted-foreground mb-3 text-center">
-        Generate Mode
+        Standalone Mode
       </div>
       <div className="flex-1 border border-border rounded-lg bg-background overflow-hidden flex flex-row">
         {/* Left panel - prompt */}
@@ -104,10 +104,10 @@ export function GenerationModesDiagram() {
     <div className="not-prose my-8">
       <div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
         <div className="h-[280px]">
-          <ChatModeDiagram />
+          <InlineModeDiagram />
         </div>
         <div className="h-[280px]">
-          <GenerateModeDiagram />
+          <StandaloneModeDiagram />
         </div>
       </div>
     </div>

+ 1 - 1
examples/chat/lib/agent.ts

@@ -130,7 +130,7 @@ When the user asks for a quiz, test, or Q&A, build an interactive experience:
 4. You can also add a final score section that becomes visible when all questions are submitted.
 
 ${explorerCatalog.prompt({
-  mode: "chat",
+  mode: "inline",
   customRules: [
     "NEVER use viewport height classes (min-h-screen, h-screen) — the UI renders inside a fixed-size container.",
     "Prefer Grid with columns='2' or columns='3' for side-by-side layouts.",

+ 1 - 1
examples/svelte-chat/src/lib/agent.ts

@@ -62,7 +62,7 @@ INPUT COMPONENTS:
 - Button: Clickable button. Use on.press to trigger actions.
 
 ${explorerCatalog.prompt({
-  mode: "chat",
+  mode: "inline",
   customRules: [
     "NEVER use viewport height classes (min-h-screen, h-screen) — the UI renders inside a fixed-size container.",
     "Prefer Grid with columns='2' or columns='3' for side-by-side layouts.",

+ 1 - 1
packages/codegen/package.json

@@ -15,7 +15,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/codegen"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/core/README.md

@@ -227,7 +227,7 @@ Schema options:
 | `ActionBinding` | Action binding with `action`, `params`, `confirm`, `preventDefault`, etc. |
 | `BuiltInAction` | Built-in action definition with `name` and `description` |
 
-### Chat Mode (Mixed Streams)
+### Inline Mode (Mixed Streams)
 
 | Export | Purpose |
 |--------|---------|

+ 1 - 1
packages/core/package.json

@@ -19,7 +19,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/core"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 35 - 3
packages/core/src/schema.test.ts

@@ -257,7 +257,7 @@ describe("catalog.prompt", () => {
     expect(prompt).toContain("Keep UIs simple");
   });
 
-  it("generates chat mode prompt when mode is chat", () => {
+  it("generates inline mode prompt when mode is inline", () => {
     const catalog = defineCatalog(testSchema, {
       components: {
         Text: {
@@ -268,13 +268,13 @@ describe("catalog.prompt", () => {
       },
       actions: {},
     });
-    const prompt = catalog.prompt({ mode: "chat" });
+    const prompt = catalog.prompt({ mode: "inline" });
     expect(prompt).toContain("```spec");
     expect(prompt).toContain("conversationally");
     expect(prompt).toContain("text + JSONL");
   });
 
-  it("generates generate mode prompt by default", () => {
+  it("generates standalone mode prompt by default", () => {
     const catalog = defineCatalog(testSchema, {
       components: {
         Text: {
@@ -290,6 +290,38 @@ describe("catalog.prompt", () => {
     expect(prompt).not.toContain("conversationally");
   });
 
+  it("accepts deprecated 'chat' as alias for 'inline'", () => {
+    const catalog = defineCatalog(testSchema, {
+      components: {
+        Text: {
+          props: z.object({}),
+          description: "",
+          slots: [],
+        },
+      },
+      actions: {},
+    });
+    const inlinePrompt = catalog.prompt({ mode: "inline" });
+    const chatPrompt = catalog.prompt({ mode: "chat" });
+    expect(chatPrompt).toEqual(inlinePrompt);
+  });
+
+  it("accepts deprecated 'generate' as alias for 'standalone'", () => {
+    const catalog = defineCatalog(testSchema, {
+      components: {
+        Text: {
+          props: z.object({}),
+          description: "",
+          slots: [],
+        },
+      },
+      actions: {},
+    });
+    const standalonePrompt = catalog.prompt({ mode: "standalone" });
+    const generatePrompt = catalog.prompt({ mode: "generate" });
+    expect(generatePrompt).toEqual(standalonePrompt);
+  });
+
   it("uses actual catalog component names in examples", () => {
     const catalog = defineCatalog(testSchema, {
       components: {

+ 22 - 6
packages/core/src/schema.ts

@@ -112,11 +112,14 @@ export interface PromptOptions {
   /**
    * Output mode for the generated prompt.
    *
-   * - `"generate"` (default): The LLM should output only JSONL patches (no prose).
-   * - `"chat"`: The LLM should respond conversationally first, then output JSONL patches.
+   * - `"standalone"` (default): The LLM should output only JSONL patches (no prose).
+   * - `"inline"`: The LLM should respond conversationally first, then output JSONL patches.
    *   Includes rules about interleaving text with JSONL and not wrapping in code fences.
+   *
+   * @deprecated `"generate"` — use `"standalone"` instead.
+   * @deprecated `"chat"` — use `"inline"` instead.
    */
-  mode?: "generate" | "chat";
+  mode?: "standalone" | "inline" | "generate" | "chat";
 }
 
 /**
@@ -563,15 +566,28 @@ function generatePrompt<TDef extends SchemaDefinition, TCatalog>(
   const {
     system = "You are a UI generator that outputs JSON.",
     customRules = [],
-    mode = "generate",
+    mode: rawMode = "standalone",
   } = options;
 
+  const mode: "standalone" | "inline" =
+    rawMode === "chat"
+      ? (console.warn(
+          '[json-render] mode "chat" is deprecated, use "inline" instead',
+        ),
+        "inline")
+      : rawMode === "generate"
+        ? (console.warn(
+            '[json-render] mode "generate" is deprecated, use "standalone" instead',
+          ),
+          "standalone")
+        : rawMode;
+
   const lines: string[] = [];
   lines.push(system);
   lines.push("");
 
   // Output format section - explain JSONL streaming patch format
-  if (mode === "chat") {
+  if (mode === "inline") {
     lines.push("OUTPUT FORMAT (text + JSONL, RFC 6902 JSON Patch):");
     lines.push(
       "You respond conversationally. When generating UI, first write a brief explanation (1-3 sentences), then output JSONL patch lines wrapped in a ```spec code fence.",
@@ -1014,7 +1030,7 @@ Note: state patches appear right after the elements that use them, so the UI fil
   // Rules
   lines.push("RULES:");
   const baseRules =
-    mode === "chat"
+    mode === "inline"
       ? [
           "When generating UI, wrap all JSONL patches in a ```spec code fence - one JSON object per line inside the fence",
           "Write a brief conversational response before any JSONL output",

+ 1 - 1
packages/image/package.json

@@ -20,7 +20,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/image"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/jotai/package.json

@@ -14,7 +14,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/jotai"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/mcp/package.json

@@ -22,7 +22,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/mcp"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/react-email/package.json

@@ -18,7 +18,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/react-email"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/react-native/package.json

@@ -19,7 +19,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/react-native"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/react-pdf/package.json

@@ -18,7 +18,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/react-pdf"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/react/package.json

@@ -19,7 +19,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/react"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/redux/package.json

@@ -14,7 +14,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/redux"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/remotion/package.json

@@ -19,7 +19,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/remotion"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/shadcn/package.json

@@ -22,7 +22,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/shadcn"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/svelte/package.json

@@ -21,7 +21,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/svelte"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/vue/package.json

@@ -19,7 +19,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/vue"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/xstate/package.json

@@ -15,7 +15,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/xstate"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },

+ 1 - 1
packages/zustand/package.json

@@ -14,7 +14,7 @@
     "url": "git+https://github.com/vercel-labs/json-render.git",
     "directory": "packages/zustand"
   },
-  "homepage": "https://github.com/vercel-labs/json-render#readme",
+  "homepage": "https://json-render.dev",
   "bugs": {
     "url": "https://github.com/vercel-labs/json-render/issues"
   },