add docs page and button to launch the app
This commit is contained in:
parent
a7d06a86cb
commit
a97d73a8a9
@ -6,6 +6,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>SessionZero</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<link rel="icon" href="d20_no-bg_medium.png">
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-container">
|
||||
@ -15,7 +16,6 @@
|
||||
<a href="#" class="logo-container">
|
||||
<img src="d20_no-bg_medium.png" alt="SessionZero Logo" class="logo-placeholder">
|
||||
<div class="logo-text">SessionZero</div>
|
||||
<link rel="icon" href="d20_no-bg_medium.png">
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
@ -25,7 +25,8 @@
|
||||
<section class="hero">
|
||||
<h1>SessionZero</h1>
|
||||
<p class="tagline">A TTRPG companion that gets out of your way</p>
|
||||
<a href="https://git.bellsworne.tech/Bellsworne/SessionZeroWeb">Work in progress—View the source code</a>
|
||||
<a href="https://web.sessionzero.app">Open SessionZero</a>
|
||||
<p>⚠️ SessionZero is still in development, but you can still access it while it's being developed! ⚠️</p>
|
||||
</section>
|
||||
|
||||
<section class="features">
|
||||
@ -48,7 +49,7 @@
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 SessionZero. All rights reserved.</p>
|
||||
<p>© 2025 Bellsworne LLC. All rights reserved. | Made with ❤️ by <a href="https://bellsworne.com/tech">Bellsworne Tech</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
11
styles.css
11
styles.css
@ -167,6 +167,17 @@ footer {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--accent-color);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--text-color);
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.hero {
|
||||
|
689
szf-docs.html
Normal file
689
szf-docs.html
Normal file
@ -0,0 +1,689 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Session Zero Format (.szf) Documentation</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
||||
<link rel="icon" href="d20_no-bg_medium.png">
|
||||
<style>
|
||||
:root {
|
||||
--background-color: #1a202e;
|
||||
--primary-color: #3a4f6f;
|
||||
--secondary-color: #2d3f5c;
|
||||
--accent-color: #5b89b3;
|
||||
--text-color: #ffffff;
|
||||
--heading-color: #c5d5e6;
|
||||
--form-background: #222837;
|
||||
--text-on-primary: #ffffff;
|
||||
--button-text: #ffffff;
|
||||
--neutral-light: #d8e1ea;
|
||||
--neutral-medium: #8494a7;
|
||||
--neutral-dark: #2d364a;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
font-family: "PT Serif", serif;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: var(--background-color);
|
||||
padding: 1rem 2rem;
|
||||
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.5);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
max-width: 1200px;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.logo-placeholder {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: var(--heading-color);
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: var(--heading-color);
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
background-color: var(--form-background);
|
||||
padding: 2rem 1rem;
|
||||
border-right: 1px solid var(--neutral-dark);
|
||||
position: sticky;
|
||||
top: 80px;
|
||||
height: calc(100vh - 80px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sidebar h3 {
|
||||
color: var(--heading-color);
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.sidebar ul {
|
||||
list-style: none;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.sidebar li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar a {
|
||||
color: var(--neutral-medium);
|
||||
text-decoration: none;
|
||||
padding: 0.25rem 0;
|
||||
display: block;
|
||||
transition: color 0.2s ease;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.sidebar a:hover {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.sidebar .subsection {
|
||||
margin-left: 1rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
padding: 2rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
color: var(--heading-color);
|
||||
margin-bottom: 1rem;
|
||||
border-bottom: 2px solid var(--accent-color);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
color: var(--heading-color);
|
||||
margin: 3rem 0 1rem 0;
|
||||
border-bottom: 1px solid var(--neutral-dark);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.5rem;
|
||||
color: var(--heading-color);
|
||||
margin: 2rem 0 1rem 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.2rem;
|
||||
color: var(--heading-color);
|
||||
margin: 1.5rem 0 0.5rem 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin-left: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: var(--neutral-dark);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
font-family: 'Courier New', monospace;
|
||||
color: var(--neutral-light);
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: var(--form-background);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 1rem 0;
|
||||
border-left: 4px solid var(--accent-color);
|
||||
}
|
||||
|
||||
pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
color: var(--neutral-light);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1rem 0;
|
||||
background-color: var(--form-background);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--neutral-dark);
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: var(--secondary-color);
|
||||
color: var(--heading-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: var(--accent-color);
|
||||
color: var(--button-text);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.back-to-top {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
background-color: var(--primary-color);
|
||||
color: var(--button-text);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 50px;
|
||||
text-decoration: none;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.back-to-top:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
position: static;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--neutral-dark);
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-container">
|
||||
<header>
|
||||
<nav>
|
||||
<div class="nav-content">
|
||||
<a href="index.html" class="logo-container">
|
||||
<img src="d20_no-bg_medium.png" alt="SessionZero Logo" class="logo-placeholder">
|
||||
<div class="logo-text">SessionZero</div>
|
||||
<link rel="icon" href="d20_no-bg_medium.png">
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<aside class="sidebar">
|
||||
<h3>Contents</h3>
|
||||
<ul>
|
||||
<li><a href="#overview">Overview</a></li>
|
||||
<li><a href="#file-structure">File Structure</a>
|
||||
<ul class="subsection">
|
||||
<li><a href="#header">Header</a></li>
|
||||
<li><a href="#sections">Sections</a></li>
|
||||
<li><a href="#nested-sections">Nested Sections</a></li>
|
||||
<li><a href="#fields">Fields</a></li>
|
||||
<li><a href="#comments">Comments</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#field-types">Field Types</a></li>
|
||||
<li><a href="#file-types">File Type Specifications</a>
|
||||
<ul class="subsection">
|
||||
<li><a href="#dataset">Dataset</a></li>
|
||||
<li><a href="#character-template">Character Template</a></li>
|
||||
<li><a href="#character">Character</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#advanced-features">Advanced Features</a></li>
|
||||
<li><a href="#best-practices">Best Practices</a></li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
<main>
|
||||
<h1 id="overview">Session Zero Format (.szf) Specification</h1>
|
||||
|
||||
<div class="section">
|
||||
<h2>Overview</h2>
|
||||
<p>The Session Zero Format (.szf) is a structured, human-readable data format for defining and storing tabletop RPG data, including characters, templates, and game assets. It is designed to be simple to write by hand, easy to parse, and flexible enough to support a wide variety of game systems.</p>
|
||||
|
||||
<h3>Core Principles</h3>
|
||||
<ul>
|
||||
<li><strong>Human-Readable:</strong> The format uses plain text and a clear, indented structure that is easy to read and edit.</li>
|
||||
<li><strong>Structured & Typed:</strong> Data is organized into logical sections with explicitly declared field types defined in templates.</li>
|
||||
<li><strong>Extensible:</strong> The format can be extended with new fields and sections without breaking existing parsers.</li>
|
||||
<li><strong>Portable:</strong> .szf files are self-contained and can be easily shared and used across different platforms.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 id="file-structure">File Structure</h2>
|
||||
<p>Every .szf file consists of three main parts: a <strong>Header</strong>, a <strong>Metadata Section</strong>, and one or more <strong>Content Sections</strong>.</p>
|
||||
|
||||
<h3 id="header">Header</h3>
|
||||
<p>The header is mandatory and must be the first two lines of the file. It declares the file type and the schema version.</p>
|
||||
|
||||
<pre><code>!type: [file_type]
|
||||
!schema: [schema_version]</code></pre>
|
||||
|
||||
<ul>
|
||||
<li><strong>!type</strong>: Defines the purpose of the file. Valid types are:
|
||||
<ul>
|
||||
<li><span class="highlight">dataset</span>: A collection of related game elements (e.g., items, spells).</li>
|
||||
<li><span class="highlight">character_template</span>: A blueprint defining the structure of a character sheet.</li>
|
||||
<li><span class="highlight">character</span>: An instance of a character created from a template.</li>
|
||||
<li><span class="highlight">session</span>: Data related to a specific game session (future use).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>!schema</strong>: The version of the .szf specification the file adheres to (e.g., 1.1.0).</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="sections">Sections</h3>
|
||||
<p>Data is organized into named sections. Sections create a hierarchical structure for organizing related fields.</p>
|
||||
<p><strong>Syntax:</strong> <code>[SectionName]</code></p>
|
||||
<p>SectionName must be a single word, is case-sensitive, and must use <strong>PascalCase</strong> (e.g., AbilityScores, CharacterInfo).</p>
|
||||
|
||||
<h3 id="nested-sections">Nested Sections</h3>
|
||||
<p>Sections can be nested to create a logical hierarchy. The dot (.) notation is used to define a parent-child relationship.</p>
|
||||
<p><strong>Syntax:</strong> <code>[ParentSection.ChildSection]</code></p>
|
||||
|
||||
<pre><code>[AbilityScores]
|
||||
Strength (number) = 10
|
||||
|
||||
[AbilityScores.Modifiers]
|
||||
StrengthMod (calculated) = (AbilityScores.Strength - 10) / 2</code></pre>
|
||||
|
||||
<h3 id="fields">Fields</h3>
|
||||
<p>Fields represent individual pieces of data within a section. Each field has a name, a type, and a value.</p>
|
||||
<p><strong>Syntax:</strong> <code>FieldName (type) = value</code></p>
|
||||
|
||||
<ul>
|
||||
<li><strong>FieldName</strong>: The name of the field. Must be a single word, is case-sensitive, and must use <strong>PascalCase</strong>.</li>
|
||||
<li><strong>(type)</strong>: The data type of the field, enclosed in parentheses.</li>
|
||||
<li><strong>=</strong>: The assignment operator.</li>
|
||||
<li><strong>value</strong>: The data assigned to the field.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="comments">Comments</h3>
|
||||
<p>Comments are denoted by a hash symbol (#) at the beginning of a line. Parsers should ignore comments.</p>
|
||||
|
||||
<pre><code># This is a full-line comment.
|
||||
FieldName (text) = Some Value</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 id="field-types">Field Types</h2>
|
||||
<p>The .szf format supports a variety of field types to handle different kinds of data:</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Example Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>text</td>
|
||||
<td>A single line of text.</td>
|
||||
<td>Elara the Brave</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>text-field</td>
|
||||
<td>A multi-line block of text.</td>
|
||||
<td>A long sword forged by...\nIt glows faintly.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>number</td>
|
||||
<td>An integer or floating-point number.</td>
|
||||
<td>16 or 3.5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>bool</td>
|
||||
<td>A boolean value.</td>
|
||||
<td>true or false</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>calculated</td>
|
||||
<td>A value derived from a formula.</td>
|
||||
<td>(Strength - 10) / 2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>A special field that controls application behavior.</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>entry-reference</td>
|
||||
<td>A reference to a single entry from a dataset.</td>
|
||||
<td>ClassData or ItemData.Longsword</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>entry-reference-list</td>
|
||||
<td>A comma-separated list of references to entries from a dataset.</td>
|
||||
<td>CoreFeats.PowerAttack, CoreFeats.Cleave</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 id="file-types">File Type Specifications</h2>
|
||||
|
||||
<h3 id="dataset">Dataset (!type: dataset)</h3>
|
||||
<p>A dataset file is a collection of structured entries.</p>
|
||||
|
||||
<h4>Structure:</h4>
|
||||
<ul>
|
||||
<li><strong>[Metadata] Section</strong>: Contains information about the dataset.
|
||||
<ul>
|
||||
<li>Name (text): The human-readable name of the dataset.</li>
|
||||
<li>Type (text): The category of the dataset (e.g., items, spells, classes).</li>
|
||||
<li>Guid (text): A globally unique identifier. <em>Optional</em>.</li>
|
||||
<li>Version (text): The semantic version of the dataset.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>[EntryName] Section</strong>: Each entry represents a specific item, spell, or other game element.</li>
|
||||
</ul>
|
||||
|
||||
<h4>Example: CoreItems.szf</h4>
|
||||
<pre><code>!type: dataset
|
||||
!schema: 1.1.0
|
||||
|
||||
[Metadata]
|
||||
Name (text) = Core Fantasy Items
|
||||
Type (text) = items
|
||||
Guid (text) = c3d4e5f6-g7h8-9012-cdef-123456789012
|
||||
Version (text) = 1.0.0
|
||||
Author (text) = Fantasy Creator
|
||||
Description (text-field) = A collection of basic items for any fantasy campaign.
|
||||
|
||||
[Longsword]
|
||||
Name (text) = Longsword
|
||||
Description (text-field) = A standard sword with a long blade and crossguard.
|
||||
Category (text) = Weapon
|
||||
|
||||
[Longsword.Stats]
|
||||
Damage (text) = 1d8 slashing
|
||||
Weight (number) = 3
|
||||
Cost (number) = 15
|
||||
IsMartial (bool) = true</code></pre>
|
||||
|
||||
<h3 id="character-template">Character Template (!type: character_template)</h3>
|
||||
<p>A character_template defines the structure, fields, and rules for a character sheet.</p>
|
||||
|
||||
<h4>Structure:</h4>
|
||||
<ul>
|
||||
<li><strong>[Metadata] Section</strong>: Contains information about the template.</li>
|
||||
<li><strong>[RequiredDatasets] Section</strong>: Lists all datasets required by this template.</li>
|
||||
<li><strong>[SectionName]</strong>: Defines sections on the character sheet with fields, types, and default values.</li>
|
||||
<li><strong>System Fields</strong>: Special fields that modify section behavior.</li>
|
||||
</ul>
|
||||
|
||||
<h4>Example: FantasyTemplate.szf</h4>
|
||||
<pre><code>!type: character_template
|
||||
!schema: 1.1.0
|
||||
|
||||
[Metadata]
|
||||
Name (text) = Standard Fantasy Character
|
||||
Guid (text) = f9e8d7c6-b5a4-3210-9876-543210fedcba
|
||||
Version (text) = 2.1.0
|
||||
Author (text) = Template Master
|
||||
|
||||
[RequiredDatasets]
|
||||
ClassData (text) = Core Classes|aaa-bbb-ccc|1.5.0
|
||||
ItemData (text) = Core Fantasy Items|c3d4e5f6-g7h8-9012-cdef-123456789012|1.0.0
|
||||
WeaponData (text) = Core Weapons|12345678-90ab-cdef-1234567890ab|1.0.0
|
||||
|
||||
[Info]
|
||||
CharacterName (text) =
|
||||
Class (entry-reference) = ClassData
|
||||
|
||||
[AbilityScores]
|
||||
Strength (number) = 10
|
||||
Dexterity (number) = 10
|
||||
|
||||
[AbilityScores.Modifiers]
|
||||
StrengthMod (calculated) = (AbilityScores.Strength - 10) / 2
|
||||
DexterityMod (calculated) = (AbilityScores.Dexterity - 10) / 2
|
||||
|
||||
[Equipment]
|
||||
DatasetReference (system) = WeaponData
|
||||
|
||||
[Inventory]
|
||||
DatasetType (system) = items
|
||||
AllowQuantity (system) = true</code></pre>
|
||||
|
||||
<h3 id="character">Character (!type: character)</h3>
|
||||
<p>A character file is an instance of a character_template filled with specific data. It <strong>only contains values</strong>, as the structure and types are defined by the template.</p>
|
||||
|
||||
<h4>Example: Elara.szf</h4>
|
||||
<pre><code>!type: character
|
||||
!schema: 1.1.0
|
||||
|
||||
[Metadata]
|
||||
Name = Aela the Huntress
|
||||
Guid = a1b2c3d4-e5f6-7890-abcd-ef1234567890
|
||||
Version = 1.0.0
|
||||
TemplateRef = Standard Fantasy Character|f9e8d7c6-b5a4-3210-9876-543210fedcba|2.1.0
|
||||
|
||||
[Info]
|
||||
CharacterName = Aela the Huntress
|
||||
Class = Ranger
|
||||
|
||||
[AbilityScores]
|
||||
Strength = 16
|
||||
Dexterity = 14
|
||||
|
||||
[Equipment]
|
||||
PrimaryWeapon = ItemData.Longsword
|
||||
PrimaryWeapon.Quantity = 1
|
||||
|
||||
[Inventory]
|
||||
HealingPotion = ItemData.HealingPotion
|
||||
HealingPotion.Quantity = 5
|
||||
HempRope = ItemData.HempRope
|
||||
HempRope.Quantity = 2</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 id="advanced-features">Advanced Features</h2>
|
||||
|
||||
<h3>System Properties</h3>
|
||||
<p>System properties are special fields within a character_template that modify the behavior of a section:</p>
|
||||
<ul>
|
||||
<li><code>DatasetType (system) = type</code>: Restricts a section to holding references from datasets of a specific type.</li>
|
||||
<li><code>DatasetReference (system) = alias</code>: Restricts a section to holding references from a specific dataset.</li>
|
||||
<li><code>AllowQuantity (system) = true</code>: Allows entry-reference fields to have associated quantity fields.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Quantity Fields</h3>
|
||||
<p>If a template section has <code>AllowQuantity (system) = true</code>, a character file can specify quantities using:</p>
|
||||
<p><strong>Syntax:</strong> <code>ReferenceFieldName.Quantity = value</code></p>
|
||||
|
||||
<h3>Calculated Fields</h3>
|
||||
<p>Fields of type <code>calculated</code> contain formulas that are evaluated by the application. They support:</p>
|
||||
<ul>
|
||||
<li>Basic arithmetic operations (+, -, *, /)</li>
|
||||
<li>Parentheses for grouping</li>
|
||||
<li>Dot notation to reference other fields</li>
|
||||
</ul>
|
||||
|
||||
<h3>Wildcard Calculations</h3>
|
||||
<p>For sections with AllowQuantity enabled, use wildcard syntax for aggregate calculations:</p>
|
||||
<p><code>SectionName.*.FieldName</code>: Refers to the FieldName property of all items in SectionName.</p>
|
||||
|
||||
<pre><code>[Inventory]
|
||||
DatasetType (system) = items
|
||||
AllowQuantity (system) = true
|
||||
TotalWeight (calculated) = Inventory.*.Weight * Inventory.*.Quantity</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 id="best-practices">Best Practices</h2>
|
||||
<ol>
|
||||
<li><strong>GUIDs:</strong> Leave this blank, and the system will generate a GUID for you. This ensures uniqueness across datasets and templates.</li>
|
||||
<li><strong>Versioning:</strong> Use semantic versioning for your files to manage updates and breaking changes.</li>
|
||||
<li><strong>Naming Convention:</strong> Strictly use <strong>PascalCase</strong> for all SectionNames and FieldNames.</li>
|
||||
<li><strong>Nested sections:</strong> Use dot notation to create logical hierarchies but avoid excessive nesting.</li>
|
||||
<li><strong>Dependencies:</strong> Explicitly list all required datasets in templates.</li>
|
||||
<li><strong>Validation:</strong> Before use, validate that a file's structure is correct and all references are valid.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<a href="#overview" class="back-to-top">↑ Top</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Smooth scrolling for anchor links
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Highlight current section in sidebar
|
||||
const observerOptions = {
|
||||
rootMargin: '-20% 0px -70% 0px',
|
||||
threshold: 0
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
const id = entry.target.id;
|
||||
document.querySelectorAll('.sidebar a').forEach(link => {
|
||||
link.classList.remove('active');
|
||||
});
|
||||
const activeLink = document.querySelector(`.sidebar a[href="#${id}"]`);
|
||||
if (activeLink) {
|
||||
activeLink.style.color = 'var(--accent-color)';
|
||||
}
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
document.querySelectorAll('h2[id], h3[id]').forEach(heading => {
|
||||
observer.observe(heading);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user