Skip to content
AstroCraft Docs
On this theme

Installation

8-BitQuest ships as a complete Astro project, not as an npm package or an integration you register. You clone the repository, install its dependencies, and start editing — there is no theme layer sitting between you and the markup, and nothing is hidden inside node_modules. Every component, token, icon and animation is a file in src/ that you own from the first commit.

It runs with no configuration, no API keys and no accounts. pnpm install followed by pnpm dev gives you the full site — home, about, blog, project log, contact, legal pages — populated with sample content reproduced from the source Figma. Configuration is what you do once you have looked around, not a prerequisite for seeing it work.

Requirements

  • Node.js 22.13.0 or newer. This is enforced by engines.node in package.json, and it is not a soft floor: the test runner executes TypeScript directly through Node’s --experimental-strip-types flag, which the theme passes explicitly so it works from 22.13 on rather than only on 23.6+ where stripping is default. Check yours with node -v.
  • pnpm. The package manager is pinned by packageManager: "[email protected]" in package.json, the lockfile is pnpm-lock.yaml, and pnpm-workspace.yaml carries install settings the theme relies on. If you do not have pnpm, corepack enable pnpm is the shortest route and will honour the pinned version.
  • Git, to clone the repository and to keep your own history from the first commit onward.

You do not need a Resend account, a domain, or any host account to run the theme locally. Each of those is optional and covered further down.

Get the code

Clone the repository and drop the upstream history so your project starts with a clean log:

git clone https://github.com/Astro-Craft-Theme/8-BitQuest.git my-portfolio
cd my-portfolio
rm -rf .git && git init

If you would rather keep the upstream remote so you can pull theme updates later, skip the rm -rf .git and rename the remote instead:

git remote rename origin upstream
git remote add origin [email protected]:you/my-portfolio.git

Keeping upstream is only worth it if you plan to merge theme changes. Because the theme is source you edit directly, a merge after heavy customization is a real merge — most people take the clean-slate route and treat the clone as a starting point.

Install dependencies

pnpm install

The dependency list is deliberately short. At runtime the theme depends on Astro 7, Tailwind CSS v4, tailwind-variants and tailwind-merge, the two Fontsource variable families that carry the retro type (@fontsource/press-start-2p and @fontsource/space-mono), and three official Astro integrations (@astrojs/mdx, @astrojs/node, @astrojs/sitemap). There is no UI kit, no animation library, no SEO package and no icon package — those four things are implemented inside the theme rather than pulled in, which is why the surface you have to keep up to date stays small.

Two details in pnpm-workspace.yaml are worth knowing about before they surprise you:

  • allowBuilds denies post-install build scripts for @parcel/watcher, esbuild and sharp. This is intentional. None of the three needs to compile from source for this project to work, and denying them keeps installs fast and free of native toolchain requirements. If your install prints a notice about ignored build scripts, that is this setting working as designed, not a failure.
  • minimumReleaseAgeExclude pins the Tailwind packages to the exact 4.3.2 version set the theme was built and tested against, including the platform-specific @tailwindcss/oxide-* binaries.

A note on image optimization

sharp is not a direct dependency — it arrives as Astro’s own optional image dependency, and it ships prebuilt binaries, so the denied build script above costs you nothing: astro:assets still optimizes the blog hero images and project thumbnails at build time. If you ever land on a platform without a prebuilt binary, pnpm add sharp installs it directly.

Start the dev server

pnpm dev

The site is at http://localhost:4321. Every route is available immediately with the sample content in place:

  • / — the home page
  • /about/
  • /projects/ and /projects/<slug>/ — six sample projects
  • /blog/ and /blog/<slug>/ — six sample posts and one author
  • /contact/ — the form renders and validates with no keys set
  • /terms/ and /privacy/ — placeholder legal copy
  • /rss.xml, /robots.txt, /llms.txt, /sitemap-index.xml — all generated, all deriving their absolute URLs from one setting

The primitive catalog

Before you start building pages, open http://localhost:4321/examples/ui. It is a development-only catalog of all 39 UI primitives in every variant, alongside the 87 motion utilities and the 571-icon registry. It is the fastest way to find out what already exists rather than rebuilding it.

The route is gated inside getStaticPaths, so a production build emits no paths for it and no HTML ships. You can leave it in place while you work. When you no longer need it, delete src/pages/examples/ and src/components/Sections/UiCatalog/ together — Tailwind still scans the catalog’s markup even though it builds no pages, and its demo classes sit in the stylesheet every real page loads. Removing it takes the shared CSS from roughly 76 KB to 57 KB and drops around 70 unused @keyframes.

What runs where

Every page is prerendered to static HTML with exactly one exception: src/pages/contact.astro sets export const prerender = false; because the form posts to a server action. That single route is the only thing the Node adapter ever runs, and it is why pnpm build splits its output into dist/client/ (the prerendered pages) and dist/server/entry.mjs (the one server route).

This matters at install time for one reason. Under astro dev everything runs on a server, so a route that accidentally depends on request-time behavior will work locally and fail — or behave differently — in a static build. Run pnpm build early and often — it is the check that tells the truth.

Environment variables

None are required. A fresh clone builds and runs with an empty environment, and the contact form still renders, validates input and reports a readable message instead of failing silently. Set these when you want the corresponding feature to work.

Copy the example file and fill in what you need:

cp .env.example .env

