New Pocket Character: a desktop digital human at 4% of one core

Bare MetalModern Web

High-performance JSX UI outside the browser, with native rendering, standard Vue Vapor and Solid support, a Tailwind design system, and 60 FPS animation under an 8 MB memory budget.

Loading Pocket Stage…
The live Pocket Launcher inside the model’s real screen material — browse the deck, launch any app, SELECT to switch. PSP model by Dibad · CC BY 4.0
Familiar tools, constrained hardware

Tailwind, flexbox, Solid and Vue Vapor under 8MB RAM.

PocketJS keeps the authoring model modern while moving the expensive work to build time and to a tiny Rust core. The result is a real interface stack that can run smoothly on a Sony PSP.

Flexbox is native

Layout runs in the Rust core through taffy, so a familiar flex-col gap-4 interface lays out deterministically on PSP, browser and Bun.

Tailwind compiles away

Class literals become compact style records at build time. There is no CSS parser, stylesheet cascade or utility runtime on the device.

Text is still sharp

Inter glyphs are baked into coverage atlases and rendered with sub-pixel positioning, so tiny PSP screens still get readable UI text.

Business logic stays intact

Native framework imports on a tiny machine.

Write Solid or Vue Vapor components with their own reactivity APIs, run them on QuickJS, and let PocketJS handle the native pixels.

  • focusable and onPress map to PSP controls.
  • focus: variants and packed assets become native data in the .pak.
Open the playground
Counter.tsx
import { Text, View } from "@pocketjs/framework/components";
import { createSignal } from "solid-js";

export default function Counter() {
  const [n, setN] = createSignal(0);
  return (
    <View class="flex-col items-center gap-4 p-6 bg-slate-950">
      <Text class="text-2xl text-slate-50 font-bold">Count: {n()}</Text>
      <View class="px-4 py-2 rounded-xl bg-slate-700 focus:bg-slate-500" focusable onPress={() => setN(n() + 1)}>
        <Text class="text-base text-slate-50 font-bold">Press Circle</Text>
      </View>
    </View>
  );
}
The proof is shipping software

Built with PocketJS.

Complete open-source apps running on real handhelds — not tech demos.

OpenStrike on de_dust2: sunlit BSP geometry, crates and arches, with the Solid HUD showing 100 HP and 30/90 ammo.

OpenStrike

A Counter-Strike-shaped FPS that plays the classic GoldSrc-era maps — BSP world, lightmaps, bots, recoil, round flow. The HUD is a Solid app; the round rules and weapon tables are TypeScript. It holds a locked 60 FPS on a 333 MHz PSP and ships as one file you drop on a Memory Stick.

Pocket Figma on a PSP at 59% zoom: the Paper Wireframe Kit cover with hand-drawn lettering, and the viewer HUD along the bottom.

Pocket Figma

A real Figma Community file, open on a PSP: the Paper Wireframe Kit — 14,430 nodes, 2,293 component instances, a canvas 26,000 pixels wide. The cooker bakes it into streaming tiles, so the device never parses the file. Pan with the analog nub, zoom with the shoulders — and the same bundle runs at native 960×544 on PS Vita.

Pocket YouTube on a PSP: a video paused under a centered pause badge, with the title bar, red progress bar and playback hints of the player HUD.

Pocket YouTube

YouTube on a PSP, where the network is a USB cable: a Mac companion runs yt-dlp and ffmpeg, and the handheld plays a ring buffer that happens to be a file. Search with the system keyboard, browse rows with CJK titles the device could never typeset, and watch at 12 fps with 44.1 kHz audio — pause, seek and all — while the UI never drops from 60 FPS.

The runtime, at a glance

Modern UI physics on retro silicon.

You keep JSX and signals. Everything expensive becomes native data, native draw calls — and a testable machine.

UI that can't flake

A virtual clock makes every frame a pure function of the input tape. Golden tests compare whole framebuffers, byte for byte — the same on CI, desktop and hardware. Scrub backwards, replay any session, on a real PSP.

The wall above? Nine of these tapes, replayed headlessly against the core.

Compiled styling

Tailwind literals become numeric style records at build time. No parser, no cascade, no utility runtime on the device.

Deterministic flexbox

taffy 0.11 lays out in the Rust core — identical positions on every target, provable in goldens.

Baked text

Coverage atlases with sub-pixel positioning. Runtime text is compositing, not font rasterization.

Native motion

Tweens, springs and keyframe timelines tick in Rust at a fixed 1/60 s. JS declares; the core animates.

Real input, system-wide

D-pad focus, analog nub, touch, a virtual cursor — and a system on-screen keyboard any app can summon with one call.

Time-travel DevTools

Every session records itself. Step to any frame, inspect the native tree, diff against a golden — over USB to real hardware.

3D, same discipline

Pocket3D runs BSP worlds with PVS through sceGu on PSP and wgpu on desktop — OpenStrike holds a locked 60 FPS with a Solid HUD on top.

One core, many devices

The no_std core needs a framebuffer and a few buttons; a pocket.json contract decides where a bundle may ship.

  • Sony PSP
  • PS Vita
  • macOS
  • iOS
  • Nintendo 3DS
  • Steam Deck
  • Android
  • Embedded Linux
shippingin progressplanned
Start from the hardware up

Build modern UI where the browser cannot go.

Bring modern frontend ergonomics to hardware that was never built for the web.