# RomM Browser-Based Emulation: Supported Platforms and Implementation Guide

> Discover RomM browser-based emulation for classic consoles and Flash content. Learn about EmulatorJS and RuffleRS, both running client-side without server binaries.

- Repository: [The RomM Project/romm](https://github.com/rommapp/romm)
- Tags: how-to-guide
- Published: 2026-07-07

---

**Yes, RomM includes built-in browser-based emulation using two client-side engines: EmulatorJS for classic consoles (NES, SNES, Genesis, etc.) and RuffleRS for Adobe Flash content, both running entirely in the browser without server-side binaries.**

RomM transforms your self-hosted game library into a playable archive by embedding **browser-based emulation** directly into its Vue.js frontend. According to the RomM source code, the platform ships with two self-contained emulation engines that stream ROM files directly to the client, eliminating the need for external plugins or server-side execution.

## How RomM Implements Browser-Based Emulation

The RomM frontend implements a dual-engine architecture located in `frontend/src/views/Player/`. Each engine handles distinct platform categories and exposes a consistent JavaScript API for programmatic control.

### EmulatorJS for Classic Consoles

**EmulatorJS** powers emulation for Nintendo Entertainment System, Super Nintendo, Sega Genesis, DOS, and other classic platforms. The core implementation resides in [`frontend/src/views/Player/EmulatorJS/Base.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/views/Player/EmulatorJS/Base.vue), a Vue component that injects the EJS script and instantiates a global `window.EJS_emulator` instance driving the HTML5 canvas.

The component loads the library from a CDN or bundled copy (controlled by `EMULATORJS_VERSION`) and manages the emulator lifecycle. For the v2 interface, this component is wrapped by [`frontend/src/v2/views/Player/EmulatorJS.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/v2/views/Player/EmulatorJS.vue).

### RuffleRS for Flash Content

**RuffleRS** handles Adobe Flash and SWF files through the WebAssembly-based Ruffle emulator. The wrapper at [`frontend/src/views/Player/RuffleRS/Base.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/views/Player/RuffleRS/Base.vue) loads [`ruffle/ruffle.js`](https://github.com/rommapp/romm/blob/main/ruffle/ruffle.js) from a CDN and creates a `window.RufflePlayer` singleton. The v2 shell reuses this component via [`frontend/src/v2/views/Player/Ruffle.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/v2/views/Player/Ruffle.vue).

## Integration Architecture and Routing

RomM exposes browser-based play through dedicated URL routes defined in [`frontend/src/v2/router/routes.ts`](https://github.com/rommapp/romm/blob/main/frontend/src/v2/router/routes.ts). When a user selects a ROM, the application navigates to platform-specific endpoints:

- `/rom/:id/emulatorjs` for EmulatorJS-supported platforms
- `/rom/:id/ruffle` for Flash content

The UI determines route availability using runtime helpers exported from [`frontend/src/utils/index.ts`](https://github.com/rommapp/romm/blob/main/frontend/src/utils/index.ts). The predicates `isEJSEmulationSupported` and `isRuffleEmulationSupported` evaluate the platform slug, server heartbeat, and configuration to decide whether to render the "Play in browser" button in [`frontend/src/components/common/Game/PlayBtn.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/components/common/Game/PlayBtn.vue).

## Programmatic Control and API Usage

Because both engines expose global window objects, you can control emulation programmatically from TypeScript or JavaScript.

### Checking Emulation Support

Before navigating to a player route, validate support using the utility functions:

```typescript
import { isEJSEmulationSupported, isRuffleEmulationSupported } from '@/utils'

// Check if ROM supports browser-based emulation
if (isEJSEmulationSupported(rom.platform_slug, heartbeat.value, config.value)) {
  router.push(`/rom/${rom.id}/emulatorjs`)
}

// Check for Flash content
if (isRuffleEmulationSupported(rom.platform_slug, heartbeat.value, config.value)) {
  router.push(`/rom/${rom.id}/ruffle`)
}

```

### Controlling the Emulator Instance

Once loaded, interact with the global emulator objects:

```typescript
// Pause EmulatorJS
window.EJS_emulator?.pause()

// Toggle fullscreen (respects user preference "emulation.fullScreenOnPlay")
window.EJS_emulator?.toggleFullscreen(true)

// Save state in Ruffle
window.RufflePlayer?.newest()?.saveState?.()

```

## Key Implementation Files

- [`frontend/src/views/Player/EmulatorJS/Base.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/views/Player/EmulatorJS/Base.vue) – Core EmulatorJS player component
- [`frontend/src/views/Player/RuffleRS/Base.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/views/Player/RuffleRS/Base.vue) – Ruffle Flash player wrapper
- [`frontend/src/v2/views/Player/EmulatorJS.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/v2/views/Player/EmulatorJS.vue) – v2 shell for EmulatorJS
- [`frontend/src/v2/views/Player/Ruffle.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/v2/views/Player/Ruffle.vue) – v2 shell for Ruffle
- [`frontend/src/v2/router/routes.ts`](https://github.com/rommapp/romm/blob/main/frontend/src/v2/router/routes.ts) – Route definitions for `/emulatorjs` and `/ruffle`
- [`frontend/src/utils/index.ts`](https://github.com/rommapp/romm/blob/main/frontend/src/utils/index.ts) – Runtime helpers `isEJSEmulationSupported` and `isRuffleEmulationSupported`
- [`frontend/src/components/common/Game/PlayBtn.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/components/common/Game/PlayBtn.vue) – UI button logic for play availability

## Summary

- **RomM supports browser-based emulation** through two embedded engines requiring no server-side binaries.
- **EmulatorJS** handles classic consoles via [`frontend/src/views/Player/EmulatorJS/Base.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/views/Player/EmulatorJS/Base.vue), exposing `window.EJS_emulator`.
- **RuffleRS** plays Flash content via [`frontend/src/views/Player/RuffleRS/Base.vue`](https://github.com/rommapp/romm/blob/main/frontend/src/views/Player/RuffleRS/Base.vue), exposing `window.RufflePlayer`.
- Runtime checks in [`frontend/src/utils/index.ts`](https://github.com/rommapp/romm/blob/main/frontend/src/utils/index.ts) determine UI visibility for the "Play in browser" feature.
- ROMs stream directly to the client, with routes at `/rom/:id/emulatorjs` and `/rom/:id/ruffle`.

## Frequently Asked Questions

### Does RomM require server-side emulators for browser-based play?

No. RomM's browser-based emulation runs entirely client-side. The EmulatorJS and RuffleRS engines execute in the user's browser using WebAssembly and JavaScript, streamed directly from your RomM instance without requiring server-side binary execution or additional emulation software on the host.

### Which platforms support browser-based emulation in RomM?

EmulatorJS supports NES, SNES, Genesis, DOS, and other classic platforms through the open-source EmulatorJS library. RuffleRS supports Adobe Flash and SWF files. The exact availability depends on the ROM's platform slug and your RomM configuration, checked via `isEJSEmulationSupported` and `isRuffleEmulationSupported` in [`frontend/src/utils/index.ts`](https://github.com/rommapp/romm/blob/main/frontend/src/utils/index.ts).

### How do I check if a specific ROM supports browser play?

Use the utility functions exported from [`frontend/src/utils/index.ts`](https://github.com/rommapp/romm/blob/main/frontend/src/utils/index.ts). Pass the ROM's platform slug, the server heartbeat, and configuration object to `isEJSEmulationSupported()` or `isRuffleEmulationSupported()`. These return booleans indicating whether the UI should display the play button and enable navigation to the emulator routes.

### Can I customize the emulator settings or behavior?

Yes. The EmulatorJS component respects configuration values such as `EMULATORJS_VERSION` for script loading and user preferences like `emulation.fullScreenOnPlay`. You can programmatically control the emulator through the global `window.EJS_emulator` API for pausing, fullscreen toggling, and save states, or use `window.RufflePlayer` for Flash-specific operations.