Guide

HTML generator code that renders, imports, and verifies before you see it

Most tools that bill themselves as an HTML generator emit a string and hope your browser likes it. mk0r is structured differently. It writes React plus TypeScript into a real Vite project, enforces a rule that every new component must be imported from App.tsx, and validates the rendered DOM in headless Chromium before the chat says "done." Here is how that pipeline is wired in the source.

m
mk0r
6 min
4.8from 10K+ creators
Vite + React + TS scaffold
App.tsx import enforced
Playwright DOM check

What "HTML generator code" usually means, and where mk0r diverges

Search "html generator code" and you mostly get two flavors of result: snippet libraries that paste a hero or a navbar into your clipboard, and one-shot AI tools that ask for a description and return a single self-contained HTML file. Both are fine for a landing page mockup. Both fall over the moment you want a counter, a fetch, a controlled form, or a second page.

mk0r treats HTML as the output of a real build pipeline, not as the medium the agent writes in. The agent writes components. Vite renders them to HTML. Playwright proves the result loads. You see the page after that round trip, not before.

The scaffold (exact commands)

When a session boots, the Freestyle VM init script provisions /app with this sequence (paraphrased from src/core/freestyle.ts lines 568 to 625):

cd /app npm create vite@latest . -- --template react-ts npm install npm install -D tailwindcss @tailwindcss/vite # rewrite vite.config.ts: wire @tailwindcss/vite plugin + HMR echo '@import "tailwindcss";' > src/index.css # install an HMR bridge that logs vite:beforeUpdate, vite:afterUpdate, # vite:beforeFullReload, vite:error into the page console cd /app && npx vite --host 0.0.0.0 --port 5173 &

The dev server runs continuously on port 5173 with HMR enabled. Every chat turn edits files inside this live project; the rendered HTML reloads in place.

The App.tsx import rule (the uncopyable part)

The single most common failure of code-generating agents is "wrote a beautiful component to a new file, never imported it, preview is blank." mk0r addresses this directly in the system prompt at src/app/api/chat/route.ts line 18:

ALWAYS edit /app/src/App.tsx to import and render any new components you create. Components that are not imported from App.tsx will never appear on screen. If you create src/components/Foo.tsx, open src/App.tsx and render <Foo /> in it.

That is in the prompt verbatim. It is one of seven workflow rules the agent must follow, and it is paired with rule 4 ("Open Chromium and navigate to http://localhost:5173 to verify the app works") and rule 5 ("Fix any errors you see in the browser or console").

The result, in practice: the agent does not just generate code, it also wires the entry point and proves the new HTML loads. You can grep the exact text in the repo if you want to verify.

See it for yourself

Open mk0r and type a one-line description. The Vite project, the App.tsx wiring, and the Playwright verification all happen behind the chat.

Open mk0r

Verification: Playwright MCP, not vibes

The agent has Playwright MCP attached. After editing files, it opens Chromium, navigates to http://localhost:5173, and reads the rendered DOM and console. The HMR bridge installed during scaffold logs four lifecycle events (vite:beforeUpdate, vite:afterUpdate, vite:beforeFullReload, vite:error), so the agent sees in the console whether its edit applied or blew up.

If the page throws, the agent fixes the file and retries before telling you the turn is done. So the HTML you eventually see has already passed through a real headless browser.

What the generated HTML actually looks like

Vite serves a tiny index.html with a single <div id="root"> and a script tag for /src/main.tsx. React mounts your component tree into that root, and the runtime DOM is your real "generated HTML." If you want a flat artifact, run npm run build inside the VM and ship /app/dist: that directory is plain HTML, hashed CSS, and hashed JS with no server requirement.

Either way, styling is Tailwind v4 via the @tailwindcss/vite plugin, so the generated HTML carries utility classes the agent can reason about, not bespoke CSS files it has to keep coherent.

When this is the wrong tool

If you want a single static .html file you can paste into a CMS box, this is overbuilt. Use a snippet library or a one-shot generator and move on. mk0r is for the case where you want the HTML to keep evolving, where turn 12 needs to be a real edit on the same code that turn 1 produced.

It is also overbuilt for a single hero section. Worth it the moment a button needs to do something.

Frequently asked questions

Does mk0r emit raw HTML or React?

It writes React plus TypeScript components into a Vite project at /app, and Vite serves the rendered HTML at port 5173. The bytes you see in the preview iframe are real, browser-evaluated HTML (with hydrated React on top), not a templated string.

What is the App.tsx import rule, and where is it enforced?

It is in the system prompt at src/app/api/chat/route.ts line 18: 'ALWAYS edit /app/src/App.tsx to import and render any new components you create. Components that are not imported from App.tsx will never appear on screen.' This catches the single most common failure mode of code-generating agents, namely creating a component file that nothing references.

How is the output verified before it is shown to me?

The system prompt instructs the agent to open Chromium via Playwright MCP, navigate to http://localhost:5173, and fix any errors visible in the browser or console before reporting completion. So the HTML the agent claims to have generated has actually been loaded and inspected in a real browser, not just written to disk.

What scaffold does the project start from?

The Freestyle VM init script runs 'npm create vite@latest . -- --template react-ts', installs Tailwind v4 via the @tailwindcss/vite plugin, rewrites vite.config.ts to wire the plugin and HMR, and writes a single '@import "tailwindcss";' line into src/index.css. The exact commands live in src/core/freestyle.ts around lines 568 to 625.

Can I just generate a static .html file?

Not directly from the chat. The architecture is opinionated: a Vite project that produces real HTML output through a real bundler. If you need a single static file, build the app (npm run build inside the VM) and ship the contents of /app/dist; that is plain HTML, CSS, and JS with no server runtime.

Why React+TypeScript instead of a flat HTML file like other generators?

Because the moment your generated HTML needs state (a form, a counter, a chart), a flat file forces the agent to inline scripts and keep them coherent across edits. A real component model lets each chat turn touch one file, not the whole document, and it lets HMR reload only the changed module instead of the whole page.

What is HMR doing in the loop?

Vite HMR is configured with explicit lifecycle hooks (vite:beforeUpdate, vite:afterUpdate, vite:beforeFullReload, vite:error) that log into the page console. The agent reads these via Playwright to confirm an edit actually applied. You can see the bridge script around src/core/freestyle.ts line 605.

Do I need an account to try this?

No. Open mk0r.com, type a description, and a fresh Freestyle VM provisions on the spot with the scaffold above. No email, no card, no setup.

Generate HTML through a real Vite project, with the App.tsx wiring and Playwright check baked in. No signup, no card.

Try mk0r