# Rust Static Site Generator – System Design
## 1. Philosophy
This static site generator (SSG) is a **content-first, convention-over-configuration** system written in Rust. It intentionally avoids front matter, template DSLs, and external tooling dependencies, favoring:
- Markdown as the primary authoring format
- Filesystem structure as the source of truth
- Rust libraries for all processing
- Lenient behavior with warnings instead of hard errors
The system is designed to support **blogs, digital gardens, code snippets, recipes, talks, and slides** in a single coherent knowledge base.
---
## 2. Repository Layout
All content lives at the **root of the repository**.
```
/
index.md
nav.md
blog/
notes/
snippets/
talks/
projects/
recipes/
slides/
tags/
contexts/
images/
static/
layouts/
```
### Ignored Files and Directories
- All **dot-prefixed files and directories** (e.g. `.git`, `.obsidian`, `.DS_Store`) are ignored
- **Exception:** dot-prefixed files inside `static/` are copied and served normally
- Build output directory is ignored
---
## 3. Collections
Each top-level directory represents a **collection** with defined behavior.
| blog | `/blog/` | flat | date-sorted, RSS |
| notes | `/notes/` | hierarchical | digital garden |
| snippets | `/snippets/` | flat | code-first |
| talks | `/talks/` | flat | |
| projects | `/projects/` | flat | |
| recipes | `/recipes/` | flat | |
| slides | `/slides/` | flat | reveal.js, no backlinks |
“Flat” means directories are allowed in source but ignored in output URLs.
---
## 4. Markdown Content Model
### 4.1 Markdown Flavor
- CommonMark + useful extensions
- Tables, footnotes, strikethrough
- Automatic heading IDs
### 4.2 Title
- First level-1 heading (`# Title`)
- Fallback: filename
### 4.3 Dates
Determined in priority order:
1. Filename prefix (`YYYY-MM-DD-`)
2. Git last-modified time
3. File modification time
### 4.4 Drafts
A page is a draft if:
- Filename starts with `_`
- Or it is inside a `_drafts/` directory
Drafts are excluded unless `--drafts` is enabled.
---
## 5. Index Page and Directives
### 5.1 Root Index
`index.md` renders to `/`.
It may contain **directives** controlling generated lists:
```
{{recent blog 5}}
{{recent notes 8}}
```
Directives are parsed and replaced during rendering.
---
## 6. Navigation
### 6.1 nav.md
Navigation is defined in `nav.md` at the repository root.
Example:
```
- [Home](/)
- [Blog](/blog/)
- [Notes](/notes/)
- [Recipes](/recipes/)
```
Only Markdown lists are parsed. Order is preserved.
---
## 7. Notes as a Digital Garden
Notes support **hierarchical structure** and directory indexes.
```
notes/
linux/
index.md
networking.md
```
Behavior:
- If a directory contains `index.md`, it is rendered
- Otherwise, an index is auto-generated
- Index pages list subdirectories and pages
Notes fully participate in backlinks.
---
## 8. Code Snippets
### 8.1 Source Format
Snippets are **code files**, not Markdown.
```
snippets/
rust/vec_dedup.rs
bash/find_large_files.sh
```
### 8.2 Rendering
- Language inferred from file extension
- Highlighted using `syntect`
- Rendered inside a page layout
- Filename becomes title
### 8.3 URLs
```
/snippets/vec-dedup/
```
Directories are organizational only.
Snippets support backlinks.
---
## 9. Tags and Contexts
### 9.1 Inline Syntax
In Markdown text:
- Tags: `[#rust systems programming]`
- Contexts: `[@linux networking]`
These generate links to:
```
/tags/rust-systems-programming/
/contexts/linux-networking/
```
### 9.2 Markdown Pages
Tags and contexts may have their own Markdown pages:
```
tags/rust.md
contexts/linux.md
```
If present:
- Rendered first
- Followed by auto-generated listing
---
## 10. Backlinks
Backlinks are computed globally for all pages **except slides**.
A backlink exists when:
- Page A links to Page B
- The link is internal
Rendered at the bottom of pages as a list.
---
## 11. Language Detection and RTL
- Content language detected using `whatlang`
- Applied to `<html lang="…">`
- Arabic → `dir="rtl"`
RTL is handled via layout and CSS.
---
## 12. Git Integration
- Implemented using the `git2` crate
- No external git commands
- If repository is not a git repo:
- Last-modified metadata is omitted
---
## 13. Images
### 13.1 Source and Output
```
images/ → /images/
```
### 13.2 Processing
Images are processed using Rust libraries:
- Load image
- Strip EXIF metadata
- Resize to maximum dimensions
- Re-encode to target format/quality
Defaults apply if no configuration is provided.
Markdown image links point directly to `/images/...`.
---
## 14. Static Files
```
static/ → /
```
- Static files are copied verbatim to output root
- Dot-prefixed files inside `static/` are included
---
## 15. Layouts
### 15.1 Directory
```
layouts/
default.html
blog.html
notes.html
slides.html
```
### 15.2 Selection Rules
1. Layout matching collection name
2. Fallback to `default.html`
### 15.3 Placeholders
Layouts support a fixed set of placeholders:
- `{{title}}`
- `{{content}}`
- `{{nav}}`
- `{{backlinks}}`
- `{{last_modified}}`
- `{{lang}}`
- `{{dir}}`
Layouts contain no logic.
---
## 16. Command-Line Interface (CLI)
The SSG exposes a small, explicit CLI focused on local workflows. All commands operate relative to the repository root.
### 16.1 `build`
```
ssg build [options]
```
Performs a one-shot build of the site.
Behavior:
- Discovers and processes all content
- Processes images
- Generates HTML, RSS, and sitemap
- Writes output to the build directory
Options:
- `--drafts` : include draft content
- `--output <dir>` : override output directory (default: `dist/`)
- `--clean` : remove output directory before building
---
### 16.2 `watch`
```
ssg watch [options]
```
Continuously watches the repository for changes and rebuilds affected content.
Behavior:
- Performs an initial build
- Watches filesystem changes (excluding ignored paths)
- Incrementally rebuilds changed pages
Options:
- `--drafts`
- `--output <dir>`
---
### 16.3 `serve`
```
ssg serve [options]
```
Builds the site and serves it locally via an HTTP server.
Behavior:
- Runs a full build
- Starts a local HTTP server rooted at the output directory
- Intended for development and preview
Options:
- `--port <port>` (default: `3000`)
- `--host <addr>` (default: `127.0.0.1`)
- `--drafts`
- `--watch` : rebuild on changes while serving
---
### 16.4 `prep-images`
```
ssg prep-images [options]
```
Preprocesses images without building the site.
Behavior:
- Loads images from `images/`
- Strips EXIF metadata
- Resizes images to configured maximum dimensions
- Writes processed images to the output `/images/` directory
Options:
- `--force` : reprocess all images, ignoring cache
- `--output <dir>` : override output directory
This command exists to support image-only workflows and CI pipelines.
---
## 17. Rendering Pipeline
1. Discover content
2. Filter ignored dot-prefixed files
3. Load git metadata
4. Process images
5. Parse Markdown and code
6. Extract links, tags, contexts
7. Build backlink graph
8. Render pages
9. Emit static files
10. Generate RSS and sitemap
---
## 18. Output Characteristics
- Pretty URLs (`/path/index.html`)
- Lenient parsing with warnings
- Deterministic output
- No front matter
- No template DSL
---
## 19. Summary
This system is a **Rust-native static knowledge engine**:
- Blog + digital garden + code notebook
- Strong internal linking via backlinks, tags, and contexts
- Image processing built into the pipeline
- Minimal authoring friction
- Maximum structural clarity
It is designed to scale from personal notes to a long-lived public knowledge base without sacrificing simplicity.