DEV Community

Chen Tao
Chen Tao

Posted on

Building a Roblox Game Guide with Next.js 16, Tailwind CSS v4, and a Single-Source-of-Truth Routing System

I recently built Catch a Brainrot Guide, a fan-made resource hub for a Roblox creature-collection RPG. Here's a walkthrough of the tech stack and some architectural decisions that made the project interesting.

Stack

  • Next.js 16 (App Router, static export)
  • React 19
  • Tailwind CSS v4 — the new @theme directive means no more tailwind.config.ts
  • TypeScript 5.7
  • Cloudflare Pages for deployment

Single Source of Truth for Routes

All 20+ page routes live in one file: src/lib/routes.ts. Every route is typed with its path, label, sitemap priority, changefreq, and nav/footer placement.

export const ROUTES: RouteDef[] = [
  { path: '/tier-list', label: 'Tier List', priority: 0.9, changefreq: 'daily', nav: 'brainrots', footer: 'quick' },
  { path: '/guide/how-to-play', label: 'How to Play', priority: 0.8, changefreq: 'weekly', nav: 'guides' },
  // ... 20+ pages
];
Enter fullscreen mode Exit fullscreen mode

The Navbar, Footer, and sitemap.ts all import from this single array. Adding a new page means one entry in routes.ts — everything else syncs automatically.

// sitemap.ts — auto-syncs from ROUTES
export default function sitemap(): MetadataRoute.Sitemap {
  return ROUTES.map((route) => ({
    url: route.path === '/' ? GAME.domain : `${GAME.domain}${route.path}`,
    lastModified: new Date(),
    changeFrequency: route.changefreq,
    priority: route.priority,
  }));
}
Enter fullscreen mode Exit fullscreen mode

Tailwind CSS v4: Bye-Bye tailwind.config.ts

Tailwind v4 moves configuration into native CSS via @theme:

@import "tailwindcss";

@theme {
  --color-background: #0a0a0f;
  --color-foreground: #f1f5f9;
  --color-primary: #8b5cf6;
  --color-card: #14141f;
  --color-glass-border: rgba(255, 255, 255, 0.08);
}
Enter fullscreen mode Exit fullscreen mode

SEO Architecture (Three Layers)

1. Global Metadata (layout.tsx)

Title templates, Open Graph, Twitter cards, robots directives, and canonical URL are set once in the root layout.

export const metadata: Metadata = {
  title: { default: `${GAME.name} - Roblox Game Guide, Codes & Wiki`, template: `%s | ${GAME.name}` },
  robots: { index: true, follow: true },
  alternates: { canonical: GAME.domain },
};
Enter fullscreen mode Exit fullscreen mode

2. Page-Level JSON-LD Schemas

Every page injects context-specific structured data — BreadcrumbList, FAQPage, or Article schemas.

const breadcrumbSchema = generateBreadcrumbSchema([
  { name: 'Home', url: '/' },
  { name: 'Tier List', url: '/tier-list' },
]);
Enter fullscreen mode Exit fullscreen mode

3. IndexNow Auto-Submission

After each build, a script parses sitemap.xml and pushes all URLs to the IndexNow API (accepted by Bing, Yandex, Naver). No registration required.

const payload = {
  host: 'catchabrainrot.site',
  key: 'your-key',
  urlList: allUrls,
};
await fetch('https://api.indexnow.org/indexnow', { method: 'POST', body: JSON.stringify(payload) });
Enter fullscreen mode Exit fullscreen mode

YouTube Embed: Facade Pattern

Instead of loading a 1MB+ YouTube iframe on page load, I use a facade — a static thumbnail with a play button that swaps to the real iframe only on click.

export default function YouTubeEmbed({ videoId, title }: Props) {
  const [loaded, setLoaded] = useState(false);
  const thumbnail = `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`;
  return loaded ? (
    <iframe src={`https://www.youtube.com/embed/${videoId}?autoplay=1`} />
  ) : (
    <button onClick={() => setLoaded(true)}>
      <img src={thumbnail} loading="lazy" fetchPriority="low" />
      <PlayIcon />
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

The "Honest Codes" Pattern

A common SEO play in Roblox guide sites is to fabricate fake codes to trap search traffic. I went the opposite direction: the /codes page transparently states the game has no code redemption system yet, and redirects users toward the official Discord for updates. It ranks well and earns trust — a better long-term play than fake codes.

AI-Assisted Development

The repo includes an AGENTS.md that defines an SEO workflow: when a keyword research report lands, the agent analyzes priorities, checks existing coverage, generates new pages, updates sitemap/nav, runs an SEO audit, builds, and logs results. This turns keyword research into a semi-automated pipeline from idea to deployment.

Deployment

Static export to Cloudflare Pages, with IndexNow submission running post-build.

Takeaways

  • Single source of truth for routes eliminates maintenance drift
  • Structured SEO from day one beats retrofitting later
  • Honesty as a content strategy builds trust and ranks better than fabricated content

The full site is live at catchabrainrot.site. Questions or thoughts? Drop a comment below.

Top comments (0)