Back to wizard
Beginner Friendly 35 minsSoftware

How to Build This Site

Learn how crafta.beer works, how to run it locally, and how to add your own tutorials using the block-based content system.

1

What is Craft a Beer?

3 minsStep 1 of 8

What is Craft a Beer?

Craft a Beer (crafta.beer) is an open-source Nuxt 3 site that provides step-by-step DIY tutorials for homebrewing electronics projects. It helps brewers build things like fermentation temperature controllers and gravity-logging bridges using affordable microcontrollers.

The Block-Based Tutorial System

The site's core architectural idea is that tutorials are assembled from reusable content blocks. Instead of writing each tutorial as a single monolithic page, you write small, self-contained steps — called blocks — and then compose them into tutorials by listing the blocks in order.

This means that when two tutorials share a step (e.g., flashing firmware), you write that step once and reference it from both tutorials. If the flashing process changes, you update one file and every tutorial that uses it gets the fix automatically.

Tech Stack

The site is built on:

  1. Nuxt 3 — the Vue.js framework that handles routing, rendering, and the dev experience
  2. @nuxt/content — reads markdown and YAML files from the content/ directory and makes them queryable
  3. @nuxtjs/i18n — provides internationalization support with locale-prefixed routes
  4. Tailwind CSS — utility-first CSS framework with the Typography plugin for rendered markdown

How Tutorials Work

A tutorial is a YAML file that declares metadata (title, difficulty, estimated time) and an ordered list of block paths. At render time, the useTutorial composable fetches the YAML definition plus all the referenced blocks in a single query, then assembles them into a numbered step-by-step page.

2

Prerequisites

5 minsStep 2 of 8

Parts Needed

PartQty
Node.js 22.x (LTS)×1
Git×1
A code editor (VS Code, WebStorm, etc.)×1

Prerequisites

Before you can run the site locally, you'll need a few tools installed on your machine.

Node.js

The site requires Node.js 22.x (the current LTS release). You can check your version with:

node --version   # should print v22.x.x
npm --version    # should print 10.x.x or later

If you need to install or update Node.js, grab it from nodejs.org or use a version manager like nvm or fnm.

Git

You'll need Git to clone the repository. Most systems have it pre-installed. Verify with:

git --version

Code Editor

Any editor works, but VS Code with the Vue and Tailwind CSS extensions provides the best experience. WebStorm also has excellent built-in Vue and Tailwind support.

3

Clone and Run the Dev Server

5 minsStep 3 of 8

Clone and Run the Dev Server

Let's get the site running on your machine.

Clone the Repository

git clone https://github.com/thorrak/craftabeer.git
cd craftabeer

Install Dependencies

npm install

This installs Nuxt, Vue, Tailwind CSS, the Content and i18n modules, and everything else the project needs. It also runs nuxt prepare automatically via the postinstall script, which generates the .nuxt/ directory with TypeScript types.

Start the Dev Server

npm run dev

The dev server starts at http://localhost:3000 with hot module replacement. Changes to Vue components, pages, composables, and content files will reflect immediately in the browser without a full reload.

Verify It Works

Open http://localhost:3000 in your browser. You should see the Craft a Beer landing page. Try navigating to /browse to see the wizard and tutorial listings.

4

Understand the Project Structure

5 minsStep 4 of 8

Understand the Project Structure

Here's how the codebase is organized:

craftabeer/
├── content/en/           # All content files
│   ├── blocks/           # Reusable tutorial steps (markdown)
│   │   ├── brewpi/       # BrewPi-specific blocks
│   │   └── tiltbridge/   # TiltBridge-specific blocks
│   ├── tutorials/        # Tutorial definitions (YAML)
│   │   ├── brewpi/       # BrewPi tutorial definitions
│   │   └── tiltbridge/   # TiltBridge tutorial definitions
│   └── guides/           # Standalone guide articles (markdown)
├── pages/                # Nuxt file-based routing
├── components/           # Vue components
├── composables/          # Shared reactive logic
├── config/               # Wizard configuration (YAML)
├── server/               # API routes (serves wizard config)
├── types/                # Shared TypeScript interfaces
├── assets/css/           # Global styles (Tailwind entry point)
├── locales/              # i18n translation files (JSON)
└── public/               # Static assets (favicon, images)

Key Directories

content/en/blocks/ — Each markdown file is a single tutorial step. Blocks are organized by project (e.g., brewpi/, tiltbridge/). A block can be referenced by any tutorial, even one in a different project folder.

content/en/tutorials/ — YAML files that define a tutorial's metadata and its ordered list of blocks. The slug field determines the URL path.

composables/ — Houses the core logic: useTutorial assembles blocks into tutorials, useWizard manages the project selector, and useBookmarks handles localStorage-based bookmarking.

config/ — The wizard configuration (wizard.en.yml) defines the dropdown options and maps selection combinations to tutorial slugs.

5

Write a Content Block

5 minsStep 5 of 8

Write a Content Block

