Changelog
What's new, changed, and fixed on PlayMemorize
April 30, 2026
Improved
- improve Silhouette shows the full outline after you answer. Hard and Medium rounds clip the silhouette during the question (one half or one quadrant hidden). Once you pick an answer the full unclipped shape appears in the result panel so you can see what you were looking at before clicking Continue.
- improve Continue button is the same everywhere. Every game that ends a round with a Continue button (Who Did, When Did, He Did What, Silhouette, Order by When, Order by Size, Sort Em Up) now uses the same coral primary button, replacing the inline green / red styles that varied between games.
- improve Illusions is now a pure observation experience. The multiple-choice buttons are gone. Each round shows the illusion and its explanation immediately below it; a single Continue button advances to the next illusion. No wrong answers · the game is about seeing, not guessing.
- improve Where's MemPi 16-piece grid no longer stacks cells. A CSS containment conflict between
container-type: inline-sizeon cells andaspect-ratio: 1caused the grid to collapse in some browsers at low counts. Removed the per-cell container context; the badge overlay now scales from the wall container instead. - improve Changelog, About, blog posts and other content pages no longer show the Pi game-switcher dropdown. The shared header on content pages was inheriting the Pi game context from the layout default. Content pages now render the clean wordmark-only header, matching the home page.
- improve Difficulty selectors read Easy / Medium / Hard. Order by When, Order by Size, Sort em Up, Who Did, When Did, He Did What, and Silhouette previously offered the difficulty knob as numeric tiers (3, 5, 7, 9). Each game now shows the same three named tiers as the rest of the catalogue, mapped to the underlying difficulty values 3, 6, and 9.
- improve Silhouette gets harder at higher tiers. Easy still shows the full silhouette. Medium randomly slices off one quadrant (a quarter of the outline). Hard slices off one half. The clip is part of the deterministic round seed so a shared link or replay shows the same partial silhouette every time.
- improve Where's MemPi greets you before the run. The idle panel now opens with MemPi waving and saying hello in your language, so the player knows what they are looking for before the wall of decoys appears. The "Find MemPi · tap his cell" line that used to sit above the wall is gone · the wall is the prompt.
- improve Where's MemPi wall spacing is consistent at every count. The wall now uses container-relative gaps (cqi units) so the visual breathing room between cells stays the same whether you pick 16, 36, 64, 100, 144, or 256. Previously the absolute 4-pixel gap looked tight at low counts and sparse at high counts.
- improve Polymath runs end with a panel, not a blink. Polymath, Math Polymath, Knowledge Polymath, Memory Polymath, and Reasoning Polymath now show a Lost panel after a wrong answer · MemPi reacts (happy on a personal best, sleepy otherwise), the final streak and best-streak are surfaced, and a Play Again button restarts the run. Previously the run flipped straight back to idle, which felt abrupt. The standalone-game lost panel now also includes MemPi for parity.
Fixed
- fix He Did What no longer leaks the answer. Events whose translated label mentions the actor's own name (or any other actor's name) are filtered out of both the truth pool and the decoy pool. So a prompt like "Andreas Vesalius · 1543" no longer surfaces "Vesalius publishes modern anatomy text" as a choice; the player has to know the deed, not pattern-match the surname.
April 29, 2026
Improved
- improve Silhouette · Normal and Hard finally feel different. Same-category distractors now kick in at difficulty 4 (was 6), so a Normal round puts a deer next to a horse, donkey, and llama instead of a deer next to pizza and Mount Fuji. Hard tier adds a famous-landmark pool (Eiffel Tower, Big Ben, Sydney Opera House, Pyramids of Giza, Leaning Tower of Pisa, Stonehenge, Taj Mahal, Empire State Building, Christ the Redeemer, Great Sphinx) rendered as inline SVG · the silhouettes mix into the choice grid at difficulty 7 and become the only options at difficulty 9. All ten landmarks ship translated into every PlayMemorize language.
New
- new Heavy Friction · a tactile idle game on PlayMemorize. A stack of industrial sliders, each with a constant snap-back force fighting your drag. Push a handle from 0% to 100% to produce one Resource. Resources accumulate in a Warehouse and the Auto-Seller drains them slowly into Money you reinvest in less Friction (Speed upgrades), Auto-Slide (the handle moves on its own), Auto-Seller (faster sales), and New Sliders (a fully independent rack of bars). Production is fast and manual; revenue is slow and automated · the bottleneck is the whole game. Plays offline as part of the PWA.
- new Idle · a new game category. The home page and the game-switcher dropdown now show a sixth group, Idle, alongside Memory, Knowledge, Numbers, Reasoning, and Polymath. Idle games are deliberately exempt from the labyrinth and Polymath roulette · their pacing doesn't fit the 30-second mini-game shape · so they live as standalone pages and the player chooses how long to stay.
- new "I disagree · skip ahead" button on every round. A small ghost button now sits next to the answer choices on every shell-driven game. Click it once and the round resolves as if you had answered correctly · for the rest of the day, the button is gone for that device. Reports flow into GA4 as a per-game
<gameId>_error_reportevent with the seed, params, prompt key, expected answer, and the configuration of the round, so we can recreate the exact question in code and either fix the data or close the report. Wired through every game that uses the shared MiniGame shell · adding a new game gets the affordance for free.
April 28, 2026
Fixed
- fix Flag a Mine verdict badge no longer reads as "exit Game Mode". The small red ✗ circle that used to overlay the prompt's top-right corner after a wrong answer was visually too close to the floating Exit-Game-Mode affordance · removed in favour of the existing tinted prompt panel + mascot reveal card. The hint copy across all 25 locales no longer references long-press, since flagging on touch goes through the dedicated flag-mode toggle, not a press-and-hold gesture.
Improved
- improve New homepage banner copy. The hero now reads "Level Up Your Mind" with "Free brain games for mental workouts" as the supporting line · sharper framing of what PlayMemorize is, translated into all 25 locales.
New
- new Sort em up · rank items by an unusual property. Three categories of ordering trivia in one game · animals by brain-cell neuron count (roundworm 302 → African elephant 257 billion), athletes by documented body weight (Simone Biles, Lionel Messi, Mike Tyson, LeBron James, Shaquille O'Neal, Yokozuna), and city pairs by great-circle distance (London ↔ Paris 344 km, New York ↔ Tokyo 10,870 km, Buenos Aires ↔ Tokyo 18,370 km). Pick a single category or leave it on Mixed and let the game roll a fresh one each round. Easy mode spreads picks across the full range; Hard mode bunches them so the absolute numbers actually matter. Reuses the shared OrderingMini chrome that Order by Size and Order by When already sit on. Translated into all 25 PlayMemorize languages and registered with the labyrinth so it appears in the polymath gauntlet.
- new Where's MemPi · a hidden-object streak game. Find the MemPi mascot hiding in a wall of coral, red, and pink decoy emojis · one tap to spot him, one wrong tap ends the run. Difficulty narrows the decoy pool from rainbow (MemPi pops by colour) through a coral / red / pink mix down to coral-only at hard, where every cell on the wall is in MemPi's exact shade and only shape gives him away. Wall sizes scale from 16 to 144 cells and ramp higher inside the labyrinth. Translated into all 25 locales.
- new Silhouette · name the black outline. A new outline-recognition streak game · 100 famous animals, foods, vehicles, places, and objects rendered as black-out Twemoji silhouettes. At low difficulty distractors come from any category and the silhouette alone gives the answer away; at higher difficulty distractors are pulled from the SAME category so a horse silhouette sits next to deer, llama, and donkey and the player has to discriminate fine outline differences. Subject names reuse the existing 25-locale emoji-name corpus, so the game ships fully translated on day one. Same deterministic-seed contract as the rest of the catalogue · the labyrinth, the standalone page, and "share this round" links all render byte-identical rounds.
- new He Did What?! · history deed quiz. The inverse of Who Did · the person and year are given, the deeds are the choices. Pick which one was actually theirs. Decoys come from other actors, with same-era preference at higher difficulty so a Newton round might sit next to Halley, Hooke, and Leibniz. Reuses the same hand-curated history dataset as When Did, Who Did, and Order by When. Translated into all 25 PlayMemorize languages, works offline.
- new Polymath roundup articles translated to 23 languages. The 20 tag-roundup blog posts (
/blog/all-{tag}-games-on-playmemorize) now ship in Arabic, Bengali, Czech, Dutch, French, German, Hebrew, Hindi, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Romanian, Russian, Simplified Chinese, Spanish, Swedish, Thai, Turkish, and Ukrainian. Hungarian ships Attention and Auditory roundups for now; the remaining 18 are pending translation. Each translated article keeps the inline mini-game embeds for every game its tag covers, so readers can practise the exact game the surrounding paragraph just explained without leaving the article. - new Mosaic catalogue + resolution + palette expansion. The painting catalogue jumps from 10 to 30 canonical works spanning four centuries · the original ten figurative classics, eight further URL-fetched works (Composition VII, Guernica, La Muse, Portrait of Dora Maar, Hand with Reflecting Sphere, Rain Princess, Feathers, a Roman mosaic), and twelve hard-edge / colour-field icons that ship as inline SVG strings rasterised through sharp at build time so they never need a network fetch (Mondrian, Malevich, Rothko, Albers, Newman, Reinhardt, Kusama, Johns). Per-painting cell budget bumps from 5 000 to ~100 000 · twenty times the resolution, so silhouettes and brushwork survive quantisation rather than dissolving into a coarse grid. The palette grows from 9 Unicode colour-square emojis to 45 emoji-derived hex chips (moon-cream, stone-grey, terracotta, peach, night-blue, fir-green, …) so muted oil-paint mid-tones land on a faithful sibling instead of collapsing to black; the build verifies every chip is actually picked by at least one cell. Reveal order switches from top-down scanline to a deterministic random Fisher-Yates permutation, so the painting emerges from a sparse signal rather than line by line. Translated into all 25 PlayMemorize languages.
Improved
- improve Game analytics simplified to a single click event. Every game now emits one GA4 event,
<gameId>_click, once per player-committed action; GA4's built-in geo dimension covers country breakdown without per-game wiring. The previous lifecycle / streak / personal-best event set was retired together with the gameEvents pub/sub bus, the B-27 max-streak verify rule, and the B-31 bus-routing rule. Existing game components continue to work unchanged · the legacy helpers (emitGameAnswerClick,reportRoundResolved,useMiniGameAnalytics) all funnel into the new click event, and the rest are no-ops. - improve Site-wide colour pass to the Pop palette. Every legacy semantic token (
--color-primary,--color-bg,--color-text, the spacing / radius / shadow scales, etc.) now resolves to a Pop token fromsrc/styles/tokens.css· cream#fff4e3backgrounds, ink#1e1a33text, coral#ff4f5eprimary CTAs, sun-yellow accents. The PWAtheme_colorand<meta name="theme-color">in the OS-level browser chrome match the new cream surface so the home screen icon and Safari address bar tint pick up the brand instead of the legacy off-white. The PlayMemorize wordmark on the home page now reads coral instead of the legacy blue, the streak chip and the install banner re-tinted to coral / cream, and the "Train your memory with free games" duplicate strap above the home banner was retired · the banner's own H1 already carries the marketing line. - improve Visual answer surfaces are now reachable by keyboard and screen reader across the catalog. Geography map cells are focusable buttons with feature names; Chess Mate squares carry algebraic notation + piece + state; Sudoku Force cells expose row, column, value, and target; Spatial, Matrix, and Odd One Out options have structural descriptions instead of empty
aria-labels; Spot the Difference cells announce row, column, and found state. Sighted play is unchanged; everyone else can finally play. - improve Wrong-answer feedback now reads aloud across every text-based game. Math shows the full equation with the answer; Backwards reveals the original word and its reverse; Stroop prints the expected color; Color prints the expected sequence; Mastermind Deduce spells out the unique code in color names instead of color circles only. Screen-reader users no longer have to infer the right answer from a green-highlighted button.
- improve Labyrinth announces every move outcome to assistive tech. A polite live region narrates direction (north / south / east / west), wall blocks, item pickups, encounter triggers, and level transitions so screen-reader users get the same feedback the visual board has always given sighted players.
- improve Polymath modes announce the rolled sub-game before input. The "Now playing: Math" label is now an assertive live region so screen readers say which game just rolled before the player is asked to answer.
- improve Polyglot now reveals the correct word + emoji pairing after a wrong answer and announces round status through a polite aria-live region so progress is audible, not just visual.
- improve Ghost now shows a numeric countdown during the memorise phase. The bar that already shrinks during memorisation now sits next to a "3s" / "2s" / "1s" chip, and the count is announced through a polite live region · no more silent dead air on slow speeds.
- improve Define prompt and choices now read clearly. Category-style rounds say "Pick the category that fits this word" instead of the generic prompt, and answer labels are formatted as "Category: Food & drink" instead of the all-caps "KIND Food & drink". Wrong answers now name the correct option in text.
- improve Mosaic reveals include a one-sentence description of every painting, and the scanline phase announces "Row N / M" via a polite live region so a screen-reader player knows the picture is still painting.
- improve Memory cards now have unique accessible names. Each card announces "Card row 1 column 2: Flag Kyrgyzstan" once revealed, instead of every hidden card sharing the generic "Hidden card" label.
- improve Comparisons shows the slot-machine spin progress in text ("Spinning slot 3 / 4") through a polite live region, so the multi-second spin animation isn't a silent dead zone.
- improve Spot the Difference now draws a divider between the reference wall and the spot-the-difference wall. Larger boards (300+ emojis) used to bleed into one continuous grid; the new horizontal rule with a magnifying-glass marker makes the boundary obvious so it's clear where one wall ends and the other begins.
- improve The PWA install banner and the social-proof toast now yield while a round is in progress. Both used to pop in over the answer surface mid-round; they now hide while the player is mid-game and re-appear once the round ends.
- improve Five more illusion deep-dives in French. Abutting Gratings, Asahi, Orbison, Ouchi, and Rubin Vase now read in French with the same TLDR, styled boxes, and inline mini-game embeds as the English originals. French readers reach the full explanation of each illusion without bouncing back to English.
Fixed
- fix Flag a Mine in-game text trimmed. The board used to carry three lines of instructional text under it during play (a "tap to reveal · toggle flag mode" rules row, a redundant prompt, and the flag-mode hint). The rules row and the playing-state prompt are gone · the flag toggle button and the landing page's About / FAQ already explain how to play. Win and lose messages still appear after the round, and the flag-mode hint still shows during play.
- fix Comparisons singular/plural grammar. Explanations like "One nails is about 3 g" now read "One of these nails weighs about 3 g". Six explanation templates were rewritten to work with plural entity labels across every category.
- fix Who Did reveal copy. Wrong-answer text now reads "The correct answer is …" instead of "The correct actor is …", which was misleading for scientists, leaders, explorers, and other non-actor historical figures.
- fix Geography United States duplicate removed. Two separate "United States" / "USA" country entries pointed at the same map; they are now a single entry. Indonesian blog articles that linked to the dropped slug have been re-routed.
- fix Labyrinth quest-giver no longer shows "Help! Help!" twice in a row. The speech bubble now hides while the quest-giver modal is open, so the same line doesn't appear simultaneously on the board and in the modal.
New
- new Ten observational-cosmology firsts added to the history dataset.
historical-events-data.tspicks up Henrietta Leavitt's Cepheid period-luminosity relation (1912), Cecilia Payne-Gaposchkin's stars-are-hydrogen thesis (1925), Karl Jansky's discovery of cosmic radio waves (1932), the Penzias and Wilson cosmic-microwave-background detection (1965), Vera Rubin's galaxy rotation curves and dark matter (1978), the Hubble Space Telescope launch (1990, attributed to NASA), the first exoplanet around a sun-like star (Mayor and Queloz, 51 Pegasi b, 1995), the discovery of accelerating expansion / dark energy (Perlmutter, Riess, and Schmidt, 1998), the first direct gravitational-wave detection (the LIGO collaboration, 2015), and the first image of a black hole (the Event Horizon Telescope collaboration, M87*, 2019). Nine new actors join the table, two of them collaborations in the same shape as the existingcernentry. Together with the existing Hubble-1929 row, the modern-cosmology arc is now end-to-end from 1912 to 2019. When Did, Who Did, and Order by When all surface the new rows automatically. - new Cosmology's Century: Ten Discoveries from Cepheids to M87* · deep-dive article on the ten new history rows. Covers each discovery's date, named scientist (or collaboration), and the distractor traps players will hit (the 17-year Leavitt → Hubble causal chain, the 1965 collision between Leonov's spacewalk and the CMB detection in mixed-topic Order by When draws, why the EHT row is attributed to a collaboration rather than to Katie Bouman, and the rule that PlayMemorize stores the discovery year not the Nobel year).
April 27, 2026
Improved
- improve Mini-games ramp difficulty one step per win. Pi now starts at 3 digits and grows one digit per successful round (3 → 4 → 5 → …, capped at 100). Color, Memory, and every other module that exposed a level-scaled knob ramp the same way without each standalone page having to thread a difficulty function. Both the standalone streak host and the in-blog
InlineGameembeds derive params fromparamsFromDifficulty(d, streak), so a player practising in a roundup article gets the same step-by-step progression as on the dedicated game page. Tier-based games (Chess, Sudoku, Mastermind) keep their picker-driven preset. - improve Spot the Difference inline embeds shrink to ~4 rows total. Default emoji count is now 16 (4×4) instead of 36 (6×6) so the two stacked walls fit cleanly in a blog card without the cells collapsing into a single razor-thin strip. The labyrinth ramp now scales 16 → 100 (instead of 36 → 144), still progressively harder but readable at every level.
- improve Chess Mate prompt + hint clarify the click-to-move flow. The prompt now reads "White to move · find mate in one" and the hint says "Tap a white piece, then tap its destination square" so players who arrive on a chess InlineGame embed (no choice buttons; the board itself is the input) immediately know how to play.
New
- new MemPi · the PlayMemorize mascot. Pixel-art π glyph with two eyes and a half-smile. Ships with six poses (default, happy, wink, sleep, look-up, mono) and shows up on the home hero, the 404 page, the changelog, the blog empty state, the install banner (winking), the labyrinth corner, and after every mini-game round (happy when you got it right, look-up when you didn't). Also became the install icon on Android, iOS, and the home-screen shortcut tile (cream-tile maskable variant). One
<Mascot pose="…" />component drives every appearance · drop a new pose SVG into/public/images/mascot/and every placement picks it up. - new Mosaic · spot the famous painting as it paints itself row by row. Ten public-domain canvases (The Starry Night, The Great Wave, The Scream, The Shipwreck of the Minotaur, Composition VII, Picasso's Self-Portrait, Frida Kahlo's Self-Portrait, Woman with a Hat, Seated Nude, Udnie) downsampled to 50×100 and quantised to the Unicode 12 colour-square emoji palette (🟥 🟧 🟨 🟩 🟦 🟪 🟫 ⬛ ⬜). The mosaic reveals top-to-bottom on a single HTML5 Canvas via
ctx.fillText; pick the painting from a multi-choice list before the scanline finishes and you score (1 000 × rows-left / total). The artist, year, and art movement appear after every round, so the streak doubles as an art-history primer. No source images ship · the repo holds only 5 000 single-digit emoji indices per painting;scripts/build-mosaic-paintings.mjsregenerates the data from public neural-style-transfer reference URLs in a single command. Translated into all 25 locales.
Fixed
- fix Homepage banner no longer collapses on mobile. The Pop hero used a CSS container query (
@container (max-width: 640px)) to switch the banner from its 1456:360 leaderboard ratio toaspect-ratio:autoon small screens · but container queries only match descendants of the container, not the container itself. The rule never fired, so the strip stayed pinned at ~80 px tall on phones and the chip + H1 + tagline got crushed insideoverflow:hidden. The banner-self property change moved into a media query (descendant rules stay in the container query, where they work), and chip / streak-badge spacing tightened up at the same breakpoint. - fix Spot the Difference walls are always a perfect rectangle. The labyrinth count ramp produced primes like 41 / 46 / 51 / 61 / 71 between 36 and 144 · those have no good factorisation so the bottom row stuck out partial. Standalone presets 200 / 300 / 500 looked the same way because
colsForAspectroundedsqrt(n*aspect)to a non-divisor (200 → 14 cols → 14×14=196 + 4 left over). Two changes: the ramp now scales the wall dimension (6 → 12 over 24 levels) and squares it, so every level is a clean N×N.colsForAspectnow picks the divisor of n closest to the aspect-derived target, so 200 fills as 20×10 (or 10×20 in portrait), 300 as 20×15, and 500 as 25×20 · no row sticks out. - improve Spot the Difference is the English name; Finn fem fel stays the Swedish nickname. The catalog label, FAQ heading, page title, and roundup-article references now lead with Spot the Difference in English. The Swedish locale still renders Finn fem fel (via per-locale i18n strings and a Swedish-specific page title) and the FAQ keeps the etymology. URL slug renamed from
/finnfemfelto/spot-the-difference(sitemap, hreflang alternates, and PWA precache list all updated; internalgameIdstaysfinnfemfelso existing high scores and analytics events keep working).
New
- new Favorite games on the home page. Every game card on the landing page now carries a star button in its top-right corner. Tap the star to pin the game to a new "Favorites" strip that appears just below the banner · your most-loved games are one tap from the top of the page on every visit. Favorites are kept in
localStorageso they survive reloads and stay in sync across tabs. The strip is rendered by cloning the underlying tile markup, so the favorite card looks identical to the regular catalog card and never drifts on label, icon, or theme. Translated into all 25 locales. Two GA4 events fire on every star tap · a genericfavoritedevent tagged withgame_idandactionfor cross-catalog dashboards plus a namespaced<gameId>_favoritedmatching the per-game event convention. - new MemPi the mascot debuts in a homepage hero banner. The site root now opens with a Pop-system hero strip · pixel-art π-shaped mascot whose eyes follow your cursor, animated mesh background, three sample game chips, and the value prop ("Free brain games. Daily streaks.") all translated into every supported locale. Built with system fonts, container queries, and
prefers-reduced-motionsupport, so the strip scales cleanly from a phone to the widest desktop and goes still for readers who ask it to. Banner only appears on/and/[lang]/· every other page keeps its existing header. - new Home page game cards now ship with bespoke per-game illustrations. Every card on the landing page has been redrawn as a "Pop tile" · square card with a CSS-only mini illustration on the top half (a simon-pad cluster for Color, a numpad strip for Math, a globe for Geography, a grid-with-a-gap for Ghost, a chronological strip for When Did, and so on across all 38 games) and the name + 1-line description below. Every illustration is pure CSS with no asset downloads, so the homepage stays under the existing performance budget while looking much richer at a glance. The full design package lives in
_handoff/as the handoff reference for the rest of the Pop migration. - new Spot the Difference · find every altered cell between two walls of Twemoji. (Known in Swedish as Finn fem fel.) The screen shows the same wall twice · top is the reference, bottom has been altered in K cells. Tap every changed cell on the bottom wall to clear the round. Pick 100 / 200 / 300 / 400 / 500 emojis and 1 / 5 / 10 / 20 differences from the start screen; the grid columns adjust to your screen aspect ratio so cells stay roughly square. Two trick types share one deterministic generator (
src/games/finnfemfel/generator.ts): visual replacement from a hand-curated cluster of look-alike emojis (smiley family, red fruits, coloured circles, numbered clocks, books) plus same-category fallback, and horizontal flip / 180° rotation gated to a curated list of emojis whose flipped form is plausibly different (animals, vehicles, tools · stars and hearts excluded because their flip is identical to the original). Reuses every emoji asset and helper the rest of the catalogue already ships ·emojiPool()from Ghost / Memory, the<Emoji>Twemoji wrapper,createRng,levelRamp, theIdlePanel/GameRoundIndicator/GameStopButtonshell, the unified game-analytics contract. Translated into all 25 locales. Also wired into the Labyrinth via the standardGameModulecontract ·paramsFromDifficulty(d, lvl)ramps wall size 36 → 144 and differences 1 → 12 across encounter levels. - new Twenty cross-game roundup articles. Every game now carries a set of cross-cutting tags (memory, spatial, deduction, attention, language, history, no-reading … 21 in total) on top of its existing landing-page group. Each tag has a dedicated long-form article that pulls its game roster from
getGamesByTag(tag)at build time, so adding a tag to a game automatically surfaces it in the roundup that should mention it. The first batch covers spatial, memory, numbers, reasoning, knowledge, language, history, pattern, deduction, attention, visual, auditory, verbal, estimation, ordering, sequence, classic-IQ-test, speed, no-reading, and trivia · twenty in-depth guides, each with every relevant game playable inline at the section that names it. Live at /blog/all-<tag>-games-on-playmemorize. - new /blog/topics · meta-index of every roundup article, grouped by category. Cognitive skills, subject knowledge, modality, and special formats. Each card shows the tag, the game count (live from
getGamesByTag(tag)), and a one-line description. The blog index now carries a "🗂️ Browse by topic" link near the top so readers can jump straight to the roundup grid.
Improved
- improve Polymath now lives at the bottom of the home page. The five game groups on the landing page (Memory · Knowledge · Numbers · Reasoning · Polymath) used to lead with Polymath because that's where the Labyrinth and the Polymath roulette live. New visitors landed on the cross-game gauntlet before they had played any individual game · backwards. The order in
GAME_GROUPSnow reads Memory → Knowledge → Numbers → Reasoning → Polymath, so the catalog opens with concrete one-skill games and the polymath gauntlet sits at the end as the natural graduation. The dropdown switchers and any other consumer ofgetGamesByGroup()follow the same order. - improve Inline game embeds in articles now hydrate on scroll, not on page load. All
<InlineGame>embeds across the 20 roundup articles switched fromclient:loadtoclient:visible. Articles like the reasoning roundup (which embeds 13 games) used to hydrate every React island on first paint; now each game module loads only when its section scrolls into view. Big LCP/TTI win on the longer roundups, no behaviour change for readers who scroll through. - improve Every blog article now surfaces related topic roundups in its CTA. The shared
BlogCTAfooter reads the article's primary game's tags and renders a "Topic roundups" section linking to up to three matching/blog/all-<tag>-games-on-playmemorizearticles. Memory-game articles point at the memory and visual roundups; geo articles point at spatial and knowledge; illusion articles point at spatial, visual, and attention. Cross-linking is automatic from the tag system · no per-article wiring. - improve Three new verify rules lock the tag system. B-33 fails the build if a roundup article's
tag:frontmatter is unknown or resolves to zero games. B-34 fails the build if any catalogued game (other than polymath/labyrinth hosts) has zero tags. B-35 · the load-bearing one · fails the build if a roundup article body's set of<InlineGame gameId="X" />embeds doesn't matchgetGamesByTag(tag) ∪ extraGames. Adding a tag to a new game now requires either updating the relevant article body or removing the tag · no silent drift between catalog and prose. The "extraGames" opt-in lets cousin embeds (e.g. the auditory article naming Color and Memory as related) coexist with strict roster checking. - improve New e2e regression suite for the roundup blog.
tests/e2e/roundup.spec.tsvisits/blog/topics, the spatial roundup, and asserts (1) the topics meta-index renders enough cards, (2) the auto-generatedGameRosterTOC links resolve to in-page anchors, and (3) at least oneInlineGameembed actually hydrates after scrolling · catching the kind of "loaded but never mounted" regression thatclient:visiblecan hide. - improve Memory, Ghost, and Polyglot strategy guides now play the relevant mini-game inline. The three game-specific strategy articles (Master Emoji Memory Games, Master Your Visual Memory: Twemoji Ghost, Fast-Track Your Vocabulary: Twemoji Polyglot) used to read like a book · all prose, no practice. Each one now embeds three rounds of its own mini-game at progressively harder settings, so a reader can immediately try the technique the paragraph just explained without leaving the page. Embed structure is identical across all 25 locales; same source-of-truth game data and same in-language prompts as the standalone game pages, so translations come for free.
Improved
- improve Header and footer dropdowns now close on Escape and announce their open / closed state. The game-switcher and language-switcher menus close with Escape (focus returns to the button) and the buttons toggle
aria-expandedin sync with the panel so screen readers announce the state correctly. A focus ring is now visible on the dropdown buttons when tabbing through the page. - improve Geo pages render emoji faster. The Twemoji observer that swaps native emoji for cross-platform SVGs no longer reparses the whole page on every DOM change. It now parses only the subtree that actually mutated and coalesces bursts through
requestAnimationFrame, so a flurry of React re-renders inside the Geo mini-game doesn't trigger a full document reparse anymore. - improve Five more illusion deep-dives in Italian. Kanizsa Square, Mach Bands, Necker Cube, Rubin Vase, and Penrose Stairs now read in Italian with the same TLDR, styled boxes, and inline mini-game embeds as the English originals. Italian readers reach the full explanation of each illusion without bouncing back to English.
- improve Five classic illusion deep-dives in French. Cafe Wall, Ebbinghaus, Hering, Ponzo, and Zoellner now read in French with the same TLDR, styled boxes, and inline mini-game embeds as the English originals. French readers reach the full explanation of each illusion without bouncing back to English.
- improve Pi memorisation milestones and the crewed-spaceflight history article now embed their mini-game inline. The three Memorise the First N Digits of Pi articles (10, 50, 100) now render the Pi numpad trainer at the test-yourself step with
lengthmatching the article so readers can drill the exact digits they just learned. Pi-10's existing translations (id, nl, sv) all pick up the same embed in the same structural slot. The Six Crewed Spaceflight Firsts article embeds an Exploration-topic When Did round at the "drill these in PlayMemorize" section so the dataset additions the article describes are immediately testable. All embeds useclient:visibleso they hydrate only on scroll.
April 26, 2026
New
- new Six crewed-spaceflight firsts added to the history dataset.
historical-events-data.tspicks up Voskhod 2 spacewalk (1965, Alexei Leonov), Salyut 1 (1971, first crewed station, attributed to the Soviet Union), STS-1 Columbia (1981, John Young), STS-7 (1983, Sally Ride), Shenzhou 5 (2003, Yang Liwei), and Crew Dragon Demo-2 (2020, SpaceX). Five new actors (alexei-leonov,john-young,sally-ride,yang-liwei,spacex); two collective rows (salyut1-station,crew-dragon-demo2) hidden from Who Did viaexcludeFromWhodidso the four-way actor pool stays fair. Together with the existing Gagarin, Tereshkova, and Apollo 11 rows, the crewed-spaceflight arc is now end-to-end from 1961 to 2020. When Did, Who Did, and Order by When all surface the new rows automatically. - new Six Crewed Spaceflight Firsts: Voskhod 2 to Crew Dragon · deep-dive article on the six new history rows. Covers each mission's launch year, named astronaut, and the distractor traps players will hit (the symmetric April 12 anchor between Vostok 1 and STS-1, John Young as cross-era distractor for Apollo and Shuttle rows, the chronology of women in orbit from Tereshkova to Liu Yang, and why Salyut 1 plus Crew Dragon Demo-2 are excluded from Who Did).
Fixed
- fix Best-streak counter now refreshes when you switch a game's tier or surface. Tone Knowledge (Piano ↔ Notes), Chess Mate (easy / medium / hard), Sudoku Force, and Flag a Mine all swap the localStorage key under the hood when you change tier · but the displayed “Best” badge was frozen to whichever key was active at first mount. Switching to a new tier mid-session now reads the right high streak immediately, and personal-best events fire against the correct baseline.
- fix Flag a Mine: stale resolve timer no longer fires after Stop. The 120ms grace timer between the final tap and the win/lose reveal was untracked, so pressing Stop in that narrow window let the timer fire against the unmounted round and React would warn about state updates on an unmounted component. The timer is now cancelled on unmount and on the next round's mount.
- fix Tone Knowledge: Replay button now actually replays. Pressing “▶ Replay” mid-round used to play the audio sequence but skip the visual key-walk and leave the input cursor stranded wherever the player had got to · so the first note they tried after replaying was marked wrong because the game still expected note N, not note 1. Replay now resets the cursor to the start, walks the highlight along the surface (piano keys, fretboard, or staff) just like the first “Listen”, and cancels any in-flight timers from a prior press so mashing the button never queues stale highlights.
- fix Riddles
lg-doctor: removed a distractor that was also a valid answer. The classic surgeon riddle (“the surgeon says ‘he is my son’ · how?”) carried the distractor “The boy has two fathers,” which · with same-sex parents · is itself a perfectly logical resolution: the deceased was father #1 and the surgeon is father #2. A player picking it for the right reason was being marked wrong. Replaced with “The surgeon misread the chart” (clearly invalid · doesn’t explain “he is my son”) and shuffled in “The surgeon is his godfather” in place of the older “stepfather” entry. The intended answer (“The surgeon is the boy’s mother”) and explanation are unchanged. - fix History games: Hamlet event no longer mistimes Shakespeare’s writing year. The
shakespeare-hamletentry inhistorical-events-data.tswas labelled “Shakespeare writes Hamlet” with year 1603, but the play was written ~1599-1601 · 1603 is the date of the first quarto publication. The label is now “Shakespeare’s Hamlet first published,” which matches the year and reads correctly in Order by When, When Did, and Who Did. Actor (shakespeare) and year (1603) unchanged.
April 25, 2026
Improved
- improve Site-wide game UX contract: explain, reveal, wait for the next click. Locked in the three-part rule that every game must follow: (1) the player sees how to play before clicking Start (the shared
IdlePanelwith a non-emptydescription· enforced by new verify rule B-29 across all 34 panels); (2) after the round resolves, the panel shows what the player picked, what the right answer was, and a one-line explainer · theQuizMini+OrderingMinishared chromes (used by When Did, Who Did, Order When, Order Size) and theRiddlesmini all now pass anexplainreveal panel through toMiniGameShellinstead of auto-advancing in 420 ms; (3) the next round only starts after the player clicks Continue / Play Again · removed the legacy 1100–1300 ms auto-resolve timer inQuizMini+OrderingMiniin favour of an explicitfinish()on Continue. Two new shared translation keys (games.shared.your_answer,games.shared.correct_answer) plus fourgames.shared.explain.*templates added across all 25 locales. New verify rule B-28 requires everyMiniGameShell-usingMiniGameto pass theexplainprop so future games can’t silently regress to auto-advance. Three new Vitest specs lock the contract at runtime:tests/games/feedback.spec.tsxmounts everyGameModule’sMiniGame, simulates a wrong pick, and asserts the host’sonFailstays unfired plus a Continue affordance is in the DOM;tests/games/customJsxFeedback.spec.tsstatic-checks the 11 custom-JSX standalone games (MathGame,FactsGame,SequencesGame, …) forIdlePanel+phase==='wrong'+ Play Again button + no auto-restart-via-setTimeout;tests/games/colorBoxes.spec.tsmirrors theF-05/E-09verify rules so the styled-box minima (tip-box,warn-box,key-point,strategy-card,step-badge) are enforced undernpm testtoo.
New
- new “Select what to study” menu on every polymath game and the Labyrinth. Every Polymath variant (Polymath, Math, Knowledge, Memory, Reasoning) and the Labyrinth now share an identical collapsible “Game filter” widget so the player can pick which games are in the rotation before they start. Polymath ships with all of its mode-relevant games on by default; Math shows only math games; Labyrinth shows every game currently in its encounter pool. Selection persists in localStorage per game.
Fixed
- fix Geo article maps now show the city named in the heading. The Memorise Sweden's Top 10 Cities article placed each map one city behind: the section Where is Gothenburg? showed only Stockholm, the section Where is Malmö? showed Stockholm + Gothenburg, and so on. Every section now reveals the city its heading asks about, with an arrow connecting from the previous one so the route through Sweden builds up visually as the reader scrolls.
- fix Mnemonic phrase no longer overflows on mobile. The Sweden article's "Seven Good Men Usually Laugh, Very Often Having New Jokes" mnemonic rendered as one continuous run of letters with no spaces between the words on iOS Safari, spilling off the right edge of the viewport. Every word is now a separate visible token in every locale, and the same fix swept the illusions blog articles where the bug was hiding.
- fix "Open game" from a blog article now opens the game with the article's context. Tapping Open game → from the Sweden article used to drop the player on a generic Geography page; it now opens Geography pre-tuned to Sweden's cities. The dead "↻ New round" button in the inline preview is gone · the inline embed is a study illustration, not a game loop.
- fix Great Pyramid of Giza no longer credited to Qin Shi Huang.
historical-events-data.tsattributed thepyramids-gizaevent (year −2560) toqin-shi-huang, who lived ~2,300 years later and built the Great Wall (a separate event already correctly attributed to him). The pyramid event is hidden from Who Did viaexcludeFromWhodidso the wrong actor never surfaced as a question, but it polluted any join over the actor table. Added a newkhufuactor (“Pharaoh Khufu”) and reattributed the event correctly. - fix Labyrinth scaling for Facts, Geography, and Crazy Comparisons. Three modules’
paramsFromDifficultystill had the legacy single-arg signature and ignored the labyrinth’slevel, so deep gauntlet runs of those three games played exactly like level 5. Facts now rampsnumAnswerswithlevelRamp(3 → 6 across the climb). Geography now rampstopNfrom 5 → 10 so deeper runs cover more obscure cities/rivers/mountains. Crazy Comparisons accepts thelevelarg for API conformance (its only knob iscategory, which difficulty already widens). - fix Riddles
wp-silent: distractor letter counts now match the question. The riddle asks for a 9-letter word containing all five vowels in order (answer: Facetious), but two of its five distractors · Sequential and Courageous · were 10 letters long, letting savvy players eliminate them by length alone instead of by vowel order. Replaced with Ambitious (9 letters, vowels A·I·I·O·U · tantalisingly close to the rule but missing E) and Authority (9 letters, vowels A·U·O·I · same shape as the trap pattern). All five distractors are now 9-letter English words, restoring the puzzle's intended difficulty. - fix Screen-reader strings on Chess Mate, Flag a Mine, and Tone Knowledge are now translated. Eleven hardcoded English aria-labels were leaking out to non-English screen readers: chess piece descriptions (“white queen”, “black knight”, “legal move”), Flag-a-Mine cell states (“revealed N”, “flag”, “hidden X,Y”), and the three tone-surface containers (“Piano keyboard”, “Guitar fretboard”, “Treble-clef staff”) plus per-key “Play C4” labels. Added the keys to
ui.tsacross all 25 locales (English values shipped as the safe fallback, fully localised translations land in a follow-up). The piano / guitar / staff components now accept alangprop and calluseTranslationsinternally so the same surfaces can be reused in any future host without re-plumbing strings. - fix Home-page tagline + section labels are now translated. The site root’s “Train your memory with free games” tagline and the five
landing-group-labelheadings (Polymath, Memory, Knowledge, Numbers, Reasoning) were hardcoded English insrc/components/LandingPage.astro. Six new keys (home.taglineplushome.group.polymath,.memory,.knowledge,.numbers, and.reasoning) added to all 25 locales inui.tswith native translations for the major locales (sv, fr, de, es, pt, it, nl, pl, ro, cs, hu, el, uk, ru, ar, he, hi, bn, zh, ja, ko, tr, th, id) and English fallback for everything else. Per-game card label/desc translation is a separate pass. - fix Every blog article now ships
readTimein its frontmatter. PerCLAUDE.md§1d, every article frontmatter must carry a localised “N min read” string · CJK locales use a character-density estimate, every other locale uses ~200 wpm rounded up to a 1-min floor. All 385 articles now have the field, plus the sharedblogLinkFieldsZod schema insrc/content/config.tsdeclares it so future articles fail loudly when missing. The byline insrc/pages/blog/[slug].astro+src/pages/[lang]/blog/[slug].astro+ the pi/digit-seriesBlogPost.astrolayout all render date · read-time when the field is present and silently skip when it isn’t, so legacy articles missing the field still render cleanly.
Improved
- improve Standardised in-game header menus across every game. The "round · streak · best" indicator, the "↺ Stop" button, and the collapsible in-game settings panel are now three shared components (
GameRoundIndicator,GameStopButton,InGameSettings) insrc/components/game/GameControls.jsx, replacing 14 hand-rolled copies that had drifted apart in margins, font sizes, aria-live, and spacing. Translation keys also cleaned up:ghost.round/ghost.rounds/ghost.best/ghost.stopwere misnamed (every game used them) and have been renamed togame.round/game.rounds/game.best/game.stopacross all 25 locales. Visible result: every game now has the same chrome at the top and bottom of a round. - improve Dutch illusion catalogue: 5 new translations.
nl/gained Müller-Lyer, Ebbinghaus, Ponzo, Hering, and Zöllner. All translations preserve the exacttip-box/warn-box/key-point/strategy-card/step-badgecounts from the English originals (verify rule E-09), use middots in place of emdashes (F-01), and pass thelocale: "nl"frontmatter contract (E-08, F-03). - improve Spanish illusion catalogue: 5 new translations.
es/gained Ebbinghaus, Ponzo, Zöllner, Orbison, and Café wall. All translations preserve the exacttip-box/warn-box/key-point/strategy-card/step-badgecounts from the English originals (verify rule E-09), use middots in place of emdashes (F-01), and pass thelocale: "es"frontmatter contract (E-08, F-03).
New
- new Four ordering / history games: Order by When (drop historical events into chronological order), Order by Size (sort planets, animals, mountains, countries, buildings, and bodies of water from smallest to largest), When Did (multiple-choice "pick the year"), and Who Did (multiple-choice "pick the person responsible"). All four share two new data files (
historical-events-data.ts,sized-items-data.ts), a sharedOrderingMiniclick-in-order component, and a sharedQuizMiniprompt + vertical-choice layout. Streak-based scoring per (count, difficulty) combination, full GameModule conformance, all 25 locales translated for the chrome strings (event descriptions and actor names ship in English with locale fallbacks).
Improved
- improve Tone Knowledge grows the sequence by one note per success. The standalone
/tonespage now plays Simon-style on both surfaces: round 1 asks for 3 notes back, round 2 asks for 4, round 3 asks for 5, … capped at 50 (the same ceiling Color uses). The first wrong note ends the run and the streak resets · how far you can climb is the streak. Implementation extendsModuleStreakGame’sparamsOverrideprop to accept a function ·(streak) => Partial<Params>· re-evaluated every round so params can ramp with the streak. Tier-picker games (Chess Mate, Sudoku Force, Mastermind Deduce, Flag a Mine) keep passing static objects and stay on their one-tier-per-run difficulty model. Tones’ ramp also nudgesdifficultyup by one every 5 rounds so the chromatic range widens and the tempo tightens as the streak climbs · the late-game challenge isn’t just “remember more notes,” it’s “remember more notes faster across more keys.” - improve Notes mode shows the letter under every notehead. The treble-clef staff used to render a parchment with bare noteheads only · learning to read the staff was harder than it needed to be because the player had no anchor for which dot was C, which was D, and so on. Each notehead now carries its letter label (C / C# / D / D# / …, octave digit dropped on purpose so the focus is the letter not the absolute pitch) anchored to the bottom edge of the parchment so the labels line up in a clean row regardless of staff-row height. The label tints amber when the note is highlighted during playback so the audio, the notehead, and the letter all light up together · same chromatic index drives all three so “the C you hear is the C you see is the C you read” is enforced by the same data, not by separate translations. Styled as a beginner aid, not as part of the notation. Real sheet music has no letters · pros read the notehead position against the clef. To respect that convention while still helping beginners, the labels are deliberately subtle: 10px italic serif (Georgia) at 45% opacity so they read as quiet reference text under the staff and never fight the noteheads themselves.
New
- new Labyrinth Easy/Medium/Hard new-journey tiers. The labyrinth’s in-game settings panel now exposes three tier buttons under Start a new journey at: 🟢 Easy · Lvl 0, 🟡 Medium · Lvl 25, 🔴 Hard · Lvl 50. Each rolls a fresh root seed and drops the player straight into the chosen level instead of always restarting at level 0. Hard mode is a real difficulty cliff because the per-game level scaling now caps much higher: Color asks for level colours back (3 → 50, 1:1 with the level), Memory grows to 12 pairs (24 cards) instead of capping at 6, Sequences grows to 16 elements instead of 8, and Sudoku Force’s noise scaling reaches its 60-blank ceiling well before level 25. Three new strings (
labyrinth.tier.new_journey_label,tier.easy,tier.medium,tier.hard,tier.easy_desc,tier.medium_desc,tier.hard_desc) propagated across all 25 locales.
Improved
- improve Illusions: explain-only, no “guess first” teaser. The labyrinth/Polymath illusions tour used to run a two-beat flow · teaser (“look for X”) → reveal (“here’s why your eye gets fooled”). The teaser added a click without changing what the player saw, so the round read as “press a button, then read.” The illusion AND the explanation now render together from the first frame · the player sees the figure with its name, the truth (“same size” / “truly parallel” / …), and the per-illusion caption all at once. The only player action is Next to advance to the next illusion.
illusionsNoFail.spec.tsxretired and replaced byillusionsExplain.spec.tsx(1 click per round, neveronFail,onWinonly on the final click).
Fixed
- fix Same streak-loop bug class swept across the rest of the engine. Followed the orderwhen / ordersize / whendid / whodid fix with a sweep of every place that had the same shape: a
useEffectkeyed on[phase, onWin, onFail]that schedules asetTimeout(... onWin/onFail, N ms). Root cause wasuseMiniGameAnalyticsinsrc/utils/gameAnalytics.js: the hook returned fresh closures every render, so every parent re-render handed down a newonWin/onFailidentity, which re-fired the resolve effect in every shared chrome below it (MiniGameShell, the labyrinth’sChallengeShell,PiEncounter,MemoryEncounter, the illusions tour). Hook now captures the latest props in a ref and returnsuseCallback-stable wrappers so callback identity stays put across re-renders, and adds its own one-shotfiredRefso a single mount can only resolve once. Each downstream shell got its ownfiredRefas a second line of defence (seeMiniGameShell.tsx,ChallengeShell.tsx,PiEncounter.tsx,MemoryEncounter.tsx,illusions/MiniGame.tsx). Regression spec extended with mount-then-re-render checks forMiniGameShellandChallengeShellalongside the existingOrderingMini+QuizMiniones. - fix Streak loop on the four ordering / history games no longer auto-advances after one round. The shared
OrderingMini+QuizMinichrome (used by /orderwhen, /ordersize, /whendid, /whodid) had two interacting bugs in the way it dispatchedonWin/onFailback toMiniGameStreakApp.OrderingMinireset its ownpicks+phasestate on every change to a memoiseddisplayreference, but the upstreamitemsprop was rebuilt fresh on every parent render · so a parent re-render mid-resolve would silently flip the round back to "asking", cancelling the 1300 ms timer that was supposed to callonFail(). The streak loop never saw the wrong answer and rolled into the next round as if the round had been won, then auto-resolved again on the next render, and so on. Fixed three ways for defence in depth:MiniGameStreakAppnow mounts theMiniGamewithkey={seed}so each round gets a fresh component instance, holds a one-shotroundClosedRefthat preventshandleWin/handleFailfrom re-entering during a single round, and clears the "next-round" setTimeout on Stop / unmount.OrderingMini+QuizMinieach hold their own one-shotfiredRefon the resolve timer, andOrderingMini’s reset effect is now keyed onseed+items.lengthinstead of the churningdisplayreference. Regression covered bytests/games/streak-loop.spec.tsx: mounts the chrome, fires a click, re-renders the parent with new callback refs, asserts the win/fail callback runs exactly once. - fix Polymath rounds of Riddles now show the real options. A Polymath round of Riddles used to render the no-fail “Reveal” tour the labyrinth was using · question + a single primary button, no choices, never
onFail. Polymath players ended up clicking Reveal once per round and effectively answering nothing. The riddles MiniGame now renders the same multiple-choice card the standalone/riddlespage uses · question, N option buttons (ramped 3 → 6 with labyrinth level), correct/wrong styling, and the riddle’s explanation. Polymath, the labyrinth, andrequestMiniGame()all share this one rendering, so “NOW PLAYING: RIDDLES” finally plays a riddle.tests/games/riddlesNoFail.spec.tsxretired and replaced bytests/games/riddlesOptions.spec.tsx(correct pick → onWin, wrong pick → onFail, button count = answer count). - fix Polyglot encounter defaults to the player’s own UI language. The hosted Polyglot encounter (Polymath, labyrinth,
requestMiniGame) used to forcibly exclude the player’s UI language from the rotation · so a Swedish speaker got Korean, Japanese, and Polish words with no way to opt down. The encounter now defaults to the player’s UI language so a Swede sees Swedish words and a German speaker sees German words. The standalone/polyglotpage still exposes a language picker for players who want to actually practice a foreign language. Falls back to the original foreign-language rotation only when the dataset somehow lacks the player’s UI language. - fix Piano + chess boards fit on mobile. Both surfaces used fixed pixel widths (40px white keys × up to 14, 44px chess cells × 8 + label gutters) which overflowed below ~420px viewports · the keyboard ran off the edge of the white card and the rook on the h-file was clipped in Game Mode. Both now scale: piano keys flex to share the container’s width with black keys positioned in percent so they track the white-key flexing exactly; chess cells use
clamp(30px, 10.5vw, 44px)with proportional label gutters and glyph sizes. The boards stay 44px on desktop and shrink smoothly to fit a 360px phone in Game Mode, no horizontal scroll. - fix Polymath wrapper stretches to its host’s width. The Polymath delegate’s root
<div>had no explicit width, so its sub-game inherited a content-shrunk box that rounded down further on every nested flex parent · noticeable in Game Mode where the chess / piano surface was rendered narrower than the surrounding card. Setwidth: 100%+display: flex; flex-direction: column; align-items: stretchon the Polymath wrapper so every hosted sub-game gets the full Polymath card width.
Improved
- improve Tone Knowledge picks Piano vs Notes up front. The standalone
/tonespage now opens with a two-tile surface picker · 🎹 Piano or 🎼 Notes · before the Start button. The selection persists in localStorage per surface and forks the high-streak board so each surface earns its own personal best. Notes mode runs the existing treble-clef staff with note-name labels off, so the goal is unambiguously “learn to read sheet music” not “match labels to dots.” The staff itself was redrawn as a parchment leaf · cream-to-amber paper gradient, ink-brown clef and noteheads, opening + closing bar lines, layered inset/drop shadows · so the page feels like a classical notebook rather than a flat svg. Guitar and mixed-instrument rounds still appear inside Polymath and the Labyrinth pool; the standalone page is the dedicated trainer for the two main shapes. Five new strings (games.tones.surface_picker,surface_piano,surface_notes,surface_piano_desc,surface_notes_desc) propagated across all 25 locales; the in-game label for the staff renamed from “Staff” to “Notes” so the chrome reads consistently with the picker.
April 24, 2026
New
- improve Geo articles now embed the Geo mini-game. The Memorise Sweden's Top 10 Cities article (and every locale of it) used to ship a hand-crafted dot-grid SVG map for each city · 11 inline maps, ~1500 lines per article, drifting away from the live game. Each map is now a
<InlineGame gameId="geo" />embed driven byprogress,showTargetLabel, andshowTargetArrow: section #1 renders the country with Stockholm marked, #2 renders Stockholm visited with an arrow to Gothenburg, #3 adds Malmö, and so on. One source of truth for country geometry · adding a city to the data file now updates every article that references it. Pattern is documented inCLAUDE.mdso every future geo article follows the same shape (any country, any topic). - improve Strict per-locale blog filter. Non-English blog indexes (
/sv/blog,/de/blog, …) used to fall back to English articles when the locale lacked its own translation, and the English-only/what/explainers were unconditionally added to every locale’s feed. Both leaks are gone · each locale now only renders posts that have actually been translated into it. Untranslated slugs 404 instead of serving English markdown under a localised URL (the language-switcher footer still tells visitors which locales DO have a translation). - improve The PlayMemorize logo always takes you home. Clicking the logo in the game header used to point at the current game's own landing · a no-op when the player was already on it. It now points at the site root (locale-aware), so every game page has a one-tap way out to the catalogue.
- new Per-game filter on every Polymath variant. The idle panel of
/all,/polymath-math,/polymath-knowledge,/polymath-memory, and/polymath-reasoningnow shows a collapsible “Game filter” checkbox list of every game in that variant’s pool. All games are checked by default; uncheck the ones you find too hard or just don’t feel like playing today and they drop out of the rotation. The selection persists in localStorage per variant and is locked the moment a streak starts so you can’t accidentally change the pool mid-run. If everything is unchecked the full pool is silently used as a fallback so the game never deadlocks. Implemented as a singlepoolstring field on the sharedmakePolymathModule()schema ·chooseSubGameintersects the player’s allow-list withMODE_GAME_IDS[mode]and picks deterministically from the result. - new Tone Knowledge at
/tones. Free ear-training game · hear a sequence of 1–10 musical notes, then click them back in order on a virtual instrument. Three surfaces share one chromatic pitch pool: piano (white + black keys, mouse / touch / keyboard), guitar (six strings × twelve frets, correctness checked on pitch so any equivalent fingering counts), and treble-clef staff (click at the line or space height to pick a note). Difficulty scales four dimensions at once · sequence length grows with labyrinth level (3 → 10), pitch range widens with difficulty (white keys → diatonic → chromatic 1-octave → chromatic 2-octave), tempo shrinks (600 ms → 320 ms), and note-name labels disappear at d≥5 so expert mode tests pitch recall not reading. Roughly a quarter of low-difficulty rounds (rising to three-quarters at expert) are transposed snippets of recognisable folk and public-domain melodies (Twinkle Twinkle, Ode to Joy, Für Elise opening, Mary Had a Little Lamb, Jingle Bells, Frère Jacques, Hot Cross Buns, …). When the player misses, the explainer says exactly what they played, what the target was, and the interval between · “you played E4, one semitone below F4 (minor 2nd flat).” The shared 24-note frequency table moved out ofsimonAudio.jsintosrc/utils/toneAudio.jsso Color, Tone Knowledge, and any future music game pull from the same source. Auto-included in the Memory Polymath pool and the full Polymath pool. - new Chess Mate now plays like real chess. The old “pick a move from a shuffled list of UCI strings” input is gone. Click a white piece to select it · the board highlights the piece in gold and paints a green ring on every square it can legally move to. Click a destination to commit the move; click the same piece again to deselect; click another white piece to switch selection. The UI can never let the player try an illegal move because the legal-destination set comes from the same
legalMovesForhelper the solver uses. Works with mouse, touch, and keyboard (squares are now focusable buttons with Enter/Space). - new Polymath split into four themed standalone games. The
/allpage no longer hides four filter modes behind a tab bar · each mode now ships as its own landing page and its own entry in the site catalogue. Math Polymath, Knowledge Polymath, Memory Polymath, and Reasoning Polymath all live alongside the full-catalogue Polymath in the Polymath section, so the five streak variants read as one cohesive group on the home page instead of being scattered across Memory / Knowledge / Numbers / Reasoning. Memory Polymath replaces the earlier Numbers variant whose pool overlapped Math too heavily · the new pool draws cleanly from pi, memory, color, and ghost. Each variant carries its own high streak, FAQ copy, PWA precache entry, and Schema.org FAQPage; shared logic stays in themakePolymathModule()factory so the five games remain byte-identical except for their id, label, and pool.
Fixed
- fix Odd One Out fruit + shape categories no longer rely on botany / geometry edge cases. The standalone
/odd-one-outgame and the labyrinth’sOddOneOutEncounterboth shipped emoji odd-pools that contained items belonging to the “wrong” group under a defensible reading. The fruits category mixed 🍅 (tomato), 🌽 (corn), and 🥒 (cucumber) into the “not a fruit” pool · all three are botanically fruits, so a botany-aware player could correctly identify them as belonging with the apple / banana / grape group. The squares category used 💠, 🔷, and 🔶 (diamonds) as the “not a square” pool · a diamond is mathematically a square rotated 45°, which a geometry-aware player would catch. Both pools now use unambiguous outliers: roots / tubers / bulbs / leaves / flower-heads / fungi for the not-fruit pool, and circles / triangles / stars for the not-square pool. - fix Analogies labyrinth encounter no longer offers a defensible second answer. The labyrinth’s
AnalogiesEncounterdistractor pool only excluded items whosebmatched the correct answer · thebfrom the SHOWN pair (e.g. “pup” in wolf : pup :: bear : ?) could still surface as a distractor. With the “young animal” relation containing multiplecub/pup/foal/calfentries, that left rounds where two on-screen options were colloquially correct. Encounter generation now mirrors the standalone Analogies game: pickp2with abdistinct fromp1.b, exclude bothp1.bandp2.bfrom the distractor pool, and de-duplicate bybso the same label can never appear twice. - fix Riddle distractors that fit the clues just as well as the answer were swapped. A second pass through the riddle pool caught four distractors with defensible alternative readings. “I have hands but cannot clap, a face but cannot smile” (
cl-clock) used to list A doll and A puppet · both have literal hands and a face that don’t clap or smile. “I have cities but no houses; forests, but no trees; water, but no fish” (cl-map) used to list A globe · a globe depicts the same things without containing them, exactly like a map. “I am always coming, but never arrive” (wa-future, answer: Tomorrow) used to list The horizon · a horizon also recedes as you approach it, which makes it a defensible answer. “The more of me you take, the more you leave behind” (cl-candle, answer: Footsteps) used to list A path · walking more of a path literally leaves more of it behind you. All four swapped for distractors that cleanly fail one of the riddle’s clues. - fix Pruned 14 illusions whose static-SVG implementation could not deliver the claimed effect. A user-led audit confirmed the Asahi glow patch (and others) read as plain grey wedges instead of self-luminous. Removed:
asahi,lilac-chaser,peripheral-drift,stepping-feet,motion-binding(animation- or fixation-dependent · don’t fit a quiz round),watercolour,cornsweet,neon-spread,todorovic,munker-white,bezold(rendering too crude or too contrast-sensitive to produce the perceptual effect on a typical screen),freemish-crate,bourdon,ehrenstein-line(implementation drew the figure without the asymmetry needed to trigger the illusion). The remaining ~42 illusions stay · all classics that survive a small-canvas SVG rendering (Müller-Lyer, Ebbinghaus, Ponzo, Café Wall, Hermann grid, Adelson checker shadow, Kanizsa figures, Necker cube, Penrose triangle, …). Each removed type is gone fromIllusionType,TYPES_BY_CATEGORY, the renderer dispatcher, the generator’s switch branches, and any orphan blog articles. - fix Polymath no longer strands the player on “Loading …”. A sub-module whose JS chunk failed to resolve (broken deploy, stale service worker, very slow network) could leave the Polymath shell spinning on “Loading sudokuforce…” forever with no exit. Added a 10 second timeout and a new “Try another” button that re-seeds the sub-game picker so the player can skip past a broken chunk without ending their streak. Translated across all 25 locales via the new
games.all.try_anotherkey. - fix Chess Mate / Mastermind Deduce / Sudoku Force explainers now translate. The post-answer verdict on all three games still read as hardcoded English (“Checkmate.”, “You pinned the unique code.”, “4 is the only digit that fits.” …) even in non-English locales. Added six new i18n keys (
games.chessmate.explain_won/explain_lost,games.masterminddeduce.explain_won/explain_lost,games.sudokuforce.explain_won/explain_lost) translated across all 25 locales, and wired the threeexplaincallbacks through the locale'st(). - fix Riddles no-fail encounter dedupes across rounds + keeps the explainer. Multi-round riddle encounters (L20+) could hand the player the same riddle twice in a row when the filtered pool was narrow. The pre-computation now tracks seen ids and retries up to 4× the requested round count before falling back to a repeat. The reveal card also paints the riddle's own “why the answer works” explanation below the answer line, so the guided-tour flow keeps the educational payoff the old options mode had.
- fix Goal marker label positioning stabilised. The badge under the 🏁 glyph used
position: absolutewithout an explicitleft, so the browser fell back to auto-placement and different engines drew the label in different spots. Now pinned atleft: cx; transform: translateX(-50%), which centres the badge under the flag deterministically on every engine. Marker icon + label now render as siblings instead of nested, so overflow can't clip one without the other. - fix Preloader skips hidden labyrinth encounters.
preloadAllAdapterswas iterating the fullADAPTERSmap after the catalog refactor, which meant it was burning bytes on Illusions / Riddles / Polyglot chunks that the player would never meet in the maze. It now preloads onlyLABYRINTH_VISIBLE_GAME_IDS· hidden entries still load on demand vialazyAdapter.
April 23, 2026
New
- new Polymath game at
/all. Cross-game streak roulette that pulls random rounds from every PlayMemorize mini-game. Five themed modes filter the pool: All (full catalogue, labyrinth excluded), Math, Knowledge, Numbers, and Reasoning. Each mode keeps its own high streak. Built on the sharedModuleStreakGame+ theGameModuleAPI: a thinMiniGamedelegate dynamically loads whichever gamegenerate()picked and forwardsonWin/onFail/onAbortunchanged, so a Polymath round of Chess Mate plays byte-identically to a native Chess Mate round. Landing page, 25-locale i18n block, FAQ copy, precache entry, and a dedicated conformance test covering the mode pool references all land in the same pass.
Fixed
- fix Pi digit counter no longer desyncs on restart. "I know X digits" could show
0even when the stored group index was mid-run, and the first three taps of a new run silently no-op'd until the player hit Reset. Root cause: stalelocalStoragevalues could push the group index past the constant's last group, and the reset path conflated learn-mode and play-mode counters. Pure helpers (parseStoredGroupclamps to[0, totalGroups-1],buildResetSnapshotpreserves learn-mode taps, a new per-constant-best-tapslocalStorage key tracks personal bests) now back theGameCorestate machine with unit-test coverage. - fix Sequences “Descending” topic is now real. The standalone picker offered a descending filter but the dispatch table only referenced the built-in ascending generators, so selecting it silently fell back to whatever the difficulty pool produced. The generators were extracted to a pure
src/components/sequences/generators.jsmodule and the descending branch now dispatches to either a geometric divide-by-N pattern or a strict arithmetic decrease. Distractors can no longer be zero, negative, or match a value already visible in the shown prefix · the classic “81, 27, 9…” confusion is gone. - fix Crazy Comparisons clicks register again. A stale-closure race in the auto-spin → handleSpin flow could display round N's slot text while rendering round N+1's answer buttons, so clicks validated against the wrong
correctIdand the game felt dead.handleSpinandhandleAnswernow read the current round through auseRefso the slots and options always agree. Addedtests/e2e/crazy-comparisons.spec.tsto exercise the full Spin → Answer flow. - fix Crazy Comparisons: slot machine now visibly spins. The 4-slot blur was silent — tones played but the text never changed.
useTranslations()returns a newtfunction on every render, which cascaded through the memoizedgeneratorreference, and an effect keyed on[generator]fired every render · blankingslotTextsback to['','','','']and snappingphaseback toidlefaster than the 80 ms spin intervals could update them. Keyed the reset effect on the raw[lang, categoryFilter]inputs instead, so the slots blur through words again while the tick tones play. - fix Ghost Mini-Game shows the full board during recall. The labyrinth
GhostEncounterstripped the grid as soon as recall started, leaving only three choice buttons with no visible cue to which slot was empty. The recall view now keeps the original grid on screen with a 👻 placeholder where the removed emoji was, mirroring how the standalone Ghost game has always worked. - fix Memory now opens at 6 cards. The default Memory grid dropped to
3×2(3 pairs) so the matching mechanic is actually interesting from the first round. Larger grids remain available through the dropdown, and the labyrinth encounter's legacy pairs fallback clamps up to 3 so Memory in the maze is never a 4-card round. - fix No more unit abbreviations in mini-games. Crazy Comparisons explainers and the Stroop timer now spell out units (“kilograms”, “square meters”, “kubikmeter”, “sekunder”…) across all 25 locales instead of
kg/m³/ bares.
Improved
- improve Riddles is now a guided no-fail “think, then peek” flow. Inside the labyrinth and every other hosted mini-game slot, Riddles mirrors the new Illusions pattern: the teaser shows the question with a single Reveal primary button, the reveal shows the answer under a “The answer” heading, and the module always calls
onWinafter the final reveal · neveronFail. No more multiple-choice grading, no red/green chrome, no “The answer was” post-mortem. A newroundsparam ramps with labyrinth level (L0 = 1 riddle, L20+ = 3). The standalone/riddlespage still shows the options picker (it readsbuildRounddirectly for its own streak flow). Three new i18n keys (riddles.cta.reveal,riddles.cta.done,riddles.reveal.heading) translated across all 25 locales. Covered by a newtests/games/riddlesNoFail.spec.tsx. - improve Visible “Mål” / “Goal” marker on the labyrinth board. The goal tile now paints a 🏁 checkered-flag glyph with a small localised text badge (Goal, Mål, 目标, Hedef, …) so the player can see the level exit from the moment the maze mounts, before they've walked close enough to fog-reveal that area. One new i18n key (
labyrinth.tile.goal) translated across all 25 locales; painted inIconOverlay.tsxin its own layer so it can't collide with NPCs, items, or the help bubble. - improve Single typed labyrinth encounter catalog. The per-level encounter pool, the adapter loaders, and the “is this game an encounter?” question now read from one source:
src/components/labyrinth/encounters/catalog.ts. Each entry carries anid, amoduleId, avisibleInLabyrinthflag, and a tier (1 / 2 / 3). Flipping a game tovisibleInLabyrinth: falsedrops it from the encounter pool without unregistering the module, sorequestMiniGame()and<InlineGame>keep working. Illusions and Riddles are nowvisibleInLabyrinth: false(B2 + B4): no-fail tours shouldn't gate progression. Covered bytests/games/labyrinthCatalog.spec.ts. - improve Illusions is now a guided no-fail tour. Each round runs as a two-beat experience: the teaser names the illusion and asks what to look for, then a single Show the truth button swaps the overlay to a neutral reveal card that narrates why the eye gets fooled (truth line + per-illusion caption). No more A/B/same guessing in the labyrinth encounter, no red/green chrome, and the module never calls
onFail· onlyonWinafter the final reveal. Three new i18n keys (illusions.cta.show_truth,illusions.cta.done,illusions.reveal.heading) translated across all 25 locales;Reveal.tsxgains an optionaltoneprop so the standalone page keeps its legacy correct/incorrect chrome unchanged. Covered by a newtests/games/illusionsNoFail.spec.tsx.
April 21, 2026
Improved
- improve Chess Mate, Sudoku Force and Flag a Mine now spawn as labyrinth encounters. The three games already shipped as conformance-clean
GameModules (deterministicgenerate(params, seed), level-scalingparamsFromDifficulty(d, lvl), sharedMiniGame) but were missing from the labyrinth's encounter pool. Added them toGameId&SUPPORTED_GAMESinengine/types.tsand registered threeasAdapterLoaderentries in the encounterADAPTERSregistry. They join the top-tier pool (level 6+) with the same level-ramped difficulty knobs their standalone pages use · no per-encounter adapter code, the unified GameModule API carries them straight through. - improve Easy / Medium / Hard tier pickers for Chess Mate and Flag a Mine. Matches the pattern Sudoku Force already ships: a three-button row above the Start card sets the round difficulty. Chess tiers vary the candidate-move count (Easy 3 · Medium 4 · Hard 6 legal decoys). Mine tiers vary the board size & density (Easy 6×6 with 5 mines · Medium 7×7 with 10 · Hard 8×8 with 15). Each tier keeps its own high-streak in localStorage. Six new i18n keys per game × 25 locales · labels reuse each locale's Sudoku Easy/Medium/Hard translations, descriptions are translated for the top locales and fall back to English elsewhere.
- improve Game-switcher dropdown capped at 3/4 of the viewport. Lowered
max-heightfrom80vhto75vhon both the in-gameGameHeaderpanel and the site-wideSiteNavStaticpanel, so the dropdown never reaches all the way to the bottom edge of the screen · the remainder of the list scrolls inside the panel. - improve Flag a Mine is now a full playable minesweeper. Click-to-reveal with classic flood-fill on zero regions, right-click or a flag-mode toggle to plant flags, a running mine counter, and a guaranteed safe opening (the largest 0-region is auto-revealed so the first move is never a blind guess). Board scales 6×6 / 7×7 / 8×8 by difficulty and mine density ramps per labyrinth level. Old "guess the one guaranteed mine" single-pick mode retired.
- improve Mastermind Deduce: column-labelled feedback grid. Past guesses render in a four-column row (Guess N · pegs · black-dot count · white-dot count) with sticky column headers that spell out In position and Color only. A down-arrow between history and choices makes the "pick the surviving code" flow obvious for first-timers. Pegs use a radial-gradient 3D look; black / white feedback dots use the classic Mastermind styling. Translated across all 25 locales.
- improve Chess Mate: algebraic rank / file labels & harder mate-in-one patterns. Board now renders inside a 10×10 grid with a-h file letters on top and bottom and 1-8 rank numbers on both sides · matches how real chess boards read. Added two new tactical compositions to the pool: a smothered mate (Nh6 → f7#) and an Arabian mate (Rh1 → h7# defended by Nf6), so the puzzle set is no longer dominated by back-rank patterns.
- improve Home page scroll no longer clips the bottom cards.
.landing-containerusedjustify-content: centerwithmin-height: 100vh· now that the catalog has grown, flex centering pushed the first row above the scroll origin and the bottom rows became unreachable. Switched tojustify-content: safe centerso short pages still center vertically and tall pages scroll normally. - improve The board stays on screen when you answer. In reveal mode the
MiniGameShellno longer collapses the prompt into a big ✓/✗ — the chess position / Sudoku grid / mine board / Rush Hour layout / Mastermind log all stay rendered while a circular ✓/✗ verdict floats at the top-right corner of the prompt. Players can now compare their pick against the correct answer directly on the original board before pressing Continue. - improve Sudoku Force: Easy / Medium / Hard tier buttons. Easy seeds a near-solved grid with a single blank (the target); Medium sprinkles ~16 extra blanks around the target; Hard leaves only the target's row, column and 3×3 block filled in, mirroring a real late-game Sudoku. Each tier keeps its own high-streak and the target's forced digit is always uniquely determined. Powered by a new
TIER_PARAMSpreset and aparamsOverride+preStartslot on the sharedModuleStreakGameso future games can expose tier pickers the same way. - improve Flag a Mine is readable for kids. Hidden cells are now labelled tactile slate tiles (A, B, C, …) with a raised 3D bevel; revealed zeros render as dug brown “holes”; revealed numbers keep the classic minesweeper palette on a beige surface. On reveal the target cell shows a 💣 and a wrong pick shows a 🚩, and a new legend row spells out what hidden / dug / numbered cells mean. Three new i18n keys (
legend_hidden,legend_dug,legend_num) translated across every supported locale. - improve Chess Mate pieces are bigger and crisper. Board cells bumped from 32 px to 44 px; piece glyph size raised to 34 px. Both colours now render from the same solid-silhouette Unicode set (U+265A–F) so CSS
color+ a bold textShadow outline distinguishes white from black; the thin-line outlined glyphs (U+2654–9) that rendered as unreadable scribbles on several platforms are no longer used. The board also has a subtle drop-shadow and a softer border. - improve Round-to-round transitions feel snappier. Legacy auto-advance flash trimmed from 700 ms to 420 ms in both
MiniGameShelland the labyrinthChallengeShell. Games with anexplaincallback are unaffected — those already advance on Continue.
Fixed
- fix Rush Hour Escape removed. The sliding-block mini-game's single-move oracle couldn't be disambiguated from a quick glance at the board · players reported that even after reading the rules it was unclear which tap did what. Pulled the game, its module, its landing pages, its 150 i18n strings, its FAQ copy, its precache entry, and its catalog row. Will revisit as a full 10-move puzzle when the shell supports multi-step encounters.
- fix Sudoku Force explainer no longer shipped an emdash. The "chained deductions" copy and the fallback-value glyph used
—/'—'which slipped past the content linter becauseF-11only scanned.astro/src/components. Extended the check to cover.tsx/.jsxundersrc/gamestoo, so user-facing JSX prose (explainers, hints, prompts) can't regress into emdash land. - fix Chess Mate: broken starting positions replaced. Two of the four frozen mate-in-one compositions were illegal (one started with Black already in check on White's turn; one had the winning rook move capturing the Black king itself). The pattern set was rebuilt with four verified mate-in-one positions (back-rank with pawn blockade, queen-in-corner, two-rook ladder, queen back-rank), so every round is now a legal position that resolves to exactly one mating move.
- fix Header game-switcher dropdown is now scrollable. With 26 games registered, the panel overflowed the viewport on short screens. Matched the behaviour of the language picker (
max-height: 80vh; overflow-y: auto; overscroll-behavior: contain) for both the in-gameGameHeaderand the site-wideSiteNavStatic. - fix Flag a Mine visual polish. Unrevealed cells now read as tactile hidden tiles (raised slate shading with letter label), revealed zeros render as clean blank cells, and revealed numbers use the classic minesweeper palette (1 blue, 2 green, 3 red, 4 navy, …). The board no longer looks like a purple name tag grid.
- fix Rush Hour Escape: clearer controls + rules. Slide buttons now describe the move as direction + cell count (Red car → 1 square) instead of raw
(x,y)coordinates. The board shows a coral → exit marker on row 3 and a one-line rules tip ("The red car exits right. Slide any car along its lane if the path is clear"). Works in all 25 locales. - fix Mastermind Deduce: in-game legend for the peg feedback. A small legend panel now explains ● = right colour + right position, ○ = right colour but wrong position, and the feedback row is rendered as actual black/white dot pegs next to the text fallback. Translated into all 25 locales.
- fix Every round of the five new games now explains itself. After picking an answer, the shell shows ✓/✗ plus a short explainer ("Queen a7 → h7 delivers mate · the black king has no legal escape", "Row already contains 5, 3, 6, 7, 8, 9, 1, 2 so only 4 fits here", "The revealed 1 at row 2 touches exactly one hidden cell, so that cell must be the mine", …) and a Continue button. Implemented generically via the shared
MiniGameShellexplainprop so any future game can opt in with a single callback.
April 20, 2026
New
- new Five new reasoning games. Chess Mate (mate-in-one picker), Sudoku Force (forced-digit Sudoku micro-puzzles), Flag a Mine (guaranteed-mine constraint deduction), Rush Hour Escape (winning-slide sliding-block puzzle, later retired), andMastermind Deduce (unique-code deduction from peg feedback). Each round is deterministic (pure
generate(params, seed)) and validated by a cheat-proof oracle —evaluateMateInOne,verifyForcedNumber,verifyGuaranteedMine,isWinningSlide,verifyFinalDeduction— with no preset "correct" flag to tamper with. All five ship asGameModuleentries so they double as Labyrinth encounters and inline blog embeds.
Fixed
- fix Header game-switcher dropdown no longer renders behind inline game cards and illusion SVGs. The header's
backdrop-filter: blur()had created a new stacking context that trapped the dropdown below any later-painted page sibling. Header is nowposition: sticky; z-index: 1000; isolation: isolate, so the game-switcher panel paints above every page element (except modals). - fix Simon Says fully translated in 11 locales. The
simon.*i18n block had been left as English in Czech, Greek, Hebrew, Hungarian, Italian, Dutch, Polish, Romanian, Thai, Turkish and Ukrainian · 17 strings × 11 locales = 187 keys now properly translated (title, colors, players, start, round, watch, your turn, correct, game over, score, best, new high score, play again, player turn, winner, speed, idle description). Translations reuse each locale'sghost.*vocabulary where the phrase is identical (Correct!, Game over!, Score, Best, Play again, etc.) so the two games feel consistent. "Simon Says" retained as a brand name in every locale. - fix Geography game: removed remaining Turkish place-name suffixes across 48 country files. Mechanical transform "X Dağı" → "Mount X" (~60 mountains), "X Gölü" → "Lake X" (~66 lakes), "X Rezervuarı" → "X Reservoir" (8 reservoirs). Danube renamed per country (Tuna → Donau/Dunărea/Duna/Dunav/Dunaj/Dunay depending on language). Compound names fixed by hand: Lake Büyük Ayı → Great Bear Lake, Lake Büyük Köle → Great Slave Lake, Lake Büyük Tuz → Great Salt Lake, Lake Urmiye → Lake Urmia, Lake İşkodra → Lake Skadar, Şattülarap → Shatt al-Arab, Şeria → Jordan, Trablus → Tripoli, Bingazi → Benghazi (Libya), Barselona → Barcelona (Venezuela).
turkey.jscorrectly retains its 5 native Dağı/Gölü entries. - fix Geography game: replaced Turkish place names that had bled into 26 country files. Capitals and major cities that had been seeded from a Turkish dataset now use the native or English exonym matching the rest of each file: Moskova → Moscow, Atina → Athína, Viyana → Wien, Varşova → Warszawa, Lahey → Den Haag, Brüksel → Brussels, Lizbon → Lisboa, Budapeşte → Budapest, Sofya → Sofia, Belgrad → Beograd, Bükreş → București, Tiflis → Tbilisi, Pekin → Beijing, Prag → Praha, Kopenhag → København, Tahran → Tehran, Bağdat → Baghdad, Meksiko → Ciudad de México, Seul → Seoul, Barselona → Barcelona, Münih → München, Küdüs → Jerusalem (+ Hayfa, Riyad, Cidde, Mekke, Medine, Halep, Şam, Trablus). Also the German rivers Ren → Rhein and Tuna → Donau, and two French rivers missing their accents Rhone → Rhône, Saone → Saône, plus Ecrins → Écrins. A systemic data-quality issue remains in the lake dataset: 27 country files still use Turkish "Gölü" (lake) in their lake names (e.g. Huron Gölü in
canada.js) and many more mountain / river / secondary-city names are likely sourced from the same Turkish dataset · tracked for a separate regeneration pass. - fix Swedish UI strings: restored missing diacritics.
explore.descandconstants.deschad "pa" where Swedish needs "på" (meaning "on"), andconstants.descmisspelled "Bläddra" ("browse") as "Bladddra".simon.game_overandghost.game_overwere left as the English "Game over!" · now "Spelet slut!". Fixed insrc/i18n/ui.ts. - fix Define (word meaning) no longer asks misleading "Activities vs Objects" questions. CLDR files many clearly-object emoji (paintings, medals, balls, gifts, tickets, game pieces, ski gear, kites) under its Activities group via the arts & crafts, award-medal, event, sport and game subgroups, which made puzzles like "Tavla" (Swedish for painting) correctly mark Objekt as wrong. The Define game now skips the Activities category entirely and draws from the 5 remaining categories (people & body, animals & nature, food & drink, travel & places, objects). Affects all 25 locales.
Improved
- improve Euler's Identity explainer now renders in every site language. The
/learn/pi/eulers-identitycomponent bundle gainedit,tr,ro,hu,cs,el,he,thanduklocales (29 keys each · headings, constant descriptions, step labels, unit-circle copy, the Feynman quote, and the 1748 Introductio historical note). Bundle went from 17 to 25 of 25 supported locales · no more English fallback on the Euler page. - improve Major Pincode System guide now renders in Italian. The
memorise-body.jsoncomponent bundle gained anitlocale (97 keys · the whole write-up of the muscle-memory + Major System method, from core idea through numpad paths, the 10-rule reference, a worked example on pi's first six digits, practice guidance, and the full footer). English words that are part of the mnemonic (Mitt, Road, Lip, Tomb, Comb…) are preserved as-is · translating them would break the system. Italian is at 15 of 25 locales.
New
- new Riddles game at /riddles. Text riddles with multiple-choice answers. Pick difficulty (easy / medium / hard or all), pick a type (classic, what-am-I, wordplay, logic, math, or all), and pick how many answer choices you want to see (2–6). Each round is a deterministic pull from a themed pool: distractors are drawn from the riddle's own trap bag first, then from sibling riddles of the same type, so the choices stay topic-coherent instead of degenerating into random nouns. Endless streak mode with per-filter best score, so changing any dial starts a fresh target. Ships as a GameModule, so it doubles as a labyrinth encounter. UI strings translated into all 25 locales; riddle content itself is English-only in v1 with a documented fallback path for future locale packs.
- new Generic
<InlineGame>blog component. Drop<InlineGame gameId="…" params={…} client:load />into any MDX article and the targeted game'sMiniGamerenders inline, fed by the same deterministic generator the standalone page uses. Generalises the original<InlineIllusion>pattern to every game inGAME_MODULES· no per-game embed component needed. Lives atsrc/components/blog/InlineGame.jsx. - new Shared deep-link helpers (
parseGameUrlParams,buildGameDeepLink). One contract every standalone game page reads from the URL:?<schema-key>=…+?seed=…+?difficulty=…. Validates against each game's GameModule paramsSchema for free, so unknown values silently fall back to defaults and authors don't have to learn 17 conventions. Lives atsrc/utils/gameUrlParams.js; documented inADDING_A_GAME.md§5c. - new Polymath category on the home page. Labyrinth moves out of the “Reasoning” group into its own top-of-page “Polymath” section · the message is now explicit: this is the gauntlet you beat to prove you're good at a bit of everything. Game-card description updated to reflect the per-level difficulty ramp.
- new Polymath ramp: every game now scales per labyrinth level. Previously the labyrinth's
difficultycapped at 10 and most encounters ignored the unboundedlevelcounter entirely · level 50 played exactly like level 5. Each game'sparamsFromDifficulty(d, lvl)now consumes both arguments and exposes a level-scaled knob (length,pairs,choices,cap,rounds,count,maxLen,gridSize,precision,targets, …) derived through the new sharedlevelRamp(level, base, perLevel, max)helper. The labyrinth gauntlet now genuinely gets harder every level · more digits to memorise, more pairs to match, bigger numbers to compute, more options to disambiguate. Lives atsrc/lib/games/levelRamp.ts; contract documented inADDING_A_GAME.md§5d andCLAUDE.md.
Improved
- improve Stop a game → Game Mode exits in the same gesture. Tapping any game's Stop button used to leave the player in distraction-free Game Mode and force a second tap on the floating Exit pill to return to the page chrome. Every game's Stop handler now dispatches a
pm:game:stopevent that the GameModeToggle listens for; if Game Mode is active, it deactivates immediately. Also addedsrc/utils/gameMode.jsas the cross-component event bus · React game islands and the inline Astro toggle script now talk through one documented contract. - improve Riddles: every riddle now explains itself after you answer. All 41 riddles carry a written-out one-to-three sentence “why the answer works” that unfolds on both correct and wrong. For the classic “bat and ball” puzzle you get the algebra; for “what 9-letter word contains all five vowels in order?” you get f-A-c-E-t-I-O-U-s spelt out; for “smallest whole number equal to 7 times the sum of its digits” you get the check that n=7 and n=14 fail. Correct answers no longer auto-advance · you read the explanation and tap “Next riddle” when you're ready. The “Correct!” label, the “Next riddle” button text and the “The answer was” label are translated across all 25 locales.
- improve Labyrinth: quest-giver now hides the reward until you've heard the brief. Previously the giver's speech-bubble spelled out what they'd lost and what they'd trade, and the lost item sat visible on the map from the moment the level loaded · there was no moment of discovery. The flow is now three beats: the giver yells “Help! Help!” from their tile, walking up to them opens a pop-up with the full quest (lost glyph → reward → obstacle) and a single “Okay” button, and dismissing the pop-up is the first time the lost item becomes visible on the map. Revisits before fetching the item are silent reminders (breathing templated bubble); revisits with the item in hand still trigger the exchange and clear the giver tile. Translated into all 25 locales.
- improve Labyrinth: pi-recall memorisation now has a visible study countdown. The memorise screen shows a shrinking green→amber→red progress bar and a whole-second readout so the player knows exactly how long they have to study before the digits vanish and the numpad appears.
- improve Labyrinth: maze is tighter and the solution path longer. The generator used to braid away every dead end, which carved so many shortcuts that the route from start to goal often skipped most puzzle tiles · you could finish a level without answering more than one or two questions. It now braids only ~25% of dead ends, so the solution path stays winding. Scattered puzzle-tile density also bumped (~1/5 of eligible cells instead of ~1/8, cap 18 instead of 12), so you actually have to work your way through a gauntlet of challenges on the way up.
Fixed
- fix Illusions: Poggendorff's three candidate lines are finally three distinct positions. The non-true slots were offset by
-spreador+spreadbased on their index relative totrueIndex, which produced two identical offsets whenevertrueIndexwas 0 or 2 · so on roughly two-thirds of rounds the player only saw two visually distinct candidate y-values with one of them sharing the position of a second label. The three offsets {−spread, 0, +spread} are now shuffled into the three slots so every round shows three strictly different y-values. - fix Illusions: Poggendorff right-side candidates now slant at the same angle as the left line. The three candidate segments were drawn horizontally while the left line was slanted, which broke the illusion entirely · the whole point of Poggendorff is that a continuous slanted line looks discontinuous across a rectangle. Candidates now share the left line's slope, and the geometry is re-anchored on the canvas midpoint so the bottom candidate no longer clips past the 220-px canvas bottom at max angle.
- fix Illusions: Sander parallelogram stays on-canvas at easy difficulties. At d=1 the skew reached 40° and the width reached 240 px, pushing the top-left and bottom-right corners to x=−10 and x=330 · both outside the 320-px canvas. Reduced max skew to 30° and width to 220 px so the four corners stay inside the canvas with ≥15 px margin at every difficulty level.
- fix Illusions: Benary cross triangle A now actually touches the cross. Triangle A was drawn at the horizontal arm's top-left tip with one leg at y=cy−thick/2 running away from the arm and the other at x=cx−arm running upward into white space · both legs were in empty space, leaving A's only contact with the cross a single vertex. Triangle B meanwhile sat snugly in a concave inner corner with two full legs on black edges, so the two triangles had totally different surround-contrast and the Wertheimer-Benary effect evaporated. A is now an isoceles triangle with its 30-px base flush along the arm's top edge and its apex in white space, matching B's contact area but in a convex configuration.
- fix Illusions: Fraser spiral's dashes now actually tilt, so a spiral finally appears. The renderer drew every dash as a flat chord with both endpoints exactly on the ring circle · despite a comment promising a ±12° tangent rotation, no tilt existed at all and the figure read as zebra rings rather than a spiral. Each dash now starts 4 px INSIDE the nominal radius and ends 4 px OUTSIDE, which cants it consistently toward the next ring; repeated around every ring in the same direction the eye chains the canted dashes into a single inward-winding spiral, even though the underlying rings remain truly concentric (trace any one of them and it closes on itself).
- fix Illusions: impossible trident now has equal prongs and equal bars. The five vertical bands that split the figure's height were sized 15 / 30 / 30 / 30 / 15 px, giving three right-side prongs of 15 / 30 / 15 px and left-side bars of 15 px and 45 px · the drawing looked broken rather than impossibly-connected. An extra "middle-prong terminus" vertical line at x=xL+140 from yB to yD was also drawn across the figure's midpoint, which gave away the trick by putting a visible cap exactly where your brain is supposed to be unable to decide whether there are two bars or three prongs. Rebuilt on five equal 24 px bands: three equal right prongs, two equal left bars, and no visible midpoint vertical · only yB and yC continue all the way across (as the inner edges of both the left bars and the middle right prong), while yA and yD stop at xL+140, which is the classic blivet construction.
- fix Illusions now scales with labyrinth level. The polymath-ramp refactor wired every other game's
paramsFromDifficulty(d, lvl)to consume both arguments via the sharedlevelRamphelper, but Illusions' module was missed · it only readdand discardedlvlentirely, so a level-50 labyrinth encounter played identically to a level-5 one (one single illusion, no streak pressure). Added aroundsparam to the schema (1–4, default 1) with alevelRamp(lvl, 1, 0.2, 4)ramp · +1 round every 5 labyrinth levels, capped at 4. The MiniGame now pre-computes each round fromseed + i·1009so every round is a distinct deterministic illusion, shows an(n/N)progress indicator whenrounds > 1, advances on correct answers, and fails immediately on any wrong pick. Standalone hosts and inline blog embeds still default to 1 round, so/illusionsand article CTAs are unaffected · only the labyrinth gauntlet gets longer. - fix Illusions: Ebbinghaus flanker rings now match the generator's stated intent. The generator sets
ringSmall(6–9 px) andringLarge(14–20 px) and documents "small ring around A, big ring around B" so the illusion percept (small flankers dilate the centre, big flankers compress it) lines up with the trap direction (trapDir='a'makes A physically 5% larger, so the illusion should reinforce truth='a' rather than fight it). The renderer was passingringLargeto A andringSmallto B · still a valid Ebbinghaus figure, but inverted relative to the generator, which meant the flanker-size cue and the 5% trap-size cue pushed the player in opposite directions on every trapped round. Swapped the two arguments so A really does get the small ring and B the big ring. - fix Illusions: Penrose staircase's vertical flights are no longer invisible. The step polygon builder used
(sx, sy)to(sx + dx·sw, sy + sh), which assumes a horizontally-running flight. For the right and left flights (dx=0,dy=±1) that collapsed every rectangle to zero width · only the top and bottom flights actually rendered, so the figure was an open L-shape rather than a closed four-flight loop. Horizontal flights now keep sw-wide treads side by side; vertical flights rotate the tread 90° (sh wide, sw tall) and stack them along the flight direction, so all four flights draw and the impossible-loop percept actually forms. Also removed a leftover{void cx}no-op in the Bezold renderer where an unused variable had been silenced instead of deleted.
April 19, 2026
Fixed
- fix Game language persistence: site language now dictates game language. Starting a game in Swedish, failing, and restarting would sometimes render the new game in English · the root cause was Stroop's own language picker persisting a
stroop-langkey in localStorage that could drift from the site locale. Removed the in-game picker entirely (Stroop now uses thelangprop from the URL, no exceptions), wiped the legacy key on load, pruned Geo's deadgeo-lang-change/geo-lang-setevent listeners so the app always reflects the URL, and taught Polyglot to reject stored target-languages that equal the site locale (you can't "learn" your own language). Polyglot's idle description and “not enough words” hint are now translated across all 25 locales instead of hardcoded English. - fix Labyrinth pi-recall now asks for the first N digits every time. Higher-level encounters were rotating through a random 100-digit window of pi, so the player would face “…35897” or “…82097” rather than the leading digits they had actually been memorising. The “level N = know the first N digits of pi” contract is now honoured for all levels, not just 0 and 1.
- fix Labyrinth pi-recall progress counter now substitutes every placeholder. The progress line read “Type the 7 digits (0/{n})” because the translation helper only replaced the first occurrence of a named placeholder, so the second
{n}leaked through unrendered. The helper now replaces every occurrence. - fix Labyrinth: tapping a far-away puzzle piece or the quest-giver now routes the hero there. The BFS previously refused to plot any path that crossed an uncleared encounter or question-tile, which made most long clicks silently do nothing. The router now treats only walls (and roadblocks the player doesn't have the item for) as hard blockers · givers and puzzle-tiles along the way trigger their own modal, the queue drains cleanly, and play resumes with a second tap.
- improve Labyrinth: quest speech-bubble sits above the giver and breathes. The bubble was anchored to the giver's side in a wide rectangle that often covered adjacent tiles. It now sits directly above the giver in a more compact, squarer box clamped to the grid, and fades out briefly every eight seconds so it doesn't permanently occupy the map while the player is navigating.
New
- new Blog component:
<InlineIllusion>. New MDX component that embeds an actually-playable illusion round inline in a blog article · no popup, no “click to try” button. The figure is drawn by the samerenderIllusion()function the standalone/illusionspage uses, fed by the same deterministiccreateIllusionData()generator, so what the article shows is by construction identical to/illusions/?id=<illusionId>. Hand-coded SVGs are out: the API is the single source of truth. Player picks an answer → reveal overlay slides up with the truth and the “why it works” caption → “Restart” reseeds for another go. Locale-aware (reads<html lang>), SSR-safe, fires ainline_illusion_answeredGA4 event with the illusion type and correctness for funnel analysis. Lives atsrc/components/blog/InlineIllusion.jsx. - improve Illusion blog articles: hand-coded SVGs replaced with the live game. The Müller-Lyer and Ebbinghaus articles previously hand-rolled SVG figures of the illusion (and a separate “Try a live round” popup CTA). Both now embed two
<InlineIllusion>rounds · one at the top of the article showing the canonical figure, one at a different difficulty further down · so the reader sees and plays the real illusion the moment the page loads. Equality of A and B is no longer an assertion in the article body, it's a pixel-level guarantee from the renderer. - new Blog: Ebbinghaus Illusion: Why Surrounding Circles Warp Size. Article #2 in the 50-illusion series. Explains the Titchener-circles figure, the three theories (size contrast, distance assumption, contour interaction at the V1 level), the cross-cultural & child-vs-adult susceptibility differences, and the famous Aglioti 1995 experiment showing the illusion fools your eye but not your reaching grip aperture · key evidence for the two-streams hypothesis. Two embedded
<InlineIllusion illusionId="ebbinghaus">rounds let the reader play the figure right inside the article. Read it at /blog/ebbinghaus-illusion. - improve PlayIllusionButton: locale-aware default label. If no
labelprop is passed, the button now reads “Play <localized illusion name>” (e.g. “Play Ebbinghaus”), pulling the name fromsrc/i18n/components/illusions.jsonusing the article's<html lang>. New optionaldifficultyprop pins the popup to a specific subtlety (1-10), and an explicitlangprop is supported for MDX articles that need to override the page locale. - improve Illusions:
?difficulty=NURL parameter. The/illusions/?id=...deep link now also accepts&difficulty=N(1-10), so an article can target both the figure and its subtlety in one link. When pinned, the playing header replaces the “X of Y figures” pool counter with a “📌 <Illusion name>” badge so the player knows the rotation is locked. - new Blog: Muller-Lyer Illusion: Why Arrows Warp Length. First in a planned 50-article series covering every illusion in /illusions. Explains the four leading theories (size constancy, centroid bias, eye-movement overshoot, neural filtering), the carpentered-world cross-cultural finding, and a hands-on way to switch the illusion off with your fingers. Two inline SVGs show the figure with and without the wings covered, and a
<PlayIllusionButton>opens a live Muller-Lyer round in a popup without leaving the page. Read it at /blog/muller-lyer-illusion. A 200-itemARTICLE_BACKLOG.mdlists every article gap identified across illusions, mathematical constants, memory techniques, sequences, cognitive phenomena, geography, language learning, unit conversion, and game strategy · so the illusion series has 49 more queued plus 150 articles across the other games. - new Illusions: deep-link a single illusion. The illusions module's params schema now accepts an optional
type(e.g.'muller-lyer','ebbinghaus','penrose-triangle') that pins every generated round to one specific illusion./illusions/?id=muller-lyerreads the query param on mount, skips the idle screen, and lands the player directly on that figure with fresh seeds each round. TherequestMiniGame()popup honours the sametype, so a blog article can open a live round in a modal. Unknown ids fall back to the existing random-pick behaviour; conformance tests stay green (66/66) because the new field defaults to empty and existing callers see no change. - new Blog component:
<PlayIllusionButton>. Drop-in CTA for MDX articles. Lazy-importsrequestMiniGameon click so the popup chunk only loads when the reader opts in. Readsdocument.documentElement.langso the in-popup UI strings match the article's locale. Fires ablog_play_illusionGA4 event with the illusion type for funnel analysis. Lives atsrc/components/blog/PlayIllusionButton.jsxand is the first component in the newblog/folder. - new Illusions game at /illusions. 52 classical optical illusions across six families: size (Müller-Lyer, Ebbinghaus, Ponzo, Jastrow, Delboeuf, Sander, vertical-horizontal, Oppel-Kundt, Shepard tables, Helmholtz squares, Baldwin), colour & brightness (Adelson checker-shadow, simultaneous contrast, White's, Cornsweet, Koffka, Chubb, Benary cross, Mach bands, dungeon, watercolour, Asahi glow, Munker-White, Bezold, Todorović), illusory contours (Kanizsa triangle/square, Ehrenstein disc, abutting gratings, neon spread), orientation (Café wall, Zöllner, Poggendorff, Hering, Wundt, Orbison, Ehrenstein line, Fraser spiral, twisted-cord, Bourdon, Ouchi), grid after-effects (Hermann, scintillating, extinction), ambiguous figures (Rubin vase, Necker cube, Schröder stairs, bulging checker), impossible figures (Penrose triangle/stairs, devil's tuning fork, impossible trident, Freemish crate), and animated (lilac chaser, rotating snakes, stepping feet, motion-induced blindness). Each round renders a deterministic SVG scene and asks one grounded question; the reveal overlay then shows the true geometry with a one-line “why it works” caption. Ships as a GameModule, so it doubles as a labyrinth encounter in Tier 2.
- new Game Mode: distraction-free focus mode on every game. A floating “Game Mode” pill sits at the bottom-right of every game landing page (Memory, Ghost, Polyglot, Geo, Pi, and the rest). Tapping it hides the header, sub-nav, footer and install banner, locks page scroll, and lifts the game to fill the viewport on the normal surface colour. Exit with the floating X button (same bottom-right slot as the toggle) or Escape · scroll position is preserved on exit. Game Mode is independent of gameplay: starting or losing a game never enters or exits it. Translated into all 25 locales.
Improved
- improve Analogies & Define: pool expanded from ~250 to 471 items. New high-quality pairs added across all 14 relations · more capitals (New Zealand, Israel, Pakistan, Qatar, Baltic states …), continents, young animals (tiger, giraffe, zebra, llama …), habitats (koala, octopus, mole …), tool functions (magnet, calculator, binoculars …), workplaces (firefighter, blacksmith, astronomer …), producers (composer, architect, journalist …), categories (guitar, gold, hydrogen, tulip …), antonyms, synonyms, part-whole pairs, tool users, characteristics, and degree intensifiers. Because the game generates A:B pairings combinatorially (N×(N−1) per relation), the distinct-round count grew from ~5,000 to 17,470 · players see far fewer repeats per session.
- improve Card-based games: every emoji card now sizes like Memory. Memory has always rendered emojis at 75% of a square card via Twemoji SVGs and container-query sizing. That same pattern ·
aspectRatio: 1,container-type: inline-size, and an<Emoji size="75%">Twemoji · is now applied across Odd One Out (emoji puzzles), Ghost (recall grid + answer buttons), Polyglot (word-to-emoji options), and the Labyrinth Memory / Odd One Out / Polyglot / Ghost popup encounters. The sharedEmojicomponent was extended to accept any CSS length (percent, cqi, px) for itssizeprop. - improve Odd One Out: removed all letter puzzles. Single-letter rounds ("all others are consonants / vowels / letters in PLAYGROUND / in the first half of the alphabet") were effectively unsolvable for non-English speakers and ambiguous even for English speakers · a letter can legitimately belong to several rules at once. The Letters category is gone, the generators (vowels, consonants, alphabet halves, word-letter lookup) are deleted, and the difficulty pools no longer include them. FAQ copy updated to match.
- improve Odd One Out: localized category filter. The "All / Emoji / Numbers / Shapes / Math" picker on the idle screen now renders in every UI language instead of hardcoded English, and your choice persists between sessions like the difficulty picker.
- improve Illusions: “See again” button added next to Next. Once you've answered, you can hide the reveal caption to study the bare illusion side-by-side with the truth before advancing · especially useful for the animated ones where you want to keep watching after the explanation appears.
- improve Illusions: removed the “2/11” pool counter. The header used to show how many of the category's illusion types had been shown this session, implying a finite run. In practice the game just continues forever until the player gets one wrong, at which point the hot-streak resets to zero · the same endless-streak shape as Memory, Ghost, Polyglot, Odd One Out and the rest. Only the streak, best and round counters remain.
Fixed
- fix Illusions: experience-only illusions no longer ask a nonsense question. Ambiguous figures (Rubin vase, Necker cube, Schröder stairs), impossible objects (Penrose triangle/stairs, devil's tuning fork, impossible trident, Freemish crate), phantom-boundary figures (abutting gratings, bulging checker, Ouchi), the Todorović shaded discs and every animated illusion (lilac chaser, rotating snakes, stepping feet, motion-induced blindness) were being framed as “which patch is lighter?” with invisible A/B labels · there was no meaningful right answer. These 16 illusions now use a new “view” mode: one “Got it” button, then the reveal explains what you just saw. The classical A/B brightness comparisons (Adelson, simultaneous contrast, White's, Cornsweet, Koffka ring, Chubb, Bénary cross, Mach bands, dungeon, Kanizsa triangle/square, Ehrenstein disc, neon spread, watercolour, Asahi, Munker-White, Bezold) still ask the proper “A / same / B” question.
- fix Illusions: twisted-cord now actually looks twisted. The previous renderer alternated the diagonal direction of each stroke, so the strokes cancelled out and the cord read as plain zig-zag with no slope. The new build draws each cord as a consistent run of black/white parallelograms tilted in one direction, over a high-contrast checker background · the classical Fraser “twisted cord” effect finally shows: the two cords look strongly slanted, although they are perfectly horizontal.
- fix Illusions: Koffka ring labels now point at the ring, not the backgrounds. The A/B letters were drawn below the ring on the bisected dark/light background, so the player was being asked to compare the two background halves (which are obviously different) instead of the two halves of the grey ring itself (which are genuinely identical). Labels now sit directly on the ring stroke so the comparison matches the illusion's claim.
- fix Illusions: Mach bands moved to “view” mode. The staircase's steps are genuinely different brightnesses · asking “which is lighter?” with truth “same” was wrong. The illusion is about perceived bright/dark bands at each step boundary, not a sameness test, so it now shows a single “Got it” button like the other experience-only illusions.
- fix Illusions: Rubin vase, Todorović discs and abutting gratings no longer carry stale A/B letters. When these three were moved to the new “view” mode, their SVG scenes still contained the leftover A/B/A text markers from the old brightness-comparison UI, which looked like you were supposed to compare two patches. The letters are gone now.
- fix Illusions: trap rounds on size illusions now match their own truth. Müller-Lyer, Ebbinghaus, Ponzo and Delbœuf high-difficulty trap rounds were inverting the sign · when truth was “A is bigger”, the renderer drew B bigger (and vice-versa), so the supposedly-correct answer was always the opposite of what the player saw. The offset direction is now aligned with the truth field.
- fix Illusions: trap rounds disabled on color illusions that don't honour them. Adelson checker-shadow, simultaneous contrast and White's illusion declared themselves trap-capable, but none of their renderers actually read the
greyDeltaparam · a trap round would paint two identical grey patches while the grader insisted one was lighter, so any honest “same” answer was counted wrong. These three no longer run trap rounds until their renderers can reflect the intended offset. - fix Illusions: Poggendorff's correct answer is now the geometric one. The “true continuation” index was picked by the RNG independent of the line's actual angle, so the answer the grader accepted often didn't match the line's real exit point. The generator now computes the exact y-coordinate where the slanted line exits the rectangle and plants that value at one of the three answer slots, with the other two offset by ±18 px.
- fix Illusions: Poggendorff no longer highlights the correct line in red. The three right-side candidate lines previously rendered in · grey-grey-grey except for the true one painted red · a dead giveaway. All four line segments (the slanted input plus the three candidates) now share the same red stroke, so the player actually has to judge the continuation.
- fix Illusions: Poggendorff candidate lines stay on-canvas at low difficulty. The easy-round angle (up to 28°) pushed the true continuation y past H=220 on the steeper cases, so the candidate lines rendered below the visible area. The max angle is now 18° and the anchor geometry has been tightened so all three candidates sit inside the canvas with room for the ±18 px spread.
- fix Illusions: Orbison now always uses the square variant. Half of the Orbison rounds rendered a circle over the radiating lines and then asked “are the lines parallel or slanted?” · there are no straight lines on a circle to judge. The circle variant is gone; every Orbison round is a square whose opposite sides are genuinely parallel but appear bowed.
- fix Illusions: Bourdon no longer draws a dashed reference line through the triangle tips. The red dashed horizontal line was meant as a construction helper but shipped into production, proving the shared axis was colinear before the player answered. Removed.
- fix Illusions: Ehrenstein line, Fraser spiral and Bourdon moved to “view” mode. All three were asking “are the lines parallel or slanted?” but none of them actually renders two lines the player can compare. Ehrenstein line draws a single straight line crossing concentric rings; the Fraser spiral draws concentric circles (and circles aren't lines); Bourdon shows two triangles tip-to-tip sharing an implicit axis. The “A / same / B” prompt was nonsensical on all three, so they now show a single “Got it” button with a caption explaining the truth · the line is truly straight, the rings truly close, the triangles truly share a horizontal axis.
- fix Illusions: SEO copy now reports the real count. Landing meta descriptions, catalog copy, FAQ answers and the README all claimed “14 classical optical illusions” · the game ships 57. Updated everywhere so search snippets, structured data and documentation match reality.
- fix Illusions: Adelson checker-shadow positions now match the classical demo. Square A was placed on a LIGHT checker cell (x+y even) outside the shadow and B on a DARK cell (x+y odd) inside the shadow · the reverse of the classical Adelson setup. With the positions swapped the illusion was actually running backwards: A's surround expected LIGHT (washing the grey patch out) while B's surround expected DARK (making the grey patch look lighter in shadow). Moved A to (1,2) (dark cell, outside shadow) and B to (5,3) (light cell, inside shadow) so the grey patches read as “dark tile on the bright side” and “light tile in shadow” respectively · the original Adelson claim.
- fix Illusions: Dungeon illusion now places its patches on opposite-polarity tiles. Both A and B were placed on dark checker cells (parity x+y even), so the two identical grey patches sat in identical local contexts and no contrast illusion could develop. B moved to (5,2) · x+y=7, a light cell · so the surround flips polarity between A and B, which is the whole point of the dungeon setup.
- fix Illusions: Bénary cross triangle A now nestles against the cross. The “outside” grey triangle was floating 42 pixels away from the cross, touching neither arm · just a grey triangle on plain white, no corner contrast. Repositioned so its right-angle vertex sits at the cross's top-left convex corner (cx-arm, cy-thick/2) with two legs running along the cross edges, matching the classical Bénary configuration where both triangles touch the cross on two sides.
- fix Illusions: Munker-White's label legend describes the actual bar layout. The code comment said patches A sit “across green-striped zone” and B “across blue-striped zone”, but A is painted on odd columns (blue bars) and B on even columns (green bars) · the exact opposite. Comment rewritten to match the rendered geometry.
- fix Illusions: scintillating grid and extinction illusion moved to “view” mode. Both renderers actually draw real dots at the grid intersections (white ones on the scintillating grid, black ones on the extinction illusion), so “How many dots do you see?” with truth “0” was factually wrong · the grid is not plain. These illusions are about perceptual flicker and peripheral disappearance, not counting, so they now show a single “Got it” button. The Hermann grid · which genuinely draws zero dots · keeps the counting question.
- fix Illusions: Sander diagonals are finally equal in length. The parallelogram's internal divider was placed at 0.4 along the top/bottom edges instead of 0.5, so the left diagonal (tl→midB) and right diagonal (mid→br) differed by roughly 20 % in length. Truth was “same” but the image showed two visibly different lines. The divider now sits at the exact midpoint, which is the only position at which the two diagonals measure equal · the classical Sander geometry.
- fix Illusions: watercolour and neon-spread moved to “view” mode. Both are phantom-colour illusions · the watercolour's thin orange/yellow contour makes the enclosed region appear pale yellow, and the neon grid makes a coloured disc appear to spread a cyan wash · but the A/B labels used to mark them were either outside the illusory region or on plain background, so the brightness comparison didn't test the illusion at all. These now show a single “Got it” button with a caption that names the perceived phantom colour.
- fix Illusions: Adelson checker-shadow now measures truly equal. The canvas rendered patches A and B with the same grey hex, but the shadow gradient was painted on top afterwards · so patch B (sitting inside the shadow's darker band) had its pixels darkened by roughly 30 %, while patch A was untouched. Truth was “same” but an eyedropper would have measured them as different greys. The paint order is now: checker base, pillar, shadow gradient, and finally the two grey patches on top, which guarantees A and B end up with pixel-identical colour regardless of which side of the shadow they sit on · matching the classical demonstration.
- fix Illusions: Bezold labels now sit on the red patches. The A and B letters were drawn in the white margin below each red rectangle, so the player was being asked to compare two trivially-equal white patches instead of the two reds that the illusion actually changes the appearance of. Labels now sit in the middle of each red rect (white A on the black-lattice rect, dark B on the white-lattice rect) so the comparison is finally between the two illusion subjects.
- fix Illusions: Adelson pillar no longer clips through patch B. The brown pillar was positioned at x = 0.68 W, which overlapped the right half of B's checker cell. Because B's grey patch was painted last, it drew over the pillar and split it into two disconnected halves above and below B's row · the pillar looked broken. Repositioned the pillar to cell 6 (x = 6·cw + 8), entirely to the right of B, so the pillar renders as a single uninterrupted column.
- fix Labyrinth: every level now actually requires the quest. The maze generator carves a perfect (single-path) maze and then braids it to break up long dead ends · but braiding occasionally opened an alternate route around the roadblock, so the player could reach the goal without delivering the ring or picking up the right item. The roadblock cell is now verified to be a real bridge between start and goal (removing it must disconnect them); if it isn't, the generator slides it along the solution path, falls back to a whole-maze bridge scan, or re-seeds. Verified across 3,000 (level × seed) combinations with zero bypasses.
- fix Labyrinth: player no longer spawns next to a puzzle piece. Question tiles were placed anywhere on the walkable grid, so on some seeds a puzzle sat one step (or zero) from the start and the player opened a puzzle modal before they'd even moved. Placement now excludes every cell within BFS distance 4 of the start · the first few steps are always free so the player can orient.
- fix Labyrinth: quest-giver's speech bubble stays visible. The bubble used to fade in and out on a 5s loop, so when a player walked onto the NPC during the "invisible" window the quest looked like nothing had happened. It now bounces in once on level start and stays pinned above the giver until the ring is delivered.
- fix Labyrinth: tapping a puzzle piece behind another puzzle now walks you there. The click-to-walk BFS treated every uncleared obstacle as impassable, so if another puzzle sat between the player and the tapped one, nothing happened. When the tap target is itself a puzzle, other puzzles are now passable as intermediates · you walk to the first puzzle, solve it (the queue drains on phase change), then tap again to continue.
- fix Labyrinth: Analogies encounter no longer shows English words in non-English UIs. The analogies relation pool only ships English for v1; every other locale fell back to it, producing "Swenglish" rounds (Swedish rule label, English option words). Analogies are now excluded from the maze's encounter pool for any locale without a translated pool · affected players see other encounter types instead until localised analogy pools land.
Improved
- improve Define: cross-category ambiguity filter plus Cyrillic 3-char handling. A third quality pass drops any word whose string contains a token from any other surviving category's label, not just its own · catches real compound-semantic overlaps like Swedish "Skaldjursspett" (contains
djur= animal), German "Feuerwerkskörper" (containskörper= body), Italian "Cercapersone" (containspersone= people), Romanian "Scorpion" (containscorp), and German "Torte" (containsorte= places). The language-class minimum-token length was also lowered to 3 for Russian and Ukrainian so Cyrillic 3-char food tokens (еда,їжа) are recognised · five Russian medal words and the Ukrainian hedgehog no longer slip past the filter.
April 18, 2026
Improved
- improve Backwards: distractors are now misspellings of the same word. Rounds used to mix the correct reversal with reverses of three unrelated words · easy to spot because only one "looked right". Every option now comes from the same word, differing only by letter swaps or substitutions, so players actually have to verify the reversal character-by-character. Works in all 25 languages · swaps operate on Unicode code points, preserving combining marks and CJK characters.
- improve Define: dropped self-explanatory word categories, expanded the pool. The Flags, Smileys & emotion, and Symbols emoji categories produced trivial rounds where the word itself gave the category away (e.g. "Flag: Comoros" under a "Flags" label). All three are now excluded. The country-to-continent pool grew from ~53 to ~90 countries across every locale, and the English analogies pool gained ~45 new items (more capitals, young animals, habitats, workplaces, tool functions, categories, antonyms, synonyms).
- improve Define: recursive scan across all 25 languages, plus analogy-pair filter. A second pass caught 72 more self-explanatory words where a word contained a token from its category label · "Canned food" under "Food & drink", "Matlagning" under "Mat & dryck", "Hot drink", "Pot of food", "Cooking food", etc. The filter now tokenises compound labels, drops language connectives / articles (and, or, the, les, और, और, 및, …), and lowers the minimum-token-length for compound-heavy Swedish and CJK scripts so short root words like "mat" (food) still register. On the analogies side, pairs where the question word trivially gives the answer away ("pig" → "piglet", "baker" → "bakery", "Mexico" → "Mexico City", 11 total) are now hidden from Define while remaining available to the Analogies game (where the a₁:b₁ :: a₂:b? format obscures the giveaway). Another ~20 good analogy items added to keep the pool deep after the filter.
Fixed
- fix Define: equal coverage across all 25 languages. Non-English locales were falling back to the English-only analogies pool, so Swedish / French / Japanese players saw English option words like "doctor" or "astronomer" under localised rule labels. Non-English rounds now draw only from fully-localised sources · the 1,400-word CLDR emoji vocabulary and a new country-to-continent pool resolved natively via
Intl.DisplayNames. - fix Define: question word could appear as a wrong answer. On the synonym / antonym relations the distractor loop didn't exclude the prompt word itself, so the very word being asked about could show up as an option labelled "wrong". Both buckets are now filtered.
New
- new Define: country-to-continent rounds in every language. A new source built on
Intl.DisplayNameswith UN M.49 region codes adds ~60 countries × 5 continents, rendered natively in the player's locale. No translation tables · every one of the 25 site locales gets the same variety.
Improved
- improve Game pages: merged "About this page" and "FAQ" into a single collapsible. Every game landing now has one "About this page & FAQ" accordion at the bottom instead of two separate ones, so readers don't have to open two toggles to see the full SEO footer content.
- improve Stroop: in-game language picker. Choose the display language for the color words (25 locales) directly from the idle panel, independent of the site locale. Your choice is saved locally, so a Swede can practice on `blå/röd/grön` even while browsing an English URL.
- improve Ghost: memorize time no longer shrinks as you advance. The game was already hard enough · round decay is gone, so memorize time depends only on grid size and tempo. The selected tempo (Slow / Normal / Fast) determines the pace for the whole session.
New
- new Define · a new vocabulary game at /define. See a word, pick its meaning from 2-6 options. Rounds are generated combinatorially from two shared pools · the Unicode CLDR emoji category vocabulary (fully localised in all 25 languages) and a hand-curated pool of 14 semantic relations (capital-of, young-of, antonym, synonym, habitat, function, part-whole, and more). Distractors are always other correct members of the same category or relation, never random words. Define is also wired into the Labyrinth mini-game pool from level 3 upward.
- new Backwards game at
/backwards. See a word, pick it spelled backwards from the list before the millisecond timer catches up. DOG → GOD, BEAR → RAEB. Ships in all 25 languages, drawing its word pool from the same Unicode CLDR source as Memory and Polyglot, and also appears as a Labyrinth encounter from tier 2 onwards. Best streak and fastest reaction time saved per difficulty. - new Templated Learn pages at
/learn/{game}/{topic}. A data-driven explainer template (src/data/learn-topics.ts+src/i18n/learn-ui.ts) renders "how it works / why it helps" articles from a shared shell · 3 tip boxes, 2 strategy cards, 2 key points, 1 warning, and a baked-in author byline on every row. Phase A ships five English seeds for Memory, Pi, Geography, and Ghost. Sitemap auto-discovers any row added to the index; new verify rule B-20 asserts sitemap parity so nothing drops silently in the future. - new Reasoning games now show reaction time. Matrix, Odd One Out, Spatial, and Analogies now measure per-round reaction time in milliseconds (matching the pattern from Stroop). Each correct answer shows your response time, and your fastest-ever answer per difficulty is saved locally and shown on the game-over screen.
- new Labyrinth: scattered ❓ challenge tiles. Every level now sprinkles question-mark tiles across the maze. Walking onto one opens a short mini-game picked from the level's encounter pool. Each tile's question is pinned to its coordinates · re-visiting the same tile asks the same question, so memory pays off. Cleared tiles turn back into plain path.
- new Labyrinth: soft-fail teleport. Answering a challenge wrong (or abandoning it) no longer drops you a level. You're teleported back to the level's start instead, keeping every tile you've already cleared and every item you've picked up. Retry by walking back.
Fixed
- fix Header drop-down and footer on the home page. The home page was missing
SiteFooter, which is where the nav drop-down's toggle script lives · so the "Reasoning / Memory / Words …" menu wouldn't open and the footer itself was absent. Labyrinth now shows in the drop-down under Reasoning on every page including Home. - fix Polyglot encounter prompt now names the language. The prompt previously just said “Foreign word” with the word and no language context, which was confusing when the word (e.g. “casa”) exists in multiple Romance languages. Prompts now lead with “Spanish word” / “French word” / “German word” / “Italian word” above the word itself, and the hint reads “Pick the emoji this {language} word means.” Analogies also switched from “A : B :: C : ?” notation to plain English (“A is to B as C is to ?”) with an explicit hint.
Improved
- improve Labyrinth: full three-beat quest chain with a visible pickup. Every level now lays out the whole quest on the map: quest-giver (mini-game) → the ring you fetch (tool pickup on the solution path) → the obstacle (hole / fire / wall / door). The perfect-maze property forces the order · you can't reach the pickup without beating the giver and you can't reach the goal without using the pickup on the obstacle. Winning the mini-game no longer silently hands you the tool; you have to go get it. Player glyph changed from a neutral person to a 🦸 hero. Quest-givers now show a pulsing “Help!” speech bubble above the tile so they're easy to spot when a new level appears.
- improve Labyrinth: smaller 12×12 grid, tighter top layout. Grid dropped from 24×30 to 12×12 cells so every emoji tile is twice as large and legible on a phone. The top of the page was also too busy · the subtitle paragraph is gone, the hero title is compact, and the level title / HUD row is tighter, so the maze sits near the top of the viewport. Smaller grid also eliminates the long horizontal black stripes that sometimes formed on bigger mazes (long even-row wall runs with subpixel rounding).
- improve Labyrinth: thin walls, open exit, emoji player. Walls are now thin black lines between big walkable cells (alternating
1fr / 5frgrid template), the goal is an empty opening in the top wall above a blank cell (no more emoji on the goal tile), and the player is a 🧑 twemoji sized to fill the cell. The board stretches to fill the viewport width almost edge-to-edge; the page container opens up to 1100px so the maze breathes on desktop too. - improve Labyrinth: bigger map, full-view, homepage header. Grid jumps to 24×30 cells (taller than wide so it fits portrait mobile without scrolling). Fog of war is gone · the entire maze is visible up front. Walls are solid black, paths are white, every feature tile (quest-giver, obstacle, goal) renders its twemoji glyph at all times so the run reads like a classic hand-drawn labyrinth. The home page now uses the same shared
GameHeaderas every other page for consistent navigation. - improve Labyrinth now has a Diablo 2 quest flavour. Each level opens with a named locale (The Blood Moor, Cold Plains, Stony Field … sixteen in total) and a one-line quest subtitle (“Quest · Descend the pit”) that flashes above the board and fades out. Palette switched from paper to torchlight: warm parchment where the light reaches, dim tan at the fog edge, near-black void beyond, dark iron walls, gold-trimmed frame. Quest-givers rotate through twelve robed glyphs and the goal tile rotates through twelve destinations (waygate, shrine, tome, portal, crown …) so repeating a level twice is visually distinct. Player marker is a warm red orb with a soft torch halo.
- improve Labyrinth redesigned as a classic paper-maze. Fixed 12×12 cell grid, white paths with crisp black walls, start at the bottom, goal at the top · no instructions, no tutorial, no toasts, no legend. The player figures it out by moving. Fog now reveals only the cell you stand on and the four walkable neighbours, one step deep in each direction; no trail, no memory · you navigate by the light in front of you.
- improve Labyrinth quest structure. Each level is now a small story: walk into the 🧙 quest-giver on the solution path, beat their short mini-game, collect the item they hand you (🪢 rope / 🪣 bucket / 🪜 ladder / 🗝 key), then use it to clear the one roadblock (🕳 hole / 🔥 fire / 🧱 wall-block / 🚪 door) blocking your way to the goal. Replaces the previous multi-encounter layout with a single self-explanatory chain.
- improve Silent level transitions. Reaching the goal auto-advances; failing the challenge auto-drops a level. The maze simply changes; there is no celebration or failure screen in the way.
- improve Removed the Labyrinth tutorial, onboarding coach-marks, event flashes, toasts, in-game settings drawer, legend, and save-code entry form. All of it: gone. Roughly −1k lines of UI chrome and three dead files so new work is cheaper to reason about.
New
- new Labyrinth. A fog-of-war maze game and the new front-page hero. Walk a top-down grid, see only adjacent tiles, beat short challenges drawn from 13 of the existing mini-games (encounters), and climb level by level. Deterministic maze generation: every level is fully reproducible from a short retro save code like
LVL15-X9B2QK4-7. No accounts, no email; bookmark or paste the code to resume any time. Failing an encounter drops you one level back to the same maze you cleared on the way up · spatial memory pays off. - new Items & roadblocks (L1+). Every level above the floor has a second route to the goal, gated by a thematic obstacle (🕳 hole / 🔥 fire / 🧱 wall-block / 🚪 door). The matching item (🪢 rope / 🪣 bucket / 🪜 ladder / 🗝 key) is hidden elsewhere on the maze. Strategic choice each level: take the long encounter-laden main path, or detour to grab the item and use the shortcut.
- new Pi & Color encounters scale to your level. Reach level 15? You must recall 15 digits of pi or repeat 15 colours in a row. The challenge length is your level number, capped at 100 (pi) and 16 (color).
- new Onboarding tutorial. First-time visitors get a guided 5x5 walk-through of movement, fog of war, encounters, drop-down failure, and the save-code system. Returning players skip straight to play; "Replay tutorial" is in the in-game settings.
- new Animated retro fog. Fogged tiles render with three drifting cloud puffs that pulse softly, each with a per-tile phase so the board never breathes in lockstep. Honours
prefers-reduced-motion. - new Facts game at
/facts. Spot the one true statement among several. Statements are generated on the fly from a pool of schemas (primes, perfect squares, divisibility, arithmetic, month lengths, country flags) so there are no hand-written questions to run out of. Country names resolve viaIntl.DisplayNamesand month names viaIntl.DateTimeFormat, so the game speaks all 25 site locales natively without a translated question bank. - new Emoji mode for Analogies. Toggle between word and emoji analogies on the /analogies landing. Emoji puzzles pair symbols like cow:milk :: chicken:egg, rendered with Twemoji so they look identical on every device.
- new E2E interaction tests. Every game in
GAMESnow has a Playwright smoke that boots real chromium, loads the page, and asserts the React island hydrated and a button click mutates the DOM. Catches the post-release regressions static checks can't see (memory cards not turning, pointer-events overlays, dead click handlers). A dedicatedtests/e2e/memory.spec.tsclicks Start and flips a card end-to-end. Gated in CI under the newe2ejob. - new Multilingual parity across Memory, Ghost, Polyglot, Convert, and Pi. Memory, Ghost, and Polyglot now ship emoji labels for all 25 site locales by sourcing names from CLDR annotations (previously 14 locales, the rest fell back to English). Convert's 11 categories and ~90 unit names are i18n-keyed. Pi's 38 constant names and descriptions are i18n-keyed via a new
getConstantMeta(slug, t)helper.
Improved
- improve Home page. Now leads with the playable Labyrinth above the fold; the existing 14-game grid is below in a "Browse the practice games" collapsible. SEO schema upgraded to WebApplication + FAQPage. The dedicated
/labyrinthpage also exists for direct linking. - improve Mobile controls. Four-arrow horizontal D-pad below the board, plus swipe-on-board input for the maze itself. Pointerdown for instant tap response with active-state colour feedback.
- improve Matrix game is significantly harder. Medium now starts at 2 rules (ramping to 4), Hard starts at 3 and ramps to 4, and Easy ramps from 1 to 2 as streak grows.
- improve Analogies is now truly infinite. Rewrote the data layer from 64 hand-written A:B::C:D rows into 14 relations × ~12-35 items (country→capital, animal→young, tool→function, antonyms, continents, part-whole, and 8 more). Each round picks a relation and two random pairs from it, so the puzzle space is thousands of combinations instead of 64. Distractors are now drawn from the same relation's other b-values, so wrong options stay on-topic (a capital question offers other capitals, not random words like "Gale" or "Huge").
- improve Removed the Difficulty picker from Memory, Color (Simon), Ghost, Geography, Polyglot, Math, Converter, Crazy Comparisons, Analogies, and Stroop. Players had no reliable intuition for what easy/medium/hard meant per game, and per-difficulty high-score keys fragmented personal bests. Each game's underlying behaviour is pinned to the old "medium" defaults (or a sensible replacement: Geo Top-N = 10, Simon base tempo, Math ±30% distractor range, Converter plausibility spread, Polyglot same-category distractors). A one-shot migration on each game collapses any legacy per-difficulty high scores into the unified key so players keep their bests.
- improve Hot streak badge now renders inline inside the game header next to the logo and game switcher, instead of floating fixed in the top-right corner. Also shown inline with the logo on the home page.
- improve Shared matching engine under
src/lib/matching-engine/: generator-driven rounds, sliding anti-repeat window, magnitude distractor helper, and locale-aware compact number formatting. Crazy Comparisons is the first game migrated to it; other matching games will follow. - improve Crazy Comparisons data model is now language-neutral: numeric facts live in
src/data/crazy-comparisons/facts.jsand all display text routes through the site-widesrc/i18n/ui.tsundercomparisons.*keys (25-locale parity). 25 hand-maintained per-locale question files were removed, so numeric fixes no longer need to be applied in 25 places.
Fixed
- fix Facts: February/29-days ambiguity. The lie generator could produce "February has 29 days" - true in leap years - as a supposedly false statement. 29 is now excluded from month-length distractors so every claim is unambiguous.
- fix Facts: round-level uniqueness for months and flags. In small-pool categories (Calendar, Geography) a round could contain two statements about the same month ("March has 31 days" vs "March has 30 days") or reuse a country's flag as a lie for another country's name, letting players solve by elimination instead of by knowledge. Generators now track used months / countries and avoid repeating.
- fix Facts: high score now saved when you press STOP (not only on a wrong answer), so ending a long streak manually no longer discards the best.
- fix Facts: NaN-safe state initialisation. Corrupted localStorage values for answer count or high score used to render the game unplayable; parsing now falls back to defaults on any non-finite input.
- fix Facts: honours
prefers-reduced-motion. The correct-answer scale animation and 150 ms transitions are disabled for users who have asked the OS for reduced motion. - fix Facts: copy no longer claims "out of four" since 2-6 answers are selectable. Landing description, noscript, FAQ and home-page card all updated across all 25 locales.
- fix UI:
game.categorylabel translated into 24 non-English locales (was hard-coded "Category" everywhere). Used by the Facts and other games' category picker. - fix Memory cards wouldn't flip. A Start overlay sat on top of the grid and swallowed taps, so first-time players tapping cards saw nothing happen. Removed the gate · cards are clickable immediately and the timer starts on the first flip, like a classic memory game.
- fix Analogies repeating questions. With the old 64-question pool and pure-random picking, duplicates started appearing within ~10 rounds (birthday paradox). The new combinatorial engine plus a recent-seen buffer on item ids means the same pair won't resurface for at least ~20 rounds.
- fix Odd One Out: ambiguous puzzles eliminated. A puzzle like
[8, 21, 2, 4]with the answer "4 (only non-Fibonacci)" was broken because 21 is also the only odd number / only non-power-of-2, and 2 is the only prime - multiple defensible answers. A validator now rejects any puzzle where a non-target item is also a unique outlier under common rules (parity, primality, squares, cubes, powers of 2, Fibonacci, multiples of 3/4/5, digit count). The Fibonacci, prime, square, cube, and powers-of-2 generators were also tightened to drop multi-distinctive items (1, 2, 8, 144) that overlapped across categories. - fix Odd One Out: math addition generator infinite loop. When the random target landed at 10 or below, the generator looped forever trying to produce 10 unique
a + b = targetpairs from a pool smaller than 10. Target range now starts at 11 so the loop is always satisfiable. - fix Odd One Out: retry-budget fallback. When the validator exhausted its 80 retry attempts (extremely rare), the old code returned the last rejected puzzle - defeating the validator. The fallback now generates an emoji/shape puzzle instead (unambiguous by construction) so a user is never shown an ambiguous puzzle, even in the worst case.
- fix Matrix answer options no longer look identical. Previously distractors could differ from the answer only in size/fill/rotation, producing choice tiles that were visually indistinguishable (e.g. three "blue +++" options at different sizes). Every option now has a unique (shape, color, count) tuple, so distinctions are always obvious at a glance.
- fix Matrix high score is now saved when you press STOP (and on every correct answer), not only on a wrong answer. Players ending a long streak manually no longer lose their best.
- fix Matrix rotation rules removed. Circle, square, diamond and cross are 4-fold symmetric, so rotation patterns were invisible for half the shape pool and made puzzles unsolvable when they fired.
- fix Matrix double-tap race. A rapid second tap between the click and the next render could slip past the play-phase guard and register two answers for one puzzle. Fixed with a synchronous ref lock.
- fix Matrix "new high" false positive. The end-of-run screen showed the trophy and "New high score!" whenever
round >= highScore, which also fires on a tie with the previous best. Now only shows when the run genuinely beat the saved high. - fix Memory game render loop.
ALL_CATwas rebuilt every render, invalidatingbuildDeck'suseCallback, re-firing the build effect, callingsetCardsagain · an infinite setState loop at ~28k mutations/sec. WrappedALL_CATandcategoryinuseMemo. No more runaway rerenders; the flip handler now commits state reliably.
April 17, 2026
New
- new Hot streak site-wide. A flame badge in the top-right tracks days in a row. Play any game once a day to keep the streak going; miss a day and it resets. Click the badge for your personal best and how it works. Localised across all 25 languages. Stored locally (no account needed) via
pm_streak_count/pm_streak_last_date/pm_streak_best. Detection hookswindow.gtaganswer events, so every existing game counts with zero per-game edits.
Fixed
- fix Polyglot high-score key mismatch. Initial high-score read used a key without
categoryId, while writes (and the post-mount sync effect) used a key that included it. The inconsistency caused the best-streak badge to briefly show 0 on first render. - fix BlogPost schema.org author. Blog post
sameAshardcoded the X/Twitter URL instead of readingAUTHOR_TWITTERfromconstants.ts, so any future handle change would have left blog schema out of date. - fix Emdash in install banner. The iOS "Add to Home Screen" banner's subtitle contained an emdash (slipped past verify because it's assigned inside a script block). Replaced with a middot per F-01 style.
Improved
- improve Stroop game is harder and deeper: answer buttons no longer show a matching color dot (that shortcut bypassed the interference), and a new Mode setting adds a reverse variant where you read the word instead of naming the ink. High score and fastest time are tracked per mode so the easier reverse variant no longer masks your Normal-mode best, and the idle description swaps to match the selected mode.
- improve Games grouped by family. Home page and the game switcher dropdown now cluster games under Memory, Knowledge, Numbers, and Reasoning headings instead of showing one flat list. Each entry in
src/lib/games.tsgained agroupfield;GAME_GROUPSdrives the display order. - improve Removed N-back game. The
/nbacklanding and all locale variants are gone, along with its registry entry, FAQ copy, service-worker precache slot, and translation keys across all 25 locales. - improve Accessibility in quiz games. Memory game dropdowns are now proper
<button>elements witharia-haspopup/aria-expandedand Escape-to-close. Polyglot, Analogies, and Matrix gainrole="group"on their answer sets; Polyglot answer buttons expose the target word viaaria-label(screen readers can now read emoji-only options); Analogies announces the rule viarole="status"; Matrix labels the pattern grid and answer options. - improve Install banner load. The home-screen install banner icon uses
loading="lazy"anddecoding="async", so it no longer competes with above-the-fold content on first paint. - improve First-time player onboarding. Pi and Geography games now show a short how-to-play banner when a new user lands on them, so it's clear what to tap and why.
- improve Geo intro text localised across all 25 locales (previously the map loaded with a raw question and no context).
New
- new Difficulty settings on every game (except Pi). Added Easy/Medium/Hard pickers to Analogies, Polyglot, Converter, Crazy Comparisons, Stroop, Geo, Memory, Ghost, Math, and Simon. Each setting tunes the game in a sensible way: distractor closeness (Converter, Polyglot, Analogies, Math), option count (Crazy Comparisons, Ghost), congruent-word rate (Stroop), top-N depth (Geo, 5/10/20), sequence tempo (Simon), and preset grid size (Memory). High scores are now segmented by difficulty so a streak on hard stays separate from one on easy. Difficulty labels localize across all 25 site locales.
- new Install to Home Screen prompt with "Play on your next flight - works offline" pitch. Android/Chromium captures
beforeinstallprompt; iOS Safari users see Share → Add to Home Screen instructions. Dismissals are remembered for 30 days. - new Verbal Analogies game at /analogies - complete word-pair analogies across function, location, part-whole, cause-effect, synonyms, antonyms and more.
- new Stroop Test game at /stroop - the classic color-word interference test. Pick the ink color while ignoring what the word says. Measures reaction time.
Improved
- improve Service worker pre-cache now covers every game landing (was 9/13). The offline "play on your next flight" promise now holds for Sequences, Matrix, Odd One Out, and Spatial too.
- improve manifest.json adds
display_override,prefer_related_applications,lang, anddir. Description now leads with offline / flight use case. - improve Analogies / Stroop localized: all interface strings and Stroop color words (RED/BLUE/GREEN...) now translate per locale. Stroop color words are shown in the player's language so the interference effect actually works; analogy content sits in a locale-keyed data file ready to grow beyond English.
Fixed
- fix Blank page on return to browser (iOS Safari). Tabs restored from the back-forward cache with a service worker registered occasionally came back visually empty.
Base.astronow reloads onpageshow/visibilitychangewhen the main element measures zero height, so the content recovers instead of showing an empty viewport. - fix Odd One Out: the game could get stuck on the correct-answer screen without advancing. Auto-advance is now scheduled via a
useEffectkeyed onphase === 'correct', removing a stale-ref race that could swallow the timer between rounds. - fix Sitemap: URLs now use the correct
/{game}/{locale}ordering (matching canonical URLs) instead of/{locale}/{game}, and game prefixes are auto-discovered fromgames.tsso new games appear insitemap.xmlautomatically. Previously all non-EN game locale variants were absent from the sitemap. - fix Browser-language auto-redirect in
Base.astrohad a hardcoded 4-prefix list (/color /memory /geo /pi) so the redirect silently skipped 12 of 16 games. Now injectsGAME_PREFIXESfromgames.tsat build time. - fix Game page copy accuracy in
game-faqs.ts: Memory grids (6×10 max, not 8×8), Convert categories (11, not 8), Polyglot languages list (added English; FAQ now reflects actual 14 supported languages), Math operations (now mentions squares and square roots). - fix Copy accuracy (round 2): Color Memory (added missing 24-color option to meta descriptions + FAQ); Memory (claimed 10 fictional categories incl. "medical", corrected to the actual 9 Unicode categories); Matrix (claimed 5 shapes, there are 8); Sequences (claimed 8 pattern types, code has 14); Polyglot (removed false "spaced repetition" FAQ - the game uses random shuffle); Analogies (removed false "progressive difficulty" claim - the pool is flat).
- fix Matrix half-fill rendering. SVG shapes (hexagon, star, cross, arrow, triangle) rendered the "half" fill as a uniformly 50%-opaque shape while div-based shapes (circle, square, diamond) rendered it as a crisp left-colored / right-transparent split. Players could see a "correct" answer that looked like it did not match its row. All shapes now use the same left-half-filled rendering, and triangle is now an SVG polygon for consistency.
April 16, 2026
New
- new Number Sequences game at /sequences - find the next number in arithmetic, geometric, Fibonacci, prime, and other sequences.
- new Matrix Reasoning game at /matrix - Raven's Progressive Matrices style pattern completion with shapes, colors, and sizes.
- new Odd One Out game at /odd-one-out - spot the item that doesn't belong across numbers, emojis, letters, shapes, and math expressions.
- new Spatial Rotation game at /spatial - find the rotated match among mirrored distractors. Trains mental rotation ability.
Improved
- improve Uniform game UI all game selection controls (difficulty, topic, category, answers) now use shared dropdown components. Selectors appear above the start box for a consistent layout across all 11 games.
- improve Shared GameControls new
GameSelectandIdlePanelcomponents insrc/components/game/GameControls.jsxreplace per-game inline button groups with uniform dropdowns and start boxes. - improve Per-game theme colors each game's Start button now uses its registry theme color from
games.tsinstead of a generic blue. - improve All games now show a one-sentence explanation of the game while the Start button is visible, so new players know what to do.
- improve Sequences, Matrix, Spatial, Odd One Out now have configurable difficulty levels (easy, medium, hard) and answer count selectors.
- improve Sequences added topic selector to practice specific sequence types (arithmetic, geometric, Fibonacci, primes, powers, triangular).
- improve Odd One Out added category selector (emoji, numbers, letters, shapes, math) so players can focus on specific puzzle types.
- improve All games now display translated UI strings for non-English users (stop button, settings, round counter, etc.).
- improve Ghost game wrong-answer screen now shows answer options with green/red highlighting and highlights the removed emoji in the grid, so you can see what you picked vs the correct answer.
- improve Polyglot game category selector replaced with a compact dropdown instead of a row of buttons.
- improve Crazy Comparisons added GA4 event tracking for answer submissions.
- improve Design system added semantic color aliases, spacing scale, type scale and shadow scale as CSS custom properties in
global.css. Site-wide visual changes now require editing one file. - improve Button system added
.btnbase class with--primary,--secondary,--ghost,--danger,--successvariants and--sm/--lg/--blockmodifiers. Replaces ad-hoc inline button styles. - improve Game landing pages now use a shared
GameLandinglayout. Each page went from ~95 lines to ~17. About/FAQ copy lives insrc/lib/game-faqs.tsso a single edit updates both the visible accordion and the FAQPage schema. - improve Schema.org helper
buildGameLandingSchema()emits WebSite + WebApplication + BreadcrumbList + FAQPage consistently across all game landing pages. - improve Game registry now carries a
themeobject per game. Adding a new game auto-themes its landing card with no CSS edits needed. - fix Canonical URLs normalized across all 7 game landing pages to match the site's
trailingSlash: 'never'policy and sitemap. - fix Crazy Comparisons title trimmed from 62 to 55 characters and normalised double spaces.
Fixed
- fix Odd One Out expanded all item pools to support 10 answer choices: powers-of-2 (added 256-1024), cubes (added 216-1000), all 12 emoji groups, letter generators (longer words: PLAYGROUND, KEYBOARDS, BIRTHDAYS, SOMETHING). Depth fallback no longer silently resets answer count.
- fix Spatial added safety guard to polyomino generation preventing rare infinite loops.
- fix Odd One Out removed font-dependent letter classifications (curved/straight, symmetry, enclosed spaces) and replaced with unambiguous rules (vowels/consonants, alphabet halves, letters in words).
- fix Simon Says color flashes no longer disappear at 300% speed. Fixed timing overlap where the off-timer from one flash killed the next flash's visual.
- fix Simon Says audio now pre-scheduled via Web Audio clock instead of setTimeout callbacks, fixing silent playback on iOS after speed changes.
- fix Crazy Comparisons correct-answer celebration tone now reliable on iOS (was using nested setTimeout).
- fix All games Play Again buttons now use each game's theme color instead of generic blue, matching the Start button for visual consistency.
- fix Polyglot dropdown selectors now use the shared gameSelectStyle with custom arrow, matching all other games.
- fix Math removed empty in-game settings panel that opened to show nothing.
- fix Site-wide internal links all 170,475 internal links across 5,811 pages now resolve correctly. Build-time link checker enforces zero broken links going forward.
- fix Geo blog Indonesian articles had inverted
/{lang}/geo/path · fixed across all 176 articles to/geo/{lang}/. - fix Geo SEO footer "Blog" and "Privacy" links now point to global routes rather than non-existent
/geo/{lang}/blog. - fix Constants page cards now link to the new blog "What is X?" articles (which exist) instead of legacy
/pi/{slug}hub URLs. - fix Pi hub page primary "Play" CTA now goes to
/pidirectly (was broken/pi/pi/play). - fix Major system component step-list links now respect the active locale, no longer producing broken English-only URLs in non-English builds.
- fix Memorise CTA button on the localized memorise pages now points to the global blog article (which exists).
- fix Language switcher EN-only learn pages now fall back to home for unsupported locales instead of emitting 404 links.
- fix Geo game "Study" blog link now uses site-wide
/blog/path instead of broken/geo/blog/path, and only appears when the article actually exists for the current locale.
April 15, 2026
New
- new Unit Converter game at /convert with 11 categories (Length, Weight, Volume, Temperature, Area, Speed, Time, Digital Storage, Pressure, Energy, Fuel Economy). Includes both a converter tool and a quiz-style game mode.
- new Ghost and Polyglot blog articles in 25 languages with full color-box styling and memory technique guides.
- new /about page with author photo, bio, game grid, and design principles.
- new /accessibility page detailing WCAG compliance and accessibility features.
- new /changelog page (this page) for tracking all site updates.
- new FAQ sections on all game pages with FAQPage schema for Google rich snippets.
- new Author bylines on all blog posts with photo, name linking to /about, and localized dates.
- new GA4 event tracking added to Major System and Flashcard components.
Improved
- improve Landing page uses 4x2 CSS grid on desktop for consistent card sizing and centering. Game cards wrap and center properly on desktop.
- improve Unit Converter formula explanations and question text now use full unit names instead of abbreviations ("500 Milliseconds" vs "500 ms"). Mobile-first stacked layout with category dropdown.
- improve About blog article in cs, pl, hu, ro, tr, nl now has proper Unicode characters.
- improve Memory blog articles in all 24 non-English languages now have full color-box styling (tip-box, warn-box, key-point, strategy-card, step-badge).
- improve Geo blog Swedish cities article now available in all 25 languages (added cs, el, he, hu, it, nl, pl, ro, th, tr, uk).
- improve Math game operation buttons and settings now centered to match other games.
- improve Footer link labels now fully translated via i18n in all 25 languages. Copyright uses AUTHOR constant. Footer now includes About link, LinkedIn/X social links, and copyright notice.
- improve Blog bylines use AUTHOR constant and i18n for "Back to blog" text across all locales.
- improve Blog index game labels now come from the centralized game registry instead of hardcoded strings.
- improve Schema markup uses AUTHOR_TWITTER constant everywhere; no more hardcoded URLs. Enhanced schema.org markup: richer Person (author image, jobTitle, sameAs), Organization (logo, founder, contactPoint), and FAQPage schemas.
- improve No more scientific notation anywhere. Large/small numbers displayed in full decimal with commas.
- improve No emdashes anywhere on the site. Replaced with middots for cleaner display.
Fixed
- fix Language selector on English-only pages (About, Changelog, Accessibility) no longer produces broken URLs. Redirects to locale home instead.
- fix Project documentation (CLAUDE.md) updated with strict article protocol requiring color boxes in all blog articles.
- fix Distractor generation for extreme values (electronvolts, very small/large numbers) now stays in the correct order of magnitude.
- fix Zero-answer edge case in converter game no longer causes infinite loop.
April 14, 2026
New
- new Speed Math game at /math with configurable operations, number ranges, and difficulty.
- new Twemoji Ghost game (Kim's Game) at /ghost with 2-40 emoji grids, adjustable tempo, and smart distractors.
- new Twemoji Polyglot game at /polyglot supporting 14 languages with emoji-word association.
- new "Why I Built PlayMemorize" article published in 25 languages.
- new Memory blog articles with cognitive science techniques in 25 languages.
- new Pi blog posts for all 24 non-English languages.
- new Unified blog at /blog aggregating articles from all games.
- new Offline mode with service worker, install prompt, and PWA manifest.
- new GA4 event tracking for Memory, Color, Ghost, Polyglot, and Math games.
- new 24-color mode for Color Memory game.
- new Auto-detect browser language and set locale defaults.
Improved
- improve SEO: canonical URLs, schema.org markup, meta descriptions, and sitemap across all pages.
- improve Consistent schema across all localized game pages.
- improve Uniform header design across all games with dark menu background.
- improve In-game settings collapsible on all games to reduce visual clutter.
- improve Ghost: preload all emoji SVGs before showing grid to prevent flicker.
- improve Polyglot: all languages loaded from emoji data, bigger emojis, portrait-friendly grids.
- improve SEO "About this page" sections added to all game pages.
Fixed
- fix Memory game: fixed card flip dependency causing missed clicks.
- fix Ghost: capped cell size and scaled grid to fit mobile screens.
- fix Polyglot: fixed crash on language switch and emoji sizing issues.
- fix Timer leaks and React performance issues across all games.
- fix Broken links, header layout, and excess spacing throughout.
- fix Color game: speed always starts at 100% now.