Skip to content

Latest commit

 

History

History
518 lines (394 loc) · 18.8 KB

API.md

File metadata and controls

518 lines (394 loc) · 18.8 KB

cfxnes API

cfxnes([options])

Function that returns new emulator instance.

options - initialization options. See the following documentation sections for their description. Options with undefined value will be ignored.

let nes;

// No options specified
nes = cfxnes();

// All options and their default values
nes = cfxnes({
  region: 'auto',
  speed: 1,
  rom: undefined,
  JSZip: undefined,
  video: {
    output: null,
    renderer: 'webgl',
    scale: 1,
    palette: 'fceux',
    filter: 'nearest',
    debug: false,
  },
  fullscreen: {
    type: 'maximized',
  }
  audio: {
    enabled: true,
    volume: {
      master: 0.5,
      pulse1: 1,
      pulse2: 1,
      triangle: 1,
      noise: 1,
      dmc: 1,
    },
  },
  devices: {
    1: 'joypad',
    2: 'zapper',
  },
  inputs: {
    '1.joypad.a': 'keyboard.x',
    '1.joypad.b': ['keyboard.y', 'keyboard.z'],
    '1.joypad.start': 'keyboard.enter',
    '1.joypad.select': 'keyboard.shift',
    '1.joypad.up': 'keyboard.up',
    '1.joypad.down': 'keyboard.down',
    '1.joypad.left': 'keyboard.left',
    '1.joypad.right': 'keyboard.right',
    '2.zapper.trigger': 'mouse.left',
  },
});

Properties

Name Type Writable Default Description
version string no cfxnes version.
logLevel string yes 'warn' Verbosity of logging for all emulator instances.
'off' - Logging is disabled.
'error' - Log errors.
'warn' - Log errors and warnings.
'info' - Log errors, warnings and info messages.
cfxnes.version; // '0.4.0', '1.0.0', '1.2.1', etc.

cfxnes.logLevel = 'off'; // Disable logging
cfxnes.logLevel = 'info'; // Log everything

nes

Emulator instance returned by the cfxnes function.

Properties

Name Type Writable Default Description
running boolean no false true when emulator is running, false otherwise.
fps number no Number of frames per second of running emulator.
region string yes 'auto' Emulated NES region.
'auto' - Automatic region detection (not very reliable).
'ntsc' - NTSC region (60 FPS).
'pal' - PAL region (50 FPS).
speed number yes 1 Emulation speed multiplier. It must be larger than 0.
nvram Uint8Array no null Provides access to NVRAM. NVRAM (Non-Volatile RAM) is a memory that is usually battery-backed and serves as a place for game saves. NVRAM is only used by some games (e.g., The Legend of Zelda or Final Fantasy). The property is null when NVRAM is not available.
rom object no ROM module
video object no Video module
fullscreen object no Fullscreen module
audio object no Audio module
devices object no Devices module
inputs object no Inputs module
config object no Configuration module

Methods

Signature Description
start() Starts emulator.
stop() Stops emulator.
step() Forces emulator to render one frame.
power() HW reset (NES power button).
reset() SW reset (NES reset button).
const nes = cfxnes();

nes.region = 'pal'; // Set PAL region
nes.speed = 1.5; // Set 1.5x emulation speed

nes.running; // false
nes.start(); // Start emulator
nes.running; // true
nes.stop(); // Stop emulator
nes.running; // false

nes.power(); // HW reset
nes.reset(); // SW reset

if (nvram.data) {
  nvram.data.fill(0); // Clear NVRAM of the currently running game
}

nes.rom

Module that can load ROM images into emulator.

Supported ROM image formats are iNES and NES 2.0. Cfxnes can also load zipped ROM image when JSZip library (^3.1.0) is present. JSZip can be provided either through global variable window.JSZip or using JSZip initialization option.

cfxnes({JSZip});

ROM image can be loaded in two ways:

  1. Use the rom initialization option. This will load ROM image from the specified source and then automatically starts execution. All loading errors will be logged using console.error.
  2. Call the nes.rom.load() method. This allows more precise control over the loading process.
// 1. Use the 'rom' initialization option
const nes = cfxnes({rom: source});

