Create your Own Card Game with Headless Chrome

Have an idea for a card game? Design it. Print it. Sell it!

Cooper Thompson
ITNEXT

--

Photo by Andrik Langfield on Unsplash

While working on the brainstorming prompts and challenges presented in my previous article, I thought it would make for a pretty interesting card game.

The concept would involve generating lots of different prompts in the user story format, grouping them by industry and type, and releasing different packs of these cards following an “expansion pack” model. The game could either be single player or collaborative, but would not necessarily have a “winner” or “path to success.” It would purely be designed to stoke the flames of creativity and ideation.

However, this article isn’t about the concept of this game, so I will get back on track. When exploring the idea of creating a card game I went down different avenues of design and printing, and I believe I stumbled upon an approach that maximizes both quality and efficiency. Rather than designing each card by hand using a tool like Adobe Illustrator, Adobe Indesign, or Inkscape, I found that by using JSON, HTML templates, and headless Chrome, it was possible to quickly iterate on designs. In this tutorial we will also be using Golang as the language of choice in combination with the Liquid template engine, but any programming language and template engine can be used.

The overall process is:

  • Find the acceptable dimensions for a deck of cards on a printing service
  • Build an HTML + CSS template using a templating language (we will be using Liquid)
  • Create a program to inject parameters into the template and script Google Chrome via the DevTools protocol to take a screenshot of the template output

Example code can be found here:

https://github.com/csthompson/cardbuilder

Finding a printing service

The first step in creating a custom card game (besides designing it of course) is to find a printing service as this will define the templates used for building the cards. A great service that I found was Make Playing Cards.com. It has lots of options for different sizes, custom boxes, and even pamphlets that can be customized and included with each deck. Regardless of the printing service used, most will offer different dimensions for decks and the number of cards included in each deck. In this example we will use the domino-sized deck.

Once you pick the form factor and the various parameters for the printing, click “Start Design,” and choose custom image and text for all cards. The next page provides the necessary dimensions, as well as a utility to bulk upload all the images or the card fronts. The important part is the resolution, which for the domino-sized deck is 597x1122. This resolution will dictate the way we build the HTML template for our cards.

Intro to headless Chrome

Google Chrome is a popular web browser that provides an orchestration layer called the Chrome DevTools Protocol. This orchestration layer allows other services and applications to “instrument, inspect, debug and profile Chromium, Chrome and other Blink-based browser.” What this means is that the browser can essentially be controlled programmatically to perform tasks such as automated testing of web applications, scraping websites, or performing robotic process automation (RPA). For this use case, we will be using Chrome in a headless mode (no user interface) to take screenshots of HTML pages. The resulting screenshots will be used for our playing cards.

Controlling Chrome

There are a plethora of different libraries for different languages that can interact with the Chrome DevTools protocol. The most popular combination for interacting with Chrome DevTools is the puppeteer library, which is a NodeJS library. However, I am a big fan of Golang and I found the awesome chromedp package that makes interacting with Chrome a breeze.

Picking a template language

Golang has an amazing built-in template language via the text/template and html/template packages, but I wanted to switch things up and use the Liquid templating engine for this use case. The main reason behind the decision is to show that any language can be used for this use case that has template libraries available (Ruby, Python, C#, Java, Javascript, etc). You may recognize Liquid as being the template language that powers Shopify storefronts.

Building a template

Once the template language is picked, we can create the actual template. Using the resolution provided by the printing service (597x1122 for this use case), we will be able to define the dimensions of our template. In this example, we will just be adding text to the cards with a solid color background, but the limits of this are only bound by the limitations of HTML and CSS. You can add custom icons, different shapes, multiple sections, images, and anything you can think of! You can see the simple template below.

Injecting values into the template

A set of playing cards typically has multiple different types of cards all following a similar design, but each card will have a unique set of attributes. This similarity of overall design, but difference in specific attributes is what makes the process so conducive to HTML templates. So how do we get these specific attributes into the template? We can use a JSON file.

A simple file with an array of JSON objects, where each JSON object represents a card, provides an easy way to iterate on designs and values without having to adjust the entire set of cards each time. Below is an example JSON file where each card has an attribute called “prompt”. You will see these prompts come from the article linked above.

Each JSON object above will be used to define a card, and each card will have a unique prompt. Looking at the template, we can clearly see where the “prompt” is injected:

<div class="prompt">
{{card.Prompt}}
</div>

We can make each object as complex as we like, allowing for card decks such as complex trading or adventure games. For example, we can even load spritesheets into the cards using this technique. Awesome spritesheets can be found on Open Game Art and you can use this tool to figure out the offsets for each sprite.

Now that we have our template and the values defined, we can work on putting them to work.

Populating the template and taking a screenshot

Our program will be responsible for two main tasks.

  • Populating the template and saving it as an HTML file
  • Taking a screenshot of the HTML file with Chrome

Golang has a built-in templating engine, but as mentioned we will be using Liquid which can be done using this package: github.com/osteele/liquid.

Because Golang is strongly typed, the card type must be predefined so that we can properly read the JSON file. Languages such as Python or Javascript would likely be much more flexible when it comes to complex JSON objects. Below is the simple struct we will use to define each card:

type Card struct {
Prompt string `json:"prompt"`
}

Using the above struct, we can then read the file, “unmarshal” the JSON into a slice of Cards, and iterate over each one to populate the Liquid template.

Let’s dive into the code that will use headless Chrome to render and screenshot the HTML code. Chrome DevTools allows for the program to override the viewport which is the dimensions of the screen. The following code is heavily borrowed from the example code provided in the Golang chromedp package:

We can see the width and height being overridden and a clip being applied to ensure we only capture the dimensions defined by the printing service.

Running the code

Below are the steps for running the code found in the repository.

  1. Download and install the latest version of Golang https://golang.org/doc/install
  2. Download and install Git
    https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
  3. Create a directory where you want to save the code, for example:
    mkdir -p ~/workspace/cardbuilder
    cd ~/workspace/cardbuilder
  4. Clone the repository:
    git clone https://github.com/csthompson/cardbuilder
  5. Run the program:
    go run main.go

The go.mod file should automatically take care of all the dependencies

Once the program is run, you should see .png files populated in the output directory. If you have any issues running the program, feel free to comment below!

Conclusion

Programmers are often plagued by the creative spirit, always wanting to build or make something. Source code can be viewed as a tool for limitless creativity, so why not use code for something besides programs? By using HTML, CSS, some simple scripting, and headless Chrome it can be easy to create a card game, and possibly eventually published and used as a side hustle.

I would love to see what you come up with! Give me a follow on Twitter and share your designs :) https://twitter.com/CooperThompson8

--

--

Writer for

I am a software engineer with a passion for brainstorming and ideation. I believe everybody has a set of skills that can be the seeds for future businesses.