Visual editor
A visual editor for your codebase, not a copy of it
Open your project's own .test URL in your own browser. PortBay injects an edit bar into the page, and the element you click resolves to a file, a line and a column you can edit in place.
Hard-wearing gear, quietly designed. Free shipping over $75.
Shop the dropHarbour tote
Trail pant
Wool crew
Finding the element by handThe loop it replaces: guess the file, grep a string you hope is unique, edit, alt-tab back to check.
Start the project and visit its .test hostname in Chrome, Safari or anything else. The bundled Caddy edge routes the page through PortBay's edit proxy, which injects the bar into a shadow root. There is no app webview and nothing to open on the side.
button.cta → partials/hero.blade.php:12:9
The bar switches from Preview to Inspect to Edit. Selecting an element resolves it to an authored coordinate — the file, line and column that produced it — through five anchor tiers, starting with the dev plugin's location stamp and falling back through a unique id, tag plus DOM ordinal, and more when it is absent.
Visual edit history
Kept 30 daysA snapshot is taken before every apply. Restoring rolls the touched files back to the state before that apply — behind a diff, like everything else.
listings.blade.php · partials/hero.blade.php
home.blade.php
resources/views/ — four templates
Text, classes, attributes and styles, plus structural edits — insert, delete, duplicate, move. Double-click to type into the page directly. The right-hand rail carries layout, spacing, typography, borders and effects, and a Tailwind token you rename is rewritten everywhere it is referenced in the same save.
Round the listing CTA and warm its border.
Done. Two files, 23 bytes. Nothing else moved — open the diff?
The write goes through the same engine the in-app Apply uses: a surgical splice into the byte span, never a parse-and-reprint. Comment placement, quote style, trailing commas and key order outside the patched span come back byte-identical.
Tokens
Brand
Surface
Every save sits on a shadow-git checkpoint kept outside your own history. The Diff button shows the working diff against it, and revert restores the pre-apply snapshot — per edit or all of it.
What one click reaches
The bar is injected into your own page at your own .test URL. Each of these writes into the file that produced the element you clicked.
Point at the element
Selecting it resolves to a file, a line and a column, through five anchor tiers starting at the dev plugin's location stamp.
Rename the token once
Text, classes, attributes and styles. A Tailwind token you rename is rewritten across the project's authored markup in the same save.
Insert, delete, move
Structural edits splice into the source the same way. Page settings cover title, description, robots and JSON-LD on 19 of the 21 stacks.
...and so
much more
rounded-md → rounded-full
14 bytes written · nothing else moved
og:image /og/listing.png
canonical /shop/harbour-tote
application/ld+json Product
Desktop — base breakpointGet started
PortBay resolves the element you clicked to a file, line and column across 21 stacks, and replaces only the bytes that changed.
Frequently asked questions
Don’t see your question answered here? The docs go deeper — every feature, flag and failure mode.
Read the docsThree ways, and one of them favours Onlook. PortBay writes by splicing the exact byte span in your file, so authored formatting survives and no marker attribute is added to your source; Onlook writes data-oid attributes into your files and reprints them through Prettier. PortBay runs locally against your own dev server on 21 stacks including Laravel, Rails, Django and WordPress; Onlook is Next.js plus Tailwind in a cloud sandbox. In Onlook's favour: it has a multi-frame infinite canvas and PortBay does not. PortBay has one breakpoint canvas, that was a deliberate decision rather than a missing feature, and a designer who works across frames will notice immediately.
No marker lands in your files. The fastest way to identify an element is a data-pb-loc location stamp, and that is applied by the dev-server transform on the way to the browser, never written back into your source. When the stamp is not there the edit is not refused: four more anchor tiers follow it, starting with a unique id that matches exactly one opening tag across the project's authored markup, then tag plus the captured DOM ordinal.
Twenty-one, checked by a standing test rather than a README: static HTML, React, Vue, Svelte, Next.js, Astro, Angular, Remix, Nuxt, SolidStart, Qwik, Laravel, Livewire, Inertia, Rails, Django, WordPress, WordPress block themes, Hugo, Jekyll and Eleventy. The test drives four write lanes — text, attribute, class and page settings — against every one of them and reads the changed bytes back off disk, and any lane that cannot work on a stack has to refuse in a sentence the test checks for. Page settings is the one lane with real gaps: both WordPress rows refuse it.
Yes, through the same write-back engine over MCP. portbay_editor_apply is a two-step tool: the agent calls it with dryRun first and gets back the exact set of files the planner would write, which is not just the files it named, then calls again passing every one of those paths back as an exact consent list. If the list does not match the plan the call refuses and writes nothing. The real write also blocks on a human approval, and returns a snapshot id that undoes exactly that apply.
No. It ships in the app — there is no plan to buy and no opt-in to turn on. It is macOS only, and it will not run while the project is shared over a public tunnel: a project with a running tunnel is dropped from the eligible set so the edit bar and its write endpoints never answer public traffic.








