The game can be run as a standalone html or integrated within JsPsych.
Play the game:
?level=N starts at a level and plays on to the end; ?levels= runs only the levels listed and
then finishes, as a range (?levels=1-3), a list (?levels=1,3) or a mix (?levels=1-2,5).
?gamified=0 runs a barebones version of the same tasks — no cover screen, cutscenes, artwork,
character, score, sounds or trial feedback, just abstract red stimuli on grey — for comparing
gamified against standard experimental presentation. Trial timing, the adaptive threshold, the
stimulus geometry and the data schema are identical to the game’s; each data file records which
condition it came from in gameParams.gamified. It combines with the switches above
(?gamified=0&levels=1-3&trials=3).
The game plays on touch devices: a tap replaces SPACE, and on the two-alternative levels (2-5) the left and right halves of the screen replace the arrow keys. Prompts and instructions name the gesture rather than the key, and the cutscene is advanced with a tap and skipped with a held finger. The stage is a fixed 16:9, so the game asks to be held sideways — Android is pinned to landscape once it is granted fullscreen, while on iPhone (where Safari supports neither the Fullscreen API nor an orientation lock) the rotate prompt is the whole mechanism.
?touch=1 forces the touch path on a desktop and ?touch=0 forces it off, which is how to look at
either presentation without the matching hardware.
Touch responses are not keyboard responses. They are slower and noisier, and how much depends
on the handset, so a mobile run is not directly comparable with a desktop one. Each level’s
gameParams records inputModality (touch / keyboard) and the viewport it ran at; treat the
two as separate populations rather than pooling them.
Studies:
Current Content
Scientific summary
DoggoNogo is a browser-based gamified neuropsychological battery designed to measure cognitive control constructs, such as processing speed, response inhibition, and conflict monitoring, through an engaging narrative game. The underlying paradigms (simple reaction time and a Simon-task variant) are well-established in experimental psychology. By embedding them inside a progression-based game with animated sprites, sound, and a points system, the battery aims to increase participant engagement and ecological validity compared to traditional lab tasks. The task is designed to be administered online as part of a larger jsPsych experiment or as a fully standalone web page.
Technical summary
The app is a pure client-side HTML5 application with no build step and no dependencies. It is written as native ES modules, so it is served over HTTP rather than opened straight from the filesystem. The rendering target is a <canvas> element that scales responsively to the viewport via CSS. The codebase is organized as follows:
| File | Role |
|---|---|
game/assets.js |
Asset manifest (DoggoNogoAssets) consumed by the global preloader |
game/game.js |
Shared UI helpers: score-screen animation, zScoreToQuantile, loading screen, asset preloader (DoggoNogoCore), trial-type constants, end-of-level computeIES |
game/core.js |
DoggoNogoBaseLevel: shared level mechanics (player physics, rendering scaffolding, phase progression, scoring helpers, input plumbing) that each level inherits via its prototype |
game/engine.js |
Central DoggoNogoEngine — orchestrates asset loading, cover screen, cutscene, instruction screen, requestAnimationFrame game loop, marker (photodiode) support, and the end-of-level score screen |
game/cutscene.js |
CutsceneRunner — a generic step-sequenced cutscene player (fill / text / image / sound / wait steps) plus inline cutscene-asset loader |
game/levels/level1.js |
All logic for Level 1 (Simple RT) as a single self-contained level1 object |
game/levels/level2.js |
All logic for Level 2 (Simon task) as a single self-contained level2 object |
game/levels/cutscenes.js |
Level 1 and Level 2 cutscene sequence definitions |
game/jspsych.js |
Thin jsPsych integration layer: creates jsPsychCallFunction trials, manages canvas lifecycle inside the jsPsych display element, and serialises per-trial data back into jsPsych’s data store |
game/index.html |
Standalone entry point |
example_jspsych.html |
Minimal jsPsych integration example |
Levels expose a uniform interface (load, showInstructionScreen, start, update, draw, handleResize) consumed by the engine, and share their common mechanics through a DoggoNogoBaseLevel prototype (game/core.js). Each level rebuilds its mutable state from getInitialState() on every start(), so a level can be run more than once in a page without carrying anything over. Asset paths are relative and accept a configurable assetBasePath so the game can be served from any directory. An optional marker square (for physiological synchronisation via a photosensor) can be enabled via markerEnabled: true and flashes on stimulus onset.
Scientific summary
Level 1 implements a Simple Reaction Time (SRT) task, one of the most fundamental measures in cognitive neuroscience. A single stimulus appears at a pseudo-random screen position after a variable inter-stimulus interval (ISI: 0.5 - 3.5 s); the participant must press a single key (ArrowDown) as quickly as possible. Because there is only one possible stimulus and one possible response, the task requires no discrimination or selection: it measures the lower bound of sensorimotor processing speed free from decision conflict.
Responses are classified as:
The adaptive median RT threshold (initialised at 1 000 ms, updated after every valid trial using a running median) serves a dual purpose: it provides an individually-tailored difficulty parameter so the task remains challenging regardless of baseline speed, and it functions as the decision criterion separating fast from slow trials. The parameter gameDifficulty (default 1) divides the median to shift this threshold (> 1 makes it easier; < 1 makes it harder).
The end-of-level performance score is IES (Mean correct RT / (1 − Error Rate)), where errors are defined as commission failures (early presses before stimulus onset) and omission timeouts (no response within 2 * median RT). The resulting score is Z-scored against population parameters (populationMean, populationSD) and converted into a percentile reflecting the percentage of players beaten, which is displayed in the end-of-level animation.
Technical summary
The level is structured as a plain JavaScript object (level1) with three top-level sections: params (static configuration), assets (preloaded Image and Audio objects), and state (all mutable runtime data). The game logic runs entirely inside the engine’s requestAnimationFrame loop, which calls level1.update() (physics + timer management) and level1.draw() (canvas rendering) every frame.
Key implementation details:
requestAnimationFrame loop reveals the stimulus on the first frame at or after it; because a frame drawn during callback N is only presented at frame N+1, the onset timestamp used for RT is taken from that following frame, and reaction times are computed from the event.timeStamp of the keypress rather than from a clock read inside the handler. This removes both timer jitter (4–15 ms) and the one-frame bias that inflates RT, at the cost of quantising onsets to the display’s refresh boundaries — which is what the hardware does anyway. The realized interval is logged per trial as ISI, so onset accuracy can be audited offline. A response arriving before the onset frame is recorded as an early press, since the participant cannot yet have seen the stimulus.DoggoNogoCore.samplePseudoExponentialISI(minISI, maxISI, meanISIDecay) (game/game.js) rather than a uniform distribution, so the hazard of stimulus onset stays roughly constant over the wait instead of rising as the interval elapses — reducing delay vs. temporal-expectancy confounds in RT. Min. ISI = 500ms, Max. ISI = 3500ms, Mean decay = 1000ms correspond to ~5% of clipped trials at the upper bound and an average of 1450ms.stimulusFallDistance = 5 % of canvas height) before the response window closes, providing a visual onset cue.minJumpStrength and maxJumpStrength based on normalised RT, giving faster responses a visually more impressive jump.trialsNumber is a theoretical target, not a hard cap — actual trial count depends on performance. At each phase break the score target for the next phase is recomputed: it distributes the remaining theoretical valid trials across remaining phases, assumes ~50 % will be fast (earning at least minScore), and takes the max of that estimate and the per-phase floor max(minScore, (minTrialsPerPhase / 2) × minScore). A consistently fast player reaches targets slightly sooner (fewer actual trials); a slower/less accurate player needs more — but recomputing at each break nudges the total toward trialsNumber. Early presses and timeouts are excluded from the trial counter.imgPlayer1/2/3) swaps, accompanied by a sparkle particle system and a sound effect, providing intrinsic gamification rewards.level1.state.data (also exposed as window.level1Data). Fields include: RT, TrialType ("fast"/"slow"/"early"/"timeout"), Error (0/1), Points, Score, Phase, StimulusX/Y, Threshold, ISI (realized interval from scheduling to onset).Scientific summary
Level 2 implements a gamified Simon task, a canonical paradigm for measuring inhibitory control and conflict monitoring. Unlike Level 1, the stimulus can appear on either the left or right side of the screen (or, in Phase 2, above/below). The participant responds with a directional key (ArrowLeft / ArrowRight) that must match the orientation of the stimulus object (a fishbone pointing left or right) — not necessarily its spatial position. This creates a potential conflict between the automatic tendency to respond toward the side where the stimulus appears (the Simon effect) and the correct rule-based response based on stimulus direction.
The level progresses across three phases of increasing cognitive demand:
| Phase | Trial types | Cognitive demand |
|---|---|---|
| Phase 1 (congruent only) | Stimulus position always matches required response direction | Baseline visuomotor compatibility; no conflict |
| Phase 2 (congruent + neutral) | Adds vertically spawned stimuli (top/bottom) with no lateral position cue | Neutral condition; introduces spatial uncertainty without direct conflict |
| Phase 3 (congruent + incongruent) | Adds horizontally spawned stimuli where position opposes required response direction | Maximal Simon interference; requires active response inhibition |
Incongruent trials in Phase 3 are expected to produce longer RTs and higher error rates than congruent trials — the Simon effect — quantifying the efficiency of the participant’s inhibitory control. Errors (incorrect direction key) are penalised (−minScore/2) and logged with difficulty: "incongruent"/"congruent"/"neutral" for downstream contrast analysis. The neutralProportionPhase2 and incongruentProportionPhase3 parameters allow researchers to adjust the conflict load without changing game structure.
ike Level 1, Level 2 computes the end-of-level IES and percentile using DoggoNogoCore.computeIES. In Level 2, the error rate reflects directional choice errors (pressing the wrong arrow key), early presses, and omission timeouts.
Technical summary
Level 2 shares the same object interface and engine as Level 1 but adds the following mechanisms:
trialsNumber uses a simpler fixed-target scheme than Level 1. At level start: perPhaseTrials = ceil(trialsNumber / 3) and every phase gets the same constant target perPhaseTrials × minScore. There is no adaptive recomputation between phases. As in Level 1, early presses do not increment the trial counter, so participants who make many commission errors will see more stimulus presentations to accumulate the required score.stimulus_1.png, stimulus_2.png — fishbones facing different directions) are randomly assigned to left/right sides once, counter-balancing across participants."left", "right", "top", "bottom") is drawn stochastically based on the current phase’s conflict proportions. Left/right spawns place the stimulus at a fixed horizontal edge; top/bottom spawns (stimulusLocationTopY, stimulusLocationBottomY) are the neutral condition, carrying no lateral position cue.incongruentProportionPhase3. For top/bottom spawns the response is always determined purely by the image direction (neutral by definition).playerFacing state ("left" / "right") is updated on each correct response and the sprite is horizontally flipped via ctx.scale(-1, 1), reflecting the direction of the last correct response.sound_error.mp3, and deducts points — providing salient negative feedback without ending the trial prematurely.RT, TrialType, Error, Points, Score, Phase, StimulusRegion ("left"/"right"/"top"/"bottom"), StimulusDifficulty ("congruent"/"neutral"/"incongruent"), ResponseKey, Threshold, ISI.The arc is “Bone fever”, a story about impulsivity that sets up the command-training level that follows it (sprite, background and cutscene prompts in prompts/make_prompts.py, under the Level 3–5 steps; cutscene text in game/levels/cutscenes.js):
drawSausage in game/stimuli.js). The sausage was chosen because its tip is a single point on the axis and its link string is the classic fin, with nothing to justify. The story beats above, the instruction text, the Level 4 cutscene and the “WRONG BONE!” feedback bubble still assume ribbons and bones and need reworking around strings of sausages (e.g. Nogo raiding the Chef’s cold room); the Müller-Lyer design itself is unchanged.level5.js predates this plan and will be reframed or moved.Parked story ideas (kept for later levels):
Go/No-go: after Level 5’s scolding, Doggo is trained to follow commands (fetch on “GO”, hold on “STAY” or the whistle) to earn his badge. He gets a collar with a medal at the end of it.