Creating a Dynamic Character Sheet Template (DST)

An Overview of DSTs

Dynamic Sheet Templates (DSTs) are pre-formatted interactive character sheets for use with characters on Obsidian Portal. Each DST is created for a specific game system, and is made up of three parts: the HTML template, the CSS styling rules, and the JavaScript functionality code. Any user can create a DST, but it must be tested and approved by one of our DST Moderators.

Notice: DST creation is one of the more advanced things you can do as a user on Obsidian Portal, so please understand that before diving in. We say this not to dissuade potential DST developers like yourself, but so no one goes into the process without a realistic expectation of what it will take to get the job done.

Assumed Technical Knowledge

This guide assumes that you have an understanding of the basic building blocks of web design - in particular HTML and CSS (with JavaScript as an optional third). You don't have to be an expert, but you will need to be able to use these tools to create a standardized character sheet layout that is structurally sound, and easy to comprehend for users who are familiar with the game system that the sheet is made for.

Assumed Design Knowledge

This guide also assumes that you have a grasp of design fundamentals, and can make a character sheet that is aesthetically pleasing as a standalone item, while still being neutral enough to be usable on campaigns with differing themes, layouts and design concepts. Filling in values should not 'break' the formatting, or push other (neighboring) sections of the sheet out of place or onto subsequent lines.

Beyond Just Characters

This guide refers to "characters" throughout, but DSTs can now also be created for Items or for Wiki Pages. Character DSTs can only be created for a specific Game System. Item DSTs and Wiki Page DSTs can also be created for "All Game Systems", and would be available to Campaigns of any Game System.

The Process in Brief

Let this rough outline serve as your "Quick Start" guide:

  • Email [email protected] to let us know what game system you're looking to tackle and why.
  • If there are any existing DSTs for your chosen game system, start there! Using the same field names will enable users to switch between sheets without losing (or having to re-enter) their character's stats.
  • Create a new DST and fill in the meta data (make sure you set the game system!)
  • Use the "DST Code" input fields to enter your HTML template, CSS styling, and (optionally) JavaScript functionality. Be sure to save periodically and keep a local copy!
  • Create one or more test characters using your DST so you can ensure that the DST looks and functions correctly. Be sure this is true for both viewing and editing!
  • Run your HTML template through the W3C validator to ensure that it validates.
  • Enter any submission notes for your DST and then press the "submit" button.
  • Once submitted, your sheet will be reviewed by one of our DST Moderators to ensure that it meets the DST Review Guidelines. Be prepared to work with them to correct any issues.
  • Assuming your sheet gets approved by the moderator, you'll receive 6 free months of Ascendant time and our everlasting gratitude (please note that if you make any changes to your DST once it has been approved, it will need to be re-approved).

The Goal

Our goal is to have Obsidian Portal be able to support characters from every game system out there! We fully understand that this is an extremely lofty (and challenging) goal, but we're hopeful that with the help of our amazing community members, it's possible. DSTs are the mechanism we're currently using to strive for that goal. DST creation is how you can help out!

Keep in Mind

DSTs are not necessarily intended to be fully-featured ultimate auto-calculating online playable character sheets. As such, there are no requirements for a lot of bells and whistles. If the sheet looks nice and is functional, that's perfectly fine. Don't be afraid to keep things simple. That said, if you have the capability to make a more advanced sheet, that's awesome! Just remember to keep the sheet's functionality unobtrusive; particularly with things like auto-calculations.

Don't forget that not everyone who uses your sheet will be playing the game exactly as laid out in the rulebook(s). If someone wants to give their character 99,999 strength or utilize house rules that will change the derived values made by your sheet's calculations, you should leave the door open for them to do so. If you don't, you're limiting the usefulness of your sheet to certain users.

The Reward

By creating a DST, you're doing the entire community a huge favor. As a token of our appreciation (because we know how much work can go into creating these sorts of things), we're awarding 6 months of Ascendant membership to anyone who creates a DST and gets it approved. This free membership time is our way of saying 'Thank you!' and letting you know that we appreciate your efforts.

So with that said, the natural question becomes "what might prevent my sheet from getting approved?". The list includes - but is not necessarily limited to:

  • The sheet is buggy and/or doesn't function correctly
  • The aesthetic is unattractive or severely counter-intuitive
  • The sheet is somehow a breach of copyright
  • The sheet is a blatant rip off of an existing DST

