No description
Find a file
Maxfield Luke bda33ef628
Some checks failed
ci / test (push) Failing after 2s
pages / build (push) Failing after 1s
pages / deploy (push) Has been skipped
Initial commit
2026-07-06 02:56:57 -04:00
.github/workflows Initial commit 2026-07-06 02:56:57 -04:00
docs Initial commit 2026-07-06 02:56:57 -04:00
example Initial commit 2026-07-06 02:56:57 -04:00
site Initial commit 2026-07-06 02:56:57 -04:00
src Initial commit 2026-07-06 02:56:57 -04:00
.gitignore Initial commit 2026-07-06 02:56:57 -04:00
action.yml Initial commit 2026-07-06 02:56:57 -04:00
build.zig Initial commit 2026-07-06 02:56:57 -04:00
CONTRIBUTING.md Initial commit 2026-07-06 02:56:57 -04:00
LICENSE Initial commit 2026-07-06 02:56:57 -04:00
mise.toml Initial commit 2026-07-06 02:56:57 -04:00
README.md Initial commit 2026-07-06 02:56:57 -04:00
test.sh Initial commit 2026-07-06 02:56:57 -04:00

ypsilanti

minimal static site generator in zig.

example/ is a demo site you can build and serve to see how everything fits together.

install

requires zig (0.14+).

zig build -Doptimize=ReleaseFast
cp zig-out/bin/ypsilanti /usr/local/bin/

-Doptimize options: Debug (default), ReleaseSafe, ReleaseFast, ReleaseSmall. use ReleaseFast for production, skip the flag for development.

usage

ypsilanti build ./site ./output    # build site
ypsilanti serve ./site             # dev server on :3000
ypsilanti serve ./site 8080        # custom port

site structure

site/
├── content/     # markdown files → html
├── layouts/     # page templates
├── partials/    # reusable snippets
├── static/      # copied as-is (css, images, fonts)
└── config       # optional site config

config

title: example.com
url: https://example.com
author: your name
description: site description
theme: darkode
paginate: 10
nav: home=/, posts=/posts/, tags=/tags/, rss=/feed.xml

front matter

---
title: Hello World
date: 2025-01-09
description: post summary for rss
layout: post
tags: linux, software
categories: technology
draft: false
aliases: /old-post/, /legacy/post.html
---

your content here
  • title - page title, available as {{title}}
  • date - includes page in rss feed
  • description - rss item description
  • layout - which layout to use from layouts/
  • tags - comma-separated tags, used for generated tag pages
  • categories - comma-separated categories, used for generated category pages
  • draft - set to true to skip the page
  • aliases / alias - comma-separated local URLs that emit static redirect pages

any key except reserved content, nav_html, and toc is available as {{key}} in templates.

templates

layouts go in layouts/. use {{content}} for the rendered markdown:

<!DOCTYPE html>
<html>
<head><title>{{title}}</title></head>
<body>
  {{> header}}
  {{{toc}}}
  <main>{{{content}}}</main>
</body>
</html>

Template variables are HTML-escaped by default. Variables rendered directly inside href and src attributes are also checked for safe URL schemes. Triple braces render raw HTML only for built-in content and nav_html variables.

partials go in partials/. include with {{> name}}:

<!-- partials/header.html -->
<nav><a href="/">home</a></nav>

markdown

supported:

  • # headers (h1-h6)
  • **bold** and *italic*
  • [links](url) with safe http, https, mailto, anchor, or relative URLs
  • `inline code`
  • fenced code blocks with language class
  • basic syntax highlighting spans for common fenced code languages
  • - unordered lists
  • > blockquotes
  • pipe tables
  • footnotes with [^id] and [^id]: text
  • whole-line shortcodes: figure, youtube, vimeo, and callout

Headings get generated id attributes and a raw {{{toc}}} template variable.

shortcode examples:

{{< figure src="/img/photo.jpg" alt="Photo" caption="A caption" >}}
{{< youtube dQw4w9WgXcQ >}}
{{< vimeo 123456789 >}}
{{< callout type="warning" title="heads up" text="important note" >}}

error pages

create content/404.md for custom 404 pages. works in dev server and most static hosts.

pages are generated with clean URLs: content/about.md becomes about/index.html and is served at /about/.

rss + sitemap

auto-generated on build:

  • sitemap.xml - all pages
  • feed.xml - pages with date: front matter
  • posts/ - dated posts sorted newest first, paginated with paginate:
  • tags/ and categories/ - taxonomy indexes and paginated term pages

set base url in site/config with url:. site/url is still supported as a fallback.

build validates internal href and src links after writing pages and static files. Root-relative links, relative links, and fragment anchors must point to generated output or the build fails.

deploy

ypsilanti ships a GitHub Action, so a full deploy is one uses: line. Copy docs/github-pages.yml into your site repo as .github/workflows/pages.yml, then set Settings → Pages → Source to GitHub Actions. The core of it:

- uses: actions/checkout@v4
- uses: maxf1eld/ypsilanti@main   # pin to a tag or SHA for stability
  with:
    source: ./site               # your site source dir
- uses: actions/upload-pages-artifact@v3
  with:
    path: ./_site

The action builds ypsilanti and your site with no local Zig install needed.

Internal links are root-relative (/about/), so deploy at a root domain — a user/org page (you.github.io) or a custom domain. A project page (you.github.io/repo/) serves under a subpath and will break those links.

manual / other hosts

Build locally and push the output anywhere that serves static files (Netlify, Cloudflare Pages, S3, a plain web server):

ypsilanti build ./site ./docs
git add docs && git commit -m "build" && git push

dev workflow

ypsilanti serve ./site

opens dev server with live reload. edit any file in content/, layouts/, partials/, or static/ and browser refreshes automatically.

tests

./test.sh

contributing

Contributions are welcome. Run ./test.sh before opening a pull request; CI runs the same suite. See CONTRIBUTING.md for more.

license

MIT — see LICENSE.