Chilled color scheme as swappable tokens, Fredoka wordmark with a
configurable tagline, genre categories, search and random hotkeys.
The homepage offers a Game of the Day, a Time Machine with a date
picker, recently played games and Flashpoint playlist shelves.
Mature games are hidden unless opted in from the user menu, stored
in the browser and the account. Browse lists default to a seeded
shuffle and accept release date ranges.
Saves games keep in the browser now sync with the signed-in player's
account: Ruffle SharedObjects and HTML5 localStorage, IndexedDB databases
(exported and imported whole, typed arrays and blobs included), and streamed
games' save files. Games share the app's origin, so storage that changes
while a game runs is attributed to it. Before a game starts, the account's
save is loaded unless this browser has a newer one; changes upload as they
happen; and a Saves dialog in the player restores any of the last 10, keeping
the save it replaces as a backup.
The index was scraped from the Flashpoint Datahub wiki on every request.
That page now sits behind a Cloudflare managed challenge that no plain
HTTP client can pass, so the endpoint answered 500 for every caller.
Ship the list instead, extracted from a saved copy of the page into
data/community-playlists.json: 104 playlists across 9 categories. Only
entries whose download URL is on the allowlist are kept, so everything
the modal offers can also be imported. That drops the Old Default
Playlists section, hosted off the allowlist and still in the
pre-Flashpoint 10 format.
The modal now fetches only while open rather than on every render of the
playlists page, and shows when the snapshot was captured. Drops cheerio,
whose only consumer was the scrape.
On a network share the database copy and cache pre-warm run for minutes,
and the listener only opened after all of it, so anyone who loaded the
page during that window got a connection error.
Open the port immediately after registering the static frontend, and
hold every route that needs the database behind a gate that answers 503
with a machine-readable marker and the current startup phase. The SPA
shell needs nothing the gate blocks, so the frontend renders a "server
is starting" screen on the login page's own background, polls /health,
and reloads once the server reports ready.
Move the database copy out of the entrypoint: it does the same freshness
check the application does, and doing it before node starts kept the port
closed for the longest part of startup. Distinguish a dead server from a
slow one by requiring the backend's own marker, since a proxy in front of
a stopped backend still answers.
Switch games search from GET to POST with JSON body to avoid URL
length limits when combining multiple filters. Filter options now
return context-aware results based on active selections.
Key changes:
- Backend: POST /api/games with array-based filter params
- Backend: Filter options cached per page combination + 30s TTL
for dynamic filter states
- Backend: Fix semicolon-delimited field matching (developers,
publishers, playModes, languages) using INSTR
- Frontend: Add URL compression (lz-string) for shareable filter URLs
- Frontend: Multi-select support in filter dropdowns and chips
- Frontend: Context-aware filter options hook
Implement activity analytics dashboard with real-time stats, charts, and
user leaderboard. Add automated Ruffle update job for Flash emulator
maintenance. Standardize datetime formatting across frontend/backend with
ISO 8601 and user preferences. Enhance security with comprehensive input
validation, rate limiting, and CSRF protection. Improve accessibility
with ARIA labels, keyboard navigation, and screen reader support. Fix
multiple security vulnerabilities including XSS, SQL injection risks, and
session management issues.