Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .github/workflows/desktop-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Linux gpui host

on:
pull_request:
paths:
- ".github/workflows/desktop-linux.yml"
- "contracts/spec/**"
- "engine/core/**"
- "engine/crates/pocket-mod/**"
- "engine/crates/pocket-ui-surface/**"
- "engine/backends/gpui/**"
- "hosts/desktop/**"
- "hosts/web/app-instance.*"
- "hosts/web/system-engine.js"
- "hosts/web/wasm-ops.js"
- "framework/src/manifest/**"
- "tests/platform-contracts.test.ts"
- "tests/pocket-system.test.ts"
- "tests/web-system-host.test.ts"
push:
branches: [main]
paths:
- ".github/workflows/desktop-linux.yml"
- "contracts/spec/**"
- "engine/core/**"
- "engine/crates/pocket-mod/**"
- "engine/crates/pocket-ui-surface/**"
- "engine/backends/gpui/**"
- "hosts/desktop/**"
- "hosts/web/app-instance.*"
- "hosts/web/system-engine.js"
- "hosts/web/wasm-ops.js"
- "framework/src/manifest/**"
- "tests/platform-contracts.test.ts"
- "tests/pocket-system.test.ts"
- "tests/web-system-host.test.ts"
workflow_dispatch: {}

permissions:
contents: read

jobs:
linux:
name: linux-app build + X11 smoke
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v7

- name: Install gpui Linux dependencies
run: >-
sudo apt-get update && sudo apt-get install -y --no-install-recommends
clang cmake pkg-config libasound2-dev libfontconfig-dev libglib2.0-dev
libssl-dev libvulkan1 libwayland-dev libx11-xcb-dev
libxkbcommon-x11-dev libzstd-dev mesa-vulkan-drivers xvfb xauth

- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
targets: wasm32-unknown-unknown

- uses: Swatinem/rust-cache@v2
with:
workspaces: |
engine/backends/gpui
hosts/desktop
engine/wasm

- uses: oven-sh/setup-bun@v2

- run: bun install --frozen-lockfile

- name: Linux, web and System contract tests
run: bun test tests/platform-contracts.test.ts tests/pocket-system.test.ts tests/web-system-host.test.ts

- name: Resolve and build the note for linux-app
run: |
bun -e '
import { validateAndResolveBuildPlan } from "./framework/src/manifest/resolve.ts";
import { mkdirSync } from "node:fs";
const manifest = await Bun.file("apps/note/pocket.json").json();
const result = validateAndResolveBuildPlan(manifest, { target: "linux-app" });
if (!result.ok) throw new Error(JSON.stringify(result.diagnostics));
mkdirSync(".pocket/linux-app", { recursive: true });
await Bun.write(".pocket/linux-app/note-main.plan.json", JSON.stringify(result.plan, null, 2) + "\n");'
bun tools/build.ts --plan=.pocket/linux-app/note-main.plan.json

- name: Rust format, lint and tests
run: |
cargo fmt --check --manifest-path hosts/desktop/Cargo.toml
cargo clippy --locked --manifest-path hosts/desktop/Cargo.toml -- -D warnings
cargo test --locked --manifest-path hosts/desktop/Cargo.toml

- name: Build linux-app release host
run: cargo build --release --locked --manifest-path hosts/desktop/Cargo.toml

- name: Launch linux-app under X11 with software Vulkan
env:
POCKETJS_DIST: ${{ github.workspace }}/dist
run: >-
timeout 30s xvfb-run -a hosts/desktop/target/release/pocket-desktop-host
--app note-main --title Note --viewport 720x480 --density 1
--native-text --companions note --editor --file /tmp/pocket-note.md
--quit-after 20
27 changes: 17 additions & 10 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: macOS gpui backend

