Skip to content

Add Simon Says memory sequence game#120

Merged
ajaynegi33 merged 6 commits into
ajaynegi33:mainfrom
Sainava:105-Simon-Says
Oct 3, 2025
Merged

Add Simon Says memory sequence game#120
ajaynegi33 merged 6 commits into
ajaynegi33:mainfrom
Sainava:105-Simon-Says

Conversation

@Sainava

@Sainava Sainava commented Oct 2, 2025

Copy link
Copy Markdown
Contributor
  • Implement complete Simon Says game with two-page structure
  • Landing page with game setup (difficulty, button count)
  • Gameplay page with full game logic and audio
  • Support for 4, 7, and 10 button configurations
  • Normal and Strict game modes
  • Keyboard controls (number keys, WASD, arrow keys)
  • Audio feedback with Web Audio API
  • Local storage for high score persistence
  • Responsive design with mobile support
  • SSR-safe implementation with proper hydration guards
  • TypeScript interfaces for type safety
  • Error boundaries and client-side API protection

Resolves #105

This will be an official contribution for GSSOC.

- Implement complete Simon Says game with two-page structure
- Landing page with game setup (difficulty, button count)
- Gameplay page with full game logic and audio
- Support for 4, 7, and 10 button configurations
- Normal and Strict game modes
- Keyboard controls (number keys, WASD, arrow keys)
- Audio feedback with Web Audio API
- Local storage for high score persistence
- Responsive design with mobile support
- SSR-safe implementation with proper hydration guards
- TypeScript interfaces for type safety
- Error boundaries and client-side API protection

Resolves #105
@vercel

vercel Bot commented Oct 2, 2025

Copy link
Copy Markdown

@Sainava is attempting to deploy a commit to the ajaynegi45's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Oct 2, 2025

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Introduced a new Simon Says game, accessible from the Games page.
    • Setup screen to choose difficulty (normal/strict) and button count (4/7/10), then start playing.
    • In-game audio toggle, keyboard and click/tap controls, status messages, and back navigation.
    • Scorekeeping with best score saved per mode and button count.
    • Responsive layout for desktop, tablet, and mobile.
  • Style

    • Added comprehensive, animated, and accessible styling for Simon Says setup and play pages.

Walkthrough

Adds a new Simon Says game: a Games page card, a landing/setup page (difficulty and button-count), a client-only play page with sequence logic, audio and keyboard support, score persistence, and two CSS modules for setup and play styling and layout.

Changes

Cohort / File(s) Summary
Game selection update
src/app/game/page.tsx
Adds a "Simon Says" card and image import; reformats existing Bullet Math card JSX.
Simon Says landing / setup
src/app/game/simon-says/page.tsx
New client landing component with local state for difficulty and buttonCount, navigation to play with query params, rules/controls UI, and CSS module usage. Exports SimonSaysLanding.
Simon Says landing styles
src/app/game/simon-says/page.module.css
New CSS module providing layout, header, setup controls, rules, grids (4/7/10), interactive states, animations, and responsive breakpoints.
Simon Says gameplay page
src/app/game/simon-says/play/page.tsx
New client play component: sequence generation/display, input handling (click/keyboard), Web Audio API tones, normal/strict modes, score/round/best persistence (localStorage), keyboard bindings, routing/back navigation, and client-only rendering guard. Exports default game page.
Simon Says gameplay styles
src/app/game/simon-says/play/page.module.css
New CSS module for gameplay layout, stats, sound toggle, grid variants, pad states, pulse animation, focus styles, and responsive rules.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Games as Game List
  participant Setup as SimonSays Setup
  participant Router
  participant Play as SimonSays Play
  participant Engine as Game Logic
  participant Audio as AudioContext
  participant Store as localStorage

  User->>Games: Click "Simon Says"
  Games->>Router: Navigate /game/simon-says
  Router->>Setup: Render landing/setup

  User->>Setup: Choose difficulty & button count
  User->>Setup: Click "Start Playing"
  Setup->>Router: Navigate to /game/simon-says/play?settings
  Router->>Play: Render play page
  Play->>Store: Load best score
  Play->>Engine: Init sequence/state

  User->>Play: Click "Start"
  Play->>Engine: Generate & show sequence
  Engine->>Audio: Play tones (visual highlights)
  Engine-->>User: Sequence displayed

  loop Player turn
    User->>Play: Input (click/keyboard)
    Play->>Audio: Play tone
    Play->>Engine: Validate input
    alt Correct & round complete
      Engine->>Store: Update best score if needed
      Engine-->>Play: Extend sequence
    else Mistake
      alt Normal
        Engine-->>Play: Retry same round
      else Strict
        Engine-->>Play: Game over
      end
    end
  end

  User->>Play: Toggle sound / Back
  Play->>Router: Navigate back to setup
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Schulte table game #79 — Adds a game card to src/app/game/page.tsx, touching the same Games list where the Simon Says card was added.

Poem

