Self-host quickstart — render MIDL in your own app
MIDL is two halves you can use independently, in any Node/edge/browser project — no SvelteKit, no bundler required:
@wisepunk/renderer-html— turn a MIDL document into an HTML string (+ theme CSS).@wisepunk/sdk— manage pages over the authenticated write API (create / update / delete / read).
Both are on public npm under the @wisepunk scope — no auth, no .npmrc:
npm install @wisepunk/renderer-html @wisepunk/core @wisepunk/sdk
1. Render a MIDL document (no server needed)
import { renderMidl } from '@wisepunk/renderer-html';
const doc = {
midl: '0.1',
ns: { ui: 'https://midl.ai/ui#' },
frames: [
{ id: 'page', type: 'ui:Page', children: ['hero', 'cta'] },
{ id: 'hero', type: 'ui:Hero', title: 'Hello from my app' },
{ id: 'cta', type: 'ui:Button', text: 'Get started', variant: 'default' },
],
};
const { html, themeCss, validation } = renderMidl(doc, { pack: '@midl/pack-minimal-html' });
// → serve `html` (and `<style>${themeCss}</style>`) from your framework of choice.
Two packs ship today: @midl/pack-minimal-html (bare semantic tags, zero CSS) and
@midl/pack-tailwind-shadcn (Tailwind + shadcn variables). validation.valid tells you whether the doc
satisfied the pack's component manifests.
Wiring tailwind-shadcn (don't hand-write the var map)
The shadcn pack emits utility classes (bg-primary, text-muted-foreground, …) that resolve to the CSS
vars themeCss sets. Import the mapping instead of writing it by hand:
// tailwind.config.js
import { tailwindThemeExtend } from '@wisepunk/core';
export default {
content: ['./**/*.{html,js}'],
theme: { extend: tailwindThemeExtend() }, // colors → var(--…), borderRadius → var(--radius)
};
Important — let Tailwind see the pack's classes. The renderer emits utility classes (
flex-row,text-6xl,max-w-5xl, the heading scale, …) at runtime from the recipes inside@wisepunk/core, not from your own source — so Tailwind's content scanner won't find them and they'll be inert. Point it at the installed package. Tailwind v4 (CSS): add@source "../node_modules/@wisepunk/core/dist/**/*.js";next to@import "tailwindcss";. Tailwind v3: add the path tocontent, e.g.content: ['./**/*.{html,js}', './node_modules/@wisepunk/core/dist/**/*.js']. (Or safelist them.)
Theme tokens accept a plain string or { value } ({ 'colors.primary': '#34d399' }). Foregrounds are
auto-derived to pass WCAG AA against their background; override a derived one with its *.text key
(e.g. colors.muted.text, colors.primary.text). A document can also theme itself — a ui:StyleToken
frame's tokens are applied automatically when you don't pass options.theme.
2. Author + manage pages via the write API
Point the SDK at your MIDL deployment and use an API key (minted by an admin):
import { createClient } from '@wisepunk/sdk';
const midl = createClient({
baseUrl: 'https://your-midl-deployment.workers.dev',
apiKey: process.env.MIDL_API_KEY!,
});
const { id } = await midl.frames.create({ content: doc, slug: 'home' });
await midl.frames.update(id, { isActive: true });
const stored = await midl.frames.get({ slug: 'home' });
3. Put them together
A minimal Node handler that fetches a stored page and renders it:
import { createClient } from '@wisepunk/sdk';
import { renderMidl } from '@wisepunk/renderer-html';
const midl = createClient({ baseUrl: process.env.MIDL_URL!, apiKey: process.env.MIDL_API_KEY! });
export async function handler(slug: string): Promise<string> {
const page = await midl.frames.get({ slug });
const { html, themeCss } = renderMidl(page.frame.content, { pack: '@midl/pack-tailwind-shadcn' });
return `<!doctype html><html><head><style>${themeCss}</style></head><body>${html}</body></html>`;
}
That's the whole loop — author with the SDK, render with the renderer — entirely outside this repo. The standalone consumer smoke test runs exactly this against the published tarballs in CI, so the quickstart can't silently rot.
Reference
- Write API + auth details:
apps/web/docs/WRITE-API-MANUAL.md - Machine description:
GET /api/agents/openapi.jsonon your deployment. - SDK reference:
packages/sdk/README.md.