TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/pocket-stack/pocketjs/llms.txt
Use this file to discover all available pages before exploring further.
HostOps interface is the lowest layer of PocketJS: the synchronous ui.* op surface that every component tree eventually drives. Three design rules define the entire model. First, every op is a mutation — there are no queries, no getters, no tree-walking reads. The one read-shaped method, measureText, is a stateless convenience; layout still measures natively inside the Rust core. Second, every op is synchronous — each call is a single blocking FFI crossing, not a buffered command or async message. Batching happens one level up, where Solid only runs effects for changed signals. Third, the reconciler never reads across FFI — the renderer keeps a JS mirror tree (NodeMirror) so every structural read Solid performs (parent, first child, next sibling, type check) is a plain JS object walk. Only writes cross the boundary. App developers never call these ops directly — View, Text, and Image emit them — but this page is the authoritative reference for anyone implementing a new host or doing advanced debugging.
On PSP,
globalThis.ui is the HostOps object, installed by the QuickJS native binding in native/src/ffi.rs. On browser, WASM, and headless-Bun hosts, you pass your own HostOps implementation explicitly to mount() or render() via opts.ops. The two paths are unified by detectHost: injected ops win, otherwise globalThis.ui is used, and if neither exists render() throws.The HostOps interface
Method reference
| Method | Signature | Description |
|---|---|---|
createNode | (type: number) => number | Creates a new node. type is a NODE_TYPE code: 0 = view, 1 = text, 2 = image. Returns a fresh generation-tagged node id. |
destroyNode | (id: number) => void | Destroys the entire subtree rooted at id, frees all animation tracks it owns, and clears focus if the currently focused node was anywhere inside the subtree. |
insertBefore | (parent: number, child: number, anchorOr0: number) => void | Inserts or moves child before anchor inside parent. DOM move semantics: if child is already attached anywhere it is unlinked from its current parent first (core tree, taffy layout, and JS mirror). anchor = 0 appends. Silently no-ops when the target parent is already at MAX_TREE_DEPTH (64) — same contract as a stale id. |
removeChild | (parent: number, child: number) => void | Detaches child from parent but keeps the node alive in memory. Solid may re-insert it later in the same frame. The end-of-frame renderer sweep calls destroyNode on any node still detached after frame() completes. |
setStyle | (id: number, styleId: number) => void | Applies a compiled style by its index in the style table. STYLE_ID_NONE (-1) clears the node back to default style. Triggers CSS-style transitions: the core diffs animatable props between the old and new style records and starts tween tracks for any that changed. |
setProp | (id: number, propId: number, value: number) => void | Sets one dynamic prop on a node. propId is a value from the PROP enum (see Spec). Color props and enum props pass their u32 bits as the number argument; dimension and scalar props pass a plain f32. |
setText | (id: number, text: string) => void | Sets the UTF-8 text content of a text node. Used at creation time when the initial string is known. |
replaceText | (id: number, text: string) => void | Updates the UTF-8 text content of an existing text node. Solid’s universal renderer calls this method (not setText) on reactive text signal updates. |
uploadTexture | (buf: Uint8Array, w: number, h: number, psm: number) => number | Uploads an image into the core’s texture arena. w and h must each be a power of two and no larger than 512. psm is a PSM format code from the spec (PSM_4444 = 2, PSM_8888 = 3). Bytes are copied and 16-byte aligned. Returns a 0-based texture handle, or -1 on failure. |
setImage | (id: number, texHandle: number) => void | Binds an uploaded texture to an image node. texHandle < 0 clears the image binding. Note: 0 is a valid handle (the first uploaded texture); only negative values clear. Also clears any active sprite binding on the same node. |
setSprite | (id: number, atlas: number, frames: number, cols: number, step: number) => void | Binds an animated sprite atlas to an image node. atlas is an uploaded texture holding a cols-wide grid of frames cells. The Rust core auto-plays the sprite by cycling cells at one cell per step vblanks — entirely in native code, with zero per-frame JS. frames <= 0 clears the sprite binding. |
animate | (id: number, propId: number, to: number, durMs: number, easing: number, delayMs: number) => number | Starts a tween on propId from its current value to to. durMs is the duration in milliseconds (ignored by spring easings, which are physics-driven). easing is an ENUMS.Easing ordinal. delayMs defers the start. Returns an animId for use with cancelAnim. |
cancelAnim | (animId: number) => void | Stops a running tween or spring track by the id animate returned. The animated prop retains its value at the moment of cancellation. |
setFocus | (idOr0: number) => void | Focuses a node, applying its focus: style variant natively. Passing 0 clears focus. Only one node can hold focus at a time. |
loadStyles | (buf: Uint8Array) => void | Web and test hosts only. Optional. Feeds the compiled styles.bin blob to the core. On PSP the native binary feeds core directly from the pak before JavaScript evaluation starts; this method exists on the interface so the full op surface is symmetric. |
loadFontAtlas | (buf: Uint8Array) => void | Web and test hosts only. Optional. Feeds one baked font atlas blob. Call once per atlas slot; slot index is encoded in the atlas header. On PSP the pak walker feeds atlases natively. |
measureText | (str: string, fontSlot: number) => number | Returns the measured pixel width of str in the given font slot. This is a JavaScript-side convenience for dynamic layout calculations. The core’s layout engine always measures text natively; call this only when you need a width in JS for positioning logic. |
Generation-tagged node handles
Node ids are not plain indices. Each id packs a slot and a generation counter:- Bit 31 is always
0, so all valid ids are positivei32values. 0is “no node” —insertBeforewithanchor = 0appends;setFocus(0)clears focus.ROOT_ID = 1(slot 1, generation 0) is the pre-created full-screen root, a flex column. App content mounts under it.MAX_TREE_DEPTH = 64bounds all recursive tree walks (layout, paint, subtree destroy) so a runaway tree cannot overflow the small PSP thread stacks.
The Host type
detectHost wraps a raw HostOps object in a Host struct that also records the kind and strictness. Strict hosts (web, WASM, Bun test) throw loudly on an unknown class string or unregistered texture src. The PSP host is non-strict and counts misses in missCounters instead of throwing, because a crash on hardware is worse than a slightly-wrong style.
Host helper functions
These three functions fromsrc/host.ts are re-exported by @pocketjs/framework.
NodeMirror
The JS-side mirror of a native node. Every reconciler read (parent, first child, next sibling, type check) operates on NodeMirror objects without crossing FFI. Only writes emit ops.
NodeMirror objects are what ref callbacks receive, and what animate(), spring(), focusNode(), pushFocusScope(), and pushFocusGrid() all accept as their first argument. The mirror tree is maintained entirely by the renderer — you never construct these objects directly.
Prop value encoding
setProp and animate both carry their value as a single number (a JavaScript f64 on the wire). The encoding depends on the prop’s VALUE_KIND:
| Kind | Prop examples | Encoding |
|---|---|---|
f32 | width, height, opacity, translateX, rotate, scale | IEEE-754 float, passed through directly |
color | bgColor, textColor, borderColor, gradFrom, gradTo | Packed u32 ABGR (0xAABBGGRR); or a '#rgb' / '#rrggbb' / '#rrggbbaa' string parsed by parseHexColor |
int | posType, overflow, zIndex, fontSlot, textAlign, flexDir | Enum ordinal or integer, stored as u32 bits |
encodePropValue(prop, value) in src/host.ts is the single encoding choke point used by the renderer’s setProperty dispatch. A non-numeric string for a non-color prop throws. Full-string hex validation is applied to color strings (#ff00zz throws rather than silently painting a prefix color).