Sample code for Pathfinder 2 (Patreon)
Content
If you're fluent in JavaScript and curious about where my thoughts for Pathfinder 2 are going right now, have a look at this gist:
https://gist.github.com/marcus-downing/24bbe8803a8c5ff367867b9c30501d7c
But first, let me reassure you: this is still all about producing *paper* character sheets first and foremost.
I was initially planning to declare the elements of a character sheet in an open data format - JSON, YAML, something like that - but as I tried writing out a few samples, it became clear that there was too much active behaviour for that to work. So instead I'm trying an approach where classes, feats and other things are written in JavaScript against an API that I've yet to design, effectively making it into a DSL.
The choice of JavaScript is simple: it runs everywhere. Client, server, desktop, mobile, Windows, Mac, Linux, everything. That means I'm keeping my options open for how I use these in the future. It's also a language lots of people know, though I suspect my style of using it here - semi-functional, chained, non-OO, and without a DOM in sight - is a little less familiar.
Obviously these are only vague samples, not even worthy of calling prototypes. We don't have the Pathfinder 2 playtest rules yet. But the previews we've seen indicate that a lot of important class functionality is going to be hidden behind feats - whether those are class feats, skill feats or ancestry feats. For example, the Wizard doesn't get a familiar by default, but it's a feat they can take. Gnomes can also take an ancestry feat giving them a familiar, whatever class they are. So the ability to build character sheets based on more than just class selection is key.
So the freedom to grow is baked into this approach. Each part of it has the freedom to create other parts, so something small like a feat has the option of adding something large like a page. Again, this is necessary when that feat adds a familiar - or an Eidolon or a set of evocative elemental powers or something else.
There's a lot to decode in the linked gist, especially without any documentation or anything. For example:-
- Most elements are built out of existing elements, which range from the simple (`p`, `hr`) to the complex (`calculation`, `feats_list`). You can write custom elements that implement their own `render` function.
- Subsystems add optional rules. For example, registering a subsystem for bardic performance allows other code to add their own bardic performances.
- You can register a known type, eg registerFeat('power_attack', 'Power Attack'), or you can register an arbitrary type of thing, eg `register('bard__performance', 'countersong', 'Countersong');`. The latter will either become meaningful when that subsystem is activated.
- When it says `addPage({ layout: 'A' });`, that just means the most common layout: 2 unequal columns with the narrow one on the left.
- Every object of it, from a whole class down to a single field, has an ID, and most of them also have a name, ie `addSection('cantrips', 'Cantrips');`
- The three phases of work are:
1. REGISTER all the options - classes, subsystems, feats, visual elements - but don't do anything with them.
2. ACTIVATE the selected classes, feats and other options. They will activate other things in turn; keep going until all the selected things have been activated. This should produce a tree of elements.
3. RENDER that tree into an HTML document by calling from the top hook, 'pages', and letting it cascade down into all the attached elements.
If you can read this, your attention span is too long.