koin.js 1.0.0

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.
@@ -0,0 +1,858 @@
1
+ import * as react from 'react';
2
+ import { Nostalgist } from 'nostalgist';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ /**
6
+ * Unified Control System Types
7
+ *
8
+ * Single source of truth for all control-related type definitions.
9
+ */
10
+ /**
11
+ * All possible button identifiers (superset of all consoles)
12
+ */
13
+ type ButtonId = 'up' | 'down' | 'left' | 'right' | 'a' | 'b' | 'x' | 'y' | 'l' | 'r' | 'l2' | 'r2' | 'l3' | 'r3' | 'start' | 'select';
14
+ /**
15
+ * D-pad buttons
16
+ */
17
+ declare const DPAD_BUTTONS: ButtonId[];
18
+ /**
19
+ * Face buttons
20
+ */
21
+ declare const FACE_BUTTONS: ButtonId[];
22
+ /**
23
+ * Shoulder buttons (L/R only)
24
+ */
25
+ declare const SHOULDER_BUTTONS: ButtonId[];
26
+ /**
27
+ * Trigger buttons (L2/R2)
28
+ */
29
+ declare const TRIGGER_BUTTONS: ButtonId[];
30
+ /**
31
+ * Stick click buttons
32
+ */
33
+ declare const STICK_BUTTONS: ButtonId[];
34
+ /**
35
+ * System buttons
36
+ */
37
+ declare const SYSTEM_BUTTONS: ButtonId[];
38
+ /**
39
+ * All buttons in display order
40
+ */
41
+ declare const ALL_BUTTONS: ButtonId[];
42
+ /**
43
+ * Keyboard mapping: button → JavaScript KeyboardEvent.code
44
+ * Partial because not all consoles have all buttons
45
+ */
46
+ type KeyboardMapping = Partial<Record<ButtonId, string>>;
47
+ /**
48
+ * Gamepad mapping: button → physical button index (W3C Gamepad API)
49
+ * Partial because users may not map all buttons
50
+ */
51
+ type GamepadMapping = Partial<Record<ButtonId, number>>;
52
+ /**
53
+ * Which buttons a console actually has
54
+ */
55
+ interface ConsoleCapabilities {
56
+ /** Console key (e.g., 'NES', 'SNES') */
57
+ console: string;
58
+ /** List of buttons this console supports */
59
+ buttons: ButtonId[];
60
+ }
61
+ /**
62
+ * Information about a connected gamepad
63
+ */
64
+ interface GamepadInfo {
65
+ /** Gamepad index (0-3) */
66
+ index: number;
67
+ /** Raw gamepad identifier string */
68
+ id: string;
69
+ /** Cleaned up display name */
70
+ name: string;
71
+ /** Whether currently connected */
72
+ connected: boolean;
73
+ /** Number of buttons */
74
+ buttons: number;
75
+ /** Number of axes */
76
+ axes: number;
77
+ /** Mapping type from Gamepad API */
78
+ mapping: GamepadMappingType;
79
+ }
80
+ /**
81
+ * Detected controller brand for UI theming
82
+ */
83
+ type ControllerBrand = 'xbox' | 'playstation' | 'nintendo' | 'generic';
84
+ /**
85
+ * Player index (1-4)
86
+ */
87
+ type PlayerIndex = 1 | 2 | 3 | 4;
88
+ /**
89
+ * Full control configuration for the emulator
90
+ */
91
+ interface ControlConfig {
92
+ /** Keyboard controls (usually player 1 only) */
93
+ keyboard?: KeyboardMapping;
94
+ /** Gamepad controls per player */
95
+ gamepads?: GamepadMapping[];
96
+ }
97
+
98
+ /**
99
+ * Default Control Mappings
100
+ *
101
+ * Single source of truth for all default button mappings.
102
+ */
103
+
104
+ /**
105
+ * Standard W3C Gamepad API button indices
106
+ * https://w3c.github.io/gamepad/#remapping
107
+ */
108
+ declare const STANDARD_GAMEPAD_BUTTONS: Record<ButtonId, number>;
109
+ /**
110
+ * Default keyboard mapping (SNES-like, works for most consoles)
111
+ */
112
+ declare const DEFAULT_KEYBOARD: KeyboardMapping;
113
+ /**
114
+ * Default gamepad mapping (uses standard W3C indices)
115
+ */
116
+ declare const DEFAULT_GAMEPAD: GamepadMapping;
117
+ /**
118
+ * Get a complete keyboard mapping with all buttons filled in
119
+ * Uses defaults for any missing buttons
120
+ */
121
+ declare function getFullKeyboardMapping(partial?: Partial<KeyboardMapping>): KeyboardMapping;
122
+ /**
123
+ * Get a complete gamepad mapping with all buttons filled in
124
+ * Uses defaults for any missing buttons
125
+ */
126
+ declare function getFullGamepadMapping(partial?: Partial<GamepadMapping>): GamepadMapping;
127
+
128
+ /**
129
+ * Button Labels for UI Display
130
+ *
131
+ * Single source of truth for button display names.
132
+ */
133
+
134
+ /**
135
+ * Human-readable labels for each button
136
+ */
137
+ declare const BUTTON_LABELS: Record<ButtonId, string>;
138
+ /**
139
+ * Button groups for organized UI display
140
+ */
141
+ declare const BUTTON_GROUPS: {
142
+ label: string;
143
+ buttons: ButtonId[];
144
+ }[];
145
+ /**
146
+ * Format a JavaScript key code for display
147
+ */
148
+ declare function formatKeyCode(code: string): string;
149
+ /**
150
+ * Get human-readable name for a gamepad button index
151
+ */
152
+ declare function formatGamepadButton(index: number | undefined): string;
153
+
154
+ /**
155
+ * Per-Console Control Presets
156
+ *
157
+ * Defines which buttons each console supports and
158
+ * console-specific default keyboard layouts.
159
+ */
160
+
161
+ /**
162
+ * Console capabilities - which buttons each system has
163
+ */
164
+ declare const CONSOLE_CAPABILITIES: Record<string, ConsoleCapabilities>;
165
+ /**
166
+ * Console-specific keyboard overrides
167
+ * Only specify keys that differ from DEFAULT_KEYBOARD
168
+ */
169
+ declare const CONSOLE_KEYBOARD_OVERRIDES: Partial<Record<string, Partial<KeyboardMapping>>>;
170
+ /**
171
+ * Get capabilities for a console
172
+ * Falls back to SNES-like if unknown
173
+ */
174
+ declare function getConsoleCapabilities(system: string): ConsoleCapabilities;
175
+ /**
176
+ * Get the list of buttons for a console
177
+ */
178
+ declare function getConsoleButtons(system: string): ButtonId[];
179
+ /**
180
+ * Get default keyboard mapping for a console
181
+ * Merges console-specific overrides with defaults
182
+ */
183
+ declare function getConsoleKeyboardDefaults(system: string): KeyboardMapping;
184
+ /**
185
+ * Check if a console supports a specific button
186
+ */
187
+ declare function consoleHasButton(system: string, button: ButtonId): boolean;
188
+
189
+ /**
190
+ * Control Storage Utilities
191
+ *
192
+ * Load and save keyboard/gamepad mappings from localStorage.
193
+ */
194
+
195
+ /**
196
+ * Load keyboard mapping from localStorage
197
+ * Falls back to console-specific defaults if not found
198
+ */
199
+ declare function loadKeyboardMapping(system?: string): KeyboardMapping;
200
+ /**
201
+ * Save keyboard mapping to localStorage
202
+ */
203
+ declare function saveKeyboardMapping(mapping: KeyboardMapping, system?: string): void;
204
+ /**
205
+ * Load gamepad mapping from localStorage
206
+ * Falls back to standard defaults if not found
207
+ */
208
+ declare function loadGamepadMapping(playerIndex?: PlayerIndex): GamepadMapping;
209
+ /**
210
+ * Save gamepad mapping to localStorage
211
+ */
212
+ declare function saveGamepadMapping(mapping: GamepadMapping, playerIndex?: PlayerIndex): void;
213
+ /**
214
+ * Load all gamepad mappings for connected players
215
+ */
216
+ declare function loadAllGamepadMappings(playerCount: number): GamepadMapping[];
217
+ /**
218
+ * Clear all saved controls (keyboard and gamepad)
219
+ */
220
+ declare function clearAllControls(): void;
221
+
222
+ /**
223
+ * RetroArch Input Configuration
224
+ *
225
+ * Converts our control mappings to RetroArch config format.
226
+ */
227
+
228
+ /**
229
+ * Convert keyboard mapping to RetroArch config for a player
230
+ */
231
+ declare function keyboardToRetroArchConfig(mapping: KeyboardMapping, playerIndex?: number): Record<string, string>;
232
+ /**
233
+ * Convert gamepad mapping to RetroArch config for a player
234
+ * Uses _btn suffix for button indices
235
+ */
236
+ declare function gamepadToRetroArchConfig(mapping: GamepadMapping, playerIndex?: number): Record<string, number | string>;
237
+ /**
238
+ * Build complete RetroArch input config from control configuration
239
+ */
240
+ declare function buildRetroArchConfig(config: ControlConfig): Record<string, unknown>;
241
+
242
+ type EmulatorStatus = 'idle' | 'loading' | 'ready' | 'running' | 'paused' | 'error';
243
+ type SpeedMultiplier = 1 | 2;
244
+ interface RetroAchievementsConfig {
245
+ username: string;
246
+ token: string;
247
+ hardcore?: boolean;
248
+ }
249
+
250
+ interface UseNostalgistOptions {
251
+ system: string;
252
+ romUrl: string;
253
+ core?: string;
254
+ biosUrl?: string | {
255
+ url: string;
256
+ name: string;
257
+ location?: 'system' | 'rom_folder';
258
+ };
259
+ initialState?: Blob | Uint8Array;
260
+ getCanvasElement?: () => HTMLCanvasElement | null;
261
+ keyboardControls?: KeyboardMapping;
262
+ gamepadBindings?: GamepadMapping[];
263
+ retroAchievements?: RetroAchievementsConfig;
264
+ onReady?: () => void;
265
+ onError?: (error: Error) => void;
266
+ initialVolume?: number;
267
+ romFileName?: string;
268
+ shader?: string;
269
+ }
270
+ interface UseNostalgistReturn {
271
+ status: EmulatorStatus;
272
+ error: string | null;
273
+ isPaused: boolean;
274
+ speed: SpeedMultiplier;
275
+ isRewinding: boolean;
276
+ rewindBufferSize: number;
277
+ volume: number;
278
+ isMuted: boolean;
279
+ prepare: () => Promise<void>;
280
+ start: () => Promise<void>;
281
+ stop: () => void;
282
+ restart: () => Promise<void>;
283
+ pause: () => void;
284
+ resume: () => void;
285
+ togglePause: () => void;
286
+ saveState: () => Promise<Uint8Array | null>;
287
+ saveStateWithBlob: () => Promise<{
288
+ data: Uint8Array;
289
+ blob: Blob;
290
+ } | null>;
291
+ loadState: (state: Uint8Array) => Promise<boolean>;
292
+ setSpeed: (multiplier: SpeedMultiplier) => void;
293
+ startRewind: () => void;
294
+ stopRewind: () => void;
295
+ rewindEnabled: boolean;
296
+ setVolume: (volume: number) => void;
297
+ toggleMute: () => void;
298
+ screenshot: () => Promise<string | null>;
299
+ pressKey: (key: string) => void;
300
+ resize: (size: {
301
+ width: number;
302
+ height: number;
303
+ }) => void;
304
+ applyCheat: (code: string) => void;
305
+ resetCheats: () => void;
306
+ getNostalgistInstance: () => Nostalgist | null;
307
+ isPerformanceMode: boolean;
308
+ }
309
+ declare const useNostalgist: ({ system, romUrl, core, biosUrl, initialState, getCanvasElement, keyboardControls, gamepadBindings, retroAchievements, onReady, onError, initialVolume, romFileName, shader, }: UseNostalgistOptions) => UseNostalgistReturn;
310
+
311
+ /**
312
+ * Available CRT Shader Presets
313
+ * ----------------------------
314
+ * These are loaded from libretro/glsl-shaders via Nostalgist.
315
+ * Format: { id: shader_path, name: display_name, description: tooltip }
316
+ */
317
+ declare const SHADER_PRESETS: readonly [{
318
+ readonly id: "";
319
+ readonly name: "None";
320
+ readonly description: "No shader - sharp pixels";
321
+ }, {
322
+ readonly id: "crt/crt-lottes";
323
+ readonly name: "CRT Lottes";
324
+ readonly description: "High-quality arcade monitor look";
325
+ }, {
326
+ readonly id: "crt/crt-easymode";
327
+ readonly name: "CRT Easy";
328
+ readonly description: "Popular, performant CRT effect";
329
+ }, {
330
+ readonly id: "crt/crt-geom";
331
+ readonly name: "CRT Geom";
332
+ readonly description: "Classic CRT shader with curvature";
333
+ }, {
334
+ readonly id: "crt/crt-hyllian";
335
+ readonly name: "CRT Hyllian";
336
+ readonly description: "Attractive with minimal tweaking";
337
+ }, {
338
+ readonly id: "crt/crt-nes-mini";
339
+ readonly name: "NES Mini";
340
+ readonly description: "Simple scanlines like NES Classic";
341
+ }, {
342
+ readonly id: "crt/zfast-crt";
343
+ readonly name: "zFast CRT";
344
+ readonly description: "Lightweight, great for mobile";
345
+ }, {
346
+ readonly id: "crt/crt-potato-cool";
347
+ readonly name: "CRT Potato";
348
+ readonly description: "Fast and good for weak devices";
349
+ }, {
350
+ readonly id: "handheld/lcd-grid-v2";
351
+ readonly name: "LCD Grid";
352
+ readonly description: "Game Boy style LCD effect";
353
+ }, {
354
+ readonly id: "scanlines";
355
+ readonly name: "Scanlines";
356
+ readonly description: "Simple horizontal scanlines";
357
+ }];
358
+ type ShaderPresetId = typeof SHADER_PRESETS[number]['id'];
359
+ interface ShaderSelectorProps {
360
+ currentShader: ShaderPresetId;
361
+ onShaderChange: (shaderId: ShaderPresetId) => void;
362
+ disabled?: boolean;
363
+ systemColor?: string;
364
+ }
365
+ /**
366
+ * Shader Selector Component
367
+ * -------------------------
368
+ * Dropdown to select CRT/LCD shader effects.
369
+ */
370
+ declare const ShaderSelector: react.NamedExoticComponent<ShaderSelectorProps>;
371
+
372
+ declare const RA_MEDIA_BASE = "https://media.retroachievements.org";
373
+ interface RACredentials {
374
+ username: string;
375
+ connectToken: string;
376
+ apiKey?: string;
377
+ score?: number;
378
+ softcoreScore?: number;
379
+ avatarUrl?: string;
380
+ }
381
+ interface RAUser {
382
+ User: string;
383
+ Token: string;
384
+ Score: number;
385
+ SoftcoreScore: number;
386
+ Messages: number;
387
+ Permissions: number;
388
+ AccountType: string;
389
+ }
390
+ interface RAAchievement {
391
+ ID: number;
392
+ NumAwarded: number;
393
+ NumAwardedHardcore: number;
394
+ Title: string;
395
+ Description: string;
396
+ Points: number;
397
+ TrueRatio: number;
398
+ Author: string;
399
+ DateModified: string;
400
+ DateCreated: string;
401
+ BadgeName: string;
402
+ DisplayOrder: number;
403
+ MemAddr: string;
404
+ type: string | null;
405
+ DateEarned?: string;
406
+ DateEarnedHardcore?: string;
407
+ }
408
+ interface RAGame {
409
+ ID: number;
410
+ Title: string;
411
+ ConsoleID: number;
412
+ ConsoleName: string;
413
+ ForumTopicID: number;
414
+ Flags: number;
415
+ ImageIcon: string;
416
+ ImageTitle: string;
417
+ ImageIngame: string;
418
+ ImageBoxArt: string;
419
+ Publisher: string;
420
+ Developer: string;
421
+ Genre: string;
422
+ Released: string;
423
+ IsFinal: boolean;
424
+ RichPresencePatch?: string;
425
+ NumAchievements?: number;
426
+ NumDistinctPlayersCasual?: number;
427
+ NumDistinctPlayersHardcore?: number;
428
+ }
429
+ interface RAGameExtended extends RAGame {
430
+ Achievements: Record<string, RAAchievement>;
431
+ NumAwardedToUser?: number;
432
+ NumAwardedToUserHardcore?: number;
433
+ UserCompletion?: string;
434
+ UserCompletionHardcore?: string;
435
+ }
436
+ /**
437
+ * Get achievement badge URL
438
+ */
439
+ declare function getAchievementBadgeUrl(badgeName: string, locked?: boolean): string;
440
+ /**
441
+ * Get user avatar URL
442
+ */
443
+ declare function getUserAvatarUrl(userPic: string): string;
444
+
445
+ interface SaveSlot {
446
+ slot: number;
447
+ timestamp: string;
448
+ size: number;
449
+ screenshot?: string | null;
450
+ }
451
+ /**
452
+ * @deprecated Use `KeyboardMapping` from `@/lib/controls` instead
453
+ */
454
+ type ControlMapping = KeyboardMapping;
455
+ /**
456
+ * @deprecated Use `DEFAULT_KEYBOARD` from `@/lib/controls` instead
457
+ */
458
+ declare const DEFAULT_CONTROLS: Partial<Record<ButtonId, string>>;
459
+ interface GamePlayerProps {
460
+ className?: string;
461
+ style?: React.CSSProperties;
462
+ romId: string;
463
+ romUrl: string;
464
+ romFileName?: string;
465
+ system: string;
466
+ title: string;
467
+ core?: string;
468
+ biosUrl?: string | {
469
+ url: string;
470
+ name: string;
471
+ location?: 'system' | 'rom_folder';
472
+ };
473
+ availableBios?: {
474
+ id: string;
475
+ name: string;
476
+ description?: string;
477
+ }[];
478
+ currentBiosId?: string;
479
+ onSelectBios?: (biosId: string) => void;
480
+ onReady?: () => void;
481
+ onError?: (error: Error) => void;
482
+ onExit?: () => void;
483
+ systemColor?: string;
484
+ shader?: string;
485
+ onShaderChange?: (shader: string, requiresRestart: boolean) => void;
486
+ initialSlot?: number;
487
+ onSaveState?: (slot: number, blob: Blob, screenshot?: string) => Promise<void>;
488
+ onLoadState?: (slot: number) => Promise<Blob | null>;
489
+ onAutoSave?: (blob: Blob, screenshot?: string) => Promise<void>;
490
+ onGetSaveSlots?: () => Promise<SaveSlot[]>;
491
+ onDeleteSaveState?: (slot: number) => Promise<void>;
492
+ initialSaveState?: Blob;
493
+ onScreenshotCaptured?: (image: string | Blob) => void;
494
+ autoSaveInterval?: number;
495
+ maxSlots?: number;
496
+ currentTier?: string;
497
+ onUpgrade?: () => void;
498
+ retroAchievementsConfig?: {
499
+ username: string;
500
+ token: string;
501
+ hardcore?: boolean;
502
+ };
503
+ cheats?: Cheat[];
504
+ onToggleCheat?: (cheatId: number, active: boolean) => void;
505
+ onSessionStart?: () => void;
506
+ onSessionEnd?: () => void;
507
+ raUser?: RACredentials | null;
508
+ raGame?: RAGameExtended | null;
509
+ raAchievements?: RAAchievement[];
510
+ raUnlockedAchievements?: Set<number>;
511
+ raIsLoading?: boolean;
512
+ raError?: string | null;
513
+ onRALogin?: (username: string, password: string) => Promise<boolean>;
514
+ onRALogout?: () => void;
515
+ onRAHardcoreChange?: (enabled: boolean) => void;
516
+ }
517
+ interface PlayerControlsProps {
518
+ isPaused: boolean;
519
+ isRunning: boolean;
520
+ speed: SpeedMultiplier;
521
+ isRewinding: boolean;
522
+ rewindBufferSize: number;
523
+ onPauseToggle: () => void;
524
+ onRestart: () => void;
525
+ onSave: () => void;
526
+ onLoad: () => void;
527
+ onSpeedChange: (speed: SpeedMultiplier) => void;
528
+ onRewindStart: () => void;
529
+ onRewindStop: () => void;
530
+ onScreenshot: () => void;
531
+ onFullscreen: () => void;
532
+ onControls: () => void;
533
+ onCheats: () => void;
534
+ onRetroAchievements: () => void;
535
+ onExit: () => void;
536
+ disabled?: boolean;
537
+ hardcoreRestrictions?: RAHardcodeRestrictions;
538
+ raConnected?: boolean;
539
+ raGameFound?: boolean;
540
+ raAchievementCount?: number;
541
+ raIsIdentifying?: boolean;
542
+ autoSaveEnabled?: boolean;
543
+ autoSaveProgress?: number;
544
+ autoSaveState?: 'idle' | 'counting' | 'saving' | 'done';
545
+ autoSavePaused?: boolean;
546
+ onAutoSaveToggle?: () => void;
547
+ systemColor?: string;
548
+ gamepadCount?: number;
549
+ onGamepadSettings?: () => void;
550
+ volume?: number;
551
+ isMuted?: boolean;
552
+ onVolumeChange?: (volume: number) => void;
553
+ onToggleMute?: () => void;
554
+ onShowShortcuts?: () => void;
555
+ onRecordToggle?: () => void;
556
+ isRecording?: boolean;
557
+ currentShader?: ShaderPresetId;
558
+ onShaderChange?: (shader: ShaderPresetId, requiresRestart: boolean) => void;
559
+ }
560
+ interface SaveSlotModalProps {
561
+ isOpen: boolean;
562
+ mode: 'save' | 'load';
563
+ slots: SaveSlot[];
564
+ isLoading: boolean;
565
+ actioningSlot?: number | null;
566
+ onSelect: (slot: number) => void;
567
+ onDelete: (slot: number) => void;
568
+ onClose: () => void;
569
+ maxSlots?: number;
570
+ currentTier?: string;
571
+ onUpgrade?: () => void;
572
+ }
573
+ interface ControlMapperProps {
574
+ isOpen: boolean;
575
+ controls: ControlMapping;
576
+ onSave: (controls: ControlMapping) => void;
577
+ onClose: () => void;
578
+ system?: string;
579
+ }
580
+ interface CheatModalProps {
581
+ isOpen: boolean;
582
+ cheats: Cheat[];
583
+ activeCheats: Set<number>;
584
+ onToggle: (cheatId: number) => void;
585
+ onClose: () => void;
586
+ }
587
+ interface Cheat {
588
+ id: number;
589
+ code: string;
590
+ description: string;
591
+ }
592
+ interface RAHardcodeRestrictions {
593
+ isHardcore?: boolean;
594
+ canUseSaveStates: boolean;
595
+ canUseRewind: boolean;
596
+ canUseCheats: boolean;
597
+ canUseSlowMotion: boolean;
598
+ }
599
+
600
+ declare const GamePlayer: react.NamedExoticComponent<GamePlayerProps & {
601
+ controls?: KeyboardMapping;
602
+ saveControls?: (controls: KeyboardMapping) => void;
603
+ }>;
604
+
605
+ /**
606
+ * Detect controller brand from gamepad id for UI theming
607
+ */
608
+ declare function detectControllerBrand(id: string): ControllerBrand;
609
+ interface UseGamepadOptions {
610
+ /** Callback when a gamepad connects */
611
+ onConnect?: (gamepad: GamepadInfo) => void;
612
+ /** Callback when a gamepad disconnects */
613
+ onDisconnect?: () => void;
614
+ }
615
+ interface UseGamepadReturn {
616
+ /** Array of connected gamepads (up to 4) */
617
+ gamepads: GamepadInfo[];
618
+ /** Whether any gamepad is connected */
619
+ isAnyConnected: boolean;
620
+ /** Number of connected gamepads */
621
+ connectedCount: number;
622
+ /** Get raw gamepad by index for reading button states */
623
+ getRawGamepad: (index: number) => Gamepad | null;
624
+ /** Force refresh gamepad list */
625
+ refresh: () => void;
626
+ }
627
+ /**
628
+ * Hook to track connected gamepads
629
+ * Uses requestAnimationFrame polling since Gamepad API requires active polling
630
+ *
631
+ * NOTE: Browsers require a button press before reporting gamepads (security feature)
632
+ */
633
+ declare function useGamepad(options?: UseGamepadOptions): UseGamepadReturn;
634
+ /**
635
+ * Standard gamepad axis indices
636
+ */
637
+ declare const STANDARD_AXIS_MAP: {
638
+ readonly leftStickX: 0;
639
+ readonly leftStickY: 1;
640
+ readonly rightStickX: 2;
641
+ readonly rightStickY: 3;
642
+ };
643
+ type StandardAxis = keyof typeof STANDARD_AXIS_MAP;
644
+
645
+ type ToastType = 'success' | 'error' | 'info' | 'warning' | 'gamepad';
646
+ interface Toast {
647
+ id: string;
648
+ message: string;
649
+ type: ToastType;
650
+ title?: string;
651
+ icon?: string;
652
+ duration?: number;
653
+ action?: {
654
+ label: string;
655
+ onClick: () => void;
656
+ };
657
+ }
658
+ interface ShowToastOptions {
659
+ title?: string;
660
+ icon?: string;
661
+ duration?: number;
662
+ action?: Toast['action'];
663
+ }
664
+ interface UseToastReturn {
665
+ toasts: Toast[];
666
+ showToast: (message: string, type?: ToastType, options?: ShowToastOptions) => void;
667
+ dismissToast: (id: string) => void;
668
+ clearToasts: () => void;
669
+ }
670
+ /**
671
+ * Hook for managing toast notifications
672
+ * @param defaultDuration - Default duration for toasts (default 3000ms)
673
+ */
674
+ declare function useToast(defaultDuration?: number): UseToastReturn;
675
+
676
+ interface SystemConfig {
677
+ key: string;
678
+ label: string;
679
+ fullName: string;
680
+ slug: string;
681
+ extensions: string[];
682
+ core: string;
683
+ dbNames: string[];
684
+ iconName: string;
685
+ color: string;
686
+ accentHex: string;
687
+ aliases: string[];
688
+ biosNeeded?: boolean;
689
+ biosFileNames?: string[];
690
+ biosLocation?: 'system' | 'rom_folder';
691
+ }
692
+ /**
693
+ * The master system configuration
694
+ * Order matters for display in dropdowns
695
+ */
696
+ declare const SYSTEMS: SystemConfig[];
697
+
698
+ /**
699
+ * Unified System Configuration
700
+ *
701
+ * SINGLE SOURCE OF TRUTH for all system-related data:
702
+ * - Canonical system keys (used internally)
703
+ * - File extensions → system detection
704
+ * - System → RetroArch emulator core
705
+ * - System → Database names (for LaunchBox matching)
706
+ * - System → Display metadata (UI labels, colors, icons)
707
+ *
708
+ * All other files should import from here instead of maintaining their own mappings.
709
+ */
710
+
711
+ /**
712
+ * Get system by canonical key (e.g., 'NES', 'GBA')
713
+ */
714
+ declare function getSystemByKey(key: string): SystemConfig | undefined;
715
+ /**
716
+ * Get system by any name/alias (case-insensitive)
717
+ * Tries: exact key match, then alias match
718
+ */
719
+ declare function getSystem(name: string): SystemConfig | undefined;
720
+ /**
721
+ * Get system from file extension (e.g., '.nes', '.gba')
722
+ */
723
+ declare function getSystemFromExtension(filename: string): SystemConfig | undefined;
724
+ /**
725
+ * Get system by database name (for LaunchBox matching)
726
+ */
727
+ declare function getSystemByDbName(dbName: string): SystemConfig | undefined;
728
+ /**
729
+ * Get RetroArch core for a system name (case-insensitive)
730
+ * Falls back to 'fceumm' (NES) if not found
731
+ */
732
+ declare function getCore(systemName: string): string;
733
+ /**
734
+ * Get DB names for matching (used in game search)
735
+ */
736
+ declare function getDBSystemNames(systemKey: string): string[];
737
+ /**
738
+ * Check if a system is supported
739
+ */
740
+ declare function isSystemSupported(name: string): boolean;
741
+ /**
742
+ * Get all supported extensions
743
+ */
744
+ declare function getSupportedExtensions(): string[];
745
+ /**
746
+ * Get all systems for UI dropdown
747
+ */
748
+ declare function getSystemsList(): Array<{
749
+ value: string;
750
+ label: string;
751
+ iconName: string;
752
+ color: string;
753
+ }>;
754
+ /**
755
+ * Detect system from filename
756
+ * Returns null for ZIP files (user must select)
757
+ */
758
+ declare function detectSystem(filename: string): SystemConfig | undefined;
759
+ /**
760
+ * Check if two system names refer to the same platform
761
+ */
762
+ declare function systemsMatch(name1: string, name2: string): boolean;
763
+ /**
764
+ * Normalize a system name to its canonical key
765
+ */
766
+ declare function normalizeSystemKey(name: string): string;
767
+ declare const SUPPORTED_EXTENSIONS: string[];
768
+ /**
769
+ * TIER 1: "Zero Lag" - Lightweight Systems
770
+ * ----------------------------------------
771
+ * These 8-bit and 16-bit systems have low CPU requirements in WASM,
772
+ * allowing us to enable Run-Ahead (frame prediction) for near-zero input latency.
773
+ *
774
+ * Run-Ahead works by running the emulator ahead by 1 frame and using that
775
+ * result for display, effectively cutting 1 frame (~16ms) of input lag.
776
+ */
777
+ declare const PERFORMANCE_TIER_1_SYSTEMS: Set<string>;
778
+ /**
779
+ * TIER 2: "Max Smoothness" - Heavy Systems
780
+ * ----------------------------------------
781
+ * These 32-bit+ systems push WASM hard. Run-Ahead would cause stuttering.
782
+ * Instead, we optimize for smooth, consistent frame delivery:
783
+ * - Threaded video rendering to prevent UI freezes
784
+ * - Larger audio buffers to prevent crackling
785
+ * - Disabled manual rewind capture (saves RAM and CPU cycles)
786
+ */
787
+ declare const PERFORMANCE_TIER_2_SYSTEMS: Set<string>;
788
+
789
+ interface RASidebarProps {
790
+ isOpen: boolean;
791
+ onClose: () => void;
792
+ isLoggedIn: boolean;
793
+ credentials: RACredentials | null;
794
+ isLoading: boolean;
795
+ error?: string | null;
796
+ onLogin: (username: string, password: string) => Promise<boolean>;
797
+ onLogout: () => void;
798
+ hardcoreEnabled: boolean;
799
+ onHardcoreChange: (enabled: boolean) => void;
800
+ currentGame: RAGameExtended | null;
801
+ achievements: RAAchievement[];
802
+ unlockedIds: Set<number>;
803
+ }
804
+ declare function RASidebar({ isOpen, onClose, isLoggedIn, credentials, isLoading, error, onLogin, onLogout, hardcoreEnabled, onHardcoreChange, currentGame, achievements, unlockedIds, }: RASidebarProps): react_jsx_runtime.JSX.Element | null;
805
+
806
+ interface AchievementPopupProps {
807
+ achievement: RAAchievement;
808
+ hardcore: boolean;
809
+ onDismiss: () => void;
810
+ autoDismissMs?: number;
811
+ }
812
+ declare function AchievementPopup({ achievement, hardcore, onDismiss, autoDismissMs, }: AchievementPopupProps): react_jsx_runtime.JSX.Element;
813
+
814
+ interface ToastContainerProps {
815
+ toasts: Toast[];
816
+ onDismiss?: (id: string) => void;
817
+ }
818
+ declare function ToastContainer({ toasts, onDismiss }: ToastContainerProps): react_jsx_runtime.JSX.Element | null;
819
+
820
+ /**
821
+ * Shortcuts Reference
822
+ * -------------------
823
+ * Collapsible panel showing player F-key shortcuts.
824
+ * Game controls have their own config in the Keys modal.
825
+ */
826
+ interface ShortcutsReferenceProps {
827
+ systemColor?: string;
828
+ isExpanded?: boolean;
829
+ }
830
+ declare const ShortcutsReference: react.NamedExoticComponent<ShortcutsReferenceProps>;
831
+
832
+ interface UseGameRecordingProps {
833
+ getCanvasElement: () => HTMLCanvasElement | null;
834
+ }
835
+ interface UseGameRecordingReturn {
836
+ isRecording: boolean;
837
+ isPaused: boolean;
838
+ recordingDuration: number;
839
+ startRecording: () => void;
840
+ stopRecording: () => Promise<Blob | null>;
841
+ pauseRecording: () => void;
842
+ resumeRecording: () => void;
843
+ isSupported: boolean;
844
+ }
845
+ /**
846
+ * Gameplay Recording Hook
847
+ * -----------------------
848
+ * Uses MediaRecorder API to capture canvas gameplay as WebM video.
849
+ *
850
+ * Features:
851
+ * - Start/stop recording
852
+ * - Pause/resume
853
+ * - Duration tracking
854
+ * - Returns Blob for download
855
+ */
856
+ declare function useGameRecording({ getCanvasElement, }: UseGameRecordingProps): UseGameRecordingReturn;
857
+
858
+ export { ALL_BUTTONS, AchievementPopup, BUTTON_GROUPS, BUTTON_LABELS, type ButtonId, CONSOLE_CAPABILITIES, CONSOLE_KEYBOARD_OVERRIDES, type Cheat, type CheatModalProps, type ConsoleCapabilities, type ControlConfig, type ControlMapperProps, type ControlMapping, type ControllerBrand, DEFAULT_CONTROLS, DEFAULT_GAMEPAD, DEFAULT_KEYBOARD, DPAD_BUTTONS, type EmulatorStatus, FACE_BUTTONS, GamePlayer, type GamePlayerProps, type GamepadInfo, type GamepadMapping, type KeyboardMapping, PERFORMANCE_TIER_1_SYSTEMS, PERFORMANCE_TIER_2_SYSTEMS, type PlayerControlsProps, type PlayerIndex, type RAAchievement, type RACredentials, type RAGame, type RAGameExtended, type RAHardcodeRestrictions, RASidebar, type RAUser, RA_MEDIA_BASE, type RetroAchievementsConfig, SHADER_PRESETS, SHOULDER_BUTTONS, STANDARD_AXIS_MAP, STANDARD_GAMEPAD_BUTTONS, STICK_BUTTONS, SUPPORTED_EXTENSIONS, SYSTEMS, SYSTEM_BUTTONS, type SaveSlot, type SaveSlotModalProps, type ShaderPresetId, ShaderSelector, ShortcutsReference, type ShowToastOptions, type SpeedMultiplier, type StandardAxis, type SystemConfig, TRIGGER_BUTTONS, type Toast, ToastContainer, type ToastType, type UseGamepadOptions, type UseGamepadReturn, type UseNostalgistReturn, type UseToastReturn, buildRetroArchConfig, clearAllControls, consoleHasButton, detectControllerBrand, detectSystem, formatGamepadButton, formatKeyCode, gamepadToRetroArchConfig, getAchievementBadgeUrl, getConsoleButtons, getConsoleCapabilities, getConsoleKeyboardDefaults, getCore, getDBSystemNames, getFullGamepadMapping, getFullKeyboardMapping, getSupportedExtensions, getSystem, getSystemByDbName, getSystemByKey, getSystemFromExtension, getSystemsList, getUserAvatarUrl, isSystemSupported, keyboardToRetroArchConfig, loadAllGamepadMappings, loadGamepadMapping, loadKeyboardMapping, normalizeSystemKey, saveGamepadMapping, saveKeyboardMapping, systemsMatch, useGameRecording, useGamepad, useNostalgist, useToast };