My Eleventy site setup

Table of Contents

    I haven’t written about my website setup in a while, and I thought it’d be nice to compile all the different parts together in one place for easy reference. This post assumes some familiarity with Eleventy, the static site generator I use.

    I don’t mean this to be instructive, but rather just an explanation of how I do things on my site.

    Doodle of a possum in a garbage can, hissing, from the 'don't touch my garbage' meme. There's a balloon tied around the possum.
    this is my garbage


    I think Eleventy is well-suited for my needs: it allows easy layout customization (I have a lot of custom pages), is mostly low-maintenance and ‘easy’ to setup (I don’t know what node is and at this point I’m too afraid to ask, but I managed it), and has enough of a community that I can Google stuff, haphazardly copy and paste things I don’t understand, and have something work.

    I make extensive use of Eleventy data files to store my media diary and other structured content. A bunch of other stuff (my blog posts, digital garden…) are collections. I use a lot of shortcodes.

    I host my code on GitHub, and my site rebuilds itself via Netlify every time I push to master.

    Blog posts

    All blog posts are markdown files within my posts directory. They’re structured like /posts/2024/

    Some of my older posts have dates attached to the file name, which is a remnant of when I used Jekyll.

    Front matter

    I use the post front matter to customize posts. Here’s Weeknotes 10, for example:

    date: 2024-02-05
    title: Weeknotes 10
    excerpt: latest creative things, internet reading, media highlights, misc.
    toc: true
    image: /img/2024/02/wk10_book.jpg
    - weeknotes
    mediaCard: true
    mediaDesc: latest creative things, internet reading, media highlights, misc.
    imageAlt: Ink sketch of a hand holding open a book. From the book are speech bubbles in the form of computer windows.
    • toc: true adds a table of contents. This pulls my H2 headings and sticks them at the top. (Further reading: Table of Contents in Eleventy)
    • I record tags but don’t do anything with them currently.
    • mediaCard: true enables meta tags on the post. By default, I don’t use these—if you link to my site on Mastodon, for example, there won’t be any kind of preview. It wasn’t until very recently that I’ve started enabling this on a per-page basis.
      • mediaDesc and imageAlt fill out the meta tags.

    Custom CSS

    I apply custom styles to individual posts as needed. Creative pursuits, for example:

    date: 2024-02-06
    title: Creative pursuits
    excerpt: things I want to do
    customStyle: smol

    The customStyle property adds smol.css, which adjusts my heading styles to be, well, smol. (Further reading: Small headings.)

    I use this for my one-off custom styling as well. For example, Weeknotes 9 is a comic, and adds weeknotes-9.css to handle that styling.

    Overriding defaults

    My Media Recap 2023 post is completely custom—different layout, colours, font, etc. I override my default site layout by setting layout: media-2023.liquid in the front matter.

    A sample blog post, with a dark brown background and yellow title text.
    my default site styling
    My Media Recap post, which has a light orange background and orange heading text.
    custom post styling


    I use a bunch of shortcodes in my posts, to make writing everything in markdown more bearable.

    For example, most of my images use a figure shortcode, rather than the default markdown syntax of ![alt text](image.jpg). In the post markdown, I’ll write:

    {% include 'figure.liquid' 
    src: '/img/2024/02/listening_room-light.jpg'
    alt: "Web page showing a vector illustration of a room with a turntable and records displayed on the wall."
    caption: 'the listening room'
    imgClass: 'screen'
    figClass: 'breakout'

    Which outputs this HTML:

    <figure class="breakout">
    <img class="screen"
    alt="Web page showing a vector illustration of a room with a turntable and records displayed on the wall.">

    <figcaption>the listening room</figcaption>

    I wrote about this way back in Markdown Optimizations.

    Shortcodes are useful for components that I use a lot because I’ve broken things in the past whenever I tried changing my markup or styling, and writing the raw <figure> HTML hurts me. (Writing these shortcodes also hurts me, but I’ve accepted it as part of the limitations of markdown.)

    My shortcodes include:

    • figures
    • asides
    • callouts
    • footnotes

    Other collections

    Digital garden

    My digital garden is much like my blog except it has some additional front matter properties:

    • date to mean the update date; datePublished for publish date
    • epistemicStatus to indicate my level of confidence/effort in something

    This section of my site is admittedly neglected though.


    My sketchbook is made up of normal blog posts. I’ve previously pondered structuring this as a JSON file as well, but decided against it.

    My 'sketchbook' page, which displays sketch thumbnails in a 3-column grid.
    my sketchbook

    I think this is an imperfect setup, but I don’t currently draw enough to warrant overhauling it. My ideal setup would involve less friction to adding stuff, the option for works to exist in multiple collections (e.g. a movie study I do can exist in either ‘movie studies’ or ‘2024 sketches’), and more layout options.


    My about page is a collection of posts, which each represent one of my ‘personas.’ I wrote about this in: About Me* (* multiple versions of me).

    Web page screenshot of a window formatted to look like a messaging client. On the left sidebar is a list of contexts: 'anhbot', 'artist', 'personal, and 'professional', all with different avatars. The right side is a chat window for 'Personal', where there are a couple of messages of me introducing myself, written in informal language.
    my about page

    Media diary

    I track four media types: film/tv, music, games, and books.

    I use data files (i.e. JSON files) to store most of my media: watched.json, books.json, music.json. This works well because my media log is consistently structured, and each entry (a book, movie, etc.) is short. My games collection is a collection of posts.


    Here are two example entries for my watchlist:

    "title": "The Grand Budapest Hotel",
    "date": "2024-02-10",
    "category": "movie",
    "rating": 5,
    "poster": "the-grand-budapest-hotel",
    "review": "perhaps, the perfect movie. i've been listening to the soundtrack a bunch lately",
    "rewatch": true,
    "favourite": true
    "title": "Only Murders in the Building (season 3)",
    "date": "2023-11-27",
    "category": "television",
    "rating": 4,
    "poster": "only-murders-in-the-building",
    "review": "delightful",
    "url": "/media/watch/only-murders-in-the-building"

    Currently, I store more information than I actually display—the category (a movie or tv show), and whether I saw it in theatres or not. Eventually, I would like to add filters/sorting to my list.

    JSON works well here because the structure is consistent. To add a new entry, I copy a previous entry, paste this at the top of the file, and edit it. While editing JSON isn’t exactly pleasing like using a GUI, it’s low-friction enough that it’s not a burden. I don’t need to remember my structure, because I can just copy and paste old entries.

    In the rare cases where I want to expand on a particular item, I create a separate post for it—e.g. my Only Murders example above has a url field that links to its own post (which, in turn, uses a custom bloop-post.liquid layout).


    My reading list is largely the same as my watchlist.

    "title": "A Psalm for the Wild-Built",
    "author": "Becky Chambers",
    "format": "fiction",
    "date": "2023-07-14",
    "cover": "a-psalm-for-the-wild-built.jpg",
    "review": "mmmm I enjoyed many things about this. It’s quite philosophical at times but it was the kind of optimistic, sincere thing I needed to read.",
    "excerpts": [
    "text": "Sometimes, a person reaches a point in their life when it becomes absolutely essential to get the fuck out of the city."

    An optional field I have is excerpts, for saving quotes. Like with my watchlist, I plan on adding filters eventually.

    A book entry, featuring a quote displayed below the review.
    a book with a quote


    This is the simplest list:

    "title": "I Wish You Love",
    "artist": "Laufey",
    "album": "Typical of Me",
    "cover": "laufey_typical-of-me.jpg"


    This media type is an exception: it’s stored as a collection of posts. Unlike my other media types, I usually have more to say about the games I play, as well as images to add, so JSON isn’t as fitting.

    Here’s the post front matter of Stray, for example:

    title: Stray
    platform: PC
    datePlayed: 2022
    status: complete
    favourite: true
    - single-player
    - atmospheric
    - adorable
    gameLinkText: Steam
    image: /img/2022/07/stray_midtown.jpg
    • The datePlayed field takes freeform text instead of an actual date, because games are played over a period of time (unlike movies), and usually don’t have a definitive completion date (unlike books). I can enter things like since 2022 or on and off or whatever.
    • I half-heartedly add tags, but this is not consistent at all. (Yeah, yeah, eventually I will add filters).

    Other data files

    I also use data files for:

    Basically, anything that is structured and doesn’t involve much writing, I stick into a data file.

    Custom pages

    Custom pages use a different layout than the default. For example:

    • A normal page: Meta, which uses the default post.liquid template.
    • A custom page: The listening room, which uses the listeningroom.liquid template.

    Whenever I want to make something custom, I create a new whatever.liquid file and stick it in my /_includes/ directory, and its corresponding CSS file in /css/.


    I have a lot of custom pages, and I also redesign my site quite often. (Is once a year often?)

    While I don’t have older versions of my site available, I do like to keep around my old custom pages, particularly if I’ve written about them. Whenever I change my homepage, I move the contents of the last one to a new page that exists independent of the current site design. (See: Past Designs.)

    For layouts that gets thrown into the archive dungeon where they will never see the light of day again, I chuck them into an archive subdirectory within /_includes/.


    I try to strike a balance between low-maintenance and project-based image organization.

    • By default, I organize images by date added: /img/2024/02/image.jpg for any images in my February 2024 blog posts, for example.
      • This is how WordPress media gets sorted, which I think works well. I don’t have to think about what folder a random blog post image goes into.
    • My media diary images (except games) go in their own project folders; e.g. /img/watchlist/movieposter.jpg, /img/music/cover.jpg. This makes them consistent to refer to.
    • Other specific projects go in their own folders, such as /img/4koma/ for my homepage comics.

    I need to figure out image processing at some point this year. This is probably the most glaring flaw with my website.


    These days, I prioritize ease-of-maintenance over efficiency. I manually add items to my media diary, manually track down images, manually rename files. I’ll copy and paste things before I build some kind of reusable template. An app can be a home-cooked meal. I used to feel like I was doing things Wrong or Suboptimally, compared to Real Developers, but nowadays I feel more confident in what I’ve built here. My website is simply mine, and I love it.