Skip to main content

Reference

Design system

Every token, component, and motion utility that makes up the VGDB visual layer. The hero switcher below re-themes the entire page through one of seven console-era looks — try it.

Click any era to re-theme the entire page below.

Foundations

Colours

Seven base tokens defined in src/styles/tokens.css and overridden per era in src/styles/era-themes.css. Switch eras using the hero control above — every swatch below uses CSS variables, so they re-theme live.

Base palette

bg-primary
#111113
--color-bg-primary
bg-bg-primary
bg-card
#1c1c1f
--color-bg-card
bg-bg-card
text-primary
#e8e8ec
--color-text-primary
text-text-primary
text-secondary
rgba(255,255,255,0.72)
--color-text-secondary
text-text-secondary
accent
#f59e0b
--color-accent
bg-accent
accent-light
rgba(245,158,11,0.15)
--color-accent-light
bg-accent-light
border
rgba(255,255,255,0.1)
--color-border
border-border

Era accent palette

Pre-8-bit
#b45309
8-bit
#a16207
16-bit
#7c3aed
32-bit
#c2410c
128-bit
#2563eb
Modern
#818cf8
Handheld
#059669

Note: the admin CMS overrides the palette to a light theme via the[data-admin]selector in globals.css. It is not interactively previewable here.

Foundations

Typography

Three primary fonts loaded via next/font/google and bound to CSS variables, plus a fourth pixel font reserved for retro mode.

The video game database

h1 · Playfair Display · 48px / 600

Eight generations of consoles

h2 · Playfair Display · 30px / 600

Pixel art and polygons

h3 · Playfair Display · 20px / 600

Section heading

h4 · Playfair Display · 18px / 600

The quick brown fox jumps over the lazy dog.

body · Inter · 16px / 400

Caption or supporting text

small · Inter · 12px / 400

const cpu = 'Motorola 68000';

mono · JetBrains Mono · 14px / 400

Font stack

The quick brown fox

Playfair Display

--font-playfair

All h1–h4 headings via globals.css

The quick brown fox

Inter

--font-inter

Body copy, default font on <body>

The quick brown fox

JetBrains Mono

--font-mono

Spec values, code blocks, mono-font chips

The quick brown fox

Press Start 2P

--font-pixel

Retro mode only (Konami code)

Foundations

Spacing & radii

No custom spacing scale yet — the project uses Tailwind defaults. The most-used values, observed across the codebase, are listed below.

Gap: no custom spacing tokens

src/styles/tokens.css defines colour, font, and shadow tokens — but no --space-* scale. If a tighter, project-specific scale becomes desirable (e.g., for the platform-detail tab grids), define it here and migrate the most-used values to named tokens.

Suggested fix:Add a --space-{xs,sm,md,lg,xl} scale to tokens.css under @theme so the values are exposed as Tailwind utilities.

Most-used spacing

ClassPixelsWhere
p-312pxTight card padding (e.g., game card footer)
p-416pxStandard card padding (e.g., spec card, platform card footer)
p-520pxRoomy card padding (e.g., gap card body)
px-6 py-1224px / 48pxPage container padding
gap-312pxTight grid gap
gap-624pxStandard grid gap
mt-832pxSection content top spacing
mt-1664pxMajor section separation

Border radii

ClassPixelsWhere
rounded-md6pxCode blocks
rounded-lg8pxAll cards (platform, game, spec, gap)
rounded-full9999pxChips, badges, circular avatars

Foundations

Elevation & borders

Two surface-treatment tokens, both defined in tokens.css. Hover lift comes from the .hover-lift animation class — see Motion.

shadow-card
0 1px 3px rgba(0, 0, 0, 0.4)
--shadow-card
shadow-card
border
rgba(255, 255, 255, 0.1)
--color-border
border-border

Components

Platform / box-art cards

The hero card pattern for every platform listing. 16:10 image area with a metadata footer; lifts on hover.

<PlatformCard />

Used in /platforms, /generations, /consoles, /timeline.

Stub data — not a real platform.

bg-bg-cardborder-borderrounded-lgshadow-cardhover-lift
Show JSX
import { PlatformCard } from "@/components/platform/platform-card";

<PlatformCard
  platform={{
    name: "Demo Console 3000",
    slug: "demo-console-3000",
    manufacturer: "Stub Industries",
    generation: "Sixth",
    release_date: "2003-09-15",
    image_url: null,
    category: "console",
  }}
/>

Components

Game cover cards

The 3:4 cover-art tile used across the games catalogue and game lists.

<GameCard />

Used in /games, top-rated carousels, list previews.

Stub data — not a real game.

bg-surface*border-borderrounded-lggrouphover:border-accent
Show JSX
import { GameCard } from "@/components/game/game-card";

<GameCard
  slug="untitled-demo-game"
  title="Untitled Demo Game"
  coverImageUrl={null}
  developer="Stub Studios"
  firstReleaseDate="2024-06-01"
  summary="An imaginary stub game used to render the design system docs."
/>

Drift: undefined bg-surface / bg-surface-alt classes

GameCard (and four other files —games-list.tsx,game-children-section.tsx,games/page.tsx,top-rated-carousel.tsx) referencebg-surface andbg-surface-alt, but neither class is defined intokens.css, the era themes, or any@themeblock. Tailwind silently emits no rule, so the cards inherit their parent's background instead. Three other files also reference an undefined--color-surface-raised with an inline fallback.

Suggested fix:Add --color-surface and --color-surface-alt tokens to tokens.css (or rename the call sites to use bg-bg-card / bg-bg-primary), and define --color-surface-raised explicitly to remove the inline fallback.

Components

Spec cards

Two-line stat tiles: uppercase tracking label, monospace value. Used across platform detail pages.

<SpecCard />

CPU
MIPS R3000A · 33.87 MHz
RAM
2 MB
Released
1994-12-03
Generation
Fifth
bg-bg-cardborder-borderrounded-lgp-4font-mono
Show JSX
import { SpecCard } from "@/components/ui/spec-card";

<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
  <SpecCard label="CPU" value="MIPS R3000A · 33.87 MHz" />
  <SpecCard label="RAM" value="2 MB" />
  <SpecCard label="Released" value="1994-12-03" />
  <SpecCard label="Generation" value="Fifth" />
</div>

Components

Chips & badges

Pill-shaped generation labels with active and inactive states. Hover-bounce on interaction.

<GenerationChip /> — all generations

FirstSecondThirdFourthFifthSixthSeventhEighthNinth
rounded-fullpx-2.5py-1text-[10px]hover-bounce
Show JSX
import { GenerationChip } from "@/components/ui/generation-chip";

<GenerationChip generation="Sixth" />
<GenerationChip generation="Sixth" active />

<GenerationChip active />

Active state: amber background, accent text.

SixthSixth
Show JSX
<GenerationChip generation="Sixth" active />

Components

Page headers

The canonical eyebrow + h1 + subtitle pattern used by every top-level public page.

<PageHeader />

Reference

Section heading

A short paragraph that sets context for the page.

text-accentfont-playfairtext-4xluppercase tracking-[2px]
Show JSX
import { PageHeader } from "@/components/ui/page-header";

<PageHeader
  eyebrow="Reference"
  title="Section heading"
  subtitle="A short paragraph that sets context for the page."
/>

Components

Empty states

Centred icon + message + submessage placeholder for tab panels and lists with no content.

<EmptyTabState />

No reviews yet

Be the first to share your thoughts.

flexitems-centerjustify-centerpy-16opacity-30
Show JSX
import { EmptyTabState } from "@/components/platform/empty-tab-state";

<EmptyTabState
  icon={<span aria-hidden="true">📦</span>}
  message="No reviews yet"
  submessage="Be the first to share your thoughts."
/>

Components

Loaders

Era-aware pixel sprite loader. The sprite and accent colour change based on the EraKey passed in — try the era switcher above and watch the sprite transform.

<PixelLoader />

Currently rendering the "modern" sprite (matches the hero switcher).

Show JSX
import { PixelLoader } from "@/components/ui/pixel-loader";
import type { EraKey } from "@/lib/era-theme";

<PixelLoader era="modern" />

Components

Buttons

Buttons are currently ad-hoc Tailwind class chains — no canonical primitive yet. The most-observed patterns are documented below.

Gap: no canonical Button primitive

The codebase has no src/components/ui/button.tsx. Buttons are assembled inline from Tailwind utilities everywhere they appear, which means class chains drift, focus styles vary, and disabled states are inconsistent. Three patterns recur often enough to standardise.

Suggested fix:Create src/components/ui/button.tsx with variant="primary" | "secondary" | "ghost", lift the patterns below, and codemod the most-repeated chains.

Primary (observed pattern)

High-emphasis CTAs — accent background, bg-primary text.

Show JSX
<button
  type="button"
  className="bg-accent text-bg-primary text-sm font-medium px-4 py-2 rounded-md hover:opacity-90 transition-opacity"
>
  Primary action
</button>

Secondary (observed pattern)

Medium-emphasis — bordered, accent on hover.

Show JSX
<button
  type="button"
  className="border border-border text-text-primary text-sm font-medium px-4 py-2 rounded-md hover:border-accent hover:text-accent transition-colors"
>
  Secondary action
</button>

Ghost (observed pattern)

