{
  "id": 12173640,
  "title": "600+ game pages from one TypeScript file: lessons from building a static games site with Astro",
  "url": "https://urgent.news/2026/10/05/600-game-pages-from-one-typescript-file-lessons-from-building-a",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-05T15:01:52.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/thanhnt9x/600-game-pages-from-one-typescript-file-lessons-from-building-a-static-games-site-with-astro-2e4o"
  },
  "original_language": "en",
  "account": "A single TypeScript file hosts over 600 game pages for a static Astro site: lessons learned\n\nI operate MathLogic Games, a free collection of browser-based math, logic and puzzle games. The games themselves come from HTML5 embeds distributed through two platforms. My role chiefly involves creating one page per game with descriptions, gameplay instructions, FAQs, category pages, topic hubs and a small blog. The entire site is a static Astro site hosted on Cloudflare, with no backend.\n\nKey lessons for similar catalog sites or directories, where most pages are derived from data:\n\n1. Centralize all game data in one file, with each game represented as an object. Key fields include a unique identifier (either wgId or gamepix), title, categories, description, gameplay instructions, FAQ, thumbnail image, last updated timestamp, newness flag, tags and more. Category pages, search index, hubs, and the sitemap all derive their content from this single array. Adding new games is a simple edit, automatically propagating changes throughout the site.\n\n2. Enforce data integrity during the build process. The array of game objects is self-checking when imported: each game must have exactly one unique identifier (either wgId or gamepix), and both identifiers must be unique across the entire catalog. Duplicate IDs or slugs throw errors. The sitemap's last modified date is pulled directly from the data rather than the build timestamp. This ensures every URL reflects a fresh update, preventing misleading signals about site changes.\n\n3. Add new features as optional data fields initially, then enable them selectively for specific pages. This approach prevents unintended site-wide changes when adding functionality. For example, a FAQ JSON-LD schema can be added to a hub page with a flag. A fullscreen button can be toggled for a landscape-only game using inline styles and scripts. Embedding a second game platform required making the wgId field optional and encapsulating the iframe URL logic in a function. After implementing the change, building the current main site in a separate worktree and comparing the output folders revealed that all 668 existing pages remained unchanged, with only the About page, Privacy page, llms.txt, and sitemap modified.\n\n4. Accurately measure user engagement time when games are embedded in cross-origin iframes. Google Analytics 4 (GA4) tracks engagement while the page retains focus. However, when users click into an embedded game, focus shifts to the cross-origin iframe, causing GA4 to stop measuring the session. To address this, a simple polling script checks if the active document element matches the iframe every second, calculating engagement time more accurately. This ensures playtime data reflects the actual user experience rather than being artificially truncated.",
  "summary": "I run MathLogic Games , a free site of math, logic and puzzle games that play in the browser. The games themselves are licensed HTML5 embeds from two distribution platforms. My job is the part around them: a page per game with a real description, how-to-play steps and an FAQ, plus category pages, topic hubs and a small blog. It is a static Astro site on Cloudflare. It has a little over 600 game…",
  "key_points": [
    "Centralize game data in one TypeScript file with unique identifiers",
    "Enforce data integrity during build process to ensure URL freshness",
    "Add new features as optional data fields to prevent site-wide changes"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}