Taxonomies in Gutenber 0.4

I finally have categories in my sidebar!

This comes from the move to Gutenberg 0.4, with its new taxonomies setup. Getting it migrate took a bit figuring out so I thought I would document it here.

Unlike earlier Gutenberg, which had the predefined taxonomies category and tags, Gutenberg 0.4 allows you to define whatever taxonomies you want. The hierarchy goes like this: At the top you have a list of taxonomies. Each taxonomy consists of a name and a few other options. categories would be a taxonomy with the name categories. Then each taxonomy itself has a list of taxonomy items. Like the categories taxonomy can contain the taxonomy items Webdev and Books.

To setup taxonomies in 0.4 the first step was to define taxonomies in config.toml file. The only taxonomy I used was categories, so I defined it like this:

[[taxonomies]]
name = "categories"
rss = false

Once I had my one taxonomy, categories, defined I needed to update the front matter on all my pages. Where before there was just a category key you could set, there is now a taxonomies section. On this post it looks like this:

[taxonomies]
categories = ["Webdev"]

Categories is now also a list because you can assign multiple taxonomy items in the same taxonomy to a page, like tags used to work. Mappings between a taxonomy items and pages is always many-to-many. You do not need to define taxonomy items, Gutenberg creates the for you based on when you assign them to pages.

The next step was to update the page.html template for the new taxonomies. Where page used to have a category key, it now has a taxonomies key, which is a HashMap from the name of the taxonomy to a list of the names of the assigned taxonomy items. So on this post it looks something like this (expressed in JSON):

"page": {
  "taxonomies": {
    "categories": [
      "Webdev"
    ]
  }
}

You can still use the get_taxonomy_url to get a url to the page for a specific taxonomy item. It takes two parameters: kind, which is the name of the taxonomy; and name, which is the name of the taxonomy item. So you get a link to the page for the Webdev taxonomy with: get_taxonomy_url(kind="categories", name="Webdev").

I updated the post header to this:

<header>
  <h2>{{page.title}}</h2>
  <div class="post-info">
    Date: {{page.date}}
    {% if page.taxonomies.categories %}
      | Category: <a href="{{get_taxonomy_url(kind="categories", name=page.taxonomies.categories[0])|safe}}">{{page.taxonomies.categories[0]}}</a>
    {% endif %}
  </div>
</header>

I check if there are any categories assigned to the post, and if there are I show the first one as a link to the page for that category. This design means I can only show one category per post, but I figure it would do for now.

The old hard coded category.html template is gone in 0.4, so the next step was to make templates for the categories taxonomy. Each taxonomy gets two templates now, in a folder named after the taxonomy. The two templates are:

  1. list.html. This is the template for the entire taxonomy, with access to a list of taxonomy items. You can see how it looks like for my categories taxonomy here.
  2. single.html. This is the template for a single taxonomy item, like Webdev. You can see what it looks like for Webdev here. It is also what the Webdev at the top of this post links to.

The list.html template get passed in a global variable called terms, which is a list of taxonomy items. Each item consists of the name of the item, the slug for the item, the permalink for the item and pages, a list of pages that has that taxonomy item assigned. My list.html for categories is quite simple. The main component are two for loops that loop through each taxonomy item in the taxonomy and then through each page in the taxonomy item:

<ul class="categories-list">
  {% for term in terms %}
    <li>
      <a href="{{term.permalink}}">{{term.name}}</a>
      <ul>
        {% for page in term.pages %}
          <li>
            <a href="{{page.permalink}}">{{page.title}}</a> - {{page.date}}
          </li>
        {% endfor %}
      </ul>
    </li>
  {% endfor %}
</ul>

The single.html templates gets passed a term variable, which is the taxonomy item being rendered. My template is basically just replicating my index.html template but now it loops through the pages in the taxonomy item.

