4 Commits

Author SHA1 Message Date
9fa46493a8 Hidden mini-game: single-table pinball (#/pinball)
A small canvas pinball engine (src/lib/pinball.js): fixed-timestep physics
with 5 substeps, circle-vs-segment collision, two rotating flippers whose
angular velocity drives the ball, 3 pop bumpers, 2 slingshots, a charged
plunger, 3 balls. Lighting all 3 bumpers "catches" a random Pokémon for a
bonus. Ball-search kicks a wedged ball toward centre; three strikes and it
drains. High score in pdx.pinball.

Hidden like "Who's that Pokémon?" — no nav entry; the two games
cross-link from each other's back-nav, or reach it at #/pinball.

Controls: ← / → (also A/L, Z) flippers, hold Space / the Launch button for
the plunger; on touch, tap the table's left or right half.

Rendering: the canvas is sized from its container with a DPR-capped
backing store (crisp on any display). `_frame()` is exposed so the physics
can be driven headlessly. 3 unit tests for the geometry helpers.

The physics are stable and the game loop is complete; feel (flipper
strength, ball speed, table balance) still wants hands-on tuning.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-10 14:18:11 -04:00
55d26f50ed Who's that Pokémon?: fuzzy guessing + a generation filter
Fuzzy: src/lib/fuzzy.js — editDistance + closeEnough (length-scaled typo
tolerance, 0 for names ≤4 chars). submitGuess() accepts a near-miss, so
"charizrd" counts. Plus inline ghost-text completion: once the typed
prefix matches exactly one Pokémon, the rest of the name shows greyed
after the caret; → (at end), Tab or End accepts it.

Generation filter: a "Pull from" select (All / Gen 1–9, built from the
snapshot's species.generation). Choice persists in pdx.whosThat.gen;
changing it reshuffles the pool (and the completion list) and resets the
streak.

7 new unit tests for fuzzy.js (48 total).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-10 13:19:03 -04:00
a57e516f16 Who's that Pokémon?: bright stage so the silhouette shows in dark mode
The stage used var(--surface), so a brightness(0) silhouette was
near-invisible on a dark theme. Make it a fixed light "TV screen"
(blue→white gradient) in every theme; move the caption/hint out onto the
page background so they stay readable; add a drop-shadow to the revealed
artwork.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-10 12:52:56 -04:00
fb299d11f9 Hidden mini-game: "Who's that Pokémon?"
Guess the Pokémon from its silhouette (official artwork, filter:brightness(0)
until revealed). Streak + best + win% persisted in pdx.whosThat. Three
misses auto-reveal; hints (letter count, then first letter) after wrong
guesses; guess matching is punctuation/space/case-insensitive.

Not in the nav or any link. Reached by the Konami code (↑↑↓↓←→←→BA,
lib/konami.js wired in main.js), seven quick taps on the nav wordmark, or
the bare #/whos-that hash once you know it.

9 new unit tests for the konami matcher (sequence, case-insensitivity,
rewind, partial).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-10 12:34:45 -04:00