The Basics of a DST

A DST allows for the marking up of the underlying structured metadata of an RPG character. This metadata consists of a set of key-value pairs. For example, here is an overly simplified D&D character expressed as a set of key-value pairs:

{
  "name" : "Tordek",
  "race" : "Dwarf",
  "class" : "Fighter",
  "level" : 12,
  "current_hit_points" : 75
}

What the DST does is take the various key-value pairs that make up the given character's statistics and plug them into an HTML template. The look of that template is determined by the CSS styling rules. If there is any functionality to the sheet beyond basic value input (such as automatic calculation of values), this is handled in the sheet's JavaScript coding. When the sheet is presented to the user, the first half of the pair maps to the field the user enters their value into, and the second half of the pair is their entered value (or potentially a calculated value).

Editing of values for the sheet is done via JavaScript. When an authorized editor (ie, the GM or a player) goes into edit mode, the values become clickable. On click, they are replaced with an input field. The editing user types in the new value, hits enter (or clicks the Ok button) and it updates the value. When the user is happy, they click the Save button and the whole sheet is saved.

HTML Template

The first piece of any DST is the HTML template. This is simply an HTML file that lays out the entire character sheet. The only special thing to note here is that certain elements will need special classes. That's how our system recognizes a DST, by HTML classes. Here's an example HTML template for Tordek, from above:

<div class="basic_info">
    <p> 
        Name: 
        <span class="dsf dsf_name"></span> 
    </p>
    <p> 
        Race: 
        <span class="dsf dsf_race"></span> 
    </p>
    <p> 
        Class: 
        <span class="dsf dsf_class"></span> 
    </p>
    <p> 
        Level: 
        <span class="dsf dsf_level"></span> 
    </p>
    <p> 
        Current Hit Points: 
        <span class="dsf dsf_current_hit_points"></span> 
    </p>
</div>

The obvious class to look for is dsf which stands for dynamic sheet field. The system will find all the span elements with the dsf class and automatically fill them with the correct value for that field. How does it know what value to fill with? That's where the dsf_ class comes in. This class is dsf_FIELDNAME. When the sheet loads, we will insert all the correct values using javascript. Here's what Tordek's sheet would look like after fully loading:

<div class="basic_info">
    <p> 
        Name: 
        <span class="dsf dsf_name">Tordek</span> 
    </p>
    <p> 
        Race: 
        <span class="dsf dsf_race">Dwarf</span> 
    </p>
    <p> 
        Class: 
        <span class="dsf dsf_class">Fighter</span> 
    </p>
    <p> 
        Level: 
        <span class="dsf dsf_level">12</span> 
    </p>
    <p> 
        Current Hit Points: 
        <span class="dsf dsf_current_hit_points">75</span> 
    </p>
</div>

To make a field updatable in view mode, as opposed to only in edit mode, you can add the class dsfu which stands for dynamic sheet field updatable.

<div class="basic_info">
    <p> 
        Name: 
        <span class="dsf dsf_name">Tordek</span> 
    </p>
    <p> 
        Race: 
        <span class="dsf dsf_race">Dwarf</span> 
    </p>
    <p> 
        Class: 
        <span class="dsf dsf_class">Fighter</span> 
    </p>
    <p> 
        Level: 
        <span class="dsf dsf_level">12</span> 
    </p>
    <p> 
        Current Hit Points: 
        <span class="dsfu dsf dsf_current_hit_points">75</span> 
    </p>
</div>

The Fields

Our backend can handle pretty much any set of fields. If one game system has level and another has rank, that's fine. Just define the fields you need when making your HTML template, by creating spans with the correct dsf class. There's no need to pre-define or enumerate them anywhere. Any span with the class of dsf will be assumed to be a field, and the field name will be extracted from the dsf_FIELDNAME class on that same element.


Be sure to use existing field names wherever possible. If there's a DST for your game system already, use it! This ensures maximum compatibility between DSTs, and will allow users to switch back and forth to find one they like. Otherwise, if an existing DST has dsf_level and you create one with dsf_lvl, then the two sheets are incompatible. Anyone that switches from one to the other will lose (or at least won't be able to see) the value for that field.

Naming Conventions

