Live Preview stops blinking
Live Preview used to reload the whole page on every change, blank and back to the top. Now it updates in place. Getting there turned up a bug of my own making in how theme types are generated.
Mahfuz Shaikh2 min read

Live Preview shows a draft exactly as the site will render it, next to the editor. It worked by posting your unsaved values into the preview frame as a form, every time you stopped typing for a moment. Which meant every change reloaded the whole page: a blank flash, and you were back at the top.
Updating in place
The preview page is an Inertia page like any other, so it can fetch new props and let Vue patch only what changed. Now it works like this:
The first load is still a normal form post, so any theme works.
Once loaded, the preview tells the editor it can take changes in place.
After that, each change is sent as a message, and the preview page asks for its new props itself, keeping its scroll position and crossfading the change with a view transition.
A theme without Nibble's preview component in its layout never says it's ready, so it just keeps reloading the old way. Nothing breaks, it's just less smooth.

The bug I made myself
The first time I tried it on this site, the update crashed halfway through patching the header. The page was already failing to hydrate before any update; a full reload had only ever shown that as a warning in the console.
The cause was me. A theme's views get their props from generated types, and I had regenerated those types for a different theme while this site's development server was running. Vue reads those types when it compiles a view, so the post page lost two of its props. It rendered on the server, threw on the client, and the mismatch took the header with it. Regenerating the right types fixed all of it.
A ribbon, not a bar
Last touch: the preview is marked with a Preview ribbon across the top corner, which pulses while a change applies. It floats over the theme and takes no space, so the preview is the page, not the page with a bar stuck on it.