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/snes9x-wasm

v0.1.1

Published

Snes9x (Super Nintendo / Super Famicom emulator) compiled to WebAssembly via Emscripten, with a JS SDK conforming to the wasm-gaming engine contract.

Readme

@wasm-gaming/snes9x-wasm

Snes9x — the long-running Super Nintendo / Super Famicom emulator — compiled to WebAssembly via Emscripten and packaged as a wasm-gaming engine SDK.

This subproject follows the same engine-package approach used by geolith-wasm, fbneo-wasm, jgenesis-wasm, blastem-wasm, and rsdkv*:

  • 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 }).

Snes9x ships several frontend ports (unix/, gtk/, libretro/); none of them suit a browser, so this package supplies its own (scripts/shim/s9x_shim.cpp) instead of an Emscripten SDL layer: no ASYNCIFY, no SDL, no emulated GL. The JS SDK drives one S9xMainLoop() per frame, blits the framebuffer to a 2D canvas, and streams audio through an AudioWorklet ring buffer. Emulation is audio-clocked: frames are produced to keep ~90 ms of audio queued, which locks speed to the audio hardware with no resampling drift.

ROM format

Pass the cartridge image as the rom asset: .sfc, .smc, .fig or .swc. The 512-byte copier headers some dumps carry are detected and skipped by the core, so both headered and unheadered images work. No BIOS is needed.

Enhancement chips are emulated in-core and need no extra files: Super FX / FX2, SA-1, DSP-1/2/3/4, S-DD1, SPC7110, C4, OBC1, S-RTC, SETA ST-010/011/018, and MSU-1.

The video standard follows the cartridge header (options.region: 'auto'), which is right for effectively every commercial release; force it with 'ntsc' / 'pal' for homebrew and hacks with a wrong or missing header.

Contract surface

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

const engine = await load({
  canvasEl: canvas,               // or attachTo: containerEl
  assets: {
    rom: sfcFileBytes,            // .sfc/.smc cartridge image
  },
  options: { region: 'auto', aspect: '4:3' },
  persist: 'opfs',
  storageNamespace: 'smw',
  onEvent: (e) => console.log(e),
});
engine.start();

Options

| Option | Default | Description | |--------|---------|-------------| | region | auto | Video standard: auto (from the ROM header), ntsc (60.098 Hz) or pal (50.007 Hz). | | interpolation | gaussian | DSP sample interpolation. gaussian matches real hardware; none/linear/cubic/sinc trade accuracy for sharpness. | | renderFilter | pixelated | Canvas scaling filter (pixelated or smooth). | | cropOverscan | true | Crop the picture to 224 lines. Disable to see all 239, including the rows many games leave as garbage. | | aspect | 4:3 | Presented aspect ratio: 4:3 (as on a CRT) or 1:1 square pixels. | | multitap | false | Emulate the 5-player Multitap in port 2 (pads 2-5). | | maxSpriteTilesPerLine | 34 | 34 matches hardware, including its sprite flicker; 128 removes dropout. | | superFXClockMultiplier | 100 | Super FX clock as a percentage of stock. Above 100 speeds up Star Fox / Yoshi's Island; a hack, not accuracy. | | volume | 1.0 | Master audio volume (0–1). | | gamepads | true | Poll connected gamepads (standard mapping) each frame. | | logLevel | error | Core messages printed to the console (off, error, debug). | | escMenu | true | Show the built-in in-game settings menu when the player presses Escape. |

In-game settings menu

Snes9x keeps its configuration in the core's global Settings struct, which the emulation re-reads as it runs — the DSP consults the interpolation mode per sample, the PPU the sprite limit per scanline — so almost every option above can be changed without restarting the game. load() mounts a settings overlay over the viewport that does exactly that — press Escape to open it.

  • ↑ ↓ select · ← → change · Enter apply · Esc close (mouse works too)
  • Changes persist per storageNamespace in localStorage and are re-applied on the next load(). Explicit options passed by the host still win.
  • region is tagged needs reset: the core reads the forced video standard while it maps the cartridge and clears it there, so the menu's Reset game re-maps the ROM to apply it (battery RAM is carried across).
  • Settings the loaded snes9x.wasm cannot apply — a build predating one of the shim's setters — are omitted rather than erroring, so the menu degrades cleanly against an older artifact.

Pass options: { escMenu: false } to suppress it and drive the settings yourself:

engine.config.write('maxSpriteTilesPerLine', 128); // no sprite dropout
engine.config.read('interpolation');               // 'gaussian'
engine.menu?.toggle();

Every knob is declared once in src/snes9x.options.ts; the manifest's options schema, the defaults and the menu are all derived from that catalog, so a new row there is enough to expose a new setting.

Capabilities

  • Save states: saveState() / loadState() via the core's in-memory snapshot API (S9xFreezeGameMem), ~800 KB for a typical cart.
  • SRAM persistence: battery-backed cartridge SRAM is persisted to OPFS (snes9x/<storageNamespace>/sram.bin) on pause/destroy and every 15 s; purgeStorage() removes the active namespace, along with the menu settings saved for it.
  • Screenshots: screenshot() returns a PNG blob.

Default controls

The face buttons follow the pad's own diamond layout on the keyboard: the bottom row is B/Y, the row above is A/X.

| Control | P1 | P2 | |---------|----|----| | D-pad | Arrow keys | I/K/J/L | | B / A | X / S | N / H | | Y / X | Z / A | B / G | | L / R | Q / W | T / Y | | Start | Enter | 2 | | Select | Right Shift | 1 |

Gamepads (standard mapping) are polled automatically. Because the SNES face buttons sit rotated relative to a modern pad, the physical bottom/right buttons map to B/A and the left/top ones to Y/X — the layout every SNES pad has had.

Rebind via engine.setInput({ 'p1.b': 'KeyJ', ... }) (KeyboardEvent codes).

Build

make build        # Full build: WASM (Docker/Emscripten) + TypeScript SDK
make build-sdk    # TypeScript only (SDK + manifest + demo shell)
make build-wasm   # Snes9x WASM only (via Docker)
make preview      # Serve dist/ at :8029 with COOP/COEP headers
make smoke        # Headless boot test (needs a ROM in roms/)

The WASM build clones a pinned Snes9x revision and compiles the enumerated core sources directly with emcc — no upstream-makefile patching and no autotools. The source list mirrors SOURCES_CXX in libretro/Makefile.common, minus the libretro port itself.

WASM artifacts

| File | Description | |------|-------------| | snes9x.js | Emscripten module loader (createSnes9xModule). | | snes9x.wasm | Compiled Snes9x core + shim (~2.1 MB). |

No SharedArrayBuffer or COOP/COEP headers are required at runtime (the preview server sets them anyway for parity with sibling engines).

See CORE.md for the mapping between upstream Snes9x capabilities and what this wrapper exposes.