HomeMethodDinosaur game night mode
Dinosaur game night mode: a modulo check at 700
Night mode looks scheduled. It is not. The transition is a modulo test on a metered distance, and the score beside it is an integral of speed. The official project already publishes the speed rule. This page is the light/dark rule in the same file, plus the scoring expression the modulo sits on.
Independent guide. Not official documentation, and not affiliated with the project's authors. The official site documents the speed rule. This page covers the light/dark cycle and the scoring integral. The jump walkthrough is the third rule in the file.
The behaviour, stated so it can be wrong
- Trigger: run without colliding.
- Observable output: the palette inverts at distance intervals, and the spacing between transitions shrinks as the run accelerates.
- Constraint: if the trigger were a timer, intervals would be evenly spaced in time regardless of speed. They are not.
Findings
Read 18 Oct 2026 from the browser edition's main script at commit 5455bfa408ec6b707c7300ff194b7390733a766d. The repository's master path now returns 404. The SHA is the citation.
| Observation | Evidence | Confidence | What it does not prove |
|---|---|---|---|
INVERT_DISTANCE: 700, INVERT_FADE_DURATION: 12000 | Runner.config, index.js @ 5455bfa | High — values | The unit of 12000. Milliseconds, frames, or a phase limit is decided by invert(), which we did not read. |
invertTrigger = !(actualDistance % INVERT_DISTANCE), where actualDistance = distanceMeter.getActualDistance(Math.ceil(distanceRan)) | the night-mode block of update() | High | The scaling inside getActualDistance — we read the call, not the method |
distanceRan += this.currentSpeed * deltaTime / this.msPerFrame, only when there is no collision | update() | High | Displayed score: the meter applies its own rounding and formatting |
msPerFrame = 1000 / FPS, FPS = 60 | constructor and top of file | High | Anything about a 120 Hz display, where deltaTime is not equal to msPerFrame |
SPEED: 6, ACCELERATION: 0.001, MAX_SPEED: 13 | same config object | High | Where acceleration is applied. The constants were verified. The call site was not. |
CLEAR_TIME: 3000 gates whether obstacles exist yet | hasObstacles = runningTime > CLEAR_TIME | High | Whether the first obstacle spacing is seeded from it |
HEIGHT = 150, DEFAULT_WIDTH = 600, BOTTOM_PAD: 10 | same config | High | — |
| Two night pieces, inverted mid-switch | invert() references INVERT_IDLETIME and a blink amount/duration pair | Low | Their values are not in what we read. Do not quote them. Open the config block yourself. |
| Night mode also changes the obstacle colour | — | — | Not confirmed. Visible in play. The code path was not verified. |
Why !(metered % 700) is a fragile line. It fires only when the remainder of the metered value is exactly zero. Distance accumulates as real numbers, then passes through getActualDistance, which we did not read. On a steady 60 Hz run the raw counter can land on 700, 1400, 2100. If a frame is dropped, an increment can step over a multiple. Whether the meter still reports an exact multiple is part of the unread scaling. The prediction is that night mode gets less regular when the frame rate is unstable.
The rule, in pseudocode
every clean frame:
distance += speed * deltaTime / (1000 / 60)
if speed < 13: speed += 0.001
if fadeCounter > 12000:
fadeCounter = 0; trigger = false; invert()
else if fadeCounter: fadeCounter += deltaTime
else:
metered = distanceMeter.actualDistance(ceil(distance))
trigger = (metered % 700 == 0)
if trigger and fadeCounter == 0:
fadeCounter += deltaTime; invert()The score is an integral
The same accumulator feeds the score. Each clean frame adds speed * deltaTime / msPerFrame. Early in a run the speed is 6, so a second of play adds less distance than a second near the cap of 13. The number on screen is that integral after the meter rounds it. A collision stops the addition.
Three derived numbers, arithmetic on the raw accumulator only — not measurements, and not the metered clock. At the starting speed of 6, 700 raw units take about 700 / 6 ≈ 117 frames, roughly 1.9 s. Reaching the ceiling of 13 takes (13 − 6) / 0.001 = 7,000 updates, about 117 s at 60 fps. Near maximum speed the same 700 raw units pass in about 700 / 13 ≈ 54 frames, roughly 0.9 s. The sky would change about twice as fast at the end of a run as at the start, if the meter does not rescale the interval. That last clause is the gap.
The 4,000 and 10,000 checks reproduce the official speed lab's published numbers from constants alone. If this arithmetic agrees, the acceleration rule and the ceiling are the same rule we read. Numbers are computed on click.
| After N clean updates | Speed | Distance units | Raw 700-multiples crossed | Elapsed (60 fps) |
|---|---|---|---|---|
| not run yet | ||||
The modulo, timed
The interval in raw distance is constant, so the interval in time shrinks as speed rises. The harness below integrates those two verified rules. It does not apply getActualDistance, because that scaling was not read.
Integrates the speed rule and the 700-unit interval. Frame rate is a control because deltaTime makes the game time-based.
press PredictTry it yourself
Use REA to inspect the loaded script of a browser dinosaur game
(JavaScript layer only). Do not explain the speed rule — the project
already documents it elsewhere.
Report each with file and line evidence:
- every value that gates the day/night transition, and the condition
that actually fires it
- the expression that accumulates distance, and whether a collision
stops it
- the transformation between the accumulated value and the value the
transition test uses
- anything you cannot locate, stated as unresolved rather than assumed
Do not rebuild anything yet.Then compare the agent's answer against the harness. A model that skips getActualDistance and treats raw distanceRan as the modulo input is missing the transformation this page could not finish. The same counter drives the jump lab's distance readout. Constants differ across write-ups because the Chromium copy and community copies are different files.
What we could not confirm. getActualDistance is called on the raw accumulator, and it scales and rounds before the modulo. So "every 700 units" is true of the metered value, and the 1.9 s / 0.9 s estimates use raw units. They are approximations, not the game's clock. The meter's scaling factor is the thing standing between this page and a confirmed interval. Also unread: the unit and consumers of INVERT_FADE_DURATION; whether invert() is a phase state machine or a linear fade; the idle and blink values; and whether the modulo trigger misses on low frame rates in practice. A short recording with frame timestamps settles the last one.
Next
The vertical axis
Why holding jump changes height, and why 120 px and 126 px are both predictions.
Walkthrough →MethodThe loop
Where step 6, diff against the original, comes from.
Read the loop →SpeedThe official half
Start at 6, add 0.001 per frame, cap at 13. Our lab measures the arc, and links the speed example.
Dino lab →