Rolling my own static site generator
Man this blog was a long time coming. For the past 5 years I’ve always wrote myself little articles, notes and journal entries and I’ve always wanted to have a central repository where I could show them off publicly.
I watch a lot of youtube videos, and youtube essays - and even though I’ve made a few, I don’t feel confident putting myself out there just yet. This is wrong. This is something I want to get better at.
Now we’re here. But the journey has been tough.
Episode 1: html+css (2023)
I made a crappy blog in 2023, using just raw html + css. It was a fun learning experience, but a horrible display of my skills. For some problems:
-
adding new pages is irritating. I need to create the page then update every link on my site. I shouldn’t have to change 2 things every time I want to make a blogpost (its trivially easy, just annoying).
-
styling is also annoying. I use a lot of custom html+css and it’s tedious to update (I have a bunch of repeated styling code, I can change the css well enough - but larger changes involve me editing every single page).
-
I can use blank templates and AI, but the templates become out of date and AI tooling was garbage then. I also wanted to learn instead of rely on AI.
-
Dynamic Theming is super hard.
Episode 2: Astro (2023-25)
If you search up technologies people used for creating custom portolios/blogs, You will see Astro a lot. Even in my local programming club, we have had a few people chat about it, and I’ve learned a lot about using it in different contexts (blogging, CMSes, portfolios) but MAN this was hard to use.
My javascript skills are on the lower-end, and my js framework skills are practically non existent. Astro is good, the documentation is nice, but I felt like I was hitting my head against the wall constantly.
This may just be a skill issue - but trust me. I’ve tried multiple times to get good at Astro. Following youtube tutorials, using AI, using templates - none of it worked for me.
To put it plainly, there was never a point when I grokked Astro. Sure, I can explain to you how hydration, tagging and dates all work together - but if you ask me to add tailwind css to my project, I’ll fail.
Like with Godot or Unity, it’s trivial for me to create scripts to get things running. It’s easy to conceptualize that I have an object, I attach scripts to it, and I change the properties / functionality. For Astro, the framework gets in the way IMO.
Case in point: Dynamic tag routing in Astro. In a typical python program this is trivial.
-
Read through list of documents
-
parse the header metadata (I use regex and pattern matching. I’m lazy.)
-
Get the tag and put the document in a certain bucket
-
Now when the user wants to see elements with a tag, show them the bucket of tags
Just a basic for loop.
Meanwhile in Astro Source
Okay. I stand corrected. It’s actually a lot easier than I thought. But still, I found it to be extremely complex because I’m working with the auxiliary framework and setting it up how THEY want. I don’t understand the reasoning of why they set up the framework this way, the tradeoffs, and how to implement it myself.
I just want to liveblog something and get it out there easily. But I was given an extremely strong tool with hydration and islands. Astro is good, but I could not, for the life of me, understand it.
Episode 3: Sveltekit static site (2026)
I’ve been learning Svelte outside of work for a few months now, and I really like it. I feel extremely productive. I would’ve stuck with it but I ran into the same issue as Astro.
I felt like I was working with a framework, when I really should’ve been making my own.
Finale: This site.
Instead of using the framework, I decided to leverage the strength of templates to take html fragments and combine them to pages.
I did something like this in 2025 for discussdock.
-
Create asciidocuments in /content
-
Create Jinja2 compatible templates in /templates.
-
The main one i use is called base.html. It provides a shell with the header, footer and navigation buttons. It also has my main.css and theme.js.
-
-
Use my main python program manually with "uv run main.py"
-
Call Asciidoctor to convert asciidoc pages to .html in a forloop
-
I do this with a python subprocess command. I basically take the asciidoc and turn it into html fragments that I’ll later use.
-
Use Jinja2 with my html fragments to convert it all to a themed, detailed webpage
-
Write everything to .html files
-
-
-
Deploy
I love how the asciidoc → html → jinatemplate injection → final page pipeline exposes everything to me. I understand exactly why my pages look a certain way.
This was the process of making this generator:
-
Create asciidoc example file
-
Make python program to call asciidoctor subprocess and write to .html
-
Extend by introducing simple css
-
Extend by introducing simple theming and theme switching
-
Get irritated and use AI to get the css and theme switching working better
-
Deploy
Now let’s move onto the index and tag bucket pages. Unlike my posts, these are dynamic (changing each build). For example, I can write my blogpost asciidoc and call it a day, but my index lists all of my articles. Thus, I will need to read through all of the titles and add it to the end. I need to take a baseline, and then iterate over in a for loop.
My solution is ugly. I don’t do pagination or reactive routing. I just hard write every article directly to the page. I do this by reading over every title/tag and just writing it to the index. I don’t even check the date - I sort it by the files last changed on disk.
I also hard write the tag buckets to their own pages too.
-
Run python builder
-
Get the tags from :tags: section
-
Append the title and tags to the indexing pages.
Interestingly, the hardest part was the CSS. I had to use AI for rewriting after an hour of trying. I wanted something simple and straightforward, using 2005-era golden age of web design formatting.
I didn’t want to make a dedicated javascript thing for the themes, so I hardcoded them in css, and I use a processing step to convert my 4 bit palettes to a larger format. I passed over some colors I liked, inspired by some combinations I liked lopsec. I had to change basically all of them because I wanted white text.
I did have to touch some advanced javascript with the theme switching. Instead of using a cookie for the themes, I used a URL hash instead. I had to use AI for this.
I know it’s in bad spirit to do use AI for something like this (this is a side project done for fun, and to show off my skills) - but I’m going to be honest. I was so done with this project, and getting the boxes looking just right was taxing on my sanity.
The image on top is from kiril777 on opengameart.
Why Asciidoc?
I made a bunch of posts in markdown. It worked perfectly fine, but I saw someone mention Asciidoc on HackerNews and I got intrigued.
I’m going to be honest - the change was minimal. I just have the reference documentation up on my second monitor and get to typing. It’s trivial. 99% of the syntax is the same, and when you change its simple stuff like turning hashtag into =
I don’t even use any of the advanced Asciidoc features. I just type in it.
I’ll feel differently as I use this more.
I will say one thing though. The strikethrough formatting is horrendous
strikethrough in markdown = ~~ text ~~
use ~~
striketrhough in markdown = line-through text]
use [.line-through]##
Links are better. Much better.