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

@wasm-gaming/fbneo-wasm

v0.1.2

Published

FBNeo (FinalBurn Neo arcade emulator) compiled to WebAssembly via Emscripten, with a JS SDK conforming to the wasm-gaming engine contract.

Downloads

45

Readme

@wasm-gaming/fbneo-wasm

FinalBurn Neo (FBNeo) — the multi-system arcade emulator (Capcom CPS-1/2/3, SNK Neo Geo, Sega System 16, Cave, PGM, and many more) — compiled to WebAssembly via Emscripten and packaged as a wasm-gaming engine SDK.

This subproject follows the same engine-package approach used by jgenesis-wasm, blastem-wasm, rsdkv3, and rsdkv4:

  • typed manifest
  • typed options
  • load(config) engine SDK surface
  • Makefile-driven build (build-sdk, build-wasm, preview)

It conforms to the @wasm-gaming/engine-specs contract (EngineSDK = { manifest, load }).

Contract surface

import { manifest, load } from '@wasm-gaming/fbneo-wasm';

const engine = await load({
  canvas,                         // per engine-specs EngineConfig
  assets: {
    rom: romZipBytes,             // arcade ROM set (zip)
    bios: neogeoZipBytes,         // optional: e.g. neogeo.zip for Neo Geo sets
  },
  options: { driver: 'mslug', renderFilter: 'pixelated' },
  onEvent: (e) => console.log(e),
});
engine.start();

FBNeo identifies a game by the ROM zip filename (without extension). Pass the game short name explicitly via options.driver (e.g. "mslug", "sf2", "kof98"), or let it be inferred from options.romFileName / the picked file's name. (The bytes are always written to MEMFS as <driver>.zip, so the source file itself never needs renaming — only its name has to resolve to a driver.)

Identifying a ROM set from its contents

When the filename is unreliable (a browser-mangled mslug (1).zip) but the ROM files inside must keep their canonical names, recover the driver from the zip's contents with the opt-in @wasm-gaming/fbneo-wasm/romset helper. It matches the CRC-32s stored in the zip's central directory against a dataset of every FBNeo ROM set — the same identity FBNeo uses internally — so it is unaffected by re-compression, entry reordering, or split/merged packaging.

import { RomsetIndex, resolveDriver } from '@wasm-gaming/fbneo-wasm/romset';

// Load the dataset for the system(s) you support (per-system JSON, loaded on demand).
const neogeo = await fetch('/romsets/neogeo.json').then((r) => r.json());
const index = new RomsetIndex([neogeo]);

const match = resolveDriver(romZipBytes, index); // { driver: 'mslug', coverage: 1, ... } | null
const engine = await load({
  canvas,
  assets: { rom: romZipBytes },
  options: { driver: match?.driver }, // fall back to your own logic when null
});

The dataset ships as data/romsets/<system>.json (also served at /romsets/… from the built dist/); data/romsets/index.json lists the systems and game counts. Regenerate it from a pinned FBNeo checkout with make romsets.

Each ROM entry carries its internal name (n) and CRC-32 (c). neogeo.json additionally carries each chip's size (s) and hardware region (r) — the chip layout — which is what lets the neo helper below rebuild a ROM set from a flash-cart image.

Because the match is by CRC-32 — and FBNeo itself looks ROM chips up by CRC before falling back to their names — a set is usually accepted as downloaded: extra files, subdirectories, and non-canonical chip filenames inside the zip do not matter. Only the zip's name has to resolve to a driver, which is exactly what this helper supplies.

Neo Geo .neo files (NeoSD / Terraonion)

FBNeo reads .zip and .7z ROM sets only. A .neo — the single-file format for NeoSD/Terraonion flash carts, and how most Neo Geo homebrew is distributed — is a 4 KiB header followed by each ROM region as one contiguous blob (with the sprite region byte-interleaved as the cartridge wires it), so it cannot be handed to the engine as-is. The opt-in @wasm-gaming/fbneo-wasm/neo helper rebuilds the chip split FBNeo expects, in the browser and with no dependencies:

import { isNeoFile, neoToRomset } from '@wasm-gaming/fbneo-wasm/neo';

const neogeo = await fetch('/romsets/neogeo.json').then((r) => r.json());

if (isNeoFile(bytes)) {
  const { driver, zip } = neoToRomset(bytes, neogeo); // throws if it cannot be rebuilt
  await load({ canvas, assets: { rom: zip }, options: { driver } });
}

It identifies the driver by matching the .neo's region sizes against the chip layouts in data/romsets/neogeo.json, rebuilds the individual chip dumps (de-interleaving sprites, undoing the HARDWARE_SNK_SWAPP program-ROM swap), and CRC-32 verifies every chip before returning — so it throws loudly rather than handing the engine a broken set. The zip it returns is stored, not deflated: FBNeo decompresses each chip immediately, so compressing would only be undone.

The same conversion is available offline, which is handy for preparing a set once rather than on every page load:

node scripts/neo2romset.mjs mygame.neo --out ./roms   # needs `make build-lib`

Sets whose program ROM lives inside the SMA custom chip cannot be reproduced by a straight carve; those fail CRC verification and are reported rather than written.

Options

| Option | Default | Description | |--------|---------|-------------| | romFileName | game.zip | Filename used when writing ROM bytes to MEMFS. | | driver | (inferred) | FBNeo ROM set short name to boot. | | renderFilter | pixelated | pixelated (crisp) or smooth (linear). | | audioSampleRate | 44100 | Target audio sample rate in Hz. | | vsync | true | Enable vertical sync. | | integerScale | false | Integer scaling only. | | windowScale | 2 | Internal render-resolution multiplier. |

Build

make build        # Full build: WASM (Docker/Emscripten) + TypeScript SDK
make build-sdk    # TypeScript only (SDK + manifest + demo shell)
make build-wasm   # FBNeo WASM only (via Docker)
make preview      # Serve dist/ with COOP/COEP headers

WebAssembly threads/SharedArrayBuffer require the COOP/COEP headers that make preview sets — serve the built dist/ with those headers in production too.

WASM artifacts

| File | Description | |------|-------------| | fbneo.js | Emscripten-generated module loader (createFbneoModule). | | fbneo.wasm | Compiled FBNeo runtime. |

FBNeo uses Emscripten SDL2. The JS loader expects a <canvas id="canvas"> in the DOM (the SDK sets this id automatically). ROM zips are written to the in-memory MEMFS under /roms/ before the emulator boots, and FBNeo is launched with the driver short name.

See CORE.md for the mapping between upstream FBNeo capabilities and the options currently exposed by this wrapper.