An open-source, self-hostable AI app generator and artifact runner, powered by open models (default: GLM-5.2) served via Nebius Token Factory.
Describe what you want — a single-page site, an interactive React component, a 3D scene, a data-analysis script, or a short video — and the model streams a structured "artifact" that runs entirely in your browser. No server sandbox, no per-run cloud compute bill: the only paid dependency is the Nebius API key.
| Artifact type | Runtime | Where it runs |
|---|---|---|
| HTML / SVG / Markdown / diagrams | sandboxed <iframe srcdoc> |
browser |
| React components & 3D (Three.js / R3F) | Sandpack | browser (CodeSandbox bundler, no API key) |
| Python (data analysis, matplotlib, code-interpreter) | Pyodide (CPython → WASM) | Web Worker |
| Video | ffmpeg.wasm (driven by a Python script via Pyodide) | Web Worker |
| Motion graphics (React) | Remotion @remotion/player (via Sandpack) |
browser (no API key) |
| Motion graphics (HTML/GSAP) | HeyGen HyperFrames @hyperframes/player web component |
browser (no API key) |
git clone <this repo>
cd open-artifacts
npm install
cp .env.example .env.local # add your NEBIUS_API_KEY
npm run dev # http://localhost:3000Get a Nebius Token Factory API key at https://tokenfactory.nebius.com → API keys → Create.
| Variable | Required | Default | Notes |
|---|---|---|---|
NEBIUS_API_KEY |
yes | — | Nebius Token Factory key |
ENABLE_CROSS_ORIGIN_ISOLATION |
no | false |
Set true to emit COOP/COEP headers for the faster multi-threaded ffmpeg core |
The default model id is not an env var — it lives in code as NEBIUS_DEFAULTS.modelId (lib/providers/nebius.ts) and in the picker list (lib/models.ts). Run curl -H "Authorization: Bearer $NEBIUS_API_KEY" https://api.tokenfactory.nebius.com/v1/models to find valid ids for your account, then add one to lib/models.ts.
The project is built test-first. Three layers:
npm test # Vitest unit + component tests (jsdom, no network)
npm run test:e2e # Playwright E2E in real Chromium (needs network for CDNs)
npm run typecheck # tsc --noEmitEach runtime has a dedicated E2E page (/e2e/html, /e2e/react, /e2e/react-3d, /e2e/python, /e2e/video, /e2e/remotion, /e2e/hyperframes) that renders a canned artifact and asserts it actually executes — e.g. that Pyodide prints stdout and renders a matplotlib figure, and that ffmpeg.wasm encodes a real, playable MP4.
flowchart LR
user[User prompt] --> chat["/api/chat (edge route)"]
chat -->|"chat.completions.create\n(official openai SDK, json_schema response_format)"| nebius["Nebius Token Factory\n(GLM-5.2, OpenAI-compatible)"]
nebius --> artifact["Structured Artifact JSON\n(type, files, deps)"]
artifact --> selector["ArtifactPanel\nselectRuntime(type)"]
selector --> htmlRt["iframe srcdoc\n(html / svg / markdown)"]
selector --> sandpackRt["Sandpack\n(react / 3D)"]
selector --> pyodideRt["Pyodide worker\n(python)"]
selector --> ffmpegRt["ffmpeg.wasm worker\n(video)"]
/api/chatis an edge-compatible route handler (app/api/chat/route.ts) that streams a structured artifact via the officialopenaiSDK'schat.completions.create({ stream: true, response_format: { type: "json_schema", ... } }), pointed at Nebius's OpenAI-compatible endpoint, and re-emits each delta as a newline-delimited JSON frame ({"type":"reasoning"|"content","text":"..."}) so the client can show live chain-of-thought progress separately from the artifact body. No Node-only APIs, so it runs on any serverless/edge free tier.- Provider registry (
lib/providers/nebius.ts) wraps the officialopenaiSDK's client with the Nebius base URL; adding other OpenAI-compatible providers is a few lines. - Streaming on the client (
lib/hooks/useObjectStream.ts) reads the response body as it arrives, accumulates the "content" frames, and re-parses them with a small hand-rolled partial-JSON repairer (lib/streaming/partial-json.ts) so the UI can render fields as they stream in — no third-party AI SDK on either side of the wire. - Pure runtime planners (
lib/runtime/*.ts) are fully unit-tested: schema validation, package splitting, srcdoc building, Sandpack file mapping, ffmpeg arg helpers. - Workers load Pyodide and the ffmpeg core from CDNs at runtime (their npm ESM builds pull in Node-only / nested-worker code that breaks browser bundling), keeping the app bundle small and the heavy wasm out of git.
The server side is just one streaming route with one env var, so any serverless free tier works.
A netlify.toml is included. The Next.js plugin (@netlify/plugin-nextjs) is auto-detected; set NEBIUS_API_KEY in Netlify's site env vars and deploy. Optional COOP/COEP headers for the multi-threaded ffmpeg core are commented in the file.
Import the repo — App Router + streaming work with zero config. Add NEBIUS_API_KEY in Project Settings → Environment Variables.
Use @cloudflare/next-on-pages; Workers' free-tier CPU limit doesn't count time spent waiting on the Nebius stream, making it the most timeout-resistant option for long generations.
app/
api/chat/route.ts edge streaming route (Nebius via the openai SDK, json_schema response_format)
e2e/<runtime>/page.tsx canned-artifact pages for runtime E2E tests
page.tsx, layout.tsx chat + artifact split-pane UI
components/
chat/ ChatPanel, ModelPicker (defaults to GLM-5.2)
artifact/ ArtifactPanel + HtmlPreview / ReactPreview / PythonPreview / VideoPreview
lib/
schema.ts Zod ArtifactSchema
providers/ Nebius OpenAI-compatible provider (official openai SDK client)
prompt.ts system prompt (per-type authoring rules)
models.ts model picker list (GLM-5.2 default)
hooks/useObjectStream.ts client-side fetch + streaming partial-JSON hook
streaming/partial-json.ts best-effort repair/parse of truncated JSON
runtime/ pure, tested planners (select-runtime, html-preview, sandpack-config, pyodide-plan, ffmpeg-args)
public/workers/ffmpeg-runner.js classic worker: Pyodide + ffmpeg.wasm from CDN
workers/pyodide.worker.ts module worker: Pyodide from CDN
- Isolation is the browser's own sandbox model (sandboxed iframe + Web Workers), not OS-level microVMs (E2B/Daytona). That's the right trade-off for a personal/local tool with no public multi-tenant exposure; the
selectRuntimeabstraction leaves room to add a server sandbox as another runtime later. - Sandpack uses CodeSandbox's free public bundler — no CSB API key required (keys are only needed to export sandboxes into a CodeSandbox project).
- ffmpeg.wasm uses the single-thread core by default so it runs anywhere; flip
ENABLE_CROSS_ORIGIN_ISOLATION=truefor the ~2-4x faster multi-threaded core.