@tmustier/pi-nes 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/AGENTS.md +89 -1
  2. package/README.md +77 -48
  3. package/extensions/nes/config.ts +32 -12
  4. package/extensions/nes/native/nes-core/Cargo.lock +0 -2
  5. package/extensions/nes/native/nes-core/Cargo.toml +1 -1
  6. package/extensions/nes/native/nes-core/index.d.ts +5 -0
  7. package/extensions/nes/native/nes-core/index.node +0 -0
  8. package/extensions/nes/native/nes-core/native.d.ts +5 -0
  9. package/extensions/nes/native/nes-core/src/lib.rs +25 -0
  10. package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo-ok +1 -0
  11. package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo_vcs_info.json +5 -0
  12. package/extensions/nes/native/nes-core/vendor/nes_rust/.travis.yml +3 -0
  13. package/extensions/nes/native/nes-core/vendor/nes_rust/Cargo.toml +23 -0
  14. package/extensions/nes/native/nes-core/vendor/nes_rust/LICENSE +21 -0
  15. package/extensions/nes/native/nes-core/vendor/nes_rust/README.md +59 -0
  16. package/extensions/nes/native/nes-core/vendor/nes_rust/src/apu.rs +1114 -0
  17. package/extensions/nes/native/nes-core/vendor/nes_rust/src/audio.rs +6 -0
  18. package/extensions/nes/native/nes-core/vendor/nes_rust/src/button.rs +23 -0
  19. package/extensions/nes/native/nes-core/vendor/nes_rust/src/cpu.rs +2364 -0
  20. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_audio.rs +49 -0
  21. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_display.rs +47 -0
  22. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_input.rs +33 -0
  23. package/extensions/nes/native/nes-core/vendor/nes_rust/src/display.rs +10 -0
  24. package/extensions/nes/native/nes-core/vendor/nes_rust/src/input.rs +7 -0
  25. package/extensions/nes/native/nes-core/vendor/nes_rust/src/joypad.rs +86 -0
  26. package/extensions/nes/native/nes-core/vendor/nes_rust/src/lib.rs +168 -0
  27. package/extensions/nes/native/nes-core/vendor/nes_rust/src/mapper.rs +502 -0
  28. package/extensions/nes/native/nes-core/vendor/nes_rust/src/memory.rs +73 -0
  29. package/extensions/nes/native/nes-core/vendor/nes_rust/src/ppu.rs +1378 -0
  30. package/extensions/nes/native/nes-core/vendor/nes_rust/src/register.rs +560 -0
  31. package/extensions/nes/native/nes-core/vendor/nes_rust/src/rom.rs +231 -0
  32. package/extensions/nes/nes-core.ts +27 -4
  33. package/package.json +1 -1
  34. package/spec.md +2 -4
package/AGENTS.md CHANGED
@@ -1,6 +1,94 @@
1
1
  # AGENTS.md
2
2
 
