Feature/bullet math#116
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
WalkthroughIntroduces a new Bullet Math game with its UI styles, a client-side React page implementing gameplay, and an added card on the game selection page linking to the new game. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Page as BulletMath Page
participant Gen as Equation Generator
participant Timer
participant Router
User->>Page: Load /game/bullet-math
activate Page
Page->>Gen: generateEquation(difficulty)
Gen-->>Page: equation, answer
Page->>Timer: start(120s)
activate Timer
loop Each second
Timer-->>Page: tick(timeLeft--)
Page-->>User: Update status bar
end
User->>Page: Enter answer + Submit/Enter
Page->>Page: validate & compute score
alt Correct
Page->>Gen: generateEquation(next)
Gen-->>Page: new equation
else Incorrect
Page-->>User: Show .wrong state
end
Timer-->>Page: timeLeft == 0
deactivate Timer
Page-->>User: Show completion overlay
User->>Page: Replay or Home
alt Replay
Page->>Timer: restart
Page->>Gen: new equation
else Home
Page->>Router: push("/game")
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
Poem
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the ✨ 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. Comment |
|
👋 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: 10
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ 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 comments (2)
src/app/game/page.tsx (1)
8-9: LGTM: asset import for Bullet Math is correct.Static import path is fine for Next.js and matches other cards.
src/app/game/bullet-math/page.tsx (1)
194-217: Scoring/attempt logic looks solid.Counting each equation once and advancing only on correct answers matches the spec. Nice job preventing double-counts.
| .input { | ||
| font-size: 28px; | ||
| font-weight: 600; | ||
| text-align: center; | ||
| padding: 10px 16px; | ||
| margin-left: 12px; | ||
| width: 120px; | ||
| border: 2px solid #aaa; | ||
| border-radius: 10px; | ||
| outline: none; | ||
| transition: border-color 0.2s, box-shadow 0.2s, color 0.2s; | ||
| } | ||
|
|
||
| .input:focus { | ||
| border-color: #2563eb; | ||
| box-shadow: 0 0 6px rgba(37, 99, 235, 0.5); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Avoid removing native focus without an accessible replacement.
You style input focus nicely—great. For consistency, add a visible focus style to .input using :focus-visible, like you did for buttons.
Apply:
+.input:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; }Also applies to: 187-187
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.module.css around lines 61 to 77 (also applies
at line 187), the current CSS uses .input:focus which can indiscriminately
remove native focus styles; add a matching .input:focus-visible rule that
provides a clear visible focus indicator for keyboard users (same visual
treatment as :focus but scoped to :focus-visible), ensuring accessible focus
styling is preserved while keeping :focus for other interactions.
| .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)
Respect reduced-motion preferences.
Transitions and hover animations are great, but consider disabling them for users who prefer reduced motion.
Apply:
+@media (prefers-reduced-motion: reduce) {
+ *, *::before, *::after {
+ animation: none !important;
+ transition: none !important;
+ }
+}Also applies to: 127-141
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.module.css around lines 84 to 101 (and also
apply same change to lines 127 to 141), the .menuButton transition and hover
transform ignore users' reduced-motion preference; update the CSS to wrap the
transition and transform rules inside a prefers-reduced-motion: reduce media
query so that when users prefer reduced motion the transition is removed and
hover transform is disabled, while keeping the existing styles for other users.
| if (op === '×' && Math.random() < 0.5) { | ||
| a = randint(6, 12) | ||
| const tens = randint(10, 90) | ||
| const ones = randint(1, 9) | ||
| b = tens + ones | ||
| } else if (op === '×') { | ||
| const three = randint(100, 999) | ||
| const two = randint(10, 25) | ||
| if (Math.random() < 0.5) { a = three; b = two } else { a = two; b = three } |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Tiny naming nit: “tens” variable may confuse future readers.
It isn’t guaranteed to be a multiple of 10. Consider renaming to base or bTens to reduce confusion.
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 71 to 79, the local variable
named "tens" is misleading because it isn’t guaranteed to be a multiple of 10;
rename it to a clearer name such as "base" or "bTens" (e.g., const base =
randint(10, 90)) and update its usage (b = base + ones) and any related comments
to reflect the new name so future readers won’t assume it represents tens only.
| type Difficulty = 'amateur' | 'normal' | 'veteran' | ||
| const [difficulty, setDifficulty] = useState<Difficulty>("amateur") | ||
| const [running, setRunning] = useState(false) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Remove duplicate type alias inside the component.
Difficulty is already defined at the module level. Redeclaring inside the component adds noise without benefit.
Apply:
- type Difficulty = 'amateur' | 'normal' | 'veteran'📝 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.
| type Difficulty = 'amateur' | 'normal' | 'veteran' | |
| const [difficulty, setDifficulty] = useState<Difficulty>("amateur") | |
| const [running, setRunning] = useState(false) | |
| const [difficulty, setDifficulty] = useState<Difficulty>("amateur") | |
| const [running, setRunning] = useState(false) |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 119 to 121, remove the
duplicate local type alias "Difficulty" declared inside the component and use
the module-level Difficulty type instead; update the useState call to rely on
the existing type (e.g., const [difficulty, setDifficulty] =
useState<Difficulty>("amateur")) and keep the running state as-is.
| const [isWrong, setIsWrong] = useState(false) | ||
| const [gameOver, setGameOver] = useState(false) | ||
| const [attemptedThisEquation, setAttemptedThisEquation] = useState(false) | ||
| const timerRef = useRef<number | null>(null) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Use ReturnType for safer timer typing.
Keeps typings correct across environments and matches the PR intent.
Apply:
- const timerRef = useRef<number | null>(null)
+ const timerRef = useRef<ReturnType<typeof setInterval> | null>(null)📝 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 timerRef = useRef<number | null>(null) | |
| const timerRef = useRef<ReturnType<typeof setInterval> | null>(null) |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around line 130, the timerRef is currently
typed as useRef<number | null>; change its type to useRef<ReturnType<typeof
setInterval> | null> so the ref uses the environment-safe timer type. Update the
declaration accordingly and adjust any places that clear or assign the timer to
use the ref.current value with the new type (e.g.,
clearInterval(timerRef.current) and assignments from setInterval).
| <div className={styles.radioGroup}> | ||
| <label> | ||
| <input type="radio" checked={difficulty === 'amateur'} onChange={() => setDifficulty('amateur')} disabled={running}/> Amateur | ||
| </label> | ||
| <label> | ||
| <input type="radio" checked={difficulty === 'normal'} onChange={() => setDifficulty('normal')} disabled={running}/> Normal | ||
| </label> | ||
| <label> | ||
| <input type="radio" checked={difficulty === 'veteran'} onChange={() => setDifficulty('veteran')} disabled={running}/> Veteran | ||
| </label> | ||
| </div> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Make the difficulty radios a proper radio group.
Add radiogroup semantics and a common name for better screen reader navigation.
Apply:
- <div className={styles.radioGroup}>
+ <div className={styles.radioGroup} role="radiogroup" aria-label="Difficulty level">
<label>
- <input type="radio" checked={difficulty === 'amateur'} onChange={() => setDifficulty('amateur')} disabled={running}/> Amateur
+ <input type="radio" name="difficulty" checked={difficulty === 'amateur'} onChange={() => setDifficulty('amateur')} disabled={running}/> Amateur
</label>
<label>
- <input type="radio" checked={difficulty === 'normal'} onChange={() => setDifficulty('normal')} disabled={running}/> Normal
+ <input type="radio" name="difficulty" checked={difficulty === 'normal'} onChange={() => setDifficulty('normal')} disabled={running}/> Normal
</label>
<label>
- <input type="radio" checked={difficulty === 'veteran'} onChange={() => setDifficulty('veteran')} disabled={running}/> Veteran
+ <input type="radio" name="difficulty" checked={difficulty === 'veteran'} onChange={() => setDifficulty('veteran')} disabled={running}/> Veteran
</label>
</div>📝 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.
| <div className={styles.radioGroup}> | |
| <label> | |
| <input type="radio" checked={difficulty === 'amateur'} onChange={() => setDifficulty('amateur')} disabled={running}/> Amateur | |
| </label> | |
| <label> | |
| <input type="radio" checked={difficulty === 'normal'} onChange={() => setDifficulty('normal')} disabled={running}/> Normal | |
| </label> | |
| <label> | |
| <input type="radio" checked={difficulty === 'veteran'} onChange={() => setDifficulty('veteran')} disabled={running}/> Veteran | |
| </label> | |
| </div> | |
| <div className={styles.radioGroup} role="radiogroup" aria-label="Difficulty level"> | |
| <label> | |
| <input | |
| type="radio" | |
| name="difficulty" | |
| checked={difficulty === 'amateur'} | |
| onChange={() => setDifficulty('amateur')} | |
| disabled={running} | |
| /> Amateur | |
| </label> | |
| <label> | |
| <input | |
| type="radio" | |
| name="difficulty" | |
| checked={difficulty === 'normal'} | |
| onChange={() => setDifficulty('normal')} | |
| disabled={running} | |
| /> Normal | |
| </label> | |
| <label> | |
| <input | |
| type="radio" | |
| name="difficulty" | |
| checked={difficulty === 'veteran'} | |
| onChange={() => setDifficulty('veteran')} | |
| disabled={running} | |
| /> Veteran | |
| </label> | |
| </div> |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 236 to 246 the three
difficulty radio inputs are missing radiogroup semantics and a shared name; wrap
them in a proper radio group by giving each input the same name (e.g.,
name="difficulty"), add a container with role="radiogroup" and an accessible
label (aria-label or aria-labelledby) or replace the div with a fieldset/legend
pair to provide native semantics, and keep the existing
checked/onChange/disabled logic unchanged.
| 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="?" | ||
| ref={inputRef} | ||
| /> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Mobile input UX: numeric keyboard + clear error as user types.
Keep type="text" (to allow '-') but hint mobile keyboards and remove the red state once the user edits.
Apply:
- onChange={(e) => setUserAnswer(e.target.value)}
+ onChange={(e) => { setUserAnswer(e.target.value); if (isWrong) setIsWrong(false) }}
+ inputMode="numeric"
+ pattern="-?[0-9]*"📝 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.
| 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="?" | |
| ref={inputRef} | |
| /> | |
| type="text" | |
| value={userAnswer} | |
| onChange={(e) => { | |
| setUserAnswer(e.target.value) | |
| if (isWrong) setIsWrong(false) | |
| }} | |
| inputMode="numeric" | |
| pattern="-?[0-9]*" | |
| onKeyDown={(e) => { if (e.key === 'Enter') onSubmitAnswer() }} | |
| className={`${styles.input} ${isWrong ? styles.wrong : ''}`} | |
| aria-label="Your answer" | |
| placeholder="?" | |
| ref={inputRef} | |
| /> |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 260 to 268, the input uses
type="text" but should hint mobile keyboards to show numeric keys and clear the
error state as the user types; keep type="text" to allow '-' but add attributes
inputMode="numeric" and pattern="[0-9\\-]*" (or similar) to prompt numeric
keyboards on mobile, and update the onChange handler to both
setUserAnswer(e.target.value) and reset the wrong-state (e.g.,
setIsWrong(false)) so the red/error styling is removed immediately when the user
edits.
| {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={resetGame} ref={resetRef}> | ||
| 🔄 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)
Consider a simple focus trap for the dialog.
You set initial focus—nice. To prevent tabbing to background elements, add a basic focus trap or set inert/aria-hidden on the page behind the modal.
I can add a lightweight focus trap hook if you’d like.
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 287-303, the modal sets
initial focus but does not trap keyboard focus, so users can tab into background
elements; implement a simple focus-trap: on modal mount save the previously
focused element, set focus to resetRef, add a keydown handler that intercepts
Tab/Shift+Tab and cycles focus among focusable elements inside the dialog, and
handle Escape to close; additionally set inert or aria-hidden="true" on the page
content behind the modal (and restore it on unmount) to prevent screen-readers
and pointer interaction with background elements.
| <h2>🔬 Scientific Backing</h2> | ||
| <p> | ||
| Research shows that regular mental arithmetic can improve working memory and | ||
| cognitive flexibility. See: <i>“Cognitive Benefits of Mental Calculation” – | ||
| Smith et al., 2020</i>. | ||
| </p> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Replace or cite the “Scientific Backing” claim.
“Smith et al., 2020” looks placeholder-like. Either link a real source or rephrase to a non-assertive note.
Proposed rephrase:
- Research shows that regular mental arithmetic can improve working memory and
- cognitive flexibility. See: “Cognitive Benefits of Mental Calculation” – Smith et al., 2020.
+ Regular mental arithmetic is commonly associated with improvements in working memory
+ and mental agility. (Educational resources and cognitive training literature discuss these benefits.)Or add a proper citation/link.
📝 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.
| <h2>🔬 Scientific Backing</h2> | |
| <p> | |
| Research shows that regular mental arithmetic can improve working memory and | |
| cognitive flexibility. See: <i>“Cognitive Benefits of Mental Calculation” – | |
| Smith et al., 2020</i>. | |
| </p> | |
| <h2>🔬 Scientific Backing</h2> | |
| <p> | |
| Regular mental arithmetic is commonly associated with improvements in working memory | |
| and mental agility. (Educational resources and cognitive training literature discuss these benefits.) | |
| </p> |
🤖 Prompt for AI Agents
In src/app/game/bullet-math/page.tsx around lines 329 to 334 the "Scientific
Backing" block uses a placeholder citation "Smith et al., 2020"; replace this
with either a real, verifiable citation and link (e.g., add the paper title,
authors, year and a URL/DOI) or rephrase the claim to a non-assertive note
(e.g., "Some studies suggest that regular mental arithmetic may help working
memory and cognitive flexibility" and remove the fake citation), and ensure any
added reference is properly formatted as a clickable link or footnote in the
markup.
| backgroundColor={'#760172'} | ||
| textColor={'white'} | ||
| /> | ||
| <Card image={BulletMath} name={'Bullet Math'} link={'bullet-math'} backgroundColor={'#F59E0B'} textColor={'white'} /> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Nice addition — one nit for accessibility.
Confirm the Card renders an alt attribute for the image (ideally the game name). If not, pass an explicit alt or update Card to derive it from name.
Would you like me to scan the Card component to verify the alt behavior?
🤖 Prompt for AI Agents
In src/app/game/page.tsx around line 49, the Card usage rendering the Bullet
Math image doesn't guarantee an alt attribute; update the call to pass an
explicit alt (e.g., alt={'Bullet Math'}) or modify the Card component to accept
an alt prop and default it to the card's name if not provided, and ensure the
Card's <img> element uses that alt prop so the image is accessible.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Hey @ajaynegi45 👋 |
|
Hey @aleenaharoldpeter 👋 |
🧮 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 Bullet Math entry 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-labelledbyautoFocusto input and reset button:focus-visibleoutline styles✅ Checklist
🙏 Acknowledgements
no-explicit-anyESLint error).Fixed
difficultyinitialization issue (Difficulty | undefinedtype error).Set default difficulty back to
"amateur".Made timer handling (
setInterval/clearInterval) type-safe and reliable.This PR introduces a fresh math challenge game to the project 🚀