Four lights blink, a melody hums bright,
Remember the pattern, press each light.
Round by round the sequence grows,
Tap with care and let memory glow.
Play, retry, and chase that high-score light. 🎵

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Beyond adding the Simon Says game, the pull request also reformats the existing Bullet Math card JSX in src/app/game/page.tsx, which is a cosmetic change unrelated to the objectives in issue #105. Please remove or isolate the Bullet Math card formatting changes into a separate commit or pull request to keep this one focused on the Simon Says feature.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly describes the primary change by stating that a Simon Says memory sequence game was added, which directly reflects the main content of the pull request.
Linked Issues Check ✅ Passed The pull request fulfills the core mechanics of Simon Says by implementing the sequence playback, visual and audio cues, state machine flow, Normal and Strict modes, keyboard support, localStorage persistence, responsive CSS Modules styling, and SSR‐safe patterns as outlined in issue #105.
Description Check ✅ Passed The description outlines the two-page structure, gameplay features, and technical details that match the actual code changes, demonstrating a clear link between the author’s summary and the implemented functionality.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 552a5e1 and 866ec69.

📒 Files selected for processing (1)
  • src/app/game/simon-says/play/page.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
src/app/game/simon-says/play/page.tsx

[error] 411-411: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 458-473: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 480-485: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🔇 Additional comments (12)
src/app/game/simon-says/play/page.tsx (12)

8-57: Nice type definitions and button configurations!

Your interfaces (GameState, Button) and type aliases (Difficulty, ButtonCount) are clear and well-structured. The BUTTON_CONFIGS constant provides clean separation of button data for different game modes. Everything looks solid here! ✨


59-97: Great job fixing the conditional hooks issue!

You've successfully addressed the previous concern about calling hooks conditionally. Now all hooks run unconditionally at the top level, and you use the mounted state to control client-side rendering safely. The timeoutsRef array and clearScheduledTimeouts helper are a smart pattern for cleanup. Everything here looks excellent! 🎉


99-117: URL parameter handling looks solid!

You're correctly reading and validating the difficulty and button count from URL params, with proper SSR guards and error handling. The validation ensures only expected values get through. Nice work! 👍


119-149: Audio implementation is well done!

Your Web Audio API usage is spot-on! The initAudioContext function correctly handles both standard and webkit-prefixed AudioContext, and playTone generates clean sine wave tones with proper gain envelope. The error handling ensures the game doesn't crash if audio fails. Great implementation! 🔊


151-179: localStorage handling is safe and correct!

You're properly guarding all localStorage access with SSR checks and error handling. The saveBestScore function only updates when the new score is actually better, which is exactly right. Well done! 💾


181-201: Game initialization logic is solid!

Your generateNextStep function correctly picks a random button, and startNewGame properly resets everything with timeout cleanup before starting fresh. Calling initAudioContext ensures audio is ready to go. Everything looks great! 🎮


203-242: Excellent fix for timeout tracking!

You've successfully addressed the previous concern about tracking all scheduled timeouts! Now every setTimeout (both the highlight and reset timeouts in the loop, plus the final playerTurn transition) is pushed into timeoutsRef.current and will be properly cleaned up. This prevents any state updates after unmount. Really well done! 🎯


244-309: Button click handling is now complete and correct!

Wonderful updates here! You've fixed both previous issues:

  1. The 300ms releaseTimeout is now tracked in timeoutsRef (line 254) ✓
  2. saveBestScore is called right after completing a round (line 301) ✓

The logic correctly handles player input, validates sequences, and manages both Normal and Strict mode behaviors. The score updates and persistence work perfectly. Great job! 🌟


311-356: Keyboard controls are well implemented!

Your keyboard handling is excellent! You support number keys for all button counts, plus arrow keys and WASD for the classic 4-button layout. The guards ensure it only works during the player's turn, and the cleanup properly removes the listener. Perfect! ⌨️


358-370: Side effects and cleanup look perfect!

The effect that triggers showSequence when the game status changes is correctly set up, and your cleanup effect properly clears all timeouts on unmount. Everything is tidy and safe! 🧹


372-500: Rendering logic is clean and accessible!

Your UI structure is well-organized with clear sections for stats, controls, and the game board. The loading state prevents hydration issues, and the ARIA labels on game buttons (aria-label with button name and key binding) are great for accessibility. The dynamic status messages keep players informed. Excellent work! 🎨


503-539: SSR handling is properly implemented!

Your use of next/dynamic with ssr: false and the Suspense boundary ensures the game component only runs on the client side, preventing any SSR-related issues with browser APIs like window, localStorage, and Web Audio. The loading states provide good UX during hydration. Well done! 🚀


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Oct 2, 2025

Copy link
Copy Markdown

👋 Hello @Sainava!

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:

  • 🌟 Don’t forget to ⭐ Star the repo and follow @ajaynegi45 for updates, ideas, and dev insights.
  • 📬 Stay inspired! Sign up for the monthly CodiesCoder Newsletter – we explore one key software engineering topic each month, beginner-friendly and fun to read!

✅ Your pull request has been submitted successfully, and a maintainer will review it soon.

@coderabbitai coderabbitai Bot added enhancement New feature or request gssoc GirlScript Summer Of Code gssoc25 level3 size:XL This PR changes 500-999 lines, ignoring generated files labels Oct 2, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8840c4 and 153ebbf.