# The first macOS lane in CI: the gpui backend (engine/backends/gpui) and
# the macos-app host (hosts/macos) are standalone crates excluded from the
# ubuntu release workspace, so this is the only place they build. The lane
# the macos-app host (hosts/desktop) are standalone crates excluded from the
# release workspace. This lane pins the macOS build while desktop-linux.yml
# pins the same crate on Linux. The lane
# also runs the TS surfaces its path filter watches (contract drift, the
# platform/note/font-bake tests, and a real macos-app plan+bundle build of
# the note). gpui needs a window server for anything more; runtime behavior
Expand All @@ -18,20 +19,23 @@ on:
- "engine/crates/pocket-ui-surface/**"
- "engine/backends/gpui/**"
- "engine/wasm/**"
- "hosts/macos/**"
- "hosts/desktop/**"
- "tools/macos.ts"
- "framework/src/components*.ts*"
- "framework/src/host.ts"
- "framework/src/native-tree.ts"
- "framework/src/primitives.ts"
- "framework/src/manifest/**"
- "hosts/web/wasm-ops.js"
- "hosts/web/app-instance.*"
- "hosts/web/system-engine.js"
- "apps/note/**"
- "framework/compiler/**"
- "assets/fonts/**"
- "tests/platform-contracts.test.ts"
- "tests/note.test.ts"
- "tests/pocket-system.test.ts"
- "tests/web-system-host.test.ts"
- "tests/font-bake.test.ts"
- "tests/npm-package.test.ts"
- "package.json"
Expand All @@ -45,20 +49,23 @@ on:
- "engine/crates/pocket-ui-surface/**"
- "engine/backends/gpui/**"
- "engine/wasm/**"
- "hosts/macos/**"
- "hosts/desktop/**"
- "tools/macos.ts"
- "framework/src/components*.ts*"
- "framework/src/host.ts"
- "framework/src/native-tree.ts"
- "framework/src/primitives.ts"
- "framework/src/manifest/**"
- "hosts/web/wasm-ops.js"
- "hosts/web/app-instance.*"
- "hosts/web/system-engine.js"
- "apps/note/**"
- "framework/compiler/**"
- "assets/fonts/**"
- "tests/platform-contracts.test.ts"
- "tests/note.test.ts"
- "tests/pocket-system.test.ts"
- "tests/web-system-host.test.ts"
- "tests/font-bake.test.ts"
- "tests/npm-package.test.ts"
- "package.json"
Expand All @@ -85,7 +92,7 @@ jobs:
with:
workspaces: |
engine/backends/gpui
hosts/macos
hosts/desktop
engine/wasm

- uses: oven-sh/setup-bun@v2
Expand All @@ -94,7 +101,7 @@ jobs:
run: bun install --frozen-lockfile

- name: Contract + System + note + platform + npm package tests
run: bun test tests/platform-contracts.test.ts tests/pocket-system.test.ts tests/note.test.ts tests/font-bake.test.ts tests/npm-package.test.ts && bun tests/contract.ts
run: bun test tests/platform-contracts.test.ts tests/pocket-system.test.ts tests/web-system-host.test.ts tests/note.test.ts tests/font-bake.test.ts tests/npm-package.test.ts && bun tests/contract.ts

- name: Compile the note against macos-app (plan + bundle + pak)
run: |
Expand All @@ -117,13 +124,13 @@ jobs:
- name: rustfmt
run: |
cargo fmt --check --manifest-path engine/backends/gpui/Cargo.toml
cargo fmt --check --manifest-path hosts/macos/Cargo.toml
cargo fmt --check --manifest-path hosts/desktop/Cargo.toml

- name: Clippy gpui backend
run: cargo clippy --locked --manifest-path engine/backends/gpui/Cargo.toml -- -D warnings

- name: Clippy macos-app host
run: cargo clippy --locked --manifest-path hosts/macos/Cargo.toml -- -D warnings
- name: Clippy native desktop host
run: cargo clippy --locked --manifest-path hosts/desktop/Cargo.toml -- -D warnings

- name: Build macos-app host
run: cargo build --locked --manifest-path hosts/macos/Cargo.toml
run: cargo build --locked --manifest-path hosts/desktop/Cargo.toml
52 changes: 51 additions & 1 deletion contracts/spec/platforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ export const POCKET_TARGETS = defineTargetRegistry<PocketCapabilityId, {
readonly pocketbook: TargetProfile<PocketCapabilityId>;
readonly "macos-widget": TargetProfile<PocketCapabilityId>;
readonly "macos-app": TargetProfile<PocketCapabilityId>;
readonly "linux-app": TargetProfile<PocketCapabilityId>;
readonly "web-app": TargetProfile<PocketCapabilityId>;
}>({
psp: {
hostAbi: 1,
Expand Down Expand Up @@ -308,7 +310,7 @@ export const POCKET_TARGETS = defineTargetRegistry<PocketCapabilityId, {
"text.glyphs.runtime",
],
},
// The gpui app frame (hosts/macos is the stock host): a resizable ordinary
// The gpui app frame (hosts/desktop is the stock host): a resizable ordinary
// window on Zed's gpui/Metal, painting the DrawList as vector quads and
// host-shaped text instead of rasterized atlas cells (docs/BACKENDS.md).
// HostAbi 4 adds the independent compositor-surface op. An app frame, not a
Expand Down Expand Up @@ -343,6 +345,54 @@ export const POCKET_TARGETS = defineTargetRegistry<PocketCapabilityId, {
systemUI: ["ui.compositor-surfaces"],
},
},
// The same gpui AppSupervisor/compositor host on Linux. Linux defaults to
// one raster sample per logical pixel while keeping native text layout and
// the same dynamic/fixed application admission contract as macOS.
"linux-app": {
hostAbi: 4,
platform: "linux",
form: "window",
display: {
physicalViewport: [1280, 800],
logicalViewports: [[800, 600]],
dynamicViewport: { min: [240, 180], max: [4096, 4096], acceptsFixed: true },
presentations: ["native"],
rasterDensity: 1,
},
capabilities: [
"input.buttons",
"display.viewport.live",
"text.glyphs.baked",
"text.layout.native",
],
roleCapabilities: {
systemUI: ["ui.compositor-surfaces"],
},
},
// Browser Pocket System host: one iframe JavaScript Realm and one wasm Ui
// per package, scheduled and composited by hosts/web/system-engine.js. The
// shell viewport follows the browser canvas; acceptsFixed admits installed
// console-shaped applications inside compositor surfaces.
"web-app": {
hostAbi: 4,
platform: "web",
form: "window",
display: {
physicalViewport: [800, 600],
logicalViewports: [[800, 600]],
dynamicViewport: { min: [320, 240], max: [4096, 4096], acceptsFixed: true },
presentations: ["native"],
rasterDensity: 1,
},
capabilities: [
"input.buttons",
"display.viewport.live",
"text.glyphs.baked",
],
roleCapabilities: {
systemUI: ["ui.compositor-surfaces"],
},
},
});

export type PocketTargetId = TargetId<typeof POCKET_TARGETS>;
Expand Down
41 changes: 28 additions & 13 deletions docs/BACKENDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ hosts, the PSP GE walker, the ESP32-P4 PPA and Symbian GLES2 ports.
## The gpui backend

