PocketJS

API reference

Every public export of @pocketjs/core, grouped by import path. Signatures are TypeScript-style; defaults are noted in parentheses. For conceptual walkthroughs see Components, Reactivity, Animation, and Input & focus.

Import path Exports
@pocketjs/core mount, render, host/runtime helpers, types
@pocketjs/core/components View, Text, Image, Show, For, Index, Switch, Match, Screen, Focusable, FocusScope, FocusGrid, ActionHandler, Portal, Modal, ActionBar
@pocketjs/core/reactivity createSignal, createEffect, createMemo, onMount, onCleanup, batch, untrack
@pocketjs/core/animation animate, spring, cancelAnim
@pocketjs/core/hooks useFrame, useButtonPress, useSpriteAnimation, pushButtonHandlerBlock
@pocketjs/core/input BTN, focusNode, getFocused, pushFocusScope, pushFocusGrid

@pocketjs/core

The runtime entry point: mount an app, tear it down, and reach the lower-level host, sweep, style, and pack utilities.

mount

function mount(code: () => unknown, opts?: MountOptions): () => void

App-level entry point for demo/application bundles. Resolves ops from opts.ops or globalThis.ui, loads opts.dcpak (when given), uploads the pack's images on injected hosts, feeds the default generated style table (opts.styles ?? STYLE_IDS), and mounts code. Returns a disposer that unmounts and destroys the app subtree. Throws if neither opts.ops nor globalThis.ui is present.

render

function render(code: () => unknown, opts?: RenderOptions): () => void

Lower-level mount: detects and installs the host, wires the style resolver, registers opts.styles, feeds styles/atlases from the pack on injected hosts, builds the app + overlay layers, installs the per-frame handler, and mounts code. Returns a disposer. mount calls render; call render directly when you supply your own ops/styles.

RenderOptions / MountOptions

MountOptions is an alias of RenderOptions.

Field Type Description
ops HostOps web/wasm/test hosts inject their op surface here; omit on PSP (globalThis.ui).
styles Record<string, number> class-literal → styleId table (styles.generated.ts).
dcpak ArrayBuffer app pack; defaults to globalThis.__dcpak when present.

Host helpers

function detectHost(injected?: HostOps): Host
function installHost(host: Host): void
function getOps(): HostOps

detectHost resolves the active host — injected ops win, otherwise globalThis.ui (PSP/QuickJS); throws when neither exists. installHost sets the active host (called by render). getOps returns the installed op surface. See Native contract for the full HostOps surface.

HostOps

The synchronous ui.* op surface. Handles are generation-tagged positive i32 ids; 0 means "none". Each op is documented in full on the Native contract page; the summary:

Op Signature Purpose
createNode (type: number) => number New node (spec NODE_TYPE) → id.
destroyNode (id: number) => void Destroy subtree; free anim tracks; clear focus.
insertBefore (parent, child, anchorOr0) => void Move/insert; anchor 0 = append.
removeChild (parent, child) => void Detach but keep the node alive.
setStyle (id, styleId) => void Apply a compiled style; -1 clears.
setProp (id, propId, value) => void Set one spec PROP.
setText / replaceText (id, str) => void Text-node content.
uploadTexture (buf, w, h, psm) => number Upload a pow2 image (≤512) → handle.
setImage (id, texHandle) => void Bind an image; <0 clears.
animate (id, propId, to, durMs, easing, delayMs) => number Start a tween → animId.
cancelAnim (animId) => void Stop a tween.
setFocus (idOr0) => void Focus a node; 0 clears.
loadStyles (buf) => void web/test only — feed the style table.
loadFontAtlas (buf) => void web/test only — feed one baked atlas.
measureText (str, fontSlot) => number Measured width in px.

Host

interface Host {
  ops: HostOps;
  kind: "psp" | "injected";
  strict: boolean;
}

strict hosts (web/wasm/test) throw on an unknown class or texture; the PSP host is non-strict and counts silently (see missCounters).

End-of-frame sweep

function retain(node: NodeMirror): void
function release(node: NodeMirror): void
function runSweep(): void

retain keeps a detached subtree alive across frames (skips the sweep); release undoes it so a still-detached node re-enters the next sweep. runSweep destroys every subtree removed during the frame and still detached — the runtime already calls it once per frame after user code and input, so remove-then-reinsert (Solid moves) never destroys live nodes. Reach for these only when hand-managing detached subtrees.

registerTexture

function registerTexture(key: string, handle: number): void

Bind an image key (the src string) to an uploadTexture handle so <Image src="key"> resolves through the renderer's texture registry.

missCounters

const missCounters: { unknownClass: number; unknownTexture: number }

On the non-strict PSP host, an unknown class or texture increments a counter instead of throwing. Read it to diagnose missing styles/images without crashing hardware.

Styles

function registerStyles(table: Record<string, number>): void
function resolveStyle(cls: string): number | undefined

