DEV Community

visiohex
visiohex

Posted on • Originally published at ballscratchsimulator.wiki

How I Built a Source-Constrained Game Guide with Astro and Cloudflare Pages

I recently built Ball Scratch Simulator Guide, an independent information site for an upcoming Steam game from 10ft Games.

The technical work was straightforward. The difficult part was deciding what the site should say when the game has not been released and much of the information people search for does not exist yet.

Instead of filling those gaps with guesses, I built the site around a simple editorial constraint:

Every factual claim must be traceable to an official public source. Anything that has not been announced must be described as unknown.

That decision shaped the content model, page structure, SEO setup, and deployment architecture.

The problem with covering an unreleased game

Searches for an upcoming game often appear before enough information exists to support a conventional guide.

Players may already be looking for:

  • The release date
  • The price
  • A playable demo
  • Controls
  • VR support
  • System requirements
  • Locations
  • Collectibles
  • Achievements
  • Codes

For Ball Scratch Simulator, the official Steam listing currently confirms several useful details:

  • It is a Windows game developed by 10ft Games.
  • Steam lists an August 2026 release window.
  • Desktop play is supported.
  • Seated PC VR is optional through OpenXR and SteamVR.
  • The game includes six public locations.
  • Cards, Chibis, high scores, and leaderboards are part of the progression system.

Other details remain unannounced, including the exact release day, launch price, demo availability, location names, and complete controls.

The site answers those questions directly. “Not announced” is more useful than a fabricated answer hidden inside a long article.

Why I launched with one indexable page

A common SEO approach is to create a page for every possible query:

/release-date/
/codes/
/controls/
/locations/
/collectibles/
/vr/
/system-requirements/
Enter fullscreen mode Exit fullscreen mode

That structure would have created several thin pages containing the same limited facts. Some pages, such as codes or walkthroughs, would have no factual basis at all.

I chose one indexable homepage that covers the current search intent in depth. It includes release information, gameplay, progression, VR support, PC requirements, languages, content warnings, and frequently asked questions.

The site also has About, Privacy, Terms, Editorial Policy, and Disclaimer pages. Those pages are useful to visitors, but they are marked noindex,follow and excluded from the sitemap.

The sitemap therefore contains one URL:

<url>
  <loc>https://ballscratchsimulator.wiki/</loc>
</url>
Enter fullscreen mode Exit fullscreen mode

More pages can be added after the game launches, when there is enough verified information for each page to serve a distinct purpose.

A small Astro architecture

The site uses Astro with static output. There is no client-side application framework, CMS, database, or runtime API.

The core configuration is deliberately small:

import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap";

const site = "https://ballscratchsimulator.wiki";

export default defineConfig({
  site,
  output: "static",
  trailingSlash: "always",
  integrations: [
    sitemap({
      filter: (url) => url === `${site}/`,
    }),
  ],
});
Enter fullscreen mode Exit fullscreen mode

Static output makes the site easy to inspect. The main content, navigation, metadata, and links are present in the generated HTML without requiring JavaScript.

Keeping game facts in one typed object

Important identity data lives in a typed object instead of being repeated across templates:

export const game: GameIdentity = {
  name: "Ball Scratch Simulator",
  steamAppId: 4951590,
  developer: "10ft Games",
  publisher: "10ft Games",
  platform: "Windows",
  releaseStatus: "Upcoming",
  releaseWindow: "August 2026",
  verifiedAt: "August 7, 2026",
  vr: {
    required: false,
    mode: "Seated",
    runtimes: ["OpenXR", "SteamVR"],
  },
};
Enter fullscreen mode Exit fullscreen mode

The page copy, metadata, calls to action, and VideoGame structured data read from this object.

This reduces the chance of publishing conflicting release windows or platform information in different parts of the site. When an official detail changes, there is one primary place to update it.

Canonical URLs and structured data

Every page receives a self-referencing canonical URL:

const canonical = new URL(Astro.url.pathname, SITE_ORIGIN).href;
Enter fullscreen mode Exit fullscreen mode

The shared layout also creates Open Graph metadata, Twitter card metadata, WebSite structured data, and page-specific structured data.

The homepage includes a VideoGame JSON-LD object using the same identity data shown to visitors. I avoided adding review scores, prices, release dates, or offers that are not supported by the official sources.

Structured data should describe the visible page. It should not become a second, more optimistic version of the content.

Treating official information carefully

Source-constrained publishing still requires judgment.

The Steam system requirements, for example, currently list GPU recommendations in an order that may look surprising. It would be easy to “correct” them based on an assumption.

The site displays the values as Steam currently lists them and adds a short note explaining where they came from.

That preserves the source instead of silently rewriting it.

The same rule applies to the six confirmed locations. The site can explain that six public settings are planned, but it does not invent names for those locations.

Fixing promotional-image cropping

The first version placed official promotional art inside fixed-ratio containers using object-fit: cover.

That worked visually for generic photographs, but it cropped important parts of the game artwork. Titles and characters near the edges disappeared on wider screens.

The fix was native image sizing:

.hero-art {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
}
Enter fullscreen mode Exit fullscreen mode

Preserving the image’s intrinsic aspect ratio was better than trying to find a universal crop position.

For artwork containing text, logos, or characters, cover often solves the container’s problem by creating an image-content problem.

Deploying to Cloudflare Pages

The generated site is deployed to Cloudflare Pages through Wrangler:

npm run build
npx wrangler pages deploy dist
Enter fullscreen mode Exit fullscreen mode

The custom domain is:

https://ballscratchsimulator.wiki/

The www hostname redirects to the root domain with a permanent redirect. Cloudflare also serves the site’s security headers, including a Content Security Policy.

Because the site includes Google Analytics and Plausible, their external script origins must be explicitly allowed by the CSP. Adding analytics without updating the policy would cause the browser to block the scripts.

Verification before deployment

The project uses a small verification chain:

{
  "scripts": {
    "check": "astro check",
    "test": "node --test",
    "build": "astro build",
    "verify": "npm run check && npm test && npm run build"
  }
}
Enter fullscreen mode Exit fullscreen mode

The tests check practical publishing requirements:

  • Every planned route exists.
  • Each page has one H1.
  • The homepage has a valid canonical URL.
  • Structured data matches visible game information.
  • Trust and legal pages use noindex.
  • The sitemap contains only the homepage.
  • Internal links resolve.
  • Core answers remain available without JavaScript.
  • Draft instructions and placeholder text do not leak into public pages.
  • External scripts are limited to known analytics providers.

I also check the generated robots.txt, sitemap.xml, and llms.txt instead of assuming the build integration produced the expected files.

What I learned

The strongest content decision was allowing “unknown” to be a complete answer.

If the price has not been announced, the page says so. If no demo is available, it does not offer a fake download button. If location names are unavailable, it does not turn speculation into a list.

Page count should also follow available evidence. A single useful page is a better starting point than ten pages repeating the same paragraph.

Static generation made these constraints easier to enforce. The final HTML can be tested directly, and the deployed output has fewer moving parts.

The site will expand when the game is released and official information supports dedicated guides. Until then, its job is narrower: collect the confirmed details, answer current questions, and make the boundaries clear.

You can see the finished site at ballscratchsimulator.wiki.

I would be interested in feedback on the source-constrained editorial model, the Astro implementation, or the decision to keep the initial sitemap to one page.

Top comments (0)