
A texture of heights
16 bits a texel. Each fragment compares its own height with one texel.
PSPNintendo 3DSPS Vita
Pocket3D is a hardware-native 3D stack for portable interactive software.















Built to use each machine in full.
Most cross-platform engines flatten every console down to what they all share. Pocket3D is designed the other way round. A game gets a renderer for each machine, so the PSP's fixed pipeline, the 3DS's glasses-free 3D screen and the Vita's GXM driver are all there to be used.
One renderer has to run on all three, so it draws with what all three share. Everything above the line goes unused. A renderer for each machine keeps everything above the line in reach.
GEGE, the Graphics EngineThe graphics chip of Sony's PSP. Its pipeline is fixed: it has no shaders, so lighting, fog and texturing are stages a game switches on and sets., 2004
PICA200PICA200The graphics chip of the Nintendo 3DS. It runs vertex programs and has no fragment shaders: a pixel's colour comes from a chain of up to six combiner stages., 2011
GXMGXMThe graphics interface of Sony's PS Vita, over a PowerVR chip. Vertex and fragment programs are written in Cg, and 4× multisampling is built in., 2011
One source of truth, a different program on each machine.
The game is modelled once, as Three.js content that runs in a browser. A compiler lowers that semantic scene to each platform, the way LLVM takes one program to many processors. Hardware-native depends on it: each back end is free to emit what its own GPU wants.
One Three.js scene of the city. Pick a line of it.
Shadows turn with the sun

16 bits a texel. Each fragment compares its own height with one texel.

An 8-bit texture of shade over the whole city, multiplied in by one of three combiner stages.

The upper half of each palette is the lower half in shadow. A thread sets the top bit where the ground is shaded.
The city lights up at dusk

Each building's rooms come on at their own moment. What is bright on screen is blurred and added to the next frame.

The lamps' light is one texture over the city. Facades carry a second picture of what their windows emit.

Every picture has a day palette and a night palette. The GE reads their mix by the hour.
A wall faces the sun, or not

A Cg program takes its dot product with the sun, then the shadow lookup cuts it.

One byte names the way the wall faces. The vertex program picks one of 17 lights by it.

Walls are sorted by the 16 directions they face. Each group is drawn with the GE's ambient colour as its light.
CityIR holds the city as meaning, with no GPU in it. A portable engine would carry one renderer to all three machines and turn its features down, or off, where a machine lacks them. Here each back end emits its own data for its own renderer, so the PSP gets moving shadows without a single shader.
Drag to compare the Three.js reference in a browser with what the compiler made of it for a PS Vita.
Development machine
Three.js, running in a browser. It draws the left half.
Lowers the scene to the formats the Vita's GPU reads.
PS Vita
Rust, written for these places. It draws the right half.
A pack of textures, vertices and baked light.
written by a coding agent, as one project
Every game gets an engine of its own.
Pocket3D is not one engine that every game has to squeeze into. Each game builds on it with its own scene DSL, its own IR and its own renderers, and all three are tuned to that one game.

Real places, at the best image a handheld holds at 30 fps.

Wire traversal through a town of 5,400 houses, at 60 fps.

The real city around Tokyo Tower, flown over at 60 fps on a PS Vita.

A round-based shooter on classic maps, locked at 60 fps on a PSP.
Pocket3Ddevice kernels and toolchains: GXM memory and patching, GE frame storage, PICA texture storage
The HUD is written like a web page, and a PSP keeps up.
A Pocket3D game draws its 3D and leaves every 2D pixel to PocketJS, the runtime Pocket3D's toolchains, dev hosts and device kernels come from. The title, the menus and the HUD are one app in JSX, with SolidJS for state and Tailwind classes for layout, drawn as a layer over the 3D frame. It costs little enough for a PSP, a machine with 32 MB of memory and a 333 MHz processor.
// Pocket Tokyo's title screen, abridged from its interface function Title(props) { return ( <View class="relative w-full h-full">1 <View class="absolute" style={{ insetL: 24, insetT: 22 }}> <Wordmark large /> </View>2 <Text class="absolute text-xs" style={{ insetL: 24, insetT: 88 }}> A flight over Shiba, around Tokyo Tower. </Text>3 <View class="absolute" style={{ insetR: 16, insetT: 12 }}> <Clock host={flight.host} /> </View>4 <View class="absolute" style={{ insetL: 10, insetT: 110 }}> <Rows flight={flight} menu={props.menu} rowHeight={26} /> </View> </View> ); }
1
2
3
4
Components in JSX, state in SolidJS signals, layout in Tailwind classes. One app serves every console and takes a layout for each screen.
Classes become a style table at build time. A QuickJS guest runs the app, and a Rust core lays it out and draws every pixel.
OpenStrike's HUD takes 2.2 ms of JavaScript in a 60 fps frame on a PSP. A number that changes every frame is written to its node with no layout.
Making a game is writing code.
The whole workflow is an agent writing Three.js and a scene DSL. There is no editor to click through and no binary scene to edit by hand, so a game, or any rich interactive scene, can be made entirely by coding. Every step after the writing is a command the agent runs.
youThe LED band over the Radio Kaikan shopfront should chase, like the real one.
agentAdded a 32-frame flipbook sign on the band. On the Vita it costs what a still sign does.
// Housing: yellow steel, the face covered by the LED bars. const housing = lib.plain(0xc9a20e, 0.5, 0.2); w.mesh(box(bw, bh, zf + 0.3), housing, …); const sign = w.addSign(new Sign("kaikan-band", tex, new Color(1.9, 1.7, 1.25), { flipbook: { frames: 32, cols: 1, rows: 32, fps: 6 } })); w.mesh(frameUV(new PlaneGeometry(bw - 0.06, bh - 0.06), 1, 32), sign.material, …);

The same sign on a PS Vita, at 30 fps. An example exchange; the code is abridged from Pocket Atlas.
Three.js and the scene DSL. It runs in a browser at once.
bun run devLower the scene to one console's formats, with budgets checked.
bun tools/maneuver.ts cookReplace the binary running on the console.
bun tools/maneuver.ts nativeFly a fixed route and read back the late frames.
bun tools/maneuver.ts benchread the numbers, write again
Pocket3D is built into Pocket Studio, our workshop in the browser. Pick a machine there, make a game with your coding agent and play it. You need no PSP, PS Vita or 3DS on your desk.