@tmustier/pi-nes 0.2.10 → 0.2.11

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.
package/README.md CHANGED
@@ -54,14 +54,15 @@ On first run, you'll be prompted to set your ROM directory and display quality.
54
54
 
55
55
  ## Configuration
56
56
 
57
- Config is stored at `~/.pi/nes/config.json`. Use `/nes config` for guided setup.
57
+ Config is stored at `~/.pi/nes/config.json`. Use `/nes config` for quick setup.
58
58
 
59
59
  ```json
60
60
  {
61
61
  "romDir": "/roms/nes",
62
62
  "saveDir": "/roms/nes/saves",
63
63
  "renderer": "image",
64
- "pixelScale": 1.2,
64
+ "imageQuality": "balanced",
65
+ "pixelScale": 1.0,
65
66
  "keybindings": {
66
67
  "up": ["up", "w"],
67
68
  "down": ["down", "s"],
@@ -82,7 +83,8 @@ Config is stored at `~/.pi/nes/config.json`. Use `/nes config` for guided setup.
82
83
  | `romDir` | `/roms/nes` | Where to look for ROM files |
83
84
  | `saveDir` | `/roms/nes/saves` | Where to store battery saves (defaults to `<romDir>/saves`) |
84
85
  | `renderer` | `"image"` | `"image"` (Kitty graphics) or `"text"` (ANSI) |
85
- | `pixelScale` | `1.2` | Display scale (0.5–4.0) |
86
+ | `imageQuality` | `"balanced"` | `"balanced"` (30 fps, max pixel scale 1.0) or `"high"` (60 fps, max pixel scale 1.5) |
87
+ | `pixelScale` | `1.0` | Display scale (0.5–1.0 balanced, 0.5–1.5 high) |
86
88
 
87
89
  ## Terminal Support
88
90
 
@@ -5,12 +5,14 @@ import { DEFAULT_INPUT_MAPPING, type InputMapping } from "./input-map.js";
5
5
  import { normalizePath } from "./paths.js";
6
6
 
7
7
  export type RendererMode = "image" | "text";
8
+ export type ImageQuality = "balanced" | "high";
8
9
 
9
10
  export interface NesConfig {
10
11
  romDir: string;
11
12
  saveDir: string;
12
13
  enableAudio: boolean;
13
14
  renderer: RendererMode;
15
+ imageQuality: ImageQuality;
14
16
  pixelScale: number;
15
17
  keybindings: InputMapping;
16
18
  }
@@ -26,7 +28,8 @@ export const DEFAULT_CONFIG: NesConfig = {
26
28
  saveDir: getDefaultSaveDir(DEFAULT_ROM_DIR),
27
29
  enableAudio: false,
28
30
  renderer: "image",
29
- pixelScale: 1.2,
31
+ imageQuality: "balanced",
32
+ pixelScale: 1.0,
30
33
  keybindings: cloneMapping(DEFAULT_INPUT_MAPPING),
31
34
  };
32
35
 
@@ -35,6 +38,7 @@ interface RawConfig {
35
38
  saveDir?: unknown;
36
39
  enableAudio?: unknown;
37
40
  renderer?: unknown;
41
+ imageQuality?: unknown;
38
42
  pixelScale?: unknown;
39
43
  keybindings?: unknown;
40
44
  }
@@ -54,12 +58,19 @@ export function normalizeConfig(raw: unknown): NesConfig {
54
58
  typeof parsed.saveDir === "string" && parsed.saveDir.length > 0
55
59
  ? normalizePath(parsed.saveDir, saveDirFallback)
56
60
  : saveDirFallback;
61
+ const imageQuality = normalizeImageQuality(parsed.imageQuality);
62
+ const maxPixelScale = imageQuality === "high" ? 1.5 : 1.0;
63
+ const pixelScale =
64
+ typeof parsed.pixelScale === "number" && !Number.isNaN(parsed.pixelScale)
65
+ ? normalizePixelScale(parsed.pixelScale, maxPixelScale)
66
+ : maxPixelScale;
57
67
  return {
58
68
  romDir,
59
69
  saveDir,
60
70
  enableAudio: typeof parsed.enableAudio === "boolean" ? parsed.enableAudio : DEFAULT_CONFIG.enableAudio,
61
71
  renderer: parsed.renderer === "text" ? "text" : DEFAULT_CONFIG.renderer,
62
- pixelScale: normalizePixelScale(parsed.pixelScale),
72
+ imageQuality,
73
+ pixelScale,
63
74
  keybindings: normalizeKeybindings(parsed.keybindings),
64
75
  };
65
76
  }
@@ -104,11 +115,12 @@ async function ensureDirectory(dirPath: string): Promise<void> {
104
115
  }
105
116
  }
106
117
 
107
- function normalizePixelScale(raw: unknown): number {
108
- if (typeof raw !== "number" || Number.isNaN(raw)) {
109
- return DEFAULT_CONFIG.pixelScale;
110
- }
111
- return Math.min(4, Math.max(0.5, raw));
118
+ function normalizePixelScale(raw: number, maxPixelScale: number): number {
119
+ return Math.min(maxPixelScale, Math.max(0.5, raw));
120
+ }
121
+
122
+ function normalizeImageQuality(raw: unknown): ImageQuality {
123
+ return raw === "high" ? "high" : "balanced";
112
124
  }
113
125
 
114
126
  function normalizeKeybindings(raw: unknown): InputMapping {
@@ -18,7 +18,8 @@ import { NesSession } from "./nes-session.js";
18
18
  import { listRoms } from "./roms.js";
19
19
  import { loadSram } from "./saves.js";
20
20
 
21
- const IMAGE_RENDER_INTERVAL_MS = 1000 / 30;
21
+ const IMAGE_RENDER_INTERVAL_BALANCED_MS = 1000 / 30;
22
+ const IMAGE_RENDER_INTERVAL_HIGH_MS = 1000 / 60;
22
23
  const TEXT_RENDER_INTERVAL_MS = 1000 / 60;
23
24
 
24
25
  let activeSession: NesSession | null = null;
@@ -174,35 +175,17 @@ async function configureWithWizard(
174
175
  }
175
176
  }
176
177
 
177
- const qualityChoice = await ctx.ui.select("Quality (pixel scale)", [
178
- "Balanced (1.2) - recommended",
179
- "Low (1.0) - faster",
180
- "High (1.5) - sharper",
181
- "Custom...",
178
+ const qualityChoice = await ctx.ui.select("Quality", [
179
+ "Balanced (recommended) 30 fps, max pixel scale 1.0",
180
+ "High — 60 fps, max pixel scale 1.5",
182
181
  ]);
183
182
  if (!qualityChoice) {
184
183
  return false;
185
184
  }
186
185
 
187
- let pixelScale: number;
188
- if (qualityChoice.startsWith("Low")) {
189
- pixelScale = 1.0;
190
- } else if (qualityChoice.startsWith("Balanced")) {
191
- pixelScale = 1.2;
192
- } else if (qualityChoice.startsWith("High")) {
193
- pixelScale = 1.5;
194
- } else {
195
- const pixelScaleInput = await ctx.ui.input("Pixel scale (0.5 - 4)", config.pixelScale.toString());
196
- if (pixelScaleInput === undefined) {
197
- return false;
198
- }
199
- const parsed = pixelScaleInput.trim() === "" ? config.pixelScale : Number(pixelScaleInput);
200
- if (Number.isNaN(parsed)) {
201
- ctx.ui.notify("Pixel scale must be a number.", "error");
202
- return false;
203
- }
204
- pixelScale = parsed;
205
- }
186
+ const isHighQuality = qualityChoice.startsWith("High");
187
+ const imageQuality = isHighQuality ? "high" : "balanced";
188
+ const pixelScale = isHighQuality ? 1.5 : 1.0;
206
189
 
207
190
  const defaultSaveDir = getDefaultSaveDir(config.romDir);
208
191
  const shouldSyncSaveDir = config.saveDir === defaultSaveDir;
@@ -211,6 +194,7 @@ async function configureWithWizard(
211
194
  ...config,
212
195
  romDir,
213
196
  saveDir,
197
+ imageQuality,
214
198
  pixelScale,
215
199
  });
216
200
  await saveConfig(normalized);
@@ -318,7 +302,11 @@ async function attachSession(
318
302
  }
319
303
  : undefined;
320
304
 
321
- const renderIntervalMs = config.renderer === "image" ? IMAGE_RENDER_INTERVAL_MS : TEXT_RENDER_INTERVAL_MS;
305
+ const renderIntervalMs = config.renderer === "image"
306
+ ? config.imageQuality === "high"
307
+ ? IMAGE_RENDER_INTERVAL_HIGH_MS
308
+ : IMAGE_RENDER_INTERVAL_BALANCED_MS
309
+ : TEXT_RENDER_INTERVAL_MS;
322
310
  session.setRenderIntervalMs(renderIntervalMs);
323
311
 
324
312
  await ctx.ui.custom(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmustier/pi-nes",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "NES emulator extension for pi",
5
5
  "keywords": [
6
6
  "pi-package",
package/spec.md CHANGED
@@ -70,7 +70,8 @@ pi-nes/
70
70
  - `saveDir`
71
71
  - `enableAudio`
72
72
  - `renderer` ("image" or "text")
73
- - `pixelScale` (float, e.g. 1.5)
73
+ - `imageQuality` ("balanced" or "high")
74
+ - `pixelScale` (float, e.g. 1.0)
74
75
  - `keybindings` (button-to-keys map, e.g. `{ "a": ["z"] }`)
75
76
 
76
77
  Note: audio output is currently disabled; setting `enableAudio` will show a warning.
@@ -88,5 +89,6 @@ Note: audio output is currently disabled; setting `enableAudio` will show a warn
88
89
  - Audio: disabled (no safe dependency selected).
89
90
  - Default ROM dir: `/roms/nes` (configurable).
90
91
  - Default core: `native`.
91
- - Default pixel scale: `1.2`.
92
+ - Default image quality: `balanced`.
93
+ - Default pixel scale: `1.0`.
92
94
  - Default save dir: `/roms/nes/saves` (configurable).