What's new

Recent changes to Poké Memory. You're on version 0.11.8.

  1. v0.11.8

    Jul 16, 2026

    Added

    • The end-of-session summary now previews how many new cards tomorrow will introduce alongside the reviews already due, so you can see the full shape of your next session at a glance.
    • The Pokédex detail page now shows a "First reviewed" date for any species you have started, and a "Mastered" badge for species you currently have mastered, turning each entry into a small record of your learning journey.
    • The all-done end-of-session screen now shows a "Pokémon of the day" spotlight: a daily-rotating species with its sprite and a fact, and a "reveal the name" prompt to flip it into view. The same Pokémon shows all day and rotates the next day.
    • Signed-in users can now opt in to a late-day reminder that only fires when their streak is genuinely at risk (they have not practised today and no streak-protection token would save it automatically), never a duplicate of the primary daily reminder.

    Changed

    • The Pokédex mastery filter now splits "Not yet mastered" into separate "New" and "Learning" pills, so you can browse only the species you have never seen or only the ones you are actively learning.

    Fixed

    • Branching evolutions with identical triggers no longer show two forward cards with the same question but different answers: Cosmoem, Meowth and Wooper now name the game version or regional form in the prompt, and Wurmple (which evolves at random) carries a note that either result is correct.
    • The Pokémon of the day spotlight now shows its sprite and heading straight away rather than waiting for its fact to load, so it no longer appears blank for a moment on a slow connection.
    • Fixed a crash on browsers that block site data or cookies (seen on Windows), where the machine-translation notice and a few other storage reads could throw instead of degrading gracefully.
  2. v0.11.7

    Jul 15, 2026

    Added

    • Verified typed entry now works for Japanese and Chinese learning languages: answers are graded against the native-script name, with romanised input (romaji / pinyin) accepted in the default lenient mode. A new answer-matching setting under Practice switches between lenient and native-script-only strict matching, and the reveal always shows both the native script and the romanisation.

    Changed

    • The daily Web Push reminder route now reads through two SECURITY DEFINER RPCs (get_push_targets, get_push_due_cards, migration 046) instead of raw service-role table SELECTs, narrowing its cross-user read surface to the functions' explicit return contracts.
    • Extracted four duplicated code patterns into single-source helpers (weekly code-quality digest #1906, items 2-5): the persisted-queue push + session-fallback engine shared by the sync retry and reconnect hooks (lib/sync/pushWithFallback.ts), the getUser() + 401 guard used by authenticated API routes (lib/auth/requireAuth.ts), the JSON-body parse guard used by POST API routes (lib/api/parseJsonBody.ts), and the inline section-heading Tailwind literal now routed through sectionHeadingSm. No behaviour change.

    Fixed

    • Weekly workflow digest cron no longer dies at the agent turn cap: the 30-day signal gather (retro comments, review feedback, WIP commits, merged-PR bodies) is pre-fetched deterministically in a shell step and the agent reads prepared files.
    • Journey milestone banner now reads as a crossed achievement ("Milestone reached: 100 Pokémon mastered!") instead of a bare number that looked like a wrong live count, and its banner and share text are localised in all four app locales.
  3. v0.11.6

    Jul 14, 2026

    Added

    • E2E layout-regression check for the Higher-or-Lower minigame: bounding-box assertions on tile proportions and viewport-edge clearance (highlight-ring clipping), covering the two v0.11.5 visual regressions.

    Changed

    • Extracted the bearer-token authorisation check duplicated across three API routes into a single shared helper (lib/auth/bearerAuth.ts); no behaviour change.

    Fixed

    • Service-worker registration and update failures no longer surface as unhandled promise rejections. A browser that declines to register a service worker (private browsing, enterprise policy, a search-engine crawler) now degrades silently to an online-only page instead of reporting an error.
    • The cron-health monitor now finds its own open tracking issues again: repeat failures update the existing issue in place instead of filing duplicates, and a recovered workflow's issue closes automatically on the next healthy run. The broken gh issue list --search marker lookup (the marker's colon parsed as a search qualifier and matched nothing) is replaced with the repo-standard local jq marker match.
  4. v0.11.5

    Jun 12, 2026

    Changed

    • The Higher or Lower mini-game now launches from a "Play Higher or Lower" button on the end-of-session summary into the practice-card position, instead of being stacked at the bottom of the page. The summary collapses to a compact highlights bar while playing, and a "Back to summary" control returns to it.

    Fixed

    • Play cry on reveal is now independent of the Cry cards setting: the toggle is no longer greyed out or labelled as disabled when cry cards are off.
    • Cry audio served from the offline pack now plays on WebKit (Safari): the service worker honours range requests with a 206 response, fixing a silent stall that played no cry and added a delay when grading (#1886).
    • The Higher or Lower tiles now render as content-sized cards (no longer stretched to the full height with empty space) and their highlight borders are no longer clipped at the screen edges.
    • Settings toggles now save immediately when switched, so Play cry on reveal (and other toggles) no longer revert on navigation.
  5. v0.11.4

    Jun 11, 2026

    Changed

    • Discord bug-report notifications now include a capped preview (up to 500 characters) of the feedback message, fetched route-side by id rather than via the pg_net trigger payload. The trigger payload and forbidden-fields guard are unchanged. Privacy notice, DPIA, and Children's Code assessment updated to record the Discord data flow.

    Fixed

    • Fix Higher-or-Lower Next/Play-again button pushed below the fold on mobile: adopt the flex-1 min-h-0 shrinkable sprite row plus flex-none pinned footer layout so the action button is always visible without scrolling, and remove the scrollIntoView workaround from #1447.
    • Offline pack download now checks available storage headroom (via navigator.storage.estimate()) before starting, comparing it against the pack's expected size plus a buffer for concurrent progress saves. When space is tight a low-storage warning appears with "Cancel" and "Download anyway" options, instead of silently filling the origin quota and disrupting card-progress saves. If the Storage API is unavailable the download proceeds as before.
    • Lifted the "Send feedback" entry to the top of Settings (above all accordions) so it is reachable without scrolling (#1849). The buried bottom link has been removed.
    • Added feedback/bug/report/contact/support synonyms to the Settings search index so searching "feedback", "bug", or "report" surfaces the entry (#1849).
    • Added an optional "Which page is this about?" selector to the feedback form; the stored page now reflects the user-stated route (or null), so the Discord bug notification no longer shows a constant "Page: /settings" (#1847).
    • Account switch now clears the previous user's IndexedDB review session and grade log, so their progress can no longer blend into the next signed-in account on a shared device.
    • Mastery badges can now be earned in every learning language: badge checks, the Stats mastery and struggling panels, the per-game breakdown, the Journey timeline and close-to-mastery list, and the favourite-theme unlock all follow your active Pokémon-name language instead of silently evaluating English-only progress.
    • The "I already know these" onboarding quiz no longer double-grades species when more than one learning language is enrolled, and its grades now sync with the correct language.
    • Journey evolution wall now shows Pokémon names in your chosen Pokémon-name language (Japanese, Simplified Chinese, Traditional Chinese) instead of always showing English names. Image alt text and edge aria-labels are updated to match.
    • Stats "Struggling cards" list now resolves locale names via the locale-aware hook; the speciesId field was missing from StrugglingCard, preventing the hook from being called at all.
    • Higher-or-Lower minigame tiles now display localised Pokémon names instead of raw English seed names.
    • Pokédex and Pasture search now matches the locale name and transliteration (rōmaji for Japanese, pinyin for Chinese) as well as the English name, so searching by the name visible on screen works for all supported locales.
    • Pokédex alphabetical sort now uses the displayed locale name with an appropriate collator instead of sorting by invisible English strings.
    • Streak days and grade-log entries are now recorded in your timezone, so evening reviews no longer land on the wrong day, phantom gaps no longer break streaks or auto-spend protection tokens, and the Stats charts count today's reviews immediately.
    • Date displays no longer shift one day late for UTC+13/+14 timezones, the due-forecast axis labels now match their tooltips everywhere west of UTC, and the Stats history windows no longer skip a date across DST changes.
    • Closed six superuser write-guard gaps: sign-in callback no longer uploads QA-seeded cards; Pasture mark-seen respects the guard; Settings regional-prefs pushes are suppressed while any flag is on; a persisted cleanup-pending marker keeps writes suppressed throughout exitCleanup so a degraded pull cannot allow seeded data to reach Supabase; the guest destructive reset now clears all seeded state (streak, protection tokens, grade log, mastered-count cache) via clearSeedScenario; the QA-seed active indicator now survives a cancelled or failed cleanup; and the Cmd/Ctrl+Z undo handler captures the current guard value rather than a stale closure.
    • GDPR data export now paginates the grade_log fetch, ensuring users with more than 1000 reviews receive a complete export (previously silently truncated at the PostgREST 1000-row cap).
    • pullGradeLog and pullStreak paginate to completion so a fresh device always receives the full review history and streak history rather than only the oldest 1000 rows.
    • The daily push notification route paginates the due-card query and adds an ORDER BY for deterministic offset pagination, preventing large backlogs from being miscounted or skipped.
    • The FSRS optimiser fetches the full grade log rather than only the oldest 1000 rows, so personalised weights reflect the user's complete review history.
    • A shared fetchAllPages helper (lib/sync/paginatedFetch.ts) provides a tested, client-agnostic pagination loop so future queries do not silently re-introduce the cap.
    • Offline grades from a force-killed tab are no longer silently discarded: the persisted queue is rehydrated on the next session and pushed to the cloud.
    • A card rejected by the regression trigger (SQLSTATE 23514) is now evicted from the retry queue instead of being retried forever and poisoning the unload beacon batch.
    • updated_at on card_reviews is now stamped server-side by a BEFORE UPDATE trigger (migration 043) so the lastPullAt clock-skew anchor is always authoritative regardless of the pushing device's clock.
    • pullAndMerge and the useSyncOnUnload catch path re-read the current sync status immediately before writing, preventing concurrent legs from clobbering each other's fields.
    • Re-grading the same card while a push is in flight no longer causes the newer re-grade to be silently dropped from the queue.
    • clearLocalProgress no longer sweeps other users' archived state on a shared device.
    • Seed pipeline: flattenChain now picks the region-tagged evolution detail (fixing silent omission of Alolan, Galarian, Hisuian, and Paldean form-aware evolution edges); buildVarietiesLookup keys by regional prefix so multi-segment slugs (e.g. "galar-standard") resolve correctly.
    • Seed pipeline: a failed evolution-chain fetch now exits the seed run immediately rather than persisting an empty chain; validateShards asserts at least one form-aware edge (id > 10000) and, when prior chain data is supplied, that no previously non-empty chain has become empty.
    • Seed pipeline: 429 rate-limit responses are now retried with backoff (previously immediately fatal, causing silent species drops); validateSpeciesIds checks set membership so a dropped species is detected even when new species arrive in the same run.
    • Seed pipeline: writeSplitSeedFiles now writes generated-core.json and generated-chains.json to public/pokemon-data/ as well as lib/pokemon/ (mirroring the existing flavor/locale-names dual-write); validateShardParity asserts byte-equality of all four shards between both directories.
    • Seed validator: flavour-shard check now only requires records with non-empty flavorTexts in generated.json to appear in the shard, preventing a false-positive failure on freshly-backfilled flavourless species.
    • Service worker no longer caches authenticated /api/** responses: the GDPR export CSV can no longer persist in Cache Storage after sign-out or be served to a different account.
    • SKIP_WAITING multi-tab gate now uses REQUEST_SKIP_WAITING so Serwist's unconditional built-in listener cannot bypass it, and queries includeUncontrolled:true so the client count is accurate for a waiting worker.
    • Push toggle now reconciles against the server on mount: an orphaned subscription (server row deleted after a 410) is re-inserted automatically or the toggle is flipped off so the user knows reminders have stopped.
    • F7: cry auto-play effect now fires only when the displayed card's id changes, not on every grade that updates the cards array
    • F10: typed-entry normaliser folds U+2018/U+2019 typographic apostrophes to ASCII and strips ♀/♂, so Farfetch'd, Sirfetch'd, Nidoran♀ and Nidoran♂ can now be graded Good
    • F19: forgetting-horizon projection now anchors on lastReview instead of dueDate, fixing the double-interval overestimate
    • F28+F32: /api/feedback now rate-limits via check_rate_limit RPC and caps page/appVersion fields to 300 chars
    • F29: /api/srs/optimize pre-stamps an in-progress marker before the CPU-heavy fit, closing the concurrent-request window (migration-free)
    • F36: TTS speakName now threads the active pokemonNameLocale into the utterance lang and voice selection, and skips English MP3s for non-English locales
    • F40: MasteryOverTimeChart tooltip now formats dates via the user's date format preference; formatXTick helper hoisted to formatChartDate in lib/utils/format-date.ts (shared with ActivityHistoryChart)
    • F41: five inlined Tailwind literals replaced with class-name constants (mutedTextXs, mutedText, pageTitle)
    • F44: saveSettings now falls back to pokemonNameLocale when activePokemonNameLocale is absent, preserving locale enrolment from pre-#1484 backups
    • F48: future-direction forgotten pill now counts relative to the projectable population (trackedCount) rather than totalSpecies (~1025)
    • F53: robots.txt Disallow rule for /audit-themes no longer has a trailing slash, correctly matching the route
    • F59: pretendAllMastered past overlay now synthesises events before the earliest checkpoint so all past snapshots show the full mastered count
    • Theme unlock and the applied-favourite check now use the same species-level mastery rule as the Pasture and Stats (both the name and reverse legs, mastered in any enrolled locale), instead of unlocking on the name card alone. Already-applied favourites are grandfathered and kept.
    • Feedback submission no longer fails with 429/500 for all users: added 'feedback' action to check_rate_limit (migration 045) and made the route fail-open on RPC errors rather than treating them as rate-limit blocks (#1883)

    Security

    • Drop the dead usernames_select_public RLS policy; all username rows are no longer publicly readable via PostgREST now that the sign-up/sign-in path runs entirely through Server Actions.
  6. v0.11.3

    Jun 10, 2026

    Added

    • The maintainer receives Discord notifications when users submit feedback: immediate ping for bug reports, weekly digest for all categories.
    • Added Sentry error and performance monitoring (@sentry/nextjs): client, Node, and Edge runtime initialisation, server-side onRequestError hook, and client error-boundary capture. Wired inert until the maintainer provisions the DSN and auth token.
    • Settings > About now shows the active service-worker version alongside the app version, with a clear warning when they differ (indicating a pending update). (#1826)
    • Settings "Last synced" time now correctly honours the user's configured timezone, matching the fix previously applied to Stats. (#1823)
    • Added app/global-error.tsx: a root-layout error boundary that reports uncaught errors to Sentry. app/error.tsx does not catch errors thrown in the root layout or template; this boundary fills that gap (follow-up #1822).

    Changed

    • Offline download progress now shows MB-scale bytes (e.g. "60.0 MB downloaded") rather than coarse GB-with-one-decimal ("0.1 GB"), making progress meaningful from the start of the run.
    • Added a "Delete offline cache" button to the Offline settings section so users can reclaim the storage used by the downloaded sprite and cry pack without clearing all site data.

    Fixed

    • Fixed the Practice-page bottom tab bar floating ~21px above the bottom of the screen on iOS (it now sits flush). The bottom nav is an in-flow app-shell child anchored to the large viewport (lvh) instead of position:fixed, so it reaches the true visible bottom on non-scrolling pages.
    • On desktop (md+) the layout reverts to normal document scroll so existing scrollable pages are unaffected.
    • Fixed the ~6-second blank (black) screen on PWA cold launch. The cause was the Practice cold-boot session build calling new Intl.DateTimeFormat(...) once per card (via the SRS scheduler's date helpers), thousands of constructions that blocked the main thread before first paint. The per-timezone formatter is now cached, collapsing the per-card date cost from ~147ms to ~4ms per session-build pass over the full deck and removing the main-thread block.
    • Offline sprite/cry pack now stored in IndexedDB instead of Cache Storage, eliminating the root cause of the iOS PWA cold-launch hang (#1803). A Cache Storage with ~10,000+ entries makes WebKit's cache.match globally slow, stalling render-critical precache lookups on every cold launch. Moving the offline pack to IndexedDB keeps Cache Storage small so cold launch is fast regardless of whether the pack is downloaded.
    • On SW activate, the old poke-memory-sprites-v2 / poke-memory-cries-v2 Cache Storage buckets are deleted automatically, unblocking existing affected users without any manual action.
    • The "Delete offline cache" button now clears the IndexedDB offline-pack store and also sweeps the legacy Cache Storage buckets for users who have not yet received the new SW activate.
    • Fixed the remaining PWA cold-launch hang by switching the service-worker navigation strategy from NetworkFirst (10 s timeout) to StaleWhileRevalidate. The SW now serves the cached app shell instantly on cold launch rather than blocking paint until the network returns the HTML document.
    • Precached the Pokémon seed data (public/pokemon-data/*.json) so cards render immediately on cold launch without a separate network round-trip.
    • Fix scroll regression on Settings, /privacy and /terms: the #1801/#1839 app-shell change made [data-scroll-region] always overflow-hidden, leaving pages that do not use PageShell unable to scroll on mobile.
    • Extract ScrollRegion client component that reads usePathname() and applies overflow-hidden only on the Practice route (/), overflow-y-auto on every other route, and md:overflow-visible on desktop.
    • Revert PageShell's internal overflow-y-auto min-h-0 so there is a single scroller per page and no nested double-scroll on PageShell pages (#1801, #1839).
    • Practice: all card variants now shrink to fit the viewport with no scroll and no clipping on any supported device (iPhone SE to iPhone 17 Pro). The SpritePicker 2x2 grid fills the flex-1 card region and scales sprites via max-h-full / w-auto / object-contain, so it no longer overflows or clips the queue-state badge on short viewports. The reverse-card variant no longer uses overflow-y-auto on the card region. Name, evolution, reverse-evolution, multiple-choice, and typed-entry card sprites use max-h instead of fixed h- so they can shrink on very short viewports. Builds on #1801 and #1839.
    • Fixed Practice content being clipped and scrollable on mobile after the #1801 app-shell change. Scroll ownership is now per-page: the app-shell fit region is overflow-hidden (no scroll, Practice fits); pages that need to scroll (Pokédex, Pasture, Stats, etc.) own their own overflow-y-auto inside the PageShell <main> element.
    • Fixed the pick-the-sprite practice card clipping its top pill and bottom controls on mobile: the 2x2 sprite grid now shrinks to fit the available height so nothing is cut off (follow-up to the bottom-bar app-shell fix).
  7. v0.11.2

    Jun 8, 2026

    Changed

    • Corrected mastery descriptions in the Pasture reps info panel and the Trainer Card level tooltip to reflect the stability-based mastery rule introduced in #1765, removing references to the old reps >= 3 gate.
    • Removed the deprecated "Mastery threshold" setting control from Settings (the setting no longer affected mastery since #1765).

    Removed

    • Removed always-redundant per-direction (name/reverse) mastery rows and blocked hint from the Pasture long-press popover. The Pasture only ever shows fully-mastered species, so both legs were invariably "Mastered". The rows remain on the Pokédex detail panel and Journey where they are meaningful.

    Fixed

    • Pokédex grid sprites now render crisply on retina screens (2x/3x DPR). A srcset with 1x=64 px, 2x=120 px, and 3x=192 px WebP variants lets the browser pick the sharpest source for the device. The 120 and 192 px files were already in the offline precache, so no extra bytes are added for offline users.
    • The offline-download progress now counts real downloaded bytes instead of a flat per-file estimate, storage usage is shown in GB, and the storage figure refreshes while the download runs.
    • Offline precache now downloads only the 9 WebP widths used by offline-reachable surfaces (drops the 180 px ThemeWatermark decorative variant), cutting the precache from ~67.5 MB to ~59.7 MB of actual file bytes.
    • "Last synced" time on the Stats page now respects the user's configured timezone instead of the browser's local timezone.
    • Completing a scoped practice group no longer silently drops the filter on navigation. The active scope is now shown on the end-of-session screen, and a "Clear filter to keep practising" button makes resuming the full card set a deliberate action.

    Security

    • Add per-IP rate-limit throttle on username sign-up and sign-in Server Actions (migration 041): salted-hash IP bucketing via public.check_rate_limit SECURITY DEFINER RPC, 5 sign-up/10 min + 10 sign-in/10 min caps, raw IP never persisted; rate_limited error surfaced in all four locales.
    • DB security audit: add explicit deny-all SELECT policy on feedback to document service-role-only intent; revoke authenticated execute on reconcile_grade_log_orphans maintenance RPC; document delete_account/reset_all_progress as intended SECURITY DEFINER; note pg_net-in-public WONTFIX.
  8. v0.11.1

    Jun 7, 2026

    Added

    • Pasture, the Pokédex detail panel and the Journey "Close to mastery" list now show per-direction mastery status (name card vs reverse card), with a hint naming the leg that is blocking full mastery.
    • New "Almost mastered" practice preset scopes a session to species where one direction is mastered but the other is not yet, so you can close the gap directly.

    Changed

    • Offline precache reduced from ~212 MB to ~67.5 MB (drops ~144.6 MB, 68%) by switching the Pokédex grid to the pre-generated 64 px WebP sprites already in the precache, and removing raw PNGs from the precache list. Offline Pokédex browsing is unchanged.
    • Biome detail page heading hierarchy audited and confirmed correct: one <h1> for the biome name, no skipped levels. Added component tests asserting the heading outline (#1758).
    • Mastery now uses FSRS stability (>= 21 days) instead of the old reps >= 3 sub-gate. Cards that had reached a large interval via an early Easy grade but were stuck waiting for a third review now correctly count as mastered. A lapse that drops stability below 21 reverts a species to learning; earned gym badges are unaffected.
  9. v0.11.0

    Jun 7, 2026

    Changed

    • Privacy notice (§1) now states the ICO registration number (ZC165261) for Frazzled Productions Ltd, confirming the data protection fee has been paid.

    Removed

    • Removed the Pokéball loading overlay (#pwa-splash) that appeared during PWA boot. Boot-perf work (#1677/#1705) resolved the blank-content gap it was covering, and the literal Pokéball SVG was gratuitous Pokémon branding. The neutral theme background now shows through during hydration. The iOS cold-launch fix (apple-touch-startup-image PNGs) is unaffected.

    Fixed

    • Fixed multi-user data isolation: switching accounts on one device no longer blends one user's cards, streak, grade log, or settings into another's session, and no longer pushes the blended state to the incoming user's cloud account. Outgoing user's local data is preserved in a per-user archive so it is restored if they sign back in.
    • Fixed the iOS bottom tab bar detaching from the screen bottom on cold load and snapping into place after the first scroll. Changed min-h-dvh to min-h-[100svh] on <body>: svh (URL-bar-expanded height) is correct at first paint, whereas dvh (URL-bar-collapsed height) resolved to the wrong value before any scroll reconciled the viewports (#1728).
    • Fixed production /sw/sw.js returning HTTP 500 (file-trace gap under cacheComponents: true); PWA updates are now restored for all installed users.
    • PWA now discovers and adopts fresh builds faster: the hidden-tab update check fires after 90 s (down from 5 min) and the background interval runs every hour (down from 4 h).
    • The PWA service worker is now served as a true static asset (public/sw/sw.js) generated at build time, rather than by a request-time serverless function. This removes the class of bug behind the earlier production 500 (#1749) for good, instead of patching it: a Next.js upgrade can no longer reintroduce a missing-module failure, and the worker is served straight from the CDN. The registration URL is unchanged, so installed PWAs keep working without re-registering.
  10. v0.10.35

    Jun 6, 2026

    Added

    • Pasture now shows a one-shot hint on first visit ("Press and hold any Pokémon to see its name, mastery date, and review interval") so the long-press detail popover is discoverable. The hint is dismissed with a single tap and never re-appears.
    • Practice screen now shows a one-shot hint ("Finish your session for a bonus mini-game") once you have seen at least one Pokémon in a session, signposting the Higher or Lower stat challenge that unlocks after two Pokémon. The hint is dismissed with a single tap and never re-appears.
    • Added accessible info affordances for "Closest to mastery" sort and queue-state badges: a small circle-i InfoButton explains FSRS jargon in plain language, keyboard-reachable and localised across all four supported locales.
    • Stats page: new "Languages" card for multi-language learners, showing each enrolled locale's card count, mastery percentage, and last review date. Hidden for single-locale users.
    • Journey page now shows a "Languages" section for users studying multiple Pokémon name locales, with per-language mastery count and best review day. Visible only when the Languages lab flag is on and more than one language is enrolled.
    • Added "Send feedback" entry point in Settings (Account &amp; Data section) that opens a modal for reporting bugs, requesting features, or leaving general feedback. Works for both guests and signed-in users. The form captures the current page path and app version automatically and includes a privacy notice reminding users not to share personal information.
    • Added an accessible info affordance for the reps badge on the Pasture "Next arrivals" strip: a circle-i InfoButton in the section heading explains what reps means in plain language ("how many times you have reviewed this card so far"), keyboard-reachable and localised across all four supported locales.
    • Guest sign-up nudge on Stats and Journey pages: a one-shot loss-aversion callout appears for guests who have mastered 10 or more Pokémon, or completed 3 or more practice sessions, prompting them to create a free account before browser data is cleared.
    • Replace the SignInPicker dropdown with a SignInSheet bottom sheet / centred modal that leads with a value-prop heading and a full a11y contract (focus trap, inert backdrop, Escape to close, focus restore). The sheet is the single sign-in surface: the GuestSignUpNudge CTA now opens it instead of its own inline provider picker.
    • Added username/password sign-in as a secondary door in the SignInSheet. Accounts use a synthetic email internally; the username is the only identifier shown to the user. Sign-up includes prominent no-password-reset and no-real-name warnings in all four locales.
    • Added a low-key "More from Frazzled Productions" cross-promo link to frazzledproductions.com, in the footer and under Settings → About (so mobile bottom-nav users, who do not see the footer, still get it). Opens in a new tab. Copy added in all four locales.
    • Add QA cloud seeder script (npm run qa:seed-cloud) that creates five durable named users in the QA Supabase project (qa-fresh, qa-mastery, qa-locale, qa-streak, qa-conflict) and seeds each with a faithful, cloud-specific dataset via the service-role client. Includes --dry-run mode (no network calls or credentials required) and a forcing-function test suite that enforces FSRS bounds, name+reverse pairing, and locale consistency.

    Changed

    • Privacy notice, Terms of Use, and DPIA updated to identify the data controller and service operator as Frazzled Productions Ltd (company number 17258540), registered in England and Wales.
    • Statutory trading disclosure (registered name, company number, and registered office) added to the site footer (desktop/hamburger-nav) and the Settings About section (bottom-nav mobile), so it is reachable from every page. Rendered from a single shared source component (CompanyDisclosure).
    • Move all hardcoded English aria-label strings across 15 component and page files into the next-intl message catalogues. Dynamic labels use ICU parameters. All four locale catalogues (en, ja, zh-Hans, zh-Hant) updated; xx-pseudo regenerated.
    • Privacy notice and DPIA updated to cover the new feedback-submission data flow (lawful basis, retention period, cascade deletion on account delete, and child-friendly summary item).
    • Analytics: emit an app_open custom event on load with bucketed, non-PII properties (userType and progressBucket) to measure the guest-to-account funnel. Privacy notice updated to disclose the event.
    • Updated the privacy notice, Terms of Use, DPIA, and Children's Code assessment for the new username/password sign-in door (#1671): the OAuth-only framing is gone, the chosen username is documented as the personal data collected, the DPIA R4 child-account risk is re-assessed (the inherited 13+ age gate no longer applies to this door, mitigated by the uniform Children's Code standards), and the Terms warn that username/password accounts have no password-reset path. Email-related compliance copy (SMTP sub-processor, auth-email lawful basis) is deferred until magic-link sign-in ships, since no email is collected today.
    • Add async seed-loading infrastructure: seed-constants.ts (extracted ID-namespace constants), buildSeed pure function in seed.ts, seed-async.ts module-singleton loader that fetches generated-core.json + generated-chains.json from public/pokemon-data/ at runtime, and SeedContext.tsx React context. Existing synchronous SEED_POKEMON / SEED_EVOLUTION_CARDS / SEED_REVERSE_EVOLUTION_CARDS exports are unchanged. Stage 1 of #1677.
    • Remove the ~1.28 MB Pokémon seed JSON from the first-load client bundles of all non-Practice routes (Pokédex, Stats, Settings, Pasture, Journey, Auth callback). The seed now loads asynchronously via SeedContext; pages gate their effects on seed !== null and render normally once data arrives. The QA-seed scenario builders and backup import/export read the loaded seed instead of value-importing it, and a check:bundle CI guard fails the build if the seed ever leaks back into a static chunk.

    Fixed

    • Hotfix PRs merged directly to main now automatically backmerge into qa so the next promotion PR is never silently behind. Previously a hotfix could block auto-merge until a manual sync PR was raised.
    • Removed the hard horizontal divider line that appeared under the ProfileStatusBar on all non-Practice pages (Pokédex, Pasture, Stats, Journey). The non-theme zinc border read as a near-black line in dark mode; the Nav's own border already delimits the header region.
    • Pasture: resolve Pokémon names via useLocalePokemonName for the sprite button aria-label, <Image alt>, popover aria-label, and popover visible name. Screen-reader users in Japanese, Simplified Chinese, and Traditional Chinese now hear the locale-appropriate name rather than the English name. Popover visible name is wrapped in <span lang> for non-English locales.
    • The Pasture biome "Latest addition" name now renders in the active Pokémon name locale (ja / zh-Hans / zh-Hant) instead of always in English, on both the main Pasture screen and the per-biome detail page. The name is wrapped in a lang attribute for correct screen-reader pronunciation.
    • Release cut (auto-release.yml) no longer fails on changelog fragments that carry an extra issue: front-matter key. The cut and the PR-time lint now share one parser (scripts/lib/changelog-fragment.mjs), so they can never disagree on what a valid fragment is.
    • Added a daily qa-drift-check job that detects when qa was left un-reset after a release (main no longer an ancestor of qa) and opens a tracking issue, instead of the drift surfacing as merge conflicts at the next promotion.
    • Added iOS PWA splash screens for four common iPhone form-factors that previously cold-launched to a black screen (390×844, 428×926, 414×896 @2× and @3×, covering iPhone 12/13/14, the Pro Max line, XR/11, and XS Max/11 Pro Max). The device table is now a single source of truth (lib/pwa/splashDevices.ts) shared by the PNG generator and the layout metadata, with a CI guard asserting every device has correctly-sized PNGs and a matching media query.
    • Stage 2 of async seed loading (#1677 / #1604): ReviewSession now reads the seed from useSeed() (SeedContext) instead of a direct module-level import of @/lib/pokemon/seed. SEED_POKEMON and SEED_EVOLUTION_CARDS are no longer value-imported by the practice page at module level, so the seed JSON is not required to parse synchronously before the ReviewSession component can render. A branded loading skeleton and a retry-on-error state replace the previous synchronous block.
    • <SeedProvider> wired into app/layout.tsx, making the async seed available to all routes via useSeed().
    • The EvolutionCard type alias conflict (component vs data type) in ReviewSession.tsx resolved by aliasing the data type as SeedEvolutionCard.
    • Missing </SeedProvider> closing tag in app/layout.tsx fixed.
    • ReviewSession.test.tsx updated: vi.mock("@/lib/pokemon/SeedContext") added, providing a stable useSeed() mock that returns seed data via the existing mockSeedPokemon fixture. All 103 existing tests continue to pass.
    • Boot-path (practice route /) consumer migration complete: lib/review/scope.ts, lib/superuser/SuperuserContext.tsx, and lib/profile/useProfileStatus.ts no longer value-import from @/lib/pokemon/seed at module level. scope.ts uses getSeedIfLoaded() with correct lazy-only memoisation (never caches an empty result); SuperuserContext.tsx calls await loadSeed() inside the async exit-cleanup effect; useProfileStatus.ts reads seed?.seedPokemon.length from useSeed() and re-runs when the seed loads. The settings route (which includes KnownPokemonQuiz) still statically imports seed data and will be decoupled in Stage 3.
    • vitest.setup.node.ts and vitest.setup.ts updated to call _primeSeed() with the full seed, so getSeedIfLoaded() returns real data in all test environments without triggering a fetch.
    • GameScopePicker.test.tsx updated to mock @/lib/pokemon/SeedContext (the component was migrated to useSeed() in Stage 2) so its 10 unit tests continue to pass.
    • Bundle verification: after the build, the 1.28 MB seed chunk (0fw0.e~tljz7m.js) is NOT referenced in index.html (the / route's first-load HTML). The seed JSON has left the boot path. Ivysaur, captureRate, and other seed-unique identifiers are absent from all 20 first-load chunks (~1.25 MB total, dominated by the React/Next.js/Supabase framework chunks).
    • Corrected the Higher or Lower hint copy so it accurately says the mini-game appears after you finish today's cards (with the at-least-two-Pokémon caveat), rather than implying it unlocks after reviewing two Pokémon. Updated in all four locales.
    • Sync: stop stale clients from clobbering user_settings sub-objects (streakProtection, onboarding, earnedBadges). The LWW pull branch now snapshots the applied settings so the next push sees a zero diff; first-push default-pruning prevents a fresh device from overwriting richer cloud values with defaults.
    • Integration tests no longer false-fail when run in a non-UTC timezone. Postgres date columns are now read back via local date components (a shared pgDateToISO helper) instead of toISOString().slice(0, 10), which shifted the day in timezones behind UTC. Affects pull-and-merge and reconcile-orphans.
    • The Higher or Lower teaser no longer appears after the first card. It now shows only once at least two Pokémon have been seen, matching the mini-game's own minimum (the game renders at the end of the session and needs two Pokémon), so it never teases a game the user cannot reach.
  11. v0.10.34

    Jun 3, 2026

    Fixed

    • PWA cold-start on iOS no longer shows a black screen while JavaScript loads. The correct background colour is now applied immediately, and a Pokéball loading indicator appears after 300 ms so the app looks responsive rather than broken.
  12. v0.10.33

    Jun 2, 2026

    Added

    • Practice screen now surfaces a dismissible nudge pointing to Settings > Offline when repeated slow sprite loads (3+) or five practice sessions without a download are detected, so users who experience slowness can discover the 166 MB pre-fetch feature without hunting through Settings.
    • Offline Settings section now shows whether downloaded content is "Up to date" or "Update available (N new)" by comparing a content manifest signature stored at download time against the current asset set. The Update button is disabled when content is already current, removing the blind-click guesswork.
    • Status bar pills (streak, protection tokens, mastery) now reveal their meaning on tap (touch) or hover/focus (desktop), so sighted users do not have to guess what the icons represent.

    Changed

    • Daily push notifications now cover all your learning languages, not just the active one. If you are learning multiple languages, the notification body shows a per-language due count (e.g. "English 12, 日本語 8") alongside the global total.
    • The child-facing privacy summary on the Privacy page now renders in your chosen app language (Japanese, Simplified Chinese, Traditional Chinese, and English), instead of always showing in English.
    • Pokédex entry rows in the species detail panel now show the source game name(s) instead of the repeated "Pokédex entry" label (e.g. "Red · Blue", "FireRed · LeafGreen · Emerald +2"). When the same text appears in multiple games, the row is shown once with all its games listed.

    Fixed

    • Fixed a crash in the Stats "Accuracy by card direction" chart where Recharts passing an empty payload array during chart transitions caused a TypeError.
  13. v0.10.32

    Jun 2, 2026

    Added

    • Added a persistent profile status bar showing your streak, protection-token balance, and mastery progress at a glance on every page, including the Practice screen on mobile. The three signals render as consistent icon pills drawn from one shared source, and the streak and token pips that previously sat separately on the Practice and Stats screens are now carried by the bar.
    • Each language you are learning now has its own independent practice progress and daily new-card budget. Switching the Pokémon-name language from the status-bar pill draws that language's own queue, so studying Japanese names no longer touches your English progress (your streak and protection tokens stay shared across all languages). Typed-entry answering stays English-only for now and falls back to tap-to-reveal in other languages.
    • Enrolled learning languages now sync across devices and survive signing in on a new device: the union of all enrolled languages (and the tombstone of removed ones) is merged on every background pull, so adding Japanese on your phone is visible on your tablet after the next sync.
  14. v0.10.31

    Jun 1, 2026

    Changed

    • Contact addresses updated to Frazzled Productions Google Workspace addresses: privacy@pokememory.com (legal/GDPR contact in the privacy notice, terms, and DPIA) and hello@pokememory.com (translation-feedback string, in-app and all locales).
  15. v0.10.30

    Jun 1, 2026

    Changed

    • Improved Japanese and Chinese (Simplified and Traditional) onboarding copy: replaced technical jargon and machine-translated register with child-appropriate, natural-language phrasing across the first-visit modal. An in-app "machine-translated" banner and "preview" locale label remain in place until full native-speaker sign-off is completed.
    • Added an inline note in Settings (Audio section) and the first-visit onboarding modal that spoken Pokémon names use AI-generated audio still being improved, so some may be mispronounced. Removed the stale "Voice sounding robotic?" hint, which addressed a device-TTS fallback that is rarely heard now that pre-generated name audio is fully covered.

    Fixed

    • Fixed a crash where grading a card with an invalid FSRS state (stability 0 written by an older app version) threw FSRSValidationError and permanently bricked the Practice screen. Invalid states are now healed to a clean initial state on load, and the error boundary offers a "Reset local practice data" escape hatch as a last resort.
    • Stats "Last synced" and sync-error time stamps now render in 24-hour format (e.g. 20:03) rather than 12-hour (e.g. 08:03PM), consistent with the app's British-English convention.
  16. v0.10.29

    Jun 1, 2026

    Changed

    • Streak protection token toast now matches the app's design language: uses the shared card panel, neutral icon background, and standard typography tokens instead of bespoke blue accent colours.

    Fixed

    • Push notification due-count now reflects only the cards in the user's active Pokémon name locale, preventing inflated counts for users who have practised in multiple locales.
    • Alternate-form Pokémon (Alolan, Galarian, Mega variants) no longer appear in the "Mark Pokémon I already know" quiz when alternate forms are disabled (the default). Previously, tapping those cards created FSRS states for cards that would never surface in practice.
    • The practice scope nudge now only appears after 3 completed sessions, and is suppressed permanently if the scope control was already used or a non-empty scope is already saved.
    • Settings: opening the "Mark Pokémon I already know" quiz now scrolls the heading and intro to the top of the screen instead of centring them (which hid the heading above the fold and left the user mid-list).
    • Fixed push notification over-reporting new cards when both forward-evolution and reverse-evolution are enabled. The notification now correctly shows the shared evolution bucket total rather than counting it twice.
  17. v0.10.28

    Jun 1, 2026

    Added

    • Streak protection token events are now surfaced as just-in-time toasts at the moment a token is earned or spent, so you always know when your streak is being protected.
    • Token balance and a "days to your next milestone" countdown now sit alongside your streak on the Practice screen and the Stats page, so streak status shows up where you act on it. Token balance appears only when you hold at least one token (not colour-only); the milestone countdown shows when you have an active streak.
    • Locked Pokédex detail sections (Base Stats, Facts, Evolution Chain) now show an "Unlocks when you master this Pokémon" placeholder rather than appearing empty.
    • The theme/mascot picker on Settings shows a "Master your first Pokémon to unlock themes" prompt with a link to Practice instead of rendering nothing.
    • Pasture's empty state now explains its purpose as your mastered-Pokémon collection.
    • Journey page now shows a dismissible "What the rings mean" explainer near the mastery rings, explaining Locked, Learning, Mastered, and Introduced. The hint is a one-shot hint with its own flag, so existing users see it on their next visit.
    • Settings Practice tab now shows a dismissible nudge above the Quickstart quiz, pointing users at "Mark Pokémon I already know" to fast-track species they already recognise.
    • Practice screen now shows a one-shot dismissible nudge pointing at the Scope control below it, surfacing generation, type, and group filters to users who have completed first-visit onboarding. Both nudges use dedicated flags so they appear for existing users and reset with "Show onboarding again".
  18. v0.10.27

    May 31, 2026

    Changed

    • Simplified onboarding copy to plain-English reading age: removed jargon ("spaced repetition", "scheduler", "surfaces each card") from the intro, grading note, and guest storage explanation. Updated all four locales (en/ja/zh-Hans/zh-Hant).
    • All user-facing strings across practice, stats, journey, settings, Pokédex, Pasture, and nav surfaces are now routed through next-intl, making them translatable into all four supported locales (English, Japanese, Simplified Chinese, Traditional Chinese).

    Fixed

    • Higher or Lower mini-game: the "Next pair" / "Play again" button now scrolls into view automatically after a guess, so it is reachable without manual scrolling on tall mobile viewports (iPhone 17 Pro and similar).
    • Fixed mastery counts disagreeing across surfaces: "Mastery over time" chart, "Completion projection", "Records" (average days to mastery, most mastered in 7 days), Journey "Collection timeline", share card "Mastered" count, and Pokédex tile mastered styling now all apply the species-level rule, requiring both the name and reverse cards to clear the FSRS gate before a species is counted as mastered.
  19. v0.10.26

    May 30, 2026

    Changed

    • Improved Japanese and Chinese onboarding wording for clarity and age-appropriate register.
    • Progress bars on the Stats and Journey pages now emit consistent accessible meter semantics (role="meter" with aria-valuenow/aria-valuemin/aria-valuemax and an accessible label), improving the experience for screen-reader users.

    Fixed

    • Streak protection tokens now bridge a multi-day absence in a single app open. Previously, the auto-spend logic only covered a one-day gap, so a user ill for several consecutive days would lose their streak despite holding enough tokens. The fix walks back across the full run of missed days and spends one token per day in a single pass (all-or-nothing: if the gap is longer than the balance no tokens are spent and the balance is preserved).
    • Number formatting and pluralisation now respect the active locale. Counts on the Stats, Journey, Settings, and Pokédex pages were previously hardcoded to en-GB; review counts, card counts, streak labels, and similar strings are now formatted with Intl.NumberFormat (via useFormatter from next-intl) and pluralised with ICU plural rules in all supported languages, fixing grammatically incorrect output in Japanese, Simplified Chinese, and Traditional Chinese.
    • Localised the sync status strings on the Stats page ("Last synced", "N cards may be out of sync", "Sync failed", "Not synced yet", "Retrying", "Retry failed") into Japanese, Simplified Chinese, and Traditional Chinese.
  20. v0.10.25

    May 30, 2026

    Added

    • README now includes an animated GIF of the practice card flip (Pikachu front -> Reveal -> name + grade buttons), generated with npm run animations.
    • Added a server-side weekly job (reconcile_grade_log_orphans) that auto-heals sync orphans: subjects with graduated grade_log entries but no card_reviews row are given a conservative placeholder row so future client reviews can restore correct FSRS state. Ships in dry-run mode by default; live activation is a deferred manual step after an observation period.
    • Machine-translation banner dismissals now sync across devices. Dismiss the banner on one device and it stays hidden on others after the next sync pull.

    Changed

    • Push reminders now honour each user's chosen notification hour. The pg_cron job runs hourly and the per-user UTC hour gate (added in #1315) activates for all users. Users with no preference continue to receive their reminder at 08:00 UTC as before.

    Fixed

    • Structural sync errors on the card_reviews primary path (SQLSTATE 42P10 ON CONFLICT mismatch, and other schema errors) now surface in the Stats page sync banner immediately instead of being swallowed silently. The banner reads "Sync error: a schema mismatch was detected. Your progress is safe locally." and has no Retry button, since retrying a schema mismatch always fails. Previously, these errors were logged only as console.warn and were indistinguishable from transient network failures (the root cause of the 19-hour silent outage in #1344).
    • Pokémon type-filter pill labels (Bug, Fire, Water, etc.) now localise when the app language is set to Japanese, Simplified Chinese, or Traditional Chinese. Previously they stayed in English after a locale switch.
    • Fixed a silent bug where duplicate keys in a message catalogue (e.g. practice.todayNew appearing twice with different values) were invisible to the lint gate - JSON.parse kept only the last value, so the first was dead code. The lint:i18n gate now scans the raw text before parsing and fails with the full dot-path and both line numbers for any duplicate found in any locale file.
    • Pokédex generation mastery count ("X / Y mastered"), Pasture biome stats labels, PastureZone landscape link and habitat names, practice scope section legends and preset labels, Stats trainer card, records, and streak protection labels, and Journey timeline, evolution wall, close-to-mastery, and milestone share button now all localise when the app language is switched.
    • Pasture page now honours the active Pokémon name locale when computing mastered species. Switching to Japanese or Chinese in Settings correctly shows only cards mastered in that locale, instead of always showing the English count.
    • Mastered Pokémon now appear in their correct biomes (Grasslands, Forest, Cave, and so on) instead of all falling into Wildlands. Previously, QA-seeded and freshly-loaded cards were missing habitat data, so every species defaulted to the "unknown" bucket and biome stats showed zero mastered.
·What's new·Privacy·Terms·More from Frazzled Productions·v0.11.8

Unofficial fan project, not affiliated with or endorsed by Nintendo, Game Freak, or The Pokémon Company. Pokémon and all related names, sprites, and cries are the property of their respective owners. Sprite and species data sourced from PokéAPI.

Frazzled Productions Ltd, a company registered in England and Wales (company number 17258540). Registered office: 71-75 Shelton Street, Covent Garden, London, WC2H 9JQ.

  • Practice
  • Stats
  • Journey
  • Pokédex
  • Settings
poke-memory
  • Practice
  • Stats
  • Journey
  • Pokédex
  • Settings
  • Practice
  • Stats
  • Journey
  • Pokédex
  • Settings