Skip to content

feat: Add Otter Stop! — go/no-go rapid reaction game#39

Merged
acrosman merged 13 commits intomainfrom
copilot/create-rapid-choice-reaction-game
Apr 4, 2026
Merged

feat: Add Otter Stop! — go/no-go rapid reaction game#39
acrosman merged 13 commits intomainfrom
copilot/create-rapid-choice-reaction-game

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 4, 2026

Adds a new inhibitory control training game where players must respond to each otter stimulus by pressing Space or clicking the image, except when the designated no-go otter appears. Implements an adaptive staircase: 3 consecutive correct no-go inhibitions advance one level (faster display), 3 consecutive wrong responses drop two levels.

Game mechanics (game.js)

  • Go stimuli are discovered at runtime by scanning images/go/ — drop any PNG or JPEG into that folder to add it as a go image; no code changes needed
  • 25% no-go rate: one no-go stimulus against however many go images are present
  • Display interval: 1500 ms at level 0, −50 ms/level, floor 150 ms
  • Tracks score (correct responses), no-go hits (false alarms), and misses separately
  • Level advancement counts only correct no-go inhibitions — 3 successful stops in a row → level +1; correct go responses score points but do not affect the streak
  • Force-go after wrong — after any wrong outcome (missed go or false alarm), the next trial is always a go image, giving the player a fair recovery chance before facing another no-go

Plugin controller (index.js)

  • Space keypress or mouse click on the stimulus evaluated immediately — clears the trial timer and calls endTrial() inline
  • Go images require active response — if the player does not press Space or click before the display window expires, it is scored as a miss and "Too slow!" feedback is shown for 800 ms
  • Differentiated feedback messages: "Great stop!" (correct inhibition), "Oops — too fast!" (false alarm on no-go), "Too slow!" (missed go image)
  • All wrong outcomes (missed go images and false alarms) show an 800 ms feedback pause before the next trial; correct go responses proceed immediately to maintain pace
  • On init(), calls the games:listImages IPC channel to populate go image keys from images/go/ before the player clicks Start
  • Progress saved using load → merge → save pattern — loads existing player progress, merges updated stats (highScore, highestLevel, lowestDisplayTime, sessionsPlayed, lastPlayed) into games['otter-stop'], then saves the full record; best score and max level are displayed on the game selection card
  • Play Again returns the player to the instructions screen; Start Game must be clicked to begin a new session
  • Return to Menu dispatches bsx:return-to-main-menu to navigate back to the game selection screen
  • Space bar always calls preventDefault() while the component is mounted, preventing page scroll on any screen (instructions, mid-trial, end panel)

UI

  • Three-step flow: Instructions → Game play → End panel → (Play Again) → Instructions
  • Instructions panel is correctly hidden when Start Game is clicked and restored when Play Again is clicked
  • Feedback overlay displayed inside the stimulus box — success/failure image fills the same area as the go/no-go image, overlaid with a semi-transparent white background; text label appears below the image within the overlay
  • Stimulus display area scales responsively with clamp(260px, 50vmin, 500px) so the game fits vertically without scrolling on most displays
  • Stimulus area is clickable (role="button", tabindex="0", pointer cursor) as an alternative to Space bar
  • Instructions and reminder text explicitly state that responding to every go otter is required, not optional

IPC additions (main.js / preload.js)

  • New games:listImages handler accepts { gameId, subfolder } and returns a sorted list of PNG/JPEG filenames from the given game's image subfolder
  • preload.js exposes games:listImages on the invoke allowlist

Image layout

images/
  go/           ← all go stimuli (PNG or JPEG); scanned at runtime
    go-1.png
    go-2.png
    go-3.png
  no-go.png     ← no-go stimulus
  success.png   ← correct-inhibition feedback
  failure.png   ← wrong-response feedback
  thumbnail.png ← game card thumbnail

Placeholder 1×1 PNGs are committed; replace in place with final art using the names above. Additional go images can be added by dropping files into images/go/.

Structure

Follows the existing plugin layout: manifest.json, game.js (pure logic), index.js (DOM/controller), interface.html, style.css, images/, tests/.

Copilot AI linked an issue Apr 4, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Add rapid choice reaction game for inhibitory control training feat: Add Otter Stop! — go/no-go rapid reaction game Apr 4, 2026
Copilot AI requested a review from acrosman April 4, 2026 01:18
Copy link
Copy Markdown
Owner

@acrosman acrosman left a comment

