NES EMULATOR
jsnes
jsnes is an open-source JavaScript Nintendo Entertainment System (NES) emulator that runs in web browsers and in Node.js. It is provided as a library (NES class) and a higher-level Browser embedding class for easy integration into web pages or frameworks.

WHY IT MATTERS
Why use jsnes?
jsnes is a compact, embeddable NES core written in JavaScript. Use it when you need a browser-first or Node.js-capable NES implementation with a simple API for frames, audio samples, input, and save serialization. It is suitable for demos, web integrations, teaching, and small homebrew projects where distribution as plain JavaScript or an npm package is desirable.
BEST FOR
Best for
Embedding an NES emulator into a website or web app, building a custom frontend (React/Vue/etc.) around an NES core, experimenting with NES internals in JavaScript, or running NES code in Node.js for tooling/testing.
The people behind jsnes
History and status
jsnes is a long-lived JavaScript NES project whose public presence dates back to 2009 (contemporary coverage and project pages appear from that period). The project has an active repository on GitHub with ongoing commits and tagged releases; it is distributed as an open-source library intended to run in browsers and Node.js. The maintainers provide both a low-level NES class for custom integrations and a Browser helper class that supplies convenient canvas rendering, Web Audio output, keyboard and gamepad handling, and basic embedding code. The project focuses on a lightweight, JavaScript-native approach rather than a multi-system frontend or maximal hardware-accuracy corner-case emulation.
What jsnes supports
- Web browsers (Canvas + Web Audio; modern browsers)
- Node.js (NES class for headless or custom integrations)
- Bundlers (npm package / unpkg)
- Gamepad input (browser Gamepad API) and keyboard
Download and availability
OFFICIAL DOWNLOADS
Get jsnes
Official source, releases, and distribution are available from the project's GitHub repository and its releases page. The library is also available via npm and a production bundle is published on unpkg.
Get jsnes ↗DOCUMENTATION
Official documentation
Read the official configuration, compatibility, and troubleshooting material before changing advanced options.
Read official documentation ↗jsnes setup guide
Setup note: This setup guide covers getting jsnes running in a browser page, using the Browser helper, and using the low-level NES class in Node.js or a custom frontend. The guide focuses on practical, verifiable steps and common pitfalls (CORS, serving files, save persistence).
- 1) Obtain the code: Grab the official repository or releases from the project's GitHub page (source, examples, and release bundles are published there). For bundler-based projects, install from npm (npm install jsnes). For quick demos use the prebuilt bundle served by unpkg.
- 2) Quick browser demo using the Browser helper: Add the production bundle to a page (for example, using the unpkg URL for the package version), create a container element, then instantiate jsnes.Browser with the container. Use Browser.loadROMFromURL() to load a .nes file by URL (note: many browsers block local file requests when opened via the file:// scheme; serve files from an HTTP server). The Browser helper manages canvas rendering, audio via Web Audio API, keyboard and Gamepad input, and frame timing automatically.
- 3) Serving ROM files and CORS considerations: When loading ROMs from a URL the browser enforces same-origin/CORS rules. Host your ROM files on the same origin as your page or ensure the server sets permissive CORS headers. For local testing, run a simple local HTTP server (for example npx serve or python -m http.server) rather than opening the HTML file directly with file://.
- 4) Using the low-level NES class (Node.js or custom rendering): Import or require jsnes.NES, create an instance with callbacks: onFrame(frameBuffer) to receive a 256×240 ARGB buffer per frame, onAudioSample(left, right) for audio samples, and onBatteryRamWrite(address, value) to capture battery-backed save writes. Load ROM data as a binary string or Uint8Array via nes.loadROM(data) and drive emulation by calling nes.frame() at ~60 FPS (you are responsible for timing).
- 5) Input, controllers, and gamepads: jsnes exposes button constants (BUTTON_A, BUTTON_B, BUTTON_START, etc.). In the Browser helper keyboard and Gamepad API are handled automatically; for custom setups call nes.buttonDown(player, jsnes.Controller.BUTTON_A) and nes.buttonUp(…) in response to input events. Map physical devices to these calls and implement turbo behaviour if desired using repeated press/release logic.
- 6) Audio and performance: The core provides audio sample callbacks and defaults to a 48000 Hz sample rate. When using the Browser helper, audio is produced via the Web Audio API. If your frontend does custom audio mixing, resampling to the host audio rate may be necessary. Performance depends on the host device and browser; the project is optimized for JavaScript engines but large-scale accuracy fixes or expansion audio implementations may affect speed.
- 7) Save data and state: Battery-backed SRAM writes are exposed via the onBatteryRamWrite callback; use this to persist saves (localStorage, IndexedDB, or server). For save states, the NES class supports toJSON() and fromJSON() methods to serialize and restore emulator state—implement your own storage policy for persistence or cloud-sync.
- 8) Example integration with modern frameworks: When embedding in frameworks (React/Vue), create the Browser instance on mount and destroy it on unmount. A sample React usage is available in the repository showing useRef to hold the container and calling new Browser({ container, romData }). Ensure the container has sufficient CSS size for the canvas and that audio context is resumed in response to a user gesture if browsers block autoplay.
Software reminder: jsnes is distributed as source and example bundles; it does not include commercial game ROMs, firmware, BIOSes, or other copyrighted content. Provide your own legally-obtained .nes files. When serving ROM files for development, use an HTTP server to avoid file:// restrictions.
Sources and further reading
Detailed guides and tutorials
Explore step-by-step guides for jsnes as they are published.
Retro Replay Retro Gaming History, Reviews & Emulation