⛔ Files ignored due to path filters (1)
  • public/SimonSays.png is excluded by !**/*.png
📒 Files selected for processing (5)
  • src/app/game/page.tsx (2 hunks)
  • src/app/game/simon-says/page.module.css (1 hunks)
  • src/app/game/simon-says/page.tsx (1 hunks)
  • src/app/game/simon-says/play/page.module.css (1 hunks)
  • src/app/game/simon-says/play/page.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
src/app/game/simon-says/page.tsx

[error] 34-37: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 41-44: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 54-57: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 61-64: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 68-71: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 78-78: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

src/app/game/simon-says/play/page.tsx

[error] 391-391: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 438-453: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 460-465: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🔇 Additional comments (15)
src/app/game/page.tsx (1)

9-9: Nice addition!

The Simon Says card follows the same pattern as the other game cards. The import, link, and styling look good and match the new game directory structure. Great consistency!

Also applies to: 50-63

src/app/game/simon-says/play/page.module.css (1)

1-349: Well-structured CSS module!

The play page styles are nicely organized with clear sections for layout, stats, controls, game board, and responsive behavior. The responsive breakpoints and animations look good. Great job keeping the styles modular and readable!

src/app/game/simon-says/play/page.tsx (13)

7-56: Great type definitions!

Your interfaces and types are clear and well-structured. The BUTTON_CONFIGS setup nicely handles the different difficulty levels (4, 7, 10 buttons) with distinct colors and tones. Using musical note frequencies for tones is a nice touch!


58-88: Smart SSR safety pattern!

The mounted state and the mount effect at lines 85-87 ensure that any client-only code (like localStorage or window access) waits until after hydration. This prevents SSR mismatches. Well done!


90-107: Solid URL parameter handling!

The validation checks for difficulty and buttons are thorough, and the mounted guard ensures this runs safely on the client side. The try-catch is a nice touch for robustness. Great work!


110-139: Excellent Web Audio API usage!

Your audio context initialization handles SSR safety and Safari's webkitAudioContext fallback nicely. The tone generation with oscillator and gain node is spot-on, and the exponential ramp creates a smooth fade-out. The try-catch ensures graceful degradation if audio fails. Really well implemented!


142-169: Perfect localStorage integration!

The best score persistence is well-designed with unique keys per difficulty and button count. The SSR guards (mounted, typeof window) and try-catch blocks ensure it's safe and robust. Nice job!


172-190: Clean game initialization!

The generateNextStep function correctly generates random button indices, and startNewGame sets up the initial game state perfectly. Calling initAudioContext here ensures audio is ready when the sequence starts. Looks great!


193-225: Good sequence display logic!

The showSequence function handles the timing and visual feedback well. The async/await pattern with promises makes the sequence flow clear. One small note: if the component unmounts mid-sequence, only the last timeout is cleaned up (line 346-349). The earlier timeouts will still fire, but since they only call setActiveButton, it's harmless. For now, this is fine, but if you wanted to be extra careful, you could store all timeout IDs in an array and clear them all on unmount.


228-287: Core game logic looks solid!

The handleButtonClick function correctly handles both success and failure cases. The distinction between strict mode (game over on mistake) and normal mode (retry current round) is implemented perfectly. The score calculation is correct—score only increases when a round is completed successfully. Great job on the game mechanics!


290-334: Keyboard controls are well-implemented!

The number key bindings (1-9, 0) work perfectly for all button counts, and the arrow/WASD controls for 4-button mode are a nice UX touch. The guard checks ensure inputs are only processed during the player's turn. Great attention to detail!


337-350: Effects are correctly wired!

The effect that triggers showSequence when the game status changes to 'showing' is spot-on. The cleanup effect ensures the last timeout is cleared on unmount, preventing memory leaks. Nice!


352-371: User-friendly status messages!

The getStatusMessage function provides clear feedback to the player at each stage of the game. The navigation back to the setup page is straightforward. Looks good!


374-385: Smart loading state!

The loading guard before mounted is true prevents any client-only rendering issues during SSR. This ensures a smooth hydration experience. Well done!


483-501: Perfect Suspense setup!

Wrapping SimonSaysGame in Suspense is the right approach for handling useSearchParams in Next.js client components. The fallback UI is clean and provides good feedback while loading. Great!

Comment thread src/app/game/simon-says/page.module.css Outdated
Comment on lines +1 to +713
/* Simon Says Game Styles */
.container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
text-align: center;
background: white;
min-height: 100vh;
color: #333;
}

.header {
margin-bottom: 30px;
}

