---
title: "Still blogging"
description: "I published three posts on this blog just in April. Before that, I’ve published 3 posts since May 2020. Going back to freelance work and having an interesting bioinformatics project made me want to …"
image: https://deterministic.space/still-blogging-og.png
url: https://deterministic.space/still-blogging.html
author: "Pascal Hertleif"
date: 2026-04-23
categories: ["meta"]
---

# Still blogging

I published three posts on this blog just in April.
Before that, I've published 3 posts since May 2020.
Going back to freelance work
and having an interesting [bioinformatics project][rastair]
made me want to write again,
and it feels good.
But this blog had to feel a bit nicer first!
This site has been around since 2016[^older],
and it was always just Markdown files in a git repo.
Let's update the toolchain around it as a little spring cleaning for 2026.

[rastair]: https://deterministic.space/rastair.html "Notes on Rastair, a variant and methylation caller"

[^older]: Some of the content is even older, imported from a previous site.

## Hugo

The blog ran on [Jekyll] from its inception until last month.
I chose it because GitHub Pages shipped it by default
and I wanted to publish something.
That worked in 2016,
and I'm glad it's actually still supported today.
But, in 2026, getting Jekyll to build locally
means fighting `bundler`, native extensions,
and a Ruby toolchain I haven't used for anything else in years.
I could publish blindly and just see what I get out of it,
but that's no fun.

[Jekyll]: https://jekyllrb.com/ "Jekyll: Transform your plain text into static websites and blogs"

So, I looked for something else:
Stable, usable, and likely to be maintained for the next years.
[Hugo] looked like a great option.
It's a single binary, one `brew install` away.
You run it, and the site builds in about 60 milliseconds.
The expected content is Markdown with YAML frontmatter,
so that I already had.
If I move to something else in 2036,
I expect a similar afternoon of find-and-replace.

[Hugo]: https://gohugo.io/ "Hugo: The world's fastest framework for building websites"

Of course, I also wanted to make my own theme.
At first I copy-pasted the one I had in Jekyll
but I knew I wanted to take it further.
Hugo's templating language is Go templates.
They have a pipe syntax that looks clean at first,
but some functions don't compose well in pipelines
so you end up wrapping things in parentheses.[^gotmpl]
It gets the job done.

[^gotmpl]: For example, `{{ .Title | truncate 50 }}` reads naturally. But conditionally wrapping output requires nesting `{{ if }}` blocks or calling `printf` with parenthesized arguments instead of piping. Not awful, just occasionally surprising.

A nice thing Hugo has is [render hooks]
that let you customize how individual Markdown elements get rendered
(e.g., links, images, code blocks)
without touching the main templates.
I wish they went further, though.
The table of contents, for example,
is generated as a blob of HTML
with no hook to customize its structure.[^toc]

[render hooks]: https://gohugo.io/render-hooks/introduction/ "Introduction to render hooks in Hugo"

[^toc]: Unless I missed something.
  You can set `startLevel` and `endLevel` in the config, and that's about it.
  I'd love to be able to control the markup or wrap individual entries.

## The theme

The design is loosly based on a personal website I had around 2015.
That one had sidenotes, a serif font, and a lot of whitespace.
When I started the new theme,
I went for something quite clean and polished,
with a lot of focs on typography.
I now use [Piazzolla], a really nice serif font[^piazzolla].

Then, my wife looked at it and said the older one was better.
More nerdy and authentic, less magazine.
She was right.
What made the old site feel like mine
was that the rendered HTML looked a bit like the Markdown source
and was basically just about the content,
in full monospace glory.

[^piazzolla]: By Juan Pablo del Peral at [Huerta Tipográfica], who also made [Alegreya], which I used before.

[Piazzolla]: https://piazzolla.huertatipografica.com/ "Piazzolla: a variable font family with old-style proportional numerals"
[Huerta Tipográfica]: https://huertatipografica.com/
[Alegreya]: https://www.huertatipografica.com/en/fonts/alegreya-ht-pro

### Markdown style

So I combined the two.
I added a CSS `@layer markdown-look`:
Headings get prefixed with `##`,
inline code gets wrapped in backtick markers,
lists use `–` instead of bullets,
horizontal rules render as `---`.
and footnotes get `[^x]` styling.

```css
h2::before {
  content: "## " / "";
  color: var(--md-marker);
}

code::before,
code::after {
  content: "`" / "";
  color: var(--md-marker);
}

