A photo processing pipeline for static site generators. Process your photos into multiple resolutions and formats, extract EXIF data and blurhash placeholders, and output everything as content files your SSG can consume.
akskashii ('aks-kashii, عَکْس کَشی) is Persian/Farsi origin, Urdu for "photography".
cargo install --path .akskashii is designed to work as a pre-build step for Zola. It processes your photos and outputs Zola-compatible content files and optimized images.
# In your photo source directory (separate from your Zola site)
aks init mysite
cd mysite
# Add photos to an album
mkdir -p photos/tokyo-2024
cp ~/pictures/*.jpg photos/tokyo-2024/
# Generate album metadata (optional, for titles/descriptions/alt text)
aks init-album photos/tokyo-2024/
# Process photos and output to your Zola site
aks process --source . --output ~/my-zola-siteaks process writes three things to your Zola site:
~/my-zola-site/
static/photos/tokyo-2024/
DSC_0001_480w.jpg
DSC_0001_480w.webp
DSC_0001_1024w.jpg
DSC_0001_1024w.webp
DSC_0001_1920w.jpg
DSC_0001_1920w.webp
content/photos/
_index.md # photos section index
tokyo-2024/
_index.md # album section page
DSC_0001.md # individual photo page
DSC_0002.md
Each album is a Zola section (not a page), so individual photo pages can live inside it with their own URLs and prev/next navigation.
Then build your Zola site as usual:
cd ~/my-zola-site
zola build# Typical build workflow
aks process -s ./photos-source -o ./my-zola-site
zola build
# Or wrap it in a Makefile:
# build:
# aks process -s ../photos -o .
# zola buildYou need three templates in your Zola site:
| Template | Variable | Purpose |
|---|---|---|
templates/photos.html |
section |
Lists all albums (iterates section.subsections) |
templates/album.html |
section |
Album grid (iterates section.pages for photo thumbnails) |
templates/photo.html |
page |
Individual photo with EXIF and prev/next nav |
+++
title = "Tokyo 2024"
sort_by = "weight"
template = "album.html"
description = "Spring trip"
[extra]
cover = "DSC_0001_480w.webp"
album_slug = "tokyo-2024"
date = "2024-03-15"
++++++
title = "Shibuya Crossing"
date = 2024-03-15
weight = 1
template = "photo.html"
[extra]
album_slug = "tokyo-2024"
album_title = "Tokyo 2024"
filename = "DSC_0001"
blurhash = "LEHV6nWB2yk8pyo0adR*.7kCMdnj"
alt = "Crowded pedestrian crossing at night with neon lights"
prev_slug = "" # set to stem of previous photo, empty on first
next_slug = "DSC_0002" # set to stem of next photo, empty on last
[extra.exif]
camera = "Fujifilm X-T5"
lens = "XF23mmF1.4 R"
focal_length = "23 mm"
aperture = "f/2.8"
shutter = "1/250 s"
iso = "400"
date_taken = "2024-03-15 10:30:00"
+++prev_slug and next_slug are the file stems of the adjacent photos in album order. Use them in photo.html to build prev/next links: /photos/{{ album_slug }}/{{ next_slug | slugify }}/.
At build time, akskashii processes each photo into multiple resolutions and formats:
photos/tokyo-2024/DSC_0001.jpg
-> static/photos/tokyo-2024/DSC_0001_480w.jpg
-> static/photos/tokyo-2024/DSC_0001_1024w.jpg
-> static/photos/tokyo-2024/DSC_0001_1920w.jpg
-> static/photos/tokyo-2024/DSC_0001_480w.webp
-> static/photos/tokyo-2024/DSC_0001_1024w.webp
-> static/photos/tokyo-2024/DSC_0001_1920w.webp
mysite/
akskashii.toml # site configuration
photos/
tokyo-2024/ # album (directory name = album slug)
album.yaml # album metadata (optional)
DSC_0001.jpg
DSC_0002.jpg
portraits/
IMG_4421.jpg
title = "My Photography"
author = "Your Name"
url = "https://photos.example.com"
resolutions = [480, 1024, 1920]
formats = ["jpeg", "webp"]
exif = true # show EXIF data by default
exif_show_gps = false # strip GPS coordinates by default (privacy)Generated by aks init-album. Fill in what you want, leave the rest blank.
title: "Tokyo, 2024"
description: "Spring trip"
date: "2024-03-15"
cover: DSC_0001.jpg
exif: true
photos:
DSC_0001.jpg:
title: "Shibuya Crossing"
alt: "Crowded pedestrian crossing at night with neon lights"
description: "Shot during golden week rush"
exif: true
DSC_0002.jpg:
title: "Temple Garden"
alt: "Zen rock garden with raked gravel patterns"
exif: false # hide EXIF for this imageEXIF visibility resolves in this order:
- Per-image
exiffield in album.yaml (highest priority) - Album-level
exiffield in album.yaml - Site-level
exiffield in akskashii.toml - Default:
true
GPS coordinates are stripped by default regardless of EXIF settings. Set exif_show_gps = true in akskashii.toml to include them.
Photos render in the order they appear in album.yaml. Any photos not listed in the yaml are appended at the end, sorted by filename.
The album date resolves in this order:
datefield in album.yaml- EXIF
DateTimeOriginalfrom the first photo - Fallback:
1970-01-01
Individual photo pages use the photo's own EXIF date when available, otherwise the album date.
| Command | Description |
|---|---|
aks process -s <source> -o <output> |
Process photos and output Zola content (primary workflow) |
aks init [path] |
Create a new site with default config |
aks init-album <path> |
Generate or update album.yaml for a photo directory |
aks build [-p path] |
Build standalone site to public/ (legacy) |
aks serve [-p path] [--port 8080] [--host 0.0.0.0] |
Serve the built site locally (legacy) |
init-album is re-runnable. It adds entries for new images without overwriting existing metadata.
Note: aks process does not clean up stale output. If you rename or delete a photo, manually remove the corresponding .md file from content/photos/<album>/ and the image variants from static/photos/<album>/.
akskashii separates the image processing pipeline from the metadata output format via the OutputAdapter trait:
pub trait OutputAdapter {
fn write_albums(&self, albums: &[Album], config: &SiteConfig, output_root: &Path) -> Result<()>;
}The pipeline (resizing, EXIF extraction, blurhash) runs the same for all adapters — only the metadata output changes. Currently implemented:
ZolaAdapter— TOML frontmatter with+++delimiters, Zola section/page structure
Planned (see TODO):
HugoAdapter— YAML frontmatter, Hugo directory conventionsGenericAdapter— JSON/TOML dump for custom tooling or non-Zola SSGs
To add a new adapter, implement the trait in src/output/ and wire it to a --format flag in the CLI.
akskashii can also build a complete standalone site without Zola:
aks build
aks serveThis generates HTML directly to public/ using built-in templates.
AGPL-3.0-or-later