sussy baka

sussg

sussg (pronounced sus-gee like Sasuke the guy who commited fratricide in that one Japanese Animation) is a super ultimate static site generator that is honestly just a wrapper for pulldown-cmark and minijinja. If you want a better generator, please use Zola.

If you're still here, then this is a no frills/barebones static site generator. While other SSG's tout bloated features like cdn support, image processing, taxonomies, and decent programming. Realistically, you don't need all that and let's not kid ourselves, there's not gonna be that many people visiting your site.

Well then why not just build out your entire site in raw html? You might ask, which I'll reply with: good question, because well uhhh

features

for who?

Who knows, really. The name came before the project idea, and it kinda became my own personal static site generator. If you want to make a site with very simple, low-cortisol

Install

Nix

sussg exposes itself through nix:

# as a flake input:
inputs = {
    sussg.url = "github:nuttycream/sussg";
};

Or if you want to use sussg in the current shell session:

nix shell github:nuttycream/sussg

Cachix

sussg also has a cache available through Cachix. Add the following to your NixOS configuration to avoid lengthy rebuilds and fetching extra build-time dependencies:

{
  nix.settings = {
    substituters = [ "https://nuttycream.cachix.org" ];
    trusted-public-keys = [
      "nuttycream.cachix.org-1:x8URTEpNkAQpFCf0oW5nPDJGI4Q9E8HtAO66JBjSWlY="
    ];
  };
}

Or if using the Cachix CLI outside a NixOS environment:

cachix use nuttycream

Cargo

sussg can also be downloaded and installed directly from source, though this requires compiling:

cargo install --git https://github.com/nuttycream/sussg

Manual Compile

git clone https://github.com/nuttycream/sussg
cd sussg
cargo install --path .

That should drop a sussg binary on your $PATH. Confirm with:

sussg --help

Init

To initialize the site, run:

sussg init

This should create files/folders in the current directory in this layout:

.
├── config.toml
├── content/      # markdown content
├── plugins/      # re-usable html snippets
├── static/       # images, fonts, anything that needs to be copied
├── styles/       # .css files
└── templates/    # minijinja .html templates

You can use -p some/path to generate into a specific directory. Use the navbar on the left to jump to learn more about a specific folder.

Build

sussg build

Builds everything in content/ into static html and writes it to public/ or wherever your output_dir is set to.

flagwhat it does
-p, --path PATHsite root, defaults to ./
-o, --out PATHoverride the output directory from config
-l, --localforce site_url to /
-d, --drafts BOOLinclude pages with draft = true in their frontmatter

Serve

sussg serve

Builds the site, watches for file changes, and serves the result on localhost:{{port}} with browser auto-reload.

serve always builds in local mode (site_url = "/") and turns drafts on by default. Pass -d false to hide them.

flagwhat it does
-p, --path PATHsite root
-o, --out PATHoverride the output directory
--port PORTport to listen on, defaults to 3030
-d, --drafts BOOLinclude drafts, defaults to true here

The watcher polls templates/, styles/, content/, static/, plugins/, and config.toml for changes. When something changes, the site should rebuild and your browser should auto reload via SSE.

Config

Site wide config settings live in config.toml at the root of your site. Every value has a default, so you only set what you actually want to change.

[general]
url = "/"
output_dir = "public"
drafts = false

[style]
main = ["main"]

[template]
base = "base"

[serve]
port = 3030
drafts = true

A few notes on what these actually do:

general.url is what gets prepended to internal links via {{ site_url }}. Set it to your full URL https://some.site.jpeg/. But both serve and build -l ignore this and force /.

style.main is a list of stylesheet names (without .css) that get linked on every page automatically. Any extra CSS in styles/ is still copied to public/, it just won't be auto-linked unless a page asks for it.

template.base picks which file in templates/ is used when a page doesn't override it.

Content

Anything in content/ ending in .md becomes a page. URL routing works like this:

sourceurl
content/index.md/
content/posts/index.md/posts/
content/posts/install.md/posts/install/
content/doofus/bleh.md/doofus/bleh/

Subdirectories also become sections. Anything under content/posts/ is grouped into the posts section, accessible from any template as {{ sections.posts }}. Same for content/notes/, content/projects/, and so on.

Frontmatter

Each page should declare metadata sussg codeblock to properly be registered. This can be placed anywhere within the page.

```sussg
type = "frontmatter"
title = "installing sussg"
date = "2024-08-12"
description = "how to get sussg working"
draft = false
```

