Where in Time  /  How it works

← back to game

How it works

The short version: five 360° panoramas a day, drawn from a curated pool of 374 historically anchored scenes. You drop a pin on Earth and pick a year. Both get scored on a curve calibrated to the scene's era.

The longer version is below — the math, the pools, the pipeline, the rules.

The five-round arc

Each daily session is five rounds. Each round:

  1. You're dropped into a 360° historical panorama. Look around — the architecture, costumes, technology, landmarks are the clues.
  2. Drop a pin on the world map (powered by Leaflet) for where on Earth the scene takes place.
  3. Scrub the year picker to your guess for what year.
  4. Submit. You get a Wikipedia summary of the actual event, the real coordinates, the real year, your distance miss in km, and your year miss.
  5. Repeat four more times. End-of-session shows a totaled score, a per-round breakdown, and a Wordle-style emoji-block share.

Per-era scoring math

Each round scores two dimensions independently: distance and year. Both use Gaussian decay — the score falls off smoothly with distance from the right answer, not via hard cutoffs.

The interesting design problem was the year score. A 50-year miss in 2000 BCE shouldn't score the same as a 50-year miss in 1980. The historical record for the Modern era is dense — 50 years off is a generation, three regimes, and the Internet. The Ancient era's record is sparse — 50 years off is dynastic noise.

So the year score is scaled per era. Each era pool has its own sigma (the curve's standard deviation), tuned to the era's typical date-resolution:

EraYear rangeYear sigma (≈)What that means
Ancient≤ 500 CE~500 yrLoose. A century off can still score well.
Medieval501–1500~200 yrMedium. Decades count, but not severely.
Renaissance1501–1900~80 yrTighter. The historical record is denser.
Modern1901+~25 yrTight. A decade matters.

Sigma values are approximate and may shift as the calibration loop runs against player data.

Worked example: Hammurabi

Scene: Hammurabi's Babylon, ~1792 BCE (Ancient pool, sigma ≈ 500 yr).

Your guess: 1850 BCE. Miss: 58 years.

58 ÷ 500 ≈ 0.12σ off. The Gaussian score is exp(-(0.12²)/2) ≈ 0.993 — you keep ~99% of the max year-points.

Now imagine the same 58-year miss in the Modern pool (sigma ≈ 25): 58 ÷ 25 ≈ 2.32σ off. The Gaussian score is exp(-(2.32²)/2) ≈ 0.07 — you keep ~7% of the max year-points.

Same numerical miss. Wildly different scores. That's per-era calibration.

Distance scoring uses a similar Gaussian decay, calibrated to give meaningful credit even when you pin the right continent but the wrong country. The exact distance sigma is the same across eras — Earth hasn't moved.

The four era pools

Scenes are bucketed into four non-overlapping era pools. Daily mode draws one scene per pool plus a fifth from the full set; Casual mode (coming soon) lets you pick a pool and play only from it.

As of 2026-05-13 the library has 374 scenes:

PoolYear rangeScenes
Ancient≤ 500 CE89
Medieval501–150089
Renaissance1501–190098
Modern1901+98
Total 374

The pools are deliberately non-overlapping. A scene tagged 500 CE is Ancient; 501 CE is Medieval. The transitions aren't historically perfect — no four-bucket split is — but they map roughly to broad-strokes Western periodization and keep the era-sigma calibration sane.

Why this split, not 5 or 7?

Four pools give enough granularity that "Ancient" doesn't mean both Sumer and Charlemagne, while staying few enough that Casual mode is a quick mental decision ("am I in a Medieval mood?"). Three was too coarse; five tested as analysis-paralysis.

The panorama generation pipeline

Each panorama is an AI-generated cinematic stitched into a 360° viewable sphere. The pipeline runs from scene draft to live game in about two minutes per scene, at roughly $0.36 in API costs:

  1. Scene card. A human-written prompt specifying the event, year, location, visual anchors (what landmarks/figures/objects must be identifiable in the frame), and rough composition.
  2. Cinematic still. gpt-image-2 generates the panoramic still from the prompt. About 90 seconds.
  3. Upscale. Topaz Photo AI upscales the still to the panorama resolution the sphere viewer requires. About 20 seconds.
  4. Difficulty rank. A second AI pass evaluates the scene and assigns a difficulty score (1–5). The signal is "how recognizable is the event from the panorama alone, to an American audience?" — recognizable events score easy; ambient-history scenes score hard.
  5. Upsert. The scene metadata lands in scenes.json; the panorama gets uploaded to Cloudflare R2.
  6. Review. A human (still me) plays the scene at /sphere-demo.html on localhost to spot-check before it ships.

The daily seed (deterministic, worldwide)

Every player who opens the game on the same calendar day gets the same five scenes. This is the Wordle move — the spoiler-risk is the social hook. If you and your group chat are playing on 2026-05-12, you're guessing the same Spartans-at-Thermopylae panorama at the same moment.

The daily seed is a deterministic hash of the date (UTC). Five scenes are drawn: one each from Ancient / Medieval / Renaissance / Modern, plus a fifth from the full pool. Recent scenes (the rolling 10 most-recently-used) are excluded to avoid same-week repeats.

The seed is cached server-side in Upstash Redis for the day, so every request to /api/round?mode=daily resolves to the same scenes without recomputing the draw.

The Earth-only rule

Effective 2026-05-07: every scene must occur on Earth (surface, atmosphere, or oceans).

This rule was added after a few off-planet scenes (Apollo 11 on the lunar surface, for example) shipped during the early library expansion. They were cool. They were unguessable. There was no pin you could drop on a flat map of Earth that scored well, because the scene wasn't on Earth.

The scoring math assumes Earth as the substrate. Breaking that assumption breaks the game. So: Earth-only, no exceptions, refused at draft time.

The full-color mandate

Effective 2026-05-08: every panorama must render in full color, even when the source reference photo is famously monochrome.

D-Day's Robert Capa photos are black-and-white. The first Moon landing's TV broadcast was grainy monochrome. Famous Civil War daguerreotypes are sepia. The instinct of an image model trained on those references is to reproduce the monochrome look. But Where in Time isn't a documentary recreation — it's a cinematic placement of you, the player, inside the scene as if you were there. You wouldn't have seen Omaha Beach in black and white. You'd have seen the slate gray of the Channel, the green of grass on the bluffs, the red of the blood in the sand.

The skill enforces this via an explicit color directive in the visual-style block and a B&W ban in the negative prompt.

Anti-cheat: the soft sign-in gate

Daily play is fully anonymous — no signup, no account. But leaderboard placement is a different problem. If you can submit a perfect-score result without identifying yourself, the leaderboard fills with anonymous "5000/5000" entries that are either lucky guesses, screenshot reads, or bots.

So once a session score crosses a threshold, the game prompts a soft sign-in via Google OAuth. You can decline — the score still records anonymously — but the leaderboard column is gated on the OAuth-verified identity. A pseudonym filter blocks the obvious impersonation attempts at submission time.

It's a low-friction filter that keeps the leaderboard meaningful without making the daily a signup wall.

The stack

The whole thing is intentionally boring infrastructure. No SPA framework, no GraphQL, no microservices, no Kafka. A game like this doesn't need them, and the "no build step" rule keeps iteration fast.

What's next

Casual+ (era-pick, unlimited daily rounds) is the next ship. Mastery mode and multiplayer ("Versus") are on the roadmap but not v1. See the FAQ for the public roadmap and press kit for assets.