// 2. Call the nes.rom.load() method
nes.rom.load(source)
  .then(() => {/* handle success */})
  .catch(error => {/* handle error */})

The source can be Uint8Array, ArrayBuffer, Array, Blob or string. String value is interpreted as URL of a ROM image.

Properties

Name Type Writable Default Description
loaded boolean no false true when a ROM image is loaded, false otherwise.
sha1 string no null SHA-1 of loaded ROM image, null otherwise.

Methods

Signature Returns Description
load(source) Promise Loads ROM image from the specified source.
unload() Unloads loaded ROM image.
const nes = cfxnes();
const {rom} = nes;

rom.loaded; // false
rom.sha1; // null

// Load ROM image from relative URL
rom.load('data/game.nes').then(() => {
  rom.loaded; // true
  rom.sha1; // SHA-1 of the loaded image
  rom.unload(); // Unload the image
  rom.loaded; // false;
}).catch(error => {
  console.error('Oops!', error);
})

// Load ROM image from memory or blob
var data = getData(); // Uint8Array, ArrayBuffer, Array, Blob
rom.load(data).then(/* ... */);

nes.video

Display settings module.

Cfxnes requires a canvas element to render its video output. The canvas can be specified in several ways:

  1. Create canvas element with cfxnes ID. It will be automatically used during cfxnes initialization.
  2. Use the video.output initialization option.
  3. Use the nes.video.output property.
<canvas id="cfxnes"><canvas>
<script>
  const canvas = document.getElementById('cfxnes');

  // 1. There is a canvas element with 'cfxnes' ID.
  let nes = cfxnes();
  nes.video.output === canvas; // true

  // 2. Use the 'video.output' initialization option.
  nes = cfxnes({
    video: {output: canvas}
  });

  // 3. Use the 'nes.video.output' property
  nes.video.output = canvas;
</script>

In case there is no ROM image loaded, running emulator will display white noise as its video output.

Once the output is set, it is not possible to change value of the renderer property. To change renderer, you need to use a different canvas with uninitialized context (see example bellow).

Properties

Name Type Writable Default Description
output HTMLCanvasElement yes null Canvas element used to render emulator video output. The property can be set to null to disable rendering.
renderer string yes 'webgl' Rendering back-end.
'canvas' - Renderer using Canvas API. It is used as fallback when WebGL is not available.
'webgl' - Renderer using WebGL. It should be faster than the 'canvas' renderer, but this highly depends on browser, OS, graphic card driver, etc.
palette string yes 'fceux' Palette used for generating RGB color values. Allowed values are:
'asq-real-a', 'asq-real-b', 'bmf-fin-r2', 'bmf-fin-r3', 'fceu-13', 'fceu-15', 'fceux', 'nestopia-rgb', 'nestopia-yuv', 'sony-cxa2025as', 'unsaturated-v6'
See FCEUX documentation for their description.
scale number yes 1 Canvas resolution multiplier. It must be larger than 0. Non-integer value might cause visual artifacts due to upscaling. The base resolution is 256x240.
filter string yes 'nearest' Filter used during upscaling.
'nearest' - Nearest-neighbor interpolation.
'linear' - Linear interpolation.
debug boolean yes false Enables additional video output (content of pattern tables and background/sprite palettes) to be rendered on canvas. This will also double width of the canvas.

Methods

Signature Returns Description
clear() void Clears canvas.
const nes = cfxnes();
const {video} = nes;

video.renderer = 'webgl'; // Renderer can be only changed before the output is set
video.output = document.getElementById('canvas'); // Set output
video.palette = 'nestopia-rgb'; // Set palette
video.scale = 2; // Set 2x resolution scale
video.filter = 'linear'; // Linear interpolation
video.debug = true; // Enable debug output

// To change renderer, we need a different canvas with uninitialized context
video.output = null; // Disconnect the currently used canvas
video.renderer = 'canvas'; // Change the renderer
video.output = document.getElementById('canvas-2'); // Use a different canvas

nes.fullscreen

Fullscreen module.

It is recommended to wrap used canvas element in extra div to make fullscreen working properly.

Properties

