luasmith is a small, simple, and flexible static site generator that is similar in design to Metalsmith, but much smaller because it's built on top of Lua and C instead of JavaScript and Node.js. Example sites are: here and here.
- Seamless relative links between Markdown files
- Link checking
- Syntax highlighting
- Zero run-time dependencies (and < 500 KB!)
See the tutorial for more, but here's an example that converts Markdown to HTML and adds the page's title to the resulting HTML:
-- Minimal HTML template (used below)
local outer = [[
<html>
<head><title><%= title %></title></head>
<body><%- content %></body>
</html>
]]
-- Read content/*.md, convert to HTML,
-- apply template, write to out/*.html
return {
readFromSource("content"),
processMarkdown(),
highlightSyntax(),
applyTemplates({ { "%.html$", outer } }),
checkLinks(),
writeToDestination("out"),
}Most of the heavy lifting in luasmith is done by md4c (patched for relative links), Lua, etlua, and Scintillua.
To get a feel for luasmith, either read over the design or go through the tutorial.
Note that luasmith is still an experimental project, subject to breaking changes. If you like the idea of luasmith, let me know and I can put some work into stabilizing and polishing it--for now, I'm assuming I'm probably the only person writing plugins.
There are multiple builds of luasmith available from the releases page:
- Statically-linked, native Linux build:
luasmith-*-linux-x86_64.tar.gz - Windows build:
luasmith-*-windows-x86_64.zip - "Actually Portable Executable" build (using Cosmopolitan) that should run on Windows, macOS, Linux, and most BSDs:
luasmith-*-universal.zip - There's also a source archive that actually includes submodule code (unlike GitHub's automatic source archives)
To create a minimal blog:
- Download binary package or clone and compile with
make - Create an input directory named
content/ - Add
content/site.luareturning a table containingtitle(site title) andurl(root URL for the site--used for RSS) - Add Markdown files (with
title,description, anddatein frontmatter) - Run
./luasmith blog(this will read fromcontent/and output toout/) - Open
out/index.htmlto view the site - Optionally, upload it somewhere!
For step 3, this Lua snippet can be used for a site.lua file:
return {
title = "a website"
url = "https://a.site/"
}For step 4, use this Markdown file as a template (it uses YAML frontmatter):
---
title: Title of the post
description: Short description of the post (for the Atom feed).
date: 2025-04-22
---
# Post heading
Content goes here. Note you can [link to other posts](foobar.md).Built in themes:
blog: a minimal blog theme (example site)md2blog: an opinionated (and slightly less minimal) blog theme, following the structure of md2blog (example site)
luasmith is designed around the concept of a "theme", which is basically a processing pipeline, probably including some templates (and perhaps static assets). You run the tool by providing either the path to a Lua script or the name of a built-in theme:
./luasmith theme.lua
For a built-in theme you only supply a name (the actual scripts themselves are embedded into the binary, but are present in the themes directory of this repository):
./luasmith blog
After pointing it to a theme, it's completely up to the theme what happens next, but all built-in themes do the following:
- Enumerate files in the input directory (named
content/by default) - Process Markdown (and frontmatter) for
*.mdfiles - Create a root page (and possibly keyword index pages too)
- Apply templates (using etlua)
- Write everything to the output directory (named
out/by default)
Note that the built-in templates assume Markdown files contain metadata in frontmatter that includes title, description, date, and optionally keywords. See the example/content/ directory for examples (using both Lua and a subset of YAML).
If you want to customize the site's appearance or functionality, just copy an existing theme directory from this repository and start modifying the templates and/or Lua script.
See docs/tutorial.md for a tutorial that starts from scratch with a trivial pipeline and builds it up into a simple blog theme.
See docs/api.md for detailed information on helper functions, processing nodes, etc.