html-docs · what changed

Beautify, smoother — and ready for bigger docs

The AI document features got a run of upgrades: pluggable model providers, an instant Apply, a live‑streaming preview that no longer flickers, support for much larger documents, and a Docsmith chat that knows the house style and actually streams.

branch main · Jun 2026

01 — the headline

The live preview stopped flickering

The streaming preview used to re‑set the iframe’s srcDoc on every chunk — which fully reloads the iframe. That meant a white flash and a scroll reset several times a second, plus a stretch of raw ```html and unstyled text before anything looked right.

Before · srcDoc reload per chunk
reload ⟳ flash
Every token batch reloaded the whole iframe — flash, flicker, jump to top.
After · write once, patch <body>
in‑place ✓ smooth
Shell written once (styles applied); only body.innerHTML updates as content grows.
Fig. 1 — Same stream, two rendering strategies. The right one never reloads the document, so it grows smoothly with no flash.

And before the document is renderable at all, you now get a skeleton placeholder instead of raw text — the leading markdown fence is stripped, and we wait until the model has emitted <head>/<style> and a <body> before swapping the skeleton for the live document.

Generateoverlay opens
Skeleton“designing layout…”
Live documentstyled · body grows
Final swapimages · Tailwind
Fig. 2 — The new sequence: overlay → skeleton (no raw fence) → styled live render → one clean swap to the finalized HTML.

02 — how streaming works

Tokens flow from the model to the screen

A new SSE route streams the generation; the dialog renders it live. The final done event carries the finalized HTML, so Apply stays instant — it persists that, no second generation.

Dialoglive iframe /api/beautify/previewSSE route streamBeautifyModelprovider stream Model event: delta → skeleton, then patched into the live document event: done → finalized HTML (images restored, Tailwind compiled) → Apply
Fig. 3 — All three providers stream their tokens; the dialog patches them in, the route finalizes at the end.

03 — pluggable providers

Pick the engine from a dropdown

A Model selector routes the request to one of three engines; OpenAI stays the default, so nothing changes unless you pick another.

Beautify dialogModel ▾
callBeautifyModeldispatch(provider)
OpenAI · default
Chat Completions · OPENAI_API_KEY
Claude · Anthropic
Messages API (SDK, streaming) · ANTHROPIC_API_KEY
OpenInfer
Responses API (SSE) · @oi/beta · OPENINFER_API_KEY
OpenAIClaudeOpenInfer
Fig. 4 — One dispatcher, three engines. Each needs only its own key; OpenInfer is also selectable in the Docsmith chat.

04 — fix

Apply is a DB write, not a second generation

Before

▸ Preview → full model run

▸ Apply → full model run again → “Applying…” hangs

After

▸ Preview → model run, HTML kept

▸ Apply → reuse the previewed HTML → near‑instant

The previewed HTML rides through to beautifyDocument(…, precomputedHtml), which persists it directly. The rollback snapshot still runs, so Version History is unchanged.

05 — bigger documents

The whole doc makes it through

Two limits were cutting large docs short: the input was capped low (long docs were rejected), and Claude’s output was capped (the beautified tail truncated mid‑document). Both are raised — safe, since our models have huge context windows and we stream.

Input cap — source document120k → 300k chars
old 120k
Output cap — Claude (streamed)32k → 64k tokens
old 32k
old limitnew limit
Fig. 5 — Input ~75k tokens of source now fits; Claude output room doubled so long documents aren’t truncated. OpenAI output stays uncapped.

06 — docsmith chat

House‑style aware, richer inserts, real streaming

feature

Knows the design system

The chat carries the same DESIGN_SYSTEM Beautify uses — it no longer asks you to “share your design principles.”

feature

Diagram & table inserts

Insertable tags widened to div and table, so it can add styled containers and tables instead of coercing them to <p>.

fix

Streams again

Added X‑Accel‑Buffering: no + no‑transform so proxies stop holding the SSE reply and dumping it at once.

07 — timeline

What landed, in order

Model/provider selector for Beautify
6ad775b
OpenInfer in Docsmith chat
a7b1089
Fix: Apply re‑ran the model → reuse preview HTML
96fbd59
Docsmith design system + div/table inserts
a95ab2b
Live‑streaming Beautify preview
7f65e7c
Fix: Docsmith stream buffering
ed1eadb
Beautify: larger input + output limits
9c9106c
Smoother preview: skeleton + in‑place updates
771fd6a
Config reminder

API keys are server env vars (.env.local locally, Vercel settings in prod) — not stored in Supabase. Each provider reads only its own key.

html-docs · Beautify & Docsmith — streaming & large-doc upgrades