Skip to content

About

StupidGreen – A stupid simple static site generator

Topics

Resources

Stars

10 stars

Watchers

1 watching

Forks

Latest commit

 

History

27 Commits

Folders and files

Repository files navigation

StupidGreen — A fast static blog generator built on top of Supranim
Compiled • Lightweight • Fast • 👑 Written in Nim language

nimble install stupidgreen

😍 Key Features

  • 🔥 Compiled, extremely lightweight, super fast!
  • Markdown support for writing content with YAML frontmatter
  • Blog capabilities with support for tags and categories
  • Support for pages and nested structure (pages/projects/x.md to /projects/x)
  • RSS/Atom feed + sitemap.xml + llms.txt generation
  • Lazy loading of iframes, images and other media
  • Search functionality with support for fuzzy search and search suggestions
  • /llms.txt from pages/llms.md (LLM-friendly plain text)
  • Reading time & body-derived excerpts with "Continue reading" links
  • OpenGraph Image generation for social media sharing
  • Easy to extend with custom CSS and JS

About

StupidGreen is a static blog generator written in Nim. It takes a directory of Markdown files and generates a fully static website, powered by Supranim, Tim Engine, Marvdown and Boogie.

🚀 Getting Started

stupidgreen new my-blog && cd my-blog

stupidgreen post "Hello World"   # create a new post
stupidgreen run --sync           # development server with live reload
stupidgreen build .              # generate the static site into `_build/`

StupidGreen project structure

my-blog/
├── stupidgreen.config.yaml      # site configuration
├── posts/                   # blog posts (title, date, tags, draft, ...)
│   ├── index.md             # homepage intro (blog index) when no pages/index.md
│   └── hello-world.md
├── pages/                   # standalone pages, mapped to their URL path
│   ├── index.md             # homepage intro, rendered above the post list
│   ├── about.md             # /about
│   ├── llms.md              # /llms.txt (plain text)
│   └── projects/
│       ├── index.md         # /projects
│       └── demo.md          # /projects/demo
├── assets/                  # optional `style.css` override
└── themes/                  # Tim themes (see Themes below)
    └── default/             # built-in theme, seeded by `stupidgreen new`
        ├── theme.yaml       # theme manifest (name, version, author, ...)
        ├── layouts/         # page layouts (`base.timl`)
        ├── views/           # page views (`index`, `post`, `page`, `tag`, ...)
        └── partials/        # reusable snippets (`header`, `post-cards`, ...)

Themes

StupidGreen renders pages with Tim Engine templates organized into themes. Every project has a themes/ directory; the active theme is selected with the top-level theme key in stupidgreen.config.yaml (defaults to "default"):

theme: "my-theme"

Each theme lives in themes/<name>/ and starts with a theme.yaml manifest:

name: "my-theme"
version: "0.1.0"
author: "Jane Doe"
url: "https://example.com/my-theme"
license: "MIT"
description: "A minimal theme that only restyles the homepage"

Views go in views/, layouts in layouts/, reusable snippets in partials/. The built-in default theme provides layouts/base.timl, views/{index,post,page,tag,category,search}.timl (plus views/errors/) and partials/{header,post-cards,pagination}.timl.

A theme may override only the templates it cares about: anything missing from the active theme falls back to the built-in default theme at render time. This applies to views, layouts and @included partials alike, so a one-file theme is fully functional.

Example 1 — restyle the homepage

Create a theme that only replaces the blog index. Every other page keeps rendering from default:

themes/minimal/
├── theme.yaml
└── views/index.timl
@include "header"
div.container.my-5
  h1.display-4: $this["config"]["metadata"]["title"]
  p.lead: $this["config"]["metadata"]["description"]
  if $this["intro"] != "":
    article: $this["intro"]
  @include "post-cards"
  @include "pagination"
# stupidgreen.config.yaml
theme: "minimal"
stupidgreen build .   # index.html uses minimal, posts/pages use default

The @include "header" / @include "post-cards" lines above resolve to minimal/partials/ first and fall back to default/partials/ when the minimal theme doesn't ship them.

Example 2 — override a partial

Partials are shared snippets, so overriding one affects every view that includes it. To render your own post cards, copy the original as a starting point and edit it:

mkdir -p themes/minimal/partials
cp themes/default/partials/post-cards.timl themes/minimal/partials/
# themes/minimal/partials/post-cards.timl
div.post-list
  for $post in items($this["posts"]):
    article.mb-4
      h2.h5: $post["meta"]["title"]
      a href=$post["url"]: "Read more →"

Example 3 — full custom layout

Override layouts/base.timl to take over the whole HTML shell (head, CSS, navbar, footer). Views stay compatible as long as the layout renders the view output where base.timl does:

mkdir -p themes/minimal/layouts
cp themes/default/layouts/base.timl themes/minimal/layouts/

Notes

  • Missing themes/default/ files are seeded automatically on new, start and build without overwriting your customizations, so old projects upgrade themselves on first run.
  • An unknown theme name fails fast and lists the available themes, e.g. Active theme not found: nope. Available themes: minimal, default.
  • In development (start --sync) theme files hot-reload in the browser.

Post front matter

---
title: "Hello World"
date: 2026-01-15
tags: [nim, blogging]
categories: [tutorial]
author: "George Lemon"
excerpt: "Optional custom excerpt"  # overrides the auto-generated one
cover: "/assets/cover.jpg"
draft: false
---

Pages

Any .md file in pages/ becomes a standalone page at its path. index.md is reserved for the first page of a directory (pages/projects/index.md → /projects). The homepage always renders the blog index (index.timl): it shows the intro from pages/index.md (or posts/index.md) above the list of post cards.

Note: page files under reserved route paths (/posts/*, /page/*, /tags/*, /categories/*, /search, /feed.xml, /sitemap.xml, /llms.txt) are shadowed by those routes.

Configuration

stupidgreen.config.yaml supports metadata (title, description, url, author), appearance (theme, container widths), header (search, notification), content (reading time, excerpt length, read-more label, lazyload), pagination (per_page), feed (kind rss/atom, limit) and navbar/footer links.

❤ Contributions & Support

🎩 License

StupidGreen | AGPLv3 license. Made by Humans from OpenPeeps.
Copyright © 2026 OpenPeeps & Contributors — All rights reserved.

About

StupidGreen – A stupid simple static site generator

Topics

Resources

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

Generated from openpeeps/pistachio