Dev Blog: Creating the Gods Unchained List Creator

The web application is currently hosted at https://gu-list-creator.vercel.app/

Home Page of GUListCreator

As an avid player of Gods Unchained (GU) and having recently joined Hive, I was posting quite a bit in the Gods On Chain community, sharing my decks and strategies. After posting a few articles, I realised that I was unsatisfied with the process of grabbing card images. There were existing tools available, but none specifically tailored for sharing GU card images quickly. This led me to create GUListCreator which aimed to solve this rather niche problem.

For more GU-specific details on this tool, do read my other article posted in the Gods On Chain community here.

Deciding Project Requirements

As with any software project, the first thing one needs to do is to think of the requirements. Knowing what the requirements are allowed me to focus on what was important and waste less time on potentially useless features.

My first prototype had the following requirements:

  • Have a "canvas" for putting down cards
  • The "canvas" should be able to hold many cards and will put cards into the next line if there is not enough horizontal space
  • A fuzzy search for cards - no one can remember every single card name!
  • Each search result should have key information about the card for quick recognition, but nothing more
  • A way to grab the cards for sharing
  • No server involved so there are no maintenance costs

It wasn't a long list of requirements, because I wanted to get a proof-of-concept out quickly first and validate the demand for such a tool before committing more time and resources to it. With the requirements down, I then decided on the tools I would be using to create this.

The Tools

To create a proof-of-concept quickly, I settled on the following technical stack:

  • React as the frontend framework of choice, since I was very familiar with it already
  • ParcelJS as the build tool as it required zero-config with sane defaults
  • TypeScript instead of JS for easier maintenance, plus I was already used to it
  • Bulma as the CSS Framework, as it was rather easy to use
  • gu-composited-card, the open-source web component library for rendering Gods Unchained cards
  • FuseJS for fuzzy search
  • Surge.sh for hosting, since it was the fastest to set-up and deploy

Knowing that the GU team already had a library for rendering Gods Unchained cards made it much simpler to come up with the first prototype. The library abstracted out the nitty-gritty details of knowing how to align each card perfectly. I also decided that for a first prototype, there would be no in-built functionality to save the card images. The user would just simply use their screengrab tool of choice to capture the canvas area.

I managed to get the card data from GUDecks by inspecting outgoing network requests. I noticed that they queried all card data whenever you visit a deck preview page, so I simply copied the response data and did some data cleaning on my end.

image.png

Development Process

The development process wasn't anything revolutionary. Since ParcelJS already had Hot Module Replacement (HMR) built-in, any changes that I made to the code was almost instantly reflected on the live preview / development server. This allowed for very quick development and iteration, and I finished the first prototype of the tool in a couple of hours.

I don't have any code samples of the initial prototype as I didn't commit anything to source control then 😂

First released prototype of GUListCreator

There was hardly any page design, but it got the job done. I could already see myself being able to use the tool in its current state. I quickly posted my progress on the Gods On Chain community and received lots of encouragement from the community. This validated my theory that there was a demand for such a tool and pushed me to continue development for this project.

Improving the Project

As I realised that I wouldn't be leaving the project as it was just yet, I decided to upgrade the tooling a bit.

  • I decided to make the change to TailwindCSS from Bulma as I was increasingly getting frustrated with Bulma's lack of flexibility. Tailwind required more time to set-up and scaffold but was much more flexible
  • I changed hosting from Surge to Vercel, which also meant that I had to start using source control. With Surge, every deployment was manual. Vercel did automatic deployments whenever I pushed my commits to GitHub, so it was much more convenient in the long run. It's also a plus point that Vercel's servers are much faster. (And it's still free for static frontends)

One of the biggest roadblocks for this tool to become useful was that it could not export the cards to an image with a transparent background. Being able to do so would allow content creators to modify the images further without having to remove the white background first. Thus, I set out to seek a solution for this problem.

html2canvas, and how I had to re-write the gu-composited-card library

To capture a portion of the web page, the only library that I could find that had this capability was html2canvas. Viewing the demo on their site, I thought that it couldn't be easier. Just add a couple of lines of code, run the library function, and I was done!

Capture from html2canvas

Actual cards

It turned out that things weren't that simple after all. A lot of debugging later, I found out that this happened because trying to put images from another server onto a canvas was a big no-no. It would taint the canvas and essentially would refuse to be loaded for security issues. Somehow, I figured out that if the browser developer toolpane was open and the network cache was disabled, I would be able to get the images out nice and clear.

Capture from html2canvas with network cache disabled

While the images loaded fine now, there was another glaring issue - the text was not offset properly. I still have no idea why this happened, but my first instinct was to simply do some translation of the text containers before the capture happened, and then revert that translation once the capture was finished. However, this was impossible to do without re-writing parts the gu-composited-card library. And so, I did it - I rewrote their web component library into a React component.

Source files in the gu-composited-card library

Thankfully, there were only a few files of source code that were relatively easy to understand. It wasn't tough, but it was tedious.

After a good amount of time spent on re-writing the library, I manually inserted a couple of div translations that would occur when the user clicked the "Save as PNG" button.

html2canvas capture after translations

It worked! Now, the last remaining issue was to ensure that the images loaded without having the user mess around with their developer tools.

Google-driven development

I googled around for solutions, tried some of them to no avail, before landing on this helpful comment on a html2canvas issue. The fix essentially forces the browser to re-fetch the image by appending a useless query parameter behind the original URL, like such: https://example.com/a.jpg to https://example.com/a.jpg?v=123456. This "tricks" the browser into thinking that it is a new image and will re-fetch it. I tried the fix have no idea why this fixes the issue, but it did.

I had finally fixed the most annoying issue of this project by pure brute strength and relying on the work of others. I slapped on some design changes, About and Changelog pages, and the new site was a beauty to behold.

image.png


I had a lot of fun developing this project despite its relatively niche use-case and will continue developing it a little further until I can get its functionality to where I think it should be. I'm planning to add a bunch of small features in before the New Year and release v1.0.0 then. Hopefully, people will find it much more useful then.

Thanks for reading my dev blog, and let me know if you have any questions!

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now