Fancy world-building handouts (advanced!)

Posted by Chris Rosser on Sat 29 September 2018
Hello! This site is archived and no longer maintained. For Chris' main site go to

In my last post I built a workflow for turning individual world-building articles into stylised PDFs I can give away to my readers. It worked better than I expected and I shared the first one with my subscribers in my September newsletter. The feedback was terrific. I'll be sending another one next month, so be sure to subscribe!

In this part, I hope to refine and improve upon the workflow, taking production up another notch as well as leverage the power of automation. This part is a little more advanced in places than last week but I promise to go slow, and if you've got questions, ask me!

An alternative for muggles (non-technical folk)

When I posted my first article on Facebook, someone pointed out that much of my needs were catered for by a project called GM Binder. Having looked into it, I now understand where many of the example documents I saw on Pinterest were created! GM Binder even uses the same underlying technology of Markdown and HTML/CSS — albeit they've gone to the effort of wrapping it up in a web app, which I won't do because of 1. I prefer writing in a text editor, not web browsers and 2. I can't be arsed.

GM Binder UI
GM Binder UI

GM Binder is much more polished than my solution, and it's a much better choice if you're not technically inclined. However, it's not for me because I prefer to create content on my terms not someone else's. That said, I think it's a great option and certainly worth playing with, and if you become a regular user, I suggest you support them on Patreon.

I wanted to see how easy it was to incorporate two of GM Builder's features with my workflow, namely document variables and snippets.

It turns out it was rather trivial to do so…

Document variables

Variables provide a mechanism to change words easily. Variables can be a lifesaver when you are world-building and aren't yet set on your nomenclature. It's also a useful timesaver when you don't want to keep retyping the same text over and over.

GM Builder graphical editor for creating and using variables. However, MultiMarkdown also has this feature baked in, allowing you to reuse any metadata key in your document.

Title: My character sheet
foo: bar

# [%title]

During a great time of [%foo]...


GM Binder has an excellent little snippets system that lets you add predefined blocks of content wrapped in an HTML \<div> tag block. I said in my last post I didn't want to pollute my markdown with divs, but I can't deny their effectiveness for styling content when coupled with corresponding CSS rules. For the most part, I don't need to deviate too far from my templates, but there's no harm in creating a few as needed.

Snippets are no strangers to developers, because… well, time is too precious to waste in doing boring crap manually. If you're a Microsoft Word user, chances might have used Quick Parts, which are essentially the same thing.

Most text editors worth their salt have a built-in snippet manager. The better ones even allow you to define insertion points which you can jump between using the tab key. For the editors that don't, you can use a system-wide typing assistant like Text Expander, or you can create your own like I did.

If you find yourself regularly using the same markdown tables and document sections, why not turn them into a snippet to save yourself time and improve consistency?

Joining multiple documents

As it stands, the workflow I outlined works well for compiling single world-building article into separate PDF documents. However, what if you want to merge a bunch of articles to create a booklet or something even longer?

Here, the scenario I'm imagining is the Dungeon/Game Master wanting to print an entire homebrew campaign or an author looking to produce a world encyclopaedia of their setting. Thanks to inexpensive print-on-demand services, not only is possible, but it's also cost-effective and convenient — and the results are great, allowing anyone to produce and share keepsakes of their creative work.

Fortunately, this is easy to do, and it doesn't require you to create a whopping great big markdown file. Several markdown systems, including MultiMarkdown, can merge multiple files by referencing them from another document. In MultiMarkdown parlance, this is called file transclusion.

The idea is you create a top-level index file containing the document metadata and links to all the files you want to include. I documented this extensively way back in 2014, but for the sake of brevity this is what such an index could look like:

Title: Epic world bible
Author: Chris Rosser
CSS: stylesheet.css

# Characters


# Locations


Now when I build against the index file, MultiMarkdown creates a single HTML page including all your content — all ready for PrinceXML.

When merging documents, you may wish to demote the heading levels of your articles. In the template I illustrated in my previous post, my top-level heading was Heading 1. However, that would break the hierarchy of the index file I show above. I need my articles to start off at Heading 2. To do this, I can override the heading level within each article using the following metadata key-value pair.

Title: Character sheet
Base Header Level: 2

# My character sheet

Now when the document is compiled, the headings are bumped down one level.

Table of Contents