To ensure maximum compatibility between DSTs, follow these conventions when naming fields.

  • ASCII alphanumeric (and underscore) only. We don't want to deal with encoding schemes right now.
  • Use full words, when possible.
  • Established abbreviations (str, dex, etc..) are okay. If you're not sure, use the full word (and again, check existing DSTs to see what they used)
  • Connect words with underscores, not camelCase or anything else: armor_class, not armorClass or ArmorClass
  • All lowercase.

Required Fields

There are some fields that are common to all characters (name, player name, campaign, etc..). These fields are handled separately from the other dsf fields as far as editing and saving are concerned. However, they will behave the same for display and positioning purposes. Your DST must have a place to display each of the following fields:

Required Fields

Field Field Name Class Notes
Character Name dsf_name A link to the character (ie. link to the current page). It will have an additional class of dst_character_name_link that can be used for styling.
Player Name dsf_player A link to the player's profile page. Can be empty, like for an NPC. It will have an additional class of dst_player_link that can be used for styling.
Campaign Name dsf_campaign A link to the campaign. A link to the character's campaign. It will have an additional class of dst_campaign_link that can be used for styling.
DST Author dsf_dst_author A link to the profile page for the DST author (you!). It will have an additional class of dst_dst_author_link that can be used for styling.
Character Bio dsf_bio This is HTML and can be very long. Make sure to fit it into your DST in such a way that it can grow to any length.
Character Avatar dsf_avatar_image Places the character's avatar image on the sheet. The image will have an additional class of avatar_image for styling purposes. The character's name will be added as both the alt and title values.

Checkboxes

Since checkboxes (or similar) are a very common feature for character sheets, we have added support for easily adding checkboxes to a DST. Simply add the checkbox class to a dsf span and it will automatically get converted. Here's an example:

<span class="dsf dsf_trained checkbox"></span>

The checkbox field will have a value of "1" if checked, or a value of "0" if not. It also works as normal with the dataChange javascript callback (see the section on JavaScript below).

Don't Use HTML IDs

Do not insert any HTML id tags into your template. At this time, id tags are stripped out by the system to ensure no accidental duplications. Use unique (and namespaced) classes in the place of id tags.

Readonly fields