The variables

  • SITE_URL — your production domain. It feeds the canonical link, Open Graph tags, JSON-LD, the sitemap, robots.txt, llms.txt and the RSS feed, so one wrong value poisons six things at once. It defaults to https://example.com, and a production deploy throws if it is still the placeholder. Local builds and deploy previews are unaffected, which is why this only ever bites at deploy time.
  • RESEND_API_KEY — a Resend API key. Required for the contact form to deliver mail.
  • CONTACT_TO_EMAIL — where enquiries land. Also required for delivery.
  • CONTACT_FROM_EMAIL — optional, defaults to [email protected]. That shared sender works immediately but can only deliver to the address that owns the Resend account, so if CONTACT_TO_EMAIL is a different address, delivery fails at the provider even though everything else is correct. Verify your own domain in Resend and set this to send anywhere.
  • DEPLOY_ENV — optional, and only needed on a host that is neither Netlify nor Vercel. The production gate already reads Netlify’s CONTEXT and Vercel’s VERCEL_ENV; on any other host you set DEPLOY_ENV=production in the production build environment so the SITE_URL gate can fire there too.
RESEND_API_KEY=re_xxxxxxxxxxxx
CONTACT_TO_EMAIL[email protected]
CONTACT_FROM_EMAIL[email protected]

How the form behaves with nothing set

The form is functional from the first run. It validates on the server, works with JavaScript disabled, and is protected by a honeypot field and a submit-time gate regardless of configuration. With RESEND_API_KEY or CONTACT_TO_EMAIL missing, a submission returns a message saying the form is not configured yet — a real error you can see, not a silent drop. That check happens at request time, so a missing key never breaks your build.

Make it yours

With the site running, these are the first files to edit. All of them are typed, so a mistake fails the build with the offending value named rather than shipping quietly.

  1. src/config/siteData.json.ts — brand name, page title, description, the author block (name, email, twitter handle), the default social image, and sameAs (the social/profile URLs that feed the Organization JSON-LD).
  2. src/config/portfolioData.json.ts — the buyer-facing copy: profile identity, biography, the experience and scoreboard numbers, the home intro, and the contact prompt. This is the file that turns the sample “Full-Stack Dev” persona into you.
  3. src/config/siteSettings.json.tssiteLang and siteLocale, plus two switches: useViewTransitions and useAnimations (the master switch for decorative motion). Note that prefers-reduced-motion is honored by a global CSS guard no matter what useAnimations says; the flag is a design choice, not an accessibility one.
  4. src/config/navData.json.ts — the four header links (About, Projects, Blog, Contact).
  5. src/config/legalData.json.ts — the terms and privacy copy. It is explicitly placeholder text. Have a professional review it; it is not legal advice.
  6. public/og.jpg, public/favicon.svg, public/favicon.ico — the shipped og.jpg is a placeholder. Replace it with a real 1200×630 image.
  7. src/data/ — replace the six projects, six blog posts and one sample author. Each entry is a folder whose name is the URL slug, holding an index.mdx and its own images. Schemas live in src/content.config.ts, so bad frontmatter fails the build with the entry named.

Colors, type and spacing are not in this list because they are not in the config layer. They are CSS tokens in src/styles/tailwind-theme.css and src/styles/global.css, and the Colors and Typography pages cover them.

Verify your install

pnpm lint && pnpm check && pnpm build && pnpm test
  • pnpm lint runs ESLint, including the JSX accessibility rules.
  • pnpm check runs astro check for types across .astro and .ts files.
  • pnpm build is the real check. Content-schema errors, config typos and broken references all surface here rather than in the browser.
  • pnpm test runs every *.test.ts file under src/ with Node’s type stripping — no framework, no fixtures, nothing to register. There are eleven such files today, covering the contact validation and spam gates, the Resend boundary, the JSON-LD builders, the RSS feed, reading time, the listbox kernel and more. If it ever finds zero test files it fails rather than passing, so the suite cannot quietly disappear.

That same four-command chain runs in CI on every push and pull request (.github/workflows/ci.yml), on the placeholder SITE_URL exactly as a local build does.

There is also pnpm format, which runs eslint --fix and then Prettier. Class ordering is handled by prettier-plugin-tailwindcss, so let it sort and do not hand-order class lists.

Troubleshooting

The build throws about SITE_URL. You are running a production build with the placeholder domain still in place. Set SITE_URL in your host’s environment variables. This is intentional — it makes it impossible to ship canonical URLs and a sitemap pointing at example.com.

A renamed content entry keeps 404ing in dev. Astro’s content layer caches entries, and moving or renaming a folder while the dev server is running can leave the old entry in place and the new one missing. Restart pnpm dev; touching the file will not clear it.

A utility class has no effect in dev. In a long-running dev server, classes used only in newly created files can be missing from the generated stylesheet. Restart the dev server before you go looking for a bug in your markup.

The contact form says it is not configured. That is the expected message when RESEND_API_KEY or CONTACT_TO_EMAIL is unset. See the environment section above.

Mail sends without error but never arrives. You are almost certainly still on the default [email protected] sender, which can only deliver to the address that owns your Resend account. Verify a domain in Resend and set CONTACT_FROM_EMAIL.

Node version errors on install. The floor is 22.13.0. Older releases will fail on the test runner even if the install itself appears to succeed.

NEXT STEPProject Structure