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.
Files changed (162) hide show
  1. package/README.md +372 -0
  2. package/dist/AchievementNotification.d.ts +28 -0
  3. package/dist/AchievementNotification.d.ts.map +1 -0
  4. package/dist/AchievementNotification.js +74 -0
  5. package/dist/AchievementNotification.js.map +1 -0
  6. package/dist/GameSelector.d.ts +25 -0
  7. package/dist/GameSelector.d.ts.map +1 -0
  8. package/dist/GameSelector.js +105 -0
  9. package/dist/GameSelector.js.map +1 -0
  10. package/dist/HelpOverlay.d.ts +15 -0
  11. package/dist/HelpOverlay.d.ts.map +1 -0
  12. package/dist/HelpOverlay.js +134 -0
  13. package/dist/HelpOverlay.js.map +1 -0
  14. package/dist/Layout.d.ts +49 -0
  15. package/dist/Layout.d.ts.map +1 -0
  16. package/dist/Layout.js +83 -0
  17. package/dist/Layout.js.map +1 -0
  18. package/dist/Leaderboard.d.ts +46 -0
  19. package/dist/Leaderboard.d.ts.map +1 -0
  20. package/dist/Leaderboard.js +68 -0
  21. package/dist/Leaderboard.js.map +1 -0
  22. package/dist/LogViewer.d.ts +33 -0
  23. package/dist/LogViewer.d.ts.map +1 -0
  24. package/dist/LogViewer.js +179 -0
  25. package/dist/LogViewer.js.map +1 -0
  26. package/dist/LoopAlertOverlay.d.ts +15 -0
  27. package/dist/LoopAlertOverlay.d.ts.map +1 -0
  28. package/dist/LoopAlertOverlay.js +17 -0
  29. package/dist/LoopAlertOverlay.js.map +1 -0
  30. package/dist/LoopManagementPanel.d.ts +44 -0
  31. package/dist/LoopManagementPanel.d.ts.map +1 -0
  32. package/dist/LoopManagementPanel.js +220 -0
  33. package/dist/LoopManagementPanel.js.map +1 -0
  34. package/dist/SettingsMenu.d.ts +22 -0
  35. package/dist/SettingsMenu.d.ts.map +1 -0
  36. package/dist/SettingsMenu.js +367 -0
  37. package/dist/SettingsMenu.js.map +1 -0
  38. package/dist/SplitPane.d.ts +63 -0
  39. package/dist/SplitPane.d.ts.map +1 -0
  40. package/dist/SplitPane.js +104 -0
  41. package/dist/SplitPane.js.map +1 -0
  42. package/dist/StatsMenu.d.ts +15 -0
  43. package/dist/StatsMenu.d.ts.map +1 -0
  44. package/dist/StatsMenu.js +230 -0
  45. package/dist/StatsMenu.js.map +1 -0
  46. package/dist/StatusBar.d.ts +58 -0
  47. package/dist/StatusBar.d.ts.map +1 -0
  48. package/dist/StatusBar.js +106 -0
  49. package/dist/StatusBar.js.map +1 -0
  50. package/dist/__tests__/ralph-loop-parser.test.d.ts +2 -0
  51. package/dist/__tests__/ralph-loop-parser.test.d.ts.map +1 -0
  52. package/dist/__tests__/ralph-loop-parser.test.js +143 -0
  53. package/dist/__tests__/ralph-loop-parser.test.js.map +1 -0
  54. package/dist/claude-code-process.d.ts +76 -0
  55. package/dist/claude-code-process.d.ts.map +1 -0
  56. package/dist/claude-code-process.js +221 -0
  57. package/dist/claude-code-process.js.map +1 -0
  58. package/dist/cli.d.ts +42 -0
  59. package/dist/cli.d.ts.map +1 -0
  60. package/dist/cli.js +265 -0
  61. package/dist/cli.js.map +1 -0
  62. package/dist/config.d.ts +206 -0
  63. package/dist/config.d.ts.map +1 -0
  64. package/dist/config.js +270 -0
  65. package/dist/config.js.map +1 -0
  66. package/dist/game-types.d.ts +177 -0
  67. package/dist/game-types.d.ts.map +1 -0
  68. package/dist/game-types.js +55 -0
  69. package/dist/game-types.js.map +1 -0
  70. package/dist/games/MinesweeperGame.d.ts +15 -0
  71. package/dist/games/MinesweeperGame.d.ts.map +1 -0
  72. package/dist/games/MinesweeperGame.js +555 -0
  73. package/dist/games/MinesweeperGame.js.map +1 -0
  74. package/dist/games/PongGame.d.ts +15 -0
  75. package/dist/games/PongGame.d.ts.map +1 -0
  76. package/dist/games/PongGame.js +379 -0
  77. package/dist/games/PongGame.js.map +1 -0
  78. package/dist/games/SnakeGame.d.ts +15 -0
  79. package/dist/games/SnakeGame.d.ts.map +1 -0
  80. package/dist/games/SnakeGame.js +333 -0
  81. package/dist/games/SnakeGame.js.map +1 -0
  82. package/dist/games/TetrisGame.d.ts +15 -0
  83. package/dist/games/TetrisGame.d.ts.map +1 -0
  84. package/dist/games/TetrisGame.js +654 -0
  85. package/dist/games/TetrisGame.js.map +1 -0
  86. package/dist/games/index.d.ts +23 -0
  87. package/dist/games/index.d.ts.map +1 -0
  88. package/dist/games/index.js +47 -0
  89. package/dist/games/index.js.map +1 -0
  90. package/dist/high-scores.d.ts +57 -0
  91. package/dist/high-scores.d.ts.map +1 -0
  92. package/dist/high-scores.js +230 -0
  93. package/dist/high-scores.js.map +1 -0
  94. package/dist/index.d.ts +3 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +264 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/ralph-loop-parser.d.ts +58 -0
  99. package/dist/ralph-loop-parser.d.ts.map +1 -0
  100. package/dist/ralph-loop-parser.js +315 -0
  101. package/dist/ralph-loop-parser.js.map +1 -0
  102. package/dist/stats.d.ts +142 -0
  103. package/dist/stats.d.ts.map +1 -0
  104. package/dist/stats.js +521 -0
  105. package/dist/stats.js.map +1 -0
  106. package/dist/styled-components.d.ts +231 -0
  107. package/dist/styled-components.d.ts.map +1 -0
  108. package/dist/styled-components.js +192 -0
  109. package/dist/styled-components.js.map +1 -0
  110. package/dist/theme.d.ts +301 -0
  111. package/dist/theme.d.ts.map +1 -0
  112. package/dist/theme.js +372 -0
  113. package/dist/theme.js.map +1 -0
  114. package/dist/themes.d.ts +117 -0
  115. package/dist/themes.d.ts.map +1 -0
  116. package/dist/themes.js +296 -0
  117. package/dist/themes.js.map +1 -0
  118. package/dist/ui/index.d.ts +13 -0
  119. package/dist/ui/index.d.ts.map +1 -0
  120. package/dist/ui/index.js +29 -0
  121. package/dist/ui/index.js.map +1 -0
  122. package/dist/use-claude-code.d.ts +30 -0
  123. package/dist/use-claude-code.d.ts.map +1 -0
  124. package/dist/use-claude-code.js +84 -0
  125. package/dist/use-claude-code.js.map +1 -0
  126. package/dist/use-config.d.ts +58 -0
  127. package/dist/use-config.d.ts.map +1 -0
  128. package/dist/use-config.js +113 -0
  129. package/dist/use-config.js.map +1 -0
  130. package/dist/use-game-loop.d.ts +47 -0
  131. package/dist/use-game-loop.d.ts.map +1 -0
  132. package/dist/use-game-loop.js +136 -0
  133. package/dist/use-game-loop.js.map +1 -0
  134. package/dist/use-high-scores.d.ts +41 -0
  135. package/dist/use-high-scores.d.ts.map +1 -0
  136. package/dist/use-high-scores.js +94 -0
  137. package/dist/use-high-scores.js.map +1 -0
  138. package/dist/use-layout-state.d.ts +77 -0
  139. package/dist/use-layout-state.d.ts.map +1 -0
  140. package/dist/use-layout-state.js +160 -0
  141. package/dist/use-layout-state.js.map +1 -0
  142. package/dist/use-ralph-loop.d.ts +41 -0
  143. package/dist/use-ralph-loop.d.ts.map +1 -0
  144. package/dist/use-ralph-loop.js +106 -0
  145. package/dist/use-ralph-loop.js.map +1 -0
  146. package/dist/use-spinner.d.ts +46 -0
  147. package/dist/use-spinner.d.ts.map +1 -0
  148. package/dist/use-spinner.js +71 -0
  149. package/dist/use-spinner.js.map +1 -0
  150. package/dist/use-stats.d.ts +59 -0
  151. package/dist/use-stats.d.ts.map +1 -0
  152. package/dist/use-stats.js +150 -0
  153. package/dist/use-stats.js.map +1 -0
  154. package/dist/use-terminal-size.d.ts +29 -0
  155. package/dist/use-terminal-size.d.ts.map +1 -0
  156. package/dist/use-terminal-size.js +48 -0
  157. package/dist/use-terminal-size.js.map +1 -0
  158. package/dist/useTheme.d.ts +76 -0
  159. package/dist/useTheme.d.ts.map +1 -0
  160. package/dist/useTheme.js +136 -0
  161. package/dist/useTheme.js.map +1 -0
  162. 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"}