BREAKING CHANGES: - Relationship syntax now requires blocks for all participants - Removed self/other perspective blocks from relationships - Replaced 'guard' keyword with 'if' for behavior tree decorators Language Features: - Add tree-sitter grammar with improved if/condition disambiguation - Add comprehensive tutorial and reference documentation - Add SBIR v0.2.0 binary format specification - Add resource linking system for behaviors and schedules - Add year-long schedule patterns (day, season, recurrence) - Add behavior tree enhancements (named nodes, decorators) Documentation: - Complete tutorial series (9 chapters) with baker family examples - Complete reference documentation for all language features - SBIR v0.2.0 specification with binary format details - Added locations and institutions documentation Examples: - Convert all examples to baker family scenario - Add comprehensive working examples Tooling: - Zed extension with LSP integration - Tree-sitter grammar for syntax highlighting - Build scripts and development tools Version Updates: - Main package: 0.1.0 → 0.2.0 - Tree-sitter grammar: 0.1.0 → 0.2.0 - Zed extension: 0.1.0 → 0.2.0 - Storybook editor: 0.1.0 → 0.2.0
1006 lines
39 KiB
HTML
1006 lines
39 KiB
HTML
<!DOCTYPE HTML>
|
||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||
<head>
|
||
<!-- Book generated using mdBook -->
|
||
<meta charset="UTF-8">
|
||
<title>Other Declarations - Storybook Language Guide</title>
|
||
|
||
|
||
<!-- Custom HTML head -->
|
||
|
||
<meta name="description" content="Comprehensive documentation for the Storybook narrative simulation language">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="theme-color" content="#ffffff">
|
||
|
||
<link rel="icon" href="../favicon.svg">
|
||
<link rel="shortcut icon" href="../favicon.png">
|
||
<link rel="stylesheet" href="../css/variables.css">
|
||
<link rel="stylesheet" href="../css/general.css">
|
||
<link rel="stylesheet" href="../css/chrome.css">
|
||
<link rel="stylesheet" href="../css/print.css" media="print">
|
||
|
||
<!-- Fonts -->
|
||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||
|
||
<!-- Highlight.js Stylesheets -->
|
||
<link rel="stylesheet" href="../highlight.css">
|
||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||
|
||
<!-- Custom theme stylesheets -->
|
||
|
||
|
||
<!-- Provide site root to javascript -->
|
||
<script>
|
||
var path_to_root = "../";
|
||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
||
</script>
|
||
<!-- Start loading toc.js asap -->
|
||
<script src="../toc.js"></script>
|
||
</head>
|
||
<body>
|
||
<div id="body-container">
|
||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||
<script>
|
||
try {
|
||
var theme = localStorage.getItem('mdbook-theme');
|
||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||
|
||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||
}
|
||
|
||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||
}
|
||
} catch (e) { }
|
||
</script>
|
||
|
||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||
<script>
|
||
var theme;
|
||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||
const html = document.documentElement;
|
||
html.classList.remove('light')
|
||
html.classList.add(theme);
|
||
html.classList.add("js");
|
||
</script>
|
||
|
||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||
|
||
<!-- Hide / unhide sidebar before it is displayed -->
|
||
<script>
|
||
var sidebar = null;
|
||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||
if (document.body.clientWidth >= 1080) {
|
||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||
sidebar = sidebar || 'visible';
|
||
} else {
|
||
sidebar = 'hidden';
|
||
}
|
||
sidebar_toggle.checked = sidebar === 'visible';
|
||
html.classList.remove('sidebar-visible');
|
||
html.classList.add("sidebar-" + sidebar);
|
||
</script>
|
||
|
||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||
<!-- populated by js -->
|
||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||
<noscript>
|
||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||
</noscript>
|
||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||
<div class="sidebar-resize-indicator"></div>
|
||
</div>
|
||
</nav>
|
||
|
||
<div id="page-wrapper" class="page-wrapper">
|
||
|
||
<div class="page">
|
||
<div id="menu-bar-hover-placeholder"></div>
|
||
<div id="menu-bar" class="menu-bar sticky">
|
||
<div class="left-buttons">
|
||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||
<i class="fa fa-bars"></i>
|
||
</label>
|
||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||
<i class="fa fa-paint-brush"></i>
|
||
</button>
|
||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||
</ul>
|
||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||
<i class="fa fa-search"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<h1 class="menu-title">Storybook Language Guide</h1>
|
||
|
||
<div class="right-buttons">
|
||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
||
<i id="print-button" class="fa fa-print"></i>
|
||
</a>
|
||
<a href="https://github.com/r3t-studios/storybook" title="Git repository" aria-label="Git repository">
|
||
<i id="git-repository-button" class="fa fa-github"></i>
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div id="search-wrapper" class="hidden">
|
||
<form id="searchbar-outer" class="searchbar-outer">
|
||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||
</form>
|
||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||
<div id="searchresults-header" class="searchresults-header"></div>
|
||
<ul id="searchresults">
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||
<script>
|
||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||
});
|
||
</script>
|
||
|
||
<div id="content" class="content">
|
||
<main>
|
||
<h1 id="other-declarations"><a class="header" href="#other-declarations">Other Declarations</a></h1>
|
||
<p>This chapter covers six utility declaration types that complete the Storybook language: Templates, Institutions, Locations, Species, Enums, and Use statements. These declarations enable code reuse, organizational modeling, world-building, type safety, and modular file organization.</p>
|
||
<hr />
|
||
<h2 id="templates"><a class="header" href="#templates">Templates</a></h2>
|
||
<p>Templates are reusable field sets that characters inherit using the <code>from</code> keyword. Unlike <a href="./10-characters.html#species-optional">species</a> (which define what an entity <em>is</em>), templates define what an entity <em>has</em>—capabilities, traits, and characteristics.</p>
|
||
<h3 id="syntax"><a class="header" href="#syntax">Syntax</a></h3>
|
||
<pre><code class="language-bnf"><template-decl> ::= "template" <identifier> <strict-clause>? <resource-links>? <includes-clause>? <body>
|
||
|
||
<strict-clause> ::= "strict"
|
||
|
||
<resource-links> ::= "uses" "behaviors" ":" <behavior-list>
|
||
| "uses" "schedule" ":" <schedule-ref>
|
||
| "uses" "schedules" ":" <schedule-list>
|
||
|
||
<includes-clause> ::= "include" <identifier> ("," <identifier>)*
|
||
|
||
<body> ::= "{" <field>* "}"
|
||
|
||
<field> ::= <identifier> ":" <value>
|
||
</code></pre>
|
||
<h3 id="basic-template"><a class="header" href="#basic-template">Basic Template</a></h3>
|
||
<pre><code class="language-storybook">template Warrior {
|
||
strength: 10..20
|
||
dexterity: 8..15
|
||
weapon_proficiency: 0.7..1.0
|
||
}
|
||
</code></pre>
|
||
<p>Characters inheriting this template get these fields with values selected from the specified ranges.</p>
|
||
<h3 id="template-includes"><a class="header" href="#template-includes">Template Includes</a></h3>
|
||
<p>Templates can include other templates to compose functionality:</p>
|
||
<pre><code class="language-storybook">template SkilledWorker {
|
||
skill_level: SkillLevel
|
||
confidence: Confidence
|
||
years_experience: 0..50
|
||
can_work_independently: false
|
||
}
|
||
|
||
template Baker {
|
||
include SkilledWorker
|
||
|
||
specialty: Specialty
|
||
recipes_mastered: 0..200
|
||
sourdough_starter_health: 0.0..1.0
|
||
}
|
||
</code></pre>
|
||
<p><strong>Semantics:</strong></p>
|
||
<ul>
|
||
<li><code>include SkilledWorker</code> brings in all fields from that template</li>
|
||
<li>Fields are merged left-to-right (later overrides earlier)</li>
|
||
<li>Transitive includes supported</li>
|
||
<li>Multiple includes allowed: <code>include A, B, C</code></li>
|
||
</ul>
|
||
<h3 id="range-values"><a class="header" href="#range-values">Range Values</a></h3>
|
||
<p>Templates can specify ranges for procedural variation:</p>
|
||
<pre><code class="language-storybook">template Villager {
|
||
age: 18..65
|
||
wealth: 10..100
|
||
height: 150.0..190.0
|
||
disposition: 0.0..1.0
|
||
}
|
||
</code></pre>
|
||
<p><strong>Range syntax:</strong></p>
|
||
<ul>
|
||
<li>Integer ranges: <code>min..max</code> (inclusive)</li>
|
||
<li>Float ranges: <code>min..max</code> (inclusive)</li>
|
||
<li>Both bounds must be same type</li>
|
||
<li>min ≤ max required</li>
|
||
</ul>
|
||
<p>When a character uses this template, the runtime selects specific values within each range.</p>
|
||
<h3 id="strict-mode"><a class="header" href="#strict-mode">Strict Mode</a></h3>
|
||
<p>Strict templates enforce that characters using them can only have fields defined in the template:</p>
|
||
<pre><code class="language-storybook">template RecipeCard strict {
|
||
include SkilledWorker
|
||
|
||
recipe_name: string
|
||
difficulty: Difficulty
|
||
prep_time_minutes: 10..180
|
||
requires_starter: false
|
||
}
|
||
</code></pre>
|
||
<p><strong>Strict semantics:</strong></p>
|
||
<ul>
|
||
<li>Characters using strict templates cannot add extra fields</li>
|
||
<li>All template fields must be present in the character</li>
|
||
<li>Enables type safety for well-defined schemas</li>
|
||
<li>Use for controlled domains (game cards, rigid categories)</li>
|
||
</ul>
|
||
<p><strong>Non-strict (default):</strong></p>
|
||
<pre><code class="language-storybook">template Flexible {
|
||
base_stat: 10
|
||
}
|
||
|
||
character Custom from Flexible {
|
||
base_stat: 15 // Override
|
||
extra_field: 42 // Allowed in non-strict
|
||
}
|
||
</code></pre>
|
||
<p><strong>Strict:</strong></p>
|
||
<pre><code class="language-storybook">template Rigid strict {
|
||
required_stat: 10
|
||
}
|
||
|
||
character Constrained from Rigid {
|
||
required_stat: 15 // OK: Override
|
||
extra_field: 42 // ERROR: Not allowed in strict template
|
||
}
|
||
</code></pre>
|
||
<h3 id="resource-linking-in-templates"><a class="header" href="#resource-linking-in-templates">Resource Linking in Templates</a></h3>
|
||
<p>Templates can link to behaviors and schedules (v0.2.0+):</p>
|
||
<pre><code class="language-storybook">template BakeryStaffMember
|
||
uses behaviors: DailyBakingRoutine, CustomerService
|
||
uses schedule: BakerySchedule
|
||
{
|
||
include SkilledWorker
|
||
|
||
on_shift: true
|
||
orders_completed: 0..1000
|
||
current_station: 0..4
|
||
}
|
||
</code></pre>
|
||
<p>Characters inheriting this template automatically get the linked behaviors and schedule.</p>
|
||
<h3 id="templates-vs-species"><a class="header" href="#templates-vs-species">Templates vs. Species</a></h3>
|
||
<div class="table-wrapper"><table><thead><tr><th>Aspect</th><th>Templates (<code>from</code>)</th><th>Species (<code>:</code>)</th></tr></thead><tbody>
|
||
<tr><td>Semantics</td><td>What entity <em>has</em></td><td>What entity <em>is</em></td></tr>
|
||
<tr><td>Cardinality</td><td>Multiple inheritance</td><td>Single inheritance</td></tr>
|
||
<tr><td>Ranges</td><td>Allowed</td><td>Not allowed</td></tr>
|
||
<tr><td>Strict mode</td><td>Supported</td><td>Not supported</td></tr>
|
||
<tr><td>Use case</td><td>Compositional traits</td><td>Ontological identity</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p><strong>Example combining both:</strong></p>
|
||
<pre><code class="language-storybook">species Dragon {
|
||
lifespan: 1000
|
||
can_fly: true
|
||
}
|
||
|
||
template Hoarder {
|
||
treasure_value: 0..1000000
|
||
greed_level: 0.5..1.0
|
||
}
|
||
|
||
character Smaug: Dragon from Hoarder {
|
||
age: 850
|
||
greed_level: 0.95
|
||
}
|
||
</code></pre>
|
||
<h3 id="validation-rules"><a class="header" href="#validation-rules">Validation Rules</a></h3>
|
||
<ol>
|
||
<li><strong>Includes exist</strong>: All included templates must be defined</li>
|
||
<li><strong>No circular includes</strong>: Cannot form cycles</li>
|
||
<li><strong>Range validity</strong>: min ≤ max for all ranges</li>
|
||
<li><strong>Strict enforcement</strong>: Strict templates reject extra fields in characters</li>
|
||
<li><strong>Resource links valid</strong>: Behavior/schedule references must resolve</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="institutions"><a class="header" href="#institutions">Institutions</a></h2>
|
||
<p>Institutions define organizations, groups, and systems—entities that function like characters but represent collectives rather than individuals.</p>
|
||
<h3 id="syntax-1"><a class="header" href="#syntax-1">Syntax</a></h3>
|
||
<pre><code class="language-bnf"><institution-decl> ::= "institution" <identifier> <resource-links>? <body>
|
||
|
||
<resource-links> ::= "uses" "behaviors" ":" <behavior-list>
|
||
| "uses" "schedule" ":" <schedule-ref>
|
||
| "uses" "schedules" ":" <schedule-list>
|
||
|
||
<body> ::= "{" <field>* <prose-block>* "}"
|
||
</code></pre>
|
||
<h3 id="basic-institution"><a class="header" href="#basic-institution">Basic Institution</a></h3>
|
||
<pre><code class="language-storybook">institution BakersGuild {
|
||
type: trade_guild
|
||
members: 50
|
||
founded: "1450-03-15"
|
||
reputation: 0.85
|
||
}
|
||
</code></pre>
|
||
<h3 id="institutions-with-fields"><a class="header" href="#institutions-with-fields">Institutions with Fields</a></h3>
|
||
<pre><code class="language-storybook">institution BakersGuild {
|
||
type: professional_guild
|
||
government_style: elected_board
|
||
hierarchy: flat
|
||
standards_enforcement: true
|
||
|
||
// Leadership
|
||
board_chair: Martha
|
||
vice_chair: Henri
|
||
board_temperament: collegial
|
||
|
||
// Membership
|
||
master_bakers: 12
|
||
journeymen: 25
|
||
apprentices: 8
|
||
honorary_members: 3
|
||
|
||
// Standards
|
||
certification_process: "practical exam and peer review"
|
||
quality_standard: "excellence"
|
||
annual_competition: true
|
||
scholarships_offered: 2
|
||
|
||
---description
|
||
The local bakers' guild that sets quality standards, organizes
|
||
competitions, and mentors apprentices. Martha has been a board
|
||
member for three years.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="resource-linking"><a class="header" href="#resource-linking">Resource Linking</a></h3>
|
||
<p>Institutions can use behaviors and schedules:</p>
|
||
<pre><code class="language-storybook">institution MarthasBakery
|
||
uses behaviors: DailyBakingRoutine, CustomerService
|
||
uses schedule: BakerySchedule
|
||
{
|
||
type: small_business
|
||
purpose: bread_and_pastry_production
|
||
family_owned: true
|
||
established: 2018
|
||
|
||
permanent_staff: 4
|
||
seasonal_helpers: 0..3
|
||
|
||
---description
|
||
A beloved neighborhood bakery run by Martha and Jane,
|
||
known for its sourdough bread and artisan pastries.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="prose-blocks"><a class="header" href="#prose-blocks">Prose Blocks</a></h3>
|
||
<p>Institutions support rich narrative documentation:</p>
|
||
<pre><code class="language-storybook">institution TownCulinaryScene {
|
||
type: cultural_ecosystem
|
||
governs: "local food culture"
|
||
|
||
// Characteristics
|
||
farm_to_table: true
|
||
artisan_focus: strong
|
||
seasonal_menus: true
|
||
community_events: monthly
|
||
|
||
---description
|
||
The overarching culinary culture of the town -- a network
|
||
of bakeries, farms, and food artisans that sustain each other.
|
||
---
|
||
|
||
---philosophy
|
||
The town's food scene operates on relationships: farmers
|
||
supply bakers, bakers feed families, families support farms.
|
||
Quality and trust are the currency of this ecosystem.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="use-cases"><a class="header" href="#use-cases">Use Cases</a></h3>
|
||
<ul>
|
||
<li><strong>Organizations</strong>: Guilds, companies, governments</li>
|
||
<li><strong>Systems</strong>: Magical systems, physical laws, economies</li>
|
||
<li><strong>Social structures</strong>: Families, tribes, castes</li>
|
||
<li><strong>Abstract entities</strong>: Dream logic, fate, chaos</li>
|
||
</ul>
|
||
<h3 id="validation-rules-1"><a class="header" href="#validation-rules-1">Validation Rules</a></h3>
|
||
<ol>
|
||
<li><strong>Unique names</strong>: Institution names must be unique</li>
|
||
<li><strong>Resource links valid</strong>: Behaviors/schedules must exist</li>
|
||
<li><strong>Field types</strong>: All fields must have valid values</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="locations"><a class="header" href="#locations">Locations</a></h2>
|
||
<p>Locations define places in your world—rooms, buildings, cities, landscapes, or abstract spaces.</p>
|
||
<h3 id="syntax-2"><a class="header" href="#syntax-2">Syntax</a></h3>
|
||
<pre><code class="language-bnf"><location-decl> ::= "location" <identifier> <body>
|
||
|
||
<body> ::= "{" <field>* <prose-block>* "}"
|
||
</code></pre>
|
||
<h3 id="basic-location"><a class="header" href="#basic-location">Basic Location</a></h3>
|
||
<pre><code class="language-storybook">location MarthasBakery {
|
||
square_feet: 1200
|
||
type: commercial
|
||
established: "2018"
|
||
has_storefront: true
|
||
|
||
---description
|
||
A warm, inviting bakery on Main Street. The aroma of fresh
|
||
bread wafts out the door every morning. Exposed brick walls,
|
||
a glass display case, and a view into the open kitchen.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="location-with-structure"><a class="header" href="#location-with-structure">Location with Structure</a></h3>
|
||
<pre><code class="language-storybook">location BakeryKitchen {
|
||
type: "commercial kitchen"
|
||
ovens: 3
|
||
prep_stations: 4
|
||
walk_in_cooler: true
|
||
|
||
// Equipment
|
||
has_proofing_cabinet: true
|
||
mixer_capacity_kg: 20
|
||
starter_shelf: true
|
||
|
||
// Storage
|
||
flour_bins: 6
|
||
ingredient_shelves: 12
|
||
cold_storage: true
|
||
|
||
---description
|
||
The heart of the bakery. Three professional ovens line the
|
||
back wall. The sourdough starter sits on a shelf near the
|
||
warmest oven, bubbling contentedly in its ceramic crock.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="geographic-hierarchy"><a class="header" href="#geographic-hierarchy">Geographic Hierarchy</a></h3>
|
||
<p>Locations can reference other locations:</p>
|
||
<pre><code class="language-storybook">location MainStreet {
|
||
type: commercial_district
|
||
shops: 15
|
||
foot_traffic: high
|
||
}
|
||
|
||
location BakeryStorefront {
|
||
part_of: MainStreet
|
||
seating_capacity: 12
|
||
display_case: true
|
||
|
||
---description
|
||
The customer-facing area with a glass display case full
|
||
of fresh bread, pastries, and seasonal specials.
|
||
---
|
||
}
|
||
|
||
location FarmersMarket {
|
||
part_of: MainStreet
|
||
operates_on: saturday
|
||
stalls: 30
|
||
|
||
---description
|
||
The weekly Saturday market where Martha sells bread directly
|
||
to the community. Her stall is always the first to sell out.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="location-with-state"><a class="header" href="#location-with-state">Location with State</a></h3>
|
||
<pre><code class="language-storybook">location BakeryWarehouse {
|
||
temperature: controlled
|
||
square_feet: 400
|
||
humidity_controlled: true
|
||
shelving_units: 8
|
||
|
||
// Storage state
|
||
flour_stock_kg: 200
|
||
yeast_supply_days: 14
|
||
packaging_materials: true
|
||
|
||
---description
|
||
The storage area behind the kitchen. Climate-controlled to
|
||
keep flour dry and ingredients fresh. Martha takes inventory
|
||
every Monday morning.
|
||
---
|
||
|
||
---logistics
|
||
Deliveries arrive Tuesday and Friday mornings. The walk-in
|
||
cooler holds butter, eggs, and cream. Dry goods are rotated
|
||
on a first-in-first-out basis.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="use-cases-1"><a class="header" href="#use-cases-1">Use Cases</a></h3>
|
||
<ul>
|
||
<li><strong>Physical places</strong>: Cities, buildings, rooms</li>
|
||
<li><strong>Geographic features</strong>: Mountains, rivers, forests</li>
|
||
<li><strong>Abstract spaces</strong>: Dream realms, pocket dimensions</li>
|
||
<li><strong>Game boards</strong>: Arenas, dungeons, maps</li>
|
||
</ul>
|
||
<h3 id="validation-rules-2"><a class="header" href="#validation-rules-2">Validation Rules</a></h3>
|
||
<ol>
|
||
<li><strong>Unique names</strong>: Location names must be unique</li>
|
||
<li><strong>Field types</strong>: All fields must have valid values</li>
|
||
<li><strong>References valid</strong>: Location references (like <code>part_of</code>) should resolve</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="species"><a class="header" href="#species">Species</a></h2>
|
||
<p>Species define the fundamental ontological categories of beings. A species represents what an entity <em>is</em> at its core—human, dragon, sentient tree, animated playing card.</p>
|
||
<h3 id="syntax-3"><a class="header" href="#syntax-3">Syntax</a></h3>
|
||
<pre><code class="language-bnf"><species-decl> ::= "species" <identifier> <includes-clause>? <body>
|
||
|
||
<includes-clause> ::= "includes" <identifier> ("," <identifier>)*
|
||
|
||
<body> ::= "{" <field>* <prose-block>* "}"
|
||
</code></pre>
|
||
<h3 id="basic-species"><a class="header" href="#basic-species">Basic Species</a></h3>
|
||
<pre><code class="language-storybook">species Human {
|
||
lifespan: 70
|
||
|
||
---description
|
||
Bipedal mammals with complex language and tool use.
|
||
Highly variable in cultures and capabilities.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="species-with-includes"><a class="header" href="#species-with-includes">Species with Includes</a></h3>
|
||
<p>Species can include other species for composition:</p>
|
||
<pre><code class="language-storybook">species Mammal {
|
||
warm_blooded: true
|
||
has_fur: true
|
||
}
|
||
|
||
species Primate includes Mammal {
|
||
opposable_thumbs: true
|
||
sapience_potential: 0.5..1.0
|
||
}
|
||
|
||
species Human includes Primate {
|
||
sapience_potential: 1.0
|
||
language_complexity: "high"
|
||
|
||
---description
|
||
Highly intelligent primates with advanced tool use.
|
||
---
|
||
}
|
||
</code></pre>
|
||
<h3 id="field-resolution-with-includes"><a class="header" href="#field-resolution-with-includes">Field Resolution with Includes</a></h3>
|
||
<p>When a species includes others, fields are merged in declaration order:</p>
|
||
<ol>
|
||
<li><strong>Base species</strong> (leftmost in <code>includes</code>)</li>
|
||
<li><strong>Middle species</strong></li>
|
||
<li><strong>Rightmost species</strong></li>
|
||
<li><strong>Current species</strong> (highest priority)</li>
|
||
</ol>
|
||
<p>Example:</p>
|
||
<pre><code class="language-storybook">species Aquatic {
|
||
breathes_underwater: true
|
||
speed_in_water: 2.0
|
||
}
|
||
|
||
species Reptile {
|
||
cold_blooded: true
|
||
speed_in_water: 1.0
|
||
}
|
||
|
||
species SeaTurtle includes Aquatic, Reptile {
|
||
has_shell: true
|
||
speed_in_water: 1.5 // Overrides both
|
||
}
|
||
|
||
// Resolved:
|
||
// breathes_underwater: true (from Aquatic)
|
||
// cold_blooded: true (from Reptile)
|
||
// speed_in_water: 1.5 (SeaTurtle overrides Reptile overrides Aquatic)
|
||
// has_shell: true (from SeaTurtle)
|
||
</code></pre>
|
||
<h3 id="species-vs-templates"><a class="header" href="#species-vs-templates">Species vs. Templates</a></h3>
|
||
<div class="table-wrapper"><table><thead><tr><th>Aspect</th><th>Species (<code>:</code>)</th><th>Templates (<code>from</code>)</th></tr></thead><tbody>
|
||
<tr><td>Question</td><td>“What <em>is</em> it?”</td><td>“What <em>traits</em> does it have?”</td></tr>
|
||
<tr><td>Cardinality</td><td>One per character</td><td>Zero or more</td></tr>
|
||
<tr><td>Inheritance</td><td><code>includes</code> (species → species)</td><td>Characters inherit from templates</td></tr>
|
||
<tr><td>Variation</td><td>Concrete defaults</td><td>Ranges allowed</td></tr>
|
||
<tr><td>Example</td><td><code>species Human</code></td><td><code>template Warrior</code></td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p><strong>When to use species:</strong></p>
|
||
<pre><code class="language-storybook">species Dragon {
|
||
lifespan: 1000
|
||
can_fly: true
|
||
breathes_fire: true
|
||
}
|
||
|
||
character Smaug: Dragon {
|
||
age: 850 // Smaug IS a Dragon
|
||
}
|
||
</code></pre>
|
||
<p><strong>When to use templates:</strong></p>
|
||
<pre><code class="language-storybook">template Hoarder {
|
||
treasure_value: 0..1000000
|
||
greed_level: 0.5..1.0
|
||
}
|
||
|
||
character Smaug: Dragon from Hoarder {
|
||
greed_level: 0.95 // Smaug HAS hoarder traits
|
||
}
|
||
</code></pre>
|
||
<h3 id="design-pattern-prefer-composition-over-deep-hierarchies"><a class="header" href="#design-pattern-prefer-composition-over-deep-hierarchies">Design Pattern: Prefer Composition Over Deep Hierarchies</a></h3>
|
||
<p><strong>Avoid:</strong></p>
|
||
<pre><code class="language-storybook">species Being { ... }
|
||
species LivingBeing includes Being { ... }
|
||
species Animal includes LivingBeing { ... }
|
||
species Vertebrate includes Animal { ... }
|
||
species Mammal includes Vertebrate { ... }
|
||
species Primate includes Mammal { ... }
|
||
species Human includes Primate { ... } // Too deep!
|
||
</code></pre>
|
||
<p><strong>Prefer:</strong></p>
|
||
<pre><code class="language-storybook">species Mammal {
|
||
warm_blooded: true
|
||
live_birth: true
|
||
}
|
||
|
||
species Human includes Mammal {
|
||
sapient: true
|
||
}
|
||
|
||
// Use templates for capabilities
|
||
template Climber { ... }
|
||
template SocialCreature { ... }
|
||
|
||
character Jane: Human from Climber, SocialCreature { ... }
|
||
</code></pre>
|
||
<h3 id="validation-rules-3"><a class="header" href="#validation-rules-3">Validation Rules</a></h3>
|
||
<ol>
|
||
<li><strong>Unique names</strong>: Species names must be unique</li>
|
||
<li><strong>No circular includes</strong>: Cannot form cycles</li>
|
||
<li><strong>Includes exist</strong>: All included species must be defined</li>
|
||
<li><strong>Field types</strong>: All fields must have valid values</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="enums"><a class="header" href="#enums">Enums</a></h2>
|
||
<p>Enums define controlled vocabularies—fixed sets of named values. They enable type-safe categorization and validation.</p>
|
||
<h3 id="syntax-4"><a class="header" href="#syntax-4">Syntax</a></h3>
|
||
<pre><code class="language-bnf"><enum-decl> ::= "enum" <identifier> "{" <variant>+ "}"
|
||
|
||
<variant> ::= <identifier> ","?
|
||
</code></pre>
|
||
<h3 id="basic-enum"><a class="header" href="#basic-enum">Basic Enum</a></h3>
|
||
<pre><code class="language-storybook">enum Size {
|
||
tiny,
|
||
small,
|
||
normal,
|
||
large,
|
||
huge
|
||
}
|
||
</code></pre>
|
||
<h3 id="using-enums"><a class="header" href="#using-enums">Using Enums</a></h3>
|
||
<p>Enums are used as field values throughout the system:</p>
|
||
<pre><code class="language-storybook">character Martha: Human {
|
||
skill_level: master // References SkillLevel enum
|
||
specialty: sourdough // References Specialty enum
|
||
}
|
||
</code></pre>
|
||
<h3 id="common-enum-patterns"><a class="header" href="#common-enum-patterns">Common Enum Patterns</a></h3>
|
||
<p><strong>Emotional States:</strong></p>
|
||
<pre><code class="language-storybook">enum EmotionalState {
|
||
curious,
|
||
frightened,
|
||
confused,
|
||
brave,
|
||
angry,
|
||
melancholy,
|
||
amused
|
||
}
|
||
</code></pre>
|
||
<p><strong>Card Suits:</strong></p>
|
||
<pre><code class="language-storybook">enum CardSuit {
|
||
hearts,
|
||
diamonds,
|
||
clubs,
|
||
spades
|
||
}
|
||
|
||
enum CardRank {
|
||
two, three, four, five, six, seven, eight, nine, ten,
|
||
knave, queen, king
|
||
}
|
||
</code></pre>
|
||
<p><strong>Time States:</strong></p>
|
||
<pre><code class="language-storybook">enum TimeState {
|
||
normal,
|
||
frozen,
|
||
reversed,
|
||
accelerated
|
||
}
|
||
</code></pre>
|
||
<p><strong>Government Types:</strong></p>
|
||
<pre><code class="language-storybook">enum GovernmentType {
|
||
monarchy,
|
||
democracy,
|
||
anarchy,
|
||
tyranny,
|
||
oligarchy
|
||
}
|
||
|
||
enum GovernmentStyle {
|
||
absolute_tyranny,
|
||
benevolent_dictatorship,
|
||
constitutional_monarchy,
|
||
direct_democracy,
|
||
representative_democracy
|
||
}
|
||
</code></pre>
|
||
<h3 id="calendar-enums-configurable"><a class="header" href="#calendar-enums-configurable">Calendar Enums (Configurable)</a></h3>
|
||
<p>Define custom calendars for your world:</p>
|
||
<pre><code class="language-storybook">enum Season {
|
||
spring,
|
||
summer,
|
||
fall,
|
||
winter
|
||
}
|
||
|
||
enum DayOfWeek {
|
||
monday,
|
||
tuesday,
|
||
wednesday,
|
||
thursday,
|
||
friday,
|
||
saturday,
|
||
sunday
|
||
}
|
||
|
||
enum Month {
|
||
january, february, march, april,
|
||
may, june, july, august,
|
||
september, october, november, december
|
||
}
|
||
</code></pre>
|
||
<p><strong>Custom calendars:</strong></p>
|
||
<pre><code class="language-storybook">enum EightSeasons {
|
||
deep_winter,
|
||
late_winter,
|
||
early_spring,
|
||
late_spring,
|
||
early_summer,
|
||
late_summer,
|
||
early_fall,
|
||
late_fall
|
||
}
|
||
</code></pre>
|
||
<h3 id="validation-integration"><a class="header" href="#validation-integration">Validation Integration</a></h3>
|
||
<p>Enums enable compile-time validation:</p>
|
||
<pre><code class="language-storybook">enum Size {
|
||
tiny, small, normal, large, huge
|
||
}
|
||
|
||
character Martha {
|
||
skill_level: medium // ERROR: 'medium' not in SkillLevel enum
|
||
}
|
||
</code></pre>
|
||
<h3 id="use-cases-2"><a class="header" href="#use-cases-2">Use Cases</a></h3>
|
||
<ul>
|
||
<li><strong>Controlled vocabularies</strong>: Prevent typos and invalid values</li>
|
||
<li><strong>Schema constraints</strong>: Temporal systems, card decks, status types</li>
|
||
<li><strong>Type safety</strong>: Catch errors at compile time</li>
|
||
<li><strong>Documentation</strong>: Enumerate all valid options</li>
|
||
</ul>
|
||
<h3 id="validation-rules-4"><a class="header" href="#validation-rules-4">Validation Rules</a></h3>
|
||
<ol>
|
||
<li><strong>Unique enum names</strong>: Enum names must be unique</li>
|
||
<li><strong>Unique variants</strong>: Variant names must be unique within the enum</li>
|
||
<li><strong>Non-empty</strong>: Enums must have at least one variant</li>
|
||
<li><strong>Valid identifiers</strong>: Variants must follow identifier rules</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="use-statements"><a class="header" href="#use-statements">Use Statements</a></h2>
|
||
<p>Use statements import definitions from other files, enabling modular organization and code reuse.</p>
|
||
<h3 id="syntax-5"><a class="header" href="#syntax-5">Syntax</a></h3>
|
||
<pre><code class="language-bnf"><use-decl> ::= "use" <use-path> <use-kind>
|
||
|
||
<use-path> ::= <identifier> ("::" <identifier>)*
|
||
|
||
<use-kind> ::= ";" // Single import
|
||
| "::{" <identifier> ("," <identifier>)* "}" ";" // Grouped import
|
||
| "::*" ";" // Wildcard import
|
||
</code></pre>
|
||
<h3 id="single-import"><a class="header" href="#single-import">Single Import</a></h3>
|
||
<pre><code class="language-storybook">use schema::beings::Human;
|
||
</code></pre>
|
||
<p>Imports the <code>Human</code> species from <code>schema/beings.sb</code>.</p>
|
||
<h3 id="grouped-import"><a class="header" href="#grouped-import">Grouped Import</a></h3>
|
||
<pre><code class="language-storybook">use schema::core_enums::{Size, EmotionalState};
|
||
</code></pre>
|
||
<p>Imports multiple items from the same module.</p>
|
||
<h3 id="wildcard-import"><a class="header" href="#wildcard-import">Wildcard Import</a></h3>
|
||
<pre><code class="language-storybook">use schema::beings::*;
|
||
</code></pre>
|
||
<p>Imports all public items from <code>schema/beings.sb</code>.</p>
|
||
<h3 id="qualified-paths"><a class="header" href="#qualified-paths">Qualified Paths</a></h3>
|
||
<p><strong>Module structure:</strong></p>
|
||
<pre><code>examples/alice-in-wonderland/
|
||
├─ schema/
|
||
│ ├─ core_enums.sb
|
||
│ ├─ templates.sb
|
||
│ └─ beings.sb
|
||
└─ world/
|
||
├─ characters/
|
||
│ └─ alice.sb
|
||
└─ locations/
|
||
└─ wonderland_places.sb
|
||
</code></pre>
|
||
<p><strong>In <code>martha.sb</code>:</strong></p>
|
||
<pre><code class="language-storybook">use schema::core_enums::{SkillLevel, Specialty};
|
||
use schema::templates::Baker;
|
||
use schema::beings::Human;
|
||
|
||
character Martha: Human from Baker {
|
||
skill_level: master
|
||
specialty: sourdough
|
||
}
|
||
</code></pre>
|
||
<h3 id="path-resolution"><a class="header" href="#path-resolution">Path Resolution</a></h3>
|
||
<ol>
|
||
<li><strong>Relative to file’s module path</strong>: Imports are resolved relative to the current file’s location</li>
|
||
<li><strong>Module hierarchy</strong>: <code>schema::beings</code> maps to <code>schema/beings.sb</code></li>
|
||
<li><strong>Transitive imports</strong>: Imported modules can themselves import others</li>
|
||
</ol>
|
||
<h3 id="common-patterns"><a class="header" href="#common-patterns">Common Patterns</a></h3>
|
||
<p><strong>Schema organization:</strong></p>
|
||
<pre><code class="language-storybook">// In schema/core_enums.sb
|
||
enum SkillLevel { novice, beginner, intermediate, advanced, master }
|
||
enum Specialty { sourdough, pastries, cakes, general }
|
||
|
||
// In world/characters/martha.sb
|
||
use schema::core_enums::{SkillLevel, Specialty};
|
||
</code></pre>
|
||
<p><strong>Template composition:</strong></p>
|
||
<pre><code class="language-storybook">// In schema/templates.sb
|
||
template SkilledWorker { ... }
|
||
template Baker {
|
||
include SkilledWorker
|
||
...
|
||
}
|
||
|
||
// In world/characters/martha.sb
|
||
use schema::templates::Baker;
|
||
</code></pre>
|
||
<p><strong>Cross-file references:</strong></p>
|
||
<pre><code class="language-storybook">// In world/characters/martha.sb
|
||
character Martha { ... }
|
||
|
||
// In world/relationships/bakery.sb
|
||
use world::characters::Martha;
|
||
|
||
relationship MarthaAndJane {
|
||
Martha
|
||
Jane
|
||
}
|
||
</code></pre>
|
||
<h3 id="validation-rules-5"><a class="header" href="#validation-rules-5">Validation Rules</a></h3>
|
||
<ol>
|
||
<li><strong>Path exists</strong>: Imported paths must reference defined modules/items</li>
|
||
<li><strong>No circular imports</strong>: Modules cannot form circular dependency chains</li>
|
||
<li><strong>Valid identifiers</strong>: All path segments must be valid identifiers</li>
|
||
<li><strong>Grouped import validity</strong>: All items in <code>{}</code> must exist</li>
|
||
</ol>
|
||
<h3 id="best-practices"><a class="header" href="#best-practices">Best Practices</a></h3>
|
||
<p><strong>1. Group related imports:</strong></p>
|
||
<pre><code class="language-storybook">use schema::core_enums::{SkillLevel, Specialty, Confidence};
|
||
use schema::beings::{Human, Cat};
|
||
</code></pre>
|
||
<p><strong>2. Explicit over wildcard:</strong></p>
|
||
<pre><code class="language-storybook">// Prefer:
|
||
use schema::core_enums::{SkillLevel, Specialty};
|
||
|
||
// Over:
|
||
use schema::core_enums::*; // Imports everything
|
||
</code></pre>
|
||
<p><strong>3. Organize by hierarchy:</strong></p>
|
||
<pre><code class="language-storybook">// Schema imports first
|
||
use schema::core_enums::SkillLevel;
|
||
use schema::templates::Baker;
|
||
|
||
// Then world imports
|
||
use world::characters::Martha;
|
||
</code></pre>
|
||
<p><strong>4. Use qualified paths for clarity:</strong></p>
|
||
<pre><code class="language-storybook">character Elena: Human from Baker, Apprentice {
|
||
// Human is species (from schema::beings)
|
||
// Baker, Apprentice are templates (from schema::templates)
|
||
}
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="cross-references"><a class="header" href="#cross-references">Cross-References</a></h2>
|
||
<ul>
|
||
<li><a href="./10-characters.html">Characters</a> - Using templates and species</li>
|
||
<li><a href="./15-relationships.html">Relationships</a> - Institutions can participate</li>
|
||
<li><a href="./14-schedules.html">Schedules</a> - Resource linking</li>
|
||
<li><a href="./11-behavior-trees.html">Behavior Trees</a> - Resource linking</li>
|
||
<li><a href="./18-value-types.html">Value Types</a> - Field value types</li>
|
||
</ul>
|
||
<h2 id="related-concepts"><a class="header" href="#related-concepts">Related Concepts</a></h2>
|
||
<ul>
|
||
<li><strong>Modularity</strong>: Use statements enable file organization</li>
|
||
<li><strong>Composition</strong>: Templates provide trait-based composition</li>
|
||
<li><strong>Type safety</strong>: Enums prevent invalid values</li>
|
||
<li><strong>World-building</strong>: Locations and institutions model environments</li>
|
||
<li><strong>Ontology</strong>: Species define entity essence</li>
|
||
</ul>
|
||
|
||
</main>
|
||
|
||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||
<!-- Mobile navigation buttons -->
|
||
<a rel="prev" href="../reference/16b-institutions.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="../reference/17-expressions.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
|
||
<div style="clear: both"></div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||
<a rel="prev" href="../reference/16b-institutions.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="../reference/17-expressions.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
</nav>
|
||
|
||
</div>
|
||
|
||
<!-- Livereload script (if served using the cli tool) -->
|
||
<script>
|
||
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
|
||
const socket = new WebSocket(wsAddress);
|
||
socket.onmessage = function (event) {
|
||
if (event.data === "reload") {
|
||
socket.close();
|
||
location.reload();
|
||
}
|
||
};
|
||
|
||
window.onbeforeunload = function() {
|
||
socket.close();
|
||
}
|
||
</script>
|
||
|
||
|
||
|
||
<script>
|
||
window.playground_copyable = true;
|
||
</script>
|
||
|
||
|
||
<script src="../elasticlunr.min.js"></script>
|
||
<script src="../mark.min.js"></script>
|
||
<script src="../searcher.js"></script>
|
||
|
||
<script src="../clipboard.min.js"></script>
|
||
<script src="../highlight.js"></script>
|
||
<script src="../book.js"></script>
|
||
|
||
<!-- Custom JS scripts -->
|
||
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|