Skip to content

spike: two stacked webviews, to find out if the substrate holds - #119

Open
zmaril wants to merge 3 commits into
mainfrom
spike/webview-stack
Open

spike: two stacked webviews, to find out if the substrate holds#119
zmaril wants to merge 3 commits into
mainfrom
spike/webview-stack

Conversation

@zmaril

@zmaril zmaril commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Not compiled, not run. No WebKit toolchain and no display on this machine, and build_as_child is macOS / Windows / X11 only regardless. This is a thing to run on your Mac, built so one command answers the questions instead of you having to design the test.

cd spike/webview-stack && cargo run

The setup

One window, two child webviews. The lower one loads github.com — chosen because it sets X-Frame-Options: DENY, so if it renders then this is definitively not an iframe, which is the premise everything else rests on. The upper one is transparent and holds the chrome that has to draw over it.

A shim is injected into the page before it loads. It's keymap.js and contextmenu.js with the transport swapped — window.ipc.postMessage instead of dioxus.send — and it claims only the keys the workbench asks for, leaving the rest to the page. That's the difference between embedding a page and breaking it. Matching in the guest rather than posting every keystroke is the same one-message-per-meaningful-event budget everything else here holds to.

What it answers on its own

PASS  a page that refuses to be framed rendered, and our script ran inside it
PASS  a chord pressed inside that page reached the host
PASS  a right-click inside that page reached the host
PASS  a click reached the page with the overlay idle

What only you can answer

Did the magenta frame and the menu draw above the page, and could you read the page through the dimmed backdrop? z-order and transparency — the pair that decides the architecture, and the thing no program can check. macOS is reported to handle this well; Windows is where wry's transparency bugs live (#1540).

The p key is the question behind the question

The overlay is hidden between uses rather than made click-through, because hiding needs no platform code and click-through needs an NSView hitTest: override on macOS.

Fine for menus and modals, which are transient. Not fine for a tooltip that follows the pointer. p holds the overlay up and empty so you can find out whether clicks reach the page through a transparent webview anyway — free persistent chrome if they do, interop if they don't, and much better to know now.

Notes

  • Outside the workspace (root manifest gains exclude), so wry and a WebKit toolchain never touch the lockfile CI resolves. Nothing about the existing build changes.
  • Deliberately agnostic about Dioxus-vs-GPUI. It proves the substrate, not the choice.
  • What's actually verified here: both injected scripts parse (bun build), and two tests pin the seams this kind of code rots at — the JSON kinds the scripts emit vs. the enum that receives them, and the imOverlay functions the host calls by name vs. the ones the overlay defines. They need a machine that can build wry to run.

Everything else is unverified, including whether it compiles. If it doesn't, the likely culprits are the winit 0.30 ApplicationHandler shape and the dpi re-export path — both cheap to fix once a compiler has seen them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XjCx5QszLXroGYh1YBxybw

@github-actions

Copy link
Copy Markdown

powderman preview

https://powderman-pr-119.fly.dev

The workbench, live: split/join/swap areas, the F3 palette, the widgets, themes, tooltips, the status bar.
The fleet and run execution are inert here (a Fly machine has no herdr) — this is for driving the interface.

On branches with the MCP server, point an agent at it:

claude mcp add --transport http powderman-preview "https://powderman-pr-119.fly.dev/mcp"

Updated on every push. Destroyed when this PR closes.

zmaril and others added 3 commits August 21, 2026 16:42
The question is whether a native shell can host real web pages as areas
without giving up the chords and the right-click menu. Three things have to
be true, and only one of them is a matter of opinion.

One window, two child webviews. The lower one loads github.com — chosen
because it sets X-Frame-Options: DENY, so if it renders then this is
definitively not an iframe, which is the premise everything else rests on.
The upper one is transparent and holds the chrome that has to draw over it.

A shim is injected into the page before it loads. It is keymap.js and
contextmenu.js with the transport swapped — window.ipc.postMessage instead
of dioxus.send — and it claims only the keys the workbench asks for,
leaving the rest to the page, which is the difference between embedding a
page and breaking it. Matching in the guest rather than posting every
keystroke is the same one-message-per-meaningful-event budget the rest of
the workbench holds to.

Four of the five questions the program answers out loud: the page rendered,
a chord got out of it, a right-click got out of it, a click still reaches
it. The fifth — does the overlay draw above the page, transparently — is
the one that decides the architecture and the one nothing can check for
you, so the overlay draws a magenta frame and a dimmed backdrop and the
program tells you to look at it.

The `p` key is the question behind the question. The overlay is hidden
between uses rather than made click-through, because hiding needs no
platform code and click-through needs an NSView hitTest: override. That is
fine for menus and modals; it is not fine for a tooltip that follows the
pointer. `p` holds the overlay up and empty so you can find out whether
clicks pass through a transparent webview anyway — free persistent chrome
if they do, interop if they do not, and better to know now.

Outside the workspace, because it drags in wry and a WebKit toolchain and
neither belongs in the lockfile every CI run resolves.

Not compiled and not run: no WebKit toolchain and no display here, and
build_as_child is macOS / Windows / X11 only regardless. Both injected
scripts parse, and two tests pin the seams this kind of thing rots at — the
JSON kinds the scripts emit against the enum that receives them, and the
imOverlay functions the host calls by name against the ones the overlay
defines.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjCx5QszLXroGYh1YBxybw
apt landed, so the two suspects got checked: the winit 0.30
ApplicationHandler shape and the dpi re-export path were both fine. One
unused import, and cargo check / clippy / test are clean against wry 0.56
and winit 0.30.

What is still unverified is everything that needs a screen — whether the
overlay is transparent, whether it stacks above, whether clicks pass
through it, and whether the injected shim really takes the keys back from a
live page. Those were always the point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjCx5QszLXroGYh1YBxybw
straitjacket [color]. They are the instrument rather than a style — a
magenta that cannot be mistaken for part of the page beneath is the whole
z-order test — and pointing them at theme tokens would make the spike
depend on the library whose substrate it exists to check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjCx5QszLXroGYh1YBxybw
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant