The background download was one request from the first frame not held to the bundle's end. It added that whole span to its total again on every retry and after every pause (a hidden tab), so the page showed hundreds of MB. It also fetched again any frame that a read, or an earlier visit, had already brought in after that point. Now each request is a window of up to 4 MiB over a run of frames that are neither held nor in flight. What is held is checked again before every window. A frame cut in the middle is taken up from its next byte. A read's frame the download has not reached yet still goes out at once in its own request. The total is the compressed bytes of the frames this visit did not hold when the download began. Done is the part of them held by now, however it came. A frame whose store fails (the origin's quota) is held packed for the visit instead of being fetched again. Test: page/lazy-rest-ahead logs every byte the server sends and checks it against the bundle: a pause, a cut window, a read near the end at 10%, a cut first visit then a second, a cache that refuses every frame. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_853378b774d645b4ac78b16d9af91a31
web
gex in a browser: the runtime API (runtime/, the @gexemu/runtime
package, runtime/README.md, built by make runtime PKG=DIR), gex's test page (index.html,
src/harness.js), the library an ejected program ships, and the builds of
what they load:
- the browser shim, the shared kernel module and the seed, from
hosts/browserandhosts/kernel(build-assets.sh); - Mesa for wasm32, from the
third_party/mesasubmodule. It draws through Gallium'sgex_wgpudriver on the browser's WebGPU. A guest's GL calls reach it throughguest/glandports/mesa/src/gexgl-mesa.cpp(build-mesa-wasm.sh); - Xwayland as wasm32, which runs in a Worker of the page and talks to
hosts/hostwl(build-xwayland-wasm.sh); - the guest root filesystems come from the debdemo repository, which
writes them into
page/public/rootfs.
The two builds
| build | dist | threads | hosting |
|---|---|---|---|
| multi-process (default) | page/dist |
each guest thread is a Worker on shared memory | needs COOP/COEP (SharedArrayBuffer) |
| single-thread | page/dist-sp |
every guest thread is a fiber in one Worker | any static host |
Both builds load the same shim, kernel and seed. Each builds its own Mesa
and Xwayland, with or without -pthread. The dists ship stripped wasm.
Unstripped copies stay in target/web-debug/<mp|sp>/, and --debug ships
them instead.
$ make page # multi-process: page/dist
$ make page-sp # single-thread: page/dist-sp
$ make serve # page/dist at http://localhost:8088/, page/dist-sp at :8089
make page runs page/build.sh --mp. Its header lists the steps and
the options for building one part alone; make mesa, make xwayland and
make assets are three of them. Mesa comes from the third_party/mesa
submodule, which make mesa checks out.
The first Mesa build also builds Tint (tint/build-tint.sh), so it takes
much longer than later ones. Stripping needs wasm-tools
(cargo install wasm-tools).
Ejected programs
make eject-page DIR=... (build-eject-page.sh) builds the page library that
an ejected project ships. make eject-site PROJECT=... SITE=...
(eject-site.mjs) packs a built 32-bit Wine project into a static
site: the library, its runtime and Mesa, zstd-compressed assets, and the
headers the host must send. The site's index.html belongs to the project, so the
library can be imported into a page of your own.
Its API, start(), is in src/README.md. It is a preset over the runtime
API (src/run-program.js).