registerStyles loads a class-literal → styleId table (the compiler's STYLE_IDS); it also registers a token-sorted alias so "a b" resolves the id for "b a". resolveStyle returns the styleId for a class string, or undefined if the compiler never saw it (or the token reordering is ambiguous). See Styling and Tailwind subset.

Data pack (dcpak)

function dcpakEntries(prefix?: string): string[]
function dcpakGet(key: string): Uint8Array
function loadPack(ab: ArrayBuffer): void
function resetPack(): void

dcpakEntries lists entry keys starting with prefix (default: all keys), sorted. dcpakGet returns a fresh copy of a blob's bytes, throwing on a missing key. loadPack explicitly loads a pack (web host after fetch, or tests), replacing any prior. resetPack drops the cached parsed pack. See Build pipeline.

NodeMirror

interface NodeMirror {
  id: number;                         // native generation-tagged node id
  type: number;                       // spec NODE_TYPE ordinal
  parent: NodeMirror | null;
  children: NodeMirror[];
  text?: string;                      // text nodes only
  focusable?: boolean;                // focus traversal membership
  onPress?: (() => void) | undefined; // CIRCLE handler while focused
}

The JS mirror of a native node. A ref receives one; animate, spring, focusNode, pushFocusScope, and pushFocusGrid all accept one.


@pocketjs/core/components

Platform primitives and higher-level components. Control-flow components (Show, For, Index, Switch, Match) are re-exported from Solid unchanged.

Primitives

function View(props: ViewProps): JSX.Element
function Text(props: TextProps): JSX.Element
function Image(props: ImageProps): JSX.Element

The three host tags, wrapped React Native-style. View is the flex container/box, Text renders baked-font text, Image draws an uploaded texture by src key.

ViewProps

Prop Type Description
class string Tailwind-subset class literal.
style Record<string, number | string> Inline spec props (escape hatch).
onPress () => void Fired on CIRCLE while focused.
focusable boolean Joins d-pad focus traversal.
ref (node: NodeMirror) => void | NodeMirror Node handle.
children JSX.Element Child nodes.

TextPropsclass, style, ref, children. ImagePropsclass, src (string), style, ref.

Screen

function Screen(props: ScreenProps): JSX.Element  // ScreenProps extends ViewProps

A full-screen root View. Defaults class to "relative flex-col w-full h-full bg-slate-50 overflow-hidden" when none is given.

Focusable

interface FocusableProps extends ViewProps { onPress?: () => void }
function Focusable(props: FocusableProps): JSX.Element

A View with focusable: true. Use onPress for the CIRCLE action.

FocusScope

interface FocusScopeProps extends ViewProps, FocusScopeOptions {
  active?: boolean | (() => boolean);
}
function FocusScope(props: FocusScopeProps): JSX.Element

Restricts d-pad traversal and CIRCLE to its subtree while active (default true). Adds autoFocus / restoreFocus from FocusScopeOptions. Internally pushes/pops via pushFocusScope.

FocusGrid

interface FocusGridProps extends ViewProps, FocusGridOptions {
  active?: boolean | (() => boolean);
}
function FocusGrid(props: FocusGridProps): JSX.Element

Gives its subtree row/column d-pad semantics while active. Requires columns; wrap (default false) wraps at row ends. Internally pushes/pops via pushFocusGrid.

ActionHandler

interface ActionHandlerProps extends ButtonPressOptions {
  button: number;                                    // BTN mask
  onPress: (pressed: number, buttons: number) => void;
  children?: JSX.Element;
}
function ActionHandler(props: ActionHandlerProps): JSX.Element

Declarative wrapper over useButtonPress: fires onPress on the button edge. Inherits allowWhenBlocked and active from ButtonPressOptions. Renders children (or nothing).

Portal

interface PortalProps { children?: JSX.Element | (() => JSX.Element) }
function Portal(props: PortalProps): JSX.Element

Renders children into the full-screen overlay root (above the app layer, zIndex 1000) instead of the local tree. Cleans up its host node on unmount.

Modal

interface ModalProps {
  class?: string;
  panelClass?: string;
  open?: boolean | (() => boolean);
  children?: JSX.Element;
}
function Modal(props: ModalProps): JSX.Element

A portalled backdrop + focus-scoped panel. While open, it blocks background button handlers (pushButtonHandlerBlock) and fades/scales the panel in. class styles the centering frame; panelClass styles the panel.

ActionBar

function ActionBar(props: ActionBarProps): JSX.Element  // ActionBarProps extends ViewProps

A portalled bottom bar. Defaults to a pinned left-3 right-3 bottom-3 row when no class is given.

Control flow (re-exported from Solid)

Component Usage Purpose
Show <Show when={cond} fallback={…}>…</Show> Conditional render.
For <For each={list}>{(item, i) => …}</For> List keyed by reference.
Index <Index each={list}>{(item, i) => …}</Index> List keyed by index.
Switch / Match <Switch fallback={…}><Match when={c}>…</Match></Switch> Multi-branch.

See the Solid control-flow docs for full prop shapes; behavior is unchanged.


@pocketjs/core/reactivity

Solid's reactivity, re-exported unchanged. Full docs live at solidjs.com; summary below.

Export Signature Purpose
createSignal createSignal<T>(value?, opts?) => [get: () => T, set: (v) => T] Reactive atom.
createEffect createEffect(fn: (prev) => T, value?) => void Run on dependency change.
createMemo createMemo(fn: (prev) => T, value?) => () => T Cached derived value.
onMount onMount(fn: () => void) => void Run once after first render.
onCleanup onCleanup(fn: () => void) => void Run on owner disposal.
batch batch(fn: () => T) => T Coalesce updates.
untrack untrack(fn: () => T) => T Read without tracking.

See Reactivity.


@pocketjs/core/animation

Typed motion over ops.animate. JS declares the tween once; the Rust core ticks it per vblank at a fixed dt = 1/60 s. prop is a spec PROP name and must be animatable (e.g. opacity, translateY, scale, and color props) — non-animatable props throw. See Animation.

animate

function animate(
  node: NodeMirror | number,
  prop: PropName,
  to: number | string,
  opts?: AnimateOptions,
): number   // returns animId

Tweens prop from its current value to to. For color props, to is a packed u32 ABGR or a '#rrggbb' / '#rrggbbaa' string. Returns an animId for cancelAnim.

AnimateOptions

Field Type Default Description
dur number 200 Duration in ms (ignored by spring easings).
easing EasingName | number "out" Named easing or raw ENUMS.Easing ordinal.
delay number 0 Delay in ms before the tween starts.

EasingName"linear" | "in" | "out" | "in-out" | "out-back" | "spring" | "spring-bouncy".

spring

function spring(
  node: NodeMirror | number,
  prop: PropName,
  to: number | string,
  preset?: "default" | "bouncy",
): number

Springs prop to to; duration comes from the physics, not a timer. preset (default "default") selects the base or bouncy spring. Returns an animId.

cancelAnim

function cancelAnim(animId: number): void

Stops a running animation by the id animate/spring returned.


@pocketjs/core/hooks

Component-scoped per-frame hooks. Each cleans up on owner disposal via onCleanup. See Reactivity and Input & focus.

useFrame

function useFrame(callback: (buttons: number) => void): void

Registers callback to run once per host frame with the current spec BTN bitmask.

useButtonPress

function useButtonPress(
  mask: number,
  callback: (pressed: number, buttons: number) => void,
  opts?: ButtonPressOptions,
): void

Edge-detects a button: fires callback on the frame a button in mask transitions from up to down. pressed is the just-pressed bitmask; buttons is the full held mask.

ButtonPressOptions

Field Type Default Description
allowWhenBlocked boolean false Keep firing while a modal/system block owns input.
active boolean | (() => boolean) true Gate the handler on/off.

useSpriteAnimation

function useSpriteAnimation(
  frames: readonly string[],
  opts?: SpriteAnimationOptions,
): Accessor<string>

Cycles through frames (image src keys), returning an accessor for the current frame. Throws if frames is empty. opts.frameStep (default 1, min 1) holds each sprite frame for that many host frames.

pushButtonHandlerBlock

function pushButtonHandlerBlock(): () => void

Pushes a global block so background useButtonPress handlers (those without allowWhenBlocked) stop firing; the returned disposer pops it. Modal uses this internally.


@pocketjs/core/input

Programmatic focus, the button bitmask, and the imperative focus-scope/grid stack. Prefer the FocusScope / FocusGrid components in app code. See Input & focus.

BTN

PSP button bitmask (identical on every host; web/Bun hosts remap keys).

Member Value Member Value
SELECT 0x0001 LTRIGGER 0x0100
START 0x0008 RTRIGGER 0x0200
UP 0x0010 TRIANGLE 0x1000
RIGHT 0x0020 CIRCLE 0x2000
DOWN 0x0040 CROSS 0x4000
LEFT 0x0080 SQUARE 0x8000

focusNode

function focusNode(node: NodeMirror | null): void

Programmatically focus a node (or clear focus with null). Applies the native focus: style variant.

getFocused

function getFocused(): NodeMirror | null

Returns the currently focused node, or null.

pushFocusScope

function pushFocusScope(node: NodeMirror, opts?: FocusScopeOptions): () => void

Restricts d-pad traversal and CIRCLE to node's subtree; returns a disposer that pops the scope and restores prior focus. Backs the FocusScope component.

FocusScopeOptions

Field Type Default Description
autoFocus boolean true Focus the first focusable on push.
restoreFocus boolean true Restore the previously focused node on pop.

pushFocusGrid

function pushFocusGrid(node: NodeMirror, opts: FocusGridOptions): () => void

Gives node's subtree row/column d-pad semantics; returns a disposer that pops the grid. Backs the FocusGrid component.

FocusGridOptions

Field Type Default Description
columns number Grid column count (min 1). Required.
wrap boolean false Wrap focus at row ends.

Try any of these live in the playground, or start from Getting started.