If you wish to prevent a field from being edited for any reason (such as if it is calculated by your sheet's JavaScript), you can add a class of readonly to the field to make it unable to be edited; as seen below:

<span class="dsf dsf_armor_class_total readonly"></span>

That said, in most cases we recommend letting the user have the ability to override values that have been calculated (see the Keep in Mind section above).

HTML-based Images

If your DST is going to make use of any images aside from the character's avatar (such as for backgrounds, textures or corners), you will need to have these images hosted somewhere online so that you can call them from your DST. In such cases, stability is the key. You don't want to call an image that is hosted somewhere where it isn't guaranteed to stay for a long period of time.

The Styling

Once you have your HTML template complete, all of the basic markup language is in place - but it probably doesn't look very good yet. This is where CSS styling will come into play. By targeting elements from your sheet by class name or element type, you can apply style rules and drastically alter (ie, improve) the look of your DST. To do this, you will want to add class names to your HTML template that will be targeted by your CSS. Don't forget that elements can have multiple class names.

Namespacing

All of your CSS must be namespaced! This means prefixing your CSS rules so that they only affect your particular DST and not the site's layout as a whole. This is actually quite easy to do, as each sheet will be contained inside a div with a class of ds_SLUG where SLUG is the slug for your DST. For example, sheets using the minimal4e DST will always be contained in a div with class ds_minimal4e.

Here are a couple of sample CSS rules for the minimal4e DST:

.ds_minimal4e table {
  /* This applies to all tables in my DST */
}

.ds_minimal4e a {
 /* This applies to all links in my DST */
}

When adding classes to elements in your DST's HTML template, consider namespacing those as well in order to prevent issues with the overall site's CSS rules. For example:

<span class="my_class">Some value here</span>

should be...

<span class="minimal4e_my_class">Some value here</span>

Technically, namespacing of custom element class names inside your HTML template is not required, but it's generally a good idea to do so anyway. We make periodic changes to the site-wide CSS rules, and if we unknowingly use a class name that is the same as one of yours, the look of your DST could be impacted.

CSS-based Images

Just like with images in your HTML template, you will need to have any images you intend to call with your CSS hosted somewhere on the internet. Similarly, you want to make sure they are hosted in a place where they are guaranteed to last.

Javascript

The first thing to know here is that JavaScript is NOT required. If you just want to make an attractive sheet that saves whatever the user puts into it and nothing else, that's perfectly fine. Having such a sheet is still an upgrade to having no sheet at all. In fact, it could be said to be great even, because doing so means there's no chance that your code will prevent people from using the sheet the way they want to for their character or campaign NPC.

That being said, if you want to add JavaScript to your DST, awesome!

Namespacing

Function names, and the names of any variables that might be accessible outside of your functions must be namespaced. This is required to prevent collisions between your DST's code and other JavaScript running on the Obsidian Portal site. To namespace your JavaScript, simply prepend your DST's slug to each function and broadly accessible variable. Here are some examples using the minimal4e DST:

var foo;

becomes...

var minimal4e_foo;

function bar(a, b, c) {
  // function code here
}

becomes...

function minimal4e_bar(a, b, c) {
  //function code here
}

jQuery

We use jQuery fairly extensively, and it is available for use in your DST's JavaScript, so feel free to make use of it if you are knowledgeable.

Callbacks

There are several callbacks that can be used in order to be notified of events occurring in the character sheet. In order to retrieve the callback, you will need to create a function with a specific name. If a function by that name is found, it will be called at the appropriate time. For all of the callbacks, the first part is always the slug of your DST.

Callback Functions

Function Notes
SLUG_dataPreLoad(opts)

Called immediately before the data values are loaded into the HTML template. "opts" is a JavaScript object containing:

  • containerId (string) - The HTML id of the container div surrounding the HTML template.
  • slug (string) - The slug of the current DST.
  • isEditable (boolean) - True if the DST is in edit mode, false otherwise.
SLUG_dataPostLoad(opts)

Called immediately after the data values have been loaded into the HTML template. "opts" is a JavaScript object containing:

  • containerId (string) - The HTML id of the container div surrounding the HTML template.
  • slug (string) - The slug of the current DST.
  • isEditable (boolean) - True if the DST is in edit mode, false otherwise.
SLUG_dataChange(opts)

Called immediately after a field value has been changed. This is useful if you want to do auto-calculations or validation. "opts" is a JavaScript object containing:

  • containerId (string) - The HTML id of the container div surrounding the HTML template.
  • fieldName (string) - The name of the field changed. It will not include the "ds_" prefix.
  • fieldValue (string) - The value of the field.
SLUG_dataPreSave(opts)

Called immediately before the data values are retrieved from the HTML template and sent to the server to save. "opts" is a JavaScript object containing:

  • containerId (string) - The HTML id of the container div surrounding the HTML template.
  • slug (string) - The slug of the current DST.
  • isEditable (boolean) - True if the DST is in edit mode, false otherwise.

Limitations on External JavaScript

Due to the inherent security risk of permitting external JavaScript files from other servers, the inclusion of such files is disallowed, with one exception. DST authors may make use of the CSX libraries located on ChainsawXIV's github DST wiki. These libraries have been created exclusively for DST building on Obsidian Portal by one of our trusted DST Moderators.

Notes / Misc

To close things out, here are a few notes and things that are worth mentioning:

Keep a local copy!

It is strongly recommended that you keep a local copy of your HTML template, CSS, and Javascript. Our server database is backed up regularly, but there is always a chance that your DST code will get lost or corrupted on the server. Having a local copy means you can simply copy & paste the code back in.

Backups are your friend.

Developer's Kit

While there is technically a DST developer's kit (a set of files that replicates how the DST works on the site), it is currently out of date. Getting this updated is on our to-do list, but we're not quite to it just yet. Users are certainly able to download and use it for their DST building work if they wish - but anyone who does should understand that until it is updated, what you see with the kit will not necessarily be what you see when it is plugged into the live site.

Licensing

By submitting a DST, you are agreeing to let Obsidian Portal members use it. We give full attribution of authorship to you, the author, but by submitting a DST, you are giving us a royalty free license to copy, modify, and distribute it. Essentially, all submitted DSTs are assumed to be under an open source license. If you wish, you can include an explicit license statement. I highly suggest using the MIT license. Any license not recognized by the OSI as being open source will not be accepted.

Copyright (c) [year] [copyright holders]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Still need help? Contact Us Contact Us