Choose a reason for hiding this comment

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

This is a good start but need a lot of work. Like the other games it should have a screen with instructions and then a separate game play around.

In the game play area the images need to be larger to make the interface more immersive.

Most importantly, the game requires no interaction – this is totally wrong. If I do nothing at all the game thinks I'm doing it right. It should require interaction after the go images the player should be shown the image for equal time as they have to react with the space bar or mouse click. If they don't act on the image they are wrong.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

This is a good start but need a lot of work. Like the other games it should have a screen with instructions and then a separate game play around.

In the game play area the images need to be larger to...

Fixed in commit 3867233. Here's what changed:

Go images now require active response. When a go image's display window expires without a press or click, it's scored as a miss and "Too slow!" feedback appears for 800 ms — same pause as no-go feedback. There is no longer any way to score points without interacting.

Differentiated feedback messages:

  • ✅ "Great stop!" — correctly withheld on the no-go otter
  • ❌ "Oops — too fast!" — pressed Space/clicked on the no-go otter (false alarm)
  • ❌ "Too slow!" — didn't respond to a go otter in time

Mouse click support. Clicking anywhere on the stimulus area counts as a response (Space or click). The element is a role="button" with tabindex="0" and a pointer cursor for clarity.

Larger stimulus. The display area grew from 300×300 → 500×500 px with images up to 440×440 px for a more immersive feel.

The instructions and reminder text were also updated to make clear that responding to every go otter is required, not optional.

Copilot AI requested a review from acrosman April 4, 2026 02:57
@acrosman
Copy link
Copy Markdown
Owner

acrosman commented Apr 4, 2026

@copilot the game now does require player input, but is unplayably fast. The first few rounds should be slower, more like 1 second or 1/2 second.
It also need to have the introduction screen moved to it's own step.
Finally the end game button stops the game. But there is no way back the main screen.
All games should follow the same pattern in this regard – and the rest do. Review one of the other games to use help mimic their structure.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

@copilot the game now does require player input, but is unplayably fast. The first few rounds should be slower, more like 1 second or 1/2 second.
It also need to have the introduction screen moved t...

Fixed in commit 5c7919d:

Slower start speed — Base interval increased from 700 ms → 1500 ms (matching the starting pace of other games). Speed reduces by 50 ms per level as accuracy improves, down to a 150 ms floor.

Return to Menu fixed — The button was dispatching game:return-to-menu instead of bsx:return-to-main-menu. The main app shell only listens for bsx:return-to-main-menu, which is why nothing happened. Fixed to use the same event as every other game.

Intro screen as its own step — The Play Again button now calls reset() only (returns to the instructions screen) instead of reset(); start();. The player must click "Start Game" again, making the intro a distinct, required step in the flow: Instructions → Game → End Panel → (Play Again) → Instructions.

@acrosman
Copy link
Copy Markdown
Owner

acrosman commented Apr 4, 2026

@copilot That's better. But we still need to adjust the startup process. It needs to have screen with instructions that disappear when the player clicks start game. The display also needs to prevent the default event when the player presses space to avoid it scrolling down. Ideally the whole game would fix vertically without scroll on most displays.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

@copilot That's better. But we still need to adjust the startup process. It needs to have screen with instructions that disappear when the player clicks start game. The display also needs to prevent ...

Fixed in commit 9c28ce5:

Instructions screen — The root cause was that .os-game-area { display: flex; } in the CSS was overriding the browser's [hidden] { display: none } from the UA stylesheet, so the game area was visible even with the hidden HTML attribute set. Added [hidden] { display: none !important; } to style.css (the same fix used by fast-piggie and high-speed-memory). The instructions panel now correctly hides when Start Game is clicked and reappears when Play Again is clicked.

Space bar scroll preventionevent.preventDefault() is now called immediately after detecting a Space key press, before any game-state checks. Space no longer scrolls the page on the instructions screen, between trials, or on the end panel.

Vertical fit without scroll — The stimulus area changed from a fixed 500×500 px to clamp(260px, 50vmin, 500px), so it scales down automatically on smaller displays. The section padding and gap were also tightened, and min-height: calc(100vh - 160px) was added to fill the available space — matching the pattern used by high-speed-memory.

@acrosman
Copy link
Copy Markdown
Owner

acrosman commented Apr 4, 2026

@copilot The main layout issues are fixed, but we still have at least two issues to fix.

First, when the success and failure images appear they are below the game area. The should display in the area.