Name Type Writable Default Description
is boolean no false true when emulator is in fullscreen mode, false otherwise.
type string yes 'maximized' Type of fullscreen mode.
'maximized' - Maximizes output resolution while keeping its original aspect ratio.
'normalized' - Same as the 'maximized' type, but output resolution is integer multiple of the base resolution 256x240. This should reduce visual artifacts caused by upscaling.
'stretched' - Output is stretched to fill the whole screen (both horizontally and vertically). The original aspect ratio is not preserved.

Methods

Signature Returns Description
enter() Promise Switches to fullscreen mode. The method does nothing when fullscreen is on.
exit() Promise Returns from fullscreen mode. The method does nothing when fullscreen is off.
const nes = cfxnes();
const {fullscreen} = nes;

fullscreen.is; // false
fullscreen.type = 'stretched'; // Make fullscreen 'stretched'

// Note: Due to security reasons, browsers typically block fullscreen
//       requests that are not tied to user input (e.g., button click).
fullscreen.enter().then(() => {
  fullscreen.is; // true
}).catch(error => {
  console.error('Oops!', error); // Browser refused fullscreen request
});

nes.audio

Audio settings module.

The nes.audio property is null when browser does not support Web Audio (currently only IE 11 and older).

Properties

Name Type Writable Default Description
enabled boolean yes true true when audio output is enabled, false otherwise.
volume object no Audio volume configuration.
volume.master number yes 0.5 Master volume.
volume.pulse1 number yes 1 Pulse channel #1 volume.
volume.pulse2 number yes 1 Pulse channel #2 volume.
volume.triangle number yes 1 Triangle channel volume.
volume.noise number yes 1 Noise channel volume.
volume.dmc number yes 1 DMC channel volume.
const nes = cfxnes();
const {audio} = nes;

if (audio) {
  audio.enabled = false; // Disable audio
  audio.volume.master = 1; // Maximize the overall volume
  audio.volume.dmc = 0; // Mute the DMC channel
} else {
  console.log('Web Audio not supported!');
}

nes.devices

Module that allows to set up input devices.

NES has 2 input ports, each of them can be assigned a device through numeric property. Allowed values are:

  • 'joypad' - Standard NES controller.
  • 'zapper' - NES Zapper (beam gun).
  • null - No device.

Properties

Number Type Writable Default Description
1 string yes 'joypad' Device connected to port #1.
2 string yes 'zapper' Device connected to port #2.
const nes = cfxnes();
const {devices} = nes;

devices[1] = 'zapper'; // Set zapper on port #1
devices[2] = null; // Make port #2 empty

nes.inputs

Module that allows to set up input controls.

There are 2 kinds of input devices:

  1. The ones being emulated (see nes.devices section). We refer to them as devices.
  2. The real ones (keyboard, mouse, gamepad, etc.). We refer to them as sources.

Input of any device can be expressed as a string '<port>.<device>.<name>':

  • <port> - port (1 or 2)
  • <device> - device ('joypad' or 'zapper')
  • <name> - name of the input

Input of any source can be expressed as a string '<source>.<name>':

  • <source> - source ('keyboard', 'mouse', 'gamepad0', 'gamepad1', ...)
  • <name> - name of the input

Examples:

  • '1.joypad.start' - Start button of a joypad connected to port #1.
  • '2.zapper.trigger' - Trigger button of a zapper connected to port #2.
  • 'keyboard.ctrl' - Ctrl key.
  • 'mouse.left' - Left mouse button.
  • 'gamepad0.start' - Start button of gamepad #0.
  • 'gamepad1.x' - X button of gamepad #1.

Properties

Name Type Writable Description
state object no Submodule that holds state of all inputs.
- For buttons, the state is boolean.
- For '{1,2}.zapper.beam', the state is array of 2 numbers [x, y] (beam coordinates).
map object no Submodule that holds mapping between inputs.

Methods

Signature Description
state.get(devInput) Returns state of a device input.
state.set(devInput, state) Sets state of a device input.
map.get(input) Returns mapping of an input.
map.set(devInput, srcInput) Sets mapping between source and device input.
map.delete(input) Deletes mapping of an input.
record(callback) Registers callback function that will be called when the next source input is received. The callback is immediately dropped after its use. Typical use of this method is to let users customize key bindings.
const nes = cfxnes();
const {inputs} = nes;

