Typography
8-BitQuest is a two-face type system, and the split is the whole retro identity: Press Start 2P is the pixel display face, and Space Mono is the body face. Both are self-hosted through Fontsource, so there is no third-party font request and no layout shift from a late-loading webfont.
The two faces
The faces are wired to Tailwind font tokens in src/styles/tailwind-theme.css:
@theme {
--font-display: "Press Start 2P", "Space Mono", ui-monospace, monospace;
--font-sans: "Space Mono", ui-monospace, "Menlo", "Consolas", monospace;
--font-mono: "Space Mono", ui-monospace, "Menlo", "Consolas", monospace;
}
--font-display→ Press Start 2P, the pixel heading face. It drives the.h1–.h3classes, the nav, and the pixel buttons via thefont-displayutility. It has a single weight (400) — there is no bold Press Start 2P, which is why the heading classes never usefont-mediumorfont-bold.--font-sansand--font-mono→ Space Mono, the body face and the site default (set on<html>). Body and “code” are the same mono face here, which is deliberate: it is what makes running text feel like a terminal. Space Mono ships 400 and 700.
The @font-face blocks live in src/styles/fonts.css, imported at the top of global.css. The two above-the-fold faces — Press Start 2P 400 and Space Mono 400 — are also <link rel="preload">ed in BaseHead for a faster first paint.
The heading classes
Headings are three utility classes in global.css, all on the pixel face, uppercase, and stepped down on mobile so the wide pixel glyphs don’t overflow a narrow screen:
.h1 { @apply font-display text-xl leading-tight tracking-[-0.03em] uppercase
sm:text-2xl md:text-[2rem] md:leading-[2.5rem]; }
.h2 { @apply font-display text-lg leading-tight uppercase md:text-2xl md:leading-8; }
.h3 { @apply font-display text-sm leading-6 uppercase md:text-base; }
They match the Figma scale (H1 32px / H2 24px / H3 16px at md) and drop a step on mobile. Reach for the class rather than restyling a heading inline — it keeps the pixel face, the uppercasing and the responsive steps consistent everywhere. There is also a .description helper (text-base-700 dark:text-base-200 md:text-lg) for the lede paragraph under a heading.
The blog prose
The blog article body is rendered from MDX, so its headings carry no class hooks. global.css handles this with a .blog-prose class whose h2/h3 selectors are grouped with .h2/.h3, so the prose headings share the exact same pixel face, then layer on their own colour, spacing and a retro pointer:
- H2 gets a green right-triangle
►marker drawn withclip-path(a shape, not a glyph, so it is font-safe) and reads in info blue. - H3 reads in the theme pink.
- Links flip from info blue to success green on hover, underlined.
- Bold text reads in info blue.
- Bullets get a small square marker; blockquotes get a pink left border on a muted ground.
- Inline code sits in a bordered muted chip; fenced code blocks get a heavy border and stay a fixed-dark panel in both themes — the one place in the prose that does not flip, matching the retro-terminal look.
Because everything is expressed in tokens (except that deliberately-fixed code block), the whole article flips with the theme for free.
Changing the type
The type lives in four places, and which you touch depends on the change:
- Swap a face. Add the new Fontsource package (
pnpm add @fontsource/<family>), add an@font-faceblock insrc/styles/fonts.css, and repoint the--font-displayor--font-sanstoken intailwind-theme.css. If the face is above the fold, update the<link rel="preload">inBaseHeadto match — a preload for a font you no longer use is wasted bytes, and a missing preload for one you do costs you a paint. - Add a weight. Space Mono ships 400 and 700; for a third weight,
pnpm addthe family (if not already present) and add an@font-faceblock for that weight infonts.css. Remember Press Start 2P only exists at 400. - Retune the heading scale. Edit the
.h1/.h2/.h3classes inglobal.css— the sizes, the mobile steps, the tracking. Keep them uppercase and onfont-displayunless you are deliberately changing the identity. - Restyle the article body. Edit the
.blog-proserules inglobal.css. This is global CSS, not scoped — deliberately, because the markup comes from MDX that Astro’s scoped styles cannot reach.
Verifying
Open /examples/ui in dev — the catalog shows the heading classes and the body face together — and open a blog post to check .blog-prose. The most common miss is a heading set with a raw text-2xl font-bold instead of the .h1/.h2/.h3 class, which quietly loses the pixel face; grep for font-display if a heading looks wrong.