New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

gboy-ts

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gboy-ts

A headless Game Boy (DMG) emulator in TypeScript, built for serverless

latest
npmnpm
Version
1.0.0
Version published
Maintainers
1
Created
Source

gboy.ts

A Game Boy emulator in TypeScript, designed for the browser and serverless environments.

The emulator runs headlessly with no DOM or Canvas dependency. Frames render to a raw Uint8Array RGBA buffer that can be encoded to PNG/JPEG or rendered to a terminal.

Quick Start

# Install
bun install

# Run tests
bun test

# Debug a ROM in the terminal
bun run debug path/to/rom.gb --watch

Examples

ExamplePathDescription
Vite Browserexamples/vite-browser/Client-side emulation via Web Worker + bidc
Next.jsexamples/nextjs/Server-side emulation with App Router API routes
Screenshotexamples/screenshot.tsCLI tool to capture a PNG from any ROM

Browser Demo (Worker + bidc)

Run the browser demo (Vite + Web Worker):

# From repo root:
bun install
bun --cwd examples/vite-browser install

# Start demo:
bun run demo:browser

Then open the printed local URL, load a .gb/.gbc ROM, and use keyboard controls:

  • Arrows: D-pad
  • Z / X: A / B
  • Enter / Backspace: Start / Select
  • Space: pause/resume

The browser worker protocol is powered by bidc.

Next.js Demo (App Router)

A full Next.js App Router example with server-side emulation and a Game Boy UI. Stores data in memory; move to e.g. Redis for statefulness.

# From repo root:
bun install
bun --cwd examples/nextjs install

# Place a ROM in the example directory:
cp path/to/rom.gb examples/nextjs/rom.gb

# Start the dev server:
bun run demo:nextjs

The app exposes four API routes:

RouteMethodDescription
/api/frameGETReturns the current frame as PNG (?advance=N)
/api/inputPOSTSends a button press, returns the resulting frame
/api/resetPOSTResets the game, returns the first frame
/api/stateGETReturns game info (title, ROM size, frame count)

Controls are the same as the browser demo (arrows, Z/X, Enter, Backspace, Space).

Debug CLI

bun run debug <rom-path> [options]

Options

FlagDefaultDescription
--format <fmt>green-halfRender format (see below)
--width <n>80Output width in characters
--frames <n>300Frames to run (batch mode)
--interval <n>-Print every N frames (batch mode)
--press <btn>-Press button at midpoint (batch mode)
--statsoffShow framebuffer stats
--watchoffInteractive mode

Render Formats

FormatDescription
green-halfTruecolor DMG green palette + half-block chars (highest quality)
greenTruecolor DMG green, 1 char per pixel
ansi-half256-color grayscale + half-blocks
ansi256-color grayscale backgrounds
asciiPunctuation shading: .:-=+*#%@
blocksUnicode blocks: ░▓█
half-blocksUnicode half-blocks (no color)

Interactive Controls (--watch mode)

KeyAction
Arrow keysD-pad
ZA button
XB button
EnterStart
BackspaceSelect
SpacePause / Resume
] or FSpeed up (1x / 2x / 4x / 8x / 16x)
[ or DSlow down
1-5Set speed directly
SStep one frame (while paused)
IToggle stats overlay
RReset emulator
Q / Ctrl+CQuit

Programmatic Usage

import { Emulator, Button } from "./src/emulator";

// Load ROM
const rom = new Uint8Array(await Bun.file("pokemon.gb").arrayBuffer());
const emu = new Emulator(rom);

// Run frames
emu.runFrames(60);

// Handle input
emu.pressButton(Button.A);
emu.runFrames(5);
emu.releaseButton(Button.A);

// Get framebuffer (160x144 RGBA)
const fb = emu.getFramebuffer(); // Uint8Array, 92160 bytes

// Save state (excludes ROM data)
const state = emu.serialize();
await Bun.write("save.state", state);

// Restore state
const saved = new Uint8Array(await Bun.file("save.state").arrayBuffer());
const emu2 = Emulator.deserialize(rom, saved);
emu2.runFrames(1); // continues where it left off

Browser Imports

Use the browser-safe entrypoint when bundling for the browser:

import { BrowserEmulatorClient, Button } from "gboy-ts/browser";

gboy-ts/browser excludes Node-only exports like PNG encoding.

Serialization

State serialization is designed for frequent save/load in serverless:

  • ROM data is never included in serialized state
  • Save state is ~110KB (CPU: 13B, MMU: 18KB, PPU: 92KB, Timer: 12B, Joypad: 9B, Cartridge: 8B + RAM)

Known Limitations

  • No DMA timing - OAM DMA transfer is not cycle-accurate

Tests

bun test
bun test --watch      # Watch mode
bun test src/__tests__/cpu-alu.test.ts   # Run specific test file

Keywords

gameboy

FAQs

Package last updated on 17 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts