a drawn signature made of animated wiggling letters that say Harley Denham

Spindle

A portable, hackable toolchain for static sites
%2
Released
2024 — Alpha
Role
Design
Implementation
Disciplines
Programming
License
FOSS — MIT
Sources
GitHub

Spindle is a self-contained static-site generator.

It emerged from the desire for a kind of self-editing Markdown — what if you could redefine what # did on the fly? Spindle executes on this idea, with templating and content being defined in the same space and markup language, rather than several distinct spaces and structural paradigms.

Spindle's syntax is extensible; you can add new tokens on the fly, define as many variations of elements as you like and built consistent, reusable templating that can even change based on context.

Contents

Syntax and Style

Spindle is designed to live in the non-existent no man's land between the ultra-minimal, like Brian Crabtree's clever but constrained sh, and the ultra-complex, like the very powerful but structurally batshit inflexible Hugo. It also wants to do this while being way cooler than any of them.

Spindle is essentially a very powerful variable substitution system. Its syntax has two major components —

Tokens

If you're a Markdown user, you'll be instantly familiar with what Spindle tokens are. Whenever a non-alphanumeric character, or characters, appears at the start of a line, it's treated as a placeholder for a piece of formatting —

# This is a Heading 1

However, in Spindle, this isn't hard-coded. It's defined elsewhere —

[#] = <h1 id="%0:uslug">%0</h1>

Tokens don't just have to be templating like this either. They can also define an enclosing string for repeated entries — that's how Spindle's Markdown-style lists work, for instance.

Most importantly, they can just be a Lua function. Almost all of Spindle's complex, built-in tokens like partials and inline scripting are built this way.

...and all of them can be overridden.

Blocks

Blocks, on the other hand, are structural helpers for Spindle. They both represent a 'wrapper' around the content, as well as a scope in which declarations exist —

[#] = <h1>%0</h1>
div = <div class="block">%0</div>

# This is a Heading 1

div {
    [#] = <p>%0</p>

    # This will become a paragraph, but only in this block.
}

Blocks are the structural bread and butter of Spindle. While most content pages will just look like a big linear Markdown file, blocks allow for the creation of reusable components.

Creating more complex formatting than simple linear text is simple and, critically, extremely legible and easy to grasp for non-technical content writers.

Architecture

Spindle is a portable executable which hosts a Lua script. All of Spindle's core logic is executed by that script — the executable only provides the Lua runtime and exports a few filesystem functions that Lua isn't capable of performing natively.

Spindle's Lua construction allows for total modularity. Components and functions may be overloaded and modified at any time. In addition to regular templating, Lua can be executed inline to allow for any kind of complex structure.

Spindle's core script can also be vendored into the project itself, to be hacked and modified as needed.

Certain components are actually designed with 'modding support' in mind — for instance, the Spindle markup parser, which accepts a string and returns a syntax tree, is specifically protected internally so that you can overload it with your own. This means you can take any input format you like and, as long as you can conform it to spit out Spindle's syntax tree, build any number of interfaces to different markups and languages without needing to make significant changes to the core.

Everything else, after that, is up to you. Spindle can build websites out of the box, but its design is intended to construct a custom toolchain for every project it's used on.

It's not a CMS or a static site generator you conform your project to — you conform Spindle to your project.