npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

romdev-core-runner

v0.2.5

Published

Play a ROM you just built: an SDL window over the romdev libretro host (romdev-core-host) with keyboard + hot-plug gamepad input, audio, and aspect-correct pixel-perfect scaling. The human 'fire it up' tier between an external emulator and the romdev MCP

Readme

romdev-core-runner

Play the ROM you just built: one call opens a real SDL window running any romdev-core-* emulator core, with keyboard + hot-plug gamepad input, audio at the core's native rate, and aspect-correct pixel-perfect scaling.

import { runRom } from "romdev-core-runner";
import * as core from "romdev-core-fceumm"; // any romdev-core-* package

const session = await runRom("game.nes", { core });
await session.closed; // resolves when the human closes the window

rom is a file path or raw Uint8Array bytes. No cores are bundled; the caller passes the core package (or a { jsPath, wasmPath } pair). This is the same SDL host the romdev MCP server's playtest window is built on (the server layers agent-tier extras on top). One host implementation in the whole ecosystem.

Options

runRom(rom, {
  core,        // REQUIRED: romdev-core-* package namespace or { jsPath, wasmPath }
  platform,    // platform id; inferred from the core package when possible
  scale: 3,    // initial window size, in multiples of the framebuffer
  title,       // window title (default: ROM basename + platform)
  aspect: "tv",// "tv" (real-hardware display shape) | "fb" (raw framebuffer)
               // | "core" (core-reported ratio)
  buttonMap,   // SDL button name -> RetroPad bit, replaces the default map
  keyMap,      // keyboard key -> RetroPad bit, replaces the default map
  log,         // (msg) => void progress/warning logger (default: silent)
})

buttonMap / keyMap exist for platforms with custom layouts (GameTank's two-button pad, C64 joystick + keyboard); the defaults cover the standard console pads.

The session object

runRom resolves once the window is up:

const { stop, closed, host, frameCount, running } = session;
  • closed resolves when the window closes (ESC, close button, or Select+Start on the pad). stop() closes it programmatically.
  • host is the live romdev-core-host LibretroHost instance, so while the human plays you can read/write memory, take screenshots, save states, or set cheats from the same process.

Controls

Gamepads hot-plug (connect/disconnect any time). Face buttons follow physical position: SDL bottom = RetroPad B (main action), right = A, left = Y, top = X. Analog left stick doubles as the d-pad past a deadzone.

Keyboard fallback: arrows = d-pad, Z/X/A/S = the same four face positions, Enter = Start, Right-Shift (or Backspace) = Select, Q/W = L/R shoulders. ESC closes the window.

The title bar shows live fps (<game> | 60 fps, updated once a second) — the rate the machine actually achieves, not the target.

SDL availability

@kmamal/sdl is an optionalDependency, declared once here so consuming CLIs and SDKs never carry it themselves. When its native binary is missing, runRom first re-runs SDL's own install script (self-repair), and only then throws a structured error, never a hard module-load crash:

try {
  await runRom("game.nes", { core });
} catch (e) {
  if (e.code === "SDL_UNAVAILABLE") console.error(e.fixCmd); // print, don't crash
}

so a headless environment (CI, a container) can import this package safely and print its own "install SDL or use an external emulator" message.

Building a custom frontend

The presentation layer is exported for frontends that want the maps and math without the stock window: SDL_BUTTON_TO_LIBRETRO_BIT, KEY_TO_LIBRETRO_BIT, STICK_DEADZONE, bitToName(bit), tvAspectFor(platform, displayAspect), effectiveAspect(statusAspect, fbW, fbH) (a usable ratio even when the host reports 0/NaN), initialWindowSize({fbWidth, fbHeight, scale, aspectMode, platform, displayAspect}) (the tested open-size math — never produces a zero-size window), letterbox(winW, winH, aspect), framebufferToRgba(fb, out?) (pass the previous return value as out to reuse the buffer across ticks — no per-frame allocation), and drawFpsOverlay(rgba, width, height, fps) (the corner fps counter, pure pixel writes), plus initSdl() (the hardened loader) and sdlPackageRoot().

Requirements

Node >= 24, ESM only. Software-rendered cores work everywhere SDL does; the 3D cores additionally want the native-gles optional dependency (see the romdev-core-host README).