`engine/backends/gpui` (`pocket-ui-gpui`) paints the same DrawList through
[gpui](https://gpui.rs) — Zed's Metal renderer — and is embedded by
`hosts/macos`, the stock host of the `macos-app` target. Boxes, gradients
[gpui](https://gpui.rs) — Zed's native GPU renderer — and is embedded by
`hosts/desktop`, the stock host of the `macos-app` and `linux-app` targets. Boxes, gradients
and images become antialiased vector quads instead of upscaled raster;
text can come from the host text system.

- **Text layout is a host capability, opted into per app.** An app that
`enhances: ["text.layout.native"]` gets a core text measurer installed
before the guest mounts (`Ui::set_text_measure`): taffy leaf sizes, the
`measureText` op and painted glyphs all come from one provider — CoreText
through gpui's text system. Codepoint coverage is the OS font fallback
through gpui's platform text system. Codepoint coverage is the OS font fallback
chain (CJK, emoji, everything), with **no runtime atlas baking and no
tofu**.
- **The op is `TEXT_RUN` (9).** With a measurer installed, translation-only
Expand Down Expand Up @@ -95,13 +95,13 @@ instead of `text.glyphs.baked` — and why gpui-hosted apps verify like the
note does (pure-math unit tests over an injected measurer, sim traces,
`--proof` acceptance runs) instead of joining `tests/golden-specs.ts`.

## The `macos-app` target
## Native desktop targets

`contracts/spec/platforms.ts` registers the profile: hostAbi 4 (the
compositor-surface wire generation), `form: "window"`,
dynamic viewport with `acceptsFixed` — a general app frame, not a widget
shell. Fixed-viewport console apps run size-locked and letterboxed with
their baked glyph pipeline intact; the manifest decides everything else:
`contracts/spec/platforms.ts` registers `macos-app` and `linux-app` at
hostAbi 4 with `form: "window"`, a dynamic viewport and `acceptsFixed`.
Both profiles use the same generic host. macOS resolves density 2; Linux
resolves density 1. Fixed-viewport console apps run size-locked and
letterboxed with their baked glyph pipeline intact.

```
bun run macos note # dynamic viewport, native text, svc editor protocol
Expand All @@ -119,9 +119,24 @@ viewport or title fields.
`--editor` is NOT a capability: it enables the note's companion svc adapter
(an app protocol — the profile deliberately registers no
pointer/text/IME/clipboard ids, see contracts/spec/platforms.ts). On exit
the host prints its governor receipt (`pocket-macos: N ticks, M frames
the host prints its governor receipt (`pocket-desktop-host: N ticks, M frames
rendered`); a settled app shows M ≪ N.

## Browser System host

**`web-app` runs every package in an independent same-origin iframe
JavaScript Realm with its own wasm `Ui`.** `hosts/web/system-engine.js`
derives the package catalog, surface handles and lifecycle policy from one
`ResolvedSystemPlan`. Live shell bindings create and remove AppInstances;
focus and visible painter order determine scheduling.

The wasm software compositor retains each visible child framebuffer and
replaces `SURFACE_QUAD` with a texture quad only during the host render.
Full bounds determine the child coordinate origin, clip bounds constrain the
visible pixels, and the instruction remains at its original DrawList offset.
Shell chrome emitted after the surface therefore stays above the child. A
missing child raster leaves the shell's loading fallback visible.

## System UI companion input

The host speaks the `system-ui` svc dialect when the resolved System UI plan
Expand All @@ -145,7 +160,7 @@ System UI role and background-execution policy. **Every installed entry
reaches the native host as a complete `ResolvedBuildPlan`; ordinary
applications resolve without the System UI-only compositor capability.**

- **`hosts/macos` implements a generic `AppSupervisor`; the System contract
- **`hosts/desktop` implements a generic `AppSupervisor`; the System contract
does not expose that implementation.** The host contains no product catalog
or package-name rules. Live `<CompositorSurface package>` bindings create
one AppInstance with its own `Guest`, QuickJS `Runtime`, QuickJS `Context`,
Expand Down Expand Up @@ -174,8 +189,8 @@ X,Y[,d|u|r]@TICK` (drags, right clicks), `--key

| | portable | gpui |
| ------------------ | ---------------------------------------------------------------- | ------------------------------------------- |
| hosts | PSP, Vita, PocketBook, ESP32-P4, Symbian, web, sim, macOS widget | macOS (`hosts/macos`) |
| text measurement | core, atlas advance tables | host text system (CoreText), per-app opt-in |
| hosts | PSP, Vita, PocketBook, ESP32-P4, Symbian, web, sim, macOS widget | macOS and Linux (`hosts/desktop`) |
| text measurement | core, atlas advance tables | gpui platform text system, per-app opt-in |
| codepoint coverage | baked charset (+ runtime extension) | OS fallback chain, color emoji |
| pixel determinism | byte-exact across hosts | per-host; transactions still deterministic |
| pixel goldens | `tests/golden-specs.ts`, tape hashes | opted out (note-style verification) |
Expand Down
6 changes: 3 additions & 3 deletions docs/STRUCTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pocketjs/
├─ engine/ Cores: the Rust simulation cores
│ ├─ core/ pocketjs-core — retained UI tree, taffy layout, damage + raster (standalone crate)
│ ├─ backends/ platform render backends (ESP32-P4 PPA is a standalone no_std
│ │ crate; gpui is the standalone macOS Metal backend with native
│ │ crate; gpui is the standalone native desktop backend with native
│ │ text layout — docs/BACKENDS.md)
│ ├─ wasm/ core compiled to wasm32 for web/sim hosts (standalone crate)
│ ├─ symbian/ no_std Symbian UI static library: C ABI, capture raster + GLES2 DrawList backend (standalone crate)
Expand All @@ -26,8 +26,8 @@ pocketjs/
│ ├─ pocketbook/ PocketBook e-reader host (inkview, standalone lone-bin crate)
│ ├─ symbian/ Nokia E7 Qt/QuickJS runtime + visible toolchain probe
│ ├─ apple/ NativeScript iOS shell over engine/apple + @nativescript/pocketjs
│ ├─ macos/ gpui (Metal) window host — the macos-app target (standalone lone-bin crate)
│ ├─ web/ browser dev host (wasm core)
│ ├─ desktop/ gpui window host — macos-app + linux-app (standalone lone-bin crate)
│ ├─ web/ browser dev + Pocket System host (wasm core, isolated iframe Realms)
│ └─ sim/ deterministic headless simulation host (docs/DETERMINISM.md)
├─ framework/ Guest: @pocketjs/framework
│ ├─ src/ the TS runtime (Solid + Vue Vapor renderers, components, input, osk…)
Expand Down
2 changes: 1 addition & 1 deletion engine/backends/gpui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Standalone on purpose (excluded from engine/Cargo.toml, own Cargo.lock,
# same policy as backends/esp32p4-ppa): gpui builds only where a display
# server exists, and the ubuntu release workspace build must not depend on
# it. Built through hosts/macos (the stock macos-app host) and by
# it. Built through hosts/desktop (the stock macos-app host) and by
# .github/workflows/macos.yml.

[package]
Expand Down
Loading