Bare Metal
Modern Web
PocketJS brings the modern web's entire authoring model to hardware a browser could never reach — Solid, JSX, Tailwind, signals and TypeScript, with flexbox, sub-pixel text and native animation, at 60 FPS from 32 MB up.
A whole UI engine, sized for a handheld
No VDOM, no runtime CSS, no font files shipped. Everything the app can't need is compiled away.
No VDOM
Solid's universal renderer runs only the effect closures of changed signals — updates cross one FFI boundary per frame, not a diff.
Baked fonts
Inter is rasterized at build time into 8-bit coverage atlases for exactly the glyphs your app uses. No font files, no shaper at runtime.
Tailwind, compiled away
A class literal compiles to a style record only if every token is a supported utility — zero runtime CSS, styles live in the .dcpak.
Native animation
Tweens and springs tick in Rust at a fixed 1/60 s. Frame content is a pure function of frame index — that's what makes byte-exact goldens possible.
Real flexbox
taffy 0.11 (no_std, f32-only) does layout; text measures natively. The same layout engine on every host.
One tiny Rust core
Layout, styling, animation, text and the DrawList live in a single portable core — a few hundred kilobytes, compiled straight to the PSP and to WebAssembly for the browser.
Looks like Solid. Runs like a game.
If you've written React or Solid, you already know the surface: View,
Text,
Image, signals, and class strings.
Focus and onPress map to the d-pad and buttons.
- › Dynamic styling via ternaries of full class literals,
style={'{{…}}'}, oranimate(). - ›
focus:/active:variants switch natively — zero JS on focus change. - › The same source compiles to a
.dcpakfor the PSP and runs unchanged in this page.
import { Text, View } from "@pocketjs/core/components";
import { createSignal } from "@pocketjs/core/reactivity";
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-blue-600 focus:bg-blue-500
active:bg-blue-700 transition-colors duration-150"
focusable
onPress={() => setN(n() + 1)}
>
<Text class="text-base text-white font-bold">Press Circle</Text>
</View>
</View>
);
}
From app.tsx to the screen
A two-pass build transforms your components, compiles the class strings, bakes the font atlases, and packs it all into one .dcpak. The Rust core turns the reactive tree into a draw list — sent straight to the PSP's graphics engine on hardware, or a software rasterizer in the browser.
app.tsx (Solid + Tailwind classes) │ babel-preset-solid {generate:'universal'} ▼ bundle.js + styles.bin + atlases ─▶ app.dcpak │ ┌──────────────┐ ┌──────────────┐ │ QuickJS (PSP)│ │ browser / Bun│ │ Solid + core│ │ Solid + core│ │ ▼ DrawList │ │ ▼ DrawList │ │ Sony GPU │ │ rasterizer │ └──────────────┘ └──────────────┘
Every screen deserves the modern web.
It starts on a Sony PSP — 32 MB of RAM, no browser, a fluid 60 FPS. It won't stop there.