| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Documentation · Renderer-only Playground
LLM generates JSX/TSX → browser renders it directly at runtime — no backend build server, no deploy step, JSPM package support with an explicit compatibility contract.
Renderify is a runtime-first, bundleless dynamic renderer that lets LLMs produce real, interactive UI on the fly. It bridges the gap between "LLM can generate code" and "users can see and interact with that UI instantly" — with inline transpilation via @babel/standalone, and no backend compiler/deploy pipeline in the loop.
A modern runtime renderer that lets LLMs generate JSX/TSX and render interactive UI instantly in the browser — no build step, no backend compiler.
Renderify is bundleless by design: it does not rely on a traditional bundling pipeline to run generated UI. Instead, it resolves and rewrites module imports at runtime (JSPM/CDN + moduleManifest pinning) and executes under explicit security policy and sandbox controls. In other words, bundleless runtime execution does not mean full npm bundler compatibility; Renderify intentionally targets a browser-ESM-compatible subset with explicit guarantees. See JSPM package support (tiered contract) for the exact compatibility boundary.
Want to edit and render this kind of source without installing the repo? Use the static Playground. It runs the renderer in the browser and never makes an LLM request.
import { renderTrustedPlanInBrowser } from "renderify";
await renderTrustedPlanInBrowser(
{
specVersion: "runtime-plan/v1",
id: "hello_jsx_runtime",
version: 1,
root: { type: "text", value: "Loading..." },
source: {
language: "tsx",
runtime: "preact",
code: `
import { format } from "date-fns/format";
export default function App() {
return <section>Today: {format(new Date(), "yyyy-MM-dd")}</section>;
}
`,
},
},
{ target: "#mount" },
);Defaults (no extra config):
LLMs are increasingly capable of generating UI code, but there is no good way to render that output directly in the browser:
| Existing Approach | Limitation |
|---|---|
| v0 / Bolt.new | Requires a full build backend (Next.js compile + deploy). Not embeddable as a runtime in your own app. |
| Streamlit / Gradio | Python-based, server-rendered. Not a frontend runtime. |
| MCP Apps | Standardizes the host/resource envelope; applications still need a rendering model and security boundary. |
| Anthropic Artifacts | Closed implementation, not open-source, not embeddable. |
| JSON schema renderers (A2UI, json-render) | LLM fills parameters into a predefined component catalog. Cannot express anything outside the schema. |
| Sandpack / WebContainers | Full in-browser bundlers — powerful but heavyweight, not optimized for the LLM → UI hot path. |
| The missing piece: a lightweight, security-governed runtime where LLMs output JSX/TSX (or structured plans) and the browser renders it immediately — with broad browser-ESM npm access via JSPM, without any backend compile step. |
LLM output (JSX/TSX or structured plan)
→ CodeGen (parse + normalize)
→ Security policy check (before any execution)
→ Runtime execution (Babel transpile + JSPM module resolution)
→ Rendered UI in the browser
flowchart TD
A["Prompt / Context"] --> B["LLM Interpreter"]
B --> C["Code Generator"]
C --> D["Runtime Plan (IR)"]
D --> E["Security Policy Checker"]
E --> F["Runtime Executor"]
F --> G["UI Renderer"]
F --> H["JSPM Module Loader"]
H --> I["JSPM CDN / SystemJS"]
J["Customization Plugins"] --> B
J --> C
J --> E
J --> F
J --> G
Use Renderify directly in your app code (no pnpm cli).
pnpm add renderifyimport { renderTrustedPlanInBrowser } from "renderify";
await renderTrustedPlanInBrowser(
{
specVersion: "runtime-plan/v1",
id: "quickstart_non_cli",
version: 1,
root: { type: "text", value: "Loading..." },
source: {
language: "tsx",
runtime: "preact",
code: `export default () => <section>Hello from Renderify SDK</section>;`,
},
},
{ target: "#mount" },
);For pure browser pages without a build tool, load @babel/standalone before running TSX/JSX source.
# Render prompt and print HTML
pnpm cli -- run "Build a welcome card"
# Print RuntimePlan JSON
pnpm cli -- plan "Build a welcome card"
# Probe RuntimePlan compatibility (policy + runtime preflight diagnostics)
pnpm cli -- probe-plan examples/runtime/recharts-dashboard-plan.json
# side-effect free: does not execute plan source/component logic
# Execute RuntimePlan file
pnpm cli -- render-plan examples/runtime/counter-plan.json
# Local development Playground (includes optional LLM actions)
pnpm playground
pnpm cli -- playground --host 0.0.0.0 # trusted networks only
pnpm cli -- playground --debug
pnpm cli -- playground --no-llm-log
RENDERIFY_PLAYGROUND_DEBUG=1 pnpm playground
RENDERIFY_PLAYGROUND_LLM_LOG=false pnpm playground
# Optional security env
RENDERIFY_SECURITY_PROFILE=strict pnpm playground
RENDERIFY_LLM_USE_STRUCTURED_OUTPUT=false pnpm playground
# Optional LLM provider env
RENDERIFY_LLM_PROVIDER=openai RENDERIFY_LLM_API_KEY=<your_key> pnpm playground
RENDERIFY_LLM_PROVIDER=openai RENDERIFY_LLM_MODEL=gpt-5-mini RENDERIFY_LLM_BASE_URL=https://api.openai.com/v1 pnpm playground
RENDERIFY_LLM_PROVIDER=anthropic RENDERIFY_LLM_API_KEY=<your_key> pnpm playground
RENDERIFY_LLM_PROVIDER=anthropic RENDERIFY_LLM_MODEL=claude-sonnet-4-5 RENDERIFY_LLM_BASE_URL=https://api.anthropic.com/v1 pnpm playground
RENDERIFY_LLM_PROVIDER=google RENDERIFY_LLM_API_KEY=<your_key> pnpm playground
RENDERIFY_LLM_PROVIDER=google RENDERIFY_LLM_MODEL=gemini-2.5-flash RENDERIFY_LLM_BASE_URL=https://generativelanguage.googleapis.com/v1beta pnpm playground
# OpenAI Codex OAuth backend (does not require Codex CLI)
pnpm cli -- auth codex login
RENDERIFY_LLM_PROVIDER=openai-codex pnpm playground
RENDERIFY_LLM_PROVIDER=openai-codex RENDERIFY_LLM_MODEL=gpt-5.5 pnpm playground
RENDERIFY_LLM_PROVIDER=openai-codex RENDERIFY_LLM_MODEL=gpt-5.3-codex-spark pnpm playground
# Optional reasoning override (Spark defaults to low and supports low/medium/high/xhigh)
RENDERIFY_LLM_PROVIDER=openai-codex RENDERIFY_LLM_MODEL=gpt-5.3-codex-spark RENDERIFY_LLM_REASONING_EFFORT=medium pnpm playground
# Reuse the local Codex CLI login (~/.codex/auth.json) instead of `auth codex login`
RENDERIFY_LLM_PROVIDER=openai-codex RENDERIFY_CODEX_USE_CLI_AUTH=1 \
RENDERIFY_LLM_MODEL=gpt-5.3-codex-spark pnpm playground
# `only` uses the Codex CLI file exclusively; RENDERIFY_CODEX_CLI_AUTH_FILE / $CODEX_HOME
# override the path. Tokens are refreshed and written back in the Codex CLI's native format.
RENDERIFY_LLM_PROVIDER=openai-codex RENDERIFY_CODEX_USE_CLI_AUTH=only pnpm playground
# Single-shot LLM mode (avoid structured retry/text fallback + network retries)
RENDERIFY_LLM_MAX_RETRIES=0 RENDERIFY_LLM_STRUCTURED_RETRY=false RENDERIFY_LLM_STRUCTURED_FALLBACK_TEXT=false pnpm playground
# Runtime protocol/runtime safety env
RENDERIFY_RUNTIME_ENFORCE_MANIFEST=true pnpm playground
RENDERIFY_RUNTIME_ALLOW_ISOLATION_FALLBACK=false pnpm playground
RENDERIFY_RUNTIME_SPEC_VERSIONS=runtime-plan/v1 pnpm playground
RENDERIFY_RUNTIME_PREFLIGHT=true RENDERIFY_RUNTIME_PREFLIGHT_FAIL_FAST=true pnpm playground
RENDERIFY_RUNTIME_REMOTE_FETCH_TIMEOUT_MS=12000 RENDERIFY_RUNTIME_REMOTE_FETCH_RETRIES=2 pnpm playground
RENDERIFY_RUNTIME_REMOTE_FALLBACK_CDNS=https://esm.sh,https://cdn.jsdelivr.net pnpm playground
RENDERIFY_RUNTIME_BROWSER_SANDBOX_MODE=shadowrealm RENDERIFY_RUNTIME_BROWSER_SANDBOX_TIMEOUT_MS=4000 pnpm playground
RENDERIFY_RUNTIME_BROWSER_SANDBOX_FAIL_CLOSED=true pnpm playground
# Force text/TSX generation path instead of structured RuntimePlan
RENDERIFY_LLM_USE_STRUCTURED_OUTPUT=false pnpm playgroundThe playground listens only on 127.0.0.1 by default. Remote access requires an explicit --host <host> option or RENDERIFY_PLAYGROUND_HOST override; use a non-loopback binding only on a trusted network.
By default, playground prints outbound LLM request/response payload logs in terminal ([playground-llm]) with sensitive fields redacted. Use --no-llm-log or RENDERIFY_PLAYGROUND_LLM_LOG=false to disable.
When debug mode is enabled, playground logs key inbound/outbound request summaries, exposes GET /api/debug/stats, and shows an in-page Debug Stats panel with auto-refresh.
The playground always processes plans through the server's configured security/runtime boundary first. Eligible reviewed source.runtime: "preact" plans are then transpiled and mounted in the browser so hooks, React-compatible packages, CSS-in-JS, and event handlers remain interactive. Other source modes display the server-rendered result only. Hash payloads cannot bypass the active security profile. The optional display iframe is a presentation boundary, not a security boundary for arbitrary hostile source.
The playground can auto-render from URL hash payloads:
For bare imports (for example import { LineChart } from "recharts"), playground now auto-hydrates moduleManifest from JSPM resolution. You can still pass manifest64 to pin exact mappings.
PLAN64=$(node -e 'const plan={specVersion:"runtime-plan/v1",id:"hash_demo",version:1,root:{type:"element",tag:"div",children:[{type:"text",value:"Hello from hash plan"}]},capabilities:{}};process.stdout.write(Buffer.from(JSON.stringify(plan),"utf8").toString("base64url"));')
open "http://127.0.0.1:4317/#plan64=${PLAN64}"JSX64=$(node -e 'const code="export default function App(){ return <div style={{ padding: 16 }}>Hello hash JSX</div>; }";process.stdout.write(Buffer.from(code,"utf8").toString("base64url"));')
open "http://127.0.0.1:4317/#jsx64=${JSX64}&runtime=preact"# start playground
pnpm playgroundThen open the playground page and run this prompt:
Build an analytics dashboard with KPI toggle buttons and a multi-point bar chart
The playground now uses streaming prompt rendering (/api/prompt-stream), so you'll see incremental preview updates before final UI completion.
Core quick embed path (ir + runtime, default security checker included):
import { renderPlanInBrowser } from "@renderify/runtime";
import type { RuntimePlan } from "@renderify/ir";
const plan: RuntimePlan = /* LLM generated RuntimePlan */;
await renderPlanInBrowser(plan, { target: "#mount" });You can skip @renderify/llm entirely and pass plans from any external source (your backend, another SDK, or a different model provider):
import { renderPlanInBrowser } from "renderify";
const plan = {
specVersion: "runtime-plan/v1",
id: "renderer_only_demo",
version: 1,
root: {
type: "element",
tag: "div",
children: [{ type: "text", value: "Hello from BYO plan" }],
},
capabilities: { domWrite: true },
};
await renderPlanInBrowser(plan, { target: "#mount" });renderTrustedPlanInBrowser defaults to auto-pin-latest, so reviewed source modules can use bare imports:
import { renderTrustedPlanInBrowser } from "renderify";
const tsxPlan = {
specVersion: "runtime-plan/v1",
id: "renderer_only_tsx_datefns",
version: 1,
capabilities: { domWrite: true },
root: {
type: "element",
tag: "div",
children: [{ type: "text", value: "Loading..." }],
},
source: {
language: "tsx",
runtime: "renderify",
code: `
import { format } from "date-fns/format";
export default function App() {
return <section>Today: {format(new Date(), "yyyy-MM-dd")}</section>;
}
`,
},
};
await renderTrustedPlanInBrowser(tsxPlan, { target: "#mount" });For production determinism, prefer manifest-only (explicit pinned versions) and disable auto-pin:
const pinnedPlan = {
...tsxPlan,
moduleManifest: {
"date-fns/format": {
resolvedUrl: "https://ga.jspm.io/npm:date-fns@4.1.0/format.js",
version: "4.1.0",
},
},
};
await renderTrustedPlanInBrowser(pinnedPlan, {
target: "#mount",
autoPinLatestModuleManifest: false,
});Auto-pin-latest workflow (renderTrustedPlanInBrowser default for reviewed source):
Use manifest-only in production (autoPinLatestModuleManifest: false) when you want fully pre-pinned, reviewable dependency mappings.
Use the dedicated adapter when an MCP tool should display a portable interactive view. This path intentionally accepts a narrower contract than the general runtime: element/text RuntimePlans and local state transitions only.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerRenderifyApp } from "@renderify/mcp-app";
const server = new McpServer({ name: "dashboard", version: "1.0.0" });
await registerRenderifyApp(server, {
uri: "ui://dashboard/main",
name: "Dashboard",
toolName: "show_dashboard",
handler: () => ({
specVersion: "runtime-plan/v1",
id: "dashboard",
version: 1,
root: { type: "text", value: "Hello from MCP Apps" },
}),
});The handler's second argument is the official MCP request context, including authInfo, cancellation signal, session ID, and request metadata when supplied by the transport.
Runtime source, imports, component modules, network access, timers, persistent storage, and undeclared UI-to-tool calls fail closed. See the MCP Apps architecture and threat model.
| Package | Responsibility |
|---|---|
| renderify | Official top-level SDK facade (recommended app entry) |
| @renderify/ir | Runtime IR contracts (plan/node/state/action/event/capabilities) |
| @renderify/runtime | Runtime execution engine + JSPM loader + one-line embed API |
| @renderify/security | Policy profiles + plan/module/source static checks |
| @renderify/mcp-app | Official MCP Apps adapter for offline declarative RuntimePlans |
| @renderify/core | Legacy orchestration facade (optional compatibility layer) |
| @renderify/llm | LLM provider package (OpenAI + OpenAI Codex + Anthropic + Google + local providers) |
| @renderify/cli | CLI + browser playground |
The same documents are published as a searchable Fumadocs website.
Beyond the end-to-end pipeline, several components have standalone value:
MIT
| Back | FazBrowse Home | New Git URL |