Pocket3D

PSPNintendo 3DSPS Vita

Pocket3D is a hardware-native 3D stack for portable interactive software.

  • PS Vita capture: Tokyo Tower at dusk from the air, over lit streets and windows.
    Pocket Tokyo · PS Vita
  • PS Vita capture: Stone stairs between buildings under a tree, in hard sunlight.
    Pocket Atlas · PS Vita
  • PSP capture: A street of timber houses with a tower at its end.
    Pocket Maneuver · PSP
  • Nintendo 3DS capture: Upper screen: Tokyo Tower in the afternoon.
    Pocket Tokyo · 3DS
  • PS Vita capture: A convenience store at night, reflected in wet ground.
    Pocket Atlas · PS Vita
  • PS Vita capture: A green tram passes a level crossing above the sea.
    Pocket Atlas · PS Vita
  • PSP capture: A first-person view of a sunlit courtyard with crates and a rifle.
    OpenStrike · PSP
  • Nintendo 3DS capture: Upper screen: Tokyo Tower at dusk over lit streets.
    Pocket Tokyo · 3DS
  • PS Vita capture: A figure on wires flies over the red roofs of a walled town.
    Pocket Maneuver · PS Vita
  • PSP capture: Tokyo Tower at dusk over lit streets.
    Pocket Tokyo · PSP
  • PS Vita capture: The Pocket Tokyo title menu over Tokyo Tower and the Shiba district.
    Pocket Tokyo · PS Vita
  • PS Vita capture: A grid of city lights seen from a hilltop terrace at dusk.
    Pocket Atlas · PS Vita
  • PSP capture: Tokyo Tower among office blocks by day, with altitude and speed readouts.
    Pocket Tokyo · PSP
  • PS Vita capture: The Radio Kaikan building at dusk, its facade covered in lit signs.
    Pocket Atlas · PS Vita
  • PS Vita capture: An observatory at dusk with a city skyline behind it.
    Pocket Atlas · PS Vita

Hardware-native

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.

PSP

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

  • palette textures
  • GE bone blending
  • fixed pipeline

Nintendo 3DS

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

  • glasses-free 3D
  • a second screen
  • PICA fog table

PS Vita

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

  • bloom, light shafts
  • 4× MSAA
  • Cg shaders

textured, lit triangles

Compiler-first

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.

Pocket TokyoPocket Tokyo, an example appA flight over the real Tokyo around Tokyo Tower, built on Pocket3D for the PS Vita, the PSP and the Nintendo 3DS.

One Three.js scene of the city. Pick a line of it.

CityIRCityIR, written for Pocket TokyoPocket3D games do not share an IR. Pocket Tokyo's compiler defines this one to hold a city: buildings, footprints, a picture from above. Another game defines its own.

Shadows turn with the sun

PS Vita capture: Tokyo Tower in the afternoon, with office blocks behind it.
PS Vita · GXM

A texture of heights

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

Nintendo 3DS capture, upper screen: Tokyo Tower in the afternoon.
Nintendo 3DS · PICA200

A combiner stage

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

PSP capture: Tokyo Tower in the afternoon.
PSP · GE

One bit of a palette index

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

PS Vita capture: Tokyo Tower at dusk over lit streets.
PS Vita · GXM

A glow from the last frame

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

Nintendo 3DS capture, upper screen: Tokyo Tower at dusk over lit streets.
Nintendo 3DS · PICA200

Night as light

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

PSP capture: Tokyo Tower at dusk over lit streets.
PSP · GE

Two palettes

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

PS Vita capture: Tokyo Tower in the afternoon, with office blocks behind it.
PS Vita · GXM

A normal in every vertex

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

Nintendo 3DS capture, upper screen: Tokyo Tower in the afternoon.
Nintendo 3DS · PICA200

A compass sector in the vertex

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

PSP capture: Tokyo Tower in the afternoon.
PSP · GE

One draw per direction

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.

Pocket AtlasPocket Atlas, an example appReal places to stand in, such as this observatory and a street in Akihabara, built on Pocket3D for the PS Vita and the Nintendo 3DS. Griffith Observatory

Drag to compare the Three.js reference in a browser with what the compiler made of it for a PS Vita.

PS Vita capture: an observatory at dusk with a city skyline behind it. The same view rendered by the Three.js reference in a browser.

Development machine

The scene

Three.js, running in a browser. It draws the left half.

The compiler

Lowers the scene to the formats the Vita's GPU reads.

PS Vita

The renderer

Rust, written for these places. It draws the right half.

The compiled scene

A pack of textures, vertices and baked light.

written by a coding agent, as one project

Purpose-built engines

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.

PS Vita capture: a convenience store at night, reflected in wet ground.

Pocket Atlas

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

  1. written in its DSLa place kitsigns, glass, water, light fields
  2. compiled to its IRPlaceIRglTF with a note on what each part is
  3. drawn by its renderersGXM, PICA200reflections, rain, 52,000 point-sprite lights
  4. standing onPocket3D
PS Vita capture: a figure on wires flies over the red roofs of a walled town.

Pocket Maneuver

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

  1. written in its DSLa town generatorbands, blocks, row houses, one strip atlas
  2. compiled to its IRWorldIRcells, levels of detail, a collision world
  3. drawn by its renderersGXM, PICA200, GEruns of cells in one draw, clip groups on the PSP
  4. standing onPocket3D
PS Vita capture: the Pocket Tokyo title menu over Tokyo Tower and the Shiba district.

Pocket Tokyo

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

  1. written in its DSLa city from recordsopen city model, roads, elevation
  2. compiled to its IRCityIRbuildings, footprints, a picture from above
  3. drawn by its renderersGXM, GE, PICA200shadows that follow the clock on all three
  4. standing onPocket3D
PSP capture: a first-person view of a sunlit courtyard with crates and a rifle.

OpenStrike

A round-based shooter on classic maps, locked at 60 fps on a PSP.

  1. written in its DSLmaps and rulesBSP maps, TypeScript rounds, a JSX HUD
  2. compiled to its IRMapIRvisibility solved before the game runs
  3. drawn by its renderersGE, GXM, GLES2only what the camera can see reaches the GPU
  4. standing onPocket3D

Pocket3Ddevice kernels and toolchains: GXM memory and patching, GE frame storage, PICA texture storage

Efficient UI

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>
  );
}
PS Vita capture: the Pocket Tokyo title screen, its wordmark, a line of text, a clock and a list of five rows over the city. 1 2 3 4
The same four parts on a PS Vita, over the city the renderer draws. The code is abridged from Pocket Tokyo.

Written like the web

Components in JSX, state in SolidJS signals, layout in Tailwind classes. One app serves every console and takes a layout for each screen.

No browser on the console

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.

Small in a frame

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.

Built for coding agents

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, …);
PS Vita capture: the Radio Kaikan building at dusk, its facade covered in lit signs.

The same sign on a PS Vita, at 30 fps. An example exchange; the code is abridged from Pocket Atlas.

1

Write

Three.js and the scene DSL. It runs in a browser at once.

bun run dev
2

Compile

Lower the scene to one console's formats, with budgets checked.

bun tools/maneuver.ts cook
3

Deploy

Replace the binary running on the console.

bun tools/maneuver.ts native
4

Measure

Fly a fixed route and read back the late frames.

bun tools/maneuver.ts bench

read the numbers, write again

Make your first game

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.