T48k Docs · WebAssembly: the check, an app in the browser, the gallery build, embedding, what differs

This commit is contained in:
ZacharyZhang-NY committed 2026-10-01 13:22:53 -04:00
1 parent ca76311fd3
commit 15d2eb887f
2 files changed
+52 -1

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ import { Marked, type Tokens } from "marked";
const at = (relative: string) => fileURLToPath(new URL(relative, import.meta.url));
/** The guides in reading order, by file name. */
const ORDER = ["introduction", "installation", "getting-started", "theme", "focus", "motion", "icons", "overlays", "i18n"];
const ORDER = ["introduction", "installation", "getting-started", "theme", "focus", "motion", "icons", "overlays", "i18n", "webassembly"];
export interface Guide {
/** The path segment; the introduction has none. */
+51
View File
@@ -0,0 +1,51 @@
# WebAssembly
Ely builds for `wasm32-unknown-unknown` through `gpui_web`, Zed's browser platform for GPUI. The components page runs Ely's own gallery that way, in a canvas inside the page.
## Check the build
```sh
rustup target add wasm32-unknown-unknown
RUSTC_BOOTSTRAP=1 cargo check --lib --target wasm32-unknown-unknown
```
`gpui_web` uses an unstable feature for its threads, as Zed's own web examples do, so the check needs `RUSTC_BOOTSTRAP=1`.
## Start an app in the browser
The gallery's [web entry](https://github.com/ZacharyZhang-NY/Ely-GPUI-Components/blob/main/examples/gallery/web.rs) shows the steps:
| Step | Why |
| --- | --- |
| `#[wasm_bindgen(start)]` on the entry | The browser runs it when the module loads. |
| `gpui_platform::web_init()` | Sends panics and logs to the browser console. |
| `WebPlatform::new_with_backend_and_font_fallback(false, WebBackendPreference::Auto, CanvasFontFallback::EmojiAndCjk)` | One thread, since a static site gets no cross-origin isolation; WebGPU where the browser has it, WebGL2 where it does not; the browser lends fonts for emoji and CJK alone. |
| `Application::with_platform(platform)` | Then `with_http_client(Arc::new(platform.fetch_http_client()))`, `with_assets(Assets)` and `run`, as on the desktop. |
## Build the gallery
`ELY_GALLERY_ASSETS=<address>/ scripts/web.sh <out>` builds the gallery with the `web` profile, runs `wasm-bindgen` and `wasm-opt -Oz`, and copies its page and pictures beside it. It needs the `wasm-bindgen` CLI at the version in `Cargo.lock` and binaryen's `wasm-opt`, and it fails when the wasm passes Cloudflare's 25 MiB. `ELY_GALLERY_ASSETS` is the address the pictures are served from, ending in `/`: GPUI reads no files in a browser.
The gallery opens at `?page=<slug>&story=<title or slug>&theme=light|dark`. A story needs its page.
## Embed it in a page
| Message | Direction |
| --- | --- |
| `gallery.setTheme(mode)`, or `postMessage({ ely: "theme", theme })` | From the host, before the wasm runs or after. |
| `{ ely: "ready" }` | To the parent, once the gallery runs. |
| `{ ely: "failed", error }` | To the parent, after a start that failed three times. |
Until a press or a key reaches it, the embedded gallery keeps GPUI's hidden text field from taking focus, so a starting frame leaves the host page's focus alone. Tab inside GPUI cycles within its window; a host gives a way past the frame, as the components page does.
## What differs on the web
| Area | On the web |
| --- | --- |
| Threads | One. |
| Pictures | Fetched by address, never read from files. |
| Time | `web_time::Instant`; std's panics in a browser. |
| Paste | Arrives as the browser's paste event. Code that reads the clipboard itself awaits `read_from_clipboard_async`. |
| Accessibility | GPUI builds no accessibility tree in the browser. |
| Native only | The live terminal and the gallery's capture tool do not build for WebAssembly. |
| macOS only | The tray icon, the Dock badge and the web view return an error or say so, as on Windows and Linux. |