Second the advance and step back levels don't behave as expected. It should more clearly delineate when it is going up a level and back down. 3 rights answers in a row is three successful ignoring of no-gos. After a wrong answer, always start with a go image.

…ions, force-go after wrong

Agent-Logs-Url: https://github.com/acrosman/BrainSpeedExercises/sessions/c847055a-1c95-4b65-b54f-a9f5ed44f485

Co-authored-by: acrosman <2972053+acrosman@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

@copilot The main layout issues are fixed, but we still have at least two issues to fix.

First, when the success and failure images appear they are below the game area. The should display in the ar...

Fixed in commit cf4e961:

Feedback overlay inside the stimulus area — Moved #os-feedback inside #os-stimulus in the HTML and changed its CSS to position: absolute; inset: 0; background: rgba(255,255,255,0.93); border-radius: 12px; z-index: 2. The feedback image and text now overlay the otter image within the stimulus box instead of appearing below it.

Level advancement — The consecutiveCorrect streak now only increments on correct no-go inhibitions (isNoGo && !spacePressed). 3 successful stops → level +1. Correct go responses still score +1 and reset the wrong streak, but they don't advance the level.

Force go after a wrong answer — A forceGoNext flag is set whenever any wrong outcome occurs (missed go or false alarm on no-go). pickNextImage() checks this flag and, if set, always picks from the go images and clears the flag immediately. The player is guaranteed a go stimulus on the very next trial after any mistake.

@acrosman
Copy link
Copy Markdown
Owner

acrosman commented Apr 4, 2026

@copilot We are getting close.

The success and failure images should display at the same size as the go and no-go images.

Move all go images into a folder, and then instead of loading the list by a pre-defined list of name, load all PNG and JPEG files in that folder as go images.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

@copilot We are getting close.

The success and failure images should display at the same size as the go and no-go images.
...

Fixed in commit 061a9a5:

Feedback images same size as stimulus — Changed .os-feedback__img from a fixed 120px cap to flex: 1; min-height: 0; width: 100%; object-fit: contain. The feedback overlay already fills the entire stimulus box (position: absolute; inset: 0), so the image now expands to fill the same area as the go/no-go images.

Go images moved to images/go/ and loaded dynamicallygo-1.png, go-2.png, go-3.png moved to images/go/. A new games:listImages IPC channel (wired through main.js and preload.js) reads the directory at startup and returns all PNG/JPEG filenames. index.js calls this channel on init() and updates the game's image pool via game.setGoKeys(). To add new go images, drop any PNG or JPEG into images/go/ — no code changes needed.

@acrosman
Copy link
Copy Markdown
Owner

acrosman commented Apr 4, 2026

@copilot the otter stop game does not appear to save high scores, at least not in a way that allows them to be loaded on the main screen card. It should record results like other games and display the best score on the main screen.

…ter Stop appears on game card

Agent-Logs-Url: https://github.com/acrosman/BrainSpeedExercises/sessions/18b7ae7b-dcd7-4fd9-a389-07cb946249db

Co-authored-by: acrosman <2972053+acrosman@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

@copilot the otter stop game does not appear to save high scores, at least not in a way that allows them to be loaded on the main screen card. It should record results like other games and display the...

Fixed in commit 70421de. The stop() function was calling progress:save with a flat { playerId, gameId, score } payload — not the nested format the progress manager and game card expect.

It now follows the same load→merge→save pattern as the other games:

  1. Loads the existing player progress record
  2. Merges updated otter-stop stats: highScore (keeps the max), highestLevel (keeps the max), lowestDisplayTime (keeps the fastest), sessionsPlayed (+1), lastPlayed (ISO timestamp)
  3. Saves the full record back via progress:save

The game card will now show Top Score and Max Level for Otter Stop! the same way it does for the other games.

acrosman added 2 commits April 4, 2026 16:32
…m:acrosman/BrainSpeedExercises into copilot/create-rapid-choice-reaction-game

* 'copilot/create-rapid-choice-reaction-game' of github.com:acrosman/BrainSpeedExercises:
  fix: save highScore, highestLevel and lowestDisplayTime on stop so Otter Stop appears on game card
@acrosman acrosman marked this pull request as ready for review April 4, 2026 21:34
@acrosman acrosman merged commit dbaea4c into main Apr 4, 2026
4 checks passed
@acrosman acrosman deleted the copilot/create-rapid-choice-reaction-game branch April 4, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a Rapid Choice Reaction Game

2 participants