Site converted to Haunt

By Christine Lemmer-Webber on Tue 05 July 2022

Lo and behold, I've converted the last of the sites I've been managing for ages to Haunt.

Haunt isn't well known. Apparently I am responsible for, er, many of the sites listed on But you know what? I've been making website things for a long time, and Haunt is honestly the only static site generator I've worked with (and I've worked with quite a few) that's actually truly customizable and programmable and pleasant to work with. And hackable!

This site has seen quite a few iterations... some custom code when I first launched it some time ago, then I used Zine, then I used PyBlosxom, and for quite a few years everything was running on Pelican. But I never liked hacking on any of those... I always kind of begrudgingly opened up the codebase and regretted having to change anything. But Haunt? Haunt's a dream, it's all there and ready for you, and I've even gotten some patches upstream. (Actually I owe Dave a few more, heh.)

Everything is Scheme in Haunt, which means, for instance, that this page needed an archive page for ages that actually worked and was sensible and I just didn't ever feel like doing it. But in Haunt, it's just delicious Guile flavored Scheme:

(define (archive-tmpl site posts)
  ;; build a map of (year -> posts)
  (define posts-by-year
    (let ((ht (make-hash-table)))      ; hash table we're building up
      (do ((posts posts (cdr posts)))  ; iterate over all posts
          ((null? posts) ht)           ; until we're out of posts
        (let* ((post (car posts))                   ; put this post in year bucket
               (year (date-year (post-date post)))
               (year-entries (hash-ref ht year '())))
          (hash-set! ht year (cons post year-entries))))))
  ;; sort all the years
  (define sorted-years
    (sort (hash-map->list (lambda (k v) k) posts-by-year) >))
  ;; rendering for one year
  (define (year-content year)
    `(div (@ (style "margin-bottom: 10px;"))
          (h3 ,year)
          (ul ,@(map post-content
                      (hash-ref posts-by-year year))))))
  ;; rendering for one post within a year
  (define (post-content post)
      (a (@ (href ,(post-uri site post)))
         ,(post-ref post 'title))))
  ;; the whole page
  (define content
    `(div (@ (class "entry"))
          (h2 "Blog archive (by year)")
          (ul ,@(map year-content sorted-years))))
  ;; render within base template
  (base-tmpl site content))

Lambda, the ultimate static site generator!

At any rate, I expect some things are broken, to be fixed, etc. Let me know if you see 'em. Heck, you can browse the site contents should you be so curious!

But is there really anything more boring than a meta "updated my website code" post like this? Anyway, in the meanwhile I've corrected straggling instances of my deadname which were sitting around. The last post I made was me coming out as trans, and... well a lot has changed since then. So I guess I've got some more things to write. And also this whole theme... well I like some of it but I threw it together when I was but a wee web developer, back before CSS was actually nice to write, etc. So maybe I need to overhaul the look and feel too. And I always meant to put in that project directory, and ooh maybe an art gallery, and so on and so on...

But hey, I like updating my website again! So maybe I actually will!