brainrot-cli 0.1.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.
- package/README.md +372 -0
- package/dist/AchievementNotification.d.ts +28 -0
- package/dist/AchievementNotification.d.ts.map +1 -0
- package/dist/AchievementNotification.js +74 -0
- package/dist/AchievementNotification.js.map +1 -0
- package/dist/GameSelector.d.ts +25 -0
- package/dist/GameSelector.d.ts.map +1 -0
- package/dist/GameSelector.js +105 -0
- package/dist/GameSelector.js.map +1 -0
- package/dist/HelpOverlay.d.ts +15 -0
- package/dist/HelpOverlay.d.ts.map +1 -0
- package/dist/HelpOverlay.js +134 -0
- package/dist/HelpOverlay.js.map +1 -0
- package/dist/Layout.d.ts +49 -0
- package/dist/Layout.d.ts.map +1 -0
- package/dist/Layout.js +83 -0
- package/dist/Layout.js.map +1 -0
- package/dist/Leaderboard.d.ts +46 -0
- package/dist/Leaderboard.d.ts.map +1 -0
- package/dist/Leaderboard.js +68 -0
- package/dist/Leaderboard.js.map +1 -0
- package/dist/LogViewer.d.ts +33 -0
- package/dist/LogViewer.d.ts.map +1 -0
- package/dist/LogViewer.js +179 -0
- package/dist/LogViewer.js.map +1 -0
- package/dist/LoopAlertOverlay.d.ts +15 -0
- package/dist/LoopAlertOverlay.d.ts.map +1 -0
- package/dist/LoopAlertOverlay.js +17 -0
- package/dist/LoopAlertOverlay.js.map +1 -0
- package/dist/LoopManagementPanel.d.ts +44 -0
- package/dist/LoopManagementPanel.d.ts.map +1 -0
- package/dist/LoopManagementPanel.js +220 -0
- package/dist/LoopManagementPanel.js.map +1 -0
- package/dist/SettingsMenu.d.ts +22 -0
- package/dist/SettingsMenu.d.ts.map +1 -0
- package/dist/SettingsMenu.js +367 -0
- package/dist/SettingsMenu.js.map +1 -0
- package/dist/SplitPane.d.ts +63 -0
- package/dist/SplitPane.d.ts.map +1 -0
- package/dist/SplitPane.js +104 -0
- package/dist/SplitPane.js.map +1 -0
- package/dist/StatsMenu.d.ts +15 -0
- package/dist/StatsMenu.d.ts.map +1 -0
- package/dist/StatsMenu.js +230 -0
- package/dist/StatsMenu.js.map +1 -0
- package/dist/StatusBar.d.ts +58 -0
- package/dist/StatusBar.d.ts.map +1 -0
- package/dist/StatusBar.js +106 -0
- package/dist/StatusBar.js.map +1 -0
- package/dist/__tests__/ralph-loop-parser.test.d.ts +2 -0
- package/dist/__tests__/ralph-loop-parser.test.d.ts.map +1 -0
- package/dist/__tests__/ralph-loop-parser.test.js +143 -0
- package/dist/__tests__/ralph-loop-parser.test.js.map +1 -0
- package/dist/claude-code-process.d.ts +76 -0
- package/dist/claude-code-process.d.ts.map +1 -0
- package/dist/claude-code-process.js +221 -0
- package/dist/claude-code-process.js.map +1 -0
- package/dist/cli.d.ts +42 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +265 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +206 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +270 -0
- package/dist/config.js.map +1 -0
- package/dist/game-types.d.ts +177 -0
- package/dist/game-types.d.ts.map +1 -0
- package/dist/game-types.js +55 -0
- package/dist/game-types.js.map +1 -0
- package/dist/games/MinesweeperGame.d.ts +15 -0
- package/dist/games/MinesweeperGame.d.ts.map +1 -0
- package/dist/games/MinesweeperGame.js +555 -0
- package/dist/games/MinesweeperGame.js.map +1 -0
- package/dist/games/PongGame.d.ts +15 -0
- package/dist/games/PongGame.d.ts.map +1 -0
- package/dist/games/PongGame.js +379 -0
- package/dist/games/PongGame.js.map +1 -0
- package/dist/games/SnakeGame.d.ts +15 -0
- package/dist/games/SnakeGame.d.ts.map +1 -0
- package/dist/games/SnakeGame.js +333 -0
- package/dist/games/SnakeGame.js.map +1 -0
- package/dist/games/TetrisGame.d.ts +15 -0
- package/dist/games/TetrisGame.d.ts.map +1 -0
- package/dist/games/TetrisGame.js +654 -0
- package/dist/games/TetrisGame.js.map +1 -0
- package/dist/games/index.d.ts +23 -0
- package/dist/games/index.d.ts.map +1 -0
- package/dist/games/index.js +47 -0
- package/dist/games/index.js.map +1 -0
- package/dist/high-scores.d.ts +57 -0
- package/dist/high-scores.d.ts.map +1 -0
- package/dist/high-scores.js +230 -0
- package/dist/high-scores.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +264 -0
- package/dist/index.js.map +1 -0
- package/dist/ralph-loop-parser.d.ts +58 -0
- package/dist/ralph-loop-parser.d.ts.map +1 -0
- package/dist/ralph-loop-parser.js +315 -0
- package/dist/ralph-loop-parser.js.map +1 -0
- package/dist/stats.d.ts +142 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +521 -0
- package/dist/stats.js.map +1 -0
- package/dist/styled-components.d.ts +231 -0
- package/dist/styled-components.d.ts.map +1 -0
- package/dist/styled-components.js +192 -0
- package/dist/styled-components.js.map +1 -0
- package/dist/theme.d.ts +301 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +372 -0
- package/dist/theme.js.map +1 -0
- package/dist/themes.d.ts +117 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +296 -0
- package/dist/themes.js.map +1 -0
- package/dist/ui/index.d.ts +13 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +29 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/use-claude-code.d.ts +30 -0
- package/dist/use-claude-code.d.ts.map +1 -0
- package/dist/use-claude-code.js +84 -0
- package/dist/use-claude-code.js.map +1 -0
- package/dist/use-config.d.ts +58 -0
- package/dist/use-config.d.ts.map +1 -0
- package/dist/use-config.js +113 -0
- package/dist/use-config.js.map +1 -0
- package/dist/use-game-loop.d.ts +47 -0
- package/dist/use-game-loop.d.ts.map +1 -0
- package/dist/use-game-loop.js +136 -0
- package/dist/use-game-loop.js.map +1 -0
- package/dist/use-high-scores.d.ts +41 -0
- package/dist/use-high-scores.d.ts.map +1 -0
- package/dist/use-high-scores.js +94 -0
- package/dist/use-high-scores.js.map +1 -0
- package/dist/use-layout-state.d.ts +77 -0
- package/dist/use-layout-state.d.ts.map +1 -0
- package/dist/use-layout-state.js +160 -0
- package/dist/use-layout-state.js.map +1 -0
- package/dist/use-ralph-loop.d.ts +41 -0
- package/dist/use-ralph-loop.d.ts.map +1 -0
- package/dist/use-ralph-loop.js +106 -0
- package/dist/use-ralph-loop.js.map +1 -0
- package/dist/use-spinner.d.ts +46 -0
- package/dist/use-spinner.d.ts.map +1 -0
- package/dist/use-spinner.js +71 -0
- package/dist/use-spinner.js.map +1 -0
- package/dist/use-stats.d.ts +59 -0
- package/dist/use-stats.d.ts.map +1 -0
- package/dist/use-stats.js +150 -0
- package/dist/use-stats.js.map +1 -0
- package/dist/use-terminal-size.d.ts +29 -0
- package/dist/use-terminal-size.d.ts.map +1 -0
- package/dist/use-terminal-size.js +48 -0
- package/dist/use-terminal-size.js.map +1 -0
- package/dist/useTheme.d.ts +76 -0
- package/dist/useTheme.d.ts.map +1 -0
- package/dist/useTheme.js +136 -0
- package/dist/useTheme.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Hook for Configuration Management
|
|
3
|
+
*
|
|
4
|
+
* Provides access to the application configuration in React components.
|
|
5
|
+
* Handles async loading with proper state management.
|
|
6
|
+
*/
|
|
7
|
+
import { useState, useEffect, useCallback } from "react";
|
|
8
|
+
import { loadConfig, saveConfig, updateConfig, resetConfig, DEFAULT_CONFIG, getLayoutOptions, getClaudeCodeOptions, getAppSettings, } from "./config.js";
|
|
9
|
+
/**
|
|
10
|
+
* React hook for accessing and managing application configuration.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const { config, isLoading } = useConfig();
|
|
15
|
+
*
|
|
16
|
+
* if (isLoading) return <Text>Loading config...</Text>;
|
|
17
|
+
*
|
|
18
|
+
* return <Text>Split ratio: {config.layout?.splitRatio}</Text>;
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function useConfig() {
|
|
22
|
+
const [config, setConfig] = useState(DEFAULT_CONFIG);
|
|
23
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
24
|
+
const [error, setError] = useState(null);
|
|
25
|
+
const loadConfigFromDisk = useCallback(async () => {
|
|
26
|
+
setIsLoading(true);
|
|
27
|
+
setError(null);
|
|
28
|
+
try {
|
|
29
|
+
const loaded = await loadConfig();
|
|
30
|
+
setConfig(loaded);
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
setError(e instanceof Error ? e : new Error("Failed to load config"));
|
|
34
|
+
// Keep defaults on error
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setIsLoading(false);
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
void loadConfigFromDisk();
|
|
42
|
+
}, [loadConfigFromDisk]);
|
|
43
|
+
const reload = useCallback(async () => {
|
|
44
|
+
await loadConfigFromDisk();
|
|
45
|
+
}, [loadConfigFromDisk]);
|
|
46
|
+
const update = useCallback(async (updates) => {
|
|
47
|
+
try {
|
|
48
|
+
const updated = await updateConfig(updates);
|
|
49
|
+
setConfig(updated);
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
setError(e instanceof Error ? e : new Error("Failed to update config"));
|
|
53
|
+
}
|
|
54
|
+
}, []);
|
|
55
|
+
const reset = useCallback(async () => {
|
|
56
|
+
try {
|
|
57
|
+
await resetConfig();
|
|
58
|
+
setConfig(DEFAULT_CONFIG);
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
setError(e instanceof Error ? e : new Error("Failed to reset config"));
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
const save = useCallback(async (newConfig) => {
|
|
65
|
+
try {
|
|
66
|
+
await saveConfig(newConfig);
|
|
67
|
+
setConfig(newConfig);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
setError(e instanceof Error ? e : new Error("Failed to save config"));
|
|
71
|
+
}
|
|
72
|
+
}, []);
|
|
73
|
+
return {
|
|
74
|
+
config,
|
|
75
|
+
isLoading,
|
|
76
|
+
error,
|
|
77
|
+
reload,
|
|
78
|
+
update,
|
|
79
|
+
reset,
|
|
80
|
+
save,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Hook to get layout options from config, ready for useLayoutState
|
|
85
|
+
*/
|
|
86
|
+
export function useLayoutConfig() {
|
|
87
|
+
const { config, isLoading } = useConfig();
|
|
88
|
+
return {
|
|
89
|
+
options: getLayoutOptions(config),
|
|
90
|
+
isLoading,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Hook to get Claude Code options from config
|
|
95
|
+
*/
|
|
96
|
+
export function useClaudeCodeConfig() {
|
|
97
|
+
const { config, isLoading } = useConfig();
|
|
98
|
+
return {
|
|
99
|
+
options: getClaudeCodeOptions(config),
|
|
100
|
+
isLoading,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Hook to get app settings from config
|
|
105
|
+
*/
|
|
106
|
+
export function useAppSettings() {
|
|
107
|
+
const { config, isLoading } = useConfig();
|
|
108
|
+
return {
|
|
109
|
+
settings: getAppSettings(config),
|
|
110
|
+
isLoading,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=use-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-config.js","sourceRoot":"","sources":["../src/use-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useGameLoop Hook
|
|
3
|
+
*
|
|
4
|
+
* Provides a consistent game loop with configurable FPS.
|
|
5
|
+
* Uses setInterval for smooth 30+ FPS updates in terminal.
|
|
6
|
+
*/
|
|
7
|
+
import type { GameLoopInfo } from "./game-types.js";
|
|
8
|
+
export interface UseGameLoopOptions {
|
|
9
|
+
/** Target frames per second (default: 30) */
|
|
10
|
+
targetFps?: number;
|
|
11
|
+
/** Whether the loop is active (default: true) */
|
|
12
|
+
isActive?: boolean;
|
|
13
|
+
/** Callback called each frame */
|
|
14
|
+
onTick?: (info: GameLoopInfo) => void;
|
|
15
|
+
}
|
|
16
|
+
export interface UseGameLoopResult {
|
|
17
|
+
/** Current loop info */
|
|
18
|
+
loopInfo: GameLoopInfo;
|
|
19
|
+
/** Whether the loop is currently running */
|
|
20
|
+
isRunning: boolean;
|
|
21
|
+
/** Start the game loop */
|
|
22
|
+
start: () => void;
|
|
23
|
+
/** Stop the game loop */
|
|
24
|
+
stop: () => void;
|
|
25
|
+
/** Toggle the game loop */
|
|
26
|
+
toggle: () => void;
|
|
27
|
+
/** Reset the timer */
|
|
28
|
+
reset: () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Game loop hook that provides smooth frame-based updates
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* const { loopInfo, isRunning } = useGameLoop({
|
|
36
|
+
* targetFps: 30,
|
|
37
|
+
* isActive: gameState.status === 'playing',
|
|
38
|
+
* onTick: (info) => {
|
|
39
|
+
* // Update game state based on deltaTime
|
|
40
|
+
* updateGame(info.deltaTime);
|
|
41
|
+
* }
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function useGameLoop({ targetFps, isActive, onTick, }?: UseGameLoopOptions): UseGameLoopResult;
|
|
46
|
+
export default useGameLoop;
|
|
47
|
+
//# sourceMappingURL=use-game-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-game-loop.d.ts","sourceRoot":"","sources":["../src/use-game-loop.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iCAAiC;IACjC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,4CAA4C;IAC5C,SAAS,EAAE,OAAO,CAAC;IACnB,0BAA0B;IAC1B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,yBAAyB;IACzB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,sBAAsB;IACtB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAC1B,SAAc,EACd,QAAe,EACf,MAAM,GACP,GAAE,kBAAuB,GAAG,iBAAiB,CAgI7C;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useGameLoop Hook
|
|
3
|
+
*
|
|
4
|
+
* Provides a consistent game loop with configurable FPS.
|
|
5
|
+
* Uses setInterval for smooth 30+ FPS updates in terminal.
|
|
6
|
+
*/
|
|
7
|
+
import { useRef, useEffect, useCallback, useState } from "react";
|
|
8
|
+
/**
|
|
9
|
+
* Game loop hook that provides smooth frame-based updates
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const { loopInfo, isRunning } = useGameLoop({
|
|
14
|
+
* targetFps: 30,
|
|
15
|
+
* isActive: gameState.status === 'playing',
|
|
16
|
+
* onTick: (info) => {
|
|
17
|
+
* // Update game state based on deltaTime
|
|
18
|
+
* updateGame(info.deltaTime);
|
|
19
|
+
* }
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function useGameLoop({ targetFps = 30, isActive = true, onTick, } = {}) {
|
|
24
|
+
const [isRunning, setIsRunning] = useState(isActive);
|
|
25
|
+
const [loopInfo, setLoopInfo] = useState({
|
|
26
|
+
fps: 0,
|
|
27
|
+
deltaTime: 0,
|
|
28
|
+
elapsedTime: 0,
|
|
29
|
+
frameCount: 0,
|
|
30
|
+
});
|
|
31
|
+
// Refs for timing
|
|
32
|
+
const intervalRef = useRef(null);
|
|
33
|
+
const startTimeRef = useRef(0);
|
|
34
|
+
const lastFrameTimeRef = useRef(0);
|
|
35
|
+
const frameCountRef = useRef(0);
|
|
36
|
+
const fpsAccumulatorRef = useRef([]);
|
|
37
|
+
// Store onTick in ref to avoid re-creating interval
|
|
38
|
+
const onTickRef = useRef(onTick);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
onTickRef.current = onTick;
|
|
41
|
+
}, [onTick]);
|
|
42
|
+
// Calculate frame interval in ms
|
|
43
|
+
const frameInterval = Math.floor(1000 / targetFps);
|
|
44
|
+
const tick = useCallback(() => {
|
|
45
|
+
const now = performance.now();
|
|
46
|
+
// Initialize start time on first tick
|
|
47
|
+
if (startTimeRef.current === 0) {
|
|
48
|
+
startTimeRef.current = now;
|
|
49
|
+
lastFrameTimeRef.current = now;
|
|
50
|
+
}
|
|
51
|
+
const deltaTime = now - lastFrameTimeRef.current;
|
|
52
|
+
const elapsedTime = now - startTimeRef.current;
|
|
53
|
+
lastFrameTimeRef.current = now;
|
|
54
|
+
frameCountRef.current += 1;
|
|
55
|
+
// Calculate rolling FPS average (last 10 frames)
|
|
56
|
+
const instantFps = deltaTime > 0 ? 1000 / deltaTime : targetFps;
|
|
57
|
+
fpsAccumulatorRef.current.push(instantFps);
|
|
58
|
+
if (fpsAccumulatorRef.current.length > 10) {
|
|
59
|
+
fpsAccumulatorRef.current.shift();
|
|
60
|
+
}
|
|
61
|
+
const fps = Math.round(fpsAccumulatorRef.current.reduce((a, b) => a + b, 0) /
|
|
62
|
+
fpsAccumulatorRef.current.length);
|
|
63
|
+
const info = {
|
|
64
|
+
fps,
|
|
65
|
+
deltaTime,
|
|
66
|
+
elapsedTime,
|
|
67
|
+
frameCount: frameCountRef.current,
|
|
68
|
+
};
|
|
69
|
+
setLoopInfo(info);
|
|
70
|
+
// Call onTick callback
|
|
71
|
+
if (onTickRef.current) {
|
|
72
|
+
onTickRef.current(info);
|
|
73
|
+
}
|
|
74
|
+
}, [targetFps]);
|
|
75
|
+
const start = useCallback(() => {
|
|
76
|
+
if (intervalRef.current)
|
|
77
|
+
return;
|
|
78
|
+
setIsRunning(true);
|
|
79
|
+
intervalRef.current = setInterval(tick, frameInterval);
|
|
80
|
+
}, [tick, frameInterval]);
|
|
81
|
+
const stop = useCallback(() => {
|
|
82
|
+
if (intervalRef.current) {
|
|
83
|
+
clearInterval(intervalRef.current);
|
|
84
|
+
intervalRef.current = null;
|
|
85
|
+
}
|
|
86
|
+
setIsRunning(false);
|
|
87
|
+
}, []);
|
|
88
|
+
const toggle = useCallback(() => {
|
|
89
|
+
if (isRunning) {
|
|
90
|
+
stop();
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
start();
|
|
94
|
+
}
|
|
95
|
+
}, [isRunning, start, stop]);
|
|
96
|
+
const reset = useCallback(() => {
|
|
97
|
+
startTimeRef.current = 0;
|
|
98
|
+
lastFrameTimeRef.current = 0;
|
|
99
|
+
frameCountRef.current = 0;
|
|
100
|
+
fpsAccumulatorRef.current = [];
|
|
101
|
+
setLoopInfo({
|
|
102
|
+
fps: 0,
|
|
103
|
+
deltaTime: 0,
|
|
104
|
+
elapsedTime: 0,
|
|
105
|
+
frameCount: 0,
|
|
106
|
+
});
|
|
107
|
+
}, []);
|
|
108
|
+
// Start/stop based on isActive prop
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (isActive && !intervalRef.current) {
|
|
111
|
+
start();
|
|
112
|
+
}
|
|
113
|
+
else if (!isActive && intervalRef.current) {
|
|
114
|
+
stop();
|
|
115
|
+
}
|
|
116
|
+
}, [isActive, start, stop]);
|
|
117
|
+
// Cleanup on unmount
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
return () => {
|
|
120
|
+
if (intervalRef.current) {
|
|
121
|
+
clearInterval(intervalRef.current);
|
|
122
|
+
intervalRef.current = null;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}, []);
|
|
126
|
+
return {
|
|
127
|
+
loopInfo,
|
|
128
|
+
isRunning,
|
|
129
|
+
start,
|
|
130
|
+
stop,
|
|
131
|
+
toggle,
|
|
132
|
+
reset,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
export default useGameLoop;
|
|
136
|
+
//# sourceMappingURL=use-game-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-game-loop.js","sourceRoot":"","sources":["../src/use-game-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Hook for High Score Management
|
|
3
|
+
*
|
|
4
|
+
* Provides a React-friendly interface to the high score persistence system.
|
|
5
|
+
*/
|
|
6
|
+
import { type ScoreEntry } from "./high-scores.js";
|
|
7
|
+
/** Hook return type for regular score games (higher is better) */
|
|
8
|
+
export interface UseHighScoresResult {
|
|
9
|
+
/** The current high score */
|
|
10
|
+
highScore: number;
|
|
11
|
+
/** The full leaderboard */
|
|
12
|
+
leaderboard: ScoreEntry[];
|
|
13
|
+
/** Whether the leaderboard is loading */
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
/** Submit a new score - returns position (1-10) or 0 if not on leaderboard */
|
|
16
|
+
submitScore: (score: number, metadata?: Record<string, string | number>) => Promise<number>;
|
|
17
|
+
/** Refresh the leaderboard from disk */
|
|
18
|
+
refresh: () => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/** Hook return type for time-based games (lower is better) */
|
|
21
|
+
export interface UseBestTimesResult {
|
|
22
|
+
/** The current best time */
|
|
23
|
+
bestTime: number;
|
|
24
|
+
/** The full leaderboard */
|
|
25
|
+
leaderboard: ScoreEntry[];
|
|
26
|
+
/** Whether the leaderboard is loading */
|
|
27
|
+
isLoading: boolean;
|
|
28
|
+
/** Submit a new time - returns position (1-10) or 0 if not on leaderboard */
|
|
29
|
+
submitTime: (timeSeconds: number, metadata?: Record<string, string | number>) => Promise<number>;
|
|
30
|
+
/** Refresh the leaderboard from disk */
|
|
31
|
+
refresh: () => Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Hook for games where higher scores are better (Snake, Tetris)
|
|
35
|
+
*/
|
|
36
|
+
export declare function useHighScores(gameId: string): UseHighScoresResult;
|
|
37
|
+
/**
|
|
38
|
+
* Hook for games where lower times are better (Minesweeper)
|
|
39
|
+
*/
|
|
40
|
+
export declare function useBestTimes(gameId: string): UseBestTimesResult;
|
|
41
|
+
//# sourceMappingURL=use-high-scores.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-high-scores.d.ts","sourceRoot":"","sources":["../src/use-high-scores.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAC;AAE1B,kEAAkE;AAClE,MAAM,WAAW,mBAAmB;IAClC,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,WAAW,EAAE,CACX,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACvC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,wCAAwC;IACxC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,UAAU,EAAE,CACV,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACvC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,wCAAwC;IACxC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAkDjE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAkD/D"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Hook for High Score Management
|
|
3
|
+
*
|
|
4
|
+
* Provides a React-friendly interface to the high score persistence system.
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useEffect, useCallback } from "react";
|
|
7
|
+
import { getLeaderboard, getHighScore, submitScore, submitBestTime, getBestTime, } from "./high-scores.js";
|
|
8
|
+
/**
|
|
9
|
+
* Hook for games where higher scores are better (Snake, Tetris)
|
|
10
|
+
*/
|
|
11
|
+
export function useHighScores(gameId) {
|
|
12
|
+
const [highScore, setHighScore] = useState(0);
|
|
13
|
+
const [leaderboard, setLeaderboard] = useState([]);
|
|
14
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
15
|
+
// Load initial data
|
|
16
|
+
const loadData = useCallback(async () => {
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
try {
|
|
19
|
+
const [score, board] = await Promise.all([
|
|
20
|
+
getHighScore(gameId),
|
|
21
|
+
getLeaderboard(gameId),
|
|
22
|
+
]);
|
|
23
|
+
setHighScore(score);
|
|
24
|
+
setLeaderboard(board.scores);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Silently fail - use defaults
|
|
28
|
+
}
|
|
29
|
+
setIsLoading(false);
|
|
30
|
+
}, [gameId]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
loadData();
|
|
33
|
+
}, [loadData]);
|
|
34
|
+
// Submit a score
|
|
35
|
+
const handleSubmitScore = useCallback(async (score, metadata) => {
|
|
36
|
+
const position = await submitScore(gameId, score, metadata);
|
|
37
|
+
// Refresh data after submission
|
|
38
|
+
if (position > 0) {
|
|
39
|
+
await loadData();
|
|
40
|
+
}
|
|
41
|
+
return position;
|
|
42
|
+
}, [gameId, loadData]);
|
|
43
|
+
return {
|
|
44
|
+
highScore,
|
|
45
|
+
leaderboard,
|
|
46
|
+
isLoading,
|
|
47
|
+
submitScore: handleSubmitScore,
|
|
48
|
+
refresh: loadData,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Hook for games where lower times are better (Minesweeper)
|
|
53
|
+
*/
|
|
54
|
+
export function useBestTimes(gameId) {
|
|
55
|
+
const [bestTime, setBestTime] = useState(999);
|
|
56
|
+
const [leaderboard, setLeaderboard] = useState([]);
|
|
57
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
58
|
+
// Load initial data
|
|
59
|
+
const loadData = useCallback(async () => {
|
|
60
|
+
setIsLoading(true);
|
|
61
|
+
try {
|
|
62
|
+
const [time, board] = await Promise.all([
|
|
63
|
+
getBestTime(gameId),
|
|
64
|
+
getLeaderboard(gameId),
|
|
65
|
+
]);
|
|
66
|
+
setBestTime(time);
|
|
67
|
+
setLeaderboard(board.scores);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Silently fail - use defaults
|
|
71
|
+
}
|
|
72
|
+
setIsLoading(false);
|
|
73
|
+
}, [gameId]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
loadData();
|
|
76
|
+
}, [loadData]);
|
|
77
|
+
// Submit a time
|
|
78
|
+
const handleSubmitTime = useCallback(async (timeSeconds, metadata) => {
|
|
79
|
+
const position = await submitBestTime(gameId, timeSeconds, metadata);
|
|
80
|
+
// Refresh data after submission
|
|
81
|
+
if (position > 0) {
|
|
82
|
+
await loadData();
|
|
83
|
+
}
|
|
84
|
+
return position;
|
|
85
|
+
}, [gameId, loadData]);
|
|
86
|
+
return {
|
|
87
|
+
bestTime,
|
|
88
|
+
leaderboard,
|
|
89
|
+
isLoading,
|
|
90
|
+
submitTime: handleSubmitTime,
|
|
91
|
+
refresh: loadData,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=use-high-scores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-high-scores.js","sourceRoot":"","sources":["../src/use-high-scores.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for managing and persisting layout state during a session.
|
|
3
|
+
* Handles split ratios, pane visibility, and layout preferences.
|
|
4
|
+
*/
|
|
5
|
+
export type SplitDirection = "horizontal" | "vertical";
|
|
6
|
+
export interface LayoutState {
|
|
7
|
+
/** Split direction: horizontal = left/right, vertical = top/bottom */
|
|
8
|
+
direction: SplitDirection;
|
|
9
|
+
/** Split ratio (0.0 - 1.0) - proportion of first pane */
|
|
10
|
+
splitRatio: number;
|
|
11
|
+
/** Whether the split is currently being resized */
|
|
12
|
+
isResizing: boolean;
|
|
13
|
+
/** Whether to show the secondary pane */
|
|
14
|
+
showSecondary: boolean;
|
|
15
|
+
/** Which pane is focused (0 = first/game, 1 = second/management) */
|
|
16
|
+
focusedPane: 0 | 1;
|
|
17
|
+
}
|
|
18
|
+
export interface UseLayoutStateOptions {
|
|
19
|
+
/** Initial split direction */
|
|
20
|
+
initialDirection?: SplitDirection;
|
|
21
|
+
/** Initial split ratio (0.0 - 1.0) */
|
|
22
|
+
initialSplitRatio?: number;
|
|
23
|
+
/** Minimum split ratio allowed */
|
|
24
|
+
minRatio?: number;
|
|
25
|
+
/** Maximum split ratio allowed */
|
|
26
|
+
maxRatio?: number;
|
|
27
|
+
/** Step size for keyboard-based resizing */
|
|
28
|
+
resizeStep?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface UseLayoutStateResult {
|
|
31
|
+
/** Current layout state */
|
|
32
|
+
state: LayoutState;
|
|
33
|
+
/** Set the split ratio */
|
|
34
|
+
setSplitRatio: (ratio: number) => void;
|
|
35
|
+
/** Adjust split ratio by a delta */
|
|
36
|
+
adjustSplitRatio: (delta: number) => void;
|
|
37
|
+
/** Increase the ratio (make first pane larger) */
|
|
38
|
+
increaseRatio: () => void;
|
|
39
|
+
/** Decrease the ratio (make first pane smaller) */
|
|
40
|
+
decreaseRatio: () => void;
|
|
41
|
+
/** Toggle split direction */
|
|
42
|
+
toggleDirection: () => void;
|
|
43
|
+
/** Set split direction */
|
|
44
|
+
setDirection: (direction: SplitDirection) => void;
|
|
45
|
+
/** Toggle secondary pane visibility */
|
|
46
|
+
toggleSecondary: () => void;
|
|
47
|
+
/** Set secondary pane visibility */
|
|
48
|
+
setShowSecondary: (show: boolean) => void;
|
|
49
|
+
/** Set resizing state */
|
|
50
|
+
setResizing: (isResizing: boolean) => void;
|
|
51
|
+
/** Focus a specific pane */
|
|
52
|
+
focusPane: (pane: 0 | 1) => void;
|
|
53
|
+
/** Toggle focus between panes */
|
|
54
|
+
toggleFocus: () => void;
|
|
55
|
+
/** Reset to default layout */
|
|
56
|
+
resetLayout: () => void;
|
|
57
|
+
/** Calculate pixel dimensions based on available space */
|
|
58
|
+
calculateDimensions: (availableWidth: number, availableHeight: number) => PaneDimensions;
|
|
59
|
+
}
|
|
60
|
+
export interface PaneDimensions {
|
|
61
|
+
firstPane: {
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
};
|
|
65
|
+
secondPane: {
|
|
66
|
+
width: number;
|
|
67
|
+
height: number;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* React hook for managing layout state with resizable panes.
|
|
72
|
+
*
|
|
73
|
+
* @param options - Configuration options for the layout
|
|
74
|
+
* @returns Layout state and control functions
|
|
75
|
+
*/
|
|
76
|
+
export declare function useLayoutState(options?: UseLayoutStateOptions): UseLayoutStateResult;
|
|
77
|
+
//# sourceMappingURL=use-layout-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-layout-state.d.ts","sourceRoot":"","sources":["../src/use-layout-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,UAAU,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,SAAS,EAAE,cAAc,CAAC;IAC1B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,UAAU,EAAE,OAAO,CAAC;IACpB,yCAAyC;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,oEAAoE;IACpE,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,8BAA8B;IAC9B,gBAAgB,CAAC,EAAE,cAAc,CAAC;IAClC,sCAAsC;IACtC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,2BAA2B;IAC3B,KAAK,EAAE,WAAW,CAAC;IACnB,0BAA0B;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,oCAAoC;IACpC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,kDAAkD;IAClD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,mDAAmD;IACnD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,6BAA6B;IAC7B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,0BAA0B;IAC1B,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;IAClD,uCAAuC;IACvC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,oCAAoC;IACpC,gBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,yBAAyB;IACzB,WAAW,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,4BAA4B;IAC5B,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IACjC,iCAAiC;IACjC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,8BAA8B;IAC9B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,0DAA0D;IAC1D,mBAAmB,EAAE,CACnB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,KACpB,cAAc,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAUD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,OAAO,GAAE,qBAA0B,GAClC,oBAAoB,CA6KtB"}
|