Bare MetalModern Web
PocketJS renders a real Solid app — JSX, Tailwind, signals and TypeScript — natively on the metal. Real flexbox, sub-pixel text and hardware-accelerated animation, at a fluid 60 FPS in 32 MB of RAM.
The stack you already know — running on the metal
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 before it ever reaches the device.
No VDOM
Solid's fine-grained reactivity runs only the effect closures of changed signals. Updates cross a single FFI boundary per frame — never a diff.
Zero runtime CSS
A class string compiles to a style record only if every token is a supported utility. The Tailwind subset resolves at build time — nothing ships to parse.
Baked fonts
Inter is rasterized at build time into coverage atlases for exactly the glyphs you use. No font files, no shaper at runtime — just pixels.
Native animation
Tweens and springs tick in Rust at a fixed 1/60 s. Each frame is a pure function of its index — the reason byte-exact goldens are possible.
Real flexbox
taffy 0.11 — no_std, f32-only — does the layout; text measures natively. The same engine positions every pixel on every host.
One tiny Rust core
Layout, styling, animation, text and the draw list live in one portable no_std core — a few hundred kilobytes, compiled to the PSP and to WebAssembly alike.
If you can write a component, you can write for the metal.
You already know the surface: View, Text, signals and class strings. focusable and onPress map straight to the d-pad and face buttons.
- Dynamic styles are ternaries of full class literals or animate() calls — never runtime CSS.
- The focus: and active: variants switch natively, with zero JS on focus change.
- One codebase compiles to a .dcpak for a real PSP and runs unchanged right here in your browser.
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" focusable onPress={() => setN(n() + 1)}>
<Text class="text-base text-white font-bold">Press Circle</Text>
</View>
</View>
);
}
Every screen deserves the modern web.
It starts on a 2005 handheld with 32 MB of RAM and a fluid 60 FPS. It won't stop there.