powerd6/spec
This is the powerd6 specification, and it documents how the project behaves.
Versioning
Current Version: v0.2.0
❗️ Important: This specification is unstable and constantly evolving.
Until this specification hits version
v1.0.0
, there will be no stability guarantees.
This specification follows the Semantic Versioning conventions.
Meaningful changes between versions are documented in the changelog file.
Structure
This specification is organized in the following sections:
- Glossary: Definition for common terms used across the specification.
- Actors: Generalized end-user archetypes used to encapsulate end-user needs and how they relate to the project.
- Flows: The actions that actors can take to accomplish something.
Glossary
These are the terms used throughout this documentation.
Actors
Archetypes of users. Similar to user personas , but less detailed and thorough, since there was no real-user research involved.
Content
A set of information (text, numbers, images, files) that follows a specific schema.
JSON Schema
JSON Schema is a special type of JSON file that specifies validation and correctness rules for other JSON files.
JSON
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
We usually talk about JSON files, but in some contexts we might refer to “JSON objects”.
JSON objects are generic object ({}
) defined within an existing JSON file.
Module
The combination of content, schema, and authorship information that can be processed into a book.
Rendering
Some code, associated with a schema, that creates a user-readable version of the content that can be consumed.
Schema
Composed on validation and rendering logic, schemas are the format definition of the “shape” of certain pieces of content.
Actors
To better understand the future users that would interact with the project, we define archetypes that inform the development of the specification.
Creator
A person that is creating content for the powerd6 ecosystem, utilizing it’s tools.
Creators possibly have a financial incentive to contribute, but may also be “hobbyists”, who create things for their own enjoyment rather than as a marketeable product.
Objectives
- Create something new
- Share their creations
- Sell their content
Concerns
- Unlawful distribution (copyright violations, piracy, etc)
Maintainer
A person that contributes to the development of the powerd6 project.
Objectives
- Build tools for others
- Run required services for creators
- Interact with community for direction
Concerns
- Controversial changes that split the community in two
- Lack of community support
Player
A person that is interested in using the products created with powerd6 to play a game.
Objectives
- Download books
- Play games
- Browse contents
Concerns
- Difficult rules
- Difficult tools
Flows
Flows are the series of actions that actors can take to accomplish something.
Create a module
A module is nothing more than a file that contains content, schema, and some information regarding it’s authorship.
Modules are distributed as JSON files, and validated by JSON Schema.
The format of these module files are validated by the
module.schema.json
file.
Authoring a module
To provide proper attribution and authorship, modules may include an authors
section.
In this section it is possible to associate content and schema identifiers with specific authors, but this is not required. Authors that have no specific identifier associated to them will be associated with then entire module.
Publishing a module
Publishing a module means making it available to the public.
When doing so, it is important to add information to the module that explains where
it was sourced from. This is done by providing information in the module
section.
It is important to note that the module should only contain one module.references
property named after the unique module id, where the value are one or more
URI references to where to source
the module from.
Ensuring unique module identifiers
There is not a universal way to fetch a unique module identifier.
However, some strategies can greatly improve the chance of an identifier being unique:
- Use descriptive names
30-fire-spells-for-pyromaniacs
instead offire-spells
- Use your company name in the identifier
corp-tales-from-the-dungeons
instead oftales-from-the-dungeons
- Use the initial publishing date in the identifier
2023-10-23-funny-items
instead offunny-items
- Combine all the previous strategies
Handling purchases/payments
To sell a module, a creator should use a file-sharing service that processes payments.
For example, a creator may choose to share a module only to their subscribers, while others may simply host it on their website for free.
Rendering a module
Rendering a module is the process that creates a finished book.
This process combines the information in the schema and content to create human-readable output.
The order in which the content will be rendered is defined in the following manner:
- Each schema will be rendered in the order based on:
- the
renderOrder
property of the schema, from lower to highest - the identifier of the schema, alphabetically
- the
- Each content piece for a given schema will be rendered in the order based on:
- the
renderOrder
property of the content, from lower to highest - the identifier of the content, alphabetically
- the
Combining modules
Combining modules means that you will merge the contents of one module with another.
Combining modules is the main mechanism for players to interact with published modules in order to craft their custom experiences.
Combination rules
In the following section, modules will be named by capital letters
(A
, B
, C
, etc) and the plus sign (+
) will be used to represent a combination.
For example, A+B=C
means: “Module A
being combined with module B
, resulting
in module C
”.
Blanks
A+{}=A
When combining a module with a blank module, the results is the same as the first module.
Identity
A+A=A
When combining a module with itself, the result is the same as the first module.
Non-commutative property
A+B<>B+A
When combining two modules, the order on which they are combined is meaningful and may produce different results (due to the combination rules detailed below).
Combination
For A+B=C
, module C
will follow these rules:
Authorship
Module C
will contain all the authorship information from A
and B
.
Module information, Content and Schemas
Module information, content and schemas that are defined only on A
or only on
B
will be present in C
without changes.
Module information, content and schemas that exist in A
and B
will be merged
as follows:
- All properties that exist only on
A
or only onB
will be unchanged. - Properties that exist in
A
andB
are modified:- If the property in
B
isnull
, then the property is removed fromC
. - If the property in
B
is notnull
, the the property inC
will use the value fromB
- If the property in
This set of rules is also known as a JSON merge patch.
Creating a schema
Schemas are contextual pieces of information that help creators build content.
Schemas have two components: validation rules and rendering logic.
Validation rules
Validation is defined with JSON Schema formats and they help ensure that the “shape” of the data is correct.
Rendering logic
Rendering logic is defined with tera
templates,
and they are executed by tools when rendering a module.
These templates are executed with the following information present in their context:
Property | Description |
---|---|
content | The current piece of content that is being rendered |
module | The entire module that contains the content piece |
When creating writing the template, you can use both of these properties to implement rich logic and referencing within your rendering template.
For example, you could implement a feature that renders an effect
schema for
each referenced effect inside of an item
.
Updating schema
Overwriting information in an existing schema can be done by combining modules.
Creating content
Creating content means writing arbitrary sets of data into a distributable format.
Usually, this means writing text or encoding images into a JSON object.
Encoding non-textual data
Not all data that is required for your content will be representable as plaintext.
Images, videos, and files are great examples of content that cannot simply be defined as text.
For this purpose, we encode all the data as Data URIs encoded with base64.
For example, the following data URI string data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==
represents the following image of a dot:
In markdown, this looks like this:

