PocketJS
New The modern web, from 32 MB up →

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.

SONY
booting core…
VOL+
PSP
SELECT START
live · click + arrow keys

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={'{{…}}'}, or animate().
  • focus: / active: variants switch natively — zero JS on focus change.
  • The same source compiles to a .dcpak for the PSP and runs unchanged in this page.
Try it in the playground →
Counter.tsx
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.

Read the architecture →
  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.