Bit of a longer than ideal break due to Gen Con, but I returned from the con buzzing with ideas for various board/card game designs. So I turned my mind to prototyping. I’ve used a few different tools in the past (most notably Squib), but I’ve long wanted to build my own card prototyping tool (this is definitely the programmer in me). I’ve messed around with writing an iPad app in Swift, with card rendering in Quartz, but the level of effort required to get a nice interface for desinging layouts was more than I could devote to it. I did manage to make a wireframe renderer I was happy with, but that’s a far cry from a finished app.

So I decided to lean on my positive experiences with Hugo and create a command-line tool that renders prototype cards from human-editable text files. That would also give me an excuse to write something nontrivial in Rust. Enter…

Cardboard

Design

My high-level design for the tool is one that could be run from a directory containing a collection of layout descriptions and card data (cardboard build or similar). Each card set is either a directory full of yaml files or a delimited text file (like a csv exported from ${spreadsheet_program_of_choice}); and the layout descriptions would be written in Starlark, a Python-like language for building configuration.

That last decision is a weird one, but I felt that whatever language I used should support declaring a tree of layout elements and defining re-usable components. In pursuit of the first goal, I considered an xml- or json-based format, but everything I came up with was fine to write but very clunky to read. I considered yaml (since it also supports anchors and references), but it had no method of parameterizing components or re-using them across files.

I needed something that allowed file inclusion, defining functions/macros, and was easier to read than a big blob of xml, and Starlark fit that. I drew up a quick example of what I expect a layout file to look like and set to writing some code.


layout(
    geometry = geometry(
        width = 100,
        height = 100,
        cut = uniform(6),
        units = "px",
    ),
    background = solid(color = named("blue")),
    elements = [],
)

Starlark in Rust

The last big thing I did was setting up the project skeleton and writing a barebones layout library that could load a Starlark file. Fortunately there’s already a rust implementation with the entry points reasonably well documented. It stores its values on a custom heap, so I did have to fight the borrow checker a bit to extract the relevant structures, but I did end up with a function that takes some starlark code and produces a rust-native structure describing the layout, and some patterns for adding new types of objects to the library.

What’s next?

Next up, I’d like to get it rendering a very simple static card. To accomplish that, I’ll need to:

  • add shape, rectangle, and text objects (the easy part); and
  • set up cairo integration and get it to draw the layout objects (the hard part).