Thanks to Peter Ritchie’s blog for these examples.
Validate content
Validating content is a process in which each content piece is validated against the schema validation rules.
This is not mandatory, but helps to ensure that content is created properly and can be rendered without issues.
Modifying content
Overwriting information in existing content, or changing properties inside a specific piece of content can be done by combining modules.
Translating content
An interesting application of content modification is to translate the content of a module to another language.
This can be done simply by replacing all the values (without adding or removing properties) to the desired language.
Keep in mind some templates may also need to be translated.
Deleting content
As explained in the “Combine modules” page,
content and schema can be deleted by combining a module with another that has
that specific content with a null
value.
Schemas
authorship
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://spec.powerd6.org/schemas/authorship.schema.json",
"title": "Authorship",
"description": "Information regarding authorship and contributions",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"references": {
"description": "A list of references for the author",
"examples": [
"http://mywebsite.com",
"mailto:author@domain.tld"
],
"type": "array",
"items": {
"type": "string",
"format": "uri-reference"
}
},
"contributions": {
"description": "Identifiers for schemas or contents that the author contributed to, as well as an optional explanation of the contribution",
"examples": [
{
"fireball": "created icon",
"spells": "contributed to rendering"
},
{
"slime": ""
}
],
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"required": [
"name"
],
"unevaluatedProperties": false
}
content
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://spec.powerd6.org/schemas/content.schema.json",
"title": "Content",
"description": "Content pieces in powerd6",
"type": "object",
"properties": {
"schema": {
"description": "The identifier of the schema that this content follows",
"type": "string"
},
"renderOrder": {
"type": "integer"
}
},
"required": [
"schema"
],
"additionalProperties": true
}
module-meta
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://spec.powerd6.org/schemas/module-meta.schema.json",
"title": "Module Information",
"description": "Information regarding a powerd6 module",
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"references": {
"description": "Reference information for the current module",
"examples": [
{
"module-id": [
"https://publisher.com/module-id",
"http://cdn.publisher.com/modules/module-id.json"
]
}
],
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string",
"format": "uri-reference"
}
}
}
},
"required": [
"title",
"description"
],
"unevaluatedProperties": false
}
module
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://spec.powerd6.org/schemas/module.schema.json",
"title": "Module",
"description": "A powerd6 module, with contents, schemas and authorship information",
"type": "object",
"properties": {
"module": {
"$ref": "https://spec.powerd6.org/schemas/module-meta.schema.json"
},
"authors": {
"type": "array",
"items": {
"$ref": "https://spec.powerd6.org/schemas/module-meta.schema.json"
}
},
"contents": {
"type": "object",
"additionalProperties": {
"$ref": "https://spec.powerd6.org/schemas/content.schema.json"
}
},
"schema": {
"type": "object",
"additionalProperties": {
"$ref": "https://spec.powerd6.org/schemas/schema.schema.json"
}
}
},
"required": [
"module",
"authors"
],
"unevaluatedProperties": false
}
schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://spec.powerd6.org/schemas/schema.schema.json",
"title": "Module Information",
"description": "Powerd6 schema",
"type": "object",
"properties": {
"validation": {
"$ref": "https://json-schema.org/draft/2020-12/schema"
},
"rendering": {
"type": "string"
},
"renderOrder": {
"type": "integer"
}
},
"required": [
"validation",
"rendering"
],
"unevaluatedProperties": false
}
Versions
Here are all the previously available versions of the specification: