Skip to main content

Reference

Design system

Every token, component, and motion utility that makes up the VGDB visual layer.

Toggle the Konami easter-egg palette across the page below.

Foundations

Colours

Base tokens defined in src/styles/themes/default.css. Every swatch below uses CSS variables, so the admin CMS theme override re-themes them in place.

Base palette

bg-primary
#001113
--color-bg-primary
bg-bg-primary
bg-surface
#002126
--color-bg-surface
bg-bg-surface
bg-card
#05191B
--color-bg-card
bg-bg-card
text-primary
#BFECF2
--color-text-primary
text-text-primary
text-secondary
rgba(191,236,242,0.72)
--color-text-secondary
text-text-secondary
accent
#00B4CC
--color-accent
bg-accent
accent-hover
#7FD9E0
--color-accent-hover
bg-accent-hover
accent-light
rgba(0,180,204,0.15)
--color-accent-light
bg-accent-light
border
rgba(255,255,255,0.1)
--color-border
border-border

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 · Objektiv Mk2 · 48px / 700 · -5% tracking

Eight generations of consoles

h2 · Objektiv Mk2 · 30px / 700 · -5% tracking

Pixel art and polygons

h3 · Objektiv Mk2 · 20px / 700 · -5% tracking

Section heading

h4 · Objektiv Mk2 · 18px / 700 · -5% tracking

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

Objektiv Mk2

--font-playfair

All h1–h4 headings via globals.css (loaded via Adobe Fonts)

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

Review cards

Portrait card for grids; landscape card for featured slots. Both carry the reviewer's rating and the game's community aggregate, and open a lightweight reading modal when the body is truncated.

<ReviewCardPortrait />

?
community9.6reviewer9.6
DOOM

Rip and tear, until it is done

Let me take you back to 1993 for a moment. I'm sat in front of a beige box of a PC, probably running a 486 if I was lucky, and a little game called DOOM has just landed on my hard drive. The sound of imps growling in a dark corridor will stay with me forever.

bg-bg-cardborder-borderrounded-xl
Show JSX
<ReviewCardPortrait review={review} />

<ReviewCardLandscape />

?
community9.0
reviewer9.4

Buggy, but brilliant game

Cyberpunk 2077 · 1 min read

Disclaimer: this will be a living review for the next couple of months as I progress through side-missions, multiple endings and as fixes come out. It's hard to think of where to begin when writing a review for Cyberpunk, the game has been in the making for over 7 years and has seen multiple delays in recent months as CD Projekt Red improved the experience. Before I get into the meat of things, a word on performance.

bg-bg-cardborder-borderrounded-xl
Show JSX
<ReviewCardLandscape review={review} />

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

An accent-coloured 8-bit pixel sprite used as a Suspense fallback (currently on the /compare page).

<PixelLoader />

Pixel sprite tinted with the page's accent variable, so the Konami retro toggle re-themes it for free.

Show JSX
import { PixelLoader } from "@/components/ui/pixel-loader";

<PixelLoader />

Components

Buttons

The canonical Button primitive lives at src/components/ui/button.tsx. Three variants, three sizes, a 4px corner radius (rounded-sm / --radius-sm), and a keyboard-only focus ring. Primary ships uppercase bold with white text on the accent; secondary and ghost stay title-case. Caller className is merged with tailwind-merge so overrides (e.g. font-extrabold on a marketing CTA) win deterministically. Pass href to render a Next.js Link; omit it to render a <button type='button'>.

Primary

High-emphasis CTA: accent background, white uppercase-bold text, 4px radius.

Show JSX
<Button onClick={handleSave}>Primary action</Button>

Secondary

Medium-emphasis: bordered, accent on hover.

Show JSX
<Button variant="secondary" onClick={handleCancel}>
  Secondary action
</Button>

Ghost

Low-emphasis: no border, subtle hover background.

Show JSX
<Button variant="ghost" onClick={handleDismiss}>
  Ghost
</Button>

Sizes

sm for inline / toolbar use, md is the default form button, lg for hero and landing CTAs. Variant and size compose independently.

Show JSX
<Button size="sm">Small</Button>
<Button size="md">Medium (default)</Button>
<Button size="lg">Large</Button>

As a link

Pass href to render a next/link with identical styling.

Show JSX
<Button href="/games">Browse games</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.

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.css· Base design tokens (colours, fonts, shadow)
  • src/styles/animations.css· Hover utilities, easings, keyframes
  • src/styles/retro-mode.css· Konami easter egg styles
  • docs/04_frontend/styling-and-theming.md· Long-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.