// State
inputs.state.set('1.joypad.a', true); // Press 'A button' of joypad #1
inputs.state.get('1.joypad.a'); // Returns true

// Mapping
inputs.map.delete('1.joypad.a'); // Delete mapping of a device input
inputs.map.get('1.joypad.a'); // Returns []
inputs.map.set('1.joypad.a', 'keyboard.z'); // Map 'A button' of joypad #1 to 'Z' key
inputs.map.set('1.joypad.a', 'keyboard.y'); // Map the same input to 'Y' key
inputs.map.get('1.joypad.a'); // Returns ['keyboard.z', 'keyboard.y']
inputs.map.delete('keyboard.z'); // Delete mapping of a source input
inputs.map.get('1.joypad.a'); // Returns ['keyboard.y']

// Interactive rebinding
const devInput = '1.joypad.a';
showUserMessage('Press key or button...');
inputs.record(srcInput => {
  inputs.map.delete(devInput); // Delete previous mapping for each input
  inputs.map.delete(srcInput);
  inputs.map.set(devInput, srcInput); // Set new mapping
  hideUserMessage();
})

Joypad Inputs

Input Name
A, B buttons 'a', 'b'
Start, Select buttons 'start', 'select'
D-pad buttons 'left', 'right', 'up', 'down'

Zapper Inputs

Input Name
Trigger 'trigger'
Beam position It is permanently mapped to mouse cursor position.

Keyboard Inputs

Input Name
Character keys (letters) 'a', 'b', ..., 'z'
Character keys (numbers) '0', '1', ..., '9'
Character keys (special) 'space', ',', '.', '/', ';', '\'', '\\', '[', ']', '``', '-', '='
Function keys 'f1', 'f2', ..., 'f12'
Modifier keys 'shift', 'ctrl', 'alt'
Navigation keys 'left', 'up', 'right', 'down', 'tab', 'home', 'end', 'page-up', 'page-down'
System keys 'escape', 'pause'
Editing keys 'enter', 'backspace', 'insert', 'delete'
Lock keys 'caps-lock', 'num-lock', 'scroll-lock'
Numeric keypad 'numpad-0', 'numpad-1', ..., 'numpad-9', 'add', 'subtract', 'multiply', 'divide', 'decimal-point'

Mouse Inputs

Input Name
Left, middle, right button 'left', 'middle', 'right'

Gamepad Inputs

The set of inputs that are received from a gamepad depends on whether browser is able to recognize gamepad layout. If the gamepad is correctly recognized, the standard layout is used. Otherwise the generic layout is used as fallback.

Standard Gamepad Layout

standard layout

Input Name
A, B, X, Y buttons 'a', 'b', 'x', 'y'
Back, Start, Guide buttons 'back', 'start', 'guide'
D-pad 'dpad-up', 'dpad-down', 'dpad-left', 'dpad-right'
Triggers 'left-trigger', 'right-trigger'
Bumpers 'left-bumper', 'right-bumper'
Sticks (buttons) 'left-stick', 'right-stick'
Sticks (axes) 'left-stick-x', 'left-stick-y', 'right-stick-x', 'right-stick-y'

To specify axis direction, '+' or '-' must be appended (e.g., 'left-stick-x-', 'left-stick-x+').

Generic Gamepad Layout

Input Name
Buttons 'button-0', 'button-1', ...
Axes 'axis-0', 'axis-1', ...

To specify axis direction, '+' or '-' must be appended (e.g., 'axis-0-', 'axis-0+').

nes.config

Module that provides access to emulator configuration.

The structure of configuration options corresponds to structure of initialization options (see cfxnes) with exception of rom, JSZip, video.output that are ignored.

Signature Description
get() Returns all options and their values.
use(options) Applies values of specified options.
const nes = cfxnes();
const {config} = nes;

const defaults = config.get(); // Get default configuration
config.use({region: 'pal'});   // Update configuration
config.use(defaults);          // Restore default configuration