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 🙏

© 2025 – Pkg Stats / Ryan Hefner

rom-scout

v0.1.27

Published

A toolkit for identifying ROM files, fetching Hasheous metadata, and launching games with EmulatorJS

Readme

rom-scout

rom-scout is an end-to-end toolkit for working with classic game ROMs. It identifies files via hashing, fetches metadata from a Hasheous server, and can boot games directly in the browser through the built-in EmulatorJS-powered player.

Highlights

  • File identification – calculate MD5/SHA-1/CRC32 hashes for ROMs and zip archives.
  • Metadata lookup – query Hasheous for titles, platforms, artwork, and more.
  • Emulator playback – launch ROMs with the bundled RomPlayer class to embed EmulatorJS in a web page.
  • Universal delivery – ship as ESM, CommonJS, and browser bundles with full TypeScript definitions.

TypeScript Support

rom-scout includes full TypeScript definitions. All public types are exported so you can import them directly from the package:

import {
  RomScout,
  RomMetadata,
  ImageMetadata,
  RomScoutConfig
} from 'rom-scout';

When working with image metadata you can take advantage of the richer structure exposed by the images array. For example, to grab a game's box art you can filter by the type property:

const metadata = await scout.identify(file);

const boxArt = metadata?.images?.find((image) => image.type === 'boxart');
const firstImage = metadata?.images?.[0];

The array shape allows you to store multiple images (box art, screenshots, title screens, etc.) alongside any metadata that accompanies each image.

Installation

npm install rom-scout

Quick start

Identify a ROM (Node.js or browser bundler)

import { RomScout } from 'rom-scout';

const scout = new RomScout({
  provider: 'hasheous',
  hasheousUrl: 'https://your-hasheous-instance.com',
});

const metadata = await scout.identify(fileOrBuffer, 'optional-filename.zip');

console.log(metadata?.title);
console.log(metadata?.images?.map((image) => `${image.type}: ${image.url}`));

Launch a ROM in the browser

import { RomPlayer } from 'rom-scout';

const player = await RomPlayer.start({
  romUrl: '/roms/super-mario-world.smc',
  metadata,
  mountNode: document.getElementById('player'),
});

// Persist manual saves in IndexedDB
await player.persistSave();

// Tear down when leaving the page
await player.destroy();

For zero-build sites you can load the browser bundle instead:

<script type="module">
  import { RomScout, RomPlayer } from 'https://unpkg.com/rom-scout/dist/bundles/rom-scout.esm.js';

  const scout = new RomScout({ hasheousUrl: 'https://your-hasheous-instance.com' });
  const metadata = await scout.identify(file);

  await RomPlayer.start({
    romData: file,
    metadata,
    mountNode: document.querySelector('#player'),
  });
</script>

Browser Build Warnings

rom-scout now detects the active runtime at execution time. When the Web Crypto API is available (including modern browsers and recent versions of Node.js) it is used automatically, preventing Node-specific modules from being bundled into browser builds. If your tooling still surfaces a warning such as:

Module "crypto" has been externalized for browser compatibility

the message can usually be ignored. Alternatively, configure your bundler to externalize Node built-ins or provide a lightweight polyfill so that any remaining dynamic imports resolve cleanly in browser-only builds.

API Providers

Hasheous

Hasheous is an open-source ROM metadata server.

const scout = new RomScout({
  provider: 'hasheous',
  hasheousUrl: 'https://your-hasheous-instance.com',
  timeout: 30000 // optional, in milliseconds
});

API Reference

RomScout Class

constructor(config?: RomScoutConfig)

Create a new RomScout instance.

interface RomScoutConfig {
  provider?: 'hasheous';
  hasheousUrl?: string;
  corsProxy?: string;
  timeout?: number;
}

identify(data, filename?)

Identify a ROM file and fetch metadata.

async identify(
  data: File | Blob | ArrayBuffer | Uint8Array | Buffer,
  filename?: string
): Promise<RomMetadata | null>

Parameters:

  • data: ROM file data
  • filename: Optional filename (extracted from File object if not provided)

Returns: ROM metadata or null if not found

hash(data)

Calculate hashes for ROM data without fetching metadata.

async hash(
  data: File | Blob | ArrayBuffer | Uint8Array | Buffer
): Promise<{ md5: string; sha1: string; crc32: string }>

lookup(request)

Look up ROM metadata using hash information.

async lookup(request: HashLookupRequest): Promise<RomMetadata | null>