.title {
font-size: 2.8rem;
font-weight: bold;
margin-bottom: 10px;
background: linear-gradient(135deg, #9333EA, #7C3AED);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: none;
}

.subtitle {
font-size: 1.3rem;
color: #666;
margin-bottom: 20px;
}

/* Game Setup */
.gameSetup {
max-width: 700px;
margin: 0 auto 3rem auto;
padding: 2rem;
background: #f8f9fa;
border-radius: 16px;
border: 2px solid #e2e8f0;
}

.setupTitle {
font-size: 1.8rem;
margin-bottom: 2rem;
color: #333;
text-align: center;
}

.setupSection {
margin-bottom: 2rem;
text-align: center;
}

.setupSection h3 {
font-size: 1.2rem;
margin-bottom: 1rem;
color: #333;
}

.buttonGroup {
display: flex;
justify-content: center;
gap: 15px;
flex-wrap: wrap;
}

.setupButton {
padding: 15px 25px;
border: 2px solid #e2e8f0;
border-radius: 12px;
background: white;
color: #333;
cursor: pointer;
font-weight: 500;
transition: all 0.3s ease;
font-size: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
min-width: 120px;
}

.setupButton:hover {
border-color: #9333EA;
transform: translateY(-2px);
}

.setupButton.active {
background: linear-gradient(135deg, #9333EA, #7C3AED);
color: white;
border-color: #9333EA;
}

.modeDescription {
font-size: 0.8rem;
opacity: 0.8;
}

.playButton {
background: linear-gradient(135deg, #22C55E, #16A34A);
color: white;
border: none;
padding: 18px 40px;
font-size: 1.3rem;
font-weight: bold;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(34, 197, 94, 0.3);
margin-top: 1.5rem;
}

.playButton:hover {
background: linear-gradient(135deg, #16A34A, #15803D);
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(34, 197, 94, 0.4);
}

.soundControl {
text-align: center;
}

.soundToggle {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
cursor: pointer;
font-size: 1rem;
}

.soundToggle input[type="checkbox"] {
transform: scale(1.2);
cursor: pointer;
}

/* Game Stats */
.gameStats {
display: flex;
justify-content: center;
gap: 30px;
margin-bottom: 20px;
flex-wrap: wrap;
}

.stat {
background: #f8f9fa;
padding: 15px 25px;
border-radius: 12px;
border: 2px solid #e2e8f0;
color: #2d3748;
min-width: 100px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.statLabel {
display: block;
font-size: 0.9rem;
color: #666;
margin-bottom: 5px;
}

.statValue {
display: block;
font-size: 1.5rem;
font-weight: bold;
color: #9333EA;
}

/* Status Message */
.statusMessage {
margin-bottom: 30px;
padding: 15px;
background: linear-gradient(135deg, #f3f4f6, #e5e7eb);
border-radius: 12px;
border-left: 4px solid #9333EA;
}

.statusMessage p {
font-size: 1.1rem;
font-weight: 500;
margin: 0;
color: #374151;
}

/* Game Board */
.gameBoard {
display: grid;
gap: 20px;
margin: 30px auto;
max-width: 600px;
perspective: 1000px;
padding: 20px;
}

.grid4 {
grid-template-columns: repeat(2, 1fr);
max-width: 400px;
}

.grid7 {
grid-template-columns: repeat(3, 1fr);
max-width: 500px;
}

.grid10 {
grid-template-columns: repeat(4, 1fr);
max-width: 600px;
}

.gameButton {
aspect-ratio: 1;
border: none;
border-radius: 20px;
cursor: pointer;
font-size: 1rem;
font-weight: bold;
color: white;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
min-height: 100px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
transform-style: preserve-3d;
}

.gameButton:hover:not(:disabled) {
transform: translateY(-5px) scale(1.05);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3) !important;
}

.gameButton:active:not(:disabled) {
transform: translateY(-2px) scale(0.98);
}

.gameButton:disabled {
cursor: not-allowed;
opacity: 0.8;
}

.gameButton.active {
transform: translateY(-5px) scale(1.1);
filter: brightness(1.3);
animation: pulse 0.6s ease;
}

@keyframes pulse {
0%, 100% { transform: translateY(-5px) scale(1.1); }
50% { transform: translateY(-8px) scale(1.15); }
}

.buttonLabel {
font-size: 1rem;
font-weight: bold;
}



/* Action Buttons */
.actionButtons {
margin: 30px 0;
}

.startButton {
background: linear-gradient(135deg, #22C55E, #16A34A);
color: white;
border: none;
padding: 15px 40px;
font-size: 1.2rem;
font-weight: bold;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(34, 197, 94, 0.3);
}

.startButton:hover:not(:disabled) {
background: linear-gradient(135deg, #16A34A, #15803D);
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(34, 197, 94, 0.4);
}

.startButton:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}

/* Keyboard Info */
.keyboardInfo {
margin: 20px 0;
padding: 15px;
background: #f8f9fa;
border-radius: 10px;
border: 1px solid #e2e8f0;
}

.keyboardInfo h4 {
margin: 0 0 8px 0;
color: #333;
font-size: 1rem;
}

.keyboardInfo p {
margin: 0;
color: #666;
font-size: 0.9rem;
}

/* Rules and Benefits */
.rulesContainer {
max-width: 800px;
margin: 3rem auto;
padding: 0 1rem;
font-family: system-ui, -apple-system, sans-serif;
text-align: left;
}

.sectionTitle {
font-size: 1.6rem;
margin: 2rem 0 1.2rem 0;
color: #111;
font-weight: 600;
letter-spacing: -0.01em;
text-align: center;
}

.rulesGrid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}

.ruleCard {
background: white;
padding: 1.5rem;
border-radius: 12px;
border: 2px solid #e2e8f0;
text-align: center;
transition: all 0.3s ease;
}

.ruleCard:hover {
border-color: #9333EA;
transform: translateY(-2px);
}

.ruleNumber {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #9333EA, #7C3AED);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 1.2rem;
margin: 0 auto 1rem auto;
}

.ruleCard h4 {
margin: 0 0 0.5rem 0;
color: #333;
font-size: 1.1rem;
}

.ruleCard p {
margin: 0;
color: #666;
line-height: 1.5;
}



.algorithmText {
line-height: 1.7;
color: #333;
background: #f8f9fa;
padding: 1.5rem;
border-radius: 10px;
border-left: 4px solid #9333EA;
}

.rulesGrid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}

.ruleCard {
background: white;
padding: 1.5rem;
border-radius: 12px;
border: 2px solid #e2e8f0;
text-align: center;
transition: all 0.3s ease;
}

.ruleCard:hover {
border-color: #9333EA;
transform: translateY(-2px);
}

.ruleNumber {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #9333EA, #7C3AED);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 1.2rem;
margin: 0 auto 1rem auto;
}

.ruleCard h4 {
margin: 0 0 0.5rem 0;
color: #333;
font-size: 1.1rem;
}

.ruleCard p {
margin: 0;
color: #666;
line-height: 1.5;
}

.controlsInfo {
margin: 2rem 0;
background: white;
padding: 1.5rem;
border-radius: 12px;
border: 2px solid #e2e8f0;
}

.controlsInfo h3 {
margin: 0 0 1rem 0;
color: #333;
text-align: center;
}

.controlsList {
display: flex;
flex-direction: column;
gap: 0.8rem;
}

.controlItem {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.8rem;
background: #f8f9fa;
border-radius: 8px;
}

.controlKey {
font-weight: bold;
color: #9333EA;
background: #f3f0ff;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.9rem;
}

.rulesGrid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin: 1rem 0;
}

.ruleCard {
background: linear-gradient(145deg, #f8fafc, #e2e8f0);
border: 1px solid #cbd5e1;
border-radius: 12px;
padding: 1rem;
transition: all 0.3s ease;
display: flex;
align-items: flex-start;
gap: 0.75rem;
}

.ruleCard:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
border-color: #9333EA;
}

.ruleNumber {
background: linear-gradient(135deg, #9333EA, #7c3aed);
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 0.875rem;
flex-shrink: 0;
margin-top: 2px;
}

.controlsInfo {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin: 1rem 0;
padding: 1rem;
background: linear-gradient(145deg, #f1f5f9, #e2e8f0);
border-radius: 12px;
border: 1px solid #cbd5e1;
}

.controlKey {
background: linear-gradient(145deg, #ffffff, #f1f5f9);
border: 1px solid #cbd5e1;
border-radius: 6px;
padding: 0.5rem 0.75rem;
font-family: 'Courier New', monospace;
font-weight: bold;
color: #475569;
font-size: 0.875rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
}

.controlKey:hover {
background: linear-gradient(145deg, #f1f5f9, #e2e8f0);
transform: translateY(-1px);
}

/* Responsive Design */
@media (max-width: 768px) {
.container {
padding: 15px;
}

.title {
font-size: 2.2rem;
}

.subtitle {
font-size: 1.1rem;
}

.gameControls {
gap: 15px;
}

.buttonGroup {
gap: 8px;
}

.gameSetup {
padding: 1.5rem;
}

.setupTitle {
font-size: 1.5rem;
}

.setupButton {
padding: 12px 20px;
font-size: 0.9rem;
min-width: 100px;
}

.playButton {
padding: 15px 30px;
font-size: 1.1rem;
}

.rulesGrid {
grid-template-columns: 1fr;
gap: 1rem;
}

.ruleCard {
padding: 1.2rem;
}

.controlsInfo,
.tipsSection {
padding: 1.2rem;
}

.gameStats {
gap: 15px;
}

.stat {
padding: 12px 20px;
min-width: 80px;
}

.gameBoard {
gap: 15px;
padding: 15px;
max-width: 350px;
}

.grid4 {
max-width: 280px;
}

.grid7 {
max-width: 320px;
}

.grid10 {
max-width: 350px;
}

.gameButton {
min-height: 80px;
font-size: 0.9rem;
}

.buttonLabel {
font-size: 0.9rem;
}



.startButton {
padding: 12px 30px;
font-size: 1.1rem;
}

.sectionTitle {
font-size: 1.4rem;
}


}

@media (max-width: 480px) {
.gameBoard {
gap: 10px;
max-width: 300px;
}

.grid4 {
max-width: 240px;
}

.grid7 {
max-width: 280px;
}

.grid10 {
max-width: 300px;
}

.gameButton {
min-height: 70px;
border-radius: 15px;
}

.buttonLabel {
font-size: 0.8rem;
}



.rulesContainer {
padding: 0 0.5rem;
}

.sectionTitle {
font-size: 1.25rem;
}

.rulesGrid {
grid-template-columns: 1fr;
gap: 0.75rem;
}

.ruleCard {
padding: 0.75rem;
}

.ruleNumber {
width: 20px;
height: 20px;
font-size: 0.75rem;
margin-right: 0.5rem;
}

.controlsInfo {
gap: 0.75rem;
}

.controlKey {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
}

} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider reducing CSS duplication

I noticed quite a bit of CSS duplication, both within this file and between this file and play/page.module.css. For example:

Within this file:

  • .rulesGrid, .ruleCard, .ruleNumber, .controlsInfo, and .controlKey are defined multiple times (lines 335-380, 393-438, 478-545). This creates three nearly identical rule card sections!

Between this file and play/page.module.css:

  • Common layout styles like .container, .header, .title, .gameStats, .stat, .gameBoard, .grid4/.grid7/.grid10, .gameButton, .startButton, and .keyboardInfo appear in both files with very similar (or identical) rules.

This duplication makes the code harder to maintain—if you need to change a color or spacing, you'd have to update it in multiple places.

Here are a few ways to fix this:

  1. Extract shared styles to a common CSS module (e.g., simon-says-shared.module.css) and import it in both landing and play pages.
  2. Use CSS variables for repeated values (colors, spacing, etc.) to ensure consistency.
  3. Remove the duplicate rule blocks within this file—you only need one definition of .rulesGrid, .ruleCard, etc.

Cleaning this up will reduce your bundle size, improve maintainability, and follow the DRY (Don't Repeat Yourself) principle. Would you like me to help you identify which styles to extract or merge?

🤖 Prompt for AI Agents
In src/app/game/simon-says/page.module.css (lines 1-713) there are multiple
duplicated blocks for .rulesGrid, .ruleCard, .ruleNumber, .controlsInfo and
.controlKey within this file and many shared layout rules duplicated across
play/page.module.css; remove the intra-file duplicates by keeping a single
canonical definition for each repeated selector (merge the variants into one
consistent rule set), extract truly shared layout/visual styles (e.g.,
.container, .header, .title, .gameStats, .stat, .gameBoard,
.grid4/.grid7/.grid10, .gameButton, .startButton, .keyboardInfo) into a new
shared CSS module (e.g., simon-says-shared.module.css) and import it from both
pages, and introduce CSS variables for repeated values (colors, spacing, radii)
so the merged rules reference variables rather than hard-coded values.

Comment on lines +34 to +80
<button
className={`${styles.setupButton} ${difficulty === 'normal' ? styles.active : ''}`}
onClick={() => setDifficulty('normal')}
>
Normal
<span className={styles.modeDescription}>Retry on mistake</span>
</button>
<button
className={`${styles.setupButton} ${difficulty === 'strict' ? styles.active : ''}`}
onClick={() => setDifficulty('strict')}
>
Strict
<span className={styles.modeDescription}>Game over on mistake</span>
</button>
</div>
</div>

<div className={styles.setupSection}>
<h3>Difficulty Level</h3>
<div className={styles.buttonGroup}>
<button
className={`${styles.setupButton} ${buttonCount === 4 ? styles.active : ''}`}
onClick={() => setButtonCount(4)}
>
Easy
<span className={styles.modeDescription}>4 Buttons</span>
</button>
<button
className={`${styles.setupButton} ${buttonCount === 7 ? styles.active : ''}`}
onClick={() => setButtonCount(7)}
>
Medium
<span className={styles.modeDescription}>7 Buttons</span>
</button>
<button
className={`${styles.setupButton} ${buttonCount === 10 ? styles.active : ''}`}
onClick={() => setButtonCount(10)}
>
Hard
<span className={styles.modeDescription}>10 Buttons</span>
</button>
</div>
</div>

<button className={styles.playButton} onClick={startGame}>
Start Playing
</button>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add type="button" to all buttons

Right now, all your buttons are missing the type="button" prop. By default, buttons have type="submit", which can cause unexpected behavior if they're ever inside a form. Even though there's no form here, it's a good practice to always specify type="button" for non-submit buttons.

Here's how to fix it—just add type="button" to each button:

         <button
+          type="button"
           className={`${styles.setupButton} ${difficulty === 'normal' ? styles.active : ''}`}
           onClick={() => setDifficulty('normal')}
         >

Apply this same change to all the other buttons in this file (lines 41, 54, 61, 68, and 78). This will make your code more robust and follow best practices!

As per static analysis hints.

📝 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.

Suggested change
<button
className={`${styles.setupButton} ${difficulty === 'normal' ? styles.active : ''}`}
onClick={() => setDifficulty('normal')}
>
Normal
<span className={styles.modeDescription}>Retry on mistake</span>
</button>
<button
className={`${styles.setupButton} ${difficulty === 'strict' ? styles.active : ''}`}
onClick={() => setDifficulty('strict')}
>
Strict
<span className={styles.modeDescription}>Game over on mistake</span>
</button>
</div>
</div>
<div className={styles.setupSection}>
<h3>Difficulty Level</h3>
<div className={styles.buttonGroup}>
<button
className={`${styles.setupButton} ${buttonCount === 4 ? styles.active : ''}`}
onClick={() => setButtonCount(4)}
>
Easy
<span className={styles.modeDescription}>4 Buttons</span>
</button>
<button
className={`${styles.setupButton} ${buttonCount === 7 ? styles.active : ''}`}
onClick={() => setButtonCount(7)}
>
Medium
<span className={styles.modeDescription}>7 Buttons</span>
</button>
<button
className={`${styles.setupButton} ${buttonCount === 10 ? styles.active : ''}`}
onClick={() => setButtonCount(10)}
>
Hard
<span className={styles.modeDescription}>10 Buttons</span>
</button>
</div>
</div>
<button className={styles.playButton} onClick={startGame}>
Start Playing
</button>
<button
type="button"
className={`${styles.setupButton} ${difficulty === 'normal' ? styles.active : ''}`}
onClick={() => setDifficulty('normal')}
>
Normal
<span className={styles.modeDescription}>Retry on mistake</span>
</button>
🧰 Tools
🪛 Biome (2.1.2)

[error] 34-37: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 41-44: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 54-57: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 61-64: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 68-71: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 78-78: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
In src/app/game/simon-says/page.tsx around lines 34 to 80, all button elements
are missing an explicit type attribute which defaults to "submit" and can cause
unintended form submissions; add type="button" to each non-submit button on the
listed lines (buttons at ~41, 54, 61, 68, and 78) and any other buttons in this
file to ensure they behave as plain clickable controls.

Comment on lines +391 to +393
<button className={styles.backButton} onClick={goBack}>
← Back to Setup
</button>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add type="button" to all buttons

Just like in the landing page, all your buttons here are missing the type="button" prop. This can cause unexpected behavior if they're ever inside a form. It's a simple fix—just add type="button" to each button:

For the back button (line 391):

       <button
+        type="button"
         className={styles.backButton}
         onClick={goBack}
       >

For the game buttons (lines 438-455):

         <button
+          type="button"
           key={button.id}
           className={`${styles.gameButton} ${

For the start button (lines 460-467):

       <button
+        type="button"
         className={styles.startButton}
         onClick={startNewGame}

Adding type="button" to all three makes your code more robust and follows best practices!

As per static analysis hints.

Also applies to: 438-455, 460-467

🧰 Tools
🪛 Biome (2.1.2)

[error] 391-391: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
In src/app/game/simon-says/play/page.tsx around lines 391, 438-455, and 460-467,
all button elements are missing an explicit type which can cause them to act as
form submit buttons; update each <button> (the back button at ~391, every game
button in the block ~438-455, and the start button in ~460-467) to include
type="button" in their JSX attributes so they do not trigger form submission and
follow best practices.

@vercel

vercel Bot commented Oct 3, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
time-pass Ready Ready Preview Comment Oct 3, 2025 6:33pm

@ajaynegi33

Copy link
Copy Markdown
Owner
Screenshot 2025-10-03 at 10 28 13 AM
  • Color is too light here.
  • Text is not visible properly.
  • In small screen they overlap each other

Screenshot 2025-10-03 at 10 24 10 AM
  • Not aligned

- Improve centering of rules grid on mobile screens
- Remove duplicate CSS rules in media queries
- Enhance responsive layout for better card alignment
- Ensure proper width and spacing on small screens
- Add text-align: center to rulesContainer on mobile screens
- Keep individual rule card text left-aligned within centered cards
- This fixes the alignment issue where cards appeared left-aligned on small screens
- Replace grid with flex column for deterministic alignment
- Introduce .ruleText wrapper for consistent spacing
- Remove duplicate .rulesGrid definitions & conflicts
- Add single-source responsive overrides (<=480px)
- Ensure left text alignment inside centered container

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
src/app/game/simon-says/page.tsx (1)

34-80: Please give every setup button an explicit type

Right now each of these buttons is missing type="button". Browsers default to type="submit", so if this page ever sits inside a form, a simple click could submit the form by surprise. Let’s prevent that now.

Here’s a diff showing the first few updates—repeat the same change for the remaining buttons, including “Start Playing”:

           <button
+            type="button"
             className={`${styles.setupButton} ${difficulty === 'normal' ? styles.active : ''}`}
             onClick={() => setDifficulty('normal')}
           >
@@
           <button
+            type="button"
             className={`${styles.setupButton} ${difficulty === 'strict' ? styles.active : ''}`}
             onClick={() => setDifficulty('strict')}
           >
@@
         <button
+          type="button"
           className={styles.playButton}
           onClick={startGame}
         >

Adding the type keeps each control behaving like a normal clickable button everywhere. 😊
As per static analysis hints.

src/app/game/simon-says/play/page.tsx (1)

397-472: Add type="button" to every game control

Just like on the landing page, these <button> elements default to type="submit". If we ever wrap this play view in a form (or copy the component elsewhere), a simple click could trigger an unexpected submit.

Let’s add an explicit type to each one:

-        <button className={styles.backButton} onClick={goBack}>
+        <button type="button" className={styles.backButton} onClick={goBack}>
@@
-          <button
+          <button
+            type="button"
             key={button.id}
             className={`${styles.gameButton} ${
               activeButton === button.id ? styles.active : ''
             }`}
@@
-        <button
+        <button
+          type="button"
           className={styles.startButton}
           onClick={startNewGame}
           disabled={gameState.gameStatus === 'showing'}
         >

This tiny addition keeps every control predictable and prevents accidental form submissions down the road. Nicely done on the rest of the interactivity! 🌈
As per static analysis hints.

src/app/game/simon-says/page.module.css (1)

335-840: Let’s merge the repeated rule/control styles

I spotted the same selectors repeated three times (.rulesGrid, .ruleCard, .ruleNumber, .controlsInfo, .controlKey, etc.). Each repetition tweaks tiny details, so the browser ends up applying whichever block comes last. That makes the final look hard to predict and painful to maintain—changing one color means hunting through the whole file.

A gentle path forward:

  1. Keep a single definition for each selector in this module.
  2. If you need variations, split them into modifier classes (e.g., .ruleCard, .ruleCardHighlight).
  3. Move anything shared with the play page into a small shared CSS module or define CSS variables so both files use the same tokens.

This tidy-up will shrink the file, silence the duplicate-property lint warning, and make future edits way easier. I’m happy to help outline the shared pieces if you’d like! 😊

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 153ebbf and ffd9e7d.

📒 Files selected for processing (4)
  • src/app/game/simon-says/page.module.css (1 hunks)
  • src/app/game/simon-says/page.tsx (1 hunks)
  • src/app/game/simon-says/play/page.module.css (1 hunks)
  • src/app/game/simon-says/play/page.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
src/app/game/simon-says/page.module.css

[error] 616-616: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.

text-align is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)

src/app/game/simon-says/play/page.tsx

[error] 65-65: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 66-66: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 68-68: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 78-78: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 79-79: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 80-80: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 81-81: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 82-82: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 83-83: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 85-85: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 86-86: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 91-91: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 96-96: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 116-116: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 124-124: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 148-148: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 164-164: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 178-178: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 184-184: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 199-199: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 234-234: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 296-296: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 343-343: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 350-350: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 397-397: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 444-459: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 466-471: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

src/app/game/simon-says/page.tsx

[error] 34-37: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 41-44: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 54-57: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 61-64: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 68-71: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 78-78: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

Comment thread src/app/game/simon-says/play/page.tsx Outdated
Comment thread src/app/game/simon-says/play/page.tsx
…ound

- Introduce timeoutsRef array + clearScheduledTimeouts helper
- Clear scheduled timeouts on new game, new sequence, unmount
- Track both highlight and reset timeouts plus player turn transition
- Save best score immediately after each successful round
- Prevent potential state updates after unmount

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/app/game/simon-says/play/page.tsx (1)

412-486: Let’s add type="button" to these controls.

Quick reminder from the earlier review: the back button, every game pad button, and the start/new-game button still need type="button" so they never act like form submits by accident. It’s just a tiny prop on each <button> and keeps behavior super predictable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ffd9e7d and 552a5e1.

📒 Files selected for processing (1)
  • src/app/game/simon-says/play/page.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
src/app/game/simon-says/play/page.tsx

[error] 65-65: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 66-66: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 68-68: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 78-78: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 79-79: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 80-80: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 81-81: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 82-82: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 83-83: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 85-85: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 87-87: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 89-89: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 99-99: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 104-104: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 124-124: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 132-132: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 156-156: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 172-172: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 186-186: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 192-192: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 208-208: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 249-249: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 313-313: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 360-360: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 367-367: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 412-412: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 459-474: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 481-486: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

Comment on lines +59 to +107
const SimonSaysGame = () => {
// Early return for SSR
if (typeof window === 'undefined') {
return null;
}

const searchParams = useSearchParams();
const router = useRouter();

const [gameState, setGameState] = useState<GameState>({
sequence: [],
playerSequence: [],
currentRound: 0,
isShowingSequence: false,
isPlayerTurn: false,
gameStatus: 'idle',
score: 0
});

const [difficulty, setDifficulty] = useState<Difficulty>('normal');
const [buttonCount, setButtonCount] = useState<ButtonCount>(4);
const [bestScore, setBestScore] = useState<number | null>(null);
const [activeButton, setActiveButton] = useState<number | null>(null);
const [soundEnabled, setSoundEnabled] = useState(true);
const [mounted, setMounted] = useState(false);

const audioContextRef = useRef<AudioContext | null>(null);
// Track ALL scheduled timeouts so we can clear them on unmount / restart
const timeoutsRef = useRef<Array<ReturnType<typeof setTimeout>>>([]);

const clearScheduledTimeouts = useCallback(() => {
if (timeoutsRef.current.length) {
timeoutsRef.current.forEach(id => clearTimeout(id));
timeoutsRef.current = [];
}
}, []);

const buttons = BUTTON_CONFIGS[buttonCount];

// Handle client-side mounting
useEffect(() => {
setMounted(true);
}, []);

// Get URL parameters on component mount
useEffect(() => {
if (!mounted) return;

try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Let’s move the window guard so hooks always run in the same order.

Right now we return early whenever window is missing, which means none of the hooks that follow will run in that render. React expects hooks to run every time in exactly the same order; skipping them can lead to mismatched state and the lint rule is catching that. A gentle fix is to remove the early return and instead gate your UI with the existing mounted flag (or add an isClient state set inside useEffect). That way each render still calls every hook, and you can still show null or a loading shell until the client is ready. Happy to walk through the refactor if you’d like!

🧰 Tools
🪛 Biome (2.1.2)

[error] 65-65: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 66-66: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 68-68: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 78-78: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 79-79: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 80-80: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 81-81: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 82-82: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 83-83: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 85-85: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 87-87: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 89-89: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 99-99: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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)


[error] 104-104: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

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/simon-says/play/page.tsx around lines 59 to 107, remove the
early return that checks typeof window === 'undefined' so all hooks always run
in the same order; instead rely on the existing mounted state (set to true in
the mounting useEffect) or add an isClient state set inside a useEffect, and
guard rendering/UI that depend on window or browser-only APIs with that
mounted/isClient flag (and ensure any direct window/audioContext usage is
wrapped behind the flag) so hooks are never conditionally skipped while still
rendering null or a loading placeholder until the client is ready.

Comment thread src/app/game/simon-says/play/page.tsx
- Remove early SSR return so hooks always execute in consistent order
- Rely on mounted flag for gating UI instead of skipping hooks
- Track 300ms activeButton release timeout in timeoutsRef for full cleanup
@Sainava

Sainava commented Oct 3, 2025

Copy link
Copy Markdown
Contributor Author
image image

Fixed the layout issues

@ajaynegi33
ajaynegi33 merged commit f8c6715 into ajaynegi33:main Oct 3, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request gssoc GirlScript Summer Of Code gssoc25 level3 size:XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[NEW GAME] Simon Says

2 participants