Finally, I got to the reason for this entire migration: a list of categories in the sidebar. Gutenberg 0.4 adds another function to templates: get_taxonomy. It takes one argument, kind, which is the name of the taxonomy. It returns a Taxonomy object with two fields: kind, with details about the taxonomy from the config.toml file; and items, a list of taxonomy items. With this function you can access the details of a taxonomy anywhere. I updated my sidebar template like so:

{% set categories = get_taxonomy(kind="categories") %}
<h2>Categories</h2>
<ul>
  {% for category in categories.items %}
    <li>
      <a href="{{category.permalink}}">{{category.name}}</a> ({{category.pages|length}})
    </li>
  {% endfor %}
</ul>

And so, at long last, a list of categories in the sidebar!

Gutenberg short code for making columns

One of the things I like about Gutenberg (the static site generator used for this blog) is the support for short codes. Short codes are essentially tiny Tera templates you can call in the markdown files for the content. This immediately lead me to look for a way to make short codes for multiple columns of content.

My first attempts looked something like this:

{% columns() %}
{% column() %}
Content in the left column
{% end %}
{% column() %}
Content in the right column
{% end %}
{% end %}

It didn't work. Turns out the short code parser in Gutenberg doesn't support nested short codes. The reason I wanted to nest two short codes is that the essential bit in embedding some columns in the content is that you need two levels of divs: An outer div as a container for the columns, and inner divs wrapping each column.

So, I was stuck. Later, when browsing the Tera docs for an unrelated reason, I was that it has a split method. That gave me an idea. I don't really need an inner short code, I just need a way to tell apart the content for different columns. What I could do is have one short code that splits the body of the short code based on some specified string.

The use of the new columns short code looks like this:

{% columns() %}  

Content in the left column

[[gutter]]

Content in the right column

{% end %}

It splits the body into columns any time it comes across [[gutter]]. One weakness of this is that there is no way to escape [[gutter]] so you can't write about it in a column. There is also no way to specify different column sizes. The code for the short code ended up being short and sweet:

<div class="columns">
  {% set cols = body|split(pat="[[gutter]]") %}
  {% for col in cols %}
    <div class="column">
      {{col}}
    </div>
  {% endfor %}
</div>

Then all that is needed is some CSS to layout the classes. Here is an example using flexbox to be compatible with IE11:

$gutter: 1rem;
$min-viewport-size: 600px;

.columns {
  display: flex;
  flex-direction: column;
}

.column {
  margin-bottom: $gutter;
  flex-grow: 1;
  flex-basis: 0;
  &:last-child {
    margin-bottom: 0;
    margin-right: 0;
  }
}

@media (min-width: $min-viewport-size) {
  .columns {
    display: flex;
    flex-direction: row;
  }
  
  .column {
    margin-bottom: 0;
    margin-right: $gutter;
  }
}

It uses two variables:

  • $gutter: Space between column.
  • $min-col-size: Min viewport width for switching from single column to multi column mode.

If IE11 support doesn't matter, then one could, of course, do something slick with CSS grids:

.columns {
  display: grid;
  grid-gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

That is a lot less CSS to write. This one spills columns over onto the next row to avoid them being narrower than 260px. It end up looking like this:

Bacon ipsum dolor amet leberkas ham beef ribs bresaola drumstick frankfurter cow tail. Sirloin cow picanha short loin short ribs turkey prosciutto landjaeger brisket cupim tail pig strip steak. Alcatra turducken meatloaf picanha, venison chuck pork chop ham hock. Strip steak sirloin pork chop biltong. Picanha chuck jowl turkey, doner salami ground round corned beef cow tri-tip ham brisket biltong.
Burgdoggen strip steak frankfurter tenderloin capicola, sirloin ball tip andouille tri-tip rump chicken. Shankle pork belly boudin, turducken jerky andouille bacon tenderloin ham hock capicola jowl filet mignon bresaola short loin. Bacon meatball cow sausage meatloaf. Chicken capicola cow shank frankfurter.
Spare ribs alcatra short ribs doner drumstick biltong ribeye pork chop ball tip frankfurter picanha pork loin short loin tail pancetta. Picanha ground round spare ribs pork belly landjaeger burgdoggen bresaola salami. Pig hamburger strip steak short loin doner. Short ribs t-bone shankle kevin corned beef. Fatback strip steak meatloaf, short loin ground round pancetta sirloin landjaeger. Ham chuck pig andouille ball tip kielbasa cupim sirloin jowl meatloaf chicken shankle.

The Peter Principle of POVs - and why Robert Jordan was great

There is something known as the Peter principle which basically is the idea that people get promoted to their level of incompetence. When someone is competent at what they do they are rewarded by being promoted to a new position. If they are still competent at what they do in their new position they get rewarded with a promotion again. This keeps happening until they get promoted to a job they are not good at. That is when the promotions stop and that is where they stay.

There is a similar pattern that can be observer in the use of Points of Views in books, especially in epic fantasy series. Juggling multiple POVs is tricky. Handling the different plot threads and POV switches without ruining the flow and pacing of the story telling is a challenge. It seems to me like there are many fantasy authors that keep adding POVs until they can't juggle them anymore.

A prime example of this is Robert Jordan's Wheel of Time series. That is a series that by the end was drowning in POVs. It is a common criticism of the Wheel of Time series that it had too many POVs. But this post is not a complaint about how Robert Jordan had too many POVs. Rather, I want to highlight how well he did, and how many POVs he was juggling before he became overwhelmed. I will try to avoid spoilers as much as possible.

Many authors seem to struggle once they go beyond three POVs. Robert Jordan was successfully juggling fifteen in the middle of Wheel of Time. I thought I would take a moment to see what he was doing that let him juggle so many POVs so well. The Robert Jordan rules of writing POVs, if you will. To be clear, the these are my thoughts on what he did. I don't say he would agree with me.

I must start with a couple of disclaimers/clarifications:

  1. Robert Jordan dealt with POVs differently in prologues/epilogues as compared to the main chapters in the book. In the prologue/epilogue He would often drop in to some completely unknown POV in order to give the reader some piece of information in order to set something up or foreshadow something. I am going to ignore this and focus on how he dealt with POVs in the main chapters of the books.
  2. He broke all the rules I will lay out here in one instance or another, more so in latter books in the series, probably because it became harder to keep to them when the number of POVs grew so great.
  3. Due to Robert Jordan's untimely passing the final three books were finished by Brandon Sanderson. How to portion out credit/blame for those books is something I won't touch upon.

So, without further ado, let’s get started with Robert Jordan's tricks of writing POVs.

Robert Jordan used third person limited narrator in his Wheel of Time. This means that, even though the narration was in third person, it would be limited to the kind of information the POV had. He would also color descriptions based on this. Like descriptions for a blacksmith's POV would include detail about the quality of the metalworking of the tools people were using, or the solider would notice if someone's sword had been properly cleaned and maintained. While Robert Jordan had his own voice as an author, he would flavor it differently for different POVs, in descriptions, words, thoughts and deeds.

He is also not mechanical in how he switches between POVs. Some authors mechanically switch to a new POV every chapter, whether it makes sense or not. Robert Jordan would be a lot more dynamic than that. Often, he would keep to the same POV for many chapters in a row, while in other situations he would switch POV many times in a chapter. This also has an interesting effect on the tempo of the storytelling. Staying with one POV for a long time is a more leisurely pace, while constant switching would feel more hectic. He would often switch POVs more towards the climax of a book. This would partially be because of the obvious reason that various storylines were converging, but it would also give the climax more tension, make it feel like more action.

Another thing that Robert Jordan does, that helps more the more POVs and POV-switches there are is that time is strictly increasing. What I mean by that is that time in the story is always moving forward, no matter where or how the POV switches. Every event described happens after the pervious event. For POV-switches this means that whatever the next POV after the switch sees or does happens after whatever the previous POV, from before the switch, did or saw. By avoiding going backwards in time, or even sideways, where the same time point is described from two different POVs, he greatly eases the readers ability to keep separate POVs in sync. Besides helping to keep the POVs in line it also helps keep the story moving forward. There is always momentum. Sadly, this rule completely falls apart in the last three books, which were originally supposed to be one book, but got split up into three. The split ended up completely messing up the timelines. Not just does this hurt especially bad with how many POVs there were by then, but because time starts flowing at different rates in different parts of the world due to "plot-reasons". Having abandoned strict time just before time gets wonky made things a lot worse.

Robert Jordan uses strict time and POV switches in a clever way to avoid too big time jumps but at the same time to avoid dead time. Strictly increasing time doesn't prevent time jumps if the jumps are forward in time. Robert Jordan often did time jumps between books in Wheel of Time but tried to avoid very big ones in the middle of books. This can be a problem in this sort of medieval fantasy book because there is a lot of dead time while characters are travelling between location, mostly by ship or horse. Robert Jordan uses POV switches to mask this. For example: some POV heads off with a ship on a trip that will last a week. He masks this time by switching to some other POV and follow that for a week and then switch back once a week on time has passed.

Related to how Robert Jordan handles dead time is how he switches between plot threads. Some authors, when switch plots threads, leave the previous plot thread on a cliffhanger. Cliffhangers on plot thread switches in books are like jump scares in movies. They reek of desperation. A good horror movie does not need jump scares to be scare. A good book does not need cliffhangers on switches between plot threads to keep the reader hooked. Robert Jordan usually stuck with the same plot thread for several chapters in a row, only switching away when the plot thread had reached some sort of resolution or at least a pause. This made each set of chapters following a single plot thread feel like a short story.

One of the most important things Robert Jordan did to manage so many POVs was to introduce the character before the character was introduced as a POV. By having an existing POV get to know something about a new character before that character becomes a POV the reader also starts the new POV with some notion of how the new POV fits into the story. This also made plot lines branch out from one line in a tree type fashion, rather than dumping a bunch of unrelated plot lines on the reader and hoping the reader keeps them straight. Now, Robert Jordan did have different ways of introducing new soon-to-be POV characters. The most straight forward way was to have existing POV character meet and interact with a new character, and then, later, switch to that new characters POV. Another way he did it if the characters couldn't meet was to have an existing POV character hear about some new character before that new character became a POV. If he wanted to keep the new character mysterious he would have an existing character do something somewhere and then switch to a new POV watching the existing character covertly. That way there would still be some tie to an existing character to keep the branching structure in place but keep the reader in the dark about the new POV.

To help smooth over POV switches Robert Jordan does something I call bridging. By this I mean that he keeps the thread of events ongoing across POV switches by starting off new POV after the switch following on from the last event of the old POV from before the switch. Let me give an example to make it clear what I am talking about. We are following POV character A and something happens and as a result the character decides to run off to deal with it. At this point the POV switches to another character B. It starts with POV character B reflecting on having just seen character A run off and continues with what B does after that. Because of strictly increasing time after the switch to character B cannot involve B seeing A run off, because that already happened for POV A, but it can still tie in to it by B reflecting on it. This way even though the POV switches, the chain of events remains unbroken, by having the new POV start of from where the previous POV left of. Robert Jordan mainly used this trick in two sorts of situations. One was when he did a lot of POV switches in one chapter between different POVs involved in the same events. The other is when switching to a new, never before seen, POV. Have some existing POV character meet a new character and interact with them. Then switch to new character's POV with the new character leaving the meeting and reflecting on it.

These are not the only tricks Robert Jordan used to handle his many POVs in Wheel of Time, but these are the ones that stood out to me. It is also not like it is required to use tricks like these for handling multiple POVs in books, at least not when the number of POVs are limited. Once the number of POVs start increasing beyond three to four something extra becomes useful to help the reader handle them.

The Wheel of Time series is remembered for how it drowned in POVs, which is a shame. It deserves to be remembered for how well it handled multiple POVs.

Raven's shadow - To fall so far

Raven's Shadow is the first series by a new author Anthony Ryan. It’s a trilogy consisting of Blood Song, Tower Lord and Queen of Fire. It’s also a series which starts so great and end in such mediocrity.

The first book is really one of the great works of Fantasy. The book is really great. Its set in a medieval fantasy world and is a single POV story following the protagonist Vaelin Al Sorna. He gets handed to a sort of templar like warring monk society as a child and the book covers his time growing up among the warrior monks and then how he ends up in the service of the king of the land. Being fantasy there is also some magic in play. Vaelin has a sort of magical gift, the titular Blood Song, which guides him, at least when he bothers to listen.

The book also has a brilliant narrative setup where is sort of has two narrators. The prologue and epilogue is told from the point of view of a historian how follows a condemned criminal to his execution. On the way there he convinces the criminal to tell him his life story, so he can record it. The main narrative of the book is then the story of the criminal, Vaelin. When I started the book, I was a little worried about how well this would work in that the prologue sort of spoils the main story, but my worried were unfounded. In the end the meta-narrative of the historian and the life story of Vaelin come together beautifully. The ending is truly epic.

After such a great start the second book, Tower Lord, is a big step down. This is not to say the say the second book is a bad book. It’s not. Rather it’s just that the first one is so great that you can have a big step down and still end up with a good book. Rather than being a single POV book like the first one, this one has multiple POVs. It also handles them in a way I just loath: Jump between POVs and storylines every single damn chapter. It seems like it’s become quite popular lately. I blame George RR Marten. The good there is in A Song of Ice and Fire is good despite the constant jumping not because of it.

The book also undermines the previous book's world building. Where Vaelin had to train from childhood to achieve his martial prowess, now there are characters popping up that are way too good for what training they have. Worst offender here is a new female character called Reva. Which is a shame, for aside from that she is the most interesting new character, and the only one with a proper character arc.

If there was one weakness in the first book it was that the romance was kind flat and passionless. In the second book there is a new magically induced romance. Another flat and passionless romance, this time with a side dish of questionable consent. That does not improve things.

Where the second book was still a good book, the third one, Queen of Fire, isn't even that. It is decidedly mediocre. There will be some minor spoilers ahead, but this book isn't worth reading anyway, so don't worry. It is time for the main characters to take the war to the Evil Empire. This war is really boring with short descriptions of uninteresting battles against mind-controller slave soldiers. They are like the worst evil overlord goons.

To spice things up Vaelin loses his blood song ability. Cliched sure but could be interesting. How does the hero deal with losing his defining super power? But after moping about it a bit early in the book he runs into a woman with the same ability, so he just spends the rest of the book following her around instead. So, the entire plot point really doesn't lead to any interesting character growth or anything. He can just spend the rest of the book ignoring the issue. So, what does he do? Spends most of the book traipsing across a glacier just to get a big exposition dump in the end that explain everything about the big baddie. Who turn out to be boring.

The most interesting character in the last book is Reva, and that's saying something considering that she has neither a character arc nor anything to do with the plot. Reva's character arc is basically complete by the end of the second book. There is some hope for something interesting when she adopts a girl early in the book, but after that the girl is never heard from again and has no bearing on the plot. She also has her own side plot that has nothing to do with the resolution of the main plot. She just sort of ends up at the same place as all the other characters in the end. But at least her sub-plot has interesting action and adventure, not just dry battle description or walking across a glacier.

The ending still leaves a bunch of threads hanging. Like the how Vaelin never deals with losing the blood song. Reva's hunt for the priest from her childhood never goes anywhere. The wolf god thing is never explained. And the prophecy from the first book? Apparently just someone's pipe dream or something because it never leads anywhere.

The last book is also the longest, and it really feels like it. Plot-wise, you could just rip out both Reva and Vaelin, and just have someone else get the boring exposition dumps. That way you could at least cut the length of the book in half to tighten up the pacing. But honestly, it would still be boring.

My recommendation is to read the first book, because it is really awesome. Then just skip the rest. Sure, that leaves a few plot threads hanging, but their resolution is boring and the final book has its own unresolved plot threads anyway, and the ending of the first book is way better than the end of the trilogy.

The making of a blog

I figured the most navel-gazing way to start a new blog is to talk about how the blog was made.

This blog is made with a static site generator, an (CLI) application that takes some content and templates and generates all the html/css files needed for the site offline. You then deploy the resulting files to any static files host. The means that you don't run any code on the server and don't have a database. The advantage of this is that you don't need to pay for any compute/db server side, and there is nothing that can be hacked or that needs to be administered. Also, because all pages are generated ahead of time its fast because there is no need to generate the pages as requests come in. The downsides are that the site is static, so there is no possibility for dynamic content like comments. (Unless you embed some third-party comment system like Facebook's.) The advantage of a static site generator over plain static sites is that you still get templates and stuff, so you don't need to copy/paste everything for every page on the site. Also saves you a lot of work for creating category pages and similar.