Low-emphasis — no border, subtle hover background.

Show JSX
<button
  type="button"
  className="text-text-secondary text-sm px-3 py-2 rounded-md hover:text-accent hover:bg-white/[0.04] transition-colors"
>
  Ghost
</button>

Components

Icons

Icons live as raw SVG files under src/assets/icons/, organised by category. There is no central <Icon /> component — each icon is imported individually at the use site.

Gap: no central <Icon /> component

Icons are imported per-file as static asset URLs (e.g.,import logo from "@/assets/icons/game_state/ico_state_playing_active.svg"), which works but provides no autocomplete, no centralised sizing, no tree-shaking visibility, and no consistentaria-label story.

Suggested fix:Create src/components/ui/icon.tsx with a typed name prop backed by a single import map. Use SVGR (next/svgr) so icons render as inline SVG and inherit currentColor.

Folder structure under src/assets/icons/:

add/arrow/badges/collections/common/community/editor/filter/followers_game/followers_user/game/game_state/kudos/leaderboard/leaderboard-points/login/media/menu/notification/platforms/play/report/review/screenshot/services/share/social/sso/video/

Note: rendering every icon inline would require static imports for hundreds of files and inflate the bundle. The folder list above is the canonical reference; browse the files directly in the repository.

Motion

Animations & motion

Two custom easings and a small set of hover utilities and keyframes. Defined in src/styles/animations.css and respected by the global prefers-reduced-motion media query.

Hover utilities

Hover me

.hover-lift
Cards lift -8px and scale 1.03 on hover

Hover me

.hover-bounce
Chips scale to 1.05 on hover

Hover me

.hover-glow
Scale 1.1 with accent-light box shadow

Easing functions

--ease-spring

cubic-bezier(0.34, 1.56, 0.64, 1)

Snappy overshoot — used by hover-lift, hover-bounce, hover-glow.

--ease-spring-gentle

cubic-bezier(0.22, 1.2, 0.36, 1)

Softer overshoot — used by scroll-reveal entrances.

Keyframes (consumed via inline animation styles)

NameUsed by
@keyframes bounce-inScroll-reveal entrance: scale + rotate
@keyframes fade-upScroll-reveal entrance: translateY + opacity
@keyframes bar-growSpec bar width animation in compare arena
@keyframes glow-pulseWinner glow on compare arena
@keyframes pixel-assemblePixel loader sprite assembly
@keyframes pixel-pulsePixel loader gentle scale
@keyframes nav-dropdown-inNav dropdown menu entrance

All hover utilities and entrance animations are disabled inside@media (prefers-reduced-motion: reduce)— see the bottom of src/styles/animations.css.

Theming

Era themes

Seven console-era themes defined in src/styles/era-themes.css. Applied via a data-era attribute on any wrapper element. Each row below is forced into its own era — use the hero switcher to re-theme the entire page above.

1st–2nd

Pre-8-bit

data-era="pre8bit"
#b45309

Warm amber, off-white card, CRT scanline overlay.

3rd

8-bit

data-era="8bit"
#a16207

Deep amber, off-white card, similar CRT texture.

4th

16-bit

data-era="16bit"
#7c3aed

Jewel purple accent, lavender card, saturated palette.

5th

32-bit

data-era="32bit"
#c2410c

Warm orange, warm grey card, transitional warmth.

6th–7th

128-bit

data-era="128bit"
#2563eb

Cool blue accent, brushed-metal gradient card.

8th–9th

Modern

data-era="modern"
#818cf8

Indigo, dark glassmorphic card with backdrop blur.

Portable

Handheld

data-era="handheld"
#059669

Sage green, light card, compact max-width.

Easter egg

Retro mode

A hidden Game Boy palette + Press Start 2P type theme. Activated on the live site by entering the Konami code (↑ ↑ ↓ ↓ ← → ← → B A). The hero retro toggle above flips it for the whole page.

Scoped preview (always-on, regardless of hero toggle)

Demo Console

ALL YOUR BASE

CPU
6502
RAM
2 KB

Or toggle retro mode on the whole page using the toggle in the hero ↑.

Appendix

References & next steps

Where to look in the codebase, and what's still missing.

Source files

  • src/styles/tokens.cssBase design tokens (colours, fonts, shadow)
  • src/styles/era-themes.cssPer-era CSS variable overrides (7 eras)
  • src/styles/animations.cssHover utilities, easings, keyframes
  • src/styles/retro-mode.cssKonami easter egg styles
  • src/lib/era-theme.tsEraKey type and getEraKey() helper
  • docs/frontend/styling-and-theming.mdLong-form styling reference (markdown)

Want to add to the design system? Pick a gap above, send a PR that fills it, and update the corresponding section on this page.