interface HashLookupRequest {
  md5?: string;
  sha1?: string;
  crc32?: string;
  size?: number;
  filename?: string;
}

lookupMultiple(request, providers?)

Try multiple providers in sequence until metadata is found.

async lookupMultiple(
  request: HashLookupRequest,
  providers?: Array<'hasheous'>
): Promise<RomMetadata | null>

RomPlayer class

RomPlayer wraps EmulatorJS with lifecycle helpers and IndexedDB persistence.

  • static async start(options: RomPlayerOptions): Promise<RomPlayerInstance> – boot a ROM from a URL or binary blob and mount the emulator into a DOM node.
  • persistSave(options?) – snapshot manual or auto saves into IndexedDB so they can be restored on the next launch.
  • destroy() – tear down the EmulatorJS instance, remove listeners, and release persistent saves.

The RomPlayerInstance returned from start also surfaces helpers such as restart, clearPersistedSave, and exportSave for advanced workflows.

Standalone Functions

calculateHash(data, types?)

Calculate hash(es) for data.

async function calculateHash(
  data: Uint8Array | ArrayBuffer | Buffer,
  types?: ('md5' | 'sha1' | 'crc32')[]
): Promise<HashResult>

interface HashResult {
  md5?: string;
  sha1?: string;
  crc32?: string;
}

calculateSingleHash(data, type)

Calculate a single hash type.

async function calculateSingleHash(
  data: Uint8Array | ArrayBuffer | Buffer,
  type: 'md5' | 'sha1' | 'crc32'
): Promise<string>

Types

RomMetadata

interface RomMetadata {
  id: string;
  persistId?: string;
  alternateIds?: string[];
  title: string;
  platform?: string;
  publisher?: string;
  images?: ImageMetadata[];
  source: string;
  raw?: unknown;
}

ImageMetadata

interface ImageMetadata {
  url: string;
  type: string;
  resolution?: string;
  thumbnail?: string;
}

Examples

Hash Only (No API Call)

import { RomScout } from 'rom-scout';

const scout = new RomScout();
const romData = await fetch('rom.zip').then(r => r.arrayBuffer());

const hashes = await scout.hash(romData);
console.log('MD5:', hashes.md5);
console.log('SHA-1:', hashes.sha1);
console.log('CRC32:', hashes.crc32);

Browser File Upload Example

<!DOCTYPE html>
<html>
<head>
  <title>ROM Scout Demo</title>
</head>
<body>
  <input type="file" id="rom-file" accept=".zip,.rom,.nes,.snes,.gb,.gba">
  <div id="result"></div>

  <script type="module">
    import { RomScout } from 'https://unpkg.com/rom-scout/dist/bundles/rom-scout.esm.js';

    const scout = new RomScout({
      hasheousUrl: 'https://your-hasheous-instance.com'
    });

    document.getElementById('rom-file').addEventListener('change', async (e) => {
      const file = e.target.files[0];
      if (!file) return;

      const result = document.getElementById('result');
      result.innerHTML = 'Processing...';

      try {
        const metadata = await scout.identify(file);

        if (metadata) {
          result.innerHTML = `
            <h2>${metadata.title}</h2>
            <p><strong>Platform:</strong> ${metadata.platform || 'Unknown'}</p>
            <p><strong>Publisher:</strong> ${metadata.publisher || 'Unknown'}</p>
            ${metadata.images && metadata.images.length > 0 ? `
              <img src="${metadata.images[0].url}" alt="Cover" style="max-width: 300px">
            ` : ''}
          `;
        } else {
          result.innerHTML = 'ROM not found in database';
        }
      } catch (error) {
        result.innerHTML = `Error: ${error.message}`;
      }
    });
  </script>
</body>
</html>

Supported Hash Algorithms

  • MD5: 128-bit hash, commonly used for ROM identification
  • SHA-1: 160-bit hash, more secure than MD5
  • CRC32: 32-bit checksum, fast and widely used

All hash calculations work in both browser (using Web Crypto API and pure JS) and Node.js (using crypto module).

Browser Compatibility

  • Chrome/Edge 37+
  • Firefox 34+
  • Safari 11+
  • Any browser with Web Crypto API support

Node.js Compatibility

  • Node.js 20.0.0 or higher

Development

# Install dependencies
npm install

# Build the library
npm run build

# Run tests
npm test

# Run all tests (including browser)
npm run test:all

# Check bundle sizes
npm run size

# Generate coverage report
npm run coverage

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

  • Hasheous - Open-source ROM metadata server
  • crc-32 - CRC32 implementation

Related Projects