The problem
Visual editors usually trap you in a proprietary format and an export step that drifts from your real codebase. I wanted to edit a running React app the way you would in Figma — but with the repository itself as the single source of truth. The catch: React 19 removed the fiber source-location debug data, so there's no reliable way to map a rendered element back to its source at runtime. The mapping has to be created at compile time, inside the bundler.
How it works
A Babel plugin — a pre-enforced Vite plugin, or a Turbopack loader on Next.js — stamps every JSX host element with a data-bikin="file:line:col" attribute and injects a runtime bridge into the page.
The injected bridge draws hover and selection overlays inside the iframe and speaks a postMessage protocol with the editor. Clicking surfaces the element's tag, component, and exact file:line:col, with an Open in editor deep link.
Edits land as surgical, format-preserving splices to the real file. The file is re-parsed before writing, so a broken edit never reaches disk — then HMR repaints the canvas.
Making it real
Getting from a working idea to something you can actually point at a project took more than the core edit loop:
Vite is the mature path — one pre-enforced plugin handles tagging, the bridge, and HMR. Next.js support (App Router + Turbopack) is newer and experimental, using a Turbopack loader for the same tagging.
Vite is zero-touch: the plugin is injected in-process, nothing on disk changes. Next.js gets persistent wiring instead — an idempotent, revertible codemod that wraps next.config and adds a client bridge import.
Packaged with Electron and shipped as a signed, notarized macOS .dmg, so it launches and drives the dev servers as an actual app rather than a pair of terminal commands.
A local-AI chat lets you describe a change in natural language and have an installed coding CLI — Claude Code, Codex, Cursor, or OpenCode — apply it, on a plan-then-apply flow.
Where it stands
This is a deliberately narrow v1: it edits static text and string-literal className values, and detects dynamic values — class expressions, interpolated children — to report them as non-editable rather than guess and corrupt the file. The natural next steps are broader edit coverage and reaching beyond Vite and Next.js.