3
- Project guidance for release and publishing.
3
+ Technical guidance for AI agents working on this codebase.
4
+
5
+ ## Architecture
6
+
7
+ pi-nes is a NES emulator extension for [pi](https://github.com/mariozechner/pi). It uses a Rust-based emulator core compiled as a Node.js native addon.
8
+
9
+ ### Project Structure
10
+
11
+ ```
12
+ pi-nes/
13
+ ├── package.json # Pi package manifest (pi.extensions points to ./extensions/nes)
14
+ └── extensions/nes/
15
+ ├── index.ts # Extension entry - registers /nes and /nes-config commands
16
+ ├── nes-core.ts # TypeScript wrapper for native addon
17
+ ├── nes-session.ts # Game session management (frame timing, SRAM saves)
18
+ ├── nes-component.ts # TUI overlay component (input handling, render loop)
19
+ ├── renderer.ts # Frame rendering (Kitty image protocol, PNG, ANSI)
20
+ ├── config.ts # User config (~/.pi/nes/config.json)
21
+ ├── paths.ts # Path resolution utilities
22
+ ├── roms.ts # ROM directory listing
23
+ ├── saves.ts # SRAM persistence
24
+ └── native/
25
+ ├── nes-core/ # Rust NES emulator addon (required)
26
+ │ ├── Cargo.toml # Dependencies: nes_rust, napi
27
+ │ ├── src/lib.rs # Exposes NativeNes class via napi-rs
28
+ │ └── index.node # Compiled binary
29
+ └── kitty-shm/ # Rust shared memory addon (optional)
30
+ ├── src/lib.rs # POSIX shm_open/mmap for zero-copy frames
31
+ └── index.node # Compiled binary
32
+ ```
33
+
34
+ ### Native Core
35
+
36
+ The emulator uses the [`nes_rust`](https://crates.io/crates/nes_rust) crate with [napi-rs](https://napi.rs) bindings.
37
+
38
+ **API exposed to JavaScript:**
39
+ - `new NativeNes()` - Create emulator instance
40
+ - `setRom(Uint8Array)` - Load ROM data
41
+ - `bootup()` / `reset()` - Start/restart emulation
42
+ - `stepFrame()` - Advance one frame (~60fps)
43
+ - `pressButton(n)` / `releaseButton(n)` - Controller input (0=select, 1=start, 2=A, 3=B, 4-7=dpad)
44
+ - `getFramebuffer()` - Returns RGB pixel data (256×240×3 bytes, zero-copy via external buffer)
45
+
46
+ ### Rendering Pipeline
47
+
48
+ ```
49
+ NES Core → RGB framebuffer (256×240×3) → Renderer → Terminal
50
+
51
+ ├─ Kitty shared memory (t=s) — fastest, requires kitty-shm addon
52
+ ├─ Kitty file transport (t=f) — writes to /dev/shm or temp file
53
+ ├─ Kitty PNG — base64-encoded PNG fallback
54
+ └─ ANSI half-blocks — ▀▄ characters, works everywhere
55
+ ```
56
+
57
+ - Image mode (`renderer: "image"`) runs at ~30fps to keep emulation stable
58
+ - Text mode (`renderer: "text"`) runs at ~60fps in an overlay
59
+ - Image mode uses near-fullscreen (90% height) because Kitty graphics can't composite in overlays
60
+
61
+ ### Session Lifecycle
62
+
63
+ 1. `/nes` creates a `NesSession` that owns the core and runs the frame loop
64
+ 2. `NesOverlayComponent` attaches to display frames and handle input
65
+ 3. `Ctrl+Q` detaches the component but keeps the session running in background
66
+ 4. `/nes` reattaches to existing session; `/nes <path>` starts a new one
67
+ 5. `Q` or `session_shutdown` event stops the session and disposes the core
68
+
69
+ ## Building Native Addons
70
+
71
+ Requires Rust toolchain (cargo + rustc).
72
+
73
+ ```bash
74
+ # NES core (required)
75
+ cd extensions/nes/native/nes-core
76
+ npm install && npm run build
77
+
78
+ # Kitty shared memory (optional, faster rendering)
79
+ cd extensions/nes/native/kitty-shm
80
+ npm install && npm run build
81
+ ```
82
+
83
+ The addons compile to `index.node`. The JS wrapper (`index.js`) tries to load it and exports `isAvailable: boolean`.
84
+
85
+ ## Known Limitations
86
+
87
+ - **No audio** — `enableAudio` config exists but no audio backend is implemented
88
+ - **No save states** — Only battery-backed SRAM saves are persisted
89
+ - **SRAM for native core** — Tracked in issue #3
90
+
91
+ ## Release and Publishing
4
92
 
5
93
  ## Version Bumps (Git + npm)
6
94
 
package/README.md CHANGED
@@ -1,72 +1,65 @@
1
1
  # pi-nes
2
2
 
3
- NES emulator extension for pi (targeting Kitty).
3
+ Play NES games in your terminal. A [pi](https://github.com/mariozechner/pi) extension that runs a full NES emulator with Kitty graphics support.
4
4
 
5
- ## Setup
5
+ ## Installation
6
6
 
7
7
  ```bash
8
- cd /Users/thomasmustier/projects/pi-nes
9
- npm install
8
+ pi install npm:@tmustier/pi-nes
10
9
  ```
11
10
 
12
- ### Build native addons (required core + optional Kitty shared memory)
11
+ Or from git:
12
+ ```bash
13
+ pi install git:github.com/tmustier/pi-nes
14
+ ```
13
15
 
14
- Requires a Rust toolchain (cargo + rustc).
16
+ ## Quick Start
15
17
 
16
18
  ```bash
17
- # Native NES core (required)
18
- cd /Users/thomasmustier/projects/pi-nes/extensions/nes/native/nes-core
19
- npm install
20
- npm run build
21
-
22
- # Kitty shared-memory renderer (optional, faster)
23
- cd /Users/thomasmustier/projects/pi-nes/extensions/nes/native/kitty-shm
24
- npm install
25
- npm run build
19
+ /nes # Pick a ROM from your library
20
+ /nes ~/roms/smb.nes # Load a specific ROM
26
21
  ```
27
22
 
28
- If the native core addon isn’t built, `/nes` will show an error and exit. The shared-memory renderer is optional; we fall back to the Kitty file transport if it’s missing.
23
+ On first run, you'll be prompted to set your ROM directory and display quality.
29
24
 
30
- ## Install as a pi package
25
+ ## Controls
31
26
 
32
- ```bash
33
- # From npm
34
- pi install npm:@tmustier/pi-nes
27
+ ### Game Controls
35
28
 
36
- # From git
37
- pi install git:github.com/tmustier/pi-nes
38
- ```
29
+ | Action | Keys |
30
+ |--------|------|
31
+ | D-pad | Arrow keys or WASD |
32
+ | A button | Z |
33
+ | B button | X |
34
+ | Start | Enter or Space |
35
+ | Select | Tab |
39
36
 
40
- ## Usage
37
+ ### Emulator Controls
41
38
 
42
- ```bash
43
- # Local path
44
- pi --extension /Users/thomasmustier/projects/pi-nes
45
- ```
39
+ | Action | Key |
40
+ |--------|-----|
41
+ | Detach (keep running) | Ctrl+Q |
42
+ | Quit | Q |
46
43
 
47
- Commands:
48
- - `/nes` — pick a ROM from the configured directory or reattach to a running session
49
- - `/nes <path>` — load a specific ROM
50
- - `/nes debug [<path>]` — enable debug overlay (FPS/memory stats)
51
- - `/nes config` — guided configuration (ROM directory + quality)
52
- - `/nes-config` — edit configuration (alias)
44
+ **Tip:** Detach with `Ctrl+Q` to return to pi, then run `/nes` to reattach to your game.
53
45
 
54
- Controls:
55
- - `Ctrl+Q` — detach overlay (keeps the session running)
56
- - `Q` — quit emulator
46
+ ## Commands
57
47
 
58
- Note: if a session is running, `/nes` reattaches. Use `/nes <path>` to start a new ROM.
48
+ | Command | Description |
49
+ |---------|-------------|
50
+ | `/nes` | Pick a ROM or reattach to running session |
51
+ | `/nes <path>` | Load a specific ROM file |
52
+ | `/nes config` | Configure ROM directory and quality |
53
+ | `/nes debug` | Show FPS and memory stats |
59
54
 
60
55
  ## Configuration
61
56
 
62
- Config file: `~/.pi/nes/config.json` (use `/nes config` for guided setup or `/nes-config` to edit JSON directly). On first run, `/nes` will prompt you to configure ROM directory + quality.
57
+ Config is stored at `~/.pi/nes/config.json`. Use `/nes config` for guided setup.
63
58
 
64
- Example:
65
59
  ```json
66
60
  {
67
61
  "romDir": "/roms/nes",
68
- "saveDir": "/Users/you/.pi/nes/saves",
69
- "enableAudio": false,
62
+ "saveDir": "/roms/nes/saves",
70
63
  "renderer": "image",
71
64
  "pixelScale": 1.2,
72
65
  "keybindings": {
@@ -82,14 +75,50 @@ Example:
82
75
  }
83
76
  ```
84
77
 
85
- ## Core
78
+ ### Options
86
79
 
87
- The extension uses the **native Rust core** only (required build step). Battery-backed SRAM persistence for native is tracked in issue #3.
80
+ | Option | Default | Description |
81
+ |--------|---------|-------------|
82
+ | `romDir` | `/roms/nes` | Where to look for ROM files |
83
+ | `saveDir` | `/roms/nes/saves` | Where to store battery saves (defaults to `<romDir>/saves`) |
84
+ | `renderer` | `"image"` | `"image"` (Kitty graphics) or `"text"` (ANSI) |
85
+ | `pixelScale` | `1.2` | Display scale (0.5–4.0) |
88
86
 
89
- ## Rendering
87
+ ## Terminal Support
90
88
 
91
- Default renderer is `image`, which uses Kitty's image protocol for high resolution. On Kitty, we **prefer shared-memory transport (`t=s`)** when the native addon is built, falling back to the **file transport (`t=f`)** path if the addon isn’t available; non-Kitty terminals fall back to PNG. Image mode runs **nearly full-screen** (no overlay) because Kitty graphics sequences can't be safely composited inside overlays; it caps to ~90% height and centers vertically + horizontally to reduce terminal compositor load. Image mode also **throttles rendering to ~30fps** to keep emulation speed stable. Set `renderer: "text"` if you prefer ANSI half-block rendering in an overlay. You can tweak `pixelScale` to 1.5–2.0 for larger images in PNG mode.
89
+ **Best experience:** [Kitty](https://sw.kovidgoyal.net/kitty/) terminal with image protocol support.
92
90
 
93
- ## Audio
91
+ - **Kitty** — Full graphics via image protocol (shared memory or file transport)
92
+ - **Other terminals** — Falls back to ANSI half-block characters (`▀▄`)
94
93
 
95
- Audio output is currently disabled (no safe dependency selected). If you set `enableAudio: true`, the extension will warn and continue in silent mode.
94
+ Set `"renderer": "text"` if you prefer the ANSI renderer or have display issues.
95
+
96
+ ## Limitations
97
+
98
+ - **No audio** — Sound is not currently supported
99
+ - **No save states** — Only battery-backed SRAM saves work
100
+
101
+ ---
102
+
103
+ ## Building from Source
104
+
105
+ Requires Rust toolchain (cargo + rustc).
106
+
107
+ ```bash
108
+ git clone https://github.com/tmustier/pi-nes
109
+ cd pi-nes
110
+ npm install
111
+
112
+ # Build the NES core (required)
113
+ cd extensions/nes/native/nes-core
114
+ npm install && npm run build
115
+
116
+ # Build shared memory renderer (optional, faster on Kitty)
117
+ cd ../kitty-shm
118
+ npm install && npm run build
119
+ ```
120
+
121
+ Run locally:
122
+ ```bash
123
+ pi --extension /path/to/pi-nes
124
+ ```
@@ -15,9 +15,15 @@ export interface NesConfig {
15
15
  keybindings: InputMapping;
16
16
  }
17
17
 
18
+ const DEFAULT_ROM_DIR = path.join(path.sep, "roms", "nes");
19
+
20
+ function defaultSaveDir(romDir: string): string {
21
+ return path.join(romDir, "saves");
22
+ }
23
+
18
24
  export const DEFAULT_CONFIG: NesConfig = {
19
- romDir: path.join(path.sep, "roms", "nes"),
20
- saveDir: path.join(os.homedir(), ".pi", "nes", "saves"),
25
+ romDir: DEFAULT_ROM_DIR,
26
+ saveDir: defaultSaveDir(DEFAULT_ROM_DIR),
21
27
  enableAudio: false,
22
28
  renderer: "image",
23
29
  pixelScale: 1.2,
@@ -39,15 +45,18 @@ export function getConfigPath(): string {
39
45
 
40
46
  export function normalizeConfig(raw: unknown): NesConfig {
41
47
  const parsed = typeof raw === "object" && raw !== null ? (raw as RawConfig) : {};
48
+ const romDir =
49
+ typeof parsed.romDir === "string" && parsed.romDir.length > 0
50
+ ? normalizePath(parsed.romDir, DEFAULT_CONFIG.romDir)
51
+ : DEFAULT_CONFIG.romDir;
52
+ const saveDirFallback = defaultSaveDir(romDir);
53
+ const saveDir =
54
+ typeof parsed.saveDir === "string" && parsed.saveDir.length > 0
55
+ ? normalizePath(parsed.saveDir, saveDirFallback)
56
+ : saveDirFallback;
42
57
  return {
43
- romDir:
44
- typeof parsed.romDir === "string" && parsed.romDir.length > 0
45
- ? normalizePath(parsed.romDir, DEFAULT_CONFIG.romDir)
46
- : DEFAULT_CONFIG.romDir,
47
- saveDir:
48
- typeof parsed.saveDir === "string" && parsed.saveDir.length > 0
49
- ? normalizePath(parsed.saveDir, DEFAULT_CONFIG.saveDir)
50
- : DEFAULT_CONFIG.saveDir,
58
+ romDir,
59
+ saveDir,
51
60
  enableAudio: typeof parsed.enableAudio === "boolean" ? parsed.enableAudio : DEFAULT_CONFIG.enableAudio,
52
61
  renderer: parsed.renderer === "text" ? "text" : DEFAULT_CONFIG.renderer,
53
62
  pixelScale: normalizePixelScale(parsed.pixelScale),
@@ -61,12 +70,15 @@ export function formatConfig(config: NesConfig): string {
61
70
 
62
71
  export async function loadConfig(): Promise<NesConfig> {
63
72
  const configPath = getConfigPath();
73
+ let config: NesConfig;
64
74
  try {
65
75
  const raw = await fs.readFile(configPath, "utf8");
66
- return normalizeConfig(JSON.parse(raw));
76
+ config = normalizeConfig(JSON.parse(raw));
67
77
  } catch {
68
- return DEFAULT_CONFIG;
78
+ config = DEFAULT_CONFIG;
69
79
  }
80
+ await ensureDirectory(config.saveDir);
81
+ return config;
70
82
  }
71
83
 
72
84
  export async function configExists(): Promise<boolean> {
@@ -84,6 +96,14 @@ export async function saveConfig(config: NesConfig): Promise<void> {
84
96
  await fs.writeFile(configPath, formatConfig(config));
85
97
  }
86
98
 
99
+ async function ensureDirectory(dirPath: string): Promise<void> {
100
+ try {
101
+ await fs.mkdir(dirPath, { recursive: true });
102
+ } catch {
103
+ // ignore
104
+ }
105
+ }
106
+
87
107
  function normalizePixelScale(raw: unknown): number {
88
108
  if (typeof raw !== "number" || Number.isNaN(raw)) {
89
109
  return DEFAULT_CONFIG.pixelScale;
@@ -124,8 +124,6 @@ dependencies = [
124
124
  [[package]]
125
125
  name = "nes_rust"
126
126
  version = "0.1.2"
127
- source = "registry+https://github.com/rust-lang/crates.io-index"
128
- checksum = "0ee42b041b46e53bf4e4705ca0ffe66cbc7789929c3d013fa0700d7d61cf45c6"
129
127
 
130
128
  [[package]]
131
129
  name = "once_cell"
@@ -9,7 +9,7 @@ crate-type = ["cdylib"]
9
9
 
10
10
  [dependencies]
11
11
  libc = "0.2"
12
- nes_rust = "0.1.2"
12
+ nes_rust = { path = "vendor/nes_rust" }
13
13
  napi = { version = "2", features = ["napi8"] }
14
14
  napi-derive = "2"
15
15
 
@@ -9,6 +9,11 @@ export class NativeNes {
9
9
  reset(): void;
10
10
  pressButton(button: number): void;
11
11
  releaseButton(button: number): void;
12
+ hasBatteryBackedRam(): boolean;
13
+ getSram(): Uint8Array;
14
+ setSram(data: Uint8Array): void;
15
+ isSramDirty(): boolean;
16
+ markSramSaved(): void;
12
17
  getFramebuffer(): Uint8Array;
13
18
  }
14
19
 
@@ -13,5 +13,10 @@ export declare class NativeNes {
13
13
  reset(): void
14
14
  pressButton(button: number): void
15
15
  releaseButton(button: number): void
16
+ hasBatteryBackedRam(): boolean
17
+ getSram(): Uint8Array
18
+ setSram(data: Uint8Array): void
19
+ isSramDirty(): boolean
20
+ markSramSaved(): void
16
21
  getFramebuffer(): Uint8Array
17
22
  }
@@ -108,6 +108,31 @@ impl NativeNes {
108
108
  }
109
109
  }
110
110
 
111
+ #[napi]
112
+ pub fn has_battery_backed_ram(&self) -> bool {
113
+ self.nes.has_battery_backed_ram()
114
+ }
115
+
116
+ #[napi]
117
+ pub fn get_sram(&self) -> Uint8Array {
118
+ Uint8Array::from(self.nes.get_sram())
119
+ }
120
+
121
+ #[napi]
122
+ pub fn set_sram(&mut self, data: Uint8Array) {
123
+ self.nes.set_sram(data.to_vec());
124
+ }
125
+
126
+ #[napi]
127
+ pub fn is_sram_dirty(&self) -> bool {
128
+ self.nes.is_sram_dirty()
129
+ }
130
+
131
+ #[napi]
132
+ pub fn mark_sram_saved(&mut self) {
133
+ self.nes.mark_sram_saved();
134
+ }
135
+
111
136
  #[napi]
112
137
  pub fn get_framebuffer(&mut self) -> Uint8Array {
113
138
  let ptr = self.framebuffer.as_mut_ptr();
@@ -0,0 +1,5 @@
1
+ {
2
+ "git": {
3
+ "sha1": "3bedf08313ada63f709e909232b87b408fb40696"
4
+ }
5
+ }
@@ -0,0 +1,3 @@
1
+ language: rust
2
+ rust:
3
+ - stable
@@ -0,0 +1,23 @@
1
+ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
2
+ #
3
+ # When uploading crates to the registry Cargo will automatically
4
+ # "normalize" Cargo.toml files for maximal compatibility
5
+ # with all versions of Cargo and also rewrite `path` dependencies
6
+ # to registry (e.g., crates.io) dependencies
7
+ #
8
+ # If you believe there's an error in this file please file an
9
+ # issue against the rust-lang/cargo repository. If you're
10
+ # editing this file be aware that the upstream Cargo.toml
11
+ # will likely look very different (and much more reasonable)
12
+
13
+ [package]
14
+ name = "nes_rust"
15
+ version = "0.1.2"
16
+ authors = ["Takahiro <hogehoge@gachapin.jp>"]
17
+ exclude = ["resources/*", "screenshots/*", "roms/*", "cli/*", "wasm/*"]
18
+ description = "NES emulator written in Rust"
19
+ homepage = "https://github.com/takahirox/nes-rust"
20
+ license = "MIT"
21
+ repository = "https://github.com/takahirox/nes-rust"
22
+ [badges.travis-ci]
23
+ repository = "takahirox/nes-rust"
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Takahiro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,59 @@
1
+ # nes-rust
2
+
3
+ [![Build Status](https://travis-ci.com/takahirox/nes-rust.svg?branch=master)](https://travis-ci.com/takahirox/nes-rust)
4
+ [![Crate](https://img.shields.io/crates/v/nes_rust.svg)](https://crates.io/crates/nes_rust)
5
+ [![npm version](https://badge.fury.io/js/nes_rust_wasm.svg)](https://badge.fury.io/js/nes_rust_wasm)
6
+
7
+ nes-rust is a NES emulator written in Rust. It can be compiled to WebAssembly.
8
+
9
+ ## Online Demos / Videos
10
+
11
+ - [Online Singleplay Demo](https://takahirox.github.io/nes-rust/wasm/web/index.html)
12
+ - [Online Multiplay Demo](https://takahirox.github.io/nes-rust/wasm/web/multiplay.html) / [Video](https://twitter.com/superhoge/status/1205427421010247680)
13
+ - [Online VR Multiplay Demo](https://takahirox.github.io/nes-rust/wasm/web/vr.html) / [Video](https://twitter.com/superhoge/status/1209685614074875906)
14
+
15
+ ## Screenshots
16
+
17
+ [nestest](http://wiki.nesdev.com/w/index.php/Emulator_tests)
18
+
19
+ ![nestest](./screenshots/nestest.png)
20
+
21
+ [Sgt. Helmet Training Day](http://www.mojontwins.com/juegos_mojonos/sgt-helmet-training-day-nes/)
22
+
23
+ ![Sgt. Helmet Training Day](./screenshots/Sgt_Helmet.png)
24
+
25
+ ## Features
26
+
27
+ - Audio support with SDL2 / WebAudio
28
+ - WebAssembly support
29
+ - Remote multiplay support with WebRTC
30
+
31
+ ## How to import into your Rust project
32
+
33
+ The emulator module and document are released at [crates.io](https://crates.io/crates/nes_rust).
34
+
35
+ ## How to build core library locally
36
+
37
+ ```
38
+ $ git clone https://github.com/takahirox/nes-rust.git
39
+ $ cd nes-rust
40
+ $ cargo build --release
41
+ ```
42
+
43
+ ## How to run as desktop application
44
+
45
+ Prerequirements
46
+ - Install [Rust-SDL2](https://github.com/Rust-SDL2/rust-sdl2#rust)
47
+
48
+ ```
49
+ $ cd nes-rust/cli
50
+ $ cargo run --release path_to_rom_file
51
+ ```
52
+
53
+ ## How to import and use WebAssembly NES emulator in a web browser
54
+
55
+ See [wasm/web](https://github.com/takahirox/nes-rust/tree/master/wasm/web)
56
+
57
+ ## How to install and use WebAssembly NES emulator npm package
58
+
59
+ See [wasm/npm](https://github.com/takahirox/nes-rust/tree/master/wasm/npm)