Skip to main content
The LibretroNativeCore class is the main entry point for native libretro emulation in GameLord. It handles path validation, directory setup, and autosave management before delegating actual emulation to a worker process.
This class does not load the native addon or drive the emulation loop directly. Those responsibilities belong to the worker process managed by EmulationWorkerClient.

Architecture

In the current architecture, the actual emulation loop runs in a dedicated utility process. LibretroNativeCore is responsible for:
  1. Path validation — Ensuring ROM and core paths are safe before handing them to the worker process
  2. Config storage — Exposing validated paths so EmulationWorkerClient can initialize the worker
  3. Autosave management — Filesystem checks for resume-game prompts that happen before the worker is spawned

Constructor

new LibretroNativeCore(coresBasePath: string)
coresBasePath
string
required
Base path for storing libretro cores
Initializes the core instance and creates required directories:
  • userData/savestates — Save states
  • userData/saves — SRAM/battery saves
  • userData/BIOS — System BIOS files

Methods

launch

Validate and prepare ROM/core paths for emulation.
await launch(
  romPath: string,
  options: EmulatorLaunchOptions
): Promise<void>
romPath
string
required
Absolute path to the ROM file
options.corePath
string
required
Absolute path to the libretro core (.dylib, .dll, or .so)
Throws an error if the emulator is already running or if the core path is not provided.

Core path security

Cores must be loaded from one of these allowed directories:
  • App-managed: userData/cores
  • RetroArch (macOS): ~/Library/Application Support/RetroArch/cores
  • RetroArch (Windows): %APPDATA%/RetroArch/cores
  • RetroArch (Linux): ~/.config/retroarch/cores

Example

const core = new LibretroNativeCore(coresBasePath)

await core.launch('/path/to/game.sfc', {
  corePath: '/path/to/snes9x_libretro.dylib'
})

console.log('Core launched:', core.getCorePath())

Path getters

These methods expose validated paths for the worker process.

getCorePath

getCorePath(): string
Returns the validated core path. Throws if launch() has not been called.

getRomPath

getRomPath(): string
Returns the validated ROM path. Throws if launch() has not been called.

getSystemDir

getSystemDir(): string
Returns the BIOS directory path. Throws if launch() has not been called.

getSaveDir

getSaveDir(): string
Returns the directory for game saves.

getSramDir

getSramDir(): string
Returns the directory for SRAM/battery saves.

getSaveStatesDir

getSaveStatesDir(): string
Returns the directory for save states.

Autosave management

These methods check and manage autosave files before the worker starts.

hasAutoSave

hasAutoSave(): boolean
Returns true if an autosave exists for the currently loaded ROM.

hasAutoSaveForRom

hasAutoSaveForRom(romPath: string): boolean
romPath
string
required
Path to the ROM file to check
Returns true if an autosave exists for the specified ROM.

deleteAutoSave

deleteAutoSave(): void
Deletes the autosave for the currently loaded ROM.

deleteAutoSaveForRom

deleteAutoSaveForRom(romPath: string): void
romPath
string
required
Path to the ROM whose autosave should be deleted
Deletes the autosave for the specified ROM.

Example usage

// Check for autosave before launching
if (core.hasAutoSaveForRom(romPath)) {
  const resume = await showResumeDialog()
  if (!resume) {
    core.deleteAutoSaveForRom(romPath)
  }
}

await core.launch(romPath, { corePath })

Lifecycle methods

These methods emit events but defer actual emulation control to the worker.

pause

await pause(): Promise<void>
Emits a paused event. Actual pause control happens in the worker.

resume

await resume(): Promise<void>
Emits a resumed event. Actual resume control happens in the worker.

reset

await reset(): Promise<void>
Emits a reset event. Actual reset control happens in the worker.

terminate

await terminate(): Promise<void>
Cleans up local state and emits a terminated event.

isActive

isActive(): boolean
Returns true if the core is currently running.

Events

Inherits from EventEmitter and emits the following events:
  • launched{ romPath: string, corePath: string } — Fired after successful path validation
  • paused — Fired when pause is requested
  • resumed — Fired when resume is requested
  • reset — Fired when reset is requested
  • terminated — Fired when the core is terminated

Worker integration

This class is designed to work with EmulationWorkerClient, which handles the actual emulation loop:
const core = new LibretroNativeCore(coresBasePath)
const worker = new EmulationWorkerClient()

// Validate and prepare paths
await core.launch(romPath, { corePath })

// Initialize worker with validated paths
const avInfo = await worker.init({
  corePath: core.getCorePath(),
  romPath: core.getRomPath(),
  systemDir: core.getSystemDir(),
  saveDir: core.getSaveDir(),
  sramDir: core.getSramDir(),
  saveStatesDir: core.getSaveStatesDir(),
  addonPath: nativeAddonPath
})

console.log('Emulation ready:', avInfo)

Build docs developers (and LLMs) love