Possible args:

fieldtypewhat it does
titlestringpage title (required)
descriptionstringshort blurb, exposed in templates
authorstringself-explanatory
datestringformat up to you, used for sorting/display
draftboolif true, page is skipped during build unless -d is set
templatestringuse a different template than the configured base
stylesarray of stringextra stylesheets to link (names without .css)
is_archivedboolmetadata flag, exposed via frontmatter in templates

Templates

Templates live in templates/ as .html files and use minijinja. Every template gets the same context:

variablewhat it is
titlethe page's title from frontmatter
contentthe rendered page html
frontmatterthe full frontmatter struct
headingslist of { level, text, id } for building a TOC
sectionsmap of section name → list of pages in that section
most_recentmap of section name → its most recent page
site_urlthe configured general.url (or / in local mode)

site_url is not usually required to be set, it's meant to be overridden and used when your site domain is not root, for example https://nuttycream.github.io/sussg requires it and variables referencing root need to have the {{ site_url }} otherwise url breaks and would resolve to https://nuttycream.github.io/.

An example minimal templates/base.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>{{ title }}</title>
  </head>
  <body>
    <div class="content">{{ content | safe }}</div>
  </body>
</html>

A page can override the template by setting template = "post" in its frontmatter, which would resolve to templates/post.html. Templates can use each other via minijinja's {% extends %} / {% include %} like normal.

Styles

CSS files in styles/ get copied as-is to public/. The [style] main list in your config decides which ones are auto-linked into every page. Pages can ask for extras via the frontmatter styles field.

At the moment, sussg can only support .css files.

Static

Anything in static/ gets copied verbatim to the root of public/. So static/favicon.ico ends up at /favicon.ico, static/models/Astronaut.glb at /models/Astronaut.glb. Reference these with {{ site_url }} prefixed in templates so they keep working at any deploy URL.

Plugins

A plugin is a minijinja template you keep in plugins/. Inside any markdown page you can invoke it with a sussg codeblock, and the block gets replaced with the rendered output of that template.

For example:

```sussg
type = "plugin"
name = "3d_viewer"
src = "models/Astronaut.glb"
alt = "astronaut"
```

This says: find plugins/3d_viewer.html, render it with these args. Inside that template, everything except type and name is available under args:

<model-viewer
  alt="{{ args.alt }}"
  src="{{ site_url }}{{ args.src }}"
  shadow-intensity="1"
  camera-controls
  touch-action="pan-y"
>
</model-viewer>

Plugin templates have the same context as page templates (title, frontmatter, sections, site_url, etc.), plus the args table.

Deploy

GitHub Pages

At the moment, I only know how to deploy with GitHub actions, I'm sure you can infer how to do it on other providers. If you want to add it here, open up a PR please!

I have no marketplace action you can use, though it's pretty straightforward:

on:
  workflow_dispatch:
  push:
    branches:
      - main

permissions:
  contents: read
  pages: write
  deployments: write

jobs:
  build:
    name: build site
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: install sussg
        run: cargo install --git https://github.com/nuttycream/sussg

      - name: build site
        run: sussg build

      - name: upload site files as artifact
        id: deployment
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./public

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

You can pass in any relevant args to sussg build. For example, to build with drafts, a specific folder, and a custom output path.

jobs:
  build:
    name: build site
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: install sussg
        run: cargo install --git https://github.com/nuttycream/sussg

      - name: build site
        run: sussg build --drafts true -p path/to/dir/ -o ./path/to/public

      - name: upload site files as artifact
        id: deployment
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./path/to/public

Nix

You can deploy using nix and a pre-built binary with Cachix:

on:
  workflow_dispatch:
  push:
    branches:
      - main

permissions:
  contents: read
  pages: write
  deployments: write
  id-token: write

jobs:
  build:
    name: build site
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: cachix/install-nix-action@v25
        with:
          nix_path: nixpkgs=channel:nixos-unstable

      - name: Install Cachix
        uses: cachix/cachix-action@v14
        with:
          name: nuttycream

      - name: build site
        run: nix run github:nuttycream/sussg -- build

      - name: upload site files as artifact
        id: deployment
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./public

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

References:

Attribution

Most of the work done here were pulled from examples, but I want to specifically attribute the majority of the functionality to:




The frontmatter can be anywhere, for example here at the bottom of the page, hiding, from YOU! and so it doesnt muddy up the README.md. You can't see what I'm talking about in the docs site, but the GH readme should show exactly what I'm talking about.