The static site generator I ended up using is Gutenberg. This was not the result of some in depth investigation into all the static site generators out there. Rather it was something I had stumbled upon in a Reddit thread at some point that had been sitting in a half-forgotten tab ever since.

Gutenberg appealed to me for a few different reasons:

  • It is a single statically compiled binary you can download from GitHub so there is no need to install any programming language runtime to get it working.
  • It uses Tera as a templating language, which is based on Jinja2, and Sass for css. Since I use Jinja2 and Sass at my $dayjob I felt right at home.
  • Content is written in markdown with a special header for to specify metadata.
  • It has a local serve functionality where it will watch the filesystem for changes, and when it sees them it will recompile the site and refresh it in the browsers (via some injected js). It is fast enough that a recompile takes on the order of milliseconds.
  • It has the concepts of shortcodes from WordPress, where you can define small snippets of templates that you can then call from a markdown content file.

There is one clear shortcoming I've run into with Gutenberg so far: There is no way to globally access a list of categories. I wanted to have a list of category link in the sidebar, but I can't do that. You can even see an empty box in the sidebar where I wanted to put them. There is an open issue on GitHub about User-defined taxonomies, which apparently should enable that as well.

Gutenberg does have a theme system and a few existing themes, but I didn't use it. Instead I just hand rolled a few templates. The design is based around grey lines and rounded corners. This was originally driven by laziness. It is something that can be easily done in CSS so I wouldn't need to muck about with raster images (aside from the favicon). Given that I started on design centered around shades of grey I decided continue on that path and go for a monochrome look. For example, links are black (which is a bit darker than normal text) when unvisited but switch to a shade of grey when visited. I'm also using the circle ul list style because it fits in with the rest of the design. The one exception to the monochrome design is syntax highlighting, where is use an existing built in theme called ir-white, that is light but still colored. It looks like this:

fn main () {
  println!("Hello world");
}

I also took the opportunity to finally get to play with css grids. This is something I've been drooling over for a while but never been able to take into use due to the need to support Internet Explorer. This means this blog doesn't look great in IE11. It falls back to a boring looking single column layout, which works but isn't as pretty. The advantage of making a site for your own use is that you can just choose to ignore the IE11 users. :)

For hosting I use netlify, which works great with Gutenberg and GitHub. Just push a change to the master branch on GitHub and a git hook at netlify runs gutenberg and compiles the site and deploys the result. It also has nice features like deploying a preview of the site based on a branch. Simple support for custom domains and automatic TLS via Let's Encrypt. Oh, and you can't beat the price: $0/month. How do they pay for things? They have a lot of upsell to fancier features, but nothing I need for a simple static blog.

Overall, I'm really pleased with this setup. We'll see how long it lasts before I run into something it won't do for me, or just the urge to tinker becomes overwhelming.