PocketVibe

How PocketVibe works

Short version: PocketVibe sets up a tiny website and a browser inside your handheld. The menus and the games are all web pages, running on the device itself, with no internet needed.

Why a browser engine?

three.js draws 3D with WebGL, and WebGL only exists in browsers. So the handheld needs a browser.

Chrome and Firefox are too heavy for it, and they want a desktop around them. We use WPE WebKit: Safari's engine, in the version made for small devices like TV boxes and car screens. No address bar, no window; it draws straight to the screen. Cog is the smallest browser built on it: one page, full screen.

A frame of a game reaches the screen through these layers:

  1. The gamethree.js, in JavaScriptWebGL
  2. WPE WebKitinside Cog, full screenOpenGL ES
  3. Mesa Panfrostthe open-source GPU driver
  4. Mali-G31 GPUand the screen

Getting the engine onto the handheld

ROCKNIX is very lean: it has no WPE, and no package manager to install one. So we packed WPE, Cog and Mesa into a small Debian file system.

What runs on the handheld

PocketVibe.sh

What the Ports menu starts. Sets things up, starts the service, opens the browser, and reopens it if it crashes.

pocketvibed

A small web server in Python, the handheld's backend. Downloads games, keeps settings and saves, installs updates.

Cog

The browser. It opens the launcher, and the games from there.

Why does each game get its own port? Browsers keep saves per address. A port per game means its own storage, so its own saves, and no game can read another's.

What happens when you press A

  1. The launcher asks the service to start the game.
  2. The service starts a small server for that game on its own port, and says where it is.
  3. The browser opens the game's shell there.
  4. The shell shows the cover and the name, and loads the game sized for the screen.
  5. The game sets up WebGL, reads the buttons and starts its loop. Once the first frames are drawn, the cover fades away.

Going back: hold Start + Select. The service reads those buttons straight from Linux, not through the browser, so you can leave even if a game freezes. Hold them for three seconds to quit.

Buttons and sound: games read the controls through the browser's Gamepad API. WebKit only allows sound after a real key press, and gamepad buttons do not count. So the service taps a virtual F13 key that nothing uses. A bit of a hack, but it works.

On Android

The launcher, the shell and the games are the same files. Only the layers under them change:

That is why the same game can run smoother on an Android handheld: Chrome's graphics path is very mature, and the maker's own driver is faster than Mesa on a Mali-G31.

The store, and this website

The hard part: speed

The setup itself is simple. The hard part is 60 fps on a small GPU through a browser engine. So we measured what everything costs on the handheld: triangles, draw calls, shadows, and more. Those numbers became the rules the AI follows when it writes a game. That is the difference between 3 to 6 fps for typical three.js code and 60 fps for games that follow the rules.

See the measured limits · The code on GitHub