12 Steps To Heaven (Patreon)
Content
With the actual Playtest rules in my hands, I've finally made a start on building something, putting the theories I've built up the last few months into practice. There's nothing to show yet, of course - it's still very, very early days - but I have at least settled on a plan.
I'm going to outline the steps I'll be taking here, from zero to complete product, going into gradually more technical detail.
The goal is to produce a web site like the current one that takes user selections and produces a character sheet. This will be a single HTML file with all the necessary assets embedded into it: images, fonts, CSS etc.
Step one: static file
I'm starting at the destination and working backwards from there, so my first step is to build a character sheet in HTML. This file references external files the way you normally would for a web page. Of course, it's not going to support different classes at this step, or any of the other myriad options you'd hope to see in the final system.
An important part of this step is establishing the mapping between the elements you expect to see on the page, and the elements and CSS classes used to represent them in HTML. For this I'm going to be leaning heavily on the newer HTML5 elements that don't see much use nowadays. For example, the iconic header bar you see all over my character sheets is represented with a <section><h3>, while each feat, action or weapon will be an <article>. I'm also going to be borrowing from BEM in order to keep my class names consistent, with -- for adjectives and __ for contents. For example, a domain power is an <article class='article--power'>.
The correctness of those choices won't be immediately visible in the output, but they'll have an effect on how amenable the format is to changes in the future.
Step two: templated builder
This step is where I break the toy I just made into lots of pieces, then put it back together again. I separate out the HTML for each page, the parts of the CSS etc, then use a simple template engine to combine them into a single output file. This includes embedding images and icons as data URLs.
The result will be that a couple of dozen separate components get stitched together into a single HTML file. This file will now be a reasonable facsimile of the desired output.
There will be limited options here - I may be able to, say, pick one of two classes to include by editing the test script, but that's all.
Step three: render functions
The pages I built in the previous steps had a lot of repetition, and any programmer will tell you that DRY is better than WET. So at this step I write JavaScript functions that render each of the components that get used a lot - functions like renderField(), renderLayout(), renderCalculation(), etc. Then I wire these functions together in a test script to produce the same output as previously.
It'll seem from the outside as if not much has changed at this step - in fact, ideally it'll look exactly the same. If it does, that means I have a set of render functions that can be used to make the desired product.
Step four: element tree
Rather than calling the render functions, this builds a tree of objects, each of which has a render() method and keeps track of its components. The tree is built in advance, then when you call render() on the top level element it recursively calls render() on its components, and their components, all the way down to produce the output file.
For example, a page is built up of fields, calculations, paragraphs, sections, titles and other elements. There will be quite a lot of these different pieces, and keeping them organised is an important part of this.
Step five: zone composer
This is where we start to get into the clever stuff: hooks. Hook- or event-based programming should be familiar to anyone who's programmed using jQuery, WordPress, AppleScript or a thousand other such systems. The idea is that one part of your code registers a callback against a specific hook or event; and then when another part of the code triggers that event, all the actions hooked onto it happen.
The hooks in this case are 'zones', which are named areas of the character sheet such as "the skills list", "the actions list", "the sorcerer feats" etc. Each ancestry, class, feat or other option can hook into any zone; and can also present zones of their own. At the top of the tree, "the pages list" is another zone, which is how classes can add pages.
For example, the Reactions section contains a group of placeholder action objects for users to fill in, but a class or feat can fill in that section by registering against that zone, putting its own reaction object in there instead. Each reaction has a known level, and the zone keeps them in order. When it comes time to render the page, all the hooked reactions are written out.
At this point the structure of the program starts to resemble the real thing, in that you have separate code for each class that hooks into the right events. It's still not very variable, though.
Step six: registry of objects
Filling in the work started in the previous step, this involves creating a set of self-contained objects that are capable of hooking into the tree to inserting visual elements at the right zones.
For example, the Wizard class adds the Wizard page, sets initial proficiencies for skills, saving throws etc, sets the key ability to Intelligence, and so on. Meanwhile the Wizard feat "Familiar" adds a page for a familiar / animal companion, and fills in the relevant slot in the Wizard Feats table.
At this point, these objects are all written in JavaScript. I'll probably only do one or two classes like this, to demonstrate the system works, because they'll be thrown away in the next step.
Step seven: data-driven objects
I don't want to be writing clever JavaScript for each class and feat out there. Instead I want a nice format I can write these things in quickly and easily (and that anybody else can join in with). Making it as easy as possible to add new classes, new feats, new ancestries etc is necessary because Paizo will inevitably continue to release more and more and more - and so will third party companies.
So the next step is to read files in a simple data format and convert them into JavaScript objects seen in the previous step. You've seen this format before here. YAML is a good choice for this because it's short, tidy and easy for human beings to read - human beings like me!
Step eight: transpiled library
Processing all that data is slow and time consuming for the program, and lends itself to architectural leakage, so the next step is to separate out that code into a precompile step, which will read the hundreds of YAML files, process them and produce something easier to use.
The result will be a single dense JavaScript library, usable in any context provided you call it with the right parameters.
Step nine: character data
To date, all of this is driven by test functions that say "Can we try this now, please?" For the real system we need to be able to respond to the user's input, and that means taking their choices and working with them.
I should by this time have completed the decoupling step, giving me a system-agnostic means of describing character requests. So my code for Pathfinder 2 needs to read that JSON format and use it to drive the composition of all the elements that go into making a character sheet.
Step ten: web service
If all the previous steps went right, then this step should be a doddle: connecting the library built in step eight up to the Node.js web service. Make an HTTP POST request to the right place, get a character sheet back.
Step eleven: web form
The front end of the website needs some love as well. There needs to be a form people can use to select their ancestry, background, class, feats and other things. I don't yet know what that form will look like, but it needs to be there.
This isn't just static HTML, either; the form is data-driven, built from the data of the game system. Currently that's a big file, pathfinder.json, that I edit by hand. In the new system, that JSON file will be generated alongside the JavaScript library.
Step twelve: all of the data
And finally, with all of that in place, it'll be time to fill in all the many, many options. Every class, all the bloodlines and totems and domains, all the ancestries and archetypes, and at least a few of the feats.
You may wonder why I'm leaving it this late before putting all this data in. Aside from the inevitable process of discovery I'll go through as I work through the stages I've outlined, there's a very good reason: the playtest. There's no sense me spending the time to put lots of data in until I get my hands on the real game.
---
Having nailed down the plan, I've now confirmed what I suspected all along, which is that there'll be no public release of Dyslexic Character Sheets for the playtest. I simply won't get through all that lot in the time left, so the public release will have to wait until the final system (and then some). I don't have a firm timetable for the steps either - it depends on what happens in my life.
There will, however, be a series of patron-only previews on this channel. It only takes $1 for you to get access to those, but more importantly it comes with a big stonking caveat: these will not be the finished product, not even close to it. They might be just about usable as a character sheet if you squint, but don't treat them like you would a real thing. The purpose of releasing them at all is to get feedback from you, my my patrons.
So at some point in the next few weeks, I'll release a preview for step 1 which I've been working on, and then I'll be angling for feedback.