# HowToCook Project Structure and Organization: A Technical Deep Dive

> Explore the HowToCook project structure a content-first Node.js architecture with auto-generated indexes. Understand how recipes are organized in dishes and tips directories.

- Repository: [Anduin Xue/HowToCook](https://github.com/Anduin2017/HowToCook)
- Tags: deep-dive
- Published: 2026-02-27

---

**The HowToCook repository employs a content-first architecture where Markdown recipes reside in categorized directories under `dishes/` and `tips/`, while a Node.js automation script generates navigation indexes, difficulty ratings, and static-site configuration automatically.**

The **Anduin2017/HowToCook** project demonstrates how a simple **HowToCook project structure** can scale to hundreds of recipes without manual maintenance. By storing culinary content as plain Markdown and leveraging a lightweight build pipeline, the repository maintains a clean, contributor-friendly organization while automatically generating complex navigation systems and difficulty classifications.

## Repository Layout and Directory Structure

The repository organizes content, automation, and generated artifacts into distinct top-level directories. This separation ensures that contributors can focus on writing recipes while the build system handles navigation and formatting.

### Core Content Directories

All human-authored content lives in two primary locations:

- `dishes/` – The main recipe collection organized by culinary category. Each subfolder represents a category (e.g., `meat_dish/`, `vegetable_dish/`, `breakfast/`, `soup/`) and contains individual dish folders with Markdown files and optional images. For example, `dishes/meat_dish/黑椒牛柳/黑椒牛柳.md` contains the recipe for Black Pepper Beef Tenderloin.

- `tips/` – Supplementary cooking knowledge including equipment guides, kitchen safety protocols, and advanced techniques. Files like `tips/厨房准备.md` provide foundational knowledge that supports the recipe collection.

### Generated Navigation and Configuration Files

The **HowToCook project structure** relies on auto-generated files that should never be edited manually:

- `starsystem/` – Contains difficulty index files ([`0Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/0Star.md) through [`5Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/5Star.md)) generated by counting Unicode star characters (★) in each recipe. These files are completely auto-generated based on star counts in recipe files.

- [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) – The repository's human-readable entry point. This file is regenerated automatically to include categorized recipe lists, difficulty indexes, and contribution guidelines.

- [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml) – Configuration file for the MkDocs static site generator, automatically updated to reflect the current directory structure for web deployment.

### Build System and Templates

Automation logic and contributor onboarding resources reside in:

- [`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.github/readme-generate.js) – The core Node.js script that orchestrates the entire build process, from scanning directories to rendering final output files.

- `dishes/template/示例菜/示例菜.md` – The standardized recipe template that contributors copy when adding new dishes. This template includes commented sections for ingredients, measurements, cooking steps, and difficulty ratings.

- [`.github/workflows/build.yml`](https://github.com/Anduin2017/HowToCook/blob/main/.github/workflows/build.yml) – GitHub Actions configuration that executes the build pipeline on every push to ensure documentation remains synchronized with content changes.

- [`package.json`](https://github.com/Anduin2017/HowToCook/blob/main/package.json) – Declares Node.js runtime dependencies and build scripts, including linting tools like `textlint` and `markdownlint-cli`.

## How the Build Automation Works

The repository maintains its **HowToCook project structure** through a lightweight but powerful Node.js automation pipeline. This system eliminates manual maintenance of navigation files while ensuring consistency across hundreds of recipes.

### The readme-generate.js Script

Located at [`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.github/readme-generate.js), this script serves as the central orchestrator for repository maintenance. It performs four critical operations without requiring external services or databases:

1. **Directory Scanning** – The `getAllMarkdown()` function recursively traverses the repository tree, excluding `node_modules` and `.git` directories, to collect every `.md` file with its relative path.

2. **Content Classification** – The script categorizes each file as either a tip (`tips/`), advanced tip (`tips/advanced/`), or specific dish category based on parent folder names (e.g., `meat_dish/`, `vegetable_dish/`).

3. **Star Rating Calculation** – The `organizeByStars()` function processes each recipe to count difficulty indicators.

4. **Template Rendering** – The script populates [`readme_template.md`](https://github.com/Anduin2017/HowToCook/blob/main/readme_template.md) and [`mkdocs_template.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs_template.yml) with generated navigation sections, writing the final files to [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) and [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml).

### Scanning and Classification Logic

The build system distinguishes between different content types by analyzing file paths. During the scanning phase, the script builds a `categories` object that groups files into logical sections:

- Recipes in `dishes/breakfast/` populate the breakfast category
- Files in `tips/advanced/` populate the advanced techniques section
- Each category maintains an array of file objects containing paths and metadata

This classification enables the template renderer to generate hierarchical navigation without hardcoding directory names.

### Star Rating Index Generation

The difficulty classification system relies on the `countStars()` function to analyze recipe complexity:

```javascript
async function countStars(filename) {
  const data = await fs.readFile(filename, 'utf-8');
  let stars = 0;
  const lines = data.split('\n');
  lines.forEach(line => {
    // Count every ★ character in the file
    stars += (line.match(/★/g) || []).length;
  });
  return stars;
}

```

When `organizeByStars()` processes the recipe collection, it aggregates files by their star count (0 through 5) and generates corresponding Markdown files in `starsystem/`. A recipe containing three stars appears in [`starsystem/3Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/starsystem/3Star.md), while five-star recipes populate [`5Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/5Star.md), creating a browsable difficulty ladder.

### CI/CD Pipeline Integration

The [`.github/workflows/build.yml`](https://github.com/Anduin2017/HowToCook/blob/main/.github/workflows/build.yml) configuration ensures the **HowToCook project structure** remains synchronized automatically:

```bash

# Install dev dependencies (Node.js ≥ 14)

npm install

# Re-generate README and MkDocs files

npm run build

```

Every push to the repository triggers the GitHub Actions workflow, which executes [`readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/readme-generate.js). If the script generates changes to [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md), [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml), or star system files, the CI pipeline commits these updates automatically, ensuring navigation always reflects the current content state without manual intervention.

## Adding a New Recipe to the Repository

Contributors interact with the **HowToCook project structure** through a standardized workflow that requires no knowledge of the build system. The process leverages the template system and relies on CI automation for integration.

Follow these steps to add a new dish:

```bash

# 1️⃣ Copy the template

cp -r dishes/template/示例菜 dishes/meat_dish/新菜名

# 2️⃣ Rename the Markdown file (keep the same name as the dish)

mv dishes/meat_dish/新菜名/示例菜.md dishes/meat_dish/新菜名/新菜名.md

# 3️⃣ Edit the file, delete the <!-- … --> comments and fill the sections

#    (ingredients, calculations, steps, difficulty ★ rating, etc.)

# 4️⃣ Commit & push – CI will rebuild README & star index automatically

git add dishes/meat_dish/新菜名
git commit -m "Add 新菜名 recipe"
git push

```

Because the build script recursively scans the `dishes/` tree, the new recipe automatically appears in:

- The **category list** in [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) under the appropriate section (e.g., "荤菜" for meat dishes)
- The **difficulty index** ([`starsystem/XStar.md`](https://github.com/Anduin2017/HowToCook/blob/main/starsystem/XStar.md)) based on the number of ★ characters in the file
- The **MkDocs navigation** via the auto-generated [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml) configuration

## Summary

- The **HowToCook project structure** maintains strict separation between human-authored content in `dishes/` and `tips/` and machine-generated navigation in [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md), `starsystem/`, and [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml).
- A single Node.js script ([`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.github/readme-generate.js)) automates all maintenance tasks, using `getAllMarkdown()` for directory scanning, `organizeByStars()` for difficulty classification, and template rendering for output generation.
- Recipes use a standardized Markdown template with Unicode star characters (★) to indicate difficulty, which the build system counts via `countStars()` to generate browsable difficulty indexes.
- GitHub Actions CI executes `npm run build` on every push, ensuring navigation files remain synchronized with content changes without manual intervention.

## Frequently Asked Questions

### What programming language powers the HowToCook build system?

The build automation is written in **JavaScript (Node.js)**. The main script [`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.github/readme-generate.js) uses native Node.js modules such as `fs/promises` and `path` to scan directories, parse Markdown files, and generate static navigation files. The project requires no external build tools like Jekyll or Hugo, relying only on Node.js and a few dev-dependencies including `textlint` and `markdownlint-cli`.

### How does the repository automatically categorize recipes by difficulty?

The system uses the `countStars()` function within [`readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/readme-generate.js) to scan each recipe file for Unicode star characters (★). It totals the count for each file and aggregates recipes into difficulty-specific Markdown files located in `starsystem/` (e.g., [`3Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/3Star.md) for three-star recipes). This creates a browsable difficulty ladder ranging from 0 stars (simple) to 5 stars (complex) without requiring manual categorization by contributors.

### Can I contribute a new recipe without manually editing the README?

Yes. Contributors only need to copy the template from `dishes/template/示例菜/示例菜.md` to the appropriate category folder (such as `dishes/meat_dish/`), fill in the recipe content including the difficulty rating using ★ characters, and commit the changes. The GitHub Actions workflow defined in [`.github/workflows/build.yml`](https://github.com/Anduin2017/HowToCook/blob/main/.github/workflows/build.yml) automatically runs `npm run build`, which executes [`readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/readme-generate.js) to regenerate [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md), [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml), and the star rating indexes to include your new recipe.

### What is the purpose of the mkdocs.yml file in the repository?

The [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml) file serves as the configuration for **MkDocs**, a static site generator that publishes the cookbook as a browsable website. It is auto-generated by the build script to reflect the current directory structure of recipes and tips, mapping Markdown content to navigation menus. This ensures the web version of the cookbook stays synchronized with the repository structure without requiring manual updates to the site configuration when new categories or recipes are added.