Skip to content

feat(apple): iOS host — pocket-apple core crate, PocketSurfaceView, external-guest mode - #255

Open
NathanWalker wants to merge 1 commit into
pocket-stack:mainfrom
NathanWalker:feat/apple-host
Open

feat(apple): iOS host — pocket-apple core crate, PocketSurfaceView, external-guest mode#255
NathanWalker wants to merge 1 commit into
pocket-stack:mainfrom
NathanWalker:feat/apple-host

Conversation

@NathanWalker

@NathanWalker NathanWalker commented Aug 9, 2026

Copy link
Copy Markdown

What

A new engine/apple workspace member (pocket-apple) plus a UIKit view class, packaging modern iOS as a PocketJS host. The composition mirrors hosts/pocketbook: one pocket_mod::Guest realm, one pocket_ui_surface::UiSurface, and pocketjs_core::raster driven incrementally through a DamageTracker, exposed behind a small C ABI.

  • engine/apple/src/lib.rs — guest-owning mode: pocket_apple_create/load_pak/eval_bundle/frame/render/hit_test_bounds/destroy, plus an effect channel over the ui.svc* ops (set_effect_callback drains guest svcSend lines during frame; post_event queues lines for the guest's next svcPoll).
  • engine/apple/src/core_host.rs — external-guest mode: pocket_apple_core_* owns only the core, pak feed, raster pipeline, and svc queues, for hosts whose JS engine lives elsewhere (demonstrated with the NativeScript runtime: the guest bundle evaluates in the embedding runtime's context and globalThis.ui delegates each op over the bridge).
  • engine/apple/apple/PocketSurfaceView.{h,m} — CADisplayLink capped at 60 Hz, packed touch words with aspect-fit inverse mapping, damage-gated compositing of the ARGB32 framebuffer into layer.contents.
  • engine/apple/build-xcframework.sh — clang-linked dynamic framework per slice (device arm64 + simulator arm64), no Xcode project.
  • apps/nsengine — reference guest for the effect channel: an effect driver over svcSend + a per-frame poll pump, and a platform-reach probe (typeof UIDevice) that distinguishes a sidecar realm from an embedding-runtime host.

rquickjs uses its bindgen feature here: no pregenerated bindings exist for aarch64-apple-ios targets.

Validation

  • cargo run -p pocket-apple --example render_hero — 180 frames of apps/hero/main.tsx at 480×272 density 2: non-blank, byte-identical across two independent instances, incremental damage plans active. Release mode renders 360 frames plus two guest boots in 0.34 s wall.
  • Verified on the iOS 26.5 simulator inside two NativeScript apps (embedded-surface and external-guest modes), including the guest→host→guest effect round trip.

Not included (follow-ups)

  • Manifest/target registration: bundles are built plan-less; a dev-profile target id (the tools/iphone2g-profile.ts pattern) is the likely next step before POCKET_TARGETS registration.
  • GPU path: the software rasterizer ships this iteration; the follow-up is pocket-ui-wgpu rendering into a CAMetalLayer surface as a second path behind the same view class.

@NathanWalker
NathanWalker marked this pull request as ready for review August 9, 2026 17:12
…xternal-guest mode

A new engine/apple workspace member packaging modern iOS as a PocketJS
host. The composition mirrors hosts/pocketbook: one pocket_mod::Guest
realm, one pocket_ui_surface::UiSurface, and pocketjs_core::raster driven
incrementally through a DamageTracker, exposed behind a small C ABI.

- engine/apple/src/lib.rs — guest-owning mode: create/load_pak/eval_bundle/
  frame/render/hit_test_bounds/destroy, plus an effect channel over the
  ui.svc* ops (set_effect_callback drains guest svcSend lines during frame;
  post_event queues lines for the guest's next svcPoll).
- engine/apple/src/core_host.rs — external-guest mode: pocket_apple_core_*
  owns only the core, pak feed, raster pipeline, and svc queues, for hosts
  whose JS engine lives elsewhere (demonstrated with the NativeScript
  runtime evaluating the guest bundle in its own context).
- engine/apple/apple/PocketSurfaceView.{h,m} — CADisplayLink capped at
  60 Hz, latched touch contacts (a down+up between two ticks still reaches
  the guest as one present frame then a release), aspect-fit inverse touch
  mapping, damage-gated compositing of the ARGB32 framebuffer.
- engine/apple/build-xcframework.sh — clang-linked dynamic framework per
  slice (device arm64 + simulator arm64), no Xcode project.
- pocket-ui-surface additionally mounts hitTestBounds (spec op 42), the
  touch-path hit authority the gesture layer prefers over the ink-claiming
  hitTest.
- apps/nsengine — reference guest: an effect driver over svcSend, a
  per-frame poll pump, a focusable pressable button, and a platform-reach
  probe that distinguishes a sidecar realm from an embedding-runtime host.

rquickjs uses its bindgen feature: no pregenerated bindings exist for
aarch64-apple-ios targets. Validation: the render_hero example drives the
ABI end to end — 180 frames of apps/hero/main.tsx at 480x272 density 2
render non-blank and byte-identical across two independent instances.
Build guests with --density matching the surface density (glyphs bake at
build time; density 4 supersamples cleanly on 3x screens).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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