AI-Assisted Design
If you use an AI design tool like Claude to create or modify an aphid theme, you can get better results by giving it the full picture of what a theme requires. This page provides a ready-made instruction block covering the theme format, required templates, and every variable available in the Tera template context.
For background on project-level instruction files and where each tool expects them, see AI-Assisted Writing.
Instructions
Copy the block below into your tool's project-level instruction file.
This project uses aphid, a static site generator. Themes are directories containing Tera
templates (Jinja2-style) and optional static files. The goal is to design a complete theme.
## Theme directory layout
```
mytheme/
theme.toml
templates/
base.html
home.html
blog_post.html
blog_index.html
wiki_page.html
wiki_index.html
page.html
tag.html
tags_index.html
404.html
static/
css/
js/
```
`theme.toml` is required and must contain at least:
```toml
name = "mytheme"
version = "0.1.0"
```
`description` is optional.
## Template engine
Templates use Tera — a Jinja2-style engine. Key syntax:
- `{{ variable }}` — output a value
- `{{ variable | safe }}` — output HTML without escaping (required for rendered content)
- `{% block name %}...{% endblock %}` — define/override blocks
- `{% extends "base.html" %}` — inherit from a parent template
- `{% for item in list %}...{% endfor %}` — loops
- `{% if condition %}...{% elif %}...{% else %}...{% endif %}` — conditionals
- `{# comment #}` — comments
The standard pattern is a `base.html` layout that all other templates extend.
## Global variables (available in every template)
| Variable | Type | Description |
|----------|------|-------------|
| `site_title` | string | Site title from `aphid.toml` |
| `base_url` | string | Canonical root URL from `aphid.toml` |
| `version` | string | The aphid binary version |
| `nav_pages` | list | Standalone pages sorted by `order`; each has `title` and `url` |
| `socials` | list | Social links from `aphid.toml`; each has `platform` and `url` |
## base.html
The root layout. All other templates extend this. Must define blocks that child templates
override. Typically contains `<html>`, `<head>`, navigation, header, footer.
Example skeleton:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block page_title %}{{ site_title }}{% endblock %}</title>
<link rel="stylesheet" href="/static/css/theme.css">
</head>
<body>
<nav>
<a href="/">{{ site_title }}</a>
{% for page in nav_pages %}
<a href="{{ page.url }}">{{ page.title }}</a>
{% endfor %}
</nav>
<main>
{% block content %}{% endblock %}
</main>
<footer>
{% for social in socials %}
<a href="{{ social.url }}">{{ social.platform }}</a>
{% endfor %}
<span>Built with aphid {{ version }}</span>
</footer>
</body>
</html>
```
## home.html
Renders the site root (`/index.html`).
| Variable | Type | Description |
|----------|------|-------------|
| `posts` | list | All blog posts (see post entry shape below) |
| `home` | object? | Present when `content/home.md` exists; has `content` (rendered HTML — use `| safe`) |
## blog_post.html
Renders a single blog post.
| Variable | Type | Description |
|----------|------|-------------|
| `title` | string | Post title |
| `url` | string | Clean URL, e.g. `/blog/my-post/` |
| `content` | string | Rendered HTML body — always use `| safe` |
| `toc` | list | Heading entries; each has `level` (int), `text` (string), `id` (string) |
| `backlinks` | list | Pages linking here; each has `title` and `url` |
| `author` | string? | Author name |
| `image` | string? | Hero image path or URL |
| `created` | string? | Publication date `YYYY-MM-DD` |
| `updated` | string? | Last-edited date |
| `tags` | list | Each has `name` and `slug` |
## blog_index.html
Renders the blog listing at `/blog/`.
| Variable | Type | Description |
|----------|------|-------------|
| `posts` | list | All blog posts (see post entry shape below) |
## Post entry shape (used in home.html, blog_index.html, tag.html)
| Field | Type | Description |
|-------|------|-------------|
| `title` | string | Post title |
| `url` | string | Clean URL |
| `created` | string? | Publication date |
| `image` | string? | Hero image path or URL |
| `description` | string? | Short summary from frontmatter |
| `tags` | list | Each has `name` and `slug` |
## wiki_page.html
Renders a single wiki page. Has the same variables as `blog_post.html`, plus:
| Variable | Type | Description |
|----------|------|-------------|
| `category` | string? | Category name from frontmatter |
| `wiki_categories` | list | All wiki pages grouped by category — for a sidebar. Each entry has `name` (string or null) and `pages` (list of `{title, url}`). Named categories appear first; uncategorised pages are grouped under `name = null` at the end. |
Note: `author` and `image` are always absent on wiki pages. `created`, `updated`, and `tags`
are present only if set in frontmatter.
## wiki_index.html
Renders the wiki listing at `/wiki/`.
| Variable | Type | Description |
|----------|------|-------------|
| `categories` | list | Same shape as `wiki_categories` on wiki_page.html |
## page.html
Renders standalone pages (About, Contact, etc.). Same variables as `blog_post.html`, but
`author`, `image`, `created`, `updated`, and `tags` are always absent.
## tag.html
Renders a single tag page.
| Variable | Type | Description |
|----------|------|-------------|
| `tag` | string | Tag display name |
| `tag_slug` | string | URL-safe slug |
| `posts` | list | Tagged posts; each has `title`, `url`, and `created?` |
## tags_index.html
Renders the tag listing at `/tags/`.
| Variable | Type | Description |
|----------|------|-------------|
| `tags` | list | All tags; each has `name`, `slug`, and `count` |
## 404.html
Error page. No additional variables beyond the global ones.
## Static files and CSS
Place stylesheets, scripts, and other assets in `mytheme/static/`. They are copied to the
output's `static/` directory. Reference them with absolute paths:
```html
<link rel="stylesheet" href="/static/css/theme.css">
```
If the user's `static_dir` has a file with the same name, the user's version wins.
## Syntax highlighting CSS
Code blocks use CSS classes prefixed `hl-`. The theme stylesheet must define colors for these
classes. Key token classes:
- `hl-keyword` — language keywords (`fn`, `if`, `return`)
- `hl-string` — string literals
- `hl-comment` — comments
- `hl-type` — type names
- `hl-function` — function/method names
- `hl-number` — numeric literals
- `hl-operator` — operators
- `hl-punctuation` — brackets, commas, semicolons
- `hl-variable` — variable names
- `hl-attribute` — attributes/decorators
- `hl-tag` — HTML/XML tags
- `hl-entity` — entities and special names
Wrap code blocks in a container with `overflow-x: auto` for horizontal scrolling.
Use a monospace font and a background color that contrasts with the page.
## Design guidelines
- The page title is `<h1>`, body headings start at `<h2>` (the markdown pipeline shifts levels)
- `content` is rendered HTML — use `{{ content | safe }}`
- `toc` entries can build a table of contents sidebar or in-page nav
- `backlinks` are most useful on wiki pages — show them in a footer or sidebar section
- `wiki_categories` on wiki_page.html enables a sidebar showing all wiki pages grouped by
category, with the current page highlighted (compare `page.url == url`)
- Test the theme against pages with: no image, no tags, no TOC, very long content, and many
backlinks
- Ensure the layout is responsive — test at mobile, tablet, and desktop widths
See also: Themes, Markdown, AI-Assisted Writing.
Linked from