Blocks are the building blocks (pun intended) of every tutorial. Each block is a markdown file with YAML frontmatter.

Create a New Block

Create a markdown file in the appropriate project folder under content/en/blocks/. For example, to add a block for a new project called "keezer":

content/en/blocks/keezer/what-is-a-keezer.md

Block Frontmatter

Every block needs a title and estimatedTime in its frontmatter:

---
title: "What is a Keezer?"
estimatedTime: "3 mins"
---

# What is a Keezer?

A keezer is a chest freezer converted into a draft beer dispenser...

Optional: Parts List

If your block involves gathering components, add a parts array to the frontmatter. The tutorial renderer will display these as a shopping list:

---
title: "What You'll Need"
estimatedTime: "5 mins"
parts:
  - name: "ESP32 DevKit"
    link: "https://example.com/esp32"
    quantity: 1
  - name: "Temperature sensor"
    quantity: 2
---

Writing Tips

  • Keep blocks focused on a single step or concept
  • Write as if the reader has completed the previous steps in the tutorial
  • Include code blocks, commands, or wiring diagrams where helpful
  • Blocks should make sense on their own — another tutorial might reuse yours in a different order
6

Create a Tutorial Definition

5 minsStep 6 of 8

Create a Tutorial Definition

A tutorial definition is a YAML file that ties blocks together into a complete, ordered tutorial.

Create the YAML File

Create a new file in the appropriate project folder under content/en/tutorials/. For example:

content/en/tutorials/keezer/keezer-basic.yml

Tutorial Definition Format

slug: "keezer/keezer-basic"
title: "Build a Basic Keezer Controller"
description: "Turn a chest freezer into a temperature-controlled keezer."
image: "/images/tutorials/keezer-basic.jpg"
category: "Electronics"
difficulty: "beginner"
estimatedTime: "60 mins"
tags:
  - keezer
  - esp32
  - temperature-control

blocks:
  - keezer/what-is-a-keezer
  - keezer/what-you-need
  - keezer/wiring
  - keezer/firmware-flash
  - keezer/testing

The slug must match the file's path relative to content/en/tutorials/ (without the .yml extension). The blocks array lists block paths relative to content/en/blocks/.

Block Overrides

Sometimes a shared block needs a small addition for a specific tutorial. Instead of duplicating the block, use blockOverrides to append a note:

blockOverrides:
  keezer/what-you-need:
    appendNote: "For this build you'll also need a chest freezer and an inkbird-style temperature probe."

The override note is displayed below the block's content, giving tutorial-specific context without modifying the shared block.

Wire It Into the Wizard

To make your tutorial discoverable through the wizard on the /browse page, add a route entry in config/wizard.en.yml that maps a selection combination to your tutorial's slug. See the next step for details.

7

Configure the Wizard

5 minsStep 7 of 8

Configure the Wizard

The wizard is the interactive project selector on the /browse page. It guides users through a series of dropdowns to find the right tutorial. Configuration lives in config/wizard.en.yml.

Wizard Config Structure

The config has three sections:

selectors:    # The dropdown menus
routes:       # Maps selection combos → tutorial slugs
fallback:     # Message shown when no tutorial matches

Adding a New Project

To add a new project to the first dropdown, add an entry under selectors[0].options:

selectors:
  - id: project
    label: "I want to build a"
    options:
      - id: keezer-controller
        label: "Keezer Controller"

Adding Skill Options

The second dropdown shows different options depending on the selected project. Add your options under selectors[1].optionsByProject:

  - id: skill
    connective: "And I"
    optionsByProject:
      keezer-controller:
        - id: no-solder
          label: "don't want to solder anything"
        - id: solder-ok
          label: "am comfortable soldering"

Adding Routes

Map each selection combination to a tutorial slug:

routes:
  "keezer-controller+no-solder": "keezer/keezer-no-solder"
  "keezer-controller+solder-ok": "keezer/keezer-soldered"

Use * as a wildcard to match any option in a position:

  "keezer-controller+*": "keezer/keezer-basic"

Testing

After editing the wizard config, reload the /browse page. Select your new project from the first dropdown and verify that the second dropdown shows the correct options and that the matched tutorial appears.

8

Build and Deploy

3 minsStep 8 of 8

Build and Deploy

Once you're happy with your changes locally, here's how to get them into production.

Production Build

Run a production build to verify everything compiles cleanly:

npm run build

This generates the .output/ directory using the node-server Nitro preset. You can preview the production build locally with:

npm run preview

Deploy

The site auto-deploys when you push to the main branch. A GitHub webhook notifies the server, which pulls the latest code, installs dependencies, builds, and restarts the application via PM2.

git add .
git commit -m "Add keezer tutorials"
git push origin main

That's it — your changes will be live on crafta.beer within a minute or two.

Static Generation (Optional)

If you prefer static hosting instead of a Node server, the site can also be statically generated:

npm run generate

This produces a fully static site in .output/public/ that can be deployed to any static host (Netlify, Vercel, GitHub Pages, etc.).

Step 1 of 8