If you are producing a booklet or a large book, a table of contents helps your readers to navigate your content. MultiMarkdown can create one for us.

All that's needed is to insert a directive into the markdown, and on compile, it produces a document index (basically an unformatted, unordered list) wrapped in a div element.

Add the TOC directive to your index file, and you add a master table of contents to the entire document.

Here's the MultiMarkdown TOC directive...


...and the resulting HTML.

<div class="TOC">

   <li><a href="#locationname">Location name</a>
       <li><a href="#description">Description</a></li>
       <li><a href="#quickfacts">Quick Facts</a></li>
       <li><a href="#history">History</a></li>


You can style it with CSS and add page numbers with PrinceXML when you compile to PDF. For my articles, I'm keeping things simple. I'll remove the default styling, add a small margin, and generate the word 'Contents' before it.

Since I don't need it to appear on the web, I'll enable the TOC only for print.

.TOC {
display: none;

A printed table of contents is useless without page numbers. To add page numbers, I use the following CSS:

@media only print {

   .TOC a::after {
          content: leader(".") target-counter(attr(href),page);


The syntax warrants a little explanation because it may not be familiar to those with only a casual knowledge of CSS.

The a::after tells PrinceXML to add something after a TOC's hyperlink element. The something is defined in the content directive. In this case, I'm adding a leader (essentially a dotted line), and I'm using PrinceXML's custom CSS extension to insert the correct page number.

Table of contents
Table of contents

Page breaks

As your document gets larger, or maybe you just like more control, you may want to tweak your page flow to force page breaks at specific elements. For example to ensure that every Heading 1 element begins on a new page.

h1 {

page-break-before: always;


You can also use the same technique to add manual breaks using horizontal rules.

hr {

  border: none;
  margin: 0;
  page-break-before: always;


For practical purposes, the CSS I've used makes the horizontal rule invisible and prevents it from taking up space. If you use display: none PrinceXML won't apply the page break rule. Alternatively, using "visibility: hidden" merely hides it from view; however doing this still retains the rule's physical size, adding extra padding between elements that I don't want.

You can insert a horizontal rule by typing three asterisks characters (***) on a new line.


Compiling the document to PDF is a two-step process. First I have to create the HTML file, then I have to tell Prince to convert the resulting HTML into a PDF. I then load the PDF up to my content delivery system, so it's ready to share with my readers. Since most people don't go the effort of creating their own distribution platform as I have, I'll only show you how I automate the PDF creation process.

It's not scary, I promise, just a couple line of the scripting language, Bash, which is available on macOS, Linux and Windows 10 (with the Subsystem for Linux).

, In the beginning, was the command line...

I aim to create a simple bash script that converts the markdown document into a PDF and does a little processing along the way. Ideally, I want to run a single command against a file, for example:

$ makepdf

Here’s the script I wrote1:


TITLE=`/usr/local/bin/multimarkdown $DOC —extract="Title"`
SLUG=`echo $TITLE | sed -e "s/\\ /_/g" | sed -e 's/.*/\L&/'`

/usr/local/bin/multimarkdown $1 > "$SLUG.html"

prince "$SLUG.html" -o "$SLUG.pdf"

The script might look a little bewildering, but it's pretty straightforward. I'll break it down line-by-line.


This first line declares the script uses the system's bash interpreter. This location should be the same on both macOS and most flavours of Linux — it's probably the same on Windows too, but I'm not sure as I haven't tried it.

TITLE=`/usr/local/bin/multimarkdown $DOC —extract="Title"`

The second line instructs MultiMarkdown t0 extract the Title from the metadata and assign it to the TITLE variable.

SLUG=`echo $TITLE | sed -e "s/\\ /_/g" | sed -e 's/.*/\L&/'`

The third line is the most complex. What I'm doing here is using the sed program to make the extracted title lowercase and replace the spaces with underscores. I save this modified string to a variable called SLUG.

/usr/local/bin/multimarkdown $1 > "$SLUG.html"

Next, in the fourth line, I'm using MultiMarkdown to convert the markdown file ($1) to HTML using the SLUG as the filename. $1 is a special reference to the file, which I passed as an argument to the script.

prince "$SLUG.html" -o "$SLUG.pdf"

Finally, I tell PrinceXML to create the PDF, again using the slug as the file name.

Creating a macOS droplet app

That's nice, but on a Mac, we can do a lot more, using the awesome little robot called the Automator. This incredible app allows you to build automated workflows using drag-n-drop blocks. One of those blocks is a container for a shell script. The beauty of Automator is it integrates nicely with macOS' graphical interface. With it, you can build Folder Actions for Finder or even drag-and-drop applets — or droplets.

The idea is simple: build a droplet containing our script, save it as an app, then drop a markdown document on the app’s icon and out spits a PDF — no command line required!

Shell script in Automator action
Shell script in Automator action

The workflow is straightforward. The script goes in the first action block, “Run Shell Script”. Note that I’ve selected ‘as arguments’ in the “Pass input” dropdown — this is important because it allows me to reference the input file using the bash variable $1.

Because of the peculiarities of macOS and Automator, I had to modify the script slightly. Firstly, Automator always runs a shell script from your home folder unless otherwise directed, so I needed to explicitly tell it to work with the input file’s directory. Another quirk of Automator is you have to explicitly declare where a command lives on your filesystem for any utility you installed manually — in my case that includes gsed, MultiMarkdown and PrinceXML.

Secondly, Apple’s sed command doesn’t work like sed on Linux, so I used homebrew to install GNU Sed. Once upon a time, macOS was very GNU-friendly, but at some point, they deviated wildly, presumably because they didn’t want to use GPL licensed software.

Lastly, to open the newly minted PDF, I had to pass the filename and its path to the next action “Open Finder Items” by using the echo command. Because the resulting file is a PDF, Automator uses my system’s default for PDF files (which is unless otherwise directed.

Here’s the modified script in its entirety.


DIR=$(dirname $1)

TITLE=`/usr/local/bin/multimarkdown $1 --extract="Title"`

SLUG=`echo $TITLE | /usr/local/bin/gsed -e "s/\\ /_/g" | /usr/local/bin/gsed -e 's/.*/\L&/'`

/usr/local/bin/multimarkdown $1 > "$DIR/$SLUG.html"
/usr/local/bin/prince "$DIR/$SLUG.html" -o "$DIR/$SLUG.pdf"

echo $DIR/$SLUG.pdf

Finally, here’s a brief video of the droplet in action.

Bonus round — Weasyprint

I noted in my last post that an alternative to PrinceXML is the open-source weasyprint project. I decided to give it a shot, testing the results on an old laptop running Linux.

As an aside, I decided to use an old laptop because I had done a fresh install of macOS Mojave and didn’t want to load up all the GTK dependencies on which WeasyPrint relies.

Installing Weasyprint on Linux is trivial, but outside that, you have to install a lot of non-native dependencies. That’s not something most people would care to do on their primary computer, myself included. However, it occurred to that if it produces good output, I could install it as a service on one of my Linux servers and use as a free replacement to DocRaptor (PrinceXML as SaaS).

Anyway, after installing it, I tested it against the same generated HTML document and my CSS stylesheet, without any modifications. Here’s the result:

PDF produced by Weasyprint
PDF produced by Weasyprint

It’s not perfect by any means, but it did better than I was expecting. It mangled the background texture and the footers, but it handled the two-column layout well and, surprisingly it even generated the page numbers and document title in the footer using the same syntax as PrinceXML.

I noted I used the same stylesheet — a stylesheet optimised for PrinceXML. I suspect that if I optimised the stylesheet for Weasyprint, I’d get a much better output.

The project certainly has potential, but seeing as I already have a desktop licence for PrinceXML, my motivation for switching is relatively low. That said, if you balk at PrinceXML’s cost and you don’t mind the complexity of installing it outside of Linux, then I think it’s worth exploring.

Concluding thoughts

I had a lot of fun creating this workflow. I set out with the goal of creating nice looking handouts to share with my subscribers and achieved that end. The workflow is flexible and built with tools I already have on my Mac. With the refinements I’ve added in this part, I’ve extended it to produce multi-article publications, and I’ve automated the process by creating a simple shell script and Automator to create a droplet.

If you have questions or suggestions as to ways I could make it better, I’d love to hear from you.

  1. I wrote the original script in Linux with the standard GNU utilities; I later had to modify it to work with macOS which isn’t as GNU friendly as it used to be. 

Wow you read this far! This site is archived and no longer maintained. For Chris' main site go to