Add new brain game: Bullet Math#113
Conversation
|
@aleenaharoldpeter is attempting to deploy a commit to the ajaynegi45's projects Team on Vercel. A member of the Team first needs to authorize it. |
Summary by CodeRabbit
WalkthroughAdds a new Bullet Math game page with React logic, timer, scoring, and hints; introduces a corresponding CSS module for styling; and updates the game selection page to include a Bullet Math card linking to the new route. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant P as BulletMath Page
participant T as Timer
participant R as Router
U->>P: Choose difficulty
U->>P: Click Start
activate P
P->>P: generateEquation()
P->>T: start(120s)
Note over P,T: Countdown running
loop Each answer
U->>P: Submit answer (Enter/Click)
P->>P: compute() and validate
alt correct
P->>P: update score/attempts
P->>P: generateEquation()
else incorrect
P->>P: mark input invalid
end
end
T-->>P: timeUp()
deactivate P
P->>U: Show overlay (final score)
alt Play Again
U->>P: Click Play Again
P->>P: reset state
P->>P: generateEquation()
P->>T: start(120s)
else Home
U->>P: Click Home
P->>R: push("/game")
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
|
👋 Hello @aleenaharoldpeter! Thanks for contributing to Old-School-Game – a curated collection of classic, brain-training games that boost memory, focus, creativity, and long-term brain health 🎯🧠. In today's world full of short-form distractions, this project helps rebuild deep focus and mental endurance through thoughtful gameplay. ✅ Important Things To Do:
✅ Your pull request has been submitted successfully, and a maintainer will review it soon. |
There was a problem hiding this comment.
Actionable comments posted: 7
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
public/BulletMath.pngis excluded by!**/*.png
📒 Files selected for processing (3)
src/app/game/bullet-math/page.module.css(1 hunks)src/app/game/bullet-math/page.tsx(1 hunks)src/app/game/page.tsx(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/game/bullet-math/page.tsx (1)
src/app/game/schulte-table/page.tsx (2)
numbers(14-185)num(75-95)
🪛 Biome (2.1.2)
src/app/game/bullet-math/page.tsx
[error] 17-17: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
🔇 Additional comments (2)
src/app/game/page.tsx (1)
49-55: LGTM: New “Bullet Math” card is wired correctly.Import, name, link, and colors look consistent with the other cards. Nice!
src/app/game/bullet-math/page.tsx (1)
50-58: Align Amateur mode with single-digit results and non-negative subtraction
Tighten all operand ranges to 1–9 (including addition), and for subtraction ensurea >= bso results stay non-negative. Confirm whether Amateur should ever allow negative answers.
| .btn { | ||
| padding: 12px 20px; | ||
| border: none; | ||
| border-radius: 10px; | ||
| cursor: pointer; | ||
| font-weight: 700; | ||
| font-size: 18px; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add a .startBtn style or remove its usage to avoid “undefined” class names.
The page uses styles.startBtn for the Start button, but this class isn’t defined here. That renders a literal “undefined” in the className and can confuse styling.
Option A (define the class here):
.btn {
padding: 12px 20px;
border: none;
border-radius: 10px;
cursor: pointer;
font-weight: 700;
font-size: 18px;
}
+/* Start button variant */
+.startBtn {
+ border: 2px solid #2563eb;
+}Option B (if you don’t need a variant), remove styles.startBtn from the TSX (see page.tsx comment).
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.module.css around lines 42 to 49, the TSX
references styles.startBtn but that class is not defined which results in an
"undefined" class name; either add a .startBtn rule here (e.g., copy or adjust
.btn properties to create a startBtn variant) or remove the use of
styles.startBtn from the TSX so only existing classes are applied; implement
whichever option fits the UI: define .startBtn with desired styles or update the
component to use .btn (or another defined class) and remove the undefined
reference.
| .menuButton { | ||
| margin-top: 12px; | ||
| background: linear-gradient(135deg, #3b82f6, #2563eb); | ||
| color: white; | ||
| border: none; | ||
| padding: 12px 24px; | ||
| font-size: 1.1rem; | ||
| font-weight: bold; | ||
| border-radius: 10px; | ||
| cursor: pointer; | ||
| transition: all 0.3s ease; | ||
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); | ||
| } | ||
|
|
||
| .menuButton:hover { | ||
| background: linear-gradient(135deg, #2563eb, #1e40af); | ||
| transform: translateY(-2px); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Give buttons a strong keyboard focus outline.
Right now only hover transitions are defined. Adding focus-visible styles makes the UI friendlier for keyboard users.
.menuButton:hover {
background: linear-gradient(135deg, #2563eb, #1e40af);
transform: translateY(-2px);
}
+
+/* Clear, consistent focus ring for keyboard users */
+.btn:focus-visible,
+.menuButton:focus-visible,
+.resetButton:focus-visible {
+ outline: 3px solid #f59e0b;
+ outline-offset: 2px;
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .menuButton { | |
| margin-top: 12px; | |
| background: linear-gradient(135deg, #3b82f6, #2563eb); | |
| color: white; | |
| border: none; | |
| padding: 12px 24px; | |
| font-size: 1.1rem; | |
| font-weight: bold; | |
| border-radius: 10px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); | |
| } | |
| .menuButton:hover { | |
| background: linear-gradient(135deg, #2563eb, #1e40af); | |
| transform: translateY(-2px); | |
| } | |
| .menuButton { | |
| margin-top: 12px; | |
| background: linear-gradient(135deg, #3b82f6, #2563eb); | |
| color: white; | |
| border: none; | |
| padding: 12px 24px; | |
| font-size: 1.1rem; | |
| font-weight: bold; | |
| border-radius: 10px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); | |
| } | |
| .menuButton:hover { | |
| background: linear-gradient(135deg, #2563eb, #1e40af); | |
| transform: translateY(-2px); | |
| } | |
| /* Clear, consistent focus ring for keyboard users */ | |
| .btn:focus-visible, | |
| .menuButton:focus-visible, | |
| .resetButton:focus-visible { | |
| outline: 3px solid #f59e0b; | |
| outline-offset: 2px; | |
| } |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.module.css around lines 84 to 101, the
.menuButton styles only define hover feedback and lack a strong keyboard focus
outline; add a :focus-visible rule for .menuButton that sets a clear visible
outline (e.g., 2-3px solid contrasting color or use ring-like box-shadow),
include outline-offset for spacing, and keep existing hover/transform
transitions so keyboard users get the same visual affordance as mouse users.
| const OPS: Op[] = ['+', '-', '×', '÷'] | ||
| const timerRef = useRef<ReturnType<typeof setInterval> | null>(null) | ||
|
|
There was a problem hiding this comment.
Move useRef out of module scope — hooks must be inside components.
useRef at the top level violates the Rules of Hooks and also shadows the in-component timerRef. This is likely what Biome flagged.
Apply:
-const timerRef = useRef<ReturnType<typeof setInterval> | null>(null)The in-component timerRef (Line 127) is correct; keep that one.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const OPS: Op[] = ['+', '-', '×', '÷'] | |
| const timerRef = useRef<ReturnType<typeof setInterval> | null>(null) | |
| const OPS: Op[] = ['+', '-', '×', '÷'] |
🧰 Tools
🪛 Biome (2.1.2)
[error] 17-17: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 16-18 there is a top-level
useRef declaration "const timerRef = useRef..." which violates the Rules of
Hooks and shadows the correct in-component timerRef at line 127; remove this
module-scope useRef entirely and rely on the existing in-component timerRef
(line 127), so hooks remain inside the component and no name shadowing occurs.
| {equation.a} {equation.op} {equation.b} ={' '} | ||
| <input | ||
| type="text" | ||
| value={userAnswer} | ||
| onChange={(e) => setUserAnswer(e.target.value)} | ||
| onKeyDown={(e) => { if (e.key === 'Enter') onSubmitAnswer() }} | ||
| className={`${styles.input} ${isWrong ? styles.wrong : ''}`} | ||
| aria-label="Your answer" | ||
| placeholder="?" | ||
| /> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Autofocus the answer input to speed play.
Small UX boost: place the cursor in the input when a question is shown.
<input
type="text"
value={userAnswer}
onChange={(e) => setUserAnswer(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter') onSubmitAnswer() }}
className={`${styles.input} ${isWrong ? styles.wrong : ''}`}
aria-label="Your answer"
placeholder="?"
+ autoFocus
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {equation.a} {equation.op} {equation.b} ={' '} | |
| <input | |
| type="text" | |
| value={userAnswer} | |
| onChange={(e) => setUserAnswer(e.target.value)} | |
| onKeyDown={(e) => { if (e.key === 'Enter') onSubmitAnswer() }} | |
| className={`${styles.input} ${isWrong ? styles.wrong : ''}`} | |
| aria-label="Your answer" | |
| placeholder="?" | |
| /> | |
| {equation.a} {equation.op} {equation.b} ={' '} | |
| <input | |
| type="text" | |
| value={userAnswer} | |
| onChange={(e) => setUserAnswer(e.target.value)} | |
| onKeyDown={(e) => { if (e.key === 'Enter') onSubmitAnswer() }} | |
| className={`${styles.input} ${isWrong ? styles.wrong : ''}`} | |
| aria-label="Your answer" | |
| placeholder="?" | |
| autoFocus | |
| /> |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 226-235, the answer input
should receive focus when a new question is shown; add a ref (useRef) to the
input and call ref.current?.focus() in a useEffect that runs when the equation
(or question index) changes (or simply add the autoFocus prop if this is purely
client-side and no server-rendering issues), ensuring the component is a client
component (add "use client" at top if needed) so focusing works correctly.
| <button type="button" className={`${styles.btn} ${styles.neutral} ${styles.startBtn}`} onClick={startGame}> | ||
| Press Start | ||
| </button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Start button references an undefined CSS class.
styles.startBtn doesn’t exist in the CSS module. Either add it (see CSS comment) or remove it here to avoid a literal “undefined” in className.
- <button type="button" className={`${styles.btn} ${styles.neutral} ${styles.startBtn}`} onClick={startGame}>
+ <button type="button" className={`${styles.btn} ${styles.neutral}`} onClick={startGame}>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button type="button" className={`${styles.btn} ${styles.neutral} ${styles.startBtn}`} onClick={startGame}> | |
| Press Start | |
| </button> | |
| <button type="button" className={`${styles.btn} ${styles.neutral}`} onClick={startGame}> | |
| Press Start | |
| </button> |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 239 to 241, the button
references a non-existent CSS module property styles.startBtn which results in
"undefined" being injected into the className; fix by either adding a startBtn
selector to the corresponding CSS module with the intended styles (e.g., copy
the commented suggestion or desired rules into the CSS file and export it) or
remove styles.startBtn from the className array and adjust layout/style using
the existing classes (styles.btn and styles.neutral) so no undefined value is
included.
| {gameOver && ( | ||
| <div className={styles.overlay} role="dialog" aria-modal="true" aria-labelledby="times-up-heading"> | ||
| <div className={styles.completionMessage}> | ||
| <h2 id="times-up-heading">🎉 Time’s Up!</h2> | ||
| <div className={styles.finalStats}> | ||
| <p>⭐ Score: {score}</p> | ||
| <p>📊 Questions Attempted: {attempted}</p> | ||
| </div> | ||
| <button type="button" className={styles.resetButton} onClick={startGame}> | ||
| 🔄 Play Again | ||
| </button> | ||
| <button type="button" className={styles.menuButton} onClick={() => router.push('/')}> | ||
| 🏠 Back to Homepage | ||
| </button> | ||
| </div> | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Set initial focus in the game-over dialog.
Helps keyboard users; focus the primary action when the modal opens.
- <button type="button" className={styles.resetButton} onClick={startGame}>
+ <button type="button" className={styles.resetButton} onClick={startGame} autoFocus>
🔄 Play Again
</button>Optional: we can also trap focus within the dialog; happy to add that if you’d like.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {gameOver && ( | |
| <div className={styles.overlay} role="dialog" aria-modal="true" aria-labelledby="times-up-heading"> | |
| <div className={styles.completionMessage}> | |
| <h2 id="times-up-heading">🎉 Time’s Up!</h2> | |
| <div className={styles.finalStats}> | |
| <p>⭐ Score: {score}</p> | |
| <p>📊 Questions Attempted: {attempted}</p> | |
| </div> | |
| <button type="button" className={styles.resetButton} onClick={startGame}> | |
| 🔄 Play Again | |
| </button> | |
| <button type="button" className={styles.menuButton} onClick={() => router.push('/')}> | |
| 🏠 Back to Homepage | |
| </button> | |
| </div> | |
| </div> | |
| )} | |
| {gameOver && ( | |
| <div className={styles.overlay} role="dialog" aria-modal="true" aria-labelledby="times-up-heading"> | |
| <div className={styles.completionMessage}> | |
| <h2 id="times-up-heading">🎉 Time’s Up!</h2> | |
| <div className={styles.finalStats}> | |
| <p>⭐ Score: {score}</p> | |
| <p>📊 Questions Attempted: {attempted}</p> | |
| </div> | |
| <button | |
| type="button" | |
| className={styles.resetButton} | |
| onClick={startGame} | |
| autoFocus | |
| > | |
| 🔄 Play Again | |
| </button> | |
| <button | |
| type="button" | |
| className={styles.menuButton} | |
| onClick={() => router.push('/')} | |
| > | |
| 🏠 Back to Homepage | |
| </button> | |
| </div> | |
| </div> | |
| )} |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 253 to 269, the game-over
modal opens without moving keyboard focus to the primary action; add a ref to
the "Play Again" button and use a useEffect that watches gameOver to call
focus() when the dialog becomes visible (ensure the button is focusable), and
add appropriate aria attributes (role="dialog" and aria-modal already present)
so keyboard users land on the Play Again control when the modal opens;
optionally later implement a focus trap for full modal keyboard containment.
| <Card | ||
| image={BulletMath} | ||
| name={'Bullet Math'} | ||
| link={'bullet-math'} | ||
| backgroundColor={'#F59E0B'} | ||
| textColor={'white'} | ||
| /> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Trim stray non-breaking spaces/trailing spaces in the closing tag.
Keeps diffs clean and avoids odd whitespace.
<Card
image={BulletMath}
name={'Bullet Math'}
link={'bullet-math'}
backgroundColor={'#F59E0B'}
textColor={'white'}
- />
+ />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Card | |
| image={BulletMath} | |
| name={'Bullet Math'} | |
| link={'bullet-math'} | |
| backgroundColor={'#F59E0B'} | |
| textColor={'white'} | |
| /> | |
| <Card | |
| image={BulletMath} | |
| name={'Bullet Math'} | |
| link={'bullet-math'} | |
| backgroundColor={'#F59E0B'} | |
| textColor={'white'} | |
| /> |
🤖 Prompt for AI Agents
In src/app/game/page.tsx around lines 49 to 55, the Card component's closing tag
contains stray non-breaking space or trailing spaces; remove any trailing
whitespace or NBSP characters immediately before the closing "/>" so the tag is
clean, save the file, and run a quick git diff or linter to confirm the
extraneous whitespace is gone.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|

🧮 New Game: Bullet Math
This PR adds a new brain game Bullet Math under
src/app/game/bullet-math/.✨ Features
🛠️ Fixes/Changes
src/app/game/page.tsxto include the newBullet Mathentry in the game selection.src/app/game/bullet-math/containing:page.tsx→ Game logicpage.module.css→ Stylingany, usedReturnType<typeof setInterval>).aria-labelto inputtype="button"on buttonsrole="dialog"witharia-labelledby✅ Checklist
🙏 Acknowledgements
no-explicit-anyESLint error)..input,.menuButton).This PR introduces a fresh math challenge game to the project. 🚀