/* ... */
```

*Neat little bonus:*
The `/ ""` in the `content` value is an
[alternative text][content-a11y]
so screen readers don't announce the decoration.

[content-a11y]: https://developer.mozilla.org/en-US/docs/Web/CSS/content#alternative_text "CSS content alternative text on MDN"

### Sidenotes

I write a lot of footnotes[^footnotes]
and having them at the bottom of the page
always felt too far away.
Parentheses are too noisy.
[Tufte-style] sidenotes sit right next to the text,
which is where you want the context.

[^footnotes]: tangents, caveats, small jokes, stuff too long to put in parantheses, just like this one here

[Tufte-style]: https://edwardtufte.github.io/tufte-css/ "Tufte CSS: Dave Liepmann's take on Edward Tufte's layout ideas"

On wide viewports (`72rem` and up),
footnotes move into the right margin.
Links that have `title` attribute
also get pulled into the margin as annotations,
showing the domain and the title text.
The table of contents sticks to the left.
And on narrow screens, everything is just one column.

The implementation is about 60 lines of JavaScript.
It runs before first paint and
clones both Hugo's footnote content and links with a `title` attribute
into `<span>` elements next to each reference
and floats them into the margin.

The CSS is actually quite simple
and has been done many times before.
It's just more fun with CSS features from 2026.

```css {.wide}
.sidenote {
  float: right;
  clear: right;
  width: var(--sidenote-width, 12rem);
  /* The negative margin pulls them out of the content column.  */
  margin-right: calc(
    -1 * (var(--sidenote-width, 12rem) + var(--sidenote-gap, 2rem))
  );
  font-size: var(--text-xs);
  color: var(--text-secondary);
}
```

Oh, and there's a also a `.wide` class
to make tables and some code blocks easier to read.

### Colors and dark mode

On big gap in the old blog design was that it was just black and white and pink links.
Now, all colors are in [oklch],
a pretty neat color space that works well when adjusting lightness and blending colors.
My entire accent palette actually comes from one (pink) `--hue` variable.
Super satisfying that I can do this directly in code
and get nice colors from some math.

[oklch]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch "oklch() on MDN"

Dark mode (a new feature)
follows `prefers-color-scheme` by default
with a `[data-theme]` attribute for manual override (currently unused).
Both themes use the same token names, different oklch values.
`color-mix()` handles the subtler bits,
like blending the accent with transparency for link underlines:

```css {.wide}
a {
  text-decoration-color:
    color-mix(in oklch, var(--accent) 40%, transparent);
}
```

There are a few other 2025/2026 CSS features in here
that I'm happy to finally use:
`text-wrap: balance` on headings to avoid orphaned words,
`text-wrap: pretty` on body text,
and `scroll-state()` container queries[^scroll-state]
for showing the table of contents header
only when it's stuck to the top of the viewport.

[^scroll-state]: `@container scroll-state(stuck: top)` landed in Chrome 133 and Safari 18.4
  and as of May 2026 doesn't work in Firefox.
  
### Diagrams

For my recent posts I also felt the urge to include some diagrams.
I've gotten used to adding [Mermaid] diagrams to markdown files
and this blog feels no different.
Adding diagrams via code blocks with annotations also means the source stays just text
and people are you these a lot so I guess they will stay around.

I didn't want to include Mermaid's client-side JS rendering library
since it's quite big and also won't work in feed readers.
So I was happy to see [kroki.io],
which provides a public API that you can post text diagram formats to
(incl. Mermaid, GraphViz, and even Vega)
and get SVGs back.
With a bit of config,
you can call HTTP endpoints from Hugo templates:
A match made in heaven!

[Mermaid]: https://mermaid.js.org/ "Create diagrams and visualizations using text and code"
[kroki.io]: https://kroki.io/ "A unified API for rendering text diagrams as SVGs"

With this, we have diagrams as SVGs directly embedded in the rendered post pages.
But they come with their own styles (at least the Mermaid ones).
No worries. With a little bit of `!important` CSS styling,
I overwrote the colors and fonts
so its looks more "native" to the blog
and also works in dark mode.

I wasnt't sure how to demostrate this but here we go:

```mermaid
sequenceDiagram
    Pascal->>Hugo: Markdown post
    loop every mermaid block
        Hugo->>Kroki: please render
        Kroki->>Hugo: enjoy SVG
    end
    Hugo->>Pascal: HTML
```

## Open Social Stuff

I like the idea of having a simple website
that serves content directly
on a domain that I own.
Feel nicer than to publish
on Medium[^medium], dev.to, Substack,
or some social media channel.

[^medium]: Is that still a thing people use?

This blog has an RSS feed,
and as someone who uses a feedreader daily,
this is important to me.
No need to visit this website if you want to read my content.

Publishing on the "ATmosphere"[^at] was quite simple.
I set up an account for this blog (on [Eurosky])
and then used [Sequoia] which syncs the blog content with it.
It was very easy!
You can now follow this blog [here][bsky-acc] on Bluesky.

One more thing I used from Sequoia is their comments feature.
Since the Bluesky API is public[^twitter-api],
Sequoia comes with a little Web Component
that allows showing all Bluesky replies just like comments.
(I also added support for showing quote posts.)
This means that the best way to reply to my blog posts
is now to reply on Bluesky.

I also looked into publishing the content
as an ActivityPub account,
but in contrast to some tutorials I've seen
it doesn't really work with a static site.
Looks like I need a slightly more dynamic setup
to make it work[^dynamic].

[^dynamic]: This blog is currently hosted on Cloudflare,
  so dymanic ActivityPub stuff as well as hosting my own PDS for AT
  would be [both](https://paul.kinlan.me/adding-activity-pub-to-your-static-site/) [doable](https://github.com/ascorbic/cirrus),
  but outside the "everything is Markdown files" realm,
  so I didn't do anything for this yet.

[^at]: This is what [Bluesky](https://bsky.app/) is built on, the AT protocol.
[^twitter-api]: Like APIs were in the good old days!

[Eurosky]: https://eurosky.tech/
[Sequoia]: https://sequoia.pub/ "Publish evergreen content to the ATmosphere"
[bsky-acc]: https://bsky.app/profile/deterministic.space "This blog on bluesky"

## More writing

It's fun to write!
Maybe right now I'm a bit obsessed with putting on my thoughts into text after not doing it much for a while,
but my hope is that this will last for a while.
I've always been keen on clarifying my thoughts by phrasing them out
and I read a lot of posts from other people every day.

Let me know what you'd like me to